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
This commit is contained in:
Albrecht Schlosser 2023-10-16 22:11:33 +02:00
parent e7b790ae31
commit 38871c5b31
19 changed files with 2033 additions and 134 deletions

333
FL/Fl_Grid.H Normal file
View File

@ -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_

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

1
examples/.gitignore vendored
View File

@ -12,6 +12,7 @@ callbacks
cairo-draw-x
chart-simple
draggable-group
grid-simple
howto-add_fd-and-popen
howto-browser-with-icons
howto-drag-and-drop

View File

@ -1,7 +1,7 @@
#
# CMakeLists.txt used to build example apps by the CMake build system
#
# Copyright 2020-2022 by Bill Spitzak and others.
# Copyright 2020-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
@ -31,10 +31,11 @@ file (MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
############################################################
set (SIMPLE_SOURCES
chart-simple
callbacks
browser-simple
callbacks
chart-simple
draggable-group
grid-simple
howto-add_fd-and-popen
howto-browser-with-icons
howto-drag-and-drop
@ -45,8 +46,8 @@ set (SIMPLE_SOURCES
howto-remap-numpad-keyboard-keys
howto-text-over-image-button
menubar-add
nativefilechooser-simple-app
nativefilechooser-simple
nativefilechooser-simple-app
progress-simple
shapedwindow
simple-terminal

View File

@ -31,6 +31,7 @@ ALL = animgifimage$(EXEEXT) \
callbacks$(EXEEXT) \
chart-simple$(EXEEXT) \
draggable-group$(EXEEXT) \
grid-simple$(EXEEXT) \
howto-add_fd-and-popen$(EXEEXT) \
howto-browser-with-icons$(EXEEXT) \
howto-drag-and-drop$(EXEEXT) \

49
examples/grid-simple.cxx Normal file
View File

@ -0,0 +1,49 @@
//
// Fl_Grid Example Program 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
//
// This example program is also included in the documentation.
// See FL/Fl_Grid.H
#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(1); // enable to display grid helper lines
win->end();
win->resizable(grid);
win->size_range(300, 100);
win->show(argc, argv);
return Fl::run();
}

View File

@ -41,6 +41,7 @@ set (CPPFILES
Fl_File_Input.cxx
Fl_Flex.cxx
Fl_Graphics_Driver.cxx
Fl_Grid.cxx
Fl_Group.cxx
Fl_Help_View.cxx
Fl_Image.cxx

1108
src/Fl_Grid.cxx Normal file

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@ CPPFILES = \
Fl_File_Input.cxx \
Fl_Flex.cxx \
Fl_Graphics_Driver.cxx \
Fl_Grid.cxx \
Fl_Group.cxx \
Fl_Help_View.cxx \
Fl_Image.cxx \

View File

@ -2238,6 +2238,11 @@ Fl_Graphics_Driver.o: ../FL/platform.H
Fl_Graphics_Driver.o: ../FL/platform_types.h
Fl_Graphics_Driver.o: ../FL/x11.H
Fl_Graphics_Driver.o: Fl_Screen_Driver.H
Fl_Grid.o: ../FL/fl_draw.H
Fl_Grid.o: ../FL/Fl_Grid.H
Fl_Grid.o: ../FL/Fl_Group.H
Fl_Grid.o: ../FL/Fl_Rect.H
Fl_Grid.o: ../FL/Fl_Widget.H
Fl_Group.o: ../FL/Enumerations.H
Fl_Group.o: ../FL/Fl.H
Fl_Group.o: ../FL/fl_attr.h

3
test/.gitignore vendored
View File

@ -52,6 +52,9 @@ fullscreen
gl_overlay
glpuzzle
glut_test
grid_alignment
grid_buttons
grid_login
handle_events
hello
help_dialog

View File

@ -92,6 +92,10 @@ if (OPENGL_FOUND)
CREATE_EXAMPLE (glut_test glut_test.cxx "fltk_gl;fltk")
endif()
CREATE_EXAMPLE (grid_alignment grid_alignment.cxx fltk)
CREATE_EXAMPLE (grid_buttons grid_buttons.cxx fltk)
CREATE_EXAMPLE (grid_login grid_login.cxx fltk)
if (OPENGL_FOUND)
CREATE_EXAMPLE (handle_events handle_events.cxx "fltk_gl;fltk") # opt. Fl_Gl_Window
else()

View File

@ -76,6 +76,9 @@ CPPFILES =\
gl_overlay.cxx \
glpuzzle.cxx \
glut_test.cxx \
grid_alignment \
grid_buttons \
grid_login \
hello.cxx \
help_dialog.cxx \
icon.cxx \
@ -161,6 +164,9 @@ ALL = \
fltk-versions$(EXEEXT) \
fonts$(EXEEXT) \
forms$(EXEEXT) \
grid_alignment$(EXEEXT) \
grid_buttons$(EXEEXT) \
grid_login$(EXEEXT) \
hello$(EXEEXT) \
help_dialog$(EXEEXT) \
icon$(EXEEXT) \
@ -437,6 +443,12 @@ forms$(EXEEXT): forms.o
$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ forms.o $(LINKFLTKFORMS) $(LDLIBS)
$(OSX_ONLY) ../fltk-config --post $@
grid_alignment$(EXEEXT): grid_alignment.o
grid_buttons$(EXEEXT): grid_buttons.o
grid_login$(EXEEXT): grid_login.o
hello$(EXEEXT): hello.o
help_dialog$(EXEEXT): help_dialog.o $(IMGLIBNAME)

View File

@ -3,7 +3,7 @@
//
// Modified to have 2 cubes to test multiple OpenGL contexts
//
// Copyright 1998-2021 by Bill Spitzak and others.
// Copyright 1998-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
@ -26,7 +26,7 @@
#include <FL/Fl_Slider.H>
#include <FL/Fl_Sys_Menu_Bar.H>
#include <FL/Fl_Printer.H> // demo printing
#include <FL/Fl_Grid.H> // grid layout
#include <stdlib.h>
#if !HAVE_GL
@ -39,8 +39,6 @@ public:
cube_box(int x,int y,int w,int h,const char *l=0) :Fl_Box(FL_DOWN_BOX,x,y,w,h,l) {
label("This demo does\nnot work without GL");
}
void begin() {}
void end() {}
};
#else
#include <FL/Fl_Gl_Window.H>
@ -120,11 +118,8 @@ void cube_box::draw() {
gl_draw(wire ? "Cube: wire" : "Cube: flat", -4.5f, -4.5f );
glEnable(GL_DEPTH_TEST);
// if an OpenGL graphics driver is installed, give it a chance
// to draw additional graphics
#if HAVE_GL
// draw additional FLTK widgets and graphics
Fl_Gl_Window::draw();
#endif
}
int cube_box::handle(int e) {
@ -135,121 +130,128 @@ int cube_box::handle(int e) {
return Fl_Gl_Window::handle(e);
}
#endif
Fl_Window *form;
Fl_Slider *speed, *size;
Fl_Button *exit_button, *wire, *flat;
cube_box *lt_cube, *rt_cube;
int done = 0; // set to 1 in exit button callback
// exit button callback
void exit_cb(Fl_Widget *, void *) {
done = 1;
}
// print screen demo
void print_cb(Fl_Widget *w, void *data)
{
Fl_Printer printer;
Fl_Window *win = Fl::first_window();
if(!win) return;
if( printer.start_job(1) ) return;
if( printer.start_page() ) return;
printer.scale(0.5,0.5);
printer.print_widget( win );
printer.end_page();
printer.end_job();
}
// Create a form that allows resizing for A and C (GL windows) with B fixed size/centered:
//
// lt_grp rt_grp
// |<--------------------------------------->|<---------------------->|
// . lt_cube ct_grp : rt_cube .
// . 350 100 : 350 .
// . |<------------------->| |<-------->| |<------------------->| .
// ....................................................................
// : ....................... ............ ....................... :
// : : : : : : : :
// : : A : : B : : C : :
// : : : : : : : :
// : :.....................: :..........: :.....................: : __
// :..................................................................: __ MARGIN
//
// | |
// MARGIN
//
#define MENUBAR_H 25 // menubar height
#define MARGIN 20 // fixed margin around widgets
#define MARGIN2 (MARGIN*2)
#define MARGIN3 (MARGIN*3)
// callback for overlay button (Fl_Button on OpenGL scene)
void show_info_cb(Fl_Widget*, void*) {
fl_message("This is an example of using FLTK widgets inside OpenGL windows.\n"
"Multiple widgets can be added to Fl_Gl_Windows. They will be\n"
"rendered as overlays over the scene.");
}
// overlay a button onto an OpenGL window (cube_box)
void overlay_button(cube_box *cube) {
cube->begin();
Fl_Widget *w = new Fl_Button(10, 10, 120, 30, "FLTK over GL");
w->color(FL_FREE_COLOR);
w->box(FL_BORDER_BOX);
w->callback(show_info_cb);
cube->end();
}
#endif // HAVE_GL
Fl_Window *form;
Fl_Slider *speed, *size;
Fl_Button *exit_button, *wire, *flat;
cube_box *lt_cube, *rt_cube;
int done = 0; // set to 1 in exit button callback
// exit button callback
void exit_cb(Fl_Widget *w, void *) {
done = 1;
w->window()->hide(); // necessary if built w/o GL
}
// print screen demo
void print_cb(Fl_Widget *w, void *data) {
Fl_Printer printer;
Fl_Window *win = Fl::first_window();
if (!win) return;
if (printer.start_job(1)) return;
if (printer.start_page()) return;
printer.scale(0.5, 0.5);
printer.print_widget(win);
printer.end_page();
printer.end_job();
}
// Create a form that allows resizing for A and C (GL windows) with B fixed size/centered:
//
// |<--------------------------------------->|<---------------------->|
// . lt_cube center : rt_cube .
// . 350 100 : 350 .
// . |<------------------->| |<-------->| |<------------------->| .
// ....................................................................
// : ....................... ............ ....................... : __
// : : : : : : : :
// : : A : : B : : C : : h = 350
// : : : : : : : :
// : :.....................: :..........: :.....................: : __
// :..................................................................: __ MARGIN
//
// | | | | | |
// MARGIN GAP GAP
#define MENUBAR_H 25 // menubar height
#define MARGIN 20 // fixed margin around widgets
#define GAP 20 // fixed gap between widgets
void makeform(const char *name) {
// Widget's XYWH's
int form_w = 800 + 4 * MARGIN; // main window width
int form_w = 800 + 2 * MARGIN + 2 * GAP; // main window width
int form_h = 350 + MENUBAR_H + 2 * MARGIN; // main window height
int me_bar_x=0, me_bar_y=0, me_bar_w=form_w, me_bar_h=MENUBAR_H; // menubar
int lt_grp_x=0, lt_grp_y=MENUBAR_H+MARGIN, lt_grp_w=350+100+MARGIN3, lt_grp_h=form_h-MENUBAR_H-MARGIN2; // left group
int lt_cub_x=lt_grp_x+MARGIN, lt_cub_y=lt_grp_y, lt_cub_w=350, lt_cub_h=lt_grp_h; // left cube box (GL)
int ct_grp_x=lt_grp_x+350+MARGIN2, ct_grp_y=lt_grp_y, ct_grp_w=100, ct_grp_h=lt_grp_h; // center group
int rt_grp_x=lt_grp_x+lt_grp_w, rt_grp_y=lt_grp_y, rt_grp_w=350+MARGIN, rt_grp_h=lt_grp_h; // right group
int rt_cub_x=rt_grp_x, rt_cub_y=lt_grp_y, rt_cub_w=350, rt_cub_h=lt_grp_h; // right cube box (GL)
// main window
form = new Fl_Window(form_w, form_h, name);
form->begin();
// menu bar
Fl_Sys_Menu_Bar *menubar = new Fl_Sys_Menu_Bar(me_bar_x, me_bar_y, me_bar_w, me_bar_h);
menubar->add("File/Print window", FL_COMMAND+'p', print_cb);
menubar->add("File/Quit", FL_COMMAND+'q', exit_cb);
// left group
Fl_Group *lt_grp = new Fl_Group(lt_grp_x, lt_grp_y, lt_grp_w, lt_grp_h);
lt_grp->begin();
// left GL window
lt_cube = new cube_box(lt_cub_x, lt_cub_y, lt_cub_w, lt_cub_h, 0);
// menu bar
Fl_Sys_Menu_Bar *menubar = new Fl_Sys_Menu_Bar(0, 0, form_w, MENUBAR_H);
menubar->add("File/Print window", FL_COMMAND+'p', print_cb);
menubar->add("File/Quit", FL_COMMAND+'q', exit_cb);
lt_cube->begin();
Fl_Widget *w = new Fl_Button(10, 10, 120, 30, "FLTK over GL");
w->color(FL_FREE_COLOR);
w->box(FL_BORDER_BOX );
w->callback(show_info_cb);
lt_cube->end();
// Fl_Grid (layout)
Fl_Grid *grid = new Fl_Grid(0, MENUBAR_H, form_w, 350 + 2 * MARGIN);
grid->layout(4, 4, MARGIN, GAP);
grid->box(FL_FLAT_BOX);
// center group
Fl_Group *ct_grp = new Fl_Group(ct_grp_x, ct_grp_y, ct_grp_w, ct_grp_h);
ct_grp->begin();
wire = new Fl_Radio_Light_Button(ct_grp_x, ct_grp_y, 100, 25, "Wire");
flat = new Fl_Radio_Light_Button(ct_grp_x, wire->y()+wire->h(), 100, 25, "Flat");
speed = new Fl_Slider(FL_VERT_SLIDER, ct_grp_x, flat->y()+flat->h()+MARGIN, 40, 200, "Speed");
size = new Fl_Slider(FL_VERT_SLIDER, ct_grp_x+40+MARGIN, flat->y()+flat->h()+MARGIN, 40, 200, "Size");
exit_button = new Fl_Button(ct_grp_x, form_h-MARGIN-25, 100, 25, "Exit");
exit_button->callback(exit_cb);
ct_grp->end();
ct_grp->resizable(speed); // only sliders resize vertically, not buttons
lt_grp->end();
lt_grp->resizable(lt_cube);
// right group
Fl_Group *rt_grp = new Fl_Group(rt_grp_x, rt_grp_y, rt_grp_w, rt_grp_h);
rt_grp->begin();
// right GL window
rt_cube = new cube_box(rt_cub_x, rt_cub_y, rt_cub_w, rt_cub_h, 0);
rt_grp->end();
rt_grp->resizable(rt_cube);
// right resizer
Fl_Box *rt_resizer = new Fl_Box(rt_grp_x-5, rt_grp_y, 10, rt_grp_h);
rt_resizer->box(FL_NO_BOX);
// set column and row weights to control resizing behavior
int cwe[] = {50, 0, 0, 50}; // column weights
int rwe[] = { 0, 0, 50, 0}; // row weights
grid->col_weight(cwe, 4); // set weights for resizing
grid->row_weight(rwe, 4); // set weights for resizing
// set non-default gaps for special layout purposes and labels
grid->row_gap(0, 0); // no gap below wire button
grid->row_gap(2, 50); // gap below sliders for labels
// left GL window
lt_cube = new cube_box(0, 0, 350, 350);
// center group
wire = new Fl_Radio_Light_Button( 0, 0, 100, 25, "Wire");
flat = new Fl_Radio_Light_Button( 0, 0, 100, 25, "Flat");
speed = new Fl_Slider(FL_VERT_SLIDER, 0, 0, 40, 90, "Speed");
size = new Fl_Slider(FL_VERT_SLIDER, 0, 0, 40, 90, "Size");
exit_button = new Fl_Button( 0, 0, 100, 25, "Exit");
exit_button->callback(exit_cb);
// right GL window
rt_cube = new cube_box(0, 0, 350, 350);
// assign widgets to grid positions (R=row, C=col) and sizes
// RS=rowspan, CS=colspan: R, C, RS, CS, optional alignment
grid->widget(lt_cube, 0, 0, 4, 1);
grid->widget(wire, 0, 1, 1, 2);
grid->widget(flat, 1, 1, 1, 2);
grid->widget(speed, 2, 1, 1, 1, FL_GRID_VERTICAL);
grid->widget(size, 2, 2, 1, 1, FL_GRID_VERTICAL);
grid->widget(exit_button, 3, 1, 1, 2);
grid->widget(rt_cube, 0, 3, 4, 1);
#if HAVE_GL
overlay_button(lt_cube); // overlay a button onto the OpenGL window
#endif // HAVE_GL
form->end();
form->resizable(rt_resizer);
form->resizable(grid);
form->size_range(form->w(), form->h()); // minimum window size
}
@ -257,29 +259,27 @@ int main(int argc, char **argv) {
Fl::use_high_res_GL(1);
Fl::set_color(FL_FREE_COLOR, 255, 255, 0, 75);
makeform(argv[0]);
speed->bounds(4,0);
#if HAVE_GL
speed->bounds(4, 0);
speed->value(lt_cube->speed = rt_cube->speed = 1.0);
#else
speed->value(lt_cube->speed = rt_cube->speed = 0.0);
#endif
size->bounds(4,0.01);
size->value(lt_cube->size = rt_cube->size = 3.0);
size->bounds(4, 0.2);
size->value(lt_cube->size = rt_cube->size = 2.0);
flat->value(1); lt_cube->wire = 0; rt_cube->wire = 1;
form->label("cube");
form->label("Cube Demo");
form->show(argc,argv);
lt_cube->show();
rt_cube->show();
#if 0
// This demonstrates how to manipulate OpenGL contexts.
// In this case the same context is used by multiple windows (I'm not
// sure if this is allowed on Win32, can somebody check?).
// This fixes a bug on the XFree86 3.0 OpenGL where only one context
// per program seems to work, but there are probably better uses for
// this!
// This fixes a bug on the XFree86 3.0 OpenGL where only one context per
// program seems to work, but there are probably better uses for this!
lt_cube->make_current(); // causes context to be created
rt_cube->context(lt_cube->context()); // share the contexts
#endif
#if HAVE_GL
for (;;) {
if (form->visible() && speed->value()) {
if (!Fl::check()) break; // returns immediately
@ -295,4 +295,7 @@ int main(int argc, char **argv) {
if (done) break; // exit button was clicked
}
return 0;
#else
return Fl::run();
#endif
}

View File

@ -2,7 +2,7 @@
// Fl_Flex demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 2020 by Karsten Pedersen
// Copyright 2022 by Bill Spitzak and others.
// 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
@ -32,7 +32,10 @@ Fl_Button *create_button(const char *caption) {
void buttons_panel(Fl_Flex *parent) {
new Fl_Box(0, 0, 0, 0, "");
Fl_Box *w = new Fl_Box(0, 0, 0, 0, "Welcome to Flex Login");
Fl_Box *title = new Fl_Box(0, 0, 0, 0, "Welcome to Fl_Flex");
title->align(FL_ALIGN_CENTER);
title->labelfont(FL_BOLD + FL_ITALIC);
title->labelsize(16);
Fl_Flex *urow = new Fl_Flex(Fl_Flex::ROW);
{
@ -71,7 +74,7 @@ void buttons_panel(Fl_Flex *parent) {
Fl_Box *b = new Fl_Box(0, 0, 0, 0, "");
parent->fixed(w, 60);
parent->fixed(title, 60);
parent->fixed(urow, 30);
parent->fixed(prow, 30);
parent->fixed(pad, 1);
@ -95,7 +98,7 @@ void middle_panel(Fl_Flex *parent) {
new Fl_Box(0, 0, 0, 0, "");
parent->fixed(box, 200);
parent->fixed(box, 150);
parent->fixed(spacer, 10);
parent->fixed(bp, 300);
}
@ -119,21 +122,21 @@ void mainPanel(Fl_Flex *parent) {
int main(int argc, char **argv) {
Fl_Window *window = new Fl_Double_Window(100, 100, "Simple GUI Example");
Fl_Window *win = new Fl_Double_Window(100, 100, "Fl_Flex \"Login\" Layout");
Fl_Flex *col = new Fl_Flex(5, 5, 90, 90, Fl_Flex::COLUMN);
mainPanel(col);
col->end();
window->resizable(col);
window->color(fl_rgb_color(250, 250, 250));
window->end();
win->resizable(col);
win->color(fl_rgb_color(250, 250, 250));
win->end();
window->resize(0, 0, 640, 480);
window->size_range(550, 250);
window->show(argc, argv);
win->resize(0, 0, 600, 300); // same size as grid_login
win->size_range(550, 250);
win->show(argc, argv);
int ret = Fl::run();
delete window; // not necessary but useful to test for memory leaks
delete win; // not necessary but useful to test for memory leaks
return ret;
}

203
test/grid_alignment.cxx Normal file
View File

@ -0,0 +1,203 @@
//
// Fl_Grid demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 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
//
//
// This program tests several different alignment features of Fl_Grid.
//
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Grid.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Box.H>
// Test function to change the layout (executed by timer callback)
#define TEST_RELAYOUT (0)
#define TEST_REMOVE_NOTIFY (0)
#if (TEST_RELAYOUT)
void relayout_cb(void *v) {
Fl_Grid *grid = (Fl_Grid *)v;
grid->layout(5, 5, 8, 4);
grid->margin(10, 20, 30, 40);
grid->layout();
grid->redraw();
}
#endif
#if TEST_REMOVE_NOTIFY
void remove_cb(void *v) {
static int n = 10;
n--;
Fl_Grid *grid = (Fl_Grid *)v;
#if (0) // test 1: remove() the widget -- leaks memory (!)
grid->remove(n);
#else // test 2: delete the widget -- no leak
delete grid->child(0);
#endif
if (n > 0)
Fl::repeat_timeout(0.3, remove_cb, v);
}
#endif
int main(int argc, char **argv) {
Fl_Grid::Cell *c;
Fl_Box *b;
Fl_Double_Window *win = new Fl_Double_Window(440, 350, "FLTK 1.4.0 - Fl_Grid Alignment Test");
Fl_Grid *grid = new Fl_Grid(10, 10, 420, 330);
grid->layout(7, 7, 8, 4); // cols, rows, margin, gap
grid->box(FL_FLAT_BOX);
grid->color(FL_WHITE);
// add boxes (top and bottom rows)
for (int col = 0; col < 7; col++) {
grid->col_width(col, 50);
b = new Fl_Box(0, 0, 20, 20); // variable size
if (col == 5) {
b->size(4, 20); // reduce width
grid->col_width(col, 4); // new min. width
grid->col_weight(col, 0); // no hor. resizing
}
b->box(FL_FLAT_BOX);
b->color(FL_BLUE);
grid->widget(b, 0, col);
if (col == 5)
b = new Fl_Box(0, 0, 4, 20); // variable size
else
b = new Fl_Box(0, 0, 20, 20); // variable size
b->box(FL_FLAT_BOX);
b->color(FL_RED);
grid->widget(b, 6, col);
}
// add boxes (left and right columns)
grid->row_height(0, 40);
grid->row_height(6, 40);
for (int row = 1; row < 6; row++) {
grid->row_height(row, 40);
b = new Fl_Box(0, 0, 20, 20); // fixed size, see alignment below
b->box(FL_FLAT_BOX);
b->color(FL_RED);
switch(row) {
case 1: grid->widget(b, row, 0, FL_GRID_FILL); break;
case 2: grid->widget(b, row, 0, FL_ALIGN_CENTER); break;
case 3: grid->widget(b, row, 0, FL_ALIGN_BOTTOM_RIGHT); break;
case 4: grid->widget(b, row, 0, FL_ALIGN_BOTTOM_RIGHT); break;
case 5: grid->widget(b, row, 0, FL_ALIGN_TOP_RIGHT); break;
default: break;
}
b = new Fl_Box(0, 0, 20, 20);
b->box(FL_FLAT_BOX);
b->color(FL_GREEN);
c = grid->widget(b, row, 6, FL_ALIGN_CENTER);
}
// two more boxes to demonstrate widget alignment inside the cell
for (int row = 4; row < 6; row++) {
b = new Fl_Box(0, 0, 20, 20); // fixed size, see alignment below
b->box(FL_FLAT_BOX);
b->color(FL_MAGENTA);
c = grid->widget(b, row, 1); // default alignment: FL_GRID_FILL
if (row == 4)
c->align(FL_ALIGN_BOTTOM_LEFT); // alignment uses widget size
if (row == 5)
c->align(FL_ALIGN_TOP_LEFT); // alignment uses widget size
}
// one vertical box (line), spanning 5 rows
b = new Fl_Box(0, 0, 2, 2); // extends vertically
b->box(FL_FLAT_BOX);
b->color(FL_BLACK);
grid->widget(b, 1, 5, 5, 1, FL_GRID_VERTICAL | FL_ALIGN_RIGHT);
// add a textbox with label or title, spanning 5 cells, centered
b = new Fl_Box(0, 0, 1, 1); // variable size
b->label("Hello, Fl_Grid !");
b->labelfont(FL_BOLD + FL_ITALIC);
b->labelsize(30);
b->labeltype(FL_SHADOW_LABEL);
grid->widget(b, 1, 1, 1, 5); // rowspan = 1, colspan = 5
// add a footer textbox, spanning 3 cells, right aligned
b = new Fl_Box(0, 0, 1, 10); // variable size
b->label("FLTK/test/grid_alignment.cxx");
b->labelfont(FL_COURIER);
b->labelsize(11);
b->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT);
grid->widget(b, 5, 2, 1, 3, FL_GRID_HORIZONTAL | FL_ALIGN_BOTTOM);
// input widgets with fixed size and alignment inside the cell
Fl_Input *i1 = new Fl_Input(0, 0, 100, 30, "Username:");
c = grid->widget(i1, 2, 3, 1, 2); // widget, col, row, colspan, rowspan
c->align(FL_GRID_HORIZONTAL); // widget alignment in cell
Fl_Input *i2 = new Fl_Input(0, 0, 100, 30, "Password:");
c = grid->widget(i2, 3, 3, 1, 2); // widget, col, row, colspan, rowspan
c->align(FL_GRID_HORIZONTAL); // widget alignment in cell
// the login button spans 2 columns
Fl_Button *bt = new Fl_Button(0, 0, 10, 30, "Login");
grid->widget(bt, 4, 3, 1, 2, FL_GRID_HORIZONTAL); // widget, col, row, colspan, rowspan, alignment
grid->row_weight(1, 90);
grid->row_weight(2, 0);
grid->row_weight(3, 0);
grid->row_weight(4, 0);
grid->col_weight(0, 30);
grid->col_weight(4, 90);
grid->row_gap(5, 12);
grid->end();
grid->layout();
grid->debug(0);
// grid->show_grid(1); // enable to display grid helper lines
win->end();
win->resizable(grid);
win->size_range(440, 350);
win->show(argc, argv);
#if (TEST_RELAYOUT)
Fl::add_timeout(5.0, relayout_cb, grid);
#endif
#if (TEST_REMOVE_NOTIFY)
Fl::add_timeout(3.0, remove_cb, grid);
#endif
// return Fl::run();
int ret = Fl::run();
grid->clear_layout();
delete win;
return ret;
}

75
test/grid_buttons.cxx Normal file
View File

@ -0,0 +1,75 @@
//
// Fl_Grid demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 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
//
// Q: How to achieve a spaced out layout?
// https://groups.google.com/g/fltkgeneral/c/haet7hOQR0g
// A: We use an Fl_Grid with 1 x 7 cells (5 buttons) as requested:
// [New] [Options] <gap> [About] [Help] <gap> [Quit]
#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(460, 200, "Fl_Grid Row with 5 Buttons");
Fl_Grid *grid = new Fl_Grid(0, 0, win->w(), 50);
grid->layout(1, 7, 10, 10);
// create the buttons
Fl_Button *b0 = new Fl_Button(0, 0, 80, 30, "New");
Fl_Button *b1 = new Fl_Button(0, 0, 80, 30, "Options");
Fl_Button *b3 = new Fl_Button(0, 0, 80, 30, "About");
Fl_Button *b4 = new Fl_Button(0, 0, 80, 30, "Help");
Fl_Button *b6 = new Fl_Button(0, 0, 80, 30, "Quit");
grid->end();
// assign buttons to grid positions
grid->widget(b0, 0, 0);
grid->widget(b1, 0, 1); grid->col_gap(1, 0);
grid->widget(b3, 0, 3);
grid->widget(b4, 0, 4); grid->col_gap(4, 0);
grid->widget(b6, 0, 6);
// set column weights for resizing (only empty columns resize)
int weight[] = { 0, 0, 50, 0, 0, 50, 0 };
grid->col_weight(weight, 7);
grid->end();
// grid->show_grid(1); // enable to display grid helper lines
// add content ...
Fl_Group *g1 = new Fl_Group(0, 50, win->w(), win->h() - 50);
// add more widgets ...
win->end();
win->resizable(g1);
win->size_range(win->w(), 100);
win->show(argc, argv);
int ret = Fl::run();
delete win; // not necessary but useful to test for memory leaks
return ret;
}

94
test/grid_login.cxx Normal file
View File

@ -0,0 +1,94 @@
//
// Fl_Grid demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 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
//
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Grid.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Box.H>
int main(int argc, char **argv) {
Fl_Double_Window *win = new Fl_Double_Window(480, 200, "Fl_Grid \"Login\" Layout");
// Fl_Grid of 6 x 6 cells, margin 2 and gap 2
Fl_Grid *grid = new Fl_Grid(5, 5, 470, 190);
grid->layout(6, 6, 2, 2); // 6 rows, 6 columns, margin 2, gap 2
// image (150x200) in left column
Fl_Box *ibox = new Fl_Box(0, 0, 150, 200, "Image");
ibox->box(FL_BORDER_BOX);
ibox->color(fl_rgb_color(0, 200, 0));
grid->widget(ibox, 1, 1, 4, 1, FL_GRID_CENTER);
// the title spans 2 columns (3 - 4)
Fl_Box *title = new Fl_Box(0, 0, 200, 60);
title->label("Welcome to Fl_Grid");
title->align(FL_ALIGN_CENTER);
title->labelfont(FL_BOLD + FL_ITALIC);
title->labelsize(16);
grid->widget(title, 1, 3, 1, 2, FL_GRID_HORIZONTAL | FL_GRID_CENTER);
grid->col_width(2, 90); // placeholder for labels
// input widgets with fixed height and horizontal stretching
Fl_Input *i1 = new Fl_Input(0, 0, 150, 30, "Username:");
grid->widget(i1, 2, 3, 1, 2, FL_GRID_HORIZONTAL);
grid->row_gap(2, 10); // gap below username
Fl_Input *i2 = new Fl_Input(0, 0, 150, 30, "Password:");
grid->widget(i2, 3, 3, 1, 2, FL_GRID_HORIZONTAL);
grid->row_gap(3, 10); // gap below password
// register and login buttons
Fl_Button *btr = new Fl_Button(0, 0, 80, 30, "Register");
grid->widget(btr, 4, 3, 1, 1, FL_GRID_HORIZONTAL);
grid->col_gap(3, 20); // gap right of the register button
Fl_Button *btl = new Fl_Button(0, 0, 80, 30, "Login");
grid->widget(btl, 4, 4, 1, 1, FL_GRID_HORIZONTAL);
// set column and row weights for resizing behavior (optional)
int cw[] = { 20, 0, 0, 10, 10, 20}; // column weights
int rw[] = { 10, 0, 0, 0, 0, 10}; // row weights
grid->col_weight(cw, 6);
grid->row_weight(rw, 6);
grid->end();
grid->layout();
// grid->debug(1);
// grid->show_grid(1); // enable to display grid helper lines
win->end();
grid->color(fl_rgb_color(250, 250, 250));
win->color(fl_rgb_color(250, 250, 250));
win->resizable(grid);
win->resize(0, 0, 600, 300); // same size as flex_login
win->size_range(550, 250);
win->show(argc, argv);
int ret = Fl::run();
delete win; // not necessary but useful to test for memory leaks
return ret;
}

View File

@ -539,6 +539,7 @@ cube.o: ../FL/fl_config.h
cube.o: ../FL/Fl_Device.H
cube.o: ../FL/Fl_Export.H
cube.o: ../FL/Fl_Gl_Window.H
cube.o: ../FL/Fl_Grid.H
cube.o: ../FL/Fl_Group.H
cube.o: ../FL/Fl_Image.H
cube.o: ../FL/Fl_Light_Button.H
@ -550,6 +551,7 @@ cube.o: ../FL/Fl_Plugin.H
cube.o: ../FL/Fl_Preferences.H
cube.o: ../FL/Fl_Printer.H
cube.o: ../FL/Fl_Radio_Light_Button.H
cube.o: ../FL/Fl_Rect.H
cube.o: ../FL/Fl_Slider.H
cube.o: ../FL/Fl_String.H
cube.o: ../FL/Fl_Sys_Menu_Bar.H