In my quest to have a layout manager in fltk, I found that Fl_Group 
already save it's children sizes to later resize/scale then in it's 
member field "int *sizes_;".

In my opnion for fltk to do the resize/scale properly it should change 
labels font as well text font and the ideal place to do it is together 
with the already saved "x,w,y,h" in sizes_.

Saving then on a "int *" is not flexible enough to allow extend what's 
saved without breaking already existing code, so I propose to change it to:

struct st_widget_sizes {
     int x,y,w,h;
};

That later (or right now with the help of cheap_rtti) can be extended to:

struct st_widget_sizes {
     int x,y,w,h;
     Fl_Fontsize label_size, text_size;
};

I already did the necessary changes to fltk 1.3 trunk and everything 
compile and works as before and I think it's more readable.

Changes:

Fl_Group.H:

....
struct st_widget_sizes {
     int x,y,w,h;
};

/**
   The Fl_Group class is the FLTK container widget. It maintains
   an array of child widgets. These children can themselves be any widget
   including Fl_Group. The most important subclass of Fl_Group
   is Fl_Window, however groups can also be used to control radio buttons
   or to enforce resize behavior.
*/
...
   int children_;
//bellow changed from int*
   st_widget_sizes *sizes_; // remembered initial sizes of children
...
   void update_child(Fl_Widget& widget) const;
//bellow changed from int*
   st_widget_sizes  *sizes();
...

Fl_Group.cxx:

...
st_widget_sizes* Fl_Group::sizes() {
   if (!sizes_) {
     //int* p = sizes_ = new int[4*(children_+2)];
     st_widget_sizes* p = sizes_ = new st_widget_sizes[(children_+2)];
     // first thing in sizes array is the group's size:
     if (type() < FL_WINDOW) {p->x = x(); p->y = y();} else {p->x = p->y 
= 0;}
     p->w = p->x+w(); p->h = p->y+h();
     // next is the resizable's size:
     ++p;
     p->x = sizes_->x; // init to the group's size
     p->w = sizes_->w;
     p->y = sizes_->y;
     p->h = sizes_->h;
     Fl_Widget* r = resizable();
     if (r && r != this) { // then clip the resizable to it
       int t;
       t = r->x(); if (t > sizes_->x) p->x = t;
       t +=r->w(); if (t < sizes_->w) p->w = t;
       t = r->y(); if (t > sizes_->y) p->y = t;
       t +=r->h(); if (t < sizes_->h) p->h = t;
     }
     // next is all the children's sizes:
     ++p;
     Fl_Widget*const* a = array();
     for (int i=children_; i--;) {
       Fl_Widget* o = *a++;
       p->x = o->x();
       p->w = o->x()+o->w();
       p->y = o->y();
       p->h = o->y()+o->h();
       ++p;
     }
   }
   return sizes_;
}
...
void Fl_Group::resize(int X, int Y, int W, int H) {

   int dx = X-x();
   int dy = Y-y();
   int dw = W-w();
   int dh = H-h();

   st_widget_sizes *p = sizes(); // save initial sizes and positions

   Fl_Widget::resize(X,Y,W,H); // make new xywh values visible for children

   if (!resizable() || dw==0 && dh==0 ) {

     if (type() < FL_WINDOW) {
       Fl_Widget*const* a = array();
       for (int i=children_; i--;) {
        Fl_Widget* o = *a++;
        o->resize(o->x()+dx, o->y()+dy, o->w(), o->h());
       }
     }

   } else if (children_) {

     // get changes in size/position from the initial size:
     dx = X - p->x;
     dw = W - (p->w - p->x);
     dy = Y - p->y;
     dh = H - (p->h - p->y);
     if (type() >= FL_WINDOW) dx = dy = 0;
     ++p;

     // get initial size of resizable():
     int IX = p->x;
     int IR = p->w;
     int IY = p->y;
     int IB = p->h;
     ++p;

     Fl_Widget*const* a = array();
     for (int i=children_; i--;) {
       Fl_Widget* o = *a++;
#if 1
       int XX = p->x;
       if (XX >= IR) XX += dw;
       else if (XX > IX) XX = IX+((XX-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX);
       int R = p->w;
       if (R >= IR) R += dw;
       else if (R > IX) R = IX+((R-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX);

       int YY = p->y;
       if (YY >= IB) YY += dh;
       else if (YY > IY) YY = IY+((YY-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY);
       int B = p->h;
       if (B >= IB) B += dh;
       else if (B > IY) B = IY+((B-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY);
#else // much simpler code from Francois Ostiguy:
       int XX = p->x;
       if (XX >= IR) XX += dw;
       else if (XX > IX) XX += dw * (XX-IX)/(IR-IX);
       int R = p->w;
       if (R >= IR) R += dw;
       else if (R > IX) R = R + dw * (R-IX)/(IR-IX);

       int YY = p->y;
       if (YY >= IB) YY += dh;
       else if (YY > IY) YY = YY + dh*(YY-IY)/(IB-IY);
       int B = p->h;
       if (B >= IB) B += dh;
       else if (B > IY) B = B + dh*(B-IY)/(IB-IY);
#endif
       o->resize(XX+dx, YY+dy, R-XX, B-YY);
       ++p;
     }
   }
}
...

Fl_Tile.cxx:

...
void Fl_Tile::position(int oix, int oiy, int newx, int newy) {
   Fl_Widget*const* a = array();
   //int *p = sizes();
   st_widget_sizes *p = sizes();
   //p += 8; // skip group & resizable's saved size
   p += 2; // skip group & resizable's saved size
   for (int i=children(); i--; ++p) {
     Fl_Widget* o = *a++;
     if (o == resizable()) continue;
     int X = o->x();
     int R = X+o->w();
     if (oix) {
       int t = p->x;
       if (t == oix || t>oix && X<newx || t<oix && X>newx) X = newx;
       t = p->w;
       if (t == oix || t>oix && R<newx || t<oix && R>newx) R = newx;
     }
     int Y = o->y();
     int B = Y+o->h();
     if (oiy) {
       int t = p->y;
       if (t == oiy || t>oiy && Y<newy || t<oiy && Y>newy) Y = newy;
       t = p->h;
       if (t == oiy || t>oiy && B<newy || t<oiy && B>newy) B = newy;
     }
     o->damage_resize(X,Y,R-X,B-Y);
   }
}
...
void Fl_Tile::resize(int X,int Y,int W,int H) {
   //Fl_Group::resize(X, Y, W, H);
   //return;
   // remember how much to move the child widgets:
   int dx = X-x();
   int dy = Y-y();
   int dw = W-w();
   int dh = H-h();
   //int *p = sizes();
   st_widget_sizes *p = sizes();
   // resize this (skip the Fl_Group resize):
   Fl_Widget::resize(X,Y,W,H);
   // find bottom-right of resiable:
   int OR = (p+1)->w;
   int NR = X+W-(p->w-OR);
   int OB = (p+1)->h;
   int NB = Y+H-(p->h-OB);
   // move everything to be on correct side of new resizable:
   Fl_Widget*const* a = array();
   p += 2;
   for (int i=children(); i--; ++p) {
     Fl_Widget* o = *a++;
     int xx = o->x()+dx;
     int R = xx+o->w();
     if (p->x >= OR) xx += dw; else if (xx > NR) xx = NR;
     if (p->w >= OR) R += dw; else if (R > NR) R = NR;
     int yy = o->y()+dy;
     int B = yy+o->h();
     if (p->y >= OB) yy += dh; else if (yy > NB) yy = NB;
     if (p->h >= OB) B += dh; else if (B > NB) B = NB;
     o->resize(xx,yy,R-xx,B-yy);
     // do *not* call o->redraw() here! If you do, and the tile is inside a
     // scroll, it'll set the damage areas wrong for all children!
   }
}
...
int Fl_Tile::handle(int event) {
   static int sdrag;
   static int sdx, sdy;
   static int sx, sy;
#define DRAGH 1
#define DRAGV 2
#define GRABAREA 4

   int mx = Fl::event_x();
   int my = Fl::event_y();

   switch (event) {

   case FL_MOVE:
   case FL_ENTER:
   case FL_PUSH:
     // don't potentially change the mouse cursor if inactive:
     if (!active()) break; // will cascade inherited handle()
     {
     int mindx = 100;
     int mindy = 100;
     int oldx = 0;
     int oldy = 0;
     Fl_Widget*const* a = array();
     //int *q = sizes();
     //int *p = q+8;
     st_widget_sizes *q = sizes();
     st_widget_sizes *p = q+2;
     for (int i=children(); i--; ++p) {
       Fl_Widget* o = *a++;
       if (o == resizable()) continue;
       if (p->w < q->w && o->y()<=my+GRABAREA && 
o->y()+o->h()>=my-GRABAREA) {
        int t = mx - (o->x()+o->w());
        if (abs(t) < mindx) {
          sdx = t;
          mindx = abs(t);
          oldx = p->w;
        }
       }
       if (p->h < q->h && o->x()<=mx+GRABAREA && 
o->x()+o->w()>=mx-GRABAREA) {
        int t = my - (o->y()+o->h());
        if (abs(t) < mindy) {
          sdy = t;
          mindy = abs(t);
          oldy = p->h;
        }
       }
     }
     sdrag = 0; sx = sy = 0;
     if (mindx <= GRABAREA) {sdrag = DRAGH; sx = oldx;}
     if (mindy <= GRABAREA) {sdrag |= DRAGV; sy = oldy;}
     set_cursor(this, cursors[sdrag]);
     if (sdrag) return 1;
     return Fl_Group::handle(event);
   }

   case FL_LEAVE:
     set_cursor(this, FL_CURSOR_DEFAULT);
     break;

   case FL_DRAG:
     // This is necessary if CONSOLIDATE_MOTION in Fl_x.cxx is turned off:
     // if (damage()) return 1; // don't fall behind
   case FL_RELEASE: {
     if (!sdrag) return 0; // should not happen
     Fl_Widget* r = resizable(); if (!r) r = this;
     int newx;
     if (sdrag&DRAGH) {
       newx = Fl::event_x()-sdx;
       if (newx < r->x()) newx = r->x();
       else if (newx > r->x()+r->w()) newx = r->x()+r->w();
     } else
       newx = sx;
     int newy;
     if (sdrag&DRAGV) {
       newy = Fl::event_y()-sdy;
       if (newy < r->y()) newy = r->y();
       else if (newy > r->y()+r->h()) newy = r->y()+r->h();
     } else
       newy = sy;
     position(sx,sy,newx,newy);
     if (event == FL_DRAG) set_changed();
     do_callback();
     return 1;}

   }

   return Fl_Group::handle(event);
}
_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to