Post by Greg ErcolanoI made one of these once; in my case I didn't use a tile,
just used a regular Fl_Group in which the widgets were positioned,
1) enlarged/shrunk the widget above it
2) enlarged/shrunk the parent group
3) moved all the children below it up/down
Post by dirac+---Fl_tile-------------------+
| +-------------------------+ |
| | | |
| | widget 0 | |
| | | |
| +-------------------------+ |
| | resizer | |
| +-------------------------+ |
| | | |
| | widget 1 | |
| | | |
| +-------------------------+ |
| | resizer | |
| +-------------------------+ |
| | | |
| | widget 2 | |
| | | |
| +-------------------------+ |
+-----------------------------+
Here's an example implementation of the above based on an older work.
This assumes the parent is an *Fl_Scroll*.
This is so that widgets off-screen can be reached with a scroll bar.
The ResizerButton class is what you would use in your app.
The main() below it shows how to use it.
The example code creates 10 Fl_Box widgets with a resizer below each.
You can drag the resizers around to change the size of the widget above;
the other widgets below will be moved around inside the scroller to accommodate.
Scrollbars will appear for widgets that are off-screen.
--- snip
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/fl_draw.h>
#include <stdio.h>
//
// Demonstrate a resizer class for widgets in an Fl_Scroll
// erco 1.0 ??/??/04 - original test program
// erco 1.1 04/21/13 - modernized
//
// CLASS FOR HANDLING A 'RESIZER' BETWEEN WIDGETS IN AN Fl_Scroll
//
// > Shows a resize cursor when hovered over
// > Assumes: * Parent is an Fl_Scroll
// * All children of Fl_Scroll are vertically arranged
// * The widget above us has a bottom edge touching our top edge
// ie. (w->y()+w->h() == this->y())
//
// > When this widget is dragged:
// * The widget above us (with a common edge) will be /resized/ vertically
// * All children below us will be /moved/ vertically
//
class ResizerButton : public Fl_Button {
int orig_h;
int last_y;
int min_h; // min height for widget above us
void HandleDrag(int diff) {
Fl_Scroll *grp = (Fl_Scroll*)parent();
int top = y();
int bot = y()+h();
// First pass: find widget directly above us with common edge
// Possibly clamp 'diff' if widget would get too small..
//
for ( int t=0; t<grp->children(); t++ ) {
Fl_Widget *w = grp->child(t);
if ( (w->y()+w->h()) == top ) { // found widget directly above?
if ( (w->h()+diff) < min_h ) diff = w->h() - min_h; // clamp
w->resize(w->x(), w->y(), w->w(), w->h()+diff); // change height
break; // done with first pass
}
}
// Second pass: find widgets below us, move based on clamped diff
for ( int t=0; t<grp->children(); t++ ) {
Fl_Widget *w = grp->child(t);
if ( w->y() >= bot ) // found widget below us?
w->resize(w->x(), w->y()+diff, w->w(), w->h()); // change position
}
// Change our position last
resize(x(),y()+diff,w(),h());
grp->init_sizes();
grp->redraw();
}
public:
ResizerButton(int X,int Y,int W,int H) : Fl_Button(X,Y,W,H,"///////") {
orig_h = H;
last_y = 0;
min_h = 10;
align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
labelfont(FL_COURIER);
labelsize(6);
}
void SetMinHeight(int val) { min_h = val; }
int GetMinHeight() const { return min_h; }
int handle(int e) {
int ret = 0;
int this_y = Fl::event_y_root();
switch (e) {
case FL_FOCUS: ret = 1; break;
case FL_ENTER: ret = 1; fl_cursor(FL_CURSOR_NS); break;
case FL_LEAVE: ret = 1; fl_cursor(FL_CURSOR_DEFAULT); break;
case FL_PUSH: ret = 1; last_y = this_y; break;
case FL_DRAG:
HandleDrag(this_y-last_y);
last_y = this_y;
ret = 1;
break;
default: break;
}
return(Fl_Button::handle(e) | ret);
}
void resize(int X,int Y,int W,int H) {
Fl_Button::resize(X,Y,W,orig_h); // height of resizer stays constant size
}
};
// Demonstrate the ResizerButton class above
// Creates 10 Fl_Box widgets with a resizer below each.
// User can drag the resizers around to change the size of the widget above it.
// The other widgets below will be moved around inside the scroller to accommodate.
//
int main(int argc, char** argv) {
Fl_Window win(220,400);
win.begin();
Fl_Scroll scr(0,0,220,400);
scr.begin();
// Create 10 boxes with resizer between each
for ( int i=0; i<10; i++ ) {
// Create a box..
char s[10]; sprintf(s, "%c%c%c", 'A'+i,'a'+i,'a'+i); // 'unique' label
Fl_Box *b = new Fl_Box (0,i*50,200,40);
b->copy_label(s);
b->box(FL_FLAT_BOX);
b->color(FL_WHITE);
b->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
// And put a Resizer directly below it with a common edge. (The common edge is important)
new ResizerButton(0,b->y()+b->h(),200,10);
}
scr.end();
win.end();
win.resizable(scr);
win.show();
return(Fl::run());
}