
/******************************************************************************
* MODULE     : change.gen.cc
* DESCRIPTION: Boxes whose behaviour is changed
* 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 <Boxes/composite.gen.h>

#module code_change_boxes
#import composite_boxes

/******************************************************************************
* changing the behaviour of a box
******************************************************************************/

struct change_box_rep: public composite_box_rep {
  bool child_flag, big_flag;
  change_box_rep (path ip, bool child_flag, bool big_flag= FALSE);
  operator tree () { return tree (TUPLE, "change", (tree) bs[0]); }
  int find_child (SI x, SI y, SI delta, bool force);
  path find_left_box_path () {
    return child_flag?
      composite_box_rep::find_left_box_path ():
      path (0, bs[0]->find_left_box_path ()); }
  path find_right_box_path () {
    return child_flag?
      composite_box_rep::find_right_box_path ():
      path (0, bs[0]->find_right_box_path ()); }

  double left_slope () {
    return big_flag? bs[0]->left_slope(): box_rep::left_slope(); }
  double right_slope () { 
    return big_flag? bs[0]->right_slope(): box_rep::right_slope(); }
  SI left_correction () {
    return big_flag? bs[0]->left_correction():box_rep::left_correction(); }
  SI right_correction () {
    return big_flag? bs[0]->right_correction():box_rep::right_correction(); }
  SI lsub_correction () {
    return big_flag? bs[0]->lsub_correction(): box_rep::lsub_correction(); }
  SI lsup_correction () {
    return big_flag? bs[0]->lsup_correction(): box_rep::lsup_correction(); }
  SI rsub_correction () {
    return big_flag? bs[0]->rsub_correction(): box_rep::rsub_correction(); }
  SI rsup_correction () {
    return big_flag? bs[0]->rsup_correction(): box_rep::rsup_correction(); }
  SI sub_lo_base (int l) {
    return big_flag? bs[0]->sub_lo_base (l): box_rep::sub_lo_base (l); }
  SI sub_hi_lim  (int l) {
    return big_flag? bs[0]->sub_hi_lim (l): box_rep::sub_hi_lim (l); }
  SI sup_lo_lim  (int l) {
    return big_flag? bs[0]->sup_lo_lim (l): box_rep::sup_lo_lim (l); }
  SI sup_lo_base (int l) {
    return big_flag? bs[0]->sup_lo_base (l): box_rep::sup_lo_base (l); }
  SI sup_hi_lim  (int l) {
    return big_flag? bs[0]->sup_hi_lim (l): box_rep::sup_hi_lim (l); }
};

change_box_rep::change_box_rep (path ip, bool fl1, bool fl2):
  composite_box_rep (ip), child_flag (fl1), big_flag (fl2) {}

int
change_box_rep::find_child (SI x, SI y, SI delta, bool force) {
  if (child_flag) return composite_box_rep::find_child (x, y, delta, force);
  return 0;
}

/******************************************************************************
* moving and resizing boxes
******************************************************************************/

struct move_box_rep: public change_box_rep {
  move_box_rep (path ip, box b, SI x, SI y, bool fl1, bool fl2);
  int get_type () { return MOVE_BOX; }
  operator tree () { return tree (TUPLE, "move", (tree) bs[0]); }
};

move_box_rep::move_box_rep (path ip, box b, SI x, SI y, bool fl1, bool fl2):
  change_box_rep (ip, fl1, fl2)
{
  insert (b, x, y);
  position ();
  finalize ();
}

struct resize_box_rep: public change_box_rep {
  resize_box_rep (path ip, box b, SI x1, SI y1, SI x2, SI y2,
		  bool child_flag, bool adjust);
  operator tree () { return tree (TUPLE, "resize", (tree) bs[0]); }
};

resize_box_rep::resize_box_rep (
  path ip, box b, SI X1, SI Y1, SI X2, SI Y2, bool child_flag, bool adjust):
    change_box_rep (ip, child_flag)
{
  insert (b, 0, 0);
  position ();
  x1= X1; y1= Y1;
  x2= X2; y2= Y2;
  if (adjust) left_justify ();
  finalize ();
}

struct vcorrect_box_rep: public change_box_rep {
  vcorrect_box_rep (path ip, box b, SI top_cor, SI bot_cor);
  operator tree () { return tree (TUPLE, "vcorrect", (tree) bs[0]); }
};

vcorrect_box_rep::vcorrect_box_rep (path ip, box b, SI top_cor, SI bot_cor):
  change_box_rep (ip, FALSE, FALSE)
{
  insert (b, 0, -top_cor);
  position ();
  y1 -= bot_cor;
  y2 += top_cor;
  finalize ();
}

/******************************************************************************
* horizontally repetition of one box inside another one
******************************************************************************/

struct repeat_box_rep: public change_box_rep {
  repeat_box_rep (path ip, box b, box repeat, SI xoff);
  operator tree () { return tree (TUPLE, "repeat", (tree) bs[0]); }
};

repeat_box_rep::repeat_box_rep (path ip, box b, box repeat, SI xoff):
  change_box_rep (ip, FALSE)
{
  insert (b, 0, 0);
  position ();

  SI width= repeat->w ();
  if (width >= PIXEL) {
    int i;
    int i1= ((xoff+b->x1)/width)-1;
    int i2= ((xoff+b->x2)/width)+1;
    while (i1*width < (xoff+b->x1)) i1++;
    while (i2*width > (xoff+b->x2)) i2--;
    for (i=i1; i<i2; i++) {
      box bb= move_box (decorate_right (ip), repeat, 0, 0);
      insert (bb, i*width-xoff, 0);
    }
  }

  finalize ();
  x1= b->x1; y1= b->y1;
  x2= b->x2; y2= b->y2;
}

/******************************************************************************
* cell boxes for tables
******************************************************************************/

struct cell_box_rep: public change_box_rep {
  SI    bl, br, bb, bt;
  int   corr;
  color fg, bg;
  bool  transp;
  cell_box_rep (path ip, box b, SI x0, SI y0, SI x1, SI y1, SI x2, SI y2,
		SI bl, SI br, SI bb, SI bt, int corr,
		color fg, color bg, bool transp);
  operator tree () { return tree (TUPLE, "cell", (tree) bs[0]); }
  bool display_background (ps_device dev, color& col);
  void display (ps_device dev);
};

cell_box_rep::cell_box_rep (
  path ip, box b, SI X0, SI Y0, SI X1, SI Y1, SI X2, SI Y2,
  SI Bl, SI Br, SI Bb, SI Bt, int Corr,
  color Fg, color Bg, bool Transp):
  change_box_rep (ip, FALSE),
  bl (Bl), br (Br), bb (Bb), bt (Bt), corr (Corr),
  fg (Fg), bg (Bg), transp (Transp)
{
  insert (b, X0, Y0);
  position ();
  x1= X1; y1= Y1;
  x2= X2; y2= Y2;
  finalize ();
  if ((!transp) || (bl>0) || (br>0) || (bb>0) || (bt>0)) {
    x3= min (x3, x1); y3= min (y3, y1);
    x4= max (x4, x2); y4= max (y4, y2);
  }
}

bool
cell_box_rep::display_background (ps_device dev, color& col) {
  if (transp) return FALSE;
  col= dev->get_background ();
  dev->set_background (bg);
  dev->clear (x1, y1, x2, y2);
  return TRUE;
}

void
cell_box_rep::display (ps_device dev) {
  if ((bl>0) || (br>0) || (bb>0) || (bt>0)) {
    SI l= bl, r= br, b= bb, t= bt;
    if (dev->sfactor > 1) { // correction for screen display only
      SI  pixel= corr * dev->pixel;
      l= ((l + (pixel - 1)) / pixel) * pixel;
      r= ((r + (pixel - 1)) / pixel) * pixel;
      b= ((b + (pixel - 1)) / pixel) * pixel;
      t= ((t + (pixel - 1)) / pixel) * pixel;
    }
    dev->set_color (fg);
    dev->fill (x1  , y1  , x1+l, y2  );
    dev->fill (x2-r, y1  , x2  , y2  );
    dev->fill (x1  , y1  , x2  , y1+b);
    dev->fill (x1  , y2-t, x2  , y2  );
  }
}

/******************************************************************************
* action boxes
******************************************************************************/

struct action_box_rep: public change_box_rep {
  command cmd;
  action_box_rep (path ip, box b, command cmd, bool child_flag);
  operator tree () { return tree (TUPLE, "action", bs[0]); }
  tree action (tree t, SI x, SI y, SI delta);
};

action_box_rep::action_box_rep (path ip, box b, command cmd2, bool child_flag):
  change_box_rep (ip, child_flag), cmd (cmd2)
{
  insert (b, 0, 0);
  position ();
  left_justify ();
  finalize ();
}

tree
action_box_rep::action (tree t, SI x, SI y, SI delta) {
  (void) t; (void) x; (void) y; (void) delta;
  cmd ();
  return "done";
}

/******************************************************************************
* tag boxes
******************************************************************************/

struct tag_box_rep: public change_box_rep {
  string name;
  tag_box_rep (path ip, box b, string name);
  operator tree () { return tree (TUPLE, "tag", bs[0]); }
  tree tag (tree t, SI x, SI y, SI delta);
  void collect_page_numbers (hashmap<string,tree>& h, tree page);
  path find_tag (string name);
};

tag_box_rep::tag_box_rep (path ip, box b, string name2):
  change_box_rep (ip, FALSE), name (name2)
{
  insert (b, 0, 0);
  position ();
  left_justify ();
  finalize ();
}

void
tag_box_rep::collect_page_numbers (hashmap<string,tree>& h, tree page) {
  h (name)= page;
  bs[0]->collect_page_numbers (h, page);
}

path
tag_box_rep::find_tag (string search) {
  if (name == search)
    return revert (descend_decode (ip, 1));
  return path ();
}

/******************************************************************************
* box construction routines
******************************************************************************/

box
move_box (path ip, box b, SI x, SI y, bool child_flag, bool big_flag) {
  return new move_box_rep (ip, b, x, y, child_flag, big_flag);
}

box
resize_box (path ip, box b, SI x1, SI y1, SI x2, SI y2,
	    bool child_flag, bool adjust) {
  return new resize_box_rep (ip, b, x1, y1, x2, y2, child_flag, adjust);
}

box
vcorrect_box (path ip, box b, SI top_cor, SI bot_cor) {
  return new vcorrect_box_rep (ip, b, top_cor, bot_cor);
}

box
repeat_box (path ip, box ref, box repeat, SI xoff) {
  return new repeat_box_rep (ip, ref, repeat, xoff);
}

box
cell_box (path ip, box b, SI x0, SI y0, SI x1, SI y1, SI x2, SI y2,
	  SI bl, SI br, SI bb, SI bt, int corr,
	  color fg, color bg, bool transp)
{
  return new cell_box_rep (ip, b, x0, y0, x1, y1, x2, y2,
			   bl, br, bb, bt, corr,
			   fg, bg, transp);
}

box
action_box (path ip, box b, command cmd, bool child_flag) {
  return new action_box_rep (ip, b, cmd, child_flag);
}

box
tag_box (path ip, box b, string name) {
  return new tag_box_rep (ip, b, name);
}

#endmodule // code_change_boxes
