qtxie / notes

0 stars 0 forks source link

[Draft] ScrollViewer and Scroller #3

Open qtxie opened 4 years ago

qtxie commented 4 years ago

There are two elements that enable scrolling in Red/View: ScrollView and Scroller.

ScrollView

The ScrollView is a content container, it has a horizontal Scroller and a vertical Scroller. It implements the interaction details for a scrollable face. The user just need to populate it with sub faces. The scrollers will automatically show or hide according to the size of the bounding box of the sub faces in the ScrollView.

For example, builds a ListView by using ScrollView.

item!: make face! [type: 'base size: 200x50]
offset: 0x0
view [
    sv: scrollview 202x600
    button "Add Item" [
        item: copy item!
        item/offset: offset
        append sv/pane item
        offset/y: offset/y + item/size/y
    ]
]

Scroller

There are two types of scroller: Standalone Scroller and Embeded Scroller.

scroller!: object [ position: none ;-- knob position page-size: none ;-- page size min-size: 1 ;-- minimum value max-size: none ;-- maximum value visible?: yes vertical?: yes ;-- read only. YES: vertical NO: horizontal parent: none ]

* Embeded Scroller
The embeded scrollers use the same object definition as the standalone scroller, but them attach to the base face, the position of them are fixed. It's easier to use than the standalone scroller, you don't need to handle the size and position of the scroller when resizing the parent base face. 
Use the `scrollable` flag in the `flags` facet to enable it.

view [b: base 300x300 do [b/flags: [scrollable]]]

hiiamboris commented 4 years ago

I'll share some of my thoughts here.

The ScrollView is a content container, it has a horizontal Scroller and a vertical Scroller. It implements the interaction details for a scrollable face. The user just need to populate it with sub faces. The scrollers will automatically show or hide according to the size of the bounding box of the sub faces in the ScrollView.

I actually have an imitation of it here. Imitation has a problem though: it has to attach reactions to all child faces, watch if those faces go out of pane (maybe into another scrollpanel). I.e. a lot of useless bookkeeping.

I think we do not need a separate ScrollView style. Each panel should be scrollable like this if it has a 'scrollable flag.

I also think such panel should react to wheel and pan events, scrolling itself accordingly, without any effort from the user (unless such event is captured by inner faces). Pan event will provide the scroll amount. How much to scroll (vertically) using the mouse wheel - should be controlled by the OS setting.

I would also expect it to react to clicks on the wheel (mbutton3) - like most programs do today - providing an autoscroll feature, either automatically or controlled by some flag. It should be able to scroll in both vertical and horizontal direction this way (depending on visible scrollbars).

It should provide an on-scroll event that is triggered after it has moved it's viewport. It should also provide a way to do reverse task: programmatically set it's viewport to some location (e.g. to the offset of some face), automatically adjusting the scrollers (on show). These two things should not cause event cascades (like on-scroll modifies the scrollers -> this calls on-scroll again).

If there will be an easy way to do it, I'd like to be able to choose the side for vertical scrollbar: right (default) or left (for left-handed or right-to-left writing users). Since even Windows still doesn't have any builtin setting to control that, it's not ultra important.

Another problem of my imitation is that scroller faces have to be exposed in the pane, and in order to always stay above the child faces I have to watch the pane constantly and move scrollers to the tail of it if e.g. one adds some other faces to the pane.

Then there's a problem of 2 scrollers: what to with the point where they intersect? It looks awkward if panel content pops out behind the scrollers: And I can accidentally click something I don't want to! Native apps put either an opaque box of panel color there, or a corner that may do nothing or resize the window when you drag it:


TBD: should we use face! or a special scroller! object?

I think standalone scroller must be a face. For the embedded one, let's count:


scrollable should become a VID keyword, not require messing with flags. Also should be supported by rich-text and window and future table. If we can, we should allow manipulating area and text-list scrollers using the same embedded interface.

hiiamboris commented 4 years ago

One more thought. Though in most cases scrollers' offsets and sizes should be set automatically, there are still cases where they shouldn't be: In this table there are pinned columns and rows, and only the unpinned area is scrollable. I can also imagine rows pinned at the bottom (e.g. summary), so there must be some way to manually control the scrollers geometry. So to support this kind of control one would need to:

I am not sure that this extended model should be supported in a scrollview. It's more like a thing a base with embedded scrollbars should do. Just leaving it here for consideration.