Add close buttons for individual tabs in Fl_Tabs (#628)

Add close buttons for Fl_Tabs
Introducing callback reasons
FLUID shows all FL_WHEN_... options
Adding Fl_Tabs overflow types
Improved test/tabs to show new features
This commit is contained in:
Matthias Melcher 2023-01-05 13:51:30 +01:00 committed by GitHub
parent 4d1a508c7e
commit 8826dca106
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 754 additions and 220 deletions

View File

@ -51,6 +51,7 @@ 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_Tabs now supports close buttons for individual 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

View File

@ -1,7 +1,7 @@
//
// Enumerations for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2022 by Bill Spitzak and others.
// Copyright 1998-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
@ -415,22 +415,51 @@ enum Fl_Event { // events
/*@{*/
/** These constants determine when a callback is performed.
\see Fl_Widget::when();
\todo doxygen comments for values are incomplete and maybe wrong or unclear
Fl_When is a bit field. Some values are merely shorcuts for common bit
combinations. New flags may be added in the future, so it's important to
mask the required bit when reading via \p when().
\note Some widgets may not fully suppoert \p FL_WHEN_... flags.
\see Fl_Widget::when(), Fl::callback_reason(), Fl_Callback_Reason, Fl_Widget::do_callback()
*/
enum Fl_When { // Fl_Widget::when():
FL_WHEN_NEVER = 0, ///< Never call the callback
FL_WHEN_CHANGED = 1, ///< Do the callback only when the widget value changes
FL_WHEN_NOT_CHANGED = 2, ///< Do the callback whenever the user interacts with the widget
FL_WHEN_RELEASE = 4, ///< Do the callback when the button or key is released and the value changes
FL_WHEN_RELEASE_ALWAYS = 6, ///< Do the callback when the button or key is released, even if the value doesn't change
FL_WHEN_ENTER_KEY = 8, ///< Do the callback when the user presses the ENTER key and the value changes
FL_WHEN_ENTER_KEY_ALWAYS =10, ///< Do the callback when the user presses the ENTER key, even if the value doesn't change
FL_WHEN_ENTER_KEY_CHANGED =11 ///< = (FL_WHEN_ENTER_KEY | FL_WHEN_CHANGED | FL_WHEN_NOT_CHANGED)
FL_WHEN_NEVER = 0, ///< Never call the callback
FL_WHEN_CHANGED = 1, ///< Do the callback only when the widget value changes
FL_WHEN_NOT_CHANGED = 2, ///< Do the callback whenever the user interacts with the widget
FL_WHEN_RELEASE = 4, ///< Do the callback when the button or key is released and the value changes
FL_WHEN_RELEASE_ALWAYS = 6, ///< Do the callback when the button or key is released, even if the value doesn't change
FL_WHEN_ENTER_KEY = 8, ///< Do the callback when the user presses the ENTER key and the value changes
FL_WHEN_ENTER_KEY_ALWAYS = 10, ///< Do the callback when the user presses the ENTER key, even if the value doesn't change
FL_WHEN_ENTER_KEY_CHANGED = 11, ///< Do callbacks whether the value changed or not, and when the ENTER key is pressed
FL_WHEN_CLOSED = 16 ///< Do the callback when a child of Fl_Tabs is closed
};
/*@}*/ // group: When Conditions
/** \name Callback Reasons */
/*@{*/
/** These constants describe why a callback is performed.
\see Fl::callback_reason(), Fl_Widget::when(), Fl_When
*/
enum Fl_Callback_Reason {
FL_REASON_UNKNOWN=0, ///< unknown or unset reason
FL_REASON_SELECTED, ///< an item was selected
FL_REASON_DESELECTED, ///< an item was de-selected
FL_REASON_RESELECTED, ///< an item was re-selected (double-clicked).
FL_REASON_OPENED, ///< an item was opened
FL_REASON_CLOSED, ///< an item was closed
FL_REASON_DRAGGED, ///< an item was dragged into a new place
FL_REASON_CANCELLED, ///< a dialog was cancelled
FL_REASON_CHANGED, ///< the value of the widget was modified
FL_REASON_GOT_FOCUS, ///< a widget received focus
FL_REASON_LOST_FOCUS, ///< a widget lost focus
FL_REASON_RELEASED, ///< the mouse button was released
};
/*@}*/ // group: Callback Reasons
/** \name Mouse and Keyboard Events
This and the following constants define the non-ASCII keys on the

View File

@ -202,6 +202,7 @@ public: // should be private!
static void *e_clipboard_data;
static const char *e_clipboard_type;
static Fl_Event_Dispatch e_dispatch;
static Fl_Callback_Reason callback_reason_;
static Fl_Widget* belowmouse_;
static Fl_Widget* pushed_;
static Fl_Widget* focus_;
@ -847,6 +848,7 @@ public:
static void remove_system_handler(Fl_System_Handler h);
static void event_dispatch(Fl_Event_Dispatch d);
static Fl_Event_Dispatch event_dispatch();
static Fl_Callback_Reason callback_reason();
/** @} */
/** \defgroup fl_clipboard Selection & Clipboard functions

View File

@ -53,6 +53,12 @@
accessing image data or doing stat() on a file or doing some
other slow operation.
Callbacks are called when the value changes with \p FL_REASON_CHANGED.
If \p FL_WHEN_RELEASE is set, callbacks are called when the mouse button is
released with \p FL_REASON_CHANGED or \p FL_REASON_RESELECTED if the selection
did not change. If \p FL_WHEN_ENTER_KEY is set, callbacks are also called when
key presses or double clicks change the selection.
Keyboard navigation of browser items
------------------------------------

View File

@ -65,10 +65,15 @@ class Fl_Widget_Tracker;
being \c FL_WHEN_RELEASE:
\li \c 0: The callback is not done, instead changed() is turned on.
\li \c FL_WHEN_RELEASE: The callback is done after the user successfully
clicks the button, or when a shortcut is typed.
clicks the button, or when a shortcut is typed. The reason is
\p FL_REASON_RELEASED.
\li \c FL_WHEN_CHANGED: The callback is done each time the value() changes
(when the user pushes and releases the button, and as the mouse is
dragged around in and out of the button).
dragged around in and out of the button). The reason is set to
\p FL_REASON_CHANGED
\li \c FL_WHEN_NOT_CHANGED: The callback is done when the mouse button is
released, but the value did not changed. The reason is set to
\p FL_REASON_SELECTED
*/
class FL_EXPORT Fl_Button : public Fl_Widget {

View File

@ -104,6 +104,9 @@ public:
available colors, leaving you no space to exactly represent the color the
user picks! You can however use fl_rectf() to fill a region with a simulated
color using dithering.
Callback reasons can be \c FL_REASON_DRAGGED, \c FL_REASON_CHANGED, or
\c FL_REASON_RESELECTED.
*/
/** @} */
class FL_EXPORT Fl_Color_Chooser : public Fl_Group {

View File

@ -47,6 +47,11 @@ class Fl_Rect;
\endcode
..and this will trigger proper scheduling of the widget's removal
from its parent group.
If used as a child of \p Fl_Tabs, setting \p when(FL_WHEN_CLOSED) will
enable the Close button in the corresponding tab. If the user clicks the
Close button, the callback of this group will be called with the callback
reason \p FL_REASON_CLOSED.
*/
class FL_EXPORT Fl_Group : public Fl_Widget {

View File

@ -200,7 +200,7 @@ protected:
int handletext(int e, int, int, int, int);
/* Check the when() field and do a callback if indicated. */
void maybe_do_callback();
void maybe_do_callback(Fl_Callback_Reason reason = FL_REASON_UNKNOWN);
/** \internal Horizontal offset of text to left edge of widget. */
int xscroll() const {return xscroll_;}

View File

@ -390,14 +390,14 @@ struct FL_EXPORT Fl_Menu_Item {
The callback is called with the stored user_data() as its second argument.
You must first check that callback() is non-zero before calling this.
*/
void do_callback(Fl_Widget* o) const {callback_(o, user_data_);}
void do_callback(Fl_Widget* o) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, user_data_);}
/**
Calls the Fl_Menu_Item item's callback, and provides the Fl_Widget argument.
This call overrides the callback's second argument with the given value \p arg.
You must first check that callback() is non-zero before calling this.
*/
void do_callback(Fl_Widget* o,void* arg) const {callback_(o, arg);}
void do_callback(Fl_Widget* o,void* arg) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, arg);}
/**
Calls the Fl_Menu_Item item's callback, and provides the Fl_Widget argument.
@ -406,7 +406,7 @@ struct FL_EXPORT Fl_Menu_Item {
the callback.
You must first check that callback() is non-zero before calling this.
*/
void do_callback(Fl_Widget* o,long arg) const {callback_(o, (void*)(fl_intptr_t)arg);}
void do_callback(Fl_Widget* o,long arg) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, (void*)(fl_intptr_t)arg);}
/** Back compatibility only.
\deprecated

View File

@ -1,7 +1,7 @@
//
// Tab header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2017 by Bill Spitzak and others.
// Copyright 1998-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
@ -22,10 +22,15 @@
#include "Fl_Group.H"
struct Fl_Menu_Item;
/**
The Fl_Tabs widget is the "file card tabs"
interface that allows you to put lots and lots of buttons and
switches in a panel, as popularized by many toolkits.
The Fl_Tabs widget is a container widget that displays a set of tabs, with
each tab representing a different child widget. The user can select a tab by
clicking on it, and the corresponding child widget will be displayed.
The Fl_Tabs widget is useful for organizing a large number of controls or
other widgets into a compact space, allowing the user to switch between
different sets of controls as needed.
\image html tabs.png
\image latex tabs.png "Fl_Tabs" width=8cm
@ -46,8 +51,8 @@
children (there should be some space between the children and
the edge of the Fl_Tabs), and the tabs may be placed
"inverted" on the bottom - this is determined by which
gap is larger. It is easiest to lay this out in fluid, using the
fluid browser to select each child group and resize them until
gap is larger. It is easiest to lay this out in FLUID, using the
FLUID browser to select each child group and resize them until
the tabs look the way you want them to.
The background area behind and to the right of the tabs is
@ -157,6 +162,19 @@
\image html tabs_uniform.png "Fl_Tabs with uniform colors"
\image latex tabs_uniform.png "Fl_Tabs with uniform colors" width=8cm
\b Close \b Button \b on \b Tabs
The Fl_Tabs widget allows you to specify that a child widget should display
a close button in its tab. If the \ref FL_WHEN_CLOSED flag is set for the
child widget, an "X" symbol will be displayed to the left of the label text
in the tab. When the close button is clicked, the child widget's callback
function will be called with the \ref FL_REASON_CLOSED argument. It is then
the responsibility of the child widget to remove itself from the
Fl_Tabs container.
Tabs that are in a compressed state will not display a close button until
they are fully expanded.
\b Resizing \b Caveats
When Fl_Tabs is resized vertically, the default behavior scales the
@ -197,6 +215,7 @@
-# \ref FL_WHEN_NOT_CHANGED can happen if someone clicks on an already selected tab,
or if a keyboard navigation attempt results in no change to the tabs,
such as using the arrow keys while at the left or right end of the tabs.
-# \ref Fl::callback_reason() returns FL_REASON_SELECTED or FL_REASON_RESELECTED
*/
class FL_EXPORT Fl_Tabs : public Fl_Group {
@ -204,16 +223,31 @@ class FL_EXPORT Fl_Tabs : public Fl_Group {
protected:
int overflow_type;
int tab_offset;
int *tab_pos; // array of x-offsets of tabs per child + 1
int *tab_width; // array of widths of tabs per child + 1
int *tab_flags; // array of tab flag of tabs per child + 1
int tab_count; // array size
Fl_Align tab_align_; // tab label alignment
int has_overflow_menu;
Fl_Menu_Item* overflow_menu;
void check_overflow_menu();
void handle_overflow_menu();
void draw_overflow_menu_button();
int on_insert(Fl_Widget*, int) FL_OVERRIDE;
int on_move(int, int) FL_OVERRIDE;
void on_remove(int) FL_OVERRIDE;
void resize(int, int, int, int) FL_OVERRIDE;
virtual void redraw_tabs();
virtual int tab_positions(); // allocate and calculate tab positions
virtual void clear_tab_positions();
virtual void draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int sel=0);
virtual void draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int flags, int sel);
virtual int tab_height();
virtual int hit_close(Fl_Widget *o, int event_x, int event_y);
void draw() FL_OVERRIDE;
@ -225,6 +259,7 @@ public:
int handle(int) FL_OVERRIDE;
Fl_Widget *value();
int value(Fl_Widget *);
/**
Returns the tab group for the tab the user has currently down-clicked on
and remains over until FL_RELEASE. Otherwise, returns NULL.
@ -256,12 +291,23 @@ public:
recommended alignment to show the icon left of the text.
*/
void tab_align(Fl_Align a) {tab_align_ = a;}
/**
Gets the tab label alignment.
\see tab_align(Fl_Align)
*/
Fl_Align tab_align() const {return tab_align_;}
enum {
OVERFLOW_COMPRESS = 0,
OVERFLOW_CLIP,
OVERFLOW_PULLDOWN,
OVERFLOW_DRAG,
};
void handle_overflow(int ov);
};
#endif

View File

@ -113,7 +113,7 @@ class FL_EXPORT Fl_Text_Editor : public Fl_Text_Display {
protected:
int handle_key();
void maybe_do_callback();
void maybe_do_callback(Fl_Callback_Reason reason = FL_REASON_CHANGED);
#ifndef FL_DOXYGEN
int insert_mode_;

View File

@ -273,14 +273,14 @@
/// The reason the callback was invoked.
///
enum Fl_Tree_Reason {
FL_TREE_REASON_NONE=0, ///< unknown reason
FL_TREE_REASON_SELECTED, ///< an item was selected
FL_TREE_REASON_DESELECTED, ///< an item was de-selected
FL_TREE_REASON_RESELECTED, ///< an item was re-selected (double-clicked).
FL_TREE_REASON_NONE = FL_REASON_UNKNOWN, ///< unknown reason
FL_TREE_REASON_SELECTED = FL_REASON_SELECTED, ///< an item was selected
FL_TREE_REASON_DESELECTED = FL_REASON_DESELECTED, ///< an item was de-selected
FL_TREE_REASON_RESELECTED = FL_REASON_RESELECTED, ///< an item was re-selected (double-clicked).
///< See ::Fl_Tree_Item_Reselect_Mode to enable this.
FL_TREE_REASON_OPENED, ///< an item was opened
FL_TREE_REASON_CLOSED, ///< an item was closed
FL_TREE_REASON_DRAGGED ///< an item was dragged into a new place
FL_TREE_REASON_OPENED = FL_REASON_OPENED, ///< an item was opened
FL_TREE_REASON_CLOSED = FL_REASON_CLOSED, ///< an item was closed
FL_TREE_REASON_DRAGGED = FL_REASON_DRAGGED ///< an item was dragged into a new place
};
class FL_EXPORT Fl_Tree : public Fl_Group {

View File

@ -1,7 +1,7 @@
//
// Widget header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2020 by Bill Spitzak and others.
// Copyright 1998-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
@ -707,7 +707,7 @@ public:
FL_WHEN_RELEASE.
\return set of flags
\see when(uchar)
\see when(uchar), Fl_When, do_callback(), Fl::callback_reason()
*/
Fl_When when() const {return (Fl_When)when_;}
@ -733,6 +733,11 @@ public:
a newline for a Fl_Multiline_Input) - this changes the behavior.
\li FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED: The Enter key will do the
callback even if the text has not changed. Useful for command fields.
\li \ref FL_WHEN_CLOSED : If the user requests that the widget is closed,
the callback is called with \ref FL_REASON_CLOSED. The \ref Fl_Tabs
widget checks this flag on its children to determine whether to display
a close button on the tab of that widget.
Fl_Widget::when() is a set of bitflags used by subclasses of
Fl_Widget to decide when to do the callback.
@ -741,6 +746,7 @@ public:
class so that you can scan a panel and do_callback() on all the ones
that don't do their own callbacks in response to an "OK" button.
\param[in] i set of flags
\see Fl_When, do_callback(), Fl::callback_reason()
*/
void when(uchar i) {when_ = i;}
@ -962,7 +968,7 @@ public:
\see callback()
\see do_callback(Fl_Widget *widget, void *data)
*/
void do_callback() {do_callback(this, user_data_);}
void do_callback(Fl_Callback_Reason reason=FL_REASON_UNKNOWN) {do_callback(this, user_data_, reason);}
/** Calls the widget callback function with arbitrary arguments.
\param[in] widget call the callback with \p widget as the first argument
@ -970,13 +976,11 @@ public:
\see callback()
\see do_callback(Fl_Widget *widget, void *data)
*/
void do_callback(Fl_Widget *widget, long arg) {
do_callback(widget, (void*)(fl_intptr_t)arg);
void do_callback(Fl_Widget *widget, long arg, Fl_Callback_Reason reason=FL_REASON_UNKNOWN) {
do_callback(widget, (void*)(fl_intptr_t)arg, reason);
}
// Causes a widget to invoke its callback function with arbitrary arguments.
// Documentation and implementation in Fl_Widget.cxx
void do_callback(Fl_Widget *widget, void *arg = 0);
void do_callback(Fl_Widget *widget, void *arg = 0, Fl_Callback_Reason reason=FL_REASON_UNKNOWN);
/* Internal use only. */
int test_shortcut();

View File

@ -48,6 +48,9 @@ class Fl_Double_Window;
The window's callback is done if the user tries to close a window
using the window manager and Fl::modal() is zero or equal to the
window. Fl_Window has a default callback that calls Fl_Window::hide().
Callback reasons can be \p FL_REASON_CANCELLED if the Escape key was pressed,
or \p FL_REASON_CLOSED when the close button is clicked. \p FL_WHEN_...
flags are ignored.
*/
class FL_EXPORT Fl_Window : public Fl_Group {
friend int Fl::arg(int argc, char **argv, int &i);

View File

@ -110,6 +110,27 @@ const char * const fl_fontnames[] =
"FL_ZAPF_DINGBATS",
};
/**
This is an array of callback reason names you can use to convert font numbers into names.
The array gets defined inline wherever your '\#include <FL/names.h>' appears.
*/
const char * const fl_callback_reason_names[] =
{
"FL_REASON_UNKNOWN",
"FL_REASON_SELECTED",
"FL_REASON_DESELECTED",
"FL_REASON_RESELECTED",
"FL_REASON_OPENED",
"FL_REASON_CLOSED",
"FL_REASON_DRAGGED",
"FL_REASON_CANCELLED",
"FL_REASON_CHANGED",
"FL_REASON_GOT_FOCUS",
"FL_REASON_LOST_FOCUS",
"FL_REASON_RELEASED",
};
/** @} */
#endif /* FL_NAMES_H */

View File

@ -197,7 +197,7 @@ int CodeEditor::auto_indent(int, CodeEditor* e) {
}
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
free(text);

View File

@ -1110,12 +1110,20 @@ void down_box_cb(Fl_Choice* i, void *v) {
////////////////////////////////////////////////////////////////
Fl_Menu_Item whenmenu[] = {
// set individual bits
{"FL_WHEN_CHANGED",0,0,(void*)FL_WHEN_CHANGED, FL_MENU_TOGGLE},
{"FL_WHEN_NOT_CHANGED",0,0,(void*)FL_WHEN_NOT_CHANGED, FL_MENU_TOGGLE},
{"FL_WHEN_RELEASE",0,0,(void*)FL_WHEN_RELEASE, FL_MENU_TOGGLE},
{"FL_WHEN_ENTER_KEY",0,0,(void*)FL_WHEN_ENTER_KEY, FL_MENU_TOGGLE},
{"FL_WHEN_CLOSED",0,0,(void*)FL_WHEN_CLOSED, FL_MENU_TOGGLE|FL_MENU_DIVIDER},
// set bit combinations
{"FL_WHEN_NEVER",0,0,(void*)FL_WHEN_NEVER},
{"FL_WHEN_RELEASE_ALWAYS",0,0,(void*)FL_WHEN_RELEASE_ALWAYS},
{"FL_WHEN_ENTER_KEY_ALWAYS",0,0,(void*)FL_WHEN_ENTER_KEY_ALWAYS},
{"FL_WHEN_ENTER_KEY_CHANGED",0,0,(void*)FL_WHEN_ENTER_KEY_CHANGED},
{0}};
static Fl_Menu_Item whensymbolmenu[] = {
/* 0 */ {"FL_WHEN_NEVER",0,0,(void*)FL_WHEN_NEVER},
/* 1 */ {"FL_WHEN_CHANGED",0,0,(void*)FL_WHEN_CHANGED},
@ -1136,23 +1144,48 @@ static Fl_Menu_Item whensymbolmenu[] = {
{0}
};
// Return a text string representing the Fl_When value n
const char* when_symbol_name(int n) {
static char sym[128];
if (n == FL_WHEN_CLOSED) {
strcpy(sym, "FL_WHEN_CLOSED");
} else {
strcpy(sym, whensymbolmenu[n&15].label());
if (n & FL_WHEN_CLOSED)
strcat(sym, " | FL_WHEN_CLOSED");
}
return sym;
}
// Set the check marks in the "when()" menu according to the Fl_When value n
void set_whenmenu(int n) {
if (n&FL_WHEN_CHANGED) whenmenu[0].set(); else whenmenu[0].clear();
if (n&FL_WHEN_NOT_CHANGED) whenmenu[1].set(); else whenmenu[1].clear();
if (n&FL_WHEN_RELEASE) whenmenu[2].set(); else whenmenu[2].clear();
if (n&FL_WHEN_ENTER_KEY) whenmenu[3].set(); else whenmenu[3].clear();
if (n&FL_WHEN_CLOSED) whenmenu[4].set(); else whenmenu[4].clear();
}
void when_cb(Fl_Menu_Button* i, void *v) {
if (v == LOAD) {
if (current_widget->is_menu_item()) {i->deactivate(); return;} else i->activate();
int n = current_widget->o->when() & 15;
if (n&1) whenmenu[0].set(); else whenmenu[0].clear();
if (n&2) whenmenu[1].set(); else whenmenu[1].clear();
if (n&4) whenmenu[2].set(); else whenmenu[2].clear();
if (n&8) whenmenu[3].set(); else whenmenu[3].clear();
w_when_box->label(whensymbolmenu[n].label());
int n = current_widget->o->when();
set_whenmenu(n);
w_when_box->copy_label(when_symbol_name(n));
} else {
int mod = 0;
int n = 0;
if (whenmenu[0].value()) n |= 1;
if (whenmenu[1].value()) n |= 2;
if (whenmenu[2].value()) n |= 4;
if (whenmenu[3].value()) n |= 8;
w_when_box->label(whensymbolmenu[n].label());
if (i->mvalue() && ((i->mvalue()->flags & FL_MENU_TOGGLE) == 0) ) {
n = (int)i->mvalue()->argument();
set_whenmenu(n);
} else {
if (whenmenu[0].value()) n |= FL_WHEN_CHANGED;
if (whenmenu[1].value()) n |= FL_WHEN_NOT_CHANGED;
if (whenmenu[2].value()) n |= FL_WHEN_RELEASE;
if (whenmenu[3].value()) n |= FL_WHEN_ENTER_KEY;
if (whenmenu[4].value()) n |= FL_WHEN_CLOSED;
}
w_when_box->copy_label(when_symbol_name(n));
for (Fl_Type *o = Fl_Type::first; o; o = o->next) {
if (o->selected && o->is_widget()) {
Fl_Widget_Type* q = (Fl_Widget_Type*)o;
@ -3074,8 +3107,7 @@ void Fl_Widget_Type::write_widget_code() {
if (ww==FL_WHEN_NOT_CHANGED)
ww = FL_WHEN_NEVER;
if (ww != tplate->when() || subclass())
write_c("%s%s->when(%s);\n", indent(), var,
item_name(whensymbolmenu, ww));
write_c("%s%s->when(%s);\n", indent(), var, when_symbol_name(ww));
if (!o->visible() && o->parent())
write_c("%s%s->hide();\n", indent(), var);
if (!o->active())
@ -3552,6 +3584,7 @@ void Fl_Widget_Type::copy_properties() {
w->labelsize(o->labelsize());
w->labelcolor(o->labelcolor());
w->align(o->align());
w->when(o->when());
// copy all attributes specific to widgets derived from Fl_Button
if (is_button()) {

View File

@ -1,7 +1,7 @@
//
// Widget type code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
// Copyright 1998-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
@ -86,9 +86,10 @@ int Shortcut_Button::handle(int e) {
}
/** \class Widget_Bin_Button
A button for the widget bin that allows the user to drag widgets into a window.
Dragging and dropping a new widget makes it easy for the user to position
a widget inside a window or group.
The Widget_Bin_Button button is a button that can be used in the widget bin to
allow the user to drag and drop widgets into a window or group. This feature
makes it easy for the user to position a widget at a specific location within
the window or group.
*/
/**
@ -124,8 +125,9 @@ int Widget_Bin_Button::handle(int inEvent)
}
/** \class Widget_Bin_Window_Button
This button is used by the widget bin to create new windows by drag'n'drop.
The new window will be created wherever the user drops it on the desktop.
The Widget_Bin_Window_Button button is used in the widget bin to create new
windows by dragging and dropping. When the button is dragged and dropped onto
the desktop, a new window will be created at the drop location.
*/
/**
@ -179,9 +181,10 @@ int Widget_Bin_Window_Button::handle(int inEvent)
}
/** \class Fluid_Coord_Input
An Input field for widget coordinates and sizes.
This widget adds basic math capability to the text input field and a number
of variables that can be used in the formula.
The Fluid_Coord_Input widget is an input field for entering widget coordinates
and sizes. It includes basic math capabilities and allows the use of variables
in formulas. This widget is useful for specifying precise positions and
dimensions for widgets in a graphical user interface.
*/
/**
@ -298,10 +301,15 @@ int Fluid_Coord_Input::eval(uchar *&s, int prio) const {
/**
Evaluate a formula into an integer.
The interpreter understands unary plus and minus, basic integer math
(+, -, *, /), brackets, and can handle a user defined list of variables
by name. There is no error checking. We assume that the formula is
entered correctly.
The Fluid_Coord_Input widget includes a formula interpreter that allows you
to evaluate a string containing a mathematical formula and obtain the result
as an integer. The interpreter supports unary plus and minus, basic integer
math operations (such as addition, subtraction, multiplication, and division),
and brackets. It also allows you to define a list of variables by name and use
them in the formula. The interpreter does not perform error checking, so it is
assumed that the formula is entered correctly.
\param s formula as a C string
\return the calculated value
*/

View File

@ -69,6 +69,7 @@ const char *Fl::e_clipboard_type = "";
void *Fl::e_clipboard_data = NULL;
Fl_Event_Dispatch Fl::e_dispatch = 0;
Fl_Callback_Reason Fl::callback_reason_ = FL_REASON_UNKNOWN;
unsigned char Fl::options_[] = { 0, 0 };
unsigned char Fl::options_read_ = 0;
@ -1173,6 +1174,14 @@ static int send_event(int event, Fl_Widget* to, Fl_Window* window) {
return ret;
}
/**
\brief Give the reason for calling a callback.
\return the reason for the current callback
\see Fl_Widget::when(), Fl_Widget::do_callback(), Fl_Widget::callback()
*/
Fl_Callback_Reason Fl::callback_reason() {
return callback_reason_;
}
/**
\brief Set a new event dispatch function.
@ -1258,6 +1267,8 @@ int Fl::handle(int e, Fl_Window* window)
another dispatch function. In that case, the user dispatch function must
decide when to call Fl::handle_(int, Fl_Window*)
Callbacks can set \p FL_REASON_CLOSED and \p FL_REASON_CANCELLED.
\param e the event type (Fl::event_number() is not yet set)
\param window the window that caused this event
\return 0 if the event was not handled
@ -1275,7 +1286,7 @@ int Fl::handle_(int e, Fl_Window* window)
case FL_CLOSE:
if ( grab() || (modal() && window != modal()) ) return 0;
wi->do_callback();
wi->do_callback(FL_REASON_CLOSED);
return 1;
case FL_SHOW:
@ -1425,7 +1436,7 @@ int Fl::handle_(int e, Fl_Window* window)
// make Escape key close windows:
if (event_key()==FL_Escape) {
wi = modal(); if (!wi) wi = window;
wi->do_callback();
wi->do_callback(FL_REASON_CANCELLED);
return 1;
}

View File

@ -630,7 +630,7 @@ int Fl_Browser_::select(void* item, int val, int docallbacks) {
}
if (docallbacks) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
}
return 1;
}
@ -733,7 +733,7 @@ int Fl_Browser_::handle(int event) {
if (wp.deleted()) return 1;
if (when() & FL_WHEN_ENTER_KEY) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
}
return 1;
case ' ':
@ -807,7 +807,7 @@ J1:
if (wp.deleted()) return 1;
if (change && (when() & FL_WHEN_CHANGED)) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
} else {
@ -821,7 +821,7 @@ J1:
if (wp.deleted()) return 1;
if (change && (when() & FL_WHEN_CHANGED)) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
}
@ -859,7 +859,7 @@ J1:
if (wp.deleted()) return 1;
if (change && (when() & FL_WHEN_CHANGED)) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
}
@ -897,7 +897,7 @@ J1:
change |= change_t;
if (change_t && (when() & FL_WHEN_CHANGED)) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
}
@ -922,16 +922,16 @@ J1:
}
if (change) {
set_changed();
if (when() & FL_WHEN_RELEASE) do_callback();
if (when() & FL_WHEN_RELEASE) do_callback(FL_REASON_CHANGED);
} else {
if (when() & FL_WHEN_NOT_CHANGED) do_callback();
if (when() & FL_WHEN_NOT_CHANGED) do_callback(FL_REASON_RESELECTED);
}
if (wp.deleted()) return 1;
// double click calls the callback: (like Enter Key)
if (Fl::event_clicks() && (when() & FL_WHEN_ENTER_KEY)) {
set_changed();
do_callback();
do_callback(FL_REASON_CHANGED);
}
return 1;
case FL_FOCUS:

View File

@ -100,12 +100,12 @@ int Fl_Button::handle(int event) {
value_ = newval;
set_changed();
redraw();
if (when() & FL_WHEN_CHANGED) do_callback();
if (when() & FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
}
return 1;
case FL_RELEASE:
if (value_ == oldval) {
if (when() & FL_WHEN_NOT_CHANGED) do_callback();
if (when() & FL_WHEN_NOT_CHANGED) do_callback(FL_REASON_SELECTED);
return 1;
}
set_changed();
@ -116,11 +116,11 @@ int Fl_Button::handle(int event) {
set_changed();
if (when() & FL_WHEN_CHANGED) {
Fl_Widget_Tracker wp(this);
do_callback();
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
}
if (when() & FL_WHEN_RELEASE) do_callback();
if (when() & FL_WHEN_RELEASE) do_callback(FL_REASON_RELEASED);
return 1;
case FL_SHORTCUT:
if (!(shortcut() ?
@ -150,16 +150,16 @@ int Fl_Button::handle(int event) {
if (type() == FL_RADIO_BUTTON) {
if (!value_) {
setonly();
if (when() & FL_WHEN_CHANGED) do_callback();
if (when() & FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
}
} else if (type() == FL_TOGGLE_BUTTON) {
value(!value());
if (when() & FL_WHEN_CHANGED) do_callback();
if (when() & FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
} else {
simulate_key_action();
}
if (wp.deleted()) return 1;
if (when() & FL_WHEN_RELEASE) do_callback();
if (when() & FL_WHEN_RELEASE) do_callback(FL_REASON_RELEASED);
return 1;
}
/* FALLTHROUGH */
@ -206,6 +206,11 @@ void Fl_Button::key_release_timeout(void *d)
Derived classes may handle this differently.
A button may reequest callbacks with \p whne() \p FL_WHEN_CHANGED,
\p FL_WHEN_NOT_CHANGED, and \p FL_WHEN_RELEASE, triggering the callback
reasons \p FL_REASON_CHANGED, \p FL_REASON_SELECTED,
and \p FL_REASON_DESELECTED.
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
*/

View File

@ -220,7 +220,7 @@ int Flcc_HueBox::handle(int e) {
if (fabs(H-ih) < 3*6.0/w()) H = ih;
if (fabs(S-is) < 3*1.0/h()) S = is;
if (Fl::event_state(FL_CTRL)) H = ih;
if (c->hsv(H, S, c->value())) c->do_callback();
if (c->hsv(H, S, c->value())) c->do_callback(FL_REASON_DRAGGED);
} return 1;
case FL_FOCUS : /* FALLTHROUGH */
case FL_UNFOCUS :
@ -292,7 +292,7 @@ int Flcc_HueBox::handle_key(int key) {
Xf = (double)X/(double)w1;
Yf = (double)Y/(double)h1;
tohs(Xf, Yf, H, S);
if (c->hsv(H, S, c->value())) c->do_callback();
if (c->hsv(H, S, c->value())) c->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -347,7 +347,7 @@ int Flcc_ValueBox::handle(int e) {
double Yf;
Yf = 1-(Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box()));
if (fabs(Yf-iv)<(3*1.0/h())) Yf = iv;
if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback();
if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback(FL_REASON_DRAGGED);
} return 1;
case FL_FOCUS : /* FALLTHROUGH */
case FL_UNFOCUS :
@ -418,7 +418,7 @@ int Flcc_ValueBox::handle_key(int key) {
double Yf;
Yf = 1-((double)Y/(double)h1);
if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback();
if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -432,7 +432,7 @@ void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) {
double G = c->gvalue.value();
double B = c->bvalue.value();
if (c->mode() == M_HSV) {
if (c->hsv(R,G,B)) c->do_callback();
if (c->hsv(R,G,B)) c->do_callback(FL_REASON_CHANGED);
return;
}
if (c->mode() != M_RGB) {
@ -440,7 +440,7 @@ void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) {
G = G/255;
B = B/255;
}
if (c->rgb(R,G,B)) c->do_callback();
if (c->rgb(R,G,B)) c->do_callback(FL_REASON_CHANGED);
}
void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) {
@ -455,7 +455,7 @@ void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) {
void Fl_Color_Chooser::mode(int newMode)
{
choice.value(newMode);
choice.do_callback();
choice.do_callback(FL_REASON_RESELECTED);
}
// Small local helper function:

View File

@ -269,7 +269,7 @@ Fl_File_Input::handle_button(int event) // I - Event
// Then do the callbacks, if necessary...
set_changed();
if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE) ) do_callback();
if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE) ) do_callback(FL_REASON_CHANGED);
}
return 1;

View File

@ -3553,7 +3553,7 @@ Fl_Help_View::topline(int top) // I - Top line number
scrollbar_.value(topline_, h() - scrollsize, 0, size_);
do_callback();
do_callback(FL_REASON_DRAGGED);
redraw();
}

View File

@ -577,7 +577,7 @@ int Fl_Input::handle(int event) {
// For output widgets, do the callback so the app knows the user
// did something with the mouse...
if (readonly()) do_callback();
if (readonly()) do_callback(FL_REASON_RELEASED);
return 1;

View File

@ -942,7 +942,7 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
mark_ = position_ = undo_->undoat;
set_changed();
if (when()&FL_WHEN_CHANGED) do_callback();
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
return 1;
}
@ -989,7 +989,7 @@ int Fl_Input_::undo() {
while (b1 > 0 && index(b1)!='\n') b1--;
minimal_update(b1);
set_changed();
if (when()&FL_WHEN_CHANGED) do_callback();
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
return 1;
}
@ -1013,9 +1013,9 @@ int Fl_Input_::copy_cuts() {
/** \internal
Checks the when() field and does a callback if indicated.
*/
void Fl_Input_::maybe_do_callback() {
void Fl_Input_::maybe_do_callback(Fl_Callback_Reason reason) {
if (changed() || (when()&FL_WHEN_NOT_CHANGED)) {
do_callback();
do_callback(reason);
}
}
@ -1055,7 +1055,7 @@ int Fl_Input_::handletext(int event, int X, int Y, int W, int H) {
case FL_HIDE:
fl_reset_spot();
if (!readonly() && (when() & FL_WHEN_RELEASE))
maybe_do_callback();
maybe_do_callback(FL_REASON_LOST_FOCUS);
return 1;
case FL_PUSH:

View File

@ -205,7 +205,7 @@ void Fl_Input_Choice::menu_cb(Fl_Widget*, void *data) {
{
o->Fl_Widget::clear_changed();
if (o->when() & FL_WHEN_NOT_CHANGED)
o->do_callback();
o->do_callback(FL_REASON_RESELECTED);
}
else
{
@ -213,7 +213,7 @@ void Fl_Input_Choice::menu_cb(Fl_Widget*, void *data) {
o->inp_->set_changed();
o->Fl_Widget::set_changed();
if (o->when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE))
o->do_callback();
o->do_callback(FL_REASON_CHANGED);
}
if (wp.deleted()) return;
@ -233,11 +233,11 @@ void Fl_Input_Choice::inp_cb(Fl_Widget*, void *data) {
if (o->inp_->changed()) {
o->Fl_Widget::set_changed();
if (o->when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE))
o->do_callback();
o->do_callback(FL_REASON_CHANGED);
} else {
o->Fl_Widget::clear_changed();
if (o->when() & FL_WHEN_NOT_CHANGED)
o->do_callback();
o->do_callback(FL_REASON_RESELECTED);
}
if (wp.deleted()) return;

View File

@ -99,8 +99,12 @@ int Fl_Positioner::handle(int event, int X, int Y, int W, int H) {
if (!(when() & FL_WHEN_CHANGED ||
(when() & FL_WHEN_RELEASE && event == FL_RELEASE))) return 1;
if (changed() || when()&FL_WHEN_NOT_CHANGED) {
if (event == FL_RELEASE) clear_changed();
do_callback();
Fl_Callback_Reason reason = changed() ? FL_REASON_CHANGED : FL_REASON_SELECTED;
if (event == FL_RELEASE) {
clear_changed();
reason = FL_REASON_RELEASED;
}
do_callback(reason);
}
return 1;
default:

View File

@ -23,7 +23,7 @@
void Fl_Repeat_Button::repeat_callback(void *v) {
Fl_Button *b = (Fl_Button*)v;
Fl::add_timeout(REPEAT,repeat_callback,b);
b->do_callback();
b->do_callback(FL_REASON_RESELECTED);
}
int Fl_Repeat_Button::handle(int event) {
@ -43,7 +43,7 @@ int Fl_Repeat_Button::handle(int event) {
if (value(newval)) {
if (newval) {
Fl::add_timeout(INITIALREPEAT,repeat_callback,this);
do_callback();
do_callback(FL_REASON_SELECTED);
} else {
Fl::remove_timeout(repeat_callback,this);
}

View File

@ -52,7 +52,7 @@ int Fl_Return_Button::handle(int event) {
if (event == FL_SHORTCUT &&
(Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)) {
simulate_key_action();
do_callback();
do_callback(FL_REASON_SELECTED);
return 1;
} else
return Fl_Button::handle(event);

View File

@ -188,7 +188,7 @@ int Fl_Scrollbar::handle(int event) {
Fl_Slider::value(v);
value_damage();
set_changed();
do_callback();
do_callback(FL_REASON_DRAGGED);
}
return 1;}
}

View File

@ -70,7 +70,7 @@ void Fl_Spinner::sb_cb(Fl_Widget *w, Fl_Spinner *sb) {
}
sb->set_changed();
sb->do_callback();
sb->do_callback(FL_REASON_CHANGED);
}
void Fl_Spinner::update() {
@ -154,10 +154,10 @@ int Fl_Spinner::handle(int event) {
case FL_KEYDOWN:
case FL_SHORTCUT:
if (Fl::event_key() == FL_Up) {
up_button_.do_callback();
up_button_.do_callback(FL_REASON_DRAGGED);
return 1;
} else if (Fl::event_key() == FL_Down) {
down_button_.do_callback();
down_button_.do_callback(FL_REASON_DRAGGED);
return 1;
}
return 0;

View File

@ -1,7 +1,7 @@
//
// Tab widget for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
// Copyright 1998-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
@ -24,6 +24,7 @@
#include <FL/Fl_Tabs.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Tooltip.H>
#include <FL/Fl_Menu_Item.H>
#include <stdio.h>
#include <stdlib.h>
@ -31,6 +32,41 @@
#define BORDER 2
#define EXTRASPACE 10
#define SELECTION_BORDER 5
#define EXTRAGAP 2
/** Make sure that we redraw all tabs when new children are added. */
int Fl_Tabs::on_insert(Fl_Widget* candidate, int index) {
redraw_tabs();
damage(FL_DAMAGE_EXPOSE);
return Fl_Group::on_insert(candidate, index);
}
/** Make sure that we redraw all tabs when children are moved. */
int Fl_Tabs::on_move(int a, int b) {
redraw_tabs();
damage(FL_DAMAGE_EXPOSE);
return Fl_Group::on_move(a, b);
}
/** Make sure that we redraw all tabs when new children are removed. */
void Fl_Tabs::on_remove(int index) {
redraw_tabs();
damage(FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL);
if (child(index)->visible()) {
if (index+1<children())
value(child(index+1));
else if (index>0)
value(child(index-1));
}
Fl_Group::on_remove(index);
}
/** Make sure that we redraw all tabs when the widget size changes. */
void Fl_Tabs::resize(int X, int Y, int W, int H) {
damage(FL_DAMAGE_EXPOSE);
Fl_Group::resize(X, Y, W, H);
}
// Return the left edges of each tab (plus a fake left edge for a tab
// past the right-hand one). These positions are actually of the left
@ -47,6 +83,7 @@ int Fl_Tabs::tab_positions() {
if (nc) {
tab_pos = (int*)malloc((nc+1)*sizeof(int));
tab_width = (int*)malloc((nc)*sizeof(int));
tab_flags = (int*)malloc((nc)*sizeof(int));
}
tab_count = nc;
}
@ -73,33 +110,45 @@ int Fl_Tabs::tab_positions() {
o->labeltype(ot);
o->align(oa);
if (o->when() & FL_WHEN_CLOSED)
wt += labelsize()/2 + EXTRAGAP;
tab_width[i] = wt + EXTRASPACE;
tab_pos[i+1] = tab_pos[i] + tab_width[i] + BORDER;
tab_flags[i] = 0;
}
fl_draw_shortcut = prev_draw_shortcut;
int r = w();
if (tab_pos[i] <= r) return selected;
// uh oh, they are too big:
// pack them against right edge:
tab_pos[i] = r;
for (i = nc; i--;) {
int l = r-tab_width[i];
if (tab_pos[i+1] < l) l = tab_pos[i+1];
if (tab_pos[i] <= l) break;
tab_pos[i] = l;
r -= EXTRASPACE;
}
// pack them against left edge and truncate width if they still don't fit:
for (i = 0; i<nc; i++) {
if (tab_pos[i] >= i*EXTRASPACE) break;
tab_pos[i] = i*EXTRASPACE;
int W = w()-1-EXTRASPACE*(nc-i) - tab_pos[i];
if (tab_width[i] > W) tab_width[i] = W;
}
// adjust edges according to visiblity:
for (i = nc; i > selected; i--) {
tab_pos[i] = tab_pos[i-1] + tab_width[i-1];
if (overflow_type == OVERFLOW_COMPRESS) {
// uh oh, they are too big:
// pack them against right edge:
tab_pos[i] = r;
for (i = nc; i--;) {
int l = r-tab_width[i];
if (tab_pos[i+1] < l) l = tab_pos[i+1];
if (tab_pos[i] <= l) break;
tab_pos[i] = l;
tab_flags[i] |= 1;
r -= EXTRASPACE;
}
// pack them against left edge and truncate width if they still don't fit:
for (i = 0; i<nc; i++) {
if (tab_pos[i] >= i*EXTRASPACE) break;
tab_pos[i] = i*EXTRASPACE;
tab_flags[i] |= 1;
int W = w()-1-EXTRASPACE*(nc-i) - tab_pos[i];
if (tab_width[i] > W) tab_width[i] = W;
}
// adjust edges according to visiblity:
for (i = nc; i > selected; i--) {
tab_pos[i] = tab_pos[i-1] + tab_width[i-1];
}
if ((selected > 0) && (tab_pos[selected-1]+tab_width[selected-1]>tab_pos[selected]))
tab_flags[selected] |= 1;
tab_flags[selected] &= ~1;
}
return selected;
}
@ -121,12 +170,15 @@ int Fl_Tabs::tab_height() {
else return (H <= 0) ? 0 : H;
}
/**
Return the widget of the tab the user clicked on at \p event_x / \p event_y.
This is used for event handling (clicks) and by fluid to pick tabs.
/** Return a pointer to the child widget with a tab at the given coordinates.
\returns The child widget of the tab the user clicked on, or<br>
0 if there are no children or if the event is outside of the tabs area.
The Fl_Tabs::which() method returns a pointer to the child widget of the
Fl_Tabs container that corresponds to the tab at the given event coordinates.
If the event coordinates are outside the area of the tabs or if the Fl_Tabs
container has no children, the method returns NULL.
\param event_x, event_y event coordinates
\returns pointer to the selected child widget, or NULL
*/
Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
if (children() == 0) return 0;
@ -141,7 +193,7 @@ Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
const int nc = children();
tab_positions();
for (int i=0; i<nc; i++) {
if (event_x < x()+tab_pos[i+1]) {
if (event_x < x()+tab_pos[i+1]+tab_offset) {
ret = child(i);
break;
}
@ -149,6 +201,92 @@ Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
return ret;
}
/** Check whether the coordinates fall within the "close" button area of the tab.
The Fl_Tabs::hit_close() method checks whether the given event coordinates
fall within the area of the "close" button on the tab of the specified
child widget. This method should be called after the Fl_Tabs::which() method,
which updates a lookup table used to determine the width of each tab.
\param o check the tab of this widget
\param event_x, event_y event coordinatese
\return 1 if we hit the close button, and 0 otherwie
*/
int Fl_Tabs::hit_close(Fl_Widget *o, int event_x, int event_y) {
(void)event_y;
for (int i=0; i<children(); i++) {
if (child(i)==o) {
// never hit the "close" button on a compressed tab unless it's the active one
if (tab_flags[i] & 1)
return 0;
// did we hit the area of teh "x"?
int tab_x = tab_pos[i] + tab_offset + x();
return ( (event_x >= tab_x)
&& (event_x < tab_x + (labelsize()+EXTRASPACE+EXTRAGAP)/2) );
}
}
return 0;
}
void Fl_Tabs::check_overflow_menu() {
int nc = children();
int H = tab_height(); if (H < 0) H = -H;
if (tab_pos[nc] > w()-H) {
has_overflow_menu = 1;
} else {
has_overflow_menu = 0;
}
}
void Fl_Tabs::handle_overflow_menu() {
int nc = children();
int H = tab_height(); if (H < 0) H = -H;
int vc; // number of visible children
// count visibel children
for (vc = 0; vc < nc; vc++) {
if (tab_pos[vc+1] > w()-H) break;
}
if (vc == nc) return; // children are visible
// create a menu with invisible children
int i, n = nc - vc;
overflow_menu = new Fl_Menu_Item[n+1];
memset(overflow_menu, 0, sizeof(Fl_Menu_Item)*(n+1));
for (i = 0; i < n; i++) {
overflow_menu[i].label(child(vc+i)->label());
overflow_menu[i].user_data(child(vc+i));
}
overflow_menu[i].label(NULL);
// show the menu and handle the selection
const Fl_Menu_Item *m = overflow_menu->popup(x()+w()-H, (tab_height()>0)?(y()+H):(y()+h()));
if (m)
value((Fl_Widget*)m->user_data());
// delete the menu until we need it next time
if (overflow_menu) {
delete[] overflow_menu;
overflow_menu = NULL;
}
}
void Fl_Tabs::draw_overflow_menu_button() {
int H = tab_height();
int X, Y;
if (H > 0) {
X = x() + w() - H;
Y = y();
} else {
H = -H;
X = x() + w() - H;
Y = y() + h() - H;
}
fl_draw_box(box(), X, Y, H, H, color());
Fl_Rect r(X, Y, H, H);
fl_draw_arrow(r, FL_ARROW_CHOICE, FL_ORIENT_NONE, fl_contrast(FL_BLACK, color()));
}
void Fl_Tabs::redraw_tabs()
{
int H = tab_height();
@ -162,31 +300,73 @@ void Fl_Tabs::redraw_tabs()
}
int Fl_Tabs::handle(int event) {
static int initial_x = 0;
static int initial_tab_offset = 0;
static int forward_motion_to_group = 0;
Fl_Widget *o;
int i;
switch (event) {
case FL_PUSH:
initial_x = Fl::event_x();
initial_tab_offset = tab_offset;
forward_motion_to_group = 0;
{
int H = tab_height();
if (H >= 0) {
if (Fl::event_y() > y()+H) return Fl_Group::handle(event);
if (Fl::event_y() > y()+H) {
forward_motion_to_group = 1;
return Fl_Group::handle(event);
}
} else {
if (Fl::event_y() < y()+h()+H) return Fl_Group::handle(event);
if (Fl::event_y() < y()+h()+H) {
forward_motion_to_group = 1;
return Fl_Group::handle(event);
}
H = - H;
}
if (has_overflow_menu && Fl::event_x() > x()+w()-H) {
handle_overflow_menu();
return 1;
}
}
/* FALLTHROUGH */
case FL_DRAG:
case FL_RELEASE:
if (forward_motion_to_group) {
return Fl_Group::handle(event);
}
o = which(Fl::event_x(), Fl::event_y());
if (overflow_type == OVERFLOW_DRAG) {
if (tab_pos[children()] < w() && tab_offset == 0) {
// fall through
} else if (!Fl::event_is_click()) {
tab_offset = initial_tab_offset + Fl::event_x() - initial_x;
if (tab_offset > 0) {
initial_tab_offset -= tab_offset;
tab_offset = 0;
} else {
int dw = tab_pos[children()] + tab_offset - w();
if (dw < -20) {
initial_tab_offset -= dw+20;
tab_offset -= dw+20;
}
}
damage(FL_DAMAGE_EXPOSE|FL_DAMAGE_SCROLL);
return 1;
}
}
if (event == FL_RELEASE) {
push(0);
if (o && Fl::visible_focus() && Fl::focus()!=this) {
Fl::focus(this);
redraw_tabs();
}
if (o && (o->when() & FL_WHEN_CLOSED) && hit_close(o, Fl::event_x(), Fl::event_y())) {
o->do_callback(FL_REASON_CLOSED);
return 1; // o may be deleted at this point
}
if (o && // Released on a tab and..
(value(o) || // tab changed value or..
(when()&(FL_WHEN_NOT_CHANGED)) // ..no change but WHEN_NOT_CHANGED set,
@ -194,7 +374,7 @@ int Fl_Tabs::handle(int event) {
) {
Fl_Widget_Tracker wp(o);
set_changed();
do_callback();
do_callback(FL_REASON_SELECTED);
if (wp.deleted()) return 1;
}
Fl_Tooltip::current(o);
@ -240,16 +420,16 @@ int Fl_Tabs::handle(int event) {
if (child(i)->visible()) break;
value(child(i - 1));
set_changed();
do_callback();
do_callback(FL_REASON_SELECTED);
return 1;
case FL_Right:
if (!children()) return 0;
if (child(children() - 1)->visible()) return 0;
for (i = 0; i < children(); i ++)
for (i = 0; i < children()-1; i++)
if (child(i)->visible()) break;
value(child(i + 1));
set_changed();
do_callback();
do_callback(FL_REASON_SELECTED);
return 1;
case FL_Down:
redraw();
@ -264,8 +444,12 @@ int Fl_Tabs::handle(int event) {
if (c->test_shortcut(c->label())) {
char sc = !c->visible();
value(c);
if (sc) set_changed();
do_callback();
if (sc) {
set_changed();
do_callback(FL_REASON_SELECTED);
} else {
do_callback(FL_REASON_RESELECTED);
}
return 1;
}
}
@ -300,10 +484,15 @@ int Fl_Tabs::push(Fl_Widget *o) {
/**
Gets the currently visible widget/tab.
The value() is the first visible child (or the last child if none
are visible) and this also hides any other children.
This allows the tabs to be deleted, moved to other groups, and
show()/hide() called without it screwing up.
The Fl_Tabs::value() method returns a pointer to the currently visible child
widget of the Fl_Tabs container. The visible child is the first child that
is currently being displayed, or the last child if none of the children are
being displayed.
If child widgets have been added, moved, or deleted, this method ensures that
only one tab is visible at a time.
\return a pointer to the currently visible child
*/
Fl_Widget* Fl_Tabs::value() {
Fl_Widget* v = 0;
@ -317,12 +506,17 @@ Fl_Widget* Fl_Tabs::value() {
return v;
}
/**
Sets the widget to become the current visible widget/tab.
Setting the value hides all other children, and makes this one
visible, if it is really a child.
\returns 1 if there was a change (new value different from previous),<BR>
0 if there was no change (new value already set)
/** Sets the widget to become the current visible widget/tab.
The Fl_Tabs::value() method allows you to set a particular child widget of
the Fl_Tabs container to be the currently visible widget. If the specified
widget is a child of the Fl_Tabs container, it will be made visible and all
other children will be hidden. The method returns 1 if the value was changed,
and 0 if the specified value was already set.
\param[in] newvalue a poiner to a child widget
\return 1 if a different tab was chosen
\return 0 if there was no change (new value already set)
*/
int Fl_Tabs::value(Fl_Widget *newvalue) {
Fl_Widget*const* a = array();
@ -344,12 +538,18 @@ enum {LEFT, RIGHT, SELECTED};
void Fl_Tabs::draw() {
Fl_Widget *v = value();
int H = tab_height();
int ty, th;
if (H >= 0) {
ty = y(); th = H;
} else {
ty = y() + h() + H; th = -H;
}
Fl_Color c = v ? v->color() : color();
if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing:
Fl_Color c = v ? v->color() : color();
if (damage() & FL_DAMAGE_ALL) { // redraw the children
draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), c);
}
if (damage() & (FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) {
if (selection_color() != c) {
// Draw the top or bottom SELECTION_BORDER lines of the tab pane in the
// selection color so that the user knows which tab is selected...
@ -358,33 +558,60 @@ void Fl_Tabs::draw() {
draw_box(box(), x(), clip_y, w(), SELECTION_BORDER, selection_color());
fl_pop_clip();
}
}
if (damage() & FL_DAMAGE_ALL) { // redraw the children
if (v) draw_child(*v);
} else { // redraw the child
if (v) update_child(*v);
}
if (damage() & FL_DAMAGE_EXPOSE) { // redraw the tab bar background
if (parent()) {
Fl_Widget *p = parent();
fl_push_clip(x(), ty, w(), th);
if (p->as_window())
fl_draw_box(p->box(), 0, 0, p->w(), p->h(), p->color());
else
fl_draw_box(p->box(), p->x(), p->y(), p->w(), p->h(), p->color());
fl_pop_clip();
} else {
fl_rectf(x(), ty, w(), th, color());
}
}
if (damage() & (FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) {
const int nc = children();
int selected = tab_positions();
int i;
if (H>0)
fl_push_clip(x(), ty, w(), th+BORDER);
else
fl_push_clip(x(), ty-BORDER, w(), th+BORDER);
Fl_Widget*const* a = array();
for (i=0; i<selected; i++)
draw_tab(x()+tab_pos[i], x()+tab_pos[i+1],
tab_width[i], H, a[i], LEFT);
tab_width[i], H, a[i], tab_flags[i], LEFT);
for (i=nc-1; i > selected; i--)
draw_tab(x()+tab_pos[i], x()+tab_pos[i+1],
tab_width[i], H, a[i], RIGHT);
tab_width[i], H, a[i], tab_flags[i], RIGHT);
if (v) {
i = selected;
draw_tab(x()+tab_pos[i], x()+tab_pos[i+1],
tab_width[i], H, a[i], SELECTED);
tab_width[i], H, a[i], tab_flags[i], SELECTED);
}
if (overflow_type == OVERFLOW_PULLDOWN)
check_overflow_menu();
if (has_overflow_menu)
draw_overflow_menu_button();
fl_pop_clip();
}
}
void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int flags, int what) {
x1 += tab_offset;
x2 += tab_offset;
int sel = (what == SELECTED);
int dh = Fl::box_dh(box());
int dy = Fl::box_dy(box());
int wc = 0; // width of "close" button if drawn, or 0
char prev_draw_shortcut = fl_draw_shortcut;
fl_draw_shortcut = 1;
@ -414,8 +641,18 @@ void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
// Draw the label using the current color...
o->labelcolor(sel ? labelcolor() : o->labelcolor());
o->draw_label(x1, y() + yofs, W, H - yofs, tab_align());
// Draw the "close" button if requested
if ( (o->when() & FL_WHEN_CLOSED) && !(flags & 1) ) {
int sz = labelsize()/2, sy = (H - sz)/2;
fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + yofs/2 + sy, sz, sz, o->labelcolor());
wc = sz + EXTRAGAP;
}
// Draw the label text
o->draw_label(x1 + wc, y() + yofs, W - wc, H - yofs, tab_align());
// Draw the focus box
if (Fl::focus() == this && o->visible())
draw_focus(bt, x1, y(), W, H, bc);
@ -432,8 +669,18 @@ void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
// Draw the label using the current color...
o->labelcolor(sel ? labelcolor() : o->labelcolor());
o->draw_label(x1, y() + h() - H, W, H - yofs, tab_align());
// Draw the "close" button if requested
if ( (o->when() & FL_WHEN_CLOSED) && (x1+W < x2) ) {
int sz = labelsize()/2, sy = (H - sz)/2;
fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + h() - H -yofs/2 + sy, sz, sz, o->labelcolor());
wc = sz + EXTRAGAP;
}
// Draw the label text
o->draw_label(x1 + wc, y() + h() - H, W - wc, H - yofs, tab_align());
// Draw the focus box
if (Fl::focus() == this && o->visible())
draw_focus(bt, x1, y() + h() - H, W, H, bc);
@ -472,14 +719,21 @@ Fl_Tabs::Fl_Tabs(int X, int Y, int W, int H, const char *L) :
{
box(FL_THIN_UP_BOX);
push_ = 0;
overflow_type = OVERFLOW_COMPRESS;
tab_offset = 0;
tab_pos = 0;
tab_width = 0;
tab_flags = NULL;
tab_count = 0;
tab_align_ = FL_ALIGN_CENTER;
has_overflow_menu = 0;
overflow_menu = NULL;
}
Fl_Tabs::~Fl_Tabs() {
clear_tab_positions();
if (overflow_menu)
delete[] overflow_menu;
}
/**
@ -548,4 +802,35 @@ void Fl_Tabs::clear_tab_positions() {
free(tab_width);
tab_width = 0;
}
if (tab_flags){
free(tab_flags);
tab_flags = NULL;
}
}
/** Set a method to handle an overflowing tab bar.
The Fl_Tabs widget allows you to specify how to handle the situation where
there are more tabs than can be displayed at once. The available options are:
- \c OVERFLOW_COMPRESS: Tabs will be compressed and overlaid on top of each other.
- \c OVERFLOW_CLIP: Only the first tabs that fit will be displayed.
- \c OVERFLOW_PULLDOWN: Tabs that do not fit will be placed in a pull-down menu.
- \c OVERFLOW_DRAG: The tab bar can be dragged horizontally to reveal additional tabs.
You can set the desired behavior using the overflow() method.
\param ov overflow type
*/
void Fl_Tabs::handle_overflow(int ov) {
overflow_type = ov;
tab_offset = 0;
has_overflow_menu = 0;
if (overflow_menu) {
delete[] overflow_menu;
overflow_menu = NULL;
}
damage(FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL);
redraw();
}

View File

@ -239,7 +239,7 @@ int Fl_Text_Editor::kf_default(int c, Fl_Text_Editor* e) {
else e->overstrike(s);
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -268,7 +268,7 @@ int Fl_Text_Editor::kf_backspace(int, Fl_Text_Editor* e) {
kill_selection(e);
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -280,7 +280,7 @@ int Fl_Text_Editor::kf_enter(int, Fl_Text_Editor* e) {
e->insert("\n");
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -544,7 +544,7 @@ int Fl_Text_Editor::kf_delete(int, Fl_Text_Editor* e) {
kill_selection(e);
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -567,7 +567,7 @@ int Fl_Text_Editor::kf_cut(int c, Fl_Text_Editor* e) {
kf_copy(c, e);
kill_selection(e);
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -580,7 +580,7 @@ int Fl_Text_Editor::kf_paste(int, Fl_Text_Editor* e) {
Fl::paste(*e, 1);
e->show_insert_position();
e->set_changed();
if (e->when()&FL_WHEN_CHANGED) e->do_callback();
if (e->when()&FL_WHEN_CHANGED) e->do_callback(FL_REASON_CHANGED);
return 1;
}
@ -636,7 +636,7 @@ int Fl_Text_Editor::handle_key() {
}
show_insert_position();
set_changed();
if (when()&FL_WHEN_CHANGED) do_callback();
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
return 1;
}
@ -651,10 +651,11 @@ int Fl_Text_Editor::handle_key() {
}
/** does or does not a callback according to changed() and when() settings */
void Fl_Text_Editor::maybe_do_callback() {
void Fl_Text_Editor::maybe_do_callback(Fl_Callback_Reason reason) {
// printf("Fl_Text_Editor::maybe_do_callback()\n");
// printf("changed()=%d, when()=%x\n", changed(), when());
if (changed() || (when()&FL_WHEN_NOT_CHANGED)) do_callback();
if (changed() || (when()&FL_WHEN_NOT_CHANGED))
do_callback(reason);
}
int Fl_Text_Editor::handle(int event) {
@ -679,7 +680,7 @@ int Fl_Text_Editor::handle(int event) {
if (buffer()->selected()) redraw(); // Redraw selections...
// FALLTHROUGH
case FL_HIDE:
if (when() & FL_WHEN_RELEASE) maybe_do_callback();
if (when() & FL_WHEN_RELEASE) maybe_do_callback(FL_REASON_LOST_FOCUS);
return 1;
case FL_KEYBOARD:
@ -697,7 +698,7 @@ int Fl_Text_Editor::handle(int event) {
else overstrike(Fl::event_text());
show_insert_position();
set_changed();
if (when()&FL_WHEN_CHANGED) do_callback();
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
return 1;
case FL_ENTER:
@ -719,7 +720,7 @@ int Fl_Text_Editor::handle(int event) {
Fl::paste(*this, 0);
Fl::focus(this);
set_changed();
if (when()&FL_WHEN_CHANGED) do_callback();
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
return 1;
}
break;

View File

@ -269,8 +269,12 @@ int Fl_Tile::handle(int event) {
} else
newy = sy;
position(sx,sy,newx,newy);
if (event == FL_DRAG) set_changed();
do_callback();
if (event == FL_DRAG) {
set_changed();
do_callback(FL_REASON_DRAGGED);
} else {
do_callback(FL_REASON_CHANGED);
}
return 1;}
}

View File

@ -2571,7 +2571,7 @@ int Fl_Tree::is_hscroll_visible() const {
void Fl_Tree::do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) {
callback_reason(reason);
callback_item(item);
do_callback((Fl_Widget*)this, user_data());
do_callback((Fl_Widget*)this, user_data(), (Fl_Callback_Reason)reason);
}
/// Sets the item that was changed for this callback.

View File

@ -101,7 +101,7 @@ void Fl_Valuator::handle_drag(double v) {
value_ = v;
value_damage();
set_changed();
if (when() & FL_WHEN_CHANGED) do_callback();
if (when() & FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
}
}
/** Called after an FL_WHEN_RELEASE event is received and before the callback. */
@ -113,7 +113,7 @@ void Fl_Valuator::handle_release() {
clear_changed();
// now do the callback only if slider in new position or always is on:
if (value_ != previous_value_ || when() & FL_WHEN_NOT_CHANGED) {
do_callback();
do_callback(FL_REASON_RELEASED);
}
}
}

View File

@ -33,7 +33,7 @@ void Fl_Value_Input::input_cb(Fl_Widget*, void* v) {
if (nv != t.value() || t.when() & FL_WHEN_NOT_CHANGED) {
t.set_value(nv);
t.set_changed();
if (t.when()) t.do_callback();
if (t.when()) t.do_callback(FL_REASON_CHANGED);
}
}

View File

@ -365,28 +365,33 @@ void Fl_Widget::bind_deimage(Fl_Image* img) {
/** Calls the widget callback function with arbitrary arguments.
All overloads of do_callback() call this method.
It does nothing if the widget's callback() is NULL.
It clears the widget's \e changed flag \b after the callback was
called unless the callback is the default callback. Hence it is not
necessary to call clear_changed() after calling do_callback()
in your own widget's handle() method.
All overloads of do_callback() call this method.
It does nothing if the widget's callback() is NULL.
It clears the widget's \e changed flag \b after the callback was
called unless the callback is the default callback. Hence it is not
necessary to call clear_changed() after calling do_callback()
in your own widget's handle() method.
\note It is legal to delete the widget in the callback (i.e. in user code),
but you must not access the widget in the handle() method after
calling do_callback() if the widget was deleted in the callback.
We recommend to use Fl_Widget_Tracker to check whether the widget
was deleted in the callback.
A \p reason must be set for widgets if different actions can trigger
the same callback.
\param[in] widget call the callback with \p widget as the first argument
\param[in] arg use \p arg as the user data (second) argument
\note It is legal to delete the widget in the callback (i.e. in user code),
but you must not access the widget in the handle() method after
calling do_callback() if the widget was deleted in the callback.
We recommend to use Fl_Widget_Tracker to check whether the widget
was deleted in the callback.
\see default_callback()
\see callback()
\see class Fl_Widget_Tracker
*/
\param[in] widget call the callback with \p widget as the first argument
\param[in] arg use \p arg as the user data (second) argument
\param[in] reason for calling this callback
void Fl_Widget::do_callback(Fl_Widget *widget, void *arg) {
\see default_callback()
\see callback()
\see class Fl_Widget_Tracker
\see Fl::callback_reason()
*/
void Fl_Widget::do_callback(Fl_Widget *widget, void *arg, Fl_Callback_Reason reason) {
Fl::callback_reason_ = reason;
if (!callback_) return;
Fl_Widget_Tracker wp(this);
callback_(widget, arg);

View File

@ -168,7 +168,11 @@ int main(int argc, char **argv) {
browser->callback(b_cb);
if (!browser->load(fname)) {
fl_message("Can't load '%s'\n%s\n", fname, strerror(errno));
exit(1);
browser->add("This is a test of how the browser draws lines.");
browser->add("This is a second line.");
browser->add("This is a third.");
browser->add("@bBold text");
browser->add("@iItalic text");
}
browser->position(0);

View File

@ -5,19 +5,21 @@ code_name {.cxx}
Function {} {open
} {
Fl_Window foo_window {
label {Comparison of Fl_Tab (left) vs. Fl_Wizard (right)} open selected
xywh {516 38 660 400} type Double hide resizable
label {Comparison of Fl_Tab (left) vs. Fl_Wizard (right)} open
xywh {330 402 660 400} type Double resizable visible
} {
Fl_Box {} {
label {class Fl_Tabs}
xywh {95 0 130 35} labeltype ENGRAVED_LABEL labelfont 1
}
Fl_Tabs {} {open
Fl_Tabs tabs_group {open
tooltip {the various index cards test different aspects of the Fl_Tabs widget} xywh {10 35 315 260} selection_color 4 labelcolor 7 resizable
} {
Fl_Group {} {
label {Label&1}
tooltip {this tab tests correct keyboard navigation between text input fields} xywh {10 60 315 235} selection_color 1 resizable
callback {if (Fl::callback_reason()==FL_REASON_CLOSED)
o->parent()->remove(o);} selected
tooltip {this tab tests correct keyboard navigation between text input fields} xywh {10 60 315 235} selection_color 1 when 16 hide resizable
} {
Fl_Input {} {
label {input:}
@ -35,7 +37,9 @@ Function {} {open
}
Fl_Group {} {
label {tab&2}
tooltip {tab2 tests among other things the cooperation of modal windows and tabs} xywh {10 60 315 235} selection_color 2 hide
callback {if (Fl::callback_reason()==FL_REASON_CLOSED)
o->parent()->remove(o);} selected
tooltip {tab2 tests among other things the cooperation of modal windows and tabs} xywh {10 60 315 235} selection_color 2 when 16 hide
} {
Fl_Button {} {
label button1
@ -61,7 +65,9 @@ Function {} {open
}
Fl_Group {} {
label {tab&3}
tooltip {tab3 checks for correct keyboard navigation} xywh {10 60 315 235} selection_color 3 hide
callback {if (Fl::callback_reason()==FL_REASON_CLOSED)
o->parent()->remove(o);} selected
tooltip {tab3 checks for correct keyboard navigation} xywh {10 60 315 235} selection_color 3 when 16 hide
} {
Fl_Button {} {
label button2
@ -78,7 +84,9 @@ Function {} {open
}
Fl_Group {} {
label {&tab4}
tooltip {this tab shows the issue of indicating a selected tab if the tab layouts are very similar} xywh {10 60 315 235} selection_color 5 labeltype ENGRAVED_LABEL labelfont 2 hide
callback {if (Fl::callback_reason()==FL_REASON_CLOSED)
o->parent()->remove(o);} selected
tooltip {this tab shows the issue of indicating a selected tab if the tab layouts are very similar} xywh {10 60 315 235} selection_color 5 labeltype ENGRAVED_LABEL labelfont 2 when 16 hide
} {
Fl_Button {} {
label button2
@ -94,8 +102,8 @@ Function {} {open
}
}
Fl_Group {} {
label {@fileprint &print}
tooltip {tab5 verifies if visibility requests are handled correctly} xywh {10 60 315 235} hide
label {@fileprint &print} selected
tooltip {tab5 verifies if visibility requests are handled correctly} xywh {10 60 315 235}
} {
Fl_Button {} {
label button2
@ -265,12 +273,53 @@ wWizard->value(wWizard->child(last));}
tooltip {go to last page [End]} xywh {510 305 30 25} shortcut 0xff57
}
}
Fl_Input {} {
label {inputA:}
xywh {60 310 130 25}
Fl_Button {} {
label {add tab}
callback {static int n = 6;
int X = tabs_group->x(), Y = tabs_group->y()+25;
int W = tabs_group->w(), H = tabs_group->h()-25;
Fl_Group::current(NULL);
char buf[64];
snprintf(buf, 62, "tab%d", n);
Fl_Group* new_tab = new Fl_Group(X, Y, W, H);
new_tab->copy_label(buf);
new_tab->when(FL_WHEN_CLOSED);
new_tab->callback((Fl_Callback*)cb_tab);
snprintf(buf, 62, "Empty tab %d.", n);
Fl_Box* box = new Fl_Box(X+5, Y+5, W-10, H-10);
box->copy_label(buf);
box->align(Fl_Align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE));
tabs_group->add(new_tab);
n++;}
tooltip {Add more tabs to check overflow handling.} xywh {60 309 70 25}
}
Fl_Choice {} {
label {overflow:} open
tooltip {Change how Fl_Tabs handles more tabs than fit into the tabs space.} xywh {212 309 95 25} down_box BORDER_BOX
} {
MenuItem {} {
label compress
callback {tabs_group->handle_overflow(Fl_Tabs::OVERFLOW_COMPRESS);}
xywh {0 0 31 20}
}
MenuItem {} {
label clip
callback {tabs_group->handle_overflow(Fl_Tabs::OVERFLOW_CLIP);}
xywh {0 0 31 20}
}
MenuItem {} {
label pulldown
callback {tabs_group->handle_overflow(Fl_Tabs::OVERFLOW_PULLDOWN);}
xywh {0 0 31 20}
}
MenuItem {} {
label drag
callback {tabs_group->handle_overflow(Fl_Tabs::OVERFLOW_DRAG);}
xywh {0 0 31 20}
}
}
Fl_Input {} {
label {inputB:}
label {input:}
xywh {60 345 250 25}
}
Fl_Button {} {