FLTK logo

STR #3009

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 Home  |  Articles & FAQs  |  Bugs & Features  |  Documentation  |  Download  |  Screenshots  ]
 

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:

Receive EMails Don't Receive EMails

Trouble Report Files:


Name/Time/Date Filename/Size  
 
#1 greg.ercolano
23:16 Jan 26, 2014
test-tabs.cxx
1k
 
 
#2 greg.ercolano
12:56 Jan 28, 2014
test-tabs_v2.cxx
6k
 
 
#3 greg.ercolano
13:08 Jan 28, 2014
Fl_Tabs-with-button-behavior--r10087.patch
6k
 
 
#4 greg.ercolano
13:15 Jan 28, 2014
test-tabs_v3.cxx
6k
 
     

Trouble Report Comments:


Name/Time/Date Text  
 
#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 ]

 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.