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