| [ Return to Bugs & Features | Roadmap 1.3 | SVN ⇄ GIT ]
STR #3009
Application: | FLTK Library |
Status: | 1 - Closed w/Resolution |
Priority: | 4 - High, e.g. key functionality not working |
Scope: | 3 - Applies to all machines and operating systems |
Subsystem: | Core Library |
Summary: | Fl_Tabs::value() |
Version: | 1.3-current |
Created By: | rokan2 |
Assigned To: | greg.ercolano |
Fix Version: | 1.3-current (SVN: v10122) |
Update Notification: | |
Trouble Report Files:
Trouble Report Comments:
|
#1 | rokan2 09:47 Nov 28, 2013 |
| There seems to be a serious bug introduced in recent svn when you want to inspect Fl_Tabs::value() within a callback assigned to Fl_Tabs (that is encapsulating Fl_Tabs widget, not the children): as a result you will get PREVIOUS Fl_Widget * value(), not what it suppesed to be set after tab clicking/change.
It seems that the children are shown/hidden only after the callback which gives that behaviour as value() gives the result according to children visibility.
This is inconsistent with previous behaviour and breaks applications which rely on Fl_Tabs::value() inside the callback.
This bug could be related to recent changes to Fl_Tabs::handle() introduced by Greg as 1.3.2 release works fine. I don't understand these changes - maybe Greg can look into the issue?
Thanks, Roman | |
|
#2 | greg.ercolano 22:53 Jan 26, 2014 |
| Taking a look, assigning to me.. | |
|
#3 | greg.ercolano 23:16 Jan 26, 2014 |
| Can't seem to replicate.
Attaching a modified version of the Fl_Tabs cheat sheet example with a callback() assigned to the Fl_Tabs that prints the label of the value() item.
In my tests with SVN current, it always seems to print the tab that was clicked on.
Can you either provide demo code with instructions to replicate, or try the attached and modify as needed to replicate?
Since the handle() mods you mention was to solve a when() issue, check if your app adjusts when(), and include that here, as it may be relevant to replicate. | |
|
#4 | rokan2 08:44 Jan 27, 2014 |
| Right, it missbehaves when you change when() to FL_WHEN_CHANGED, in your example modify following:
tabs->callback(Tab_CB); // <-- ADDED THIS tabs->when(FL_WHEN_CHANGED); // <-- ADDED by RK
Note that I have tested it only for FL_WHEN_CHANGED, it might missbehave also with other values of when().
R. | |
|
#5 | greg.ercolano 09:25 Jan 27, 2014 |
| OK, great, I can replicate.
Will follow up. | |
|
#6 | greg.ercolano 12:27 Jan 27, 2014 |
| OK, I see what's happening.
The problem is by not including the when() flag 'FL_WHEN_RELEASE', the tab is triggering the callback() on FL_PUSH instead of FL_RELEASE. This is now correct behavior.
(Note you're getting the callback when the button is pressed, not when it released)
But, the way the tab widget is written, the tab state doesn't change until the person /releases/ the button. This is so that the person can abort the change if they drag off the tab before releasing the button.
While this is true of other state widgets too, like Fl_Light_Button and Fl_Radio_Button, they differ slightly in that they DO change state on FL_PUSH, but will change back to the old state if the user doesn't drags off the widget before releasing. (This invokes ANOTHER callback for the value state when it reverts to the previous value).
You can actually get many callbacks from one press of the mouse button just by wagging the mouse back and forth over the edge of the button widgets without releasing the button.
This is slightly more complex behavior, but probably needed if Fl_Tabs is to behave similarly to the other widgets.
This'll take some work.. will follow up. | |
|
#7 | greg.ercolano 12:30 Jan 27, 2014 |
| Correction; when I wrote:
> but will change back to the old state if the user doesn't drags off the widget
..that "doesn't" shouldn't be in there; I meant instead:
> but will change back to the old state if the user drags off the widget | |
|
#8 | rokan2 06:35 Jan 28, 2014 |
| > ...the tab is triggering the callback() on FL_PUSH instead of FL_RELEASE. This is now correct behavior.
Is that right? I understand that other widgets change the state immediatelly after push but as you say to allow the user to "drag away" the state of the widget should be changed only after the release (if other conditions are met - like the mouse is still inside the handler).
> But, the way the tab widget is written, the tab state doesn't change until the person /releases/ the button. This is so that the person can abort the change if they drag off the tab before releasing the button.
Right, this seems to me the correct behaviour for Fl_Tabs (and contrary to the first). Anyway there is no FL_WHEN_PUSH so to me there is never any need to change the state after push and before release (apart for drawing - see below). So for various when() flags the callback should be performed as follows:
FL_WHEN_NEVER - never (0, if the other flaggs are not OR-ed)
FL_WHEN_CHANGED - only when state changes (and AFTER either mouse button is released or a shourcut key is pressed AND state changes)
FL_WHEN_NOT_CHANGED - the same as FL_WHEN_CHANGED + when switching "to the same tab" (that is otherwise no state change)
FL_WHEN_RELEASE - the same conditions as FL_WHEN_CHANGED
FL_WHEN_RELEASE_ALWAYS - the same conditions as FL_WHEN_NOT_CHANGED
FL_WHEN_ENTER_KEY - the same as FL_WHEN_NEVER (0) as enter never changes the state
FL_WHEN_ENTER_KEY_ALWAYS - wehen tabs have focus and useser presses ENTER (the state still doesnot change)
FL_WHEN_ENTER_KEY_CHANGED - 0 (never)
As usual, the flags can be OR-ed but to me for the Fl_Tabs widget the state should NOT change (and possible callback should NEVER be invoked) before mouse is released (eg NOT on push). This assures that there is no state double-switchinng for a "overal interaction" (like mouse PUSH + DRAG_AWAY + RELEASE) and also assures that the callback is invoked only ONCE.
The other thing is that upon push the tab handler might visualy change to indicate that to the user - but still the state should not change. So there must be other means to indicate "pushed-only" state (yet without changing value()). Im not sure what flag can be used for this without breaking binary compatibility - maybe ugly hack: a global/static pointer to *pushed* tab subwidget which would indicate that the tabs handler to it should be draw()n differently. Anyway as all FLTK GUI must be run from a single thread (or before messing with GUI state Fl::lock() must be called) and the user interacts only with one tab at a time there would be no conflict to that pointer (which would be obviously cleared after the release).
R. | |
|
#9 | rokan2 07:21 Jan 28, 2014 |
| Heh, I've just looked into the code and there are already push_, push() members to indicate pushed tab so there is no need for global variable ;) | |
|
#10 | greg.ercolano 12:55 Jan 28, 2014 |
| > .. but to me for the Fl_Tabs widget the state should NOT change > (and possible callback should NEVER be invoked) before mouse is > released (eg NOT on push). This assures that there is no state > double-switchinng for a "overall interaction" (like mouse PUSH + > DRAG_AWAY + RELEASE) and also assures that the callback is > invoked only ONCE.
Mmm, I see.. there seems to be different behaviors for the different widget types.. there's no true standard of behavior it seems.
TL;DR for the below: I'll see about reverting to the old 1.3.2 handle() code, and rework it to see if I can solve the previous STR and retain the behavior you need.
I tried some empirical tests with the attached "test-tabs.cxx", a handy program for comparing the callback() behavior of the following widgets for different values of when():
Fl_Tabs, Fl_Browser, Fl_Radio_Button, Fl_Light_Button
Using the 'when()' choice at the bottom applies that value to all the widgets above it, letting one exercise the widgets click behavior, printing callback results in the terminal window.
Here's what I found for fltk 1.3.2 with "when()" set to FL_WHEN_CHANGED. Fl_Tabs is odd in that it's the only one that doesn't take effect on FL_PUSH:
1) Fl_Tabs: 1a. On FL_PUSH, the visual state of the button changes, but not the group visibility, and the callback is not triggered. 1b. On FL_RELEASE the group changes and the callback is invoked 1c. If you "drag-off", you can abort the change, and no callback is done.
2) Fl_Xxx_Button widgets (Fl_Light_Button, Fl_Radio_Button..) 2a. On FL_PUSH, the state changes and the callback() invoked, value() changed. 2b. On FL_RELEASE there is no callback. 2c. On FL_DRAG, if the user "drags-off", the value() reverts to the pre-click value and the callback() re-triggers. 2d. If you wag the mouse back and forth over the button boundary while keeping the mouse down, the value() state changes and callback() re-triggers.
3) Fl_Xxx_Browser widgets (Fl_Hold_Browser..) 3a. On FL_PUSH, the state changes and triggers the callback right away. 3b. On FL_RELEASE, there is no callback. 3c. On FL_DRAG, you can't do the "drag-off to abort" trick; FL_PUSH commits the change. 3d. If you wag the mouse around with the button down, it either selects other items and triggers their callbacks, or if you drag off the widget (to the left or right) the last selection remains in effect. 3e. Interestingly (perhaps this is a bug), if you drag downward off the bottom of the item list into the white area of the widget, you can end up with nothing selected, and no callback to indicate this change.
The behavior for (1) is not documented at all in the 1.3.2 docs. It's OK I guess, but quite different from (2) and (3). I'll see about preserving this behavior in 1.3.3, while keeping the fix for the previous STR.
FWIW, I made an offline mod to Fl_Tabs() where I took the Fl_Button handle() code, and reworked it into Fl_Tabs so that the tabs have the same behavior as an Fl_Button, with regards to callback()s and "drag-off" behavior.
Providing that patch here as "Fl_Tabs-with-button-behavior.patch" if for no other reason, just to demonstrate what the behavior looks like. (In the process, I fixed a bug with tooltips in Fl_Tabs, but that's another thing)
Not suggesting that patch though, as it may be better to preserve the 1.3.2 Fl_Tabs behavior, and I'll see if I can take a different route to solving the previous STR, and get you what you want as well. And I'll redo the docs to be clear about the supported when() behaviors.
Regarding the other widgets:
The behavior for (2) is documented well in the docs for Fl_Button, and seems like reasonable behavior to me: ---- For an Fl_Button object, the following when() values are useful, the default being FL_WHEN_RELEASE:
0: The callback is not done, instead changed() is turned on. FL_WHEN_RELEASE: The callback is done after the user successfully clicks the button, or when a shortcut is typed. 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). ----
The behavior for (3) is kinda documented in Fl_Hold_Browser this way: ---- As long as the mouse button is held down the item pointed to by it is highlighted, and this highlighting remains on when the mouse button is released. Normally the callback is done when the user releases the mouse, but you can change this with when(). ----
That could probably use some elaboration. | |
|
#11 | greg.ercolano 13:09 Jan 28, 2014 |
| Will be following up with a better patch that reverts to the 1.3.2 behavior, and integrates the previous STR and this one with a less intrusive change. | |
|
#12 | greg.ercolano 13:15 Jan 28, 2014 |
| Attaching the test program I mentioned that compares the different widgets when() behavior here as "test-tabs_v3.cxx" instead.
Forgot I had one already called "test-tabs.cxx" attached to this STR (which does much less). | |
|
#13 | greg.ercolano 13:34 Jan 28, 2014 |
| For reference, the related STR: http://www.fltk.org/str.php?L2939
..which simply asks that an application that only has a single tab can trigger callback() by setting when(FL_WHEN_NOT_CHANGED).
The whole other business of trying to create a way for FL_WHEN_RELEASE to give meaningful behavior in Fl_Tabs when specified vs. not isn't mentioned in that STR, so that was perhaps a solution without a problem. "So if it ain't broke, don't fix it".. | |
|
#14 | greg.ercolano 11:52 Mar 24, 2014 |
| OK, this should now be fixed 'properly' in r10122.
Reverted the changes made r9867 that caused this problem, and applied a less intrusive fix to solve STR #2939. | |
|
#15 | ianmacarthur 16:29 Sep 04, 2014 |
| Are we happy this STR is good to close now? | |
|
#16 | greg.ercolano 17:28 Sep 04, 2014 |
| Fixed in Subversion repository.
I think so -- it's been open long enough.
If the OP has further comments, take it to fltk.development to request a reopen of this STR. | |
[ Return to Bugs & Features ]
|
| |