More Widgets

Development

Scrollbars

see #10 and #9

Features:

  • currently not selectable - keyboard scrolling should be done in scrolled widget
  • Up and down arrows for per line scrolling
  • scroll pagewise when clicking outside of the slider
  • drag slider

Problems/open questions:

  • How to set all the fancy characters/ Theming integration
  • Propagate changes from the scrolled widget to the scrollbar (works fine if scrolled widget is rendered first)

Suggestions:

  • Rename VScrollBar and HScrollBar classes to VSlider and HSlider. the fact that they scroll a window should not be known by this widget, it may be used to affect a numeric edit field, adjust a volume, or some other purpose.
  • Add callback functions similar to:
    • on_value_changed(self, change, newvalue)
  • Be able to cope with unknown minimum and maximum value. sometimes a ListBox will only know if it is at the start, end, or "somewhere in beween". It would still be useful to have a scroll bar that would allow moused-scrolling in this situation. Dragging the slider in this case would send on_page events, not on_slide events.
    Examples of HScrollBar/HSlider with unknown minimum/maximum:
    <|------------>   # at start, dragging "|" would move whole pages.
                      # this size of widget would allow one mouse drag to
                      # move 12 pages forward
                      # once released if not at maximum, would look like:
    
    <------|------>   # "somewhere in between" 
                      # "|" would return to middle after dragging.
                      # this size of widget would allow one mouse drag to
                      # move 6 pages forward or backward
    
    <------------|>   # at end.
    
  • may be this can be done with a simple tristate slider(0, 2, 1, 1). Altough dragging won't work that way...

ScrolledArea

Suggestions:

  • use the callback functions described above instead of special handling in mouse_event.
  • add always_show_hscroll (T/F) and always_show_vscroll (T/F) settings to force display of scroll bars that would otherwise be hidden
  • delegate the responsibility for displaying widget contents to a child widget.
    • vertically scrolling contents could be handled by the ListBox widget or the Filler widget, both of which already handle clipping top and/or bottom of widgets.
    • horizontal scrolling contents could be handled by the Padding widget which will clip its content on the left and/or right, and a future HListBox widget or similar.
    • child widget would use the .coords dict in the canvas it renders to communicate with the ScrolledArea widget. see "scrolled interface" below

How to Scroll

Problem: The scrolling widget does not know what it does scroll. Nevertheless someone have to take care that the focus and the cursor moves and stays visible

Scenario 1

  • cursor is visible
  • key down in pressed
  • key is propagated into the scrolled widget
  • cursor moves out of the visible area
  • render()
    • cursor is less than one screen away - scroll to cursor - everything is ok
  • cursor is too far away: wanted behaviour
    • move cursor back where it was
      • problem old position might no longer exist
    • scroll a bit into the right direction
    • if nether the old nor the new position are visible switch to navigation mode until on of the cursor positions is visible again

Scenario 2

  • cursor is visible
  • user scrolls down a page
  • cursor is no longer in visible area
  • render()
  • if there is a visible cursor position the cursor is moved there
  • else navigation mode get enabled until there is a cursor position visible

Scrolled Interface

Widgets that are displaying only a part of their complete contents should implement this interface to allow a parent widget such as ScrolledArea provide a way to scroll their contents with the mouse.

This interface uses the .coords dict and widget_info tuple described in CanvasClasses.

Eg. canv is the canvas returned by the render function of this widget, and this widget is only displaying some of the rows of its child widgets:

canv.coords['vscroll'] = (0, 0, # top-left coordinate of this widget
    (canv,        # a link back to this canvas including widget_info which
                  # includes the widget, and its rendered size
     row_offset,  # number of rows not shown at top
     total_rows)  # total number of rows for children

If the total_rows is unknown, then total_rows will be None and row_offset will be one of "start", "middle" or "end". (See examples of HSlider with unknown minimum/maximum above).

The widget in canv.widget_info is expected to have the following member functions:

  • vscroll_arrow(size, focus, num) # 1 = 1 line forward, -1 = 1 line backward
  • vscroll_page(size, focus, num) # 1 = 1 page forward, -1 = 1 page backward
  • vscroll_slide(size, focus, slider_offset, slider_size, slider_max)
    • must not be called if total_rows/total_cols are unknown.
  • scroll_vertical(rel, abs)
  • scroll_horizontal(rel, abs)
    • must fit the slider callback to they can be connected easily

The interface for horizontally scrolled widgets would be the same, replacing 'vscroll' with 'hscroll', 'row_offset' with 'col_offset' and 'total_rows' with 'total_cols'.

Scrolled Interface Example 1

We want to create a window that contains a view of a text file without wrapping lines. Our text file contains:

foo bar baz
aaaaaaaaaaddddsddddd
1234
gamma gamma hey
zip ditty do dah
ending

We extend Text so that it can behave as a fixed widget, not wrapping its content at all. We also implement the scrolled interface in Padding and Filler.

Our widget layout might look like:

+ ScrolledArea
  + VSlider
  + HSlider
  + Filler
    + Padding
      + Text("foo bar baz\naaa" ...)

Scrolled Interface Example 2

We want to have an edit field that clips its contents, but shows an arrow when the contents have extended beyond the visible area. Clicking the arrow should scroll the view.

+ ArrowScrolledArea
  + Padding
    + Edit

Stack

  • extends Overlay
  • more than one overlay widget
  • easily add and remove widgets
  • allow focus on non top widgets/background
  • made to be exteded to a window manager