STR #1895

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 ]

STR #1895

Application:FLTK Library
Status:1 - Closed w/Resolution
Priority:2 - Low, e.g. a documentation error or undocumented side-effect
Scope:3 - Applies to all machines and operating systems
Subsystem:Core Library
Summary:Fl_Scroll does its scrollbar management only in its draw()
Created By:alvin
Assigned To:greg.ercolano
Fix Version:1.3-current (SVN: v10220)
Update Notification:

Receive EMails Don't Receive EMails

Trouble Report Files:

Name/Time/Date Filename/Size top right image
#1 alvin
08:43 Mar 13, 2008
#2 alvin
08:43 Mar 13, 2008
#3 alvin
09:01 Mar 14, 2008
#4 alvin
09:01 Mar 14, 2008
#5 kdiman
03:54 Jun 15, 2014
#6 kdiman
07:53 Jun 29, 2014
#7 greg.ercolano
20:39 Jul 15, 2014
bottom left image   bottom right image

Trouble Report Comments:

Name/Time/Date Text top right image
#1 alvin
10:49 Mar 12, 2008
First off, I marked this STR as LOW only because I believe this is a undocumented side-effect.

Fl_Scroll only updates the state of its scrollbars in its draw() function. Though this seems to be fine for Fl_Scroll, it does cause some headaches when deriving a new widget based on Fl_Scroll.

For example, I was writing a scroll widget that centres its children within the viewable area. To do this, I override resize() and used Fl_Scroll::bbox() to obtain the new viewable area (after calling Fl_Scroll::resize()). I then use the viewable area to calculate where to reposition each child. This mostly worked but would often break.

The problem was that Fl_Scroll::bbox() uses the state of the scrollbars to calculate and return the viewable bounding box. However, Fl_Scroll only updates its scrollbars during a redraw(). Therefore, it is impossible for a derived class to know the true viewable area during a call to resize().

The workaround is instead, to override the draw() method and do the widget centring after calling the parent Fl_Scroll::draw(). I believe this to be counter-intuitive mostly because, AFAICT, this behaviour is not mentioned in the docs.

One possible solution is to refactor Fl_Scroll::draw() into a (1) drawing component and (2) scrollbar managing component. The scrollbar managing code could then be placed into its own protected function. This would allow derived classes the ability to force Fl_Scroll to manage its scrollbars when it desires. In my example, the widget centring logic could be placed in the overridden resize() method rather than having it executed each time the widget is redrawn.
#2 matt
12:26 Mar 12, 2008
Yes, your observations are absolutely right. Fl_Scroll is flawed in the way it handles scroll bars as the children of the widget, ropositioning them in the hierarchy, thereby creating sideeffects, including the mix and melt of scrollbar calculations and drawing routines.

But please bear in mind that thises are quite complex and internal conceptual issues that have been around since the beginning of FLTK. I find it much more useful to fix these issues when we advance to the next majo release cycle, because users will be much more aware of possible internal changes.

Up'd to 1.2 .
#3 alvin
12:33 Mar 12, 2008
I agree. However, would it be possible to add a function such as Fl_Scroll::init_scrollbars() that would do the samething that is in draw()? Basically, it would allow derived classes to force scrollbar managing to happen. And as a new function, would only effect code that calls it and be ignored by older applications? I'm not sure if this would break the ABI though?  
#4 matt
13:00 Mar 12, 2008
Which part of FL_Scroll::draw() exactly would you put in there?  
#5 AlbrechtS
14:58 Mar 12, 2008
If I may answer for Alvin: The part that does the calculation, whether scrollbars are needed or not, and that activates and deactivates the scrollbars.

In short: everything that would be needed to call bbox() and get a correct result depending on the new size of this Fl_Scroll widget in a derived Widget's resize() method (after calling Fl_Scroll::resize()).

Thus, Fl_Scroll::resize() should also call init_scrollbars to manage the appearance and maybe position of the scrollbars before (or after) calling Fl_Widget::resize().

Basically the part from " // accumulate bounding box of children:" over "// turn the scrollbars on and off as necessary:" ... until ... but not including "// draw the scrollbars:".

#6 alvin
05:12 Mar 13, 2008
I have some time this morning, so I can try to make a patch and a trivial test program. For the test program I was thinking of a derivied class from Fl_Scroll that always centred its children. I believe there are test programs already in test/ that could be used to test the standard behaviour of the patch.

Just a few questions:

1) Is 'diff -u' sufficient for creating the patch file?

2) Would it be better if I were to only implement Fl_Scroll::init_scrollbars() as an additional function OR integrate the use of init_scrollbars() throughout Fl_Scroll?

3) Is there a more appropriate name other than init_scrollbars() the would be better? I based the name off of Fl_Group::init_sizes().
#7 alvin
08:43 Mar 13, 2008
I have created Proof of Concept, non-invassive patch for Fl_Scroll. It only adds Fl_Scroll::init_scrollbars() and doesn't touch anything else. If Fl_Scroll::init_scrollbars() is never called, then Fl_Scroll will behave as it always has.

I have also created a test program that can be used to see the effects of the scrollbars with and without the patch applied.

The patch is very trivial. I simply copied the relevant portion that Albrecht identified from Fl_Scroll::draw() and pasted it into its own function, Fl_Scroll::init_scrollbars(). I did have to remove the calls to draw_clip() has they resulted in a segfault and the usage of 'd' was redundant in this context. I believe the segfault occurs because the block of code is not being called in the context of drawing.

If this patch is ok, I am willing to clean it up and fully integrate it into Fl_Scroll. By integrate, I mean that there are places that Fl_Scroll should call this such as:
1. Fl_Scroll::end() [doesn't exist] should call init_scrollbars() so that the scrollbars are adjusted after all the widgets are added.
2. Fl_Scroll::add() should call init_scrollbars() for the same reason.
3. Fl_Scroll::init_sizes() should call init_scrollbars() as well. If I understand what init_sizes() is suppose to do: When widgets are resized outside of the parent Fl_Group, init_sizes() should be called in order to let the parent Fl_Group (Fl_Scroll in this case) know about it? Therefore, calling init_scrollbars() would ensure that Fl_Scroll::bbox() would return the new bbox.

As an aside, fix_scrollbar_order() should be call by Fl_Scroll::end() and Fl_Scroll::add() as well. During my testing of init_scrollbars() there was one bug that the children bbox loop was wrong since after calling end() the scrollbars were actually the first children as opposed to being the last children.

There are two ways to compile the test app:

1) fltk-config --use-images --compile str1895_test.cxx

   This will compile the app without the calls to Fl_Scroll::init_scrollbars(). When you launch the app, you will see a gap between tux and the right hand side. This happens because when end() is called, the Fl::bbox() thinks that the scrollbars are still visible (i.e. Fl_Scroll::draw() hasn't been called yet).

   Then when you Increase and Decrease the size of Tux (The lower buttons), you will see the effects such as Tux being behind the vertical scrollbar and the gaps.

2) fltk-config -DHAVE_STR1895 --use-images --compile str1895_test.cxx

  This will compile the app with the calls to Fl_Scroll::init_scrollbars(). When you start the app, you will see Tux is flush against the right hand side. As you Increase and Decrease Tux, he should always be flush against the right side or flush against the vertical scrollbar when it appears.

Like I said, if this patch is a "good thing", then I am willing to take it to the next step if you like.

#8 alvin
09:01 Mar 14, 2008
I have prepared version 2 of the str1895 patch. This patch does the following to Fl_Scroll:

1) Overrides end(), add() and init_sizes() to call init_scrollbars(). This ensures that Fl_Scroll::bbox() will always return the correct position and dimensions.

2) Added the call to init_scrollbars() in Fl_Scroll::resize() after the base widget is resized.

3) Updated the .html documentation for Fl_Scroll. I added an entry for bbox() and init_sizes().

These allow for Fl_Scroll::bbox() to return the current viewable area which is mainly important for derived widgets. Having these overridden functions make it not necessary for derived widgets to have to call init_scrollbars() they can trust the return values of bbox().

The Fl_Scroll::draw() remains untouched. Ideally, Fl_Scroll::draw() should call init_scrollbars() so that the scrollbar logic is in one place instead of duplicated. But that optimisation would require more debugging an testing.

One question though, in Fl_Scroll::resize(), why is the Fl_Widget::resize() called instead of Fl_Group::resize()?
#9 AlbrechtS
09:55 Mar 14, 2008
Alvin wrote:
One question though, in Fl_Scroll::resize(), why is the Fl_Widget::resize() called instead of Fl_Group::resize()?

Probably to prevent the scrollbars from resizing.
#10 matt
13:10 Mar 14, 2008
I will be on a short vacation starting Monday. I will try to look at the patch before that and then decide if we do an RC3 with the patch or a final 1.1.8 without your patch. Thanks for looking into fixing all that.  
#11 alvin
05:37 Mar 15, 2008
I'm no longer fully confident that the patch does what I intended. I'm currently debugging it now.

AFAIK, no one has ever said anything before about this behaviour in Fl_Scroll before. If this is true, then if you want to push out 1.1.8 before I'm done debugging, than I have no problems with that.

Once I am confident that this patch is in fact a good thing, then I will post here. If it takes me too long, then perhaps this patch can be applied after 1.1.8?
#12 greg.ercolano
18:09 Apr 02, 2009
Revisiting this STR while implementing scrollbar_size() before 1.3.0.

If a public method for scrollbar recalculation would be desirable, I'll see if I can make that part of this change.
#13 AlbrechtS
09:14 Apr 03, 2009
Maybe not a public method, but protected? I looked at Alvin's patch files, and I think that his init_scrollbars() method in the first patch version (with fix_scrollbar_order) might be a good start.

If it simplifies adding scrollbar_size(), then I suggest to start with it. Separating drawing and scrollbar reordering could be a first step...

BTW.: Here we have a widget that exposes its scrollbars, and therefore it is possible that existing user code modifies the scrollbar widths by accessing the scrollbars directly. I'm not sure if this could have consequences for the scrollbar_size() method. What do you think about this?
#14 greg.ercolano
11:28 Apr 03, 2009
> BTW.: Here we have a widget that exposes its scrollbars,
> and therefore it is possible that existing user code modifies
> the scrollbar widths by accessing the scrollbars directly.
> I'm not sure if this could have consequences for the
> scrollbar_size() method. What do you think about this?

   Yes, it does seem like the scrollbar's size is being preserved,
   even though its recomputed during the draw().

   Would need some discussion -- I'll move that question over to so we can discuss it there, and follow up here with results.
#15 kdiman
03:54 Jun 15, 2014
Hi guys !

I did patch for correct resizing Fl_Scroll,
while the scrollbars are having value() > 0.

After applying the patch drawing children will be
correct, with scrolling them when the (h)scrollbar.value() > 0

 For reproduction the problem: run test/scroll programm,
 and drag handler of scrollbar to the end,
 then try enlarge the window  ...

Have a nice day.
#16 kdiman
07:56 Jun 29, 2014
I have attached new patch for scroll contents of the Fl_Scroll group (by resizing the group, - hidding a scrollbar ...).

FIXME Sorry but my solution is working for FL_ALIGN_RIGHT and FL_ALIGN_BOTTOM only!

Have a nice day.
#17 greg.ercolano
10:41 Jun 29, 2014
Perhaps in some way the issues raised by the "Summary"
and comments #3 thru #5 were addressed with svn r6828
which added the "private" method recalc_scrollbars().

Perhaps this can be changed to being 'protected'
to actually solve this STR. Need to check Alvin's patches
to make sure we're not missing anything he was working towards.

kdiman, looks like you've added some interesting patches for a
longstanding resize issue described in comment #15.
But I think that's a different enough issue from this STR
to warrant being a separate STR of its own.
If you agree, could you open a new STR with your patches?

It's good though that your additions here have brought new attention
to this STR, which probably can be solved with a few simple mods to
changes that have already been applied to SVN.
#18 alvin
07:51 Jun 30, 2014
I agree with Greg in that kdiman's patches should go in a new STR. Seems somewhat out of place for this STR.

I had forgotten all about this STR! I have a few patches that I apply to my build of FLTK and it appears this patch has been removed from that set.

Having reviewed my svn logs from 2008, looks like I worked around this issue by manually determining the viewable size in my derived class.

Having reviewed the Fl_Scroll source, I think, as Greg has said, if recalc_scrollbars() was protected, then it would be the "fix" and this STR can be closed.

Fl_Scroll::draw() calls recalc_scrollbars() which I think is much much better than before.
#19 greg.ercolano
08:02 Jul 15, 2014
Alvin, thanks for the follow up.

Changing private -> protected would I think break ABI,
(we've had a release since the recalc method was added)
so we'll have to protect this change with FLTK_ABI_VERSION.

Assigning this to me, and changing the software version back down
from 1.4 -> 1.3-current, since we can do this as an ABI feature now.
#20 greg.ercolano
20:39 Jul 15, 2014
Fixed in Subversion repository.

Added as an ABI feature; to use the new method in the 1.3.x series,
you'll need to set in FL/Enumerations.H:

    #define FLTK_ABI_VERSION 10303

..and rebuild FLTK. Then you can access recalc_scrollbars()

I'm attaching a simplified version of your str1895_test program
(see str1895_test_erco_v1.cxx) that demonstrates how to do what you wanted
using the new ScrollInfo structure and recalc_scrollbars() method.

Closing -- if it needs to be re-opened, put a message in fltk.coredev saying why, and I'll reopen.
bottom left image   bottom right image

Return to Bugs & Features ]


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