Clean up hints - add methods update_hint, hint_value to Widget. Split ScrollView into OffsetView and Scrolling components. Reimplement ScrollWindow using Scrolling component.
--- a/tuikit/common.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/common.py Fri Feb 01 09:34:15 2013 +0100
@@ -25,6 +25,9 @@
def selected(self):
return self._selected
+ def get_value(self):
+ return self._selected
+
def __repr__(self):
return self.__class__.__name__ + '(%r)' % self._selected
--- a/tuikit/container.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/container.py Fri Feb 01 09:34:15 2013 +0100
@@ -40,12 +40,9 @@
self.children.append(widget)
widget.parent = self
widget.top = self.top
- widget.hints.update({k:v() for k,v in self._hint_class.items()})
+ widget.reset_hints()
for key in kwargs:
- try:
- widget.hints[key].update(kwargs[key])
- except AttributeError:
- widget.hints[key] = widget.hints[key].__class__(kwargs[key])
+ widget.update_hint(key, kwargs[key])
if self.focuschild is None and widget.can_focus():
widget.set_focus()
--- a/tuikit/layout.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/layout.py Fri Feb 01 09:34:15 2013 +0100
@@ -52,9 +52,9 @@
for child in self._get_children():
reqw = max(child.sizereq.w, child.sizemin.w)
reqh = max(child.sizereq.h, child.sizemin.h)
- ha = child.hints['halign'].selected
- va = child.hints['valign'].selected
- margin = child.hints['margin']
+ ha = child.hint_value('halign')
+ va = child.hint_value('valign')
+ margin = child.hint_value('margin')
if ha == 'left':
x = margin.l
w = reqw
@@ -94,10 +94,10 @@
"""
if not child in self.children:
raise ValueError('AnchorLayout.move(): Cannot move foreign child.')
- margin = child.hints['margin']
+ margin = child.hint_value('margin')
newx = None
if x is not None:
- ha = child.hints['halign'].selected
+ ha = child.hint_value('halign')
ofsx = x - child.x
if ha == 'left':
margin.l += ofsx
@@ -107,7 +107,7 @@
newx = self.width - margin.r - child.sizereq.w
newy = None
if y is not None:
- va = child.hints['valign'].selected
+ va = child.hint_value('valign')
ofsy = y - child.y
if va == 'top':
margin.t += ofsy
@@ -142,7 +142,7 @@
# reduce by space acquired by children
space_to_divide -= sum([child.sizereq[ax1] for child in children])
# number of children with expanded hint
- expanded_num = len([ch for ch in children if ch.hints['expand']])
+ expanded_num = len([ch for ch in children if ch.hint_value('expand')])
else:
# all children are implicitly expanded
expanded_num = len(children)
@@ -161,14 +161,14 @@
size[ax2] = space2
offset += self.spacing
- if child.hints['expand'] or self.homogeneous:
+ if child.hint_value('expand') or self.homogeneous:
maxsize = int(round(space_child + math.modf(offset)[0], 2))
offset += space_child
if not self.homogeneous:
maxsize += child.sizereq[ax1]
offset += child.sizereq[ax1]
- if child.hints['fill']:
+ if child.hint_value('fill'):
size[ax1] = maxsize
else:
pos[ax1] += int((maxsize - size[ax1])/2)
@@ -216,12 +216,12 @@
child._view_size.update(w=self.width, h=self.height)
def move_child(self, child, x, y):
- child.hints('position').update(x, y)
+ child.update_hint('position', x, y)
def _update_children_position(self):
ox, oy = self._offset
for child in self.children:
- x, y = child.hints['position']
+ x, y = child.hint_value('position')
child._pos.update(x=x+ox, y=y+oy)
--- a/tuikit/scrollbar.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/scrollbar.py Fri Feb 01 09:34:15 2013 +0100
@@ -38,6 +38,9 @@
@scroll_max.setter
def scroll_max(self, value):
self._scroll_max = value
+ if self._scroll_pos > value:
+ self._scroll_pos = value
+ self.emit('change')
self._update_thumb_pos()
@property
--- a/tuikit/scrollview.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/scrollview.py Fri Feb 01 09:34:15 2013 +0100
@@ -1,11 +1,96 @@
# -*- coding: utf-8 -*-
from tuikit.layout import AnchorLayout, OffsetLayout
-from tuikit.scrollbar import VScrollbar
+from tuikit.scrollbar import VScrollbar, HScrollbar
from tuikit.common import Borders
-class ScrollView(AnchorLayout):
+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)
+
+
+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:
+ child_width = child.x - self._inner.offset.x + child.sizereq.w
+ if child_width > max_width:
+ max_width = child_width
+ child_height = child.y - self._inner.offset.y + child.sizereq.h
+ if child_height > max_height:
+ max_height = child_height
+ max_width += 1
+ if max_width < self._inner.width:
+ self.hscroll.hide()
+ else:
+ self.hscroll.scroll_max = max_width - self._inner.width
+ self.hscroll.show()
+ if max_height < self._inner.height:
+ self.vscroll.hide()
+ else:
+ self.vscroll.scroll_max = max_height - self._inner.height
+ self.vscroll.show()
+
+
+class ScrollView(OffsetView, Scrolling):
"""Scrolling view
Shows scrollbars when needed.
@@ -14,47 +99,10 @@
"""
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))
-
- self.vscroll = VScrollbar()
- self.vscroll.add_handler('change', self._on_vscroll_change)
- AnchorLayout.add(self, self.vscroll, halign='right', valign='fill')
+ OffsetView.__init__(self)
+ Scrolling.__init__(self)
def add(self, widget, **kwargs):
- self.inner.add(widget, **kwargs)
- widget.add_handler('sizereq', self._on_child_sizereq)
- widget.add_handler('spotmove', self._on_child_spotmove)
-
- def on_resize(self, ev):
- self._update_vscroll_max()
-
- def _on_vscroll_change(self, ev):
- self.inner.offset.y = - self.vscroll.scroll_pos
-
- def _on_child_sizereq(self, ev):
- self._update_vscroll_max()
+ OffsetView.add(self, widget, **kwargs)
+ self._connect_child(widget)
- def _on_child_spotmove(self, ev):
- child = ev.originator
- spot = child.y - self.inner.offset.y + child.spot.y
- if spot < self.vscroll.scroll_pos:
- self.vscroll.scroll_pos = spot
- if spot > (self.height - 1) + self.vscroll.scroll_pos:
- self.vscroll.scroll_pos = spot - (self.height - 1)
-
- def _update_vscroll_max(self):
- max_height = 0
- for child in self.inner.children:
- child_height = child.y - self.inner.offset.y + child.sizereq.h
- if child_height > max_height:
- max_height = child_height
- if max_height < self.height:
- self.vscroll.hide()
- else:
- self.vscroll.scroll_max = max_height - self.height
- self.vscroll.show()
-
--- a/tuikit/scrollwindow.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/scrollwindow.py Fri Feb 01 09:34:15 2013 +0100
@@ -1,82 +1,17 @@
from tuikit.window import Window
-from tuikit.layout import OffsetLayout, AnchorLayout
-from tuikit.scrollbar import VScrollbar, HScrollbar
-from tuikit.common import Borders
+from tuikit.scrollview import Scrolling
+from tuikit.layout import OffsetLayout
-class ScrollWindow(Window):
+class ScrollWindow(Window, Scrolling):
def __init__(self):
Window.__init__(self, inner_layout=OffsetLayout)
+ Scrolling.__init__(self)
- self.vscroll = VScrollbar()
- self.vscroll.add_handler('change', self._on_vscroll_change)
- AnchorLayout.add(self, self.vscroll, halign='right', valign='fill', margin=Borders(t=1, b=1))
-
- self.hscroll = HScrollbar()
- self.hscroll.add_handler('change', self._on_hscroll_change)
- AnchorLayout.add(self, self.hscroll, halign='fill', valign='bottom', margin=Borders(l=1, r=2))
+ self.vscroll.update_hint('margin', t=1, b=1)
+ self.hscroll.update_hint('margin', l=1, r=2)
def add(self, widget, **kwargs):
Window.add(self, widget, **kwargs)
- 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_resize(self, ev):
- self._update_scroll_max()
-
- def _on_child_sizereq(self, ev):
- self._update_scroll_max()
-
- 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 _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)
+ self._connect_child(widget)
- 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 _update_scroll_max(self):
- max_width = 0
- max_height = 0
- for child in self._inner.children:
- child_width = child.x - self._inner.offset.x + child.sizereq.w
- if child_width > max_width:
- max_width = child_width
- child_height = child.y - self._inner.offset.y + child.sizereq.h
- if child_height > max_height:
- max_height = child_height
- max_width += 1
- if max_width < self._inner.width:
- self.hscroll.hide()
- else:
- self.hscroll.scroll_max = max_width - self._inner.width
- self.hscroll.show()
- if max_height < self._inner.height:
- self.vscroll.hide()
- else:
- self.vscroll.scroll_max = max_height - self._inner.height
- self.vscroll.show()
-
--- a/tuikit/widget.py Fri Feb 01 00:24:02 2013 +0100
+++ b/tuikit/widget.py Fri Feb 01 09:34:15 2013 +0100
@@ -51,7 +51,7 @@
self.allow_focus = False
#: Dictionary containing optional parameters for layout managers etc.
- self.hints = {}
+ self._hints = {}
#: Hidden widget does not affect layout.
self.hidden = False
@@ -167,6 +167,35 @@
"""Real setter for top. Allows override."""
self._top = value
+ def reset_hints(self):
+ """Reset all hints to their initial value.
+
+ This must be called at before any call to update_hint.
+
+ """
+ self._hints.update({k:v() for k,v in self.parent._hint_class.items()})
+
+ def update_hint(self, hint_name, *args, **kwargs):
+ """Set or update hint value.
+
+ Args after hint_name are forwarded to update() method or initializer
+ of hint's class.
+
+ """
+ if hint_name not in self._hints:
+ raise ValueError('Hint %r is not registered.' % hint_name)
+ try:
+ # try update
+ self._hints[hint_name].update(*args, **kwargs)
+ except AttributeError:
+ # if update does not exist, call initializer instead
+ self._hints[hint_name] = self._hints[hint_name].__class__(*args, **kwargs)
+
+ def hint_value(self, hint_name):
+ try:
+ return self._hints[hint_name].get_value()
+ except AttributeError:
+ return self._hints[hint_name]
### events