From 17baeceb7ab90251f99c7909eb9eeca92aec5a05 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Mon, 23 Oct 2023 01:36:55 +0200 Subject: FLUID: Positioning grid cells intuitively. User can now drag widgets from the toolbox into the grid or use the context menu to add them into the corresponding cell. If no position is indicated, now children are added at the first free cell. --- FL/Fl_Grid.H | 3 +++ fluid/Fl_Grid_Type.cxx | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- fluid/Fl_Grid_Type.h | 2 ++ fluid/factory.cxx | 8 ++++++++ src/Fl_Grid.cxx | 8 ++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/FL/Fl_Grid.H b/FL/Fl_Grid.H index d7d90e352..b240ca95b 100644 --- a/FL/Fl_Grid.H +++ b/FL/Fl_Grid.H @@ -311,6 +311,9 @@ public: void row_gap(const int *value, size_t size); int row_gap(int row) const; + int computed_col_width(int col) const; + int computed_row_height(int row) const; + /** Enable or disable drawing of the grid helper lines for visualization. diff --git a/fluid/Fl_Grid_Type.cxx b/fluid/Fl_Grid_Type.cxx index 4ce0991d9..1ec831c7c 100644 --- a/fluid/Fl_Grid_Type.cxx +++ b/fluid/Fl_Grid_Type.cxx @@ -421,18 +421,62 @@ static void move_cell(Fl_Grid *grid, Fl_Widget *child, int to_row, int to_col) { if (new_cell) new_cell->minimum_size(w, h); } +void Fl_Grid_Type::insert_child_at(Fl_Widget *child, int x, int y) { + Fl_Grid *grid = (Fl_Grid*)o; + int row = -1, col = -1, ml, mt, grg, gcg; + grid->margin(&ml, &mt, NULL, NULL); + grid->gap(&grg, &gcg); + int x0 = grid->x() + Fl::box_dx(grid->box()) + ml; + int y0 = grid->y() + Fl::box_dy(grid->box()) + mt; + + for (int r = 0; r < grid->rows(); r++) { + if (y>y0) row = r; + int gap = grid->row_gap(r)>=0 ? grid->row_gap(r) : grg; + y0 += grid->computed_row_height(r); + y0 += gap; + } + + for (int c = 0; c < grid->cols(); c++) { + if (x>x0) col = c; + int gap = grid->col_gap(c)>=0 ? grid->col_gap(c) : gcg; + x0 += grid->computed_col_width(c); + x0 += gap; + } + + move_cell(grid, child, row, col); +} + +/** Insert a child window into the first new cell we can find . + + There are many other possible strategies. How about inserting to the right + of the last added child. Also, what happens if the grid is full? Should + we add a new row at the bottom? + */ +void Fl_Grid_Type::insert_child(Fl_Widget *child) { + Fl_Grid *grid = (Fl_Grid*)o; + if (grid->cell(child)) return; + for (int r=0; rrows(); r++) { + for (int c=0; ccols(); c++) { + if (!grid->cell(r, c)) { + move_cell(grid, child, r, c); + return; + } + } + } +} + // 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: grid_child_cb should move all selected cells. +// TODO: grid_child_cb should move all selected cells, not just the current_selected. // 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? +// TODO: we must set undo checkpoints in all callbacks! void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) { static Fl_Widget *prev_widget = NULL; if ( !current_widget diff --git a/fluid/Fl_Grid_Type.h b/fluid/Fl_Grid_Type.h index 3ad25095c..358489469 100644 --- a/fluid/Fl_Grid_Type.h +++ b/fluid/Fl_Grid_Type.h @@ -45,6 +45,8 @@ public: void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; void remove_child(Fl_Type*) FL_OVERRIDE; void child_resized(Fl_Widget_Type *child); + void insert_child_at(Fl_Widget *child, int x, int y); + void insert_child(Fl_Widget *child); static class Fl_Grid *selected(); }; diff --git a/fluid/factory.cxx b/fluid/factory.cxx index 28e71068e..7bd93f946 100644 --- a/fluid/factory.cxx +++ b/fluid/factory.cxx @@ -26,6 +26,7 @@ #include "fluid.h" #include "Fl_Group_Type.h" +#include "Fl_Grid_Type.h" #include "Fl_Menu_Type.h" #include "Fd_Snap_Action.h" #include "pixmaps.h" @@ -1225,6 +1226,13 @@ Fl_Type *add_new_widget_from_user(Fl_Type *inPrototype, Strategy strategy) { wt->o->size(w, h); } } + if (t->parent && t->parent->is_a(ID_Grid)) { + if (Fl_Window_Type::popupx != 0x7FFFFFFF) { + ((Fl_Grid_Type*)t->parent)->insert_child_at(((Fl_Widget_Type*)t)->o, Fl_Window_Type::popupx, Fl_Window_Type::popupy); + } else { + ((Fl_Grid_Type*)t->parent)->insert_child(((Fl_Widget_Type*)t)->o); + } + } } if (t->is_a(ID_Window)) { int x = 0, y = 0, w = 480, h = 320; diff --git a/src/Fl_Grid.cxx b/src/Fl_Grid.cxx index 9de77c7b9..ac4f9f224 100644 --- a/src/Fl_Grid.cxx +++ b/src/Fl_Grid.cxx @@ -1142,6 +1142,14 @@ int Fl_Grid::row_gap(int row) const { return 0; } +int Fl_Grid::computed_col_width(int col) const { + return Cols_[col].w_; +} + +int Fl_Grid::computed_row_height(int row) const { + return Rows_[row].h_; +} + /** Output layout information of this Fl_Grid to stderr. -- cgit v1.2.3