mirror of https://github.com/fltk/fltk
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.
This commit is contained in:
parent
d7dc491b5a
commit
b2a41e08c3
70
FL/Fl_Flex.H
70
FL/Fl_Flex.H
|
@ -2,7 +2,7 @@
|
||||||
// Fl_Flex widget header file for the Fast Light Tool Kit (FLTK).
|
// Fl_Flex widget header file for the Fast Light Tool Kit (FLTK).
|
||||||
//
|
//
|
||||||
// Copyright 2020 by Karsten Pedersen
|
// 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
|
// 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
|
// 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 {
|
class FL_EXPORT Fl_Flex : public Fl_Group {
|
||||||
|
|
||||||
int margin_left_;
|
int margin_left_; // left margin
|
||||||
int margin_top_;
|
int margin_top_; // top margin
|
||||||
int margin_right_;
|
int margin_right_; // right margin
|
||||||
int margin_bottom_;
|
int margin_bottom_; // bottom margin
|
||||||
int gap_;
|
int gap_; // gap between widgets
|
||||||
int fixed_size_size_;
|
int fixed_size_size_; // number of fixed size widgets in array
|
||||||
int fixed_size_alloc_;
|
int fixed_size_alloc_; // allocated size of fixed size array
|
||||||
Fl_Widget **fixed_size_;
|
Fl_Widget **fixed_size_; // array of fixed size widgets
|
||||||
|
bool need_layout_; // true if layout needs to be calculated
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ public:
|
||||||
Fl_Flex(int X, int Y, int W, int H, const char *L = 0);
|
Fl_Flex(int X, int Y, int W, int H, const char *L = 0);
|
||||||
|
|
||||||
// original Fl_Flex constructors:
|
// 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 direction);
|
||||||
Fl_Flex(int w, int h, 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.
|
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)
|
\param[in] size width (Fl_Flex::HORIZONTAL) or height (Fl_Flex::VERTICAL)
|
||||||
|
|
||||||
\see fixed(Fl_Widget *w, int size)
|
\see fixed(Fl_Widget *w, int size)
|
||||||
|
@ -168,9 +169,37 @@ protected:
|
||||||
virtual int alloc_size(int size) const;
|
virtual int alloc_size(int size) const;
|
||||||
|
|
||||||
void on_remove(int) FL_OVERRIDE;
|
void on_remove(int) FL_OVERRIDE;
|
||||||
|
void draw() FL_OVERRIDE;
|
||||||
|
|
||||||
public:
|
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.
|
/** Returns the left margin size of the widget.
|
||||||
|
|
||||||
This returns the \b left margin of the widget which is not necessarily
|
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;
|
margin_left_ = margin_top_ = margin_right_ = margin_bottom_ = m;
|
||||||
if (g >= 0)
|
if (g >= 0)
|
||||||
gap_ = g;
|
gap_ = g;
|
||||||
|
need_layout(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the margin sizes at all four edges of the Fl_Flex widget.
|
/** 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_top_ = top < 0 ? 0 : top;
|
||||||
margin_right_ = right < 0 ? 0 : right;
|
margin_right_ = right < 0 ? 0 : right;
|
||||||
margin_bottom_ = bottom < 0 ? 0 : bottom;
|
margin_bottom_ = bottom < 0 ? 0 : bottom;
|
||||||
|
need_layout(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the gap size of the widget.
|
/** Return the gap size of the widget.
|
||||||
|
@ -273,6 +304,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void gap(int g) {
|
void gap(int g) {
|
||||||
gap_ = g < 0 ? 0 : g;
|
gap_ = g < 0 ? 0 : g;
|
||||||
|
need_layout(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns non-zero (true) if Fl_Flex alignment is horizontal (row mode).
|
/** Returns non-zero (true) if Fl_Flex alignment is horizontal (row mode).
|
||||||
|
@ -287,19 +319,8 @@ public:
|
||||||
return type() == Fl_Flex::HORIZONTAL ? 1 : 0;
|
return type() == Fl_Flex::HORIZONTAL ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Calculate the layout of the widget and redraw it.
|
||||||
Calculates the layout of the widget and redraws it.
|
void layout();
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Gets the number of extra pixels of blank space that are added
|
Gets the number of extra pixels of blank space that are added
|
||||||
|
@ -325,6 +346,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void spacing(int i) {
|
void spacing(int i) {
|
||||||
gap(i);
|
gap(i);
|
||||||
|
need_layout(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
101
src/Fl_Flex.cxx
101
src/Fl_Flex.cxx
|
@ -2,7 +2,7 @@
|
||||||
// Fl_Flex widget implementation for the Fast Light Tool Kit (FLTK).
|
// Fl_Flex widget implementation for the Fast Light Tool Kit (FLTK).
|
||||||
//
|
//
|
||||||
// Copyright 2020 by Karsten Pedersen
|
// 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
|
// 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
|
// the file "COPYING" which should have been included with this file. If this
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <FL/Fl_Flex.H>
|
#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.
|
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) {
|
void Fl_Flex::init(int t) {
|
||||||
gap_ = 0; // default gap size
|
|
||||||
margin_left_ = 0; // default margin size
|
margin_left_ = 0; // default margin size
|
||||||
margin_top_ = 0; // default margin size
|
margin_top_ = 0; // default margin size
|
||||||
margin_right_ = 0; // default margin size
|
margin_right_ = 0; // default margin size
|
||||||
margin_bottom_ = 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_size_ = 0; // number of fixed size widgets
|
||||||
fixed_size_alloc_ = 0; // allocated size of array 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);
|
type(HORIZONTAL);
|
||||||
if (t == VERTICAL)
|
if (t == VERTICAL)
|
||||||
type(VERTICAL);
|
type(VERTICAL);
|
||||||
|
@ -138,13 +140,62 @@ Fl_Flex::~Fl_Flex() {
|
||||||
*/
|
*/
|
||||||
void Fl_Flex::on_remove(int index) {
|
void Fl_Flex::on_remove(int index) {
|
||||||
fixed(child(index), 0);
|
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) {
|
void Fl_Flex::resize(int x, int y, int w, int h) {
|
||||||
|
|
||||||
Fl_Widget::resize(x, y, w, 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 dx = Fl::box_dx(box());
|
||||||
int dy = Fl::box_dy(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());
|
int dh = Fl::box_dh(box());
|
||||||
|
|
||||||
// Calculate total space minus gaps
|
// Calculate total space minus gaps
|
||||||
int gaps = cc > 1 ? cc - 1 : 0;
|
int gaps = nc > 1 ? nc - 1 : 0;
|
||||||
int hori = horizontal();
|
int hori = horizontal();
|
||||||
int space = hori ? (w - dw - margin_left_ - margin_right_)
|
int space = hori ? (w() - dw - margin_left_ - margin_right_)
|
||||||
: (h - dh - margin_top_ - margin_bottom_);
|
: (h() - dh - margin_top_ - margin_bottom_);
|
||||||
|
|
||||||
// set x and y (start) position, calculate widget sizes
|
// set x and y (start) position, calculate widget sizes
|
||||||
int xp = x + dx + margin_left_;
|
int xp = x() + dx + margin_left_;
|
||||||
int yp = y + dy + margin_top_;
|
int yp = y() + dy + margin_top_;
|
||||||
int hh = h - dh - margin_top_ - margin_bottom_; // if horizontal: constant height of widgets
|
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 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
|
// 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);
|
Fl_Widget *c = child(i);
|
||||||
if (c->visible()) {
|
if (c->visible()) {
|
||||||
if (fixed(c)) {
|
if (fixed(c)) {
|
||||||
|
@ -194,7 +245,7 @@ void Fl_Flex::resize(int x, int y, int w, int h) {
|
||||||
sp++;
|
sp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < cc; i++) {
|
for (int i = 0; i < nc; i++) {
|
||||||
Fl_Widget *c = child(i);
|
Fl_Widget *c = child(i);
|
||||||
if (!c->visible())
|
if (!c->visible())
|
||||||
continue;
|
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.
|
Ends automatic child addition and resizes all children.
|
||||||
|
|
||||||
This calculates the layout depending on all children and whether
|
This marks the Fl_Flex widget as changed (need_layout(1)) which forces the
|
||||||
they have been assigned fix sizes or not.
|
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() {
|
void Fl_Flex::end() {
|
||||||
Fl_Group::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
|
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).
|
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
|
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
|
This can be used to set a fixed widget width or height of children
|
||||||
of Fl_Flex so they are not resized dynamically.
|
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_[i] = fixed_size_[i+1];
|
||||||
}
|
}
|
||||||
fixed_size_size_--;
|
fixed_size_size_--;
|
||||||
|
need_layout(1);
|
||||||
return;
|
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)
|
if (size == 0)
|
||||||
return;
|
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()));
|
child->size(size, h()-margin_top_-margin_bottom_-Fl::box_dh(box()));
|
||||||
else
|
else
|
||||||
child->size(w()-margin_left_-margin_right_-Fl::box_dw(box()), size);
|
child->size(w()-margin_left_-margin_right_-Fl::box_dw(box()), size);
|
||||||
|
need_layout(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue