FLUID: Adds grid child positioning via +/- keys

This commit is contained in:
Matthias Melcher 2023-10-23 00:44:26 +02:00
parent 6cc3eb32db
commit d573bfe799
5 changed files with 195 additions and 81 deletions

View File

@ -187,7 +187,7 @@ public:
Fl_Grid_Align align() const { return align_; }
void minimum_size(int w, int h) { if (w>=0) w_ = w; if (h>=0) h_ = h; }
void minimum_size(int *w, int *h) { if (w) *w = w_; if (h) *h = h_; }
void minimum_size(int *w, int *h) const { if (w) *w = w_; if (h) *h = h_; }
}; // class Cell
private:

View File

@ -400,38 +400,55 @@ Fl_Grid *Fl_Grid_Type::selected() {
return NULL;
}
extern Fluid_Coord_Input *widget_grid_row_input, *widget_grid_col_input;
extern Fluid_Coord_Input *widget_grid_row_input, *widget_grid_col_input,
*widget_grid_rowspan_input, *widget_grid_colspan_input;
extern Fl_Group *widget_tab_grid_child;
// FIXME: when changing row or col or moving a cell in any other way, we need
// to copy all attributes from the old cell, or they will be lost
// FIXME: changing a single row or col value should not move the cell, or we
// may overwrite other cells
// FIXME: when changing the cell location, activate a button [move] to actually
// move the cell there. If it would replace another cell, show a
// [replace] button instead that my be bright red
// TODO: update the row and col widgets when the cell changes location
static void move_cell(Fl_Grid *grid, Fl_Widget *child, int to_row, int to_col) {
short rowspan = 1, colspan = 1;
Fl_Grid_Align align = FL_GRID_FILL;
int w = 20, h = 20;
const Fl_Grid::Cell *old_cell = grid->cell(child);
if (old_cell) {
rowspan = old_cell->rowspan();
colspan = old_cell->colspan();
align = old_cell->align();
old_cell->minimum_size(&w, &h);
}
if ((to_row<0) || (to_row+rowspan>grid->rows())) return;
if ((to_col<0) || (to_col+colspan>grid->cols())) return;
Fl_Grid::Cell *new_cell = grid->widget(child, to_row, to_col, rowspan, colspan, align);
if (new_cell) new_cell->minimum_size(w, h);
}
// FIXME: when changing the cell location, and another cell would be overridden,
// don't actually move the cell (hard to implement!) and activate
// a red button "replace". If clicked, user gets the option to delete
// the old widget, or just remove the cell, or cancel.
// TODO: move cells by using the arrow keys?
// TODO: move cells via drag'n'drop
// TODO: insert cells when adding them from the menu or toolbar
// TODO: better grid overlay?
// TODO: handle illegal values in all cells
// TODO: maybe increment, decrement buttons for cell locations as they only change in increments?
// TODO: we could even use formulas for moving multiple cells in one go
// TODO: grid_child_cb should move all selected cells.
// TODO: buttons to add and delete rows and columns in the widget dialog
// TODO: ways to resize rows and columns, add and delete them in the project window, pulldown menu?
// TODO: alignment can be FL_GRID_LEFT|FL_GRID_VERTICAL?
void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
static Fl_Widget *prev_widget = NULL;
if ( !current_widget
|| !current_widget->parent
|| !current_widget->parent->is_a(ID_Grid))
{
return;
}
Fl_Widget *child = ((Fl_Widget_Type*)current_widget)->o;
Fl_Grid *g = ((Fl_Grid*)((Fl_Widget_Type*)current_widget->parent)->o);
Fl_Grid::Cell *cell = g->cell(child);
bool freeze_row_col = (!cell && prev_widget==child && ((what&0x00ff)==8 || (what&0x00ff)==9));
if (v == LOAD) {
int v = -1;
Fl_Grid::Cell *cell = g->cell(current_widget->o);
if (cell) {
switch (what) {
switch (what & 0x00ff) {
case 8: v = cell->row(); break;
case 9: v = cell->col(); break;
case 10: v = cell->rowspan(); break;
@ -440,15 +457,17 @@ void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
case 13: cell->minimum_size(NULL, &v); break;
}
}
i->value(v);
if (!cell && prev_widget!=child && what==11)
prev_widget = child;
if (!freeze_row_col)
i->value(v);
} else {
int v2 = -1, old_v = -1, v = i->value();
if (i==widget_grid_row_input) v2 = widget_grid_col_input->value();
if (i==widget_grid_col_input) v2 = widget_grid_row_input->value();
Fl_Grid::Cell *cell = g->cell(current_widget->o);
Fl_Grid::Cell *new_cell = NULL;
if (cell) {
switch (what) {
switch (what & 0x00ff) {
case 8: old_v = cell->row(); v2 = cell->col(); break;
case 9: old_v = cell->col(); v2 = cell->row(); break;
case 10: old_v = cell->rowspan(); break;
@ -457,34 +476,91 @@ void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
case 13: cell->minimum_size(&v2, &old_v); break;
}
}
switch (what & 0xff00) {
case 0x0100: v--; break;
case 0x0200: v++; break;
}
if (old_v != v) {
switch (what) {
case 8: if (v>=0 && v2>=0) new_cell = g->widget(current_widget->o, v, v2); break;
case 9: if (v>=0 && v2>=0) new_cell = g->widget(current_widget->o, v2, v); break;
case 10: if (cell) cell->rowspan(v); break;
case 11: if (cell) cell->colspan(v); break;
switch (what & 0x00ff) {
case 8: if (v>=0 && v2>=0) move_cell(g, current_widget->o, v, v2);
if (freeze_row_col) i->value(v); break;
case 9: if (v>=0 && v2>=0) move_cell(g, current_widget->o, v2, v);
if (freeze_row_col) i->value(v); break;
case 10: if (cell && cell->row()+v<=g->rows()) cell->rowspan(v); break;
case 11: if (cell && cell->col()+v<=g->cols()) cell->colspan(v); break;
case 12: if (cell) cell->minimum_size(v, v2); break;
case 13: if (cell) cell->minimum_size(v2, v); break;
}
if (!cell && new_cell)
new_cell->minimum_size(20, 20);
g->need_layout(true);
g->redraw();
set_modflag(1);
}
}
}
void grid_set_row_cb(Fluid_Coord_Input* i, void* v) {
grid_child_cb(i, v, 8);
if (v!=LOAD) widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
void grid_dec_row_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_row_input, v, 0x0100 + 8);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_inc_row_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_row_input, v, 0x0200 + 8);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_set_col_cb(Fluid_Coord_Input* i, void* v) {
grid_child_cb(i, v, 9);
if (v!=LOAD) widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
void grid_dec_col_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_col_input, v, 0x0100 + 9);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_inc_col_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_col_input, v, 0x0200 + 9);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_set_rowspan_cb(Fluid_Coord_Input* i, void* v) {
grid_child_cb(i, v, 10);
if (v!=LOAD) widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
void grid_dec_rowspan_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_rowspan_input, v, 0x0100 + 10);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_inc_rowspan_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_rowspan_input, v, 0x0200 + 10);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_set_colspan_cb(Fluid_Coord_Input* i, void* v) {
grid_child_cb(i, v, 11);
if (v!=LOAD) widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
void grid_dec_colspan_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_colspan_input, v, 0x0100 + 11);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_inc_colspan_cb(Fl_Button* i, void* v) {
if (v!=LOAD) {
grid_child_cb(widget_grid_colspan_input, v, 0x0200 + 11);
widget_tab_grid_child->do_callback(widget_tab_grid_child, LOAD);
}
}
void grid_set_min_wdt_cb(Fluid_Coord_Input* i, void* v) {
grid_child_cb(i, v, 12);

View File

@ -27,7 +27,7 @@ Fl_Double_Window* make_window() {
Fl_Double_Window* w;
{ Fl_Double_Window* o = new Fl_Double_Window(480, 320);
w = o; (void)w;
{ Fl_Grid* o = new Fl_Grid(25, 25, 240, 160);
{ Fl_Grid* o = new Fl_Grid(25, 25, 262, 160);
o->labelsize(11);
o->layout(3, 3);
o->margin(10, 8, 11, 12);
@ -39,7 +39,7 @@ Fl_Double_Window* make_window() {
o->col_weight(colweights, 3);
static const int colgaps[] = { 1, 3, -1 };
o->col_gap(colgaps, 3);
{ Fl_Button* o = new Fl_Button(77, 75, 133, 59, "Button");
{ Fl_Button* o = new Fl_Button(85, 75, 139, 59, "Button");
o->labelsize(11);
} // Fl_Button* o
Fl_Grid::Cell *cell = NULL;
@ -168,6 +168,10 @@ Fl_Menu_Item menu_5[] = {
{0,0,0,0,0,0,0,0,0}
};
Fluid_Coord_Input *widget_grid_rowspan_input=(Fluid_Coord_Input *)0;
Fluid_Coord_Input *widget_grid_colspan_input=(Fluid_Coord_Input *)0;
Fl_Group *widget_tab_grid=(Fl_Group *)0;
Fluid_Coord_Input *widget_grid_rows=(Fluid_Coord_Input *)0;
@ -560,6 +564,7 @@ Fl_Double_Window* make_widget_panel() {
o->labelsize(11);
o->callback((Fl_Callback*)propagate_load);
o->when(FL_WHEN_NEVER);
o->hide();
{ Fl_Group* o = new Fl_Group(95, 40, 309, 20, "Label:");
o->labelfont(1);
o->labelsize(11);
@ -1433,7 +1438,6 @@ access the Widget pointer and \'v\' to access the user value.");
{ widget_tab_grid_child = new Fl_Group(10, 30, 400, 330, "Grid Child");
widget_tab_grid_child->labelsize(11);
widget_tab_grid_child->callback((Fl_Callback*)propagate_load);
widget_tab_grid_child->hide();
{ Fl_Group* o = new Fl_Group(95, 60, 315, 20, "Location:");
o->labelfont(1);
o->labelsize(11);
@ -1456,12 +1460,14 @@ access the Widget pointer and \'v\' to access the user value.");
{ Fl_Button* o = new Fl_Button(135, 60, 15, 20, "-");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_dec_row_cb);
o->clear_visible_focus();
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(150, 60, 15, 20, "+");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_inc_row_cb);
o->clear_visible_focus();
} // Fl_Button* o
o->end();
} // Fl_Group* o
@ -1482,12 +1488,14 @@ access the Widget pointer and \'v\' to access the user value.");
{ Fl_Button* o = new Fl_Button(215, 60, 15, 20, "-");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_dec_col_cb);
o->clear_visible_focus();
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(230, 60, 15, 20, "+");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_inc_col_cb);
o->clear_visible_focus();
} // Fl_Button* o
o->end();
} // Fl_Group* o
@ -1553,60 +1561,64 @@ access the Widget pointer and \'v\' to access the user value.");
} // Fl_Box* o
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(95, 160, 315, 20, "Cell Span:");
{ Fl_Group* o = new Fl_Group(95, 160, 315, 20, "Span:");
o->labelfont(1);
o->labelsize(11);
o->callback((Fl_Callback*)propagate_load);
o->align(Fl_Align(FL_ALIGN_LEFT));
{ Fluid_Coord_Input* o = new Fluid_Coord_Input(95, 160, 40, 20, "Rows:");
o->box(FL_DOWN_BOX);
o->color(FL_BACKGROUND2_COLOR);
o->selection_color(FL_SELECTION_COLOR);
o->labeltype(FL_NORMAL_LABEL);
o->labelfont(0);
o->labelsize(11);
o->labelcolor(FL_FOREGROUND_COLOR);
o->textsize(11);
o->callback((Fl_Callback*)grid_set_rowspan_cb);
o->align(Fl_Align(FL_ALIGN_TOP_LEFT));
o->when(FL_WHEN_RELEASE);
} // Fluid_Coord_Input* o
{ widget_grid_rowspan_input = new Fluid_Coord_Input(95, 160, 40, 20, "Row Span:");
widget_grid_rowspan_input->box(FL_DOWN_BOX);
widget_grid_rowspan_input->color(FL_BACKGROUND2_COLOR);
widget_grid_rowspan_input->selection_color(FL_SELECTION_COLOR);
widget_grid_rowspan_input->labeltype(FL_NORMAL_LABEL);
widget_grid_rowspan_input->labelfont(0);
widget_grid_rowspan_input->labelsize(11);
widget_grid_rowspan_input->labelcolor(FL_FOREGROUND_COLOR);
widget_grid_rowspan_input->textsize(11);
widget_grid_rowspan_input->callback((Fl_Callback*)grid_set_rowspan_cb);
widget_grid_rowspan_input->align(Fl_Align(FL_ALIGN_TOP_LEFT));
widget_grid_rowspan_input->when(FL_WHEN_RELEASE);
} // Fluid_Coord_Input* widget_grid_rowspan_input
{ Fl_Group* o = new Fl_Group(135, 160, 30, 20);
{ Fl_Button* o = new Fl_Button(135, 160, 15, 20, "-");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_dec_rowspan_cb);
o->clear_visible_focus();
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(150, 160, 15, 20, "+");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_inc_rowspan_cb);
o->clear_visible_focus();
} // Fl_Button* o
o->end();
} // Fl_Group* o
{ Fluid_Coord_Input* o = new Fluid_Coord_Input(175, 160, 40, 20, "Columns:");
o->box(FL_DOWN_BOX);
o->color(FL_BACKGROUND2_COLOR);
o->selection_color(FL_SELECTION_COLOR);
o->labeltype(FL_NORMAL_LABEL);
o->labelfont(0);
o->labelsize(11);
o->labelcolor(FL_FOREGROUND_COLOR);
o->textsize(11);
o->callback((Fl_Callback*)grid_set_colspan_cb);
o->align(Fl_Align(FL_ALIGN_TOP_LEFT));
o->when(FL_WHEN_RELEASE);
} // Fluid_Coord_Input* o
{ widget_grid_colspan_input = new Fluid_Coord_Input(175, 160, 40, 20, "Col. Span:");
widget_grid_colspan_input->box(FL_DOWN_BOX);
widget_grid_colspan_input->color(FL_BACKGROUND2_COLOR);
widget_grid_colspan_input->selection_color(FL_SELECTION_COLOR);
widget_grid_colspan_input->labeltype(FL_NORMAL_LABEL);
widget_grid_colspan_input->labelfont(0);
widget_grid_colspan_input->labelsize(11);
widget_grid_colspan_input->labelcolor(FL_FOREGROUND_COLOR);
widget_grid_colspan_input->textsize(11);
widget_grid_colspan_input->callback((Fl_Callback*)grid_set_colspan_cb);
widget_grid_colspan_input->align(Fl_Align(FL_ALIGN_TOP_LEFT));
widget_grid_colspan_input->when(FL_WHEN_RELEASE);
} // Fluid_Coord_Input* widget_grid_colspan_input
{ Fl_Group* o = new Fl_Group(215, 160, 30, 20);
{ Fl_Button* o = new Fl_Button(215, 160, 15, 20, "-");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_dec_colspan_cb);
o->clear_visible_focus();
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(230, 160, 15, 20, "+");
o->compact(1);
o->labelsize(11);
o->hide();
o->callback((Fl_Callback*)grid_inc_colspan_cb);
o->clear_visible_focus();
} // Fl_Button* o
o->end();
} // Fl_Group* o

View File

@ -49,7 +49,7 @@ Function {make_window()} {open
xywh {867 441 480 320} type Double visible
} {
Fl_Grid {} {open
xywh {25 25 240 160} labelsize 11
xywh {25 25 262 160} labelsize 11
dimensions {3 3} margin {10 8 11 12}
rowgaps { 3 -1 -1 }
colwidths { 0 100 0 }
@ -57,8 +57,8 @@ Function {make_window()} {open
colgaps { 1 3 -1 }
} {
Fl_Button {} {
label Button
xywh {77 75 133 59} labelsize 11
label Button selected
xywh {85 75 139 59} labelsize 11
parent_properties {
location {1 1}
}
@ -82,8 +82,8 @@ Function {make_widget_panel()} {
} {
Fl_Group {} {
label GUI
callback propagate_load selected
xywh {10 30 400 330} labelsize 11 when 0 resizable
callback propagate_load
xywh {10 30 400 330} labelsize 11 when 0 hide resizable
} {
Fl_Group {} {
label {Label:}
@ -859,7 +859,7 @@ wCallback->do_callback(wCallback, v);} open
Fl_Group widget_tab_grid_child {
label {Grid Child}
callback propagate_load open
xywh {10 30 400 330} labelsize 11 hide
xywh {10 30 400 330} labelsize 11
} {
Fl_Group {} {
label {Location:}
@ -877,11 +877,15 @@ wCallback->do_callback(wCallback, v);} open
} {
Fl_Button {} {
label {-}
xywh {135 60 15 20} labelsize 11 hide compact 1
callback grid_dec_row_cb
xywh {135 60 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
Fl_Button {} {
label {+}
xywh {150 60 15 20} labelsize 11 hide compact 1
callback grid_inc_row_cb
xywh {150 60 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
}
Fl_Input widget_grid_col_input {
@ -895,11 +899,15 @@ wCallback->do_callback(wCallback, v);} open
} {
Fl_Button {} {
label {-}
xywh {215 60 15 20} labelsize 11 hide compact 1
callback grid_dec_col_cb
xywh {215 60 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
Fl_Button {} {
label {+}
xywh {230 60 15 20} labelsize 11 hide compact 1
callback grid_inc_col_cb
xywh {230 60 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
}
Fl_Box {} {
@ -1002,12 +1010,12 @@ wCallback->do_callback(wCallback, v);} open
}
}
Fl_Group {} {
label {Cell Span:}
label {Span:}
callback propagate_load open
xywh {95 160 315 20} labelfont 1 labelsize 11 align 4
} {
Fl_Input {} {
label {Rows:}
Fl_Input widget_grid_rowspan_input {
label {Row Span:}
callback grid_set_rowspan_cb
xywh {95 160 40 20} labelsize 11 align 5 textsize 11
class Fluid_Coord_Input
@ -1017,15 +1025,19 @@ wCallback->do_callback(wCallback, v);} open
} {
Fl_Button {} {
label {-}
xywh {135 160 15 20} labelsize 11 hide compact 1
callback grid_dec_rowspan_cb
xywh {135 160 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
Fl_Button {} {
label {+}
xywh {150 160 15 20} labelsize 11 hide compact 1
callback grid_inc_rowspan_cb
xywh {150 160 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
}
Fl_Input {} {
label {Columns:}
Fl_Input widget_grid_colspan_input {
label {Col. Span:}
callback grid_set_colspan_cb
xywh {175 160 40 20} labelsize 11 align 5 textsize 11
class Fluid_Coord_Input
@ -1035,11 +1047,15 @@ wCallback->do_callback(wCallback, v);} open
} {
Fl_Button {} {
label {-}
xywh {215 160 15 20} labelsize 11 hide compact 1
callback grid_dec_colspan_cb
xywh {215 160 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
Fl_Button {} {
label {+}
xywh {230 160 15 20} labelsize 11 hide compact 1
callback grid_inc_colspan_cb
xywh {230 160 15 20} labelsize 11
code0 {o->clear_visible_focus();} compact 1
}
}
Fl_Box {} {

View File

@ -139,13 +139,23 @@ extern Fl_Box *w_when_box;
extern Fl_Group *widget_tab_grid_child;
extern void grid_set_row_cb(Fluid_Coord_Input*, void*);
extern Fluid_Coord_Input *widget_grid_row_input;
extern void grid_dec_row_cb(Fl_Button*, void*);
extern void grid_inc_row_cb(Fl_Button*, void*);
extern void grid_set_col_cb(Fluid_Coord_Input*, void*);
extern Fluid_Coord_Input *widget_grid_col_input;
extern void grid_dec_col_cb(Fl_Button*, void*);
extern void grid_inc_col_cb(Fl_Button*, void*);
extern void grid_align_cb(Fl_Choice*, void*);
extern void grid_set_min_wdt_cb(Fluid_Coord_Input*, void*);
extern void grid_set_min_hgt_cb(Fluid_Coord_Input*, void*);
extern void grid_set_rowspan_cb(Fluid_Coord_Input*, void*);
extern Fluid_Coord_Input *widget_grid_rowspan_input;
extern void grid_dec_rowspan_cb(Fl_Button*, void*);
extern void grid_inc_rowspan_cb(Fl_Button*, void*);
extern void grid_set_colspan_cb(Fluid_Coord_Input*, void*);
extern Fluid_Coord_Input *widget_grid_colspan_input;
extern void grid_dec_colspan_cb(Fl_Button*, void*);
extern void grid_inc_colspan_cb(Fl_Button*, void*);
extern Fl_Group *widget_tab_grid;
extern Fluid_Coord_Input *widget_grid_rows;
extern Fluid_Coord_Input *widget_grid_cols;