1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
//
// Fl_Flex widget implementation for the Fast Light Tool Kit (FLTK).
//
// Copyright 2020 by Karsten Pedersen
// Copyright 2022 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_Flex.H>
#include <stdlib.h>
/**
Construct a new Fl_Flex widget with the given position, size, and label.
You can set \p type(Fl_Flex::HORIZONTAL) or \p type(Fl_Flex::VERTICAL).
The default is \p type(Fl_Flex::VERTICAL).
Alternate constructors let you specify the layout as Fl_Flex::HORIZONTAL or
Fl_Flex::VERTICAL directly. Fl_Flex::ROW is an alias of Fl_Flex::HORIZONTAL
and Fl_Flex::COLUMN is an alias of Fl_Flex::VERTICAL.
\param[in] X,Y position
\param[in] W,H size (width and height)
\param[in] L label (optional)
\see Fl_Flex::Fl_Flex(int direction)
\see Fl_Flex::Fl_Flex(int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, const char *L)
*/
Fl_Flex::Fl_Flex(int X, int Y, int W, int H, const char *L)
: Fl_Group(X, Y, W, H, L) {
init();
}
// special Fl_Flex constructors w/o label (backwards compatible with original Fl_Flex widget)
/**
Construct a new Fl_Flex widget specifying its layout.
Use Fl_Flex::HORIZONTAL (aka Fl_Flex::ROW) or Fl_Flex::VERTICAL
(aka Fl_Flex::COLUMN) as the \p direction argument.
This constructor sets the position and size to (0, 0, 0, 0) which is suitable
for nested Fl_Flex widgets. Use one of the other constructors to set the
desired position and size as well.
\param[in] direction horizontal (row) or vertical (column) layout
\see Fl_Flex::Fl_Flex(int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, const char *L)
*/
Fl_Flex::Fl_Flex(int direction)
: Fl_Group(0, 0, 0, 0, 0) {
init(direction);
}
/**
Construct a new Fl_Flex widget specifying its layout and size.
Use Fl_Flex::HORIZONTAL (aka Fl_Flex::ROW) or Fl_Flex::VERTICAL
(aka Fl_Flex::COLUMN) as the \p direction argument.
This constructor sets the position to (x = 0, y = 0) which is suitable
for nested Fl_Flex widgets. Use one of the other constructors to set the
desired position as well.
\param[in] w,h widget size
\param[in] direction horizontal (row) or vertical (column) layout
\see Fl_Flex::Fl_Flex(int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, const char *L)
*/
Fl_Flex::Fl_Flex(int w, int h, int direction)
: Fl_Group(0, 0, w, h, 0) {
init(direction);
}
/**
Construct a new Fl_Flex widget specifying its layout, position, and size.
Use Fl_Flex::HORIZONTAL (aka Fl_Flex::ROW) or Fl_Flex::VERTICAL
(aka Fl_Flex::COLUMN) as the \p direction argument.
This constructor sets the position and size of the widget which is suitable
for top level Fl_Flex widgets but does not set a widget label.
Use Fl_Widget::label() to set one if desired.
\param[in] x,y widget position
\param[in] w,h widget size
\param[in] direction horizontal (row) or vertical (column) layout
\see Fl_Flex::Fl_Flex(int direction)
\see Fl_Flex::Fl_Flex(int w, int h, int direction)
\see Fl_Flex::Fl_Flex(int x, int y, int w, int h, const char *L)
*/
Fl_Flex::Fl_Flex(int x, int y, int w, int h, int direction)
: Fl_Group(x, y, w, h, 0) {
init(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
set_size_ = NULL; // array of fixed size widgets
set_size_size_ = 0; // number of fixed size widgets
set_size_alloc_ = 0; // allocated size of array of fixed size widgets
type(HORIZONTAL);
if (t == VERTICAL)
type(VERTICAL);
}
Fl_Flex::~Fl_Flex() {
if (set_size_)
free(set_size_);
}
/*
Fl_Group calls this method when a child widget is about to be removed.
Make sure that the widget is also removed from our fixed list.
*/
void Fl_Flex::on_remove(int index) {
set_size(child(index), 0);
}
void Fl_Flex::resize(int x, int y, int w, int h) {
Fl_Widget::resize(x, y, w, h);
int cc = children();
int dx = Fl::box_dx(box());
int dy = Fl::box_dy(box());
int dw = Fl::box_dw(box());
int dh = Fl::box_dh(box());
// Calculate total space minus gaps
int gaps = cc > 1 ? cc - 1 : 0;
int hori = horizontal();
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 fw = cc; // number of flexible widgets
// Precalculate remaining space that can be distributed
for (int i = 0; i < cc; i++) {
Fl_Widget *c = child(i);
if (c->visible()) {
if (set_size(c)) {
space -= (hori ? c->w() : c->h());
fw--;
}
} else { // hidden widget
fw--;
gaps--;
}
}
if (gaps > 0)
space -= gaps * gap_;
// Set children to shared width/height of remaining space
int sp = 0; // width or height of flexible widget
int rem = 0; // remainder (to be distributed evenly)
if (fw > 0) {
sp = space / fw;
rem = space % fw;
if (rem) // adjust space for first 'rem' widgets
sp++;
}
for (int i = 0; i < cc; i++) {
Fl_Widget *c = child(i);
if (!c->visible())
continue;
if (hori) {
if (set_size(c)) {
c->resize(xp, yp, c->w(), hh);
} else {
c->resize(xp, yp, sp, hh);
if (--rem == 0) sp--;
}
xp += c->w() + gap_;
} else {
if (set_size(c)) {
c->resize(xp, yp, vw, c->h());
} else {
c->resize(xp, yp, vw, sp);
if (--rem == 0) sp--;
}
yp += c->h() + gap_;
}
}
} // resize()
/**
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.
*/
void Fl_Flex::end() {
Fl_Group::end();
resize(x(), y(), w(), h());
}
/**
Set the horizontal or vertical size of a child widget.
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.
This can be used to set a fixed widget width or height of children
of Fl_Flex so they are not resized dynamically.
If \p size is 0 (zero) or negative the widget size is reset to flexible size.
\param[in] child widget to be affected
\param[in] size width (Fl_Flex::HORIZONTAL) or height (Fl_Flex::VERTICAL)
*/
void Fl_Flex::set_size(Fl_Widget *child, int size) {
if (size <= 0)
size = 0;
// find w in our fixed size list
int idx = -1;
for (int i = 0; i < set_size_size_; i++) {
if (set_size_[i] == child) {
idx = i;
break;
}
}
// remove from array, if we want the widget to be flexible, but an entry was found
if (size == 0 && idx >= 0) {
for (int i = idx; i < set_size_size_ - 1; i++) {
set_size_[i] = set_size_[i+1];
}
set_size_size_--;
return;
}
// if w is meant to be flexible, we are done now
if (size == 0)
return;
// if we have no entry yet, add to array of fixed size widgets
if (idx == -1) {
if (set_size_size_ == set_size_alloc_) {
set_size_alloc_ = alloc_size(set_size_alloc_);
set_size_ = (Fl_Widget **)realloc(set_size_, set_size_alloc_ * sizeof(Fl_Widget *));
}
set_size_[set_size_size_] = child;
set_size_size_++;
}
// if the child size is meant to be fixed, set its new size
if (horizontal())
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);
}
/**
Return whether the given widget has a fixed size or resizes dynamically.
\param[in] w widget
\return whether the widget has a fixed size
\retval 1 the widget has a fixed size
\retval 0 the widget resizes dynamically
*/
int Fl_Flex::set_size(Fl_Widget *w) const {
for (int i = 0; i < set_size_size_; i++) {
if (w == set_size_[i]) {
return 1;
}
}
return 0;
}
/**
Return new size to be allocated for array of fixed size widgets.
This method is called when the array of fixed size widgets needs to be
expanded. The current \p size is provided (size can be 0). The default
method adds 8 to the current size.
This can be used in derived classes to change the allocation strategy.
Note that this method only \p queries the new size which shall be allocated
but does not allocate the memory.
\param[in] size current size
\return int new size (to be allocated)
*/
int Fl_Flex::alloc_size(int size) const {
return size + 8;
}
|