How is scrolling traditionally done?

kungfoomasta

24-09-2007 05:56:53

So I have implemented scrolling, but there are some problems which will take some effort to fix. I tried browsing google some, but couldn't find much on how scrolling is implemented. I also tried looking at other GUI libraries, but I'm not sure where to look.

This is what I do currently. I have a ScrollPane widget that has event handlers that handle events fired by its parent. For example, the Panel Widget creates a ScrollPane. The scroll pane, on construction, creates 4 scroll bars, and sets up the event handlers. Note that the scroll bars, while created in the scroll pane constructor, are children of the ScrollPane's parent, in this case the Panel. When the parent creates children widgets, the ScrollPane gets notified. The ScrollPane adds the widget to a list of managed widgets, and also stores the original offset between the widget and its parent, the Panel. Whenever horizontal or vertical scrolling occurs, the ScrollPane's position changes. In addition, the Scroll Pane iterates through its managed widgets, and moves them vertically and horizontally, taking into account the original offset between widget and parent, and moves the widgets so that the offset is maintained, but according to the scroll pane's origin. I designed the ScrollPane object to not be too intrusive. Simply create it and it will hook into events and take care of everything behind the hood. It's a good idea, anyway..

Also at my disposal is the ability to perform clipping. I can set a Clipping rect for any quad, and the quad will only draw parts that are inside of this Rect. In this way, I can move widgets around, and they won't be drawn. For example, sliding buttons inside of a Window will scroll the buttons outside the window bounds, but the window is the clipping rect, so the buttons will not draw.

Current Problems:
- Removing managed widgets. I made a function that determines the ScrollPane's bounds, which should always oncompass all managed widgets. When a Widget is added to managed widgets, the pane could get larger. Likewise, when a widget is removed, it could get smaller. The problem is, it is difficult to derive the new scroll pane bounds, because the managed widgets are shifted around. For example, I create a Button at absolute x position -1. I create another button at absolute x position 2. I scroll down to the second button and click it, and it removes itself. The problem is, I have scrolled over to this button, which has moved the first button to -2. In general, the problem is that widget positions are not constant, and it's hard using them to derive scroll bounds, or where these widgets should be placed relative to scroll value, etc.

With some more work, I think I could solve this problem. Mouse events work normally. But I'm thinking to myself.. is there a better way to do this?

I would like to put into place some method that doesn't involve altering the widgets actual position. Since the Quad object is not part of the Widget class, I do have the ability to draw Quads in locations different from the actual widget location. Maybe this, combined with some form of translating mouse coordinates into "virtual" coordinates, would work? I haven't looked far enough into this to see if this is a good approach or not.

Any information, comments, or suggestions are welcome. If anybody has experience, or know where I can look, it would be most appreciated. Sorry for the long post. :P

Zini

24-09-2007 07:16:03

From what I see most of your problems are causes by the »scrollbar-auto-detection-feature«. I found it an interesting idea, when I sew it first. But it is not always useful (considering my problems with windows, which shouldn't have scrollbars at all and I could come up with more examples). And since it is causing problems in the implementation too, maybe you should drop this feature.

Here is, how RISC OS handles this scrolling:

We have the Visible Area and the Workspace. The Workspace is an rectangular area, whose size must be explicitly set (though by default it is usually the same as the Visible Area. All widgets that could be possibly visible for any scroll index must be within the Workspace.

Then we have the Visible Area. That is, what is shown in the window (see sketch). By changing the scroll index the Visible Area is moved across the Workspace. Note that the size of the Visible Area is not necessarily the same as the window area. The scrollbars (if any) are part of the window area, but not of the Visible Area.

Please note also, that there don't need to be any scrollbars to make use of this feature. You can set up an entire Workspace and then have the Visible Area scroll over it controlled by your program (good for a scrolling title screen and a lot of other things, because you can move around what is visible without the need to move every single widget).

kungfoomasta

24-09-2007 07:36:13

Thanks for posting that up. Its actually really close to my current implementation/design! :D

It looks to me like the Visible Area doesn't move around, but the workspace does, as this is how I do it. (When scrolling, the window doesn't change position, the workspace does behind it, revealing a different part of it)

In comparison, the ScrollPane is the Workspace, and the Clipping Rect is the Visible Area. However, my Workspace grows and shrinks, depending on widgets added, which makes things complicated. Also having nested Windows makes things difficult. (Think of a Sheet with a Window with a Panel..)

Thanks for sharing this info, it looks like I'm not too far off. *goes back to thinking*

kungfoomasta

24-09-2007 08:04:15

I just played around with a windows form application project, and I saw that adding widgets to the left or above a panel do not spawn scroll bars, however adding widgets to the right or below a panel do result in scroll bars. If I imitated this functionality, that would definately help me out.

What does this mean? In the QuickGUI Editor, when you make your layout, adding widgets to the left or above a Panel/Sheet/Window/List/etc will not be viewable, however any widget placed inside or to the right/below will be able to be viewed.

If you made a layout, and then you said to yourself "I want a widget X placed to the left of all these other child widgets." You'd have to group select all the widgets, move them to the right, and then add in widget X.

I am in favor of this, since it makes things somewhat easier. There are lots of other things I need to work on as well. Comments?


Zini

24-09-2007 09:25:56

Looking at Windoze stuff for ideas when developing GUIs is a really bad idea IMHO. Again, that is only the opinion of someone, who comes from a totally different background, but Windoze and most Windoze applications break pretty much every single rule about good GUI design, that I know of. Furthermore limiting Workspace auto-sizing to only two sides looks rather artificial to me.

However since I am not planning to use the QuickGUI editor at all and this limitation won't interfere with my current GUI, I am fine with it (even more, if it is speeding up the scrollbar fixing). I guess a game GUI can be a bit more limited in some areas than a regular GUI without causing any harm.

kungfoomasta

24-09-2007 17:16:56

Wow, you have a lot of feeling for that OS, lol.

I don't really like this limitation either. I've been drawing pictures and thinking about how I would surpass this limitation, and I think I've come up with a way to do it. So I will give it another shot tonight, I think it will work.

Also, I haven't really talked about the editor because it doesn't do anything at the moment. My plans regarding it have changed some, I plan to use QuickGUI to implement it. This way it will be cross platform. Not sure if that influenced your willingness to use it or not. Either way, it's a ways down the road.

Zini

24-09-2007 17:56:38

My issue with the editor is, that I don't need it, since pretty much every single part of my GUI is generated dynamically, i.e. window layouts are determined algorithmically at runtime depending on the »world data«.

kungfoomasta

25-09-2007 08:26:15

Unfortunately, my plan didn't pan out. It is really a pain to support adding widgets to the left and above the visual area, changing the origin of the Workspace. So I've decided to go ahead and not support this. It's working and committed to SVN. Also implemented is ScrollPane::scrollIntoView.

I hate scrolling. :?

Regardless, if you find bugs please let me know. I am seeing some issues with Lists and ScrollPane, because lists can be either autoSized or not. In the case of autoSizing the height I have to disable to ScrollPane functionality.

Zini

25-09-2007 10:12:36

I can confirm, that removing widgets now does remove the scrollbar as expected. But I am still seeing widgets below the window.

kungfoomasta

25-09-2007 17:13:26

That's odd. Can you show/send a screenshot? What are the types of widgets seen below the window? When added, the ScrollPane should detect it and set the clip plane to the window dimensions, so anything outside the window should be completely clipped. And just to make sure.. you're positive the widgets you see outside the window are children of the window, right?

Zini

25-09-2007 17:25:50

The widget that escapes from the window is a Label. Here is the screenshot:



Here is the piece of code, that is used to generate the label:


static const int Height = 20;

// make label
QuickGUI::Rect Rect (10, Height*(1+d_Lines.size()),
d_Text->getSize (QuickGUI::QGUI_GMM_PIXELS).width-20, Height);

QuickGUI::Label *Label = d_Text->createLabel (Rect, QuickGUI::QGUI_GMM_PIXELS,
QuickGUI::QGUI_GMM_PIXELS);

Label->setCaption (Message);
Label->setHorizontalAlignment (QuickGUI::QGUI_HA_LEFT);


And yes, I am absolutely sure, that the Label does belong to the console window (actually it belongs to the Panel d_Text, which belongs to the console window)..

kungfoomasta

25-09-2007 17:37:29

Thanks for showing me this. Are there any widgets in between the window and the label?

It looks to me like the label itself is properly clipped, but the text object is not being clipped. I will check the setCaption function, I think I need to set the clipping rect each time the caption is set.

Also, I see on the bottom the scrollbar is still there. It should not be there, correct? I haven't addressed this, I'm unsure how to implement the behavior. When the slider becomes larger than the area containing the slider, everything should be squished. At a certain point, the slider should disappear. But unless you have more widgets in that List, the scroll bar should not be showing up at all. Is that list using autoSizeHeight, or a pre determined height? I need to make some changes regarding List and its interaction with ScrollPane.

Zini

25-09-2007 17:45:20

No, there aren't any widgets between the window and the label.

Regarding the scrollbar, it indeed shouldn't be there. What you see in this window is just a collection of manually positioned labels. It is possible, that I have a minor formatting error there, which moves one of the labels partially outside the visible area. But even if that is the case, I would prefer having no scrollbar (that's way I asked for an option to disable scrollbars).

kungfoomasta

25-09-2007 17:58:40

So "Tri: 46708" Is a Label? It shouldn't be possible for a label to have a scrollbar! Is this label part of a panel?

Also, I forgot to mention, but I believe I committed the enum types supporting showing of no scroll bars. I can double check this tonight, it's really easy for me to add. :)

When you get a chance, can you answer the poll? I want to remove QGUI_GMM_RELATIVE, but I will be more reluctant to do so if current users will be effected by this. I consider it deprecated.

Zini

25-09-2007 18:02:47

Yes, "Tri: 46708" is a Label. But I think it is the window, which has a scrollbar, not the Label.

Haven't checked on additions in the current SVN version. Will do so, when I am getting back to work on the GUI part again (right now I am working on a different part of my project).

I voted already, but I will soon add a post to elaborate on my vote.

Zini

26-09-2007 07:10:16

Minor correction: "Tri: 46708" is not a Label, but a TextBox.