Redraw widgets on request. Add scrollbar demo.
# -*- coding: utf-8 -*-
from tuikit.layout import AnchorLayout, OffsetLayout
from tuikit.scrollbar import VScrollbar, HScrollbar
from tuikit.common import Borders
class OffsetView(AnchorLayout):
def __init__(self):
AnchorLayout.__init__(self)
self._default_size.update(20, 20)
self._inner = OffsetLayout()
AnchorLayout.add(self, self._inner, halign='fill', valign='fill', margin=Borders(r=1))
def add(self, widget, **kwargs):
self._inner.add(widget, **kwargs)
def on_draw(self, ev):
ev.driver.fill_clip()
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)