summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbrecht Schlosser <albrechts.fltk@online.de>2023-09-04 16:16:40 +0200
committerAlbrecht Schlosser <albrechts.fltk@online.de>2023-09-04 16:16:42 +0200
commitb2a41e08c3b9b5fbbd0c899537611b8e28e5993d (patch)
tree13a5cdfa90075847c6754bd31e5fcbf093d8fe12
parentd7dc491b5a35cf72769ca99577b39c5470106a6a (diff)
Introduce Fl_Flex::need_layout() to optimize layout calculation
This is intended to reduce layout calculation and resizing of child widgets until necessary before the Fl_Flex widget and all its children are drawn in Fl_Flex::draw(). With this commit users no longer need to call layout() to layout the Fl_Flex widget and its children properly unless they change widget sizes or show/hide children.
-rw-r--r--FL/Fl_Flex.H70
-rw-r--r--src/Fl_Flex.cxx101
2 files changed, 126 insertions, 45 deletions
diff --git a/FL/Fl_Flex.H b/FL/Fl_Flex.H
index 6d8a76fbd..20b4f50f5 100644
--- a/FL/Fl_Flex.H
+++ b/FL/Fl_Flex.H
@@ -2,7 +2,7 @@
// Fl_Flex widget header file 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
@@ -113,14 +113,15 @@
*/
class FL_EXPORT Fl_Flex : public Fl_Group {
- int margin_left_;
- int margin_top_;
- int margin_right_;
- int margin_bottom_;
- int gap_;
- int fixed_size_size_;
- int fixed_size_alloc_;
- Fl_Widget **fixed_size_;
+ int margin_left_; // left margin
+ int margin_top_; // top margin
+ int margin_right_; // right margin
+ int margin_bottom_; // bottom margin
+ int gap_; // gap between widgets
+ int fixed_size_size_; // number of fixed size widgets in array
+ int fixed_size_alloc_; // allocated size of fixed size array
+ Fl_Widget **fixed_size_; // array of fixed size widgets
+ bool need_layout_; // true if layout needs to be calculated
public:
@@ -135,7 +136,7 @@ public:
Fl_Flex(int X, int Y, int W, int H, const char *L = 0);
// original Fl_Flex constructors:
- // backwards compatible if direction *names* { ROW | COLUMN } are used
+ // backwards compatible if direction enums { ROW | COLUMN } are used
Fl_Flex(int direction);
Fl_Flex(int w, int h, int direction);
@@ -149,7 +150,7 @@ public:
/**
Set the horizontal or vertical size of a child widget.
- \param[in] w widget to be affected
+ \param[in] w widget to be affected
\param[in] size width (Fl_Flex::HORIZONTAL) or height (Fl_Flex::VERTICAL)
\see fixed(Fl_Widget *w, int size)
@@ -168,9 +169,37 @@ protected:
virtual int alloc_size(int size) const;
void on_remove(int) FL_OVERRIDE;
+ void draw() FL_OVERRIDE;
public:
+ /**
+ Set or reset the request to calculate the layout of children.
+
+ This is intended for internal use but can also be used by user
+ code to request layout calculation before the widget is drawn.
+
+ Call this if you changed attributes or sizes of children to ensure
+ that the layout is calculated properly. Changing other Fl_Flex
+ attributes or resizing the widget does this automatically.
+
+ \note Never call this with '\c set == 0' because this would defeat its
+ purpose to recalculate the layout before the widget is drawn.
+ */
+ void need_layout(int set) {
+ if (set) need_layout_ = true;
+ else need_layout_ = false;
+ }
+
+ /**
+ Returns whether layout calculation is required.
+
+ This should rarely be needed by user code. Used internally in draw().
+ */
+ bool need_layout() const {
+ return need_layout_;
+ }
+
/** Returns the left margin size of the widget.
This returns the \b left margin of the widget which is not necessarily
@@ -233,6 +262,7 @@ public:
margin_left_ = margin_top_ = margin_right_ = margin_bottom_ = m;
if (g >= 0)
gap_ = g;
+ need_layout(1);
}
/** Set the margin sizes at all four edges of the Fl_Flex widget.
@@ -254,6 +284,7 @@ public:
margin_top_ = top < 0 ? 0 : top;
margin_right_ = right < 0 ? 0 : right;
margin_bottom_ = bottom < 0 ? 0 : bottom;
+ need_layout(1);
}
/** Return the gap size of the widget.
@@ -273,6 +304,7 @@ public:
*/
void gap(int g) {
gap_ = g < 0 ? 0 : g;
+ need_layout(1);
}
/** Returns non-zero (true) if Fl_Flex alignment is horizontal (row mode).
@@ -287,19 +319,8 @@ public:
return type() == Fl_Flex::HORIZONTAL ? 1 : 0;
}
- /**
- Calculates the layout of the widget and redraws it.
-
- If you change widgets in the Fl_Flex container you should call this method
- to force recalculation of child widget sizes and positions. This can be
- useful (necessary) if you hide(), show(), add() or remove() children.
-
- This method also calls redraw() on the Fl_Flex widget.
- */
- void layout() {
- resize(x(), y(), w(), h());
- redraw();
- }
+ // Calculate the layout of the widget and redraw it.
+ void layout();
/**
Gets the number of extra pixels of blank space that are added
@@ -325,6 +346,7 @@ public:
*/
void spacing(int i) {
gap(i);
+ need_layout(1);
}
};
diff --git a/src/Fl_Flex.cxx b/src/Fl_Flex.cxx
index 5167bc4d1..81f200b14 100644
--- a/src/Fl_Flex.cxx
+++ b/src/Fl_Flex.cxx
@@ -2,7 +2,7 @@
// Fl_Flex widget implementation 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
@@ -16,7 +16,7 @@
//
#include <FL/Fl_Flex.H>
-#include <stdlib.h>
+#include <stdlib.h> // malloc, free, ...
/**
Construct a new Fl_Flex widget with the given position, size, and label.
@@ -114,14 +114,16 @@ Fl_Flex::Fl_Flex(int x, int y, int w, int h, int direction)
}
void Fl_Flex::init(int t) {
- gap_ = 0; // default gap size
margin_left_ = 0; // default margin size
margin_top_ = 0; // default margin size
margin_right_ = 0; // default margin size
margin_bottom_ = 0; // default margin size
- fixed_size_ = NULL; // array of fixed size widgets
+ gap_ = 0; // default gap size
fixed_size_size_ = 0; // number of fixed size widgets
fixed_size_alloc_ = 0; // allocated size of array of fixed size widgets
+ fixed_size_ = NULL; // array of fixed size widgets
+ need_layout_ = false; // no need to calculate layout yet
+
type(HORIZONTAL);
if (t == VERTICAL)
type(VERTICAL);
@@ -138,13 +140,62 @@ Fl_Flex::~Fl_Flex() {
*/
void Fl_Flex::on_remove(int index) {
fixed(child(index), 0);
+ need_layout(1);
+}
+
+/**
+ Draw the widget.
+
+ This will finally calculate the layout of the widget and of all its
+ children if necessary and draw the widget.
+
+ Some changes of included children may require a new layout to be
+ calculated. If this is the case the user may need to call layout()
+ to make sure everything is calculated properly.
+
+ \see layout()
+*/
+void Fl_Flex::draw() {
+ if (need_layout()) {
+ layout();
+ }
+ need_layout(0);
+ Fl_Group::draw();
}
+/**
+ Resize the container and calculate all child positions and sizes.
+
+ \param[in] x,y position
+ \param[in] w,h width and height
+*/
void Fl_Flex::resize(int x, int y, int w, int h) {
Fl_Widget::resize(x, y, w, h);
+ need_layout(1);
- int cc = children();
+} // resize()
+
+
+
+/**
+ Calculates the layout of the widget and redraws it.
+
+ If you change widgets in the Fl_Flex container you should call this method
+ to force recalculation of child widget sizes and positions. This can be
+ useful (necessary) if you hide(), show(), add() or remove() children.
+
+ Call this method if you need to recalculate widget positions for usage in
+ an algorithm that places widgets at certain positions or when you need to
+ display (show) or hide one or more children depending on the current layout
+ (for instance a side bar).
+
+ This method also calls redraw() on the Fl_Flex widget.
+*/
+void Fl_Flex::layout() {
+ resize(x(), y(), w(), h());
+
+ const int nc = children();
int dx = Fl::box_dx(box());
int dy = Fl::box_dy(box());
@@ -152,22 +203,22 @@ void Fl_Flex::resize(int x, int y, int w, int h) {
int dh = Fl::box_dh(box());
// Calculate total space minus gaps
- int gaps = cc > 1 ? cc - 1 : 0;
+ int gaps = nc > 1 ? nc - 1 : 0;
int hori = horizontal();
- int space = hori ? (w - dw - margin_left_ - margin_right_)
- : (h - dh - margin_top_ - margin_bottom_);
+ int space = hori ? (w() - dw - margin_left_ - margin_right_)
+ : (h() - dh - margin_top_ - margin_bottom_);
// set x and y (start) position, calculate widget sizes
- int xp = x + dx + margin_left_;
- int yp = y + dy + margin_top_;
- int hh = h - dh - margin_top_ - margin_bottom_; // if horizontal: constant height of widgets
- int vw = w - dw - margin_left_ - margin_right_; // if vertical: constant width of widgets
+ int xp = x() + dx + margin_left_;
+ int yp = y() + dy + margin_top_;
+ int hh = h() - dh - margin_top_ - margin_bottom_; // if horizontal: constant height of widgets
+ int vw = w() - dw - margin_left_ - margin_right_; // if vertical: constant width of widgets
- int fw = cc; // number of flexible widgets
+ int fw = nc; // number of flexible widgets
// Precalculate remaining space that can be distributed
- for (int i = 0; i < cc; i++) {
+ for (int i = 0; i < nc; i++) {
Fl_Widget *c = child(i);
if (c->visible()) {
if (fixed(c)) {
@@ -194,7 +245,7 @@ void Fl_Flex::resize(int x, int y, int w, int h) {
sp++;
}
- for (int i = 0; i < cc; i++) {
+ for (int i = 0; i < nc; i++) {
Fl_Widget *c = child(i);
if (!c->visible())
continue;
@@ -218,17 +269,23 @@ void Fl_Flex::resize(int x, int y, int w, int h) {
}
}
-} // resize()
+ need_layout(0); // layout done, no need to do it again when drawing
+ redraw();
+}
/**
Ends automatic child addition and resizes all children.
- This calculates the layout depending on all children and whether
- they have been assigned fix sizes or not.
+ This marks the Fl_Flex widget as changed (need_layout(1)) which forces the
+ widget to calculate its layout depending on all children and whether
+ they have been assigned fix sizes or not right before it is drawn.
+
+ \see layout()
+ \see draw()
*/
void Fl_Flex::end() {
Fl_Group::end();
- resize(x(), y(), w(), h());
+ need_layout(1);
}
/**
@@ -237,7 +294,7 @@ void Fl_Flex::end() {
This sets either the width or height of a child widget, depending on the
type() of the Fl_Flex container (Fl_Flex::HORIZONTAL or Fl_Flex::VERTICAL).
The other dimension is set to the full width or height of the Fl_Flex widget
- minus margin sizes.
+ minus border and margin sizes.
This can be used to set a fixed widget width or height of children
of Fl_Flex so they are not resized dynamically.
@@ -266,10 +323,11 @@ void Fl_Flex::fixed(Fl_Widget *child, int size) {
fixed_size_[i] = fixed_size_[i+1];
}
fixed_size_size_--;
+ need_layout(1);
return;
}
- // if w is meant to be flexible, we are done now
+ // if w is meant to be flexible and we didn't find it, we are done now
if (size == 0)
return;
@@ -288,6 +346,7 @@ void Fl_Flex::fixed(Fl_Widget *child, int size) {
child->size(size, h()-margin_top_-margin_bottom_-Fl::box_dh(box()));
else
child->size(w()-margin_left_-margin_right_-Fl::box_dw(box()), size);
+ need_layout(1);
}
/**