Restore original Fl_Button event behavior(#877)

Previous commits introduced too many changes to Fl_Button callbacks,
creating problems in user apps. This is the base for a second much
more specific fix to event flags.
This commit is contained in:
Matthias Melcher 2024-01-17 18:54:01 +01:00
parent 0dfa37f4c0
commit a038e55783
1 changed files with 110 additions and 151 deletions

View File

@ -32,10 +32,10 @@ Fl_Widget_Tracker *Fl_Button::key_release_tracker = 0;
// here. This includes Fl_Radio_Button and Fl_Toggle_Button
/**
Sets the current value of the button.
A non-zero value sets the button to 1 (ON), and zero sets it to 0 (OFF).
\param[in] v button value.
\see set(), clear()
Sets the current value of the button.
A non-zero value sets the button to 1 (ON), and zero sets it to 0 (OFF).
\param[in] v button value.
\see set(), clear()
*/
int Fl_Button::value(int v) {
v = v ? 1 : 0;
@ -52,8 +52,8 @@ int Fl_Button::value(int v) {
}
/**
Turns on this button and turns off all other radio buttons in the group
(calling \c value(1) or \c set() does not do this).
Turns on this button and turns off all other radio buttons in the group
(calling \c value(1) or \c set() does not do this).
*/
void Fl_Button::setonly() { // set this radio button on, turn others off
value(1);
@ -102,112 +102,93 @@ void Fl_Button::draw() {
}
int Fl_Button::handle(int event) {
static bool s_key_repeat = false;
int newval;
switch (event) {
case FL_ENTER: /* FALLTHROUGH */
case FL_LEAVE:
// if ((value_?selection_color():color())==FL_GRAY) redraw();
return 1;
case FL_PUSH:
if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
/* FALLTHROUGH */
case FL_DRAG:
if (Fl::event_inside(this)) {
if (type() == FL_RADIO_BUTTON) newval = 1;
else newval = !oldval;
} else {
clear_changed();
newval = oldval;
}
if (newval != value_) {
value_ = newval;
set_changed();
redraw();
if ((type() == 0) && (when() & FL_WHEN_CHANGED)) do_callback(FL_REASON_CHANGED);
}
return 1;
case FL_RELEASE:
if (value_ == oldval) {
clear_changed();
} else {
if (type() == FL_RADIO_BUTTON) {
setonly();
} else if (type() == FL_TOGGLE_BUTTON) {
oldval = value_;
case FL_ENTER: /* FALLTHROUGH */
case FL_LEAVE:
// if ((value_?selection_color():color())==FL_GRAY) redraw();
return 1;
case FL_PUSH:
if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
/* FALLTHROUGH */
case FL_DRAG:
if (Fl::event_inside(this)) {
if (type() == FL_RADIO_BUTTON) newval = 1;
else newval = !oldval;
} else {
clear_changed();
newval = oldval;
}
if (newval != value_) {
value_ = newval;
set_changed();
redraw();
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(FL_REASON_SELECTED);
return 1;
}
set_changed();
if (type() == FL_RADIO_BUTTON) setonly();
else if (type() == FL_TOGGLE_BUTTON) oldval = value_;
else {
value(oldval);
}
set_changed();
}
if (changed() && (when() & FL_WHEN_CHANGED))
do_callback(FL_REASON_CHANGED);
else if (!changed() && (when() & FL_WHEN_NOT_CHANGED))
do_callback(FL_REASON_SELECTED);
else if (when() & FL_WHEN_RELEASE)
do_callback(FL_REASON_RELEASED);
return 1;
case FL_SHORTCUT:
if (!(shortcut() ?
Fl::test_shortcut(shortcut()) : test_shortcut())) return 0;
if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
goto triggered_by_keyboard;
case FL_FOCUS :
case FL_UNFOCUS :
if (Fl::visible_focus()) {
if (box() == FL_NO_BOX) {
// Widgets with the FL_NO_BOX boxtype need a parent to
// redraw, since it is responsible for redrawing the
// background...
int X = x() > 0 ? x() - 1 : 0;
int Y = y() > 0 ? y() - 1 : 0;
if (window()) window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2);
} else redraw();
return 1;
} else return 0;
/* NOTREACHED */
case FL_KEYUP:
s_key_repeat = false;
return 0;
case FL_KEYBOARD :
if (Fl::focus() == this && Fl::event_key() == ' ' &&
!(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) {
triggered_by_keyboard:
if (s_key_repeat) return 1;
Fl_Widget_Tracker wp(this);
if (type() == FL_RADIO_BUTTON) {
if (!value_) {
setonly();
set_changed();
} else {
clear_changed();
set_changed();
if (when() & FL_WHEN_CHANGED) {
Fl_Widget_Tracker wp(this);
do_callback(FL_REASON_CHANGED);
if (wp.deleted()) return 1;
}
} else if (type() == FL_TOGGLE_BUTTON) {
value(!value());
set_changed();
} else {
set_changed();
}
if (changed() && (when() & FL_WHEN_CHANGED))
do_callback(FL_REASON_CHANGED);
else if (!changed() && (when() & FL_WHEN_NOT_CHANGED))
do_callback(FL_REASON_SELECTED);
else if (when() & FL_WHEN_RELEASE)
do_callback(FL_REASON_RELEASED);
s_key_repeat = true;
if (wp.deleted()) return 1; // leave if the widget was deleted in the callback
if ((type() != FL_RADIO_BUTTON) && (type() != FL_TOGGLE_BUTTON)) {
simulate_key_action(); // for visual feedback only
}
if (when() & FL_WHEN_RELEASE) do_callback(FL_REASON_RELEASED);
return 1;
}
/* FALLTHROUGH */
default:
return 0;
case FL_SHORTCUT:
if (!(shortcut() ?
Fl::test_shortcut(shortcut()) : test_shortcut())) return 0;
if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
goto triggered_by_keyboard;
case FL_FOCUS :
case FL_UNFOCUS :
if (Fl::visible_focus()) {
if (box() == FL_NO_BOX) {
// Widgets with the FL_NO_BOX boxtype need a parent to
// redraw, since it is responsible for redrawing the
// background...
int X = x() > 0 ? x() - 1 : 0;
int Y = y() > 0 ? y() - 1 : 0;
if (window()) window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2);
} else redraw();
return 1;
} else return 0;
/* NOTREACHED */
case FL_KEYBOARD :
if (Fl::focus() == this && Fl::event_key() == ' ' &&
!(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) {
set_changed();
triggered_by_keyboard:
Fl_Widget_Tracker wp(this);
if (type() == FL_RADIO_BUTTON) {
if (!value_) {
setonly();
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(FL_REASON_CHANGED);
} else {
simulate_key_action();
}
if (wp.deleted()) return 1;
if (when() & FL_WHEN_RELEASE) do_callback(FL_REASON_RELEASED);
return 1;
}
/* FALLTHROUGH */
default:
return 0;
}
return 0;
}
void Fl_Button::simulate_key_action()
@ -238,65 +219,43 @@ void Fl_Button::key_release_timeout(void *d)
}
/**
The constructor creates the button using the given position, size, and label.
The constructor creates the button using the given position, size, and label.
The default box type is box(FL_UP_BOX).
The default box type is box(FL_UP_BOX).
You can control how the button is drawn when ON by setting down_box().
The default is FL_NO_BOX (0) which will select an appropriate box type
using the normal (OFF) box type by using fl_down(box()).
You can control how the button is drawn when ON by setting down_box().
The default is FL_NO_BOX (0) which will select an appropriate box type
using the normal (OFF) box type by using fl_down(box()).
Derived classes may handle this differently.
Derived classes may handle this differently.
A button may request callbacks by setting bits in the \p when() bitfield.
Only one callback is called for any one event. If multiple bits are set,
only the first callback in the list below will be called.
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.
If the `FL_WHEN_CHANGED` bit is set, the callback is called when the mouse
button is released, the shortcut key was pressed, or the button has focus
and the space bar was pressed, and the value of the button changed. A regular
button (not a radio or toggle button) callback is also triggered by key
repeat events. The callback reason is set to `FL_REASON_CHANGED`.
`Fl_Button::changed()` is !=0, and `Fl_Button::value()` is set to the new
value for radio and check buttons.
If `FL_WHEN_NOT_CHANGED` is set, the callback is called for the same events
as above, but only if the value did *not* change. The callback reason is
`FL_REASON_SELECTED`. This bit is usually combined with other bits in `when()`.
The default setting is `FL_WHEN_RELEASE`. If this flag is set, the callback is
called when the mouse button or the shortcut key is released. Toggle and radio
button callbacks are called, even if the value did not change, however the
`Fl_Button::changed()` flag is set accordingly. The callback reason is given
as `FL_REASON_RELEASED`.
When a radio button changes other radio buttons in the same group, only the
user activated button will trigger its callback according to the flags above.
The other widgets in the group will change their value, but not call their
corresponding callbacks.
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
\param[in] X, Y, W, H position and size of the widget
\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),
shortcut_(0),
value_(0),
oldval(0),
down_box_(FL_NO_BOX),
compact_(0)
shortcut_(0),
value_(0),
oldval(0),
down_box_(FL_NO_BOX),
compact_(0)
{
box(FL_UP_BOX);
set_flag(SHORTCUT_LABEL);
}
/**
The constructor creates the button using the given position, size, and label.
The constructor creates the button using the given position, size, and label.
The Button type() is set to FL_RADIO_BUTTON.
The Button type() is set to FL_RADIO_BUTTON.
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
*/
Fl_Radio_Button::Fl_Radio_Button(int X,int Y,int W,int H,const char *L)
: Fl_Button(X, Y, W, H, L) {
@ -304,12 +263,12 @@ Fl_Radio_Button::Fl_Radio_Button(int X,int Y,int W,int H,const char *L)
}
/**
The constructor creates the button using the given position, size, and label.
The constructor creates the button using the given position, size, and label.
The Button type() is set to FL_TOGGLE_BUTTON.
The Button type() is set to FL_TOGGLE_BUTTON.
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
*/
Fl_Toggle_Button::Fl_Toggle_Button(int X,int Y,int W,int H,const char *L)
: Fl_Button(X,Y,W,H,L)