summaryrefslogtreecommitdiff
path: root/FL
diff options
context:
space:
mode:
authorAlbrecht Schlosser <albrechts.fltk@online.de>2023-10-16 22:11:33 +0200
committerAlbrecht Schlosser <albrechts.fltk@online.de>2023-10-16 22:18:24 +0200
commit38871c5b3192bccd508f3686413d4e56041ab091 (patch)
tree26db3ef4a73e93f23a1d1bcb037652aafc26dbed /FL
parente7b790ae31b3c5d5e819f35f5fa8bd3619f7103f (diff)
Add Fl_Grid widget and test and demo programs
- FL/Fl_Grid.H: header file - src/Fl_Grid.cxx: implementation - examples/grid-simple.cxx: simple example program - test/cube.cxx: use Fl_Grid for layout - test/grid_alignment.cxx: test cell alignment and other functions - test/grid_buttons.cxx: demo program as discussed in fltk.general - test/grid_login.cxx: like test/flex_login.cxx but with Fl_Grid - test/flex_login.cxx: modified to match test/grid_login.cxx
Diffstat (limited to 'FL')
-rw-r--r--FL/Fl_Grid.H333
1 files changed, 333 insertions, 0 deletions
diff --git a/FL/Fl_Grid.H b/FL/Fl_Grid.H
new file mode 100644
index 000000000..d7782ee5e
--- /dev/null
+++ b/FL/Fl_Grid.H
@@ -0,0 +1,333 @@
+//
+// Fl_Grid widget header for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2021-2022 by Albrecht Schlosser.
+// Copyright 2022-2023 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#ifndef _FL_FL_GRID_H_
+#define _FL_FL_GRID_H_
+
+/** \file FL/Fl_Grid.H
+ Fl_Grid container widget.
+*/
+
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Rect.H>
+
+/** Fl_Grid type for child widget alignment control. */
+typedef unsigned short Fl_Grid_Align;
+
+/** Align the widget in the middle of the cell (default). */
+const Fl_Grid_Align FL_GRID_CENTER = 0x0000;
+
+/** Align the widget at the top of the cell. */
+const Fl_Grid_Align FL_GRID_TOP = 0x0001;
+
+/** Align the widget at the bottom of the cell. */
+const Fl_Grid_Align FL_GRID_BOTTOM = 0x0002;
+
+/** Align the widget at the left side of the cell. */
+const Fl_Grid_Align FL_GRID_LEFT = 0x0004;
+
+/** Align the widget at the right side of the cell. */
+const Fl_Grid_Align FL_GRID_RIGHT = 0x0008;
+
+/** Stretch the widget horizontally to fill the cell. */
+const Fl_Grid_Align FL_GRID_HORIZONTAL = 0x0010;
+
+/** Stretch the widget vertically to fill the cell. */
+const Fl_Grid_Align FL_GRID_VERTICAL = 0x0020;
+
+/** Stretch the widget in both directions to fill the cell. */
+const Fl_Grid_Align FL_GRID_FILL = 0x0030;
+
+/** Stretch the widget proportionally. */
+const Fl_Grid_Align FL_GRID_PROPORTIONAL = 0x0040;
+
+const Fl_Grid_Align FL_GRID_TOP_LEFT = FL_GRID_TOP | FL_GRID_LEFT;
+const Fl_Grid_Align FL_GRID_TOP_RIGHT = FL_GRID_TOP | FL_GRID_RIGHT;
+const Fl_Grid_Align FL_GRID_BOTTOM_LEFT = FL_GRID_BOTTOM | FL_GRID_LEFT;
+const Fl_Grid_Align FL_GRID_BOTTOM_RIGHT = FL_GRID_BOTTOM | FL_GRID_RIGHT;
+
+/**
+ Fl_Grid is a container (layout) widget with multiple columns and rows.
+
+ This container widget features very flexible layouts in columns and rows
+ w/o the need to position each child widget in x/y coordinates.
+
+ Widgets are assigned to grid cells (column, row) with their minimal sizes
+ in \p w() and \p h(). The \p x() and \p y() positions are ignored and can
+ be (0, 0). Fl_Grid calculates widget positions and resizes the widgets to
+ fit into the grid. It is possible to create a single row or column of
+ widgets with Fl_Grid.
+
+ You should design your grid with the smallest possible sizes of all widgets
+ in mind. Fl_Grid will automatically assign additional space to cells
+ according to some rules (described later) when resizing the Fl_Grid widget.
+
+ \b Hint: You should set a minimum window size to make sure the Fl_Grid is
+ never resized below its minimal sizes. Resizing below the given widget
+ sizes results in undefined behavior.
+
+ Fl_Grid and other container widgets (e.g. Fl_Group) can be nested. One main
+ advantage of this usage is that widget coordinates in embedded Fl_Group
+ widgets become relative to the group and will be positioned as expected.
+ \todo This (relative group coordinates of nested groups of Fl_Grid)
+ needs explanation and maybe an example.
+
+ Fl_Grid child widgets are handled by its base class Fl_Group but Fl_Grid
+ stores additional data corresponding to each widget in internal grid cells.
+
+ Fl_Grid children are allowed to span multiple columns and rows like HTML
+ \<table\> cells. Individual children can have fixed sizes or be aligned
+ inside their cells (left, right, top, bottom, and more) and/or follow
+ their cell sizes when the Fl_Grid container is resized.
+
+ Note to resizing: since Fl_Grid uses its own layout algorithm the normal
+ Fl_Group::resizable() widget is ignored (if set). Calling init_sizes()
+ is not necessary.
+
+ \note Fl_Grid is, as of FLTK 1.4.0, still in experimental state and
+ should be used with caution. The API can still be changed although it is
+ assumed to be almost stable - as stable as possible for a first release.
+
+ Example: Simple 3x3 Fl_Grid with five buttons:
+ \n
+ \code
+ #include <FL/Fl.H>
+ #include <FL/Fl_Double_Window.H>
+ #include <FL/Fl_Grid.H>
+ #include <FL/Fl_Button.H>
+
+ int main(int argc, char **argv) {
+ Fl_Double_Window *win = new Fl_Double_Window(320, 180, "3x3 Fl_Grid with Buttons");
+ // create the Fl_Grid container with five buttons
+ Fl_Grid *grid = new Fl_Grid(0, 0, win->w(), win->h());
+ grid->layout(3, 3, 10, 10);
+ grid->color(FL_WHITE);
+ Fl_Button *b0 = new Fl_Button(0, 0, 0, 0, "New");
+ Fl_Button *b1 = new Fl_Button(0, 0, 0, 0, "Options");
+ Fl_Button *b3 = new Fl_Button(0, 0, 0, 0, "About");
+ Fl_Button *b4 = new Fl_Button(0, 0, 0, 0, "Help");
+ Fl_Button *b6 = new Fl_Button(0, 0, 0, 0, "Quit");
+ // assign buttons to grid positions
+ grid->widget(b0, 0, 0);
+ grid->widget(b1, 0, 2);
+ grid->widget(b3, 1, 1);
+ grid->widget(b4, 2, 0);
+ grid->widget(b6, 2, 2);
+ grid->show_grid(0); // 1 to display grid helper lines
+ win->end();
+ win->resizable(grid);
+ win->size_range(300, 100);
+ win->show(argc, argv);
+ return Fl::run();
+ }
+ \endcode
+
+ \image html Fl_Grid.png
+ \image latex Fl_Grid.png "Simple 3x3 Fl_Grid" width=7cm
+*/
+class Fl_Grid : public Fl_Group {
+
+public:
+ class Cell {
+ friend class Fl_Grid;
+ private:
+ Cell *next_; // next cell in row
+ short row_; // row number
+ short col_; // column number
+ short rowspan_; // row span (1 - n)
+ short colspan_; // column span (1 - n)
+ Fl_Grid_Align align_; // widget alignment in its cell
+ Fl_Widget *widget_; // assigned widget
+ int w_; // minimal widget width
+ int h_; // minimal widget height
+
+ public:
+
+ Cell(int row, int col) {
+ next_ = NULL;
+ row_ = row;
+ col_ = col;
+ rowspan_ = 1;
+ colspan_ = 1;
+ widget_ = NULL;
+ w_ = 0;
+ h_ = 0;
+ align_ = 0;
+ }
+
+ ~Cell() {}
+
+ Fl_Widget *widget() { return widget_; }
+ void align(Fl_Grid_Align align) {
+ align_ = align;
+ }
+ }; // class Cell
+
+private:
+ class Row;
+ class Col;
+ short rows_;
+ short cols_;
+
+ short margin_left_; // left margin
+ short margin_top_; // top margin
+ short margin_right_; // right margin
+ short margin_bottom_; // bottom margin
+ short gap_row_; // gap between rows
+ short gap_col_; // gap between columns
+ Fl_Rect old_size; // only for resize callback (TBD)
+ Col *Cols_; // array of columns
+ Row *Rows_; // array of rows
+ bool need_layout_; // true if layout needs to be calculated
+
+protected:
+ Fl_Color grid_color; // color for drawing the grid lines (design helper)
+ bool draw_grid_; // draw the grid for testing / design
+
+private:
+ void init();
+ Cell *add_cell(int row, int col);
+ void remove_cell(int row, int col);
+
+public:
+ Fl_Grid(int X, int Y, int W, int H, const char *L = 0);
+ virtual ~Fl_Grid();
+
+ // define and manage the layout and resizing
+
+ virtual void layout(int rows, int cols, int margin = -1, int gap = -1);
+ virtual void layout();
+ virtual void clear_layout();
+ virtual void resize(int X, int Y, int W, int H) FL_OVERRIDE;
+
+ /**
+ Request or reset the request to calculate the layout of children.
+
+ If called with \p true (1) this calls redraw() to schedule a
+ full draw(). When draw is eventually called, the layout is
+ (re)calculated before actually drawing the widget.
+
+ \param[in] set 1 to request layout calculation,\n
+ 0 to reset the request
+ */
+ void need_layout(int set) {
+ if (set) {
+ need_layout_ = true;
+ redraw();
+ }
+ else {
+ need_layout_ = false;
+ }
+ }
+
+ /**
+ Return whether layout calculation is required.
+ */
+ bool need_layout() const {
+ return need_layout_;
+ }
+
+protected:
+ virtual void draw() FL_OVERRIDE;
+ void on_remove(int) FL_OVERRIDE;
+ virtual void draw_grid(); // draw grid lines for debugging
+
+public:
+
+ // set individual margins
+
+ virtual void margin(int left, int top = -1, int right = -1, int bottom = -1);
+
+ // set default row and column gaps for all rows and columns, respectively
+
+ virtual void gap(int row_gap, int col_gap = -1); // set default row and column gap(s)
+
+ // find cells, get cell pointers
+
+ Fl_Grid::Cell* cell(int row, int col) const;
+ Fl_Grid::Cell* cell(Fl_Widget *widget) const;
+
+ // assign a widget to a cell
+
+ Fl_Grid::Cell* widget(Fl_Widget *wi, int row, int col, Fl_Grid_Align align = FL_GRID_FILL);
+ Fl_Grid::Cell* widget(Fl_Widget *wi, int row, int col, int rowspan, int colspan, Fl_Grid_Align align = FL_GRID_FILL);
+
+ // set minimal column and row sizes (widths and heights, respectively),
+ // set row and column specific gaps and weights
+
+ void col_width(int col, int value);
+ void col_width(const int *value, size_t size);
+
+ void col_weight(int col, int value);
+ void col_weight(const int *value, size_t size);
+
+ void col_gap(int col, int value);
+ void col_gap(const int *value, size_t size);
+
+ void row_height(int row, int value);
+ void row_height(const int *value, size_t size);
+
+ void row_weight(int row, int value);
+ void row_weight(const int *value, size_t size);
+
+ void row_gap(int row, int value);
+ void row_gap(const int *value, size_t size);
+
+ /**
+ Enable or disable drawing of the grid helper lines for visualization.
+
+ Use this method during the design stage of your Fl_Grid widget or
+ for debugging if widgets are not positioned as intended.
+
+ The default is a light green color but you can change it for better
+ contrast if needed, see show_grid(int set, Fl_Color col).
+
+ \note You can define the environment variable \c FLTK_GRID_DEBUG=1
+ to set show_grid(1) for all Fl_Grid widgets at construction time.
+ This enables you to debug the grid layout w/o changing code.
+
+ \param[in] set 1 (true) = draw, 0 = don't draw the grid
+
+ \see show_grid(int set, Fl_Color col)
+ */
+ void show_grid(int set) {
+ draw_grid_ = set ? true : false;
+ }
+
+ /**
+ Enable or disable drawing of the grid helper lines for visualization.
+
+ This method also sets the color used for the helper lines.
+
+ The default is a light green color but you can change it to any color
+ for better contrast if needed.
+
+ \param[in] set 1 (true) = draw, 0 = don't draw the grid
+ \param[in] col color to use for the grid helper lines
+
+ \see show_grid(int set)
+ */
+ void show_grid(int set, Fl_Color col) {
+ draw_grid_ = set ? true : false;
+ grid_color = col;
+ }
+
+ void debug(int level = 127);
+
+}; // class Fl_Grid
+
+#endif // _FL_FL_GRID_H_