tuikit/scrollview.py
changeset 75 2430c643838a
parent 64 03f591f5fe5c
child 76 fa5301e58eca
equal deleted inserted replaced
74:23767a33a781 75:2430c643838a
     1 # -*- coding: utf-8 -*-
     1 # -*- coding: utf-8 -*-
     2 
     2 
     3 from tuikit.layout import AnchorLayout, OffsetLayout
     3 from tuikit.layout import AnchorLayout, OffsetLayout
     4 from tuikit.scrollbar import VScrollbar
     4 from tuikit.scrollbar import VScrollbar, HScrollbar
     5 from tuikit.common import Borders
     5 from tuikit.common import Borders
     6 
     6 
     7 
     7 
     8 class ScrollView(AnchorLayout):
     8 class OffsetView(AnchorLayout):
       
     9     def __init__(self):
       
    10         AnchorLayout.__init__(self)
       
    11         self._default_size.update(20, 20)
       
    12         self._inner = OffsetLayout()
       
    13         AnchorLayout.add(self, self._inner, halign='fill', valign='fill', margin=Borders(r=1))
       
    14 
       
    15     def add(self, widget, **kwargs):
       
    16         self._inner.add(widget, **kwargs)
       
    17 
       
    18 
       
    19 class Scrolling:
       
    20     def __init__(self):
       
    21         self.vscroll = VScrollbar()
       
    22         self.vscroll.add_handler('change', self._on_vscroll_change)
       
    23         AnchorLayout.add(self, self.vscroll, halign='right', valign='fill')
       
    24 
       
    25         self.hscroll = HScrollbar()
       
    26         self.hscroll.add_handler('change', self._on_hscroll_change)
       
    27         AnchorLayout.add(self, self.hscroll, halign='fill', valign='bottom')
       
    28 
       
    29     def on_resize(self, ev):
       
    30         self._update_scroll_max()
       
    31 
       
    32     def _connect_child(self, widget):
       
    33         widget.add_handler('sizereq', self._on_child_sizereq)
       
    34         widget.add_handler('spotmove', self._on_child_spotmove)
       
    35         widget.add_handler('scrollreq', self._on_child_scrollreq)
       
    36 
       
    37     def _on_child_sizereq(self, ev):
       
    38         self._update_scroll_max()
       
    39 
       
    40     def _on_child_spotmove(self, ev):
       
    41         child = ev.originator
       
    42         # x
       
    43         spot_x = child.x - self._inner.offset.x + child.spot.x
       
    44         if spot_x < self.hscroll.scroll_pos:
       
    45             self.hscroll.scroll_pos = spot_x
       
    46         if spot_x > (self._inner.width - 1) + self.hscroll.scroll_pos:
       
    47             self.hscroll.scroll_pos = spot_x - (self._inner.width - 1)
       
    48         # y
       
    49         spot_y = child.y - self._inner.offset.y + child.spot.y
       
    50         if spot_y < self.vscroll.scroll_pos:
       
    51             self.vscroll.scroll_pos = spot_y
       
    52         if spot_y > (self._inner.height - 1) + self.vscroll.scroll_pos:
       
    53             self.vscroll.scroll_pos = spot_y - (self._inner.height - 1)
       
    54 
       
    55     def _on_child_scrollreq(self, ev):
       
    56         new_scroll_pos = self.vscroll.scroll_pos + ev.data
       
    57         if new_scroll_pos > self.vscroll.scroll_max:
       
    58             self.vscroll.scroll_pos = self.vscroll.scroll_max
       
    59         elif new_scroll_pos < 0:
       
    60             self.vscroll.scroll_pos = 0
       
    61         else:
       
    62             self.vscroll.scroll_pos = new_scroll_pos
       
    63 
       
    64     def _on_vscroll_change(self, ev):
       
    65         self._inner.offset.y = - self.vscroll.scroll_pos
       
    66 
       
    67     def _on_hscroll_change(self, ev):
       
    68         self._inner.offset.x = - self.hscroll.scroll_pos
       
    69 
       
    70     def _update_scroll_max(self):
       
    71         max_width = 0
       
    72         max_height = 0
       
    73         for child in self._inner.children:
       
    74             child_width = child.x - self._inner.offset.x + child.sizereq.w
       
    75             if child_width > max_width:
       
    76                 max_width = child_width
       
    77             child_height = child.y - self._inner.offset.y + child.sizereq.h
       
    78             if child_height > max_height:
       
    79                 max_height = child_height
       
    80         max_width += 1
       
    81         if max_width < self._inner.width:
       
    82             self.hscroll.hide()
       
    83         else:
       
    84             self.hscroll.scroll_max = max_width - self._inner.width
       
    85             self.hscroll.show()
       
    86         if max_height < self._inner.height:
       
    87             self.vscroll.hide()
       
    88         else:
       
    89             self.vscroll.scroll_max = max_height - self._inner.height
       
    90             self.vscroll.show()
       
    91 
       
    92 
       
    93 class ScrollView(OffsetView, Scrolling):
     9     """Scrolling view
    94     """Scrolling view
    10 
    95 
    11     Shows scrollbars when needed.
    96     Shows scrollbars when needed.
    12     Scrolling area is determined according to child widget's size request.
    97     Scrolling area is determined according to child widget's size request.
    13 
    98 
    14     """
    99     """
    15 
   100 
    16     def __init__(self):
   101     def __init__(self):
    17         AnchorLayout.__init__(self)
   102         OffsetView.__init__(self)
    18         self._default_size.update(20, 20)
   103         Scrolling.__init__(self)
    19 
       
    20         self.inner = OffsetLayout()
       
    21         AnchorLayout.add(self, self.inner, halign='fill', valign='fill', margin=Borders(r=1))
       
    22 
       
    23         self.vscroll = VScrollbar()
       
    24         self.vscroll.add_handler('change', self._on_vscroll_change)
       
    25         AnchorLayout.add(self, self.vscroll, halign='right', valign='fill')
       
    26 
   104 
    27     def add(self, widget, **kwargs):
   105     def add(self, widget, **kwargs):
    28         self.inner.add(widget, **kwargs)
   106         OffsetView.add(self, widget, **kwargs)
    29         widget.add_handler('sizereq', self._on_child_sizereq)
   107         self._connect_child(widget)
    30         widget.add_handler('spotmove', self._on_child_spotmove)
       
    31 
   108 
    32     def on_resize(self, ev):
       
    33         self._update_vscroll_max()
       
    34 
       
    35     def _on_vscroll_change(self, ev):
       
    36         self.inner.offset.y = - self.vscroll.scroll_pos
       
    37 
       
    38     def _on_child_sizereq(self, ev):
       
    39         self._update_vscroll_max()
       
    40 
       
    41     def _on_child_spotmove(self, ev):
       
    42         child = ev.originator
       
    43         spot = child.y - self.inner.offset.y + child.spot.y
       
    44         if spot < self.vscroll.scroll_pos:
       
    45             self.vscroll.scroll_pos = spot
       
    46         if spot > (self.height - 1) + self.vscroll.scroll_pos:
       
    47             self.vscroll.scroll_pos = spot - (self.height - 1)
       
    48 
       
    49     def _update_vscroll_max(self):
       
    50         max_height = 0
       
    51         for child in self.inner.children:
       
    52             child_height = child.y - self.inner.offset.y + child.sizereq.h
       
    53             if child_height > max_height:
       
    54                 max_height = child_height
       
    55         if max_height < self.height:
       
    56             self.vscroll.hide()
       
    57         else:
       
    58             self.vscroll.scroll_max = max_height - self.height
       
    59             self.vscroll.show()
       
    60