
/******************************************************************************
* MODULE     : button_widget.gen.cc
* DESCRIPTION: Buttons
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <Widget/attribute_widget.gen.h>
#include <Event/composite_event.gen.h>

#module code_button_widget
#import attribute_widget
#import composite_event

/******************************************************************************
* Abstract button_widgets
******************************************************************************/

class button_widget_rep: public attribute_widget_rep {
protected:
  SI     X1, Y1, X2, Y2;
  SI     extra_width;
  bool   rflag;
  bool   button_flag;

public:
  bool   status;
  bool   inside;

  button_widget_rep (widget w, bool rflag=FALSE, bool button_flag= FALSE);
  button_widget_rep (widget lw, widget rw);
  operator tree ();

  void handle_get_size (get_size_event ev);
  void handle_position (position_event ev);
  void handle_repaint (repaint_event ev);
  void handle_get_coord1 (get_coord1_event ev);
  void handle_set_coord1 (set_coord1_event ev);
};

/******************************************************************************
* Routines for abstract button_widgets
******************************************************************************/

button_widget_rep::button_widget_rep (widget w2, bool rf2, bool bf2):
  attribute_widget_rep (w2->dis, 1, south_west),
  extra_width (0), rflag (rf2), button_flag (bf2),
  status (FALSE), inside (FALSE) { a[0]= w2; }

button_widget_rep::button_widget_rep (widget lw, widget rw):
  attribute_widget_rep (lw->dis, 2, south_west),
  extra_width (0), rflag (FALSE), button_flag (FALSE),
  status (FALSE), inside (FALSE) { a[0]= lw; a[1]= rw; }

button_widget_rep::operator tree () {
  if (N(a)==1) return tree (TUPLE, "button", (tree) a[0]);
  else return tree (TUPLE, "button", (tree) a[0], (tree) a[1]);
}

void
button_widget_rep::handle_get_size (get_size_event ev) {
  if (N(a)==1) {
    attribute_widget_rep::handle_get_size (ev);
    if (rflag) ev->w += max (extra_width, 16*PIXEL);
    else ev->w += extra_width;
  }
  else {
    SI pw1= 0, ph1= 0, pw2= 0, ph2= 0;
    a[0] << get_size (pw1, ph1, -1);
    a[1] << get_size (pw2, ph2, -1);
    ev->w = pw1+ max (extra_width, pw2)+ 8*PIXEL; ev->h = max (ph1, ph2);
    abs_round (ev->w, ev->h);
  }
  ev->w += 2*PIXEL;
  ev->h += 2*PIXEL;
}

void
button_widget_rep::handle_position (position_event ev) {
  (event) ev;
  if (N(a)==1) {
    SI ww= w-2*PIXEL;
    SI hh= h-2*PIXEL;
    if (rflag) ww -= 16*PIXEL;
    a[0] << emit_position (PIXEL, PIXEL, ww, hh, south_west);
  }
  else {
    SI pw1= 0, ph1= 0, pw2= 0, ph2= 0;
    a[0] << get_size (pw1, ph1, -1);
    a[1] << get_size (pw2, ph2, -1);
    a[0] << emit_position (PIXEL, PIXEL, pw1, ph1, south_west);
    a[1] << emit_position (w-PIXEL-extra_width, PIXEL, pw2, ph2, south_west);
  }
}

void
button_widget_rep::handle_repaint (repaint_event ev) { (void) ev;
  layout_default (win, 0, 0, w, h);
  if (button_flag) layout_higher (win, 0, 0, w, h);
  if (status) {
    layout_dark (win, 0, 0, w, h);
    layout_lower (win, 0, 0, w, h);
  }
  if (rflag) layout_submenu_triangle (win, w-10*PIXEL, h>>1);
}

void
button_widget_rep::handle_get_coord1 (get_coord1_event ev) {
  if (ev->which != "extra width") attribute_widget_rep::handle_get_coord1 (ev);
  else {
    SI dummy;
    ev->c1= 0;
    if (N(a) == 2) a[1] << get_size (ev->c1, dummy, -1);
  }
}

void
button_widget_rep::handle_set_coord1 (set_coord1_event ev) {
  if (ev->which != "extra width") attribute_widget_rep::handle_set_coord1 (ev);
  else extra_width= ev->c1;
}

/******************************************************************************
* Command buttons
******************************************************************************/

class command_button_rep: public button_widget_rep {
  command cmd;
public:
  command_button_rep (widget w, command cmd, bool button_flag= FALSE);
  command_button_rep (widget lw, widget rw, command cmd);
  void handle_mouse (mouse_event ev);
};

command_button_rep::command_button_rep (widget w, command cmd2, bool bf):
  button_widget_rep (w, FALSE, bf), cmd (cmd2) {}

command_button_rep::command_button_rep (widget lw, widget rw, command cmd2):
  button_widget_rep (lw, rw), cmd (cmd2) {}

void
command_button_rep::handle_mouse (mouse_event ev) {
  string type= ev->type;
  SI     x= ev->x, y= ev->y;
  // cout << "Command button[" << status << "] "
  //      << s << ": " << ((event) ev) << "\n";

  bool old= status;
  inside= (y>=0) && (y<h) && (x>=0) && (x<w);
  status= inside && (ev->pressed ("left") || ev->pressed ("right"));

  if (status!=old) {
    this << emit_invalidate_all ();
    if ((type == "release-left") || (type == "release-right"))
      if (!nil (cmd)) cmd ();
  }
}

/******************************************************************************
* Interface
******************************************************************************/

widget
command_button (widget w, command cmd, bool button_flag) {
  return new command_button_rep (w, cmd, button_flag);
}

widget
command_button (widget lw, widget rw, command cmd) {
  return new command_button_rep (lw, rw, cmd);
}

#endmodule // code_button_widget
