tuikit/widgets/scrollview.py
author Radek Brich <radek.brich@devl.cz>
Mon, 16 Feb 2015 21:17:43 +0100
changeset 117 8680c2333546
parent 114 26c02bd94bd9
permissions -rw-r--r--
Update FixedLayout. Add demo launcher.

from tuikit.core.container import Container
from tuikit.layouts.offset import OffsetLayout

#from tuikit.layout import AnchorLayout, OffsetLayout
#from tuikit.scrollbar import VScrollbar, HScrollbar
#from tuikit.common import Borders


class Viewport(Container):

    """Viewport for partial view on widgets.

    Viewport is special type of Container, which shows partial view
    on its managed widgets. This view can be moved to show different part
    and thus allow "scrolling" over the content. Complete view with scrollbars
    is implemented in ScrollView.

    """

    def __init__(self):
        Container.__init__(self, OffsetLayout)



class Scrolling:
    def __init__(self):
        self.vscroll = VScrollbar()
        self.vscroll.add_handler('change', self._on_vscroll_change)
        AnchorLayout.add(self, self.vscroll, halign='right', valign='fill')

        self.hscroll = HScrollbar()
        self.hscroll.add_handler('change', self._on_hscroll_change)
        AnchorLayout.add(self, self.hscroll, halign='fill', valign='bottom')

    def on_resize(self, ev):
        self._update_scroll_max()

    def _connect_child(self, widget):
        widget.add_handler('sizereq', self._on_child_sizereq)
        widget.add_handler('spotmove', self._on_child_spotmove)
        widget.add_handler('scrollreq', self._on_child_scrollreq)

    def _on_child_sizereq(self, ev):
        self._update_scroll_max()

    def _on_child_spotmove(self, ev):
        child = ev.originator
        # x
        spot_x = child.x - self._inner.offset.x + child.spot.x
        if spot_x < self.hscroll.scroll_pos:
            self.hscroll.scroll_pos = spot_x
        if spot_x > (self._inner.width - 1) + self.hscroll.scroll_pos:
            self.hscroll.scroll_pos = spot_x - (self._inner.width - 1)
        # y
        spot_y = child.y - self._inner.offset.y + child.spot.y
        if spot_y < self.vscroll.scroll_pos:
            self.vscroll.scroll_pos = spot_y
        if spot_y > (self._inner.height - 1) + self.vscroll.scroll_pos:
            self.vscroll.scroll_pos = spot_y - (self._inner.height - 1)

    def _on_child_scrollreq(self, ev):
        new_scroll_pos = self.vscroll.scroll_pos + ev.data
        if new_scroll_pos > self.vscroll.scroll_max:
            self.vscroll.scroll_pos = self.vscroll.scroll_max
        elif new_scroll_pos < 0:
            self.vscroll.scroll_pos = 0
        else:
            self.vscroll.scroll_pos = new_scroll_pos

    def _on_vscroll_change(self, ev):
        self._inner.offset.y = - self.vscroll.scroll_pos

    def _on_hscroll_change(self, ev):
        self._inner.offset.x = - self.hscroll.scroll_pos

    def _update_scroll_max(self):
        max_width = 0
        max_height = 0
        for child in self._inner.children:
            posx, posy = child.hint_value('position')
            child_width = posx + child.sizereq.w
            if child_width > max_width:
                max_width = child_width
            child_height = posy + child.sizereq.h
            if child_height > max_height:
                max_height = child_height
        max_width += 1
        self.hscroll.scroll_max = max_width - self._inner.width
        self.vscroll.scroll_max = max_height - self._inner.height
        hscroll_hide = max_width < self._inner.width
        vscroll_hide = max_height < self._inner.height
        self._toggle_scrollers(hscroll_hide, vscroll_hide)

    def _toggle_scrollers(self, hscroll_hide, vscroll_hide):
        if hscroll_hide:
            self.hscroll.hide()
        else:
            self.hscroll.show()
        if vscroll_hide:
            self.vscroll.hide()
        else:
            self.vscroll.show()
        # self._inner.need_resize()


class ScrollView(OffsetView, Scrolling):
    """Scrolling view

    Shows scrollbars when needed.
    Scrolling area is determined according to child widget's size request.

    """

    def __init__(self):
        OffsetView.__init__(self)
        Scrolling.__init__(self)

    def add(self, widget, **kwargs):
        OffsetView.add(self, widget, **kwargs)
        self._connect_child(widget)

    def _toggle_scrollers(self, hscroll_hide, vscroll_hide):
        bpad = int(not hscroll_hide)
        self.vscroll.update_hint('margin', b=bpad)
        rpad = int(not vscroll_hide)
        self.hscroll.update_hint('margin', r=rpad)
        self._inner.update_hint('margin', b=bpad, r=rpad)
        Scrolling._toggle_scrollers(self, hscroll_hide, vscroll_hide)