summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt4
-rw-r--r--FL/Fl_Button.H9
-rw-r--r--fluid/Fl_Button_Type.cxx28
-rw-r--r--fluid/Fl_Button_Type.h4
-rw-r--r--fluid/Fl_Widget_Type.cxx34
-rw-r--r--fluid/alignment_panel.cxx3
-rw-r--r--fluid/alignment_panel.fl10
-rw-r--r--fluid/widget_panel.cxx8
-rw-r--r--fluid/widget_panel.fl7
-rw-r--r--fluid/widget_panel.h1
-rw-r--r--src/Fl.cxx4
-rw-r--r--src/Fl_Button.cxx56
-rw-r--r--src/fl_boxtype.cxx4
-rw-r--r--test/buttons.cxx21
-rw-r--r--test/inactive.fl34
15 files changed, 197 insertions, 30 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 010a8c5e6..037c18397 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -51,7 +51,11 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2022
- New Fl_ICO_Image class to read Windows .ico icon files.
- New classes Fl_SVG_File_Surface and Fl_EPS_File_Surface to save any FLTK
graphics to SVG or EPS files, respectively.
+ - Fl_Button now supports a compact flag that visually groups closely set
+ buttons into keypads.
- Fl_Tabs now supports close buttons for individual tabs.
+ - Fl_Tabs now support four different modes for handling an
+ overflowing number of tabs.
- Windows platform: added support for using a manifest to set the
application's level of DPI awareness (issue #309).
- class Fl_Native_File_Chooser on the X11/Wayland platform relies on external
diff --git a/FL/Fl_Button.H b/FL/Fl_Button.H
index 9908b9742..31b71a416 100644
--- a/FL/Fl_Button.H
+++ b/FL/Fl_Button.H
@@ -79,6 +79,7 @@ class FL_EXPORT Fl_Button : public Fl_Widget {
char value_;
char oldval;
uchar down_box_;
+ uchar compact_;
protected:
@@ -167,6 +168,14 @@ public:
/// (for backwards compatibility)
void down_color(unsigned c) {selection_color(c);}
+
+ // handle flag for compact buttons, documentation in source code
+ void compact(uchar v);
+
+ /// Return true if buttons are rendered as compact buttons.
+ /// \return 0 if compact mode is off, 1 if it is on
+ /// \see compact(bool)
+ uchar compact() { return compact_; }
};
#endif
diff --git a/fluid/Fl_Button_Type.cxx b/fluid/Fl_Button_Type.cxx
index 53355b7c3..ee12c731a 100644
--- a/fluid/Fl_Button_Type.cxx
+++ b/fluid/Fl_Button_Type.cxx
@@ -25,6 +25,7 @@
#include "Fl_Button_Type.h"
#include "Fd_Snap_Action.h"
+#include "file.h"
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
@@ -34,6 +35,9 @@
#include <FL/Fl_Repeat_Button.H>
#include <FL/Fl_Round_Button.H>
+#include <stdlib.h>
+
+
// ---- Button Types --------------------------------------------------- MARK: -
@@ -61,6 +65,30 @@ Fl_Widget *Fl_Button_Type::widget(int x, int y, int w, int h) {
return new Fl_Button(x, y, w, h, "Button");
}
+void Fl_Button_Type::write_properties(Fd_Project_Writer &f) {
+ Fl_Widget_Type::write_properties(f);
+ Fl_Button *btn = (Fl_Button*)o;
+ if (btn->compact()) {
+ f.write_string("compact");
+ f.write_string("%d", btn->compact());
+ }
+}
+
+void Fl_Button_Type::read_property(Fd_Project_Reader &f, const char *c) {
+ Fl_Button *btn = (Fl_Button*)o;
+ if (!strcmp(c, "compact")) {
+ btn->compact((uchar)atol(f.read_word()));
+ } else {
+ Fl_Widget_Type::read_property(f, c);
+ }
+}
+
+void Fl_Button_Type::copy_properties() {
+ Fl_Widget_Type::copy_properties();
+ Fl_Button *s = (Fl_Button*)o, *d = (Fl_Button*)live_widget;
+ d->compact(s->compact());
+}
+
Fl_Button_Type Fl_Button_type;
diff --git a/fluid/Fl_Button_Type.h b/fluid/Fl_Button_Type.h
index 743c1fdd5..c731ce7e7 100644
--- a/fluid/Fl_Button_Type.h
+++ b/fluid/Fl_Button_Type.h
@@ -35,6 +35,10 @@ public:
int is_button() const FL_OVERRIDE { return 1; }
ID id() const FL_OVERRIDE { return ID_Button; }
bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Button) ? true : super::is_a(inID); }
+ void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+ void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
+ void copy_properties() FL_OVERRIDE;
+
};
extern Fl_Button_Type Fl_Button_type;
diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx
index 7418e65e1..3eddc890f 100644
--- a/fluid/Fl_Widget_Type.cxx
+++ b/fluid/Fl_Widget_Type.cxx
@@ -1081,6 +1081,39 @@ void down_box_cb(Fl_Choice* i, void *v) {
}
}
+void compact_cb(Fl_Light_Button* i, void* v) {
+ if (v == LOAD) {
+ uchar n;
+ if (current_widget->is_a(Fl_Type::ID_Button)) {
+ n = ((Fl_Button*)(current_widget->o))->compact();
+ i->value(n);
+ i->show();
+ } else {
+ i->hide();
+ }
+ } else {
+ int mod = 0;
+ uchar n = (uchar)i->value();
+ for (Fl_Type *o = Fl_Type::first; o; o = o->next) {
+ if (o->selected && o->is_a(Fl_Type::ID_Button)) {
+ Fl_Widget_Type* q = (Fl_Widget_Type*)o;
+ uchar v = ((Fl_Button*)(q->o))->compact();
+ if (n != v) {
+ if (!mod) {
+ mod = 1;
+ undo_checkpoint();
+ }
+ ((Fl_Button*)(q->o))->compact(n);
+ q->redraw();
+ }
+ }
+ }
+ if (mod) set_modflag(1);
+ }
+}
+
+
+
////////////////////////////////////////////////////////////////
Fl_Menu_Item whenmenu[] = {
@@ -3039,6 +3072,7 @@ void Fl_Widget_Type::write_widget_code(Fd_Code_Writer& f) {
if (b->down_box()) f.write_c("%s%s->down_box(FL_%s);\n", f.indent(), var,
boxname(b->down_box()));
if (b->value()) f.write_c("%s%s->value(1);\n", f.indent(), var);
+ if (b->compact()) f.write_c("%s%s->compact(%d);\n", f.indent(), var, b->compact());
} else if (is_a(Fl_Type::ID_Input_Choice)) {
Fl_Input_Choice* b = (Fl_Input_Choice*)o;
if (b->down_box()) f.write_c("%s%s->down_box(FL_%s);\n", f.indent(), var,
diff --git a/fluid/alignment_panel.cxx b/fluid/alignment_panel.cxx
index b3df61cfe..29f21fd4c 100644
--- a/fluid/alignment_panel.cxx
+++ b/fluid/alignment_panel.cxx
@@ -1239,18 +1239,21 @@ ped using octal notation `\\0123`. If this option is checked, Fluid will write\
{ preset_choice[0] = new Fl_Button(85, 107, 78, 20, "Application");
preset_choice[0]->type(102);
preset_choice[0]->value(1);
+ preset_choice[0]->compact(1);
preset_choice[0]->selection_color(FL_DARK2);
preset_choice[0]->labelsize(11);
preset_choice[0]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(0));
} // Fl_Button* preset_choice[0]
{ preset_choice[1] = new Fl_Button(163, 107, 79, 20, "Dialog");
preset_choice[1]->type(102);
+ preset_choice[1]->compact(1);
preset_choice[1]->selection_color(FL_DARK2);
preset_choice[1]->labelsize(11);
preset_choice[1]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(1));
} // Fl_Button* preset_choice[1]
{ preset_choice[2] = new Fl_Button(242, 107, 78, 20, "Toolbox");
preset_choice[2]->type(102);
+ preset_choice[2]->compact(1);
preset_choice[2]->selection_color(FL_DARK2);
preset_choice[2]->labelsize(11);
preset_choice[2]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(2));
diff --git a/fluid/alignment_panel.fl b/fluid/alignment_panel.fl
index d6b9325b4..845d7b7f6 100644
--- a/fluid/alignment_panel.fl
+++ b/fluid/alignment_panel.fl
@@ -107,7 +107,7 @@ decl {void scheme_cb(Fl_Scheme_Choice *, void *);} {public local
Function {make_settings_window()} {open
} {
Fl_Window settings_window {
- label {FLUID Settings} open selected
+ label {FLUID Settings} open
xywh {423 204 340 580} type Double align 80 non_modal visible
} {
Fl_Tabs w_settings_tabs {
@@ -115,7 +115,7 @@ Function {make_settings_window()} {open
xywh {10 10 320 530} selection_color 12 labelsize 11 labelcolor 255
} {
Fl_Group {} {
- label General open
+ label General open selected
image {icons/general_64.png} compress_image 1 xywh {10 60 320 480} labelsize 11
code0 {o->image()->scale(36, 24);}
} {
@@ -471,19 +471,19 @@ g_layout_list.update_dialogs();}
label Application
user_data 0 user_data_type long
callback edit_layout_preset_cb
- xywh {85 107 78 20} type Radio value 1 selection_color 45 labelsize 11
+ xywh {85 107 78 20} type Radio value 1 selection_color 45 labelsize 11 compact 1
}
Fl_Button {preset_choice[1]} {
label Dialog
user_data 1 user_data_type long
callback edit_layout_preset_cb
- xywh {163 107 79 20} type Radio selection_color 45 labelsize 11
+ xywh {163 107 79 20} type Radio selection_color 45 labelsize 11 compact 1
}
Fl_Button {preset_choice[2]} {
label Toolbox
user_data 2 user_data_type long
callback edit_layout_preset_cb
- xywh {242 107 78 20} type Radio selection_color 45 labelsize 11
+ xywh {242 107 78 20} type Radio selection_color 45 labelsize 11 compact 1
}
}
Fl_Box {} {
diff --git a/fluid/widget_panel.cxx b/fluid/widget_panel.cxx
index 4bb22b797..12976268b 100644
--- a/fluid/widget_panel.cxx
+++ b/fluid/widget_panel.cxx
@@ -803,10 +803,16 @@ sized to fit the container.");
} // Fl_Menu_Button* o
o->end();
} // Fl_Group* o
- { Fl_Box* o = new Fl_Box(95, 140, 300, 40);
+ { Fl_Box* o = new Fl_Box(95, 165, 300, 40);
o->labelsize(11);
Fl_Group::current()->resizable(o);
} // Fl_Box* o
+ { Fl_Light_Button* o = new Fl_Light_Button(95, 140, 90, 20, "Compact");
+ o->tooltip("use compact box types for closely set buttons");
+ o->selection_color((Fl_Color)1);
+ o->labelsize(11);
+ o->callback((Fl_Callback*)compact_cb);
+ } // Fl_Light_Button* o
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(10, 30, 400, 330, "C++");
diff --git a/fluid/widget_panel.fl b/fluid/widget_panel.fl
index 1ebbaa7d6..139dbe716 100644
--- a/fluid/widget_panel.fl
+++ b/fluid/widget_panel.fl
@@ -655,7 +655,12 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize
} {}
}
Fl_Box {} {
- xywh {95 140 300 40} labelsize 11 resizable
+ xywh {95 165 300 40} labelsize 11 resizable
+ }
+ Fl_Light_Button {} {
+ label Compact
+ callback compact_cb
+ tooltip {use compact box types for closely set buttons} xywh {95 140 90 20} selection_color 1 labelsize 11
}
}
Fl_Group {} {
diff --git a/fluid/widget_panel.h b/fluid/widget_panel.h
index ae15583b0..196e10632 100644
--- a/fluid/widget_panel.h
+++ b/fluid/widget_panel.h
@@ -113,6 +113,7 @@ extern void textsize_cb(Fl_Value_Input*, void*);
extern void textcolor_cb(Fl_Button*, void*);
extern Fl_Button *w_textcolor;
extern void textcolor_menu_cb(Fl_Menu_Button*, void*);
+extern void compact_cb(Fl_Light_Button*, void*);
extern void subclass_cb(Fl_Input*, void*);
extern void subtype_cb(Fl_Choice*, void*);
extern void name_cb(Fl_Input*, void*);
diff --git a/src/Fl.cxx b/src/Fl.cxx
index c08eb4930..e204a1cd5 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -1143,12 +1143,12 @@ void fl_throw_focus(Fl_Widget *o) {
// the inactive widget and all inactive parent groups.
//
// This is used to send FL_SHORTCUT events to the Fl::belowmouse() widget
-// in case the target widget itself is inactive_r(). In this case the event
+// in case the target widget itself is !active_r(). In this case the event
// is sent to the first active_r() parent.
//
// This prevents sending events to inactive widgets that might get the
// input focus otherwise. The search is fast and light and avoids calling
-// inactive_r() multiple times.
+// !active_r() multiple times.
// See STR #3216.
//
// Returns: first active_r() widget "above" the widget wi or NULL if
diff --git a/src/Fl_Button.cxx b/src/Fl_Button.cxx
index dec92d483..b15b33fbf 100644
--- a/src/Fl_Button.cxx
+++ b/src/Fl_Button.cxx
@@ -18,6 +18,7 @@
#include <FL/Fl_Button.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Window.H>
+#include <FL/fl_draw.H>
#include <FL/Fl_Radio_Button.H>
#include <FL/Fl_Toggle_Button.H>
@@ -67,7 +68,29 @@ void Fl_Button::setonly() { // set this radio button on, turn others off
void Fl_Button::draw() {
if (type() == FL_HIDDEN_BUTTON) return;
Fl_Color col = value() ? selection_color() : color();
- draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col);
+ Fl_Boxtype bt = value() ? (down_box()?down_box():fl_down(box())) : box();
+ if (compact_ && parent()) {
+ Fl_Widget *p = parent();
+ int px, py, pw = p->w(), ph = p->h();
+ if (p->as_window()) { px = 0; py = 0; } else { px = p->x(); py = p->y(); }
+ fl_push_clip(x(), y(), w(), h());
+ draw_box(bt, px, py, pw, ph, col);
+ fl_pop_clip();
+ const int hh = 5, ww = 5;
+ Fl_Color divider_color = fl_gray_ramp(FL_NUM_GRAY/3);
+ if (!active_r())
+ divider_color = fl_inactive(divider_color);
+ if (x()+w() != px+pw) {
+ fl_color(divider_color);
+ fl_yxline(x()+w()-1, y()+hh, y()+h()-1-hh);
+ }
+ if (y()+h() != py+ph) {
+ fl_color(divider_color);
+ fl_xyline(x()+ww, y()+h()-1, x()+w()-1-ww);
+ }
+ } else {
+ draw_box(bt, col);
+ }
draw_backdrop();
if (labeltype() == FL_NORMAL_LABEL && value()) {
Fl_Color c = labelcolor();
@@ -215,11 +238,14 @@ void Fl_Button::key_release_timeout(void *d)
\param[in] L widget label, default is no label
*/
Fl_Button::Fl_Button(int X, int Y, int W, int H, const char *L)
-: Fl_Widget(X,Y,W,H,L) {
+: Fl_Widget(X,Y,W,H,L),
+ shortcut_(0),
+ value_(0),
+ oldval(0),
+ down_box_(FL_NO_BOX),
+ compact_(0)
+{
box(FL_UP_BOX);
- down_box(FL_NO_BOX);
- value_ = oldval = 0;
- shortcut_ = 0;
set_flag(SHORTCUT_LABEL);
}
@@ -249,3 +275,23 @@ Fl_Toggle_Button::Fl_Toggle_Button(int X,int Y,int W,int H,const char *L)
{
type(FL_TOGGLE_BUTTON);
}
+
+/**
+ Decide if buttons should be rendered in compact mode.
+
+ \image html compact_buttons_gtk.png "compact button keypad using GTK+ Scheme"
+ \image latex compact_buttons_gtk.png "compact button keypad using GTK+ Scheme" width=4cm
+
+ \image html compact_buttons_gleam.png "compact buttons in Gleam"
+ \image latex compact_buttons_gleam.png "compact buttons in Gleam" width=4cm
+
+ In compact mode, the button's surrounding border is altered to visually signal
+ that multiple buttons are functionally linked together. To ensure the correct
+ rendering of buttons in compact mode, all buttons must be part of the same
+ group, positioned close to each other, and aligned with the edges of the
+ group. Any button outlines not in contact with the parent group's outline
+ will be displayed as separators.
+
+ \param[in] v switch compact mode on (1) or off (0)
+ */
+void Fl_Button::compact(uchar v) { compact_ = v; }
diff --git a/src/fl_boxtype.cxx b/src/fl_boxtype.cxx
index 96d016fe1..4f446c8ec 100644
--- a/src/fl_boxtype.cxx
+++ b/src/fl_boxtype.cxx
@@ -64,7 +64,7 @@ const uchar *fl_gray_ramp() {return (draw_it_active?active_ramp:inactive_ramp)-'
Gets the drawing color to be used for the background of a box.
This method is only useful inside box drawing code. It returns the
- color to be used, either fl_inactive(c) if the widget is inactive_r()
+ color to be used, either fl_inactive(c) if the widget is !active_r()
or \p c otherwise.
*/
Fl_Color Fl::box_color(Fl_Color c) {
@@ -84,7 +84,7 @@ Fl_Color Fl::box_color(Fl_Color c) {
This method is only useful inside box drawing code. Whenever a box is
drawn with one of the standard box drawing methods, a static variable
is set depending on the widget's current state - if the widget is
- inactive_r() then the internal variable is false (0), otherwise it
+ !active_r() then the internal variable is false (0), otherwise it
is true (1). This is faster than calling Fl_Widget::active_r()
because the state is cached.
diff --git a/test/buttons.cxx b/test/buttons.cxx
index e93f4dc8e..f5a945994 100644
--- a/test/buttons.cxx
+++ b/test/buttons.cxx
@@ -25,7 +25,7 @@
#include <FL/Fl_Scheme_Choice.H>
int main(int argc, char **argv) {
- Fl_Window *window = new Fl_Window(320, 170);
+ Fl_Window *window = new Fl_Window(420, 170);
Fl_Button *b1 = new Fl_Button(10, 10, 130, 30, "Fl_Button");
b1->tooltip("Fl_Button");
Fl_Button *b2 = new Fl_Return_Button(150, 10, 160, 30, "Fl_Return_Button");
@@ -39,6 +39,25 @@ int main(int argc, char **argv) {
Fl_Button *b6 = new Fl_Check_Button(150, 90, 160, 30, "Fl_Check_Button");
b6->tooltip("Fl_Check_Button");
+ Fl_Group *keypad = new Fl_Group(320, 10, 90, 120);
+ Fl_Button *kp[11];
+ kp[7] = new Fl_Button(320, 10, 30, 30, "7");
+ kp[8] = new Fl_Button(350, 10, 30, 30, "8");
+ kp[9] = new Fl_Button(380, 10, 30, 30, "9");
+ kp[4] = new Fl_Button(320, 40, 30, 30, "4");
+ kp[5] = new Fl_Button(350, 40, 30, 30, "5");
+ kp[6] = new Fl_Button(380, 40, 30, 30, "6");
+ kp[1] = new Fl_Button(320, 70, 30, 30, "1");
+ kp[2] = new Fl_Button(350, 70, 30, 30, "2");
+ kp[3] = new Fl_Button(380, 70, 30, 30, "3");
+ kp[0] = new Fl_Button(320, 100, 60, 30, "0");
+ kp[10] = new Fl_Button(380, 100, 30, 30, ".");
+ for (int i=0; i<11; i++) {
+ kp[i]->compact(1);
+ kp[i]->selection_color(FL_SELECTION_COLOR);
+ }
+ keypad->end();
+
// Add a scheme choice widget for easier testing. Position the widget at
// the right window border so the menu popup doesn't cover the check boxes etc.
Fl_Scheme_Choice *scheme_choice = new Fl_Scheme_Choice(180, 130, 130, 30, "Active FLTK Scheme:");
diff --git a/test/inactive.fl b/test/inactive.fl
index 0038a4fb3..c19b50a20 100644
--- a/test/inactive.fl
+++ b/test/inactive.fl
@@ -13,44 +13,52 @@ Function {} {open
xywh {462 303 420 369} type Double resizable visible
} {
Fl_Group the_group {
- label {activate()/deactivate() called on this Fl_Group} open selected
+ label {activate()/deactivate() called on this Fl_Group} open
xywh {25 25 375 295} box ENGRAVED_FRAME align 17 resizable
} {
Fl_Button {} {
label button
- xywh {50 50 105 25}
+ xywh {50 50 105 20}
}
Fl_Light_Button {} {
label {light button}
- xywh {50 80 105 25} value 1 align 16
+ xywh {50 75 105 20} value 1 align 16
+ }
+ Fl_Group {} {open
+ xywh {50 100 105 20}
+ } {
+ Fl_Button {} {
+ label On selected
+ xywh {50 100 52 20} type Radio value 1 compact 1
+ }
+ Fl_Button {} {
+ label Off selected
+ xywh {102 100 53 20} type Radio compact 1
+ }
}
Fl_Group {} {
label {Child group} open
- xywh {50 130 105 125} box DOWN_FRAME
+ xywh {50 150 105 105} box DOWN_FRAME
} {
Fl_Check_Button {} {
label red
- xywh {54 172 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 1 labelcolor 1
+ xywh {54 192 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 1 labelcolor 1
}
Fl_Check_Button {} {
label green
- xywh {54 192 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 2 labelcolor 2
+ xywh {54 212 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 2 labelcolor 2
}
Fl_Check_Button {} {
label blue
- xywh {54 212 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 4 labelcolor 4
- }
- Fl_Check_Button {} {
- label white
- xywh {54 232 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 55 labelcolor 55
+ xywh {54 232 97 20} type Radio down_box DIAMOND_DOWN_BOX selection_color 4 labelcolor 4
}
Fl_Check_Button {} {
label check
- xywh {54 132 97 20} down_box DOWN_BOX
+ xywh {54 152 97 20} down_box DOWN_BOX
}
Fl_Round_Button {} {
label round
- xywh {54 152 97 20} down_box ROUND_DOWN_BOX
+ xywh {54 172 97 20} down_box ROUND_DOWN_BOX
}
}
Fl_Slider {} {