# HG changeset patch # User Radek Brich # Date 1359707655 -3600 # Node ID 2430c643838a16093fa25df134109af33c764bc8 # Parent 23767a33a781a422bb8071ad4d9a735aba0bcb03 Clean up hints - add methods update_hint, hint_value to Widget. Split ScrollView into OffsetView and Scrolling components. Reimplement ScrollWindow using Scrolling component. diff -r 23767a33a781 -r 2430c643838a tuikit/common.py --- 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 diff -r 23767a33a781 -r 2430c643838a tuikit/container.py --- 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() diff -r 23767a33a781 -r 2430c643838a tuikit/layout.py --- 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) diff -r 23767a33a781 -r 2430c643838a tuikit/scrollbar.py --- 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 diff -r 23767a33a781 -r 2430c643838a tuikit/scrollview.py --- 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() - diff -r 23767a33a781 -r 2430c643838a tuikit/scrollwindow.py --- 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() - diff -r 23767a33a781 -r 2430c643838a tuikit/widget.py --- 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