
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//

#include "button.hh"
#include "multiwindow.hh"
#include "displays.hh"

extern bool draw_hotspots;

void button::enable()
{
  enabled = true;
}

void button::disable()
{
  enabled = false;
}


void button::push()
{
  int returnval = 0;
  send_event(this, selection_changed_event(0, name, true), returnval);
}

void button::release()
{
  //int returnval = 0;
  //send_event(this, selection_changed_event(0, name, false), returnval);
}


button::button(const multilingua&   name,
	       int                  x_margin_percent,
	       int                  y_margin_percent,
	       int                  circle_width_percent,
	       dt_colors&           textcolors,
	       color                fg,
	       dt_colors&           flash_textcolors,
	       color                flash_fg,
	       push_function*       pf,
	       void*                pf_data,
	       bool                 tighten_x,
	       bool                 tighten_y)
  : window(BLACK)
{
  silent = false;
  enable_flash = true;

  this->name = name;
  
  enabled = true;
  
  this->x_margin_percent     = x_margin_percent;
  this->y_margin_percent     = y_margin_percent;
  this->circle_width_percent = circle_width_percent;

  this->tighten_x = tighten_x;
  this->tighten_y = tighten_y;
  
  FG_COLOR           = fg;
  TEXT_COLORS        = textcolors;
  FLASH_FG_COLOR     = flash_fg;
  FLASH_TEXT_COLORS  = flash_textcolors;

  this->pf = pf;
  this->pf_data = pf_data;

  highlight_count    = 0;
  flash_count        = 0;
}


int button::calculate_preferred_width(int height)
{
  // Use local variables here, to not change the button with
  // this calculation.
  int top_margin    = height * y_margin_percent / 100;
  int bottom_margin = height * y_margin_percent / 100;
  int left_margin   = width  * x_margin_percent / 100;
  int right_margin  = width  * x_margin_percent / 100;

  int font_height   = height - top_margin - bottom_margin;

  set_text_size(font_height);
  
  int text_width = calculate_text_width(name);

  int preferred_width = text_width + left_margin + right_margin;

  return preferred_width;
}

void button::layout()
{
  //  printf("in button::layout();\n");

  top_margin    = height * y_margin_percent / 100;
  bottom_margin = height * y_margin_percent / 100;
  left_margin   = width  * x_margin_percent / 100;
  right_margin  = width  * x_margin_percent / 100;

  font_height = height - top_margin - bottom_margin;

  bool font_height_diminished = false;
  int text_width = 1;
  int desired_width = width-left_margin-right_margin;
  
  while(font_height>1)
    {
      set_text_size(font_height);
      
      text_width = calculate_text_width(name);

      if(text_width<=desired_width)
	break;

      int best_guess_font_height = font_height * desired_width / text_width;
      
      if(best_guess_font_height<font_height)
        font_height = best_guess_font_height;
      else
        font_height--;

      font_height_diminished = true;
    }

  if(font_height_diminished && tighten_y)
    {
      int height_diff = height - (font_height+top_margin+bottom_margin);
      offset.y += height_diff/2;
      height -= height_diff;
    }
  else if(tighten_x)
    {
      int width_diff = width - (text_width+left_margin+right_margin);
      if(width_diff>0)
	{
	  offset.x += width_diff/2;
	  width -= width_diff;
	}
    }

  circle_width  = height * circle_width_percent / 100;

  layout_dirty = false;
  dirty = true;
}


void button::draw_dirty()
{
  //printf("in button::draw_dirty();\n");

  if(enabled)
    {
      draw_rect_with_curved_edges(FG_COLOR,
				  0,
				  0,
				  width,
				  height,
				  circle_width);
      
      set_text_size(font_height);//font_height);
      
      draw_multicolored_text(name, 0, TEXT_COLORS, width/2, height/2, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0);
    }
  
  dirty = false;
}


void button::draw_dynamic()
{
  if(enabled && (draw_hotspots || highlight_count))
    {
      if(highlight_count)
	highlight_count--;

      point tl(       0,        0);
      point tr( width-1,        0);
      point bl(       0, height-1);
      point br( width-1, height-1);
      draw_line(tl, tr, GREEN);
      draw_line(tl, bl, GREEN);
      draw_line(tr, br, GREEN);
      draw_line(bl, br, GREEN);
    }

  if(flash_count)
    {
       draw_rect_with_curved_edges(FLASH_FG_COLOR,
				  0,
				  0,
				  width,
				  height,
				  circle_width);
	
      set_text_size(font_height);//font_height);
      
      draw_multicolored_text(name, 0, FLASH_TEXT_COLORS, width/2, height/2, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0);
      flash_count--;
    }
}


button::~button()
{
}



bool button::handle_event(my_event& me)
{
  if(!enabled)
    return false;
  
  //print_event(me);
  
  int xoff = 0;
  int yoff = 0;
  window* p = this;
  while(p)
    {
      xoff += p->offset.x;
      yoff += p->offset.y;
      p = p->parent;
    }

  int x = me.c[0].x - xoff;
  int y = me.c[0].y - yoff;
  
  if(x<0 || x>=width || y<0 || y>=height)
    return false;

  if(me.type == EVENT_TOUCH && me.num_touches==1)
    {
      if(me.source_mouse && me.mouse_buttons_pressed!=MOUSE_BUTTON_LEFT)
	return false;

      display* disp = get_display();
	  
      trash_events_until_release();
      
      if(!silent)
	disp->touch_recognized_beep();
      
      if(enable_flash)
	flash_count = 10;
      
      if(pf)
	(*pf)(this, pf_data);
      
      //claim_events();
      push();
    }
  else if(me.type == EVENT_RELEASE)
    {
      //release_events();
      release();
    }

  return true;
}
