Fix Fl_Pack to support more box types.

Old code supported only frame styles, this code
can now handle box types with a background.
This commit is contained in:
Matthias Melcher
2025-12-29 16:21:17 +01:00
parent 2fb67053a1
commit 83fab8cb0f
3 changed files with 41 additions and 10 deletions

View File

@@ -21,6 +21,7 @@
#define Fl_Pack_H #define Fl_Pack_H
#include <FL/Fl_Group.H> #include <FL/Fl_Group.H>
#include <FL/Fl_Rect.H>
/** /**
This widget was designed to add the functionality of compressing and This widget was designed to add the functionality of compressing and
@@ -39,6 +40,12 @@
resizable() widget is the last widget in the group it is extended to take resizable() widget is the last widget in the group it is extended to take
the full available width or height, respectively, of the Fl_Pack group. the full available width or height, respectively, of the Fl_Pack group.
\note Fl_Pack is optimized to use a frame-only (`..._FRAME`) box type.
Box types with background graphics (`..._BOX`) generally work, but can be
slower witch a large number of children. Not all box types work well
with FL_Pack. Avoid irregular graphics like FL_DIAMOND_BOX and background
images.
\note You can nest Fl_Pack widgets or put them inside Fl_Scroll widgets \note You can nest Fl_Pack widgets or put them inside Fl_Scroll widgets
or inside other group widgets but their behavior can sometimes be or inside other group widgets but their behavior can sometimes be
<i>"surprising"</i>. This is partly due to the fact that Fl_Pack widgets <i>"surprising"</i>. This is partly due to the fact that Fl_Pack widgets
@@ -61,6 +68,7 @@ public:
}; };
protected: protected:
void draw_filler_(const Fl_Rect& rect);
void draw() override; void draw() override;
public: public:

View File

@@ -49,6 +49,22 @@ Fl_Pack::Fl_Pack(int X, int Y, int W, int H, const char *L)
// type(VERTICAL); // already set like this // type(VERTICAL); // already set like this
} }
/** Draw a rectangular area as a background filler.
If the box type has a background (is not a frame), this will clip to the
rectangular area and draw the box. Otherwise, it will draw a rectangle
in widget color.
\param[in] rect fill this rectangle inside the widget bounds
*/
void Fl_Pack::draw_filler_(const Fl_Rect& rect) {
if (Fl::box_bg(box())) {
fl_push_clip(rect.x(), rect.y(), rect.w(), rect.h());
draw_box();
fl_pop_clip();
} else {
fl_rectf(rect.x(), rect.y(), rect.w(), rect.h(), color());
}
}
void Fl_Pack::draw() { void Fl_Pack::draw() {
int tx = x()+Fl::box_dx(box()); int tx = x()+Fl::box_dx(box());
int ty = y()+Fl::box_dy(box()); int ty = y()+Fl::box_dy(box());
@@ -102,11 +118,10 @@ void Fl_Pack::draw() {
} }
if (spacing_ && current_position>maximum_position && box() && if (spacing_ && current_position>maximum_position && box() &&
(X != o->x() || Y != o->y() || d&FL_DAMAGE_ALL)) { (X != o->x() || Y != o->y() || d&FL_DAMAGE_ALL)) {
fl_color(color());
if (horizontal()) if (horizontal())
fl_rectf(maximum_position, ty, spacing_, th); draw_filler_( { maximum_position, ty, spacing_, th } );
else else
fl_rectf(tx, maximum_position, tw, spacing_); draw_filler_( { tx, maximum_position, tw, spacing_ } );
} }
if (X != o->x() || Y != o->y() || W != o->w() || H != o->h()) { if (X != o->x() || Y != o->y() || W != o->w() || H != o->h()) {
o->resize(X,Y,W,H); o->resize(X,Y,W,H);
@@ -132,14 +147,12 @@ void Fl_Pack::draw() {
if (horizontal()) { if (horizontal()) {
if (maximum_position < tx+tw && box()) { if (maximum_position < tx+tw && box()) {
fl_color(color()); draw_filler_( { maximum_position, ty, tx+tw-maximum_position, th } );
fl_rectf(maximum_position, ty, tx+tw-maximum_position, th);
} }
tw = maximum_position-tx; tw = maximum_position-tx;
} else { } else {
if (maximum_position < ty+th && box()) { if (maximum_position < ty+th && box()) {
fl_color(color()); draw_filler_( { tx, maximum_position, tw, ty+th-maximum_position } );
fl_rectf(tx, maximum_position, tw, ty+th-maximum_position);
} }
th = maximum_position-ty; th = maximum_position-ty;
} }
@@ -153,7 +166,13 @@ void Fl_Pack::draw() {
d = FL_DAMAGE_ALL; d = FL_DAMAGE_ALL;
} }
if (d&FL_DAMAGE_ALL) { if (d&FL_DAMAGE_ALL) {
draw_box(); if (Fl::box_bg(box())) {
// Make sure that we only draw the frame part, because the children
// and fillers are already rendered at this point.
draw_box(fl_frame(box()), x(), y(), w(), h(), color());
} else {
draw_box();
}
draw_label(); draw_label();
} }
} }

View File

@@ -186,9 +186,11 @@ Fl_Input::paste_menu_text = gettext("Paste");} {}
MenuItem {} { MenuItem {} {
label sandals label sandals
callback {[](Fl_Widget*, void*) callback {[](Fl_Widget*, void*)
/* If this code generates an error, you are using an older version of Fluid */
/* Support for lambda callbacks was added dec 12 2025 */
{ {
puts("The shoe is the sign!"); puts("The shoe is the sign!");
}} selected }}
xywh {0 0 100 20} xywh {0 0 100 20}
} }
MenuItem {} { MenuItem {} {
@@ -223,6 +225,8 @@ Fl_Input::paste_menu_text = gettext("Paste");} {}
Fl_Check_Button wShave { Fl_Check_Button wShave {
label shave label shave
callback {[](Fl_Widget* w, void*)->void { callback {[](Fl_Widget* w, void*)->void {
/* If this code generates an error, you are using an older version of Fluid */
/* Support for lambda callbacks was added dec 12 2025 */
auto* btn = static_cast<Fl_Check_Button*>(w); auto* btn = static_cast<Fl_Check_Button*>(w);
if (btn->value()) { if (btn->value()) {
puts("Shave."); puts("Shave.");
@@ -230,7 +234,7 @@ Fl_Input::paste_menu_text = gettext("Paste");} {}
puts("Don't shave."); puts("Don't shave.");
} }
}} }}
comment {// Testing lambdas for callbacks} comment {// Testing lambdas for callbacks} selected
xywh {25 212 105 24} down_box DOWN_BOX xywh {25 212 105 24} down_box DOWN_BOX
} }
Fl_Check_Button wBrush { Fl_Check_Button wBrush {