Solves STR #2939; adding when() support to Fl_Tabs.

Also added a general Fl_Tabs code example to the docs.



git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@9867 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Greg Ercolano 2013-04-08 20:18:40 +00:00
parent d5404dea25
commit 6bcd9390f8
2 changed files with 153 additions and 22 deletions

View File

@ -49,6 +49,49 @@
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.
Typical use:
\code
Fl_Tabs *tabs = new Fl_Tabs(10,10,300,200);
{
Fl_Group *tab1 = new Fl_Group(20,30,280,170,"Tab1");
{
..widgets that go in tab#1..
}
tab1->end();
Fl_Group *tab2 = new Fl_Group(20,30,280,170,"Tab2");
{
..widgets that go in tab#2..
}
tab2->end();
}
tabs->end();
\endcode
In the above, tab1's tab can be made red by using tab1->selection_color(FL_RED);
and tab1's text can be made bold by tab1->labelfont(FL_HELVETICA_BOLD),
and can be made 'engraved' by tab1->labeltype(FL_ENGRAVED_LABEL);
As of FLTK 1.3.3, Fl_Tabs() supports the following flags for when():
- \ref FL_WHEN_NEVER -- callback never invoked (all flags off)
- \ref FL_WHEN_CHANGED -- if flag set, invokes callback when a tab has been changed (on click or keyboard navigation)
- \ref FL_WHEN_NOT_CHANGED -- if flag set, invokes callback when the tabs remain unchanged (on click or keyboard navigation)
- \ref FL_WHEN_RELEASE -- if flag set, invokes callback on RELEASE of mouse button or keyboard navigation
Notes:
-# The above flags can be logically OR-ed (|) or added (+) to combine behaviors.
-# The default value for when() is \ref FL_WHEN_RELEASE (inherited from Fl_Widget).
-# If \ref FL_WHEN_RELEASE is the \em only flag specified,
the behavior will be as if (\ref FL_WHEN_RELEASE|\ref FL_WHEN_CHANGED) was specified.
-# The value of changed() will be valid during the callback.
-# If both \ref FL_WHEN_CHANGED and \ref FL_WHEN_NOT_CHANGED are specified,
the callback is invoked whether the tab has been changed or not.
The changed() method can be used to determine the cause.
-# \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.
*/
class FL_EXPORT Fl_Tabs : public Fl_Group {
Fl_Widget *value_;

View File

@ -170,25 +170,59 @@ int Fl_Tabs::handle(int event) {
}}
/* FALLTHROUGH */
case FL_DRAG:
case FL_RELEASE:
o = which(Fl::event_x(), Fl::event_y());
case FL_RELEASE: {
// PUSH, DRAG, RELEASE..
int do_cb=0;
if ((o = which(Fl::event_x(), Fl::event_y()))) { // get tab group for tab user is over
if (o != value()) set_changed(); // if over tab, handle change
else clear_changed();
}
if (event == FL_RELEASE) {
push(0);
if (o && Fl::visible_focus() && Fl::focus()!=this) {
Fl::focus(this);
redraw_tabs();
}
if (o && value(o)) {
Fl_Widget_Tracker wp(o);
set_changed();
do_callback();
if (wp.deleted()) return 1;
push(0); // no longer 'pushed'
// Over a tab?
if (o) {
// Handle taking keyboard focus w/visible focus indication
if (Fl::visible_focus() && Fl::focus()!=this) {
Fl::focus(this);
redraw_tabs();
}
if (value(o)) { // commit to value, see if it "changed"..
set_changed(); // it changed
do_cb =
( (when() & FL_WHEN_RELEASE) && // wants cb on RELEASE and..
(when() & FL_WHEN_CHANGED) // when changed?
) || ( // ..or..
(when() == FL_WHEN_RELEASE) // *only* WHEN_RELEASE specified? (default behavior)
) ? 1 : 0;
} else {
clear_changed(); // no change
do_cb = (when() & FL_WHEN_RELEASE && // wants cb when RELEASE and..
when() & FL_WHEN_NOT_CHANGED)?1:0; // ..when no change occurred?
}
}
Fl_Tooltip::current(o);
} else {
push(o);
// PUSH or DRAG?
// Be careful; a user can PUSH on a tab, but can abort the change
// if they glide off the tab before a RELEASE. Callbacks on PUSH
// will see a value change, but it may change back on RELEASE if
// the user aborts the change.
//
push(o); // DRAG|PUSH -- indicate if still on tab
if (o && event == FL_PUSH) { // still on tab?
// See if we should do the callback
do_cb =
( !(when() & FL_WHEN_RELEASE) && // wants callback on PUSH? (ie. NOT RELEASE)
(
((when() & FL_WHEN_NOT_CHANGED) && !changed()) || // want cb if no change and no change occurred?
((when() & FL_WHEN_CHANGED) && changed()) // want cb if change and change occurred?
)
) ? 1 : 0;
}
}
return 1;
if (do_cb)
do_callback();
return 1; }
case FL_MOVE: {
int ret = Fl_Group::handle(event);
Fl_Widget *o = Fl_Tooltip::current(), *n = o;
@ -217,23 +251,53 @@ int Fl_Tabs::handle(int event) {
if (Fl::event() == FL_UNFOCUS) return 0;
else return 1;
} else return Fl_Group::handle(event);
/* NOTREACHED */
case FL_KEYBOARD:
// NOTE:
// 1) FL_KEYBOARD same as FL_KEYDN; we can receive a string of these
// without FL_KEYUP between during key-repeat.
// 2) We use push() to keep track of value() changes during key-repeat for FL_KEYUP.
// (It would be bad if app's callback saw changed()=false if key-repeat hit the
// left-most or right-most tabs)
//
switch (Fl::event_key()) {
case FL_Left:
if (child(0)->visible()) return 0;
for (i = 1; i < children(); i ++)
// First push on tab? (ie. non key-repeat?)
// Save current value (so KEYUP can see if changed() during key-repeat)
// and clear_changed().
//
if (!push()) { push(value()); clear_changed(); }// first push on tab? (not key-repeat) save curr value for change
if (child(0)->visible()) { // already on left-most tab?
if (when() & FL_WHEN_NOT_CHANGED) // want callback if no change?
do_callback(); // do callback
// return 1 to 'handle' the arrow key, or 0 to let
// arrow key be used by fltk for focus navigation.
return (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1);
}
for (i = 1; i < children(); i ++) // Find currently visible child
if (child(i)->visible()) break;
value(child(i - 1));
value(child(i - 1)); // select the next tab to the left
set_changed();
do_callback();
if ( (when() & FL_WHEN_CHANGED) && // changed: want cb on change and..
!(when() & FL_WHEN_RELEASE)) // ..on PUSH?
do_callback(); // do callback
return 1;
case FL_Right:
if (child(children() - 1)->visible()) return 0;
for (i = 0; i < children(); i ++)
if (!push()) { push(value()); clear_changed(); }// first push on tab? (not key-repeat)
if (child(children() - 1)->visible()) { // already on right-most tab?
if (when() & FL_WHEN_NOT_CHANGED) // want callback if no change?
do_callback(); // do callback
// return 1 to 'handle' the arrow key, or 0 to let
// arrow key be used by fltk for focus navigation.
return (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1);
}
for (i = 0; i < children(); i ++) // Find currently visible child
if (child(i)->visible()) break;
value(child(i + 1));
value(child(i + 1)); // select the next tab to the right
set_changed();
do_callback();
if ( (when() & FL_WHEN_CHANGED) && // change: want callback on change and..
!(when() & FL_WHEN_RELEASE)) // ..on PUSH?
do_callback(); // do callback
return 1;
case FL_Down:
redraw();
@ -242,6 +306,29 @@ int Fl_Tabs::handle(int event) {
break;
}
return Fl_Group::handle(event);
case FL_KEYUP:
switch (Fl::event_key()) {
case FL_Left:
case FL_Right:
if (push()) {
// See if value() changed since first KEYDN
if (push() != value()) set_changed();
else clear_changed();
push(0); // key released, no longer push()ed
if ( when() & FL_WHEN_RELEASE) { // want cb on RELEASE?
if ( (changed() && ( // changed and..
(when() & FL_WHEN_CHANGED) || // want cb on change or..
(when()==FL_WHEN_RELEASE))) || // want cb on RELEASE only (implies change -- legacy default)
(!changed() && // ..or, not changed and..
(when() & FL_WHEN_NOT_CHANGED))) { // want cb on no change?
do_callback(); // do callback
}
}
}
return 1;
break;
}
return Fl_Group::handle(event);
case FL_SHORTCUT:
for (i = 0; i < children(); ++i) {
Fl_Widget *c = child(i);
@ -256,6 +343,7 @@ int Fl_Tabs::handle(int event) {
return Fl_Group::handle(event);
case FL_SHOW:
value(); // update visibilities and fall through
/* FALLTHROUGH */
default:
return Fl_Group::handle(event);