summaryrefslogtreecommitdiff
path: root/fluid/Fl_Grid_Type.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2023-11-05 22:18:56 +0100
committerMatthias Melcher <github@matthiasm.com>2023-11-05 22:19:03 +0100
commite690e76da1555e61bd6bde89d00215b11352f8b2 (patch)
tree048cf12b8c35a60b0b983dbb8303f800a9b3da11 /fluid/Fl_Grid_Type.cxx
parent95daa77c497254919d17b23de56397788b291ecf (diff)
FLUID: Adds undo for all grid operations.
Diffstat (limited to 'fluid/Fl_Grid_Type.cxx')
-rw-r--r--fluid/Fl_Grid_Type.cxx117
1 files changed, 65 insertions, 52 deletions
diff --git a/fluid/Fl_Grid_Type.cxx b/fluid/Fl_Grid_Type.cxx
index 493565b6a..1565f19da 100644
--- a/fluid/Fl_Grid_Type.cxx
+++ b/fluid/Fl_Grid_Type.cxx
@@ -93,30 +93,25 @@ void Fl_Grid_Proxy::draw_overlay() {
/**
Move a cell into the grid or within the grid.
- \param[in] in_child must already be a child of grid
- \param[in] to_row, to_col move the child into this cell
- \param[in] how 0: replace occupant, 1: don't replace, 2 = make transient
- if occupied
+ If the target cell is already taken, \p how will determine what to do:
- \todo If the target cell is already taken, this function will remove the old
- child from the cell and leave it in limbo (a child of grid, but with no
- assigned cell). As this function is used to move children around with arrow
- keys, it must be possible to move a widget past a cell that is already taken
- without disturbing the existing system.
+ If \p how is 0, the existing cell at \p to_row, \p to_col will be deleted,
+ unlinking the occupant from the grid. \p in_child will the be inserted at the
+ given location.
- One solution would be to make the widget "hover", meaning, it will be registered
- in Fl_Grid_Proxy as using the same cell as another widget. I am not sure at all
- how to implement that yet. We could return the original cell, but that may have
- different minsize, etc. . It would be better to have a temporary cell to store
- all the information.
+ If \p how is 1, the old cell will remain intact, however \p in_child will be
+ unlinked from the grid.
- We must make sure that a hovering cell (or multiple cells) are a very temporary
- solution, because all this information will be skewed if Grid::layout is
- called, and all information is lost when we save the file for compilation.
+ If \p how is 2, the old cell will remain intact, and \p in_child will be
+ removed from the grid, but it will be stored in the transient list and
+ resized to the target cell position and size. If \p in_child is later
+ moved to an unoccupied cell, it will be removed from the transient list and
+ relinked to the grid. Rowspan and colspan are ignored here.
- We must show a conflict grid under or around the hovering cell!
-
- Also mind the rowspan and colspan!
+ \param[in] in_child must already be a child of grid
+ \param[in] to_row, to_col move the child into this cell
+ \param[in] how 0: replace occupant, 1: don't replace, 2: make transient
+ if occupied
*/
void Fl_Grid_Proxy::move_cell(Fl_Widget *in_child, int to_row, int to_col, int how) {
// the child must already be a true child of grid
@@ -127,6 +122,7 @@ void Fl_Grid_Proxy::move_cell(Fl_Widget *in_child, int to_row, int to_col, int h
int w = 20, h = 20;
const Fl_Grid::Cell *old_cell = cell(in_child);
if (old_cell) {
+ if (old_cell->row() == to_row && old_cell->col() == to_col) return;
rowspan = old_cell->rowspan();
colspan = old_cell->colspan();
align = old_cell->align();
@@ -162,8 +158,10 @@ void Fl_Grid_Proxy::move_cell(Fl_Widget *in_child, int to_row, int to_col, int h
/**
Generate or replace a transient widget entry.
+
If the widget is in the cell list, it will be removed there.
If the widget is already transient, the cell will be replaced.
+
\param[in] wi a child of this Fl_Grid_Proxy, that may be linked to a cell or transient cell
\param[in] row, col, row_span, col_span, align cell parameters
*/
@@ -239,6 +237,15 @@ void Fl_Grid_Proxy::transient_remove_(Fl_Widget *w) {
Fl_Grid_Proxy::Cell *Fl_Grid_Proxy::any_cell(Fl_Widget *widget) const {
Cell *c = cell(widget);
if (c) return c;
+ return transient_cell(widget);
+}
+
+/**
+ Find a cell in the transient cell list.
+ \param[in] widget must be a child of the grid.
+ \return the transient cell, or NULL if it was not found.
+ */
+Fl_Grid_Proxy::Cell *Fl_Grid_Proxy::transient_cell(Fl_Widget *widget) const {
for (int i=0; i<num_transient_; i++) {
if (transient_[i].widget == widget)
return transient_[i].cell;
@@ -634,6 +641,11 @@ Fl_Grid *Fl_Grid_Type::selected() {
return NULL;
}
+/**
+ Insert a child widget into the cell at the x, y position inside the window.
+ /param[in] child
+ /param[in] x, y pixels from the top left of the window
+ */
void Fl_Grid_Type::insert_child_at(Fl_Widget *child, int x, int y) {
Fl_Grid_Proxy *grid = (Fl_Grid_Proxy*)o;
int row = -1, col = -1, ml, mt, grg, gcg;
@@ -656,10 +668,11 @@ void Fl_Grid_Type::insert_child_at(Fl_Widget *child, int x, int y) {
x0 += gap;
}
- grid->move_cell(child, row, col);
+ grid->move_cell(child, row, col, 2);
}
-/** Insert a child widget into the first new cell we can find .
+/**
+ Insert a child widget 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
@@ -667,17 +680,28 @@ void Fl_Grid_Type::insert_child_at(Fl_Widget *child, int x, int y) {
/param[in] child
*/
-void Fl_Grid_Type::insert_child(Fl_Widget *child) {
+void Fl_Grid_Type::insert_child_at_next_free_cell(Fl_Widget *child) {
Fl_Grid_Proxy *grid = (Fl_Grid_Proxy*)o;
if (grid->cell(child)) return;
- for (int r=0; r<grid->rows(); r++) {
- for (int c=0; c<grid->cols(); c++) {
+// The code below would insert the new widget after the last selected one, but
+// unfortunately the current_widget is already invalid.
+// if (current_widget && (current_widget->parent == this)) {
+// Fl_Grid::Cell *current_cell = grid->any_cell(current_widget->o);
+// if (current_cell) {
+// r = current_cell->row();
+// c = current_cell->col();
+// }
+// }
+ for (int r = 0; r < grid->rows(); r++) {
+ for (int c = 0; c < grid->cols(); c++) {
if (!grid->cell(r, c)) {
grid->move_cell(child, r, c);
return;
}
}
}
+ grid->layout(grid->rows() + 1, grid->cols());
+ grid->move_cell(child, grid->rows() - 1, 0);
}
/** Move cells around using the keyboard.
@@ -712,29 +736,17 @@ void Fl_Grid_Type::layout_widget() {
// ---- Widget Panel Callbacks ---------------------------------------- MARK: -
-// 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 -> int Fl_Window_Type::handle(int event)
-// TODO: handling of children that are themselves Groups. As it is, the children
-// are not moved correctly if a parent group repositions or resizes groups.
-// The same is true for Fl_Flex.
// TODO: better grid overlay?
// 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!
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;
-
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))
@@ -743,8 +755,7 @@ void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
}
Fl_Widget *child = ((Fl_Widget_Type*)current_widget)->o;
Fl_Grid_Proxy *g = ((Fl_Grid_Proxy*)((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));
+ Fl_Grid::Cell *cell = g->any_cell(child);
if (v == LOAD) {
int v = -1;
if (cell) {
@@ -757,12 +768,10 @@ void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
case 13: cell->minimum_size(NULL, &v); break;
}
}
- if (!cell && prev_widget!=child && what==11)
- prev_widget = child;
- if (!freeze_row_col)
- i->value(v);
+ i->value(v);
} else {
- int v2 = -1, old_v = -1, v = i->value();
+ undo_checkpoint();
+ int v2 = -2, old_v = -2, 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 *new_cell = NULL;
@@ -782,19 +791,21 @@ void grid_child_cb(Fluid_Coord_Input* i, void* v, int what) {
}
if (old_v != v) {
switch (what & 0x00ff) {
- case 8: if (v>=0 && v2>=0) g->move_cell(current_widget->o, v, v2);
- if (freeze_row_col) i->value(v);
+ case 8:
+ if (v2 == -1 && v >= 0) v2 = 0;
+ g->move_cell(current_widget->o, v, v2, 2); i->value(v);
break;
- case 9: if (v>=0 && v2>=0) g->move_cell(current_widget->o, v2, v);
- if (freeze_row_col) i->value(v);
+ case 9:
+ if (v2 == -1 && v >= 0) v2 = 0;
+ g->move_cell(current_widget->o, v2, v, 2); i->value(v);
break;
- case 10: if (cell && cell->row()+v<=g->rows()) cell->rowspan(v);
+ case 10: if (cell && cell->row()+v<=g->rows() && v>0) cell->rowspan(v);
break;
- case 11: if (cell && cell->col()+v<=g->cols()) cell->colspan(v);
+ case 11: if (cell && cell->col()+v<=g->cols() && v>0) cell->colspan(v);
break;
- case 12: if (cell) cell->minimum_size(v, v2);
+ case 12: if (cell && v>=0) cell->minimum_size(v, v2);
break;
- case 13: if (cell) cell->minimum_size(v2, v);
+ case 13: if (cell && v>=0) cell->minimum_size(v2, v);
break;
}
if (!cell && new_cell)
@@ -893,6 +904,7 @@ void grid_align_horizontal_cb(Fl_Choice* i, void* v) {
const Fl_Menu_Item *mi = i->find_item_with_argument(a);
if (mi) i->value(mi);
} else {
+ undo_checkpoint();
int v = FL_GRID_FILL & mask, old_v = FL_GRID_FILL & mask;
const Fl_Menu_Item *mi = i->mvalue();
if (mi) v = (int)mi->argument();
@@ -927,6 +939,7 @@ void grid_align_vertical_cb(Fl_Choice* i, void* v) {
const Fl_Menu_Item *mi = i->find_item_with_argument(a);
if (mi) i->value(mi);
} else {
+ undo_checkpoint();
int v = FL_GRID_FILL & mask, old_v = FL_GRID_FILL & mask;
const Fl_Menu_Item *mi = i->mvalue();
if (mi) v = (int)mi->argument();