Documentation on widget coordinates and layout, plus new test programs (#304)

Add coordinates and layout section to user manual

add section to user manual to clarify the use of window-relative
coordinates in both Fl_Group and Fl_Window containers, and include
brief descriptions of current layout manager widgets in one place.

add test/coordinates.cxx, test/wizard.cxx and related screenshots
under documentation/src.

update CMakeLists.txt, Makefile and .gitignore for new files.

Co-authored-by: Albrecht Schlosser <albrechts.fltk@online.de>
This commit is contained in:
engelsman 2021-12-08 15:00:33 +01:00 committed by GitHub
parent eb7fb00801
commit 2d18c6f650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 376 additions and 6 deletions

View File

@ -557,6 +557,7 @@ INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/preface.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/intro.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/basics.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/common.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/coordinates.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/resize.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/editor.dox
INPUT += @CMAKE_CURRENT_SOURCE_DIR@/src/drawing.dox

View File

@ -29,6 +29,7 @@ HTMLFILES = \
$(SRC_DOCDIR)/intro.dox \
$(SRC_DOCDIR)/basics.dox \
$(SRC_DOCDIR)/common.dox \
$(SRC_DOCDIR)/coordinates.dox \
$(SRC_DOCDIR)/resize.dox \
$(SRC_DOCDIR)/editor.dox \
$(SRC_DOCDIR)/drawing.dox \

View File

@ -640,8 +640,8 @@ combined with any modifiers like \p Shift , \p Alt , and \p Control.
<a class="el" href="index.html">[Index]</a>
</td>
<td width="45%" align="RIGHT">
<a class="el" href="resize.html">
How does resizing work?
<a class="el" href="coordinates.html">
Coordinates and Layout Widgets
[Next]
</a>
</td>

View File

@ -0,0 +1,171 @@
/**
\page coordinates Coordinates and Layout Widgets
This chapter describes the coordinate systems that apply when
positioning widgets manually, and some of the basics of FLTK
layout widgets that are used to position widgets automatically.
\section coordinates_coordinates The widget coordinate system
All widgets have constructors with \p x and \p y parameters to
let the programmer specify the desired initial position of the
top left corner during explicit manual layout within Fl_Window
and Fl_Group container widgets.
This position is always relative to the enclosing Fl_Window,
which is usually, but not always, the top-level application
window, or a free-floating pop-up dialog window.
In some cases it could also be a subwindow embedded in a
higher-level window, as shown in the figure below.
\image html coordinates.png "FLTK coordinate system"
\image latex coordinates.png "FLTK coordinate system" width=6cm
The positions of the TL and BR sub-windows and the TR and BL
groups are all relative to the top-left corner of the main window.
The positions of the boxes inside the TR and BL groups are also
relative to the main window, but the boxes inside the TL and BR
sub-windows are positioned relative to the enclosing sub-window.
In other words, the widget hierarchy and positions can be summarized as:
<pre>
Fl_Window main window
Fl_Window TL subwindow # x, y relative to main window
Fl_Box tl box # x, y relative to TL subwindow
Fl_Window BR subwindow # x, y relative to main window
Fl_Box br box # x, y relative to BR subwindow
Fl_Group TR group # x, y relative to main window
Fl_Box tr box # x, y relative to main window
Fl_Group BL group # x, y relative to main window
Fl_Box bl box # x, y relative to main window
</pre>
\section coordinate_layout Layout and container widgets
There are four main groups of widgets derived from Fl_Group for
a range of different purposes.
The first group are composite widgets that each contain a fixed
set of components that work together for a specific purpose,
rather than layout widgets as such, and are not discussed here.
The second group are basically containers offering the same manual
layout features as Fl_Group, as described above, but which add one
new capability. These widgets are Fl_Scroll, Fl_Tabs and Fl_Wizard.
The third group are layout managers that relocate and resize the
child widgets added to them in order to satisfy a particular layout
algorithm. These widgets are Fl_Pack and Fl_Tile.
The final group consists of Fl_Window and its derivatives.
Their special capability is that they can be top-level application
windows and dialogs that interface with the operating system window
manager, but can also be embedded within other windows and groups
as shown in the example above.
Note that the window manager may impose its own constraints on
the position of top-level windows, and the \p x and \p y
position parameters may be treated as hints, or even ignored.
The Fl_Window class has an extra constructor that omits them.
\subsection coordinates_pack The Fl_Pack layout widget
The Fl_Pack widget allows the layout of its direct children as a
single row, or column.
If its type() is set to give the row or horizontal layout,
the children are all resized to have the same height as the Fl_Pack
and are moved next to each other.
If set to give the column or vertical layout, the children are all
resized to have the same width as the Fl_Pack and are then stacked
below each other.
The Fl_Pack then resizes itself to shrink-wrap itself around all
of the children.
Fl_Pack widgets are often used inside an Fl_Scroll, as shown in the
diagram below, to avoid having to deal with tricky resize behavior
when used with nested widgets.
\image html pack.png "Fl_Pack test program screenshot"
\image latex pack.png "Fl_Pack test program screenshot" width=8cm
\subsection coordinates_scroll The Fl_Scroll container widget
The Fl_Scroll container widget can hold an assortment of widgets
that may extend beyond its own width and height, in which case
horizontal and/or vertical scrollbars may appear automatically
so that you can scroll and view the entire contents.
\image html Fl_Scroll.png "Fl_Scroll container widget"
\image latex Fl_Scroll.png "Fl_Scroll container widget" width=4cm
\subsection coordinates_tabs The Fl_Tabs container widget
The Fl_Tabs widget provides a front-to-back stack of individual
panels which usually contain Fl_Group widgets and their children.
The user can switch between panels by clicking on the small
tabs that protrude from the panels. The appearance of each tab
is determined by the child widget's label and related attributes.
\image html tabs.png "Fl_Tabs container widget"
\image latex tabs.png "Fl_Tabs container widget" width=8cm
\subsection coordinates_tile The Fl_Tile layout widget
The Fl_Tile widget allows the user to resize one or more of its children
by dragging on the border between adjacent child widgets.
However, the programmer must first explicitly layout the child widgets
so that their borders exactly fill the width and height of the Fl_Tile
without having any gaps between them, or at the edges.
Some care is needed when initially positioning the children and setting
the resizable() widget within the Fl_Tile to prevent squeezing a child
to have a zero width or height.
For more information see the Fl_Tile widget manual page, and \ref resize.
\image html Fl_Tile.png "The Fl_Tile layout widget"
\image latex Fl_Tile.png "The Fl_Tile layout widget" width=4cm
\subsection coordinates_wizard The Fl_Wizard container widget
The Fl_Wizard widget derives from the Fl_Tabs class, but instead
of having tabs that the user can click to select the corresponding
panel, the programmer uses the prev(), next() or value() methods
to show the appropriate panel.
For example, the user might be able to click on "Next" and "Prev"
navigation buttons or keys, as shown below.
\image html wizard.png "FL_Wizard container widget"
\image latex wizard.png "FL_Wizard container widget" width=4cm
\htmlonly
<hr>
<table summary="navigation bar" width="100%" border="0">
<tr>
<td width="45%" align="LEFT">
<a class="el" href="common.html">
[Prev]
Common Widgets and Attributes
</a>
</td>
<td width="10%" align="CENTER">
<a class="el" href="index.html">[Index]</a>
</td>
<td width="45%" align="RIGHT">
<a class="el" href="resize.html">
How Does Resizing Work?
[Next]
</a>
</td>
</tr>
</table>
\endhtmlonly
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -900,7 +900,7 @@ style_parse(const char *text,
<td width="45%" align="LEFT">
<a class="el" href="resize.html">
[Prev]
How does resizing work?
How Does Resizing Work?
</a>
</td>
<td width="10%" align="CENTER">

View File

@ -43,6 +43,8 @@
- \ref common_labels
- \ref drawing_images
\subpage coordinates
\subpage resize
\subpage editor

BIN
documentation/src/pack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,6 +1,6 @@
/**
\page resize How does resizing work?
\page resize How Does Resizing Work?
This chapter describes the basic mechanism behind the creation
of resizable user interface elements in FLTK.
@ -280,9 +280,9 @@ To summarize the key points of the new technique:
<table summary="navigation bar" width="100%" border="0">
<tr>
<td width="45%" align="LEFT">
<a class="el" href="common.html">
<a class="el" href="coordinates.html">
[Prev]
Common Widgets and Attributes
Coordinates and Layout Widgets
</a>
</td>
<td width="10%" align="CENTER">

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

2
test/.gitignore vendored
View File

@ -33,6 +33,7 @@ clipboard
clock
colbrowser
color_chooser
coordinates
cube
CubeView
CubeViewUI.cxx
@ -133,6 +134,7 @@ valuators
valuators.cxx
valuators.h
windowfocus
wizard
# macOS binary files

View File

@ -76,6 +76,7 @@ CREATE_EXAMPLE (clipboard clipboard.cxx "fltk_images;fltk")
CREATE_EXAMPLE (clock clock.cxx fltk ANDROID_OK)
CREATE_EXAMPLE (colbrowser colbrowser.cxx fltk)
CREATE_EXAMPLE (color_chooser color_chooser.cxx fltk ANDROID_OK)
CREATE_EXAMPLE (coordinates coordinates.cxx fltk)
CREATE_EXAMPLE (cursor cursor.cxx fltk ANDROID_OK)
CREATE_EXAMPLE (curve curve.cxx fltk ANDROID_OK)
CREATE_EXAMPLE (demo demo.cxx fltk)
@ -146,6 +147,7 @@ CREATE_EXAMPLE (utf8 utf8.cxx fltk)
CREATE_EXAMPLE (valuators valuators.fl fltk)
CREATE_EXAMPLE (unittests unittests.cxx fltk)
CREATE_EXAMPLE (windowfocus windowfocus.cxx fltk)
CREATE_EXAMPLE (wizard wizard.cxx fltk)
# create additional test programs (used by developers for testing)
if (extra_tests)

125
test/coordinates.cxx Normal file
View File

@ -0,0 +1,125 @@
//
// Coordinate demonstration program for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 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_Box.H>
#include <FL/Fl_Window.H>
#include <stdio.h>
class Box : public Fl_Box {
public:
Box(int X, int Y, int W, int H, Fl_Color C, const char* T)
: Fl_Box(X, Y, W, H, T) {
align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER);
box(FL_DOWN_BOX);
labelcolor(C);
labelsize(11);
}
};
class Title : public Fl_Box {
public:
Title(int X, int Y, int W, int H, Fl_Color C, const char* T)
: Fl_Box(X, Y, W, H, T) {
align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_TOP);
box(FL_NO_BOX);
labelcolor(C);
labelsize(12);
}
};
class MainWindow : public Fl_Window {
public:
MainWindow(int X, int Y, const char* T)
: Fl_Window(X, Y, T) {
Fl_Window* tl_window = new Fl_Window(0, 0, 250, 100);
tl_window->box(FL_ENGRAVED_BOX);
Title* tl_title = new Title(10, 10, 230, 40, FL_RED,
"Fl_Window TL(0, 0, 250, 100)\nx, y relative to main window");
Box* tl_box = new Box(25, 50, 200, 40, FL_RED,
"Fl_Box tl(25, 50, 200, 40)\nx, y relative to TL window");
tl_window->end();
Fl_Window* br_window = new Fl_Window(250, 100, 250, 100);
br_window->box(FL_ENGRAVED_BOX);
Title* br_title = new Title(10, 10, 230, 40, FL_MAGENTA,
"Fl_Window BR(250, 100, 250, 100)\nx, y relative to main window");
Box* br_box = new Box(25, 50, 200, 40, FL_MAGENTA,
"Fl_Box br(25, 50, 200, 40)\nx, y relative to BR window");
br_window->end();
Fl_Group* tr_group = new Fl_Group(250, 0, 250, 100);
tr_group->box(FL_ENGRAVED_BOX);
Title* tr_title = new Title(260, 10, 230, 40, FL_BLUE,
"Fl_Group TR(250, 0, 250, 100)\nx, y relative to main window");
Box* tr_box = new Box(275, 50, 200, 40, FL_BLUE,
"Fl_Box tr(275, 50, 200, 40)\nx, y relative to main window");
tr_group->end();
Fl_Group* bl_group = new Fl_Group(0, 100, 250, 100);
bl_group->box(FL_ENGRAVED_BOX);
Title* bl_title = new Title(10, 110, 230, 40, FL_BLACK,
"Fl_Group BL(0, 100, 250, 100)\nx, y relative to main window");
Box* bl_box = new Box(25, 150, 200, 40, FL_BLACK,
"Fl_Box bl(25, 150, 200, 40)\nx, y relative to main window");
bl_group->end();
// member variable
message_box = new Fl_Box(0, 201, 500, 30);
message_box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER);
message_box->box(FL_ENGRAVED_BOX);
message_box->labelfont(FL_COURIER);
message_box->labelsize(12);
end();
}
protected:
int handle(int event) {
static char buffer[128];
static const char* fmt = "Mouse position relative to main window: %3d,%3d";
int result = Fl_Window::handle(event);
switch (event) {
case FL_ENTER:
case FL_LEAVE:
result = 1;
message_box->copy_label("");
break;
case FL_MOVE:
case FL_DRAG:
result = 1;
if (0 < Fl::event_x() && Fl::event_x() < w() &&
0 < Fl::event_y() && Fl::event_y() < h()) {
snprintf(buffer, 128-1, fmt, Fl::event_x(), Fl::event_y());
message_box->copy_label(buffer);
} else message_box->copy_label("");
break;
default:
break;
}
return result;
}
private:
Fl_Box* message_box;
};
int main(int argc, char** argv) {
MainWindow window(500, 232, "FLTK Coordinate Systems");
window.show(argc, argv);
return Fl::run();
}

66
test/wizard.cxx Normal file
View File

@ -0,0 +1,66 @@
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Wizard.H>
class Panel : public Fl_Group {
public:
Panel(int X, int Y, int W, int H, Fl_Color C, const char* T)
: Fl_Group(X, Y, W, H, T) {
align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER);
box(FL_ENGRAVED_BOX);
labelcolor(C);
labelsize(20);
end();
}
};
class Wizard : public Fl_Wizard {
public:
Wizard(int X, int Y, int W, int H, const char* T=0)
: Fl_Wizard(X, Y, W, H, T) {
p1 = new Panel(X, Y, W, H, FL_RED, "Panel 1");
p2 = new Panel(X, Y, W, H, FL_MAGENTA, "Panel 2");
p3 = new Panel(X, Y, W, H, FL_BLUE, "Panel 3");
value(p1);
}
void next_panel() {
Panel* p = (Panel*)value();
if (p == p3) value(p1); else next();
}
void prev_panel() {
Panel* p = (Panel*)value();
if (p == p1) value(p3); else prev();
}
private:
Panel *p1, *p2, *p3;
};
void next_callback(Fl_Widget *widget, void *data) {
Wizard *pWizard = (Wizard*)data;
pWizard->next_panel();
}
void prev_callback(Fl_Widget *widget, void *data) {
Wizard *pWizard = (Wizard*)data;
pWizard->prev_panel();
}
int main(int argc, char** argv) {
Fl_Window window(300, 165, "Fl_Wizard test");
Wizard wizard(5, 5, 290, 100);
wizard.end();
Fl_Group buttons(5, 110, 290, 50);
buttons.box(FL_ENGRAVED_BOX);
Fl_Button prev_button( 15, 120, 110, 30, "@< Prev Panel");
prev_button.callback(prev_callback, (void*)&wizard);
prev_button.align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_LEFT);
Fl_Button next_button(175, 120, 110, 30, "Next Panel @>");
next_button.align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_RIGHT);
next_button.callback(next_callback, (void*)&wizard);
buttons.end();
window.end();
window.show(argc, argv);
return Fl::run();
}