tuikit/widgets/scrollbar.py
changeset 118 8c7970520632
parent 76 fa5301e58eca
child 119 dd91747504dd
equal deleted inserted replaced
117:8680c2333546 118:8c7970520632
       
     1 # -*- coding: utf-8 -*-
       
     2 
       
     3 from tuikit.core.widget import Widget
       
     4 from tuikit.core.signal import Signal
       
     5 
       
     6 
       
     7 class Scrollbar(Widget):
       
     8 
       
     9     """Abstract base class for scrollbars."""
       
    10 
       
    11     def __init__(self):
       
    12         Widget.__init__(self)
       
    13 
       
    14         # Scrolling range is 0 .. _scroll_max
       
    15         self._scroll_max = self._get_length() - 3
       
    16         # Current position of scrollbar in scrolling range.
       
    17         self._scroll_pos = 0
       
    18         # Current position of thumb on scrollbar - used for draw.
       
    19         self._thumb_pos = 0
       
    20         # Auxilliary variable, True when user holds mouse on thumb.
       
    21         self._dragging = False
       
    22         # Auxilliary variable, 'up' or 'down' depending on last move direction.
       
    23         self._move = None
       
    24 
       
    25         #: delay before continuous scrolling when user holds mouse on scrollbar arrow
       
    26         self.scroll_delay = 0.150
       
    27         #: interval for continuous scrolling
       
    28         self.scroll_interval = 0.030
       
    29 
       
    30         # change event is emitted when user moves scrollbar (even programmatically)
       
    31         self.sig_changed = Signal()
       
    32 
       
    33     @property
       
    34     def scroll_max(self):
       
    35         """Maximum for scrolling position."""
       
    36         return self._scroll_max
       
    37 
       
    38     @scroll_max.setter
       
    39     def scroll_max(self, value):
       
    40         if value < 0:
       
    41             value = 0
       
    42         self._scroll_max = value
       
    43         if self._scroll_pos > value:
       
    44             self._scroll_pos = value
       
    45             self.sig_changed()
       
    46         self._update_thumb_pos()
       
    47 
       
    48     @property
       
    49     def scroll_pos(self):
       
    50         """Scrolling position.
       
    51 
       
    52         Integer number between 0 and 'max'.
       
    53 
       
    54         """
       
    55         return self._scroll_pos
       
    56 
       
    57     @scroll_pos.setter
       
    58     def scroll_pos(self, value):
       
    59         if self._scroll_pos != value:
       
    60             self._scroll_pos = value
       
    61             self._update_thumb_pos()
       
    62             self.sig_changed()
       
    63 
       
    64     def move_up(self):
       
    65         """Move scrolling position up/left."""
       
    66         if self._scroll_pos > 0:
       
    67             self.scroll_pos = self._scroll_pos - 1
       
    68         self._move = 'up'
       
    69 
       
    70     def move_down(self):
       
    71         """Move scrolling position down/right."""
       
    72         if self._scroll_pos < self._scroll_max:
       
    73             self.scroll_pos = self._scroll_pos + 1
       
    74         self._move = 'down'
       
    75 
       
    76     def drag(self, mouse_pos):
       
    77         """Scroll using mouse drag on thumb.
       
    78 
       
    79         Args:
       
    80             mouse_pos: new position of mouse, in range 0 .. self._get_length()
       
    81 
       
    82         """
       
    83         new_pos = int(round((mouse_pos - 1) / (self._get_length() - 3) * self._scroll_max))
       
    84         if new_pos < 0:
       
    85             new_pos = 0
       
    86         if new_pos > self._scroll_max:
       
    87             new_pos = self._scroll_max
       
    88         if self._scroll_pos != new_pos:
       
    89             self.scroll_pos = new_pos
       
    90 
       
    91     def _get_length(self):
       
    92         """Return length of scrollbar.
       
    93 
       
    94         This will be widget height for vertical scrollbar,
       
    95         width for horizontal scrollbar.
       
    96 
       
    97         """
       
    98         raise NotImplementedError()
       
    99 
       
   100     def _update_thumb_pos(self):
       
   101         """Update value of internal variable _thumb_pos."""
       
   102         self._thumb_pos = 0
       
   103         if self._scroll_max and self._scroll_pos <= self._scroll_max:
       
   104             self._thumb_pos = int(round(self._scroll_pos / self._scroll_max * (self._get_length() - 3)))
       
   105         #self.redraw()
       
   106 
       
   107     def _continuous_scroll(self):
       
   108         if self._move == 'up':
       
   109             self.move_up()
       
   110         if self._move == 'down':
       
   111             self.move_down()
       
   112         self.add_timeout(self.scroll_interval, self._continuous_scroll)
       
   113 
       
   114 
       
   115 class VScrollbar(Scrollbar):
       
   116     def __init__(self):
       
   117         Scrollbar.__init__(self)
       
   118         self.sizereq.update(1, 20)
       
   119 
       
   120     def draw(self, buffer):
       
   121         Widget.draw(self, buffer)
       
   122         ug = ev.driver.unigraph
       
   123         ev.driver.pushcolor('normal')
       
   124         ev.driver.putch(ev.x, ev.y, ug.get_char('sb_up'))
       
   125         for i in range(1, self.height - 1):
       
   126             ev.driver.putch(ev.x, ev.y + i, ug.get_char('sb_vtrack'))
       
   127         ev.driver.putch(ev.x, ev.y + 1 + self._thumb_pos, ug.get_char('sb_thumb'))
       
   128         ev.driver.putch(ev.x, ev.y + self.height - 1, ug.get_char('sb_down'))
       
   129         ev.driver.popcolor()
       
   130 
       
   131     def on_mousedown(self, ev):
       
   132         self._dragging = False
       
   133         self._move = None
       
   134         # arrow buttons
       
   135         if ev.wy == 0 or ev.wy == self.height - 1:
       
   136             if ev.wy == 0:
       
   137                 self.move_up()
       
   138             else:
       
   139                 self.move_down()
       
   140             self.add_timeout(self.scroll_delay, self._continuous_scroll)
       
   141             return
       
   142         # thumb bar
       
   143         if ev.wy == 1 + self._thumb_pos:
       
   144             self._dragging = True
       
   145             return
       
   146 
       
   147     def on_mousemove(self, ev):
       
   148         if self._dragging:
       
   149             self.drag(ev.wy)
       
   150 
       
   151     def on_mouseup(self, ev):
       
   152         if self._dragging:
       
   153             self.drag(ev.wy)
       
   154             self._dragging = False
       
   155             return
       
   156         if self._move:
       
   157             self.remove_timeout(self._continuous_scroll)
       
   158             self._move = None
       
   159             return
       
   160 
       
   161     def _get_length(self):
       
   162         return self.height
       
   163 
       
   164 
       
   165 class HScrollbar(Scrollbar):
       
   166     def __init__(self):
       
   167         Scrollbar.__init__(self)
       
   168         self.sizereq.update(20, 1)
       
   169 
       
   170     def on_draw(self, ev):
       
   171         ug = ev.driver.unigraph
       
   172         ev.driver.pushcolor('normal')
       
   173         ev.driver.putch(ev.x, ev.y, ug.get_char('sb_left'))
       
   174         for i in range(1, self.width - 1):
       
   175             ev.driver.putch(ev.x + i, ev.y, ug.get_char('sb_htrack'))
       
   176         ev.driver.putch(ev.x + 1 + self._thumb_pos, ev.y, ug.get_char('sb_thumb'))
       
   177         ev.driver.putch(ev.x + self.width - 1, ev.y, ug.get_char('sb_right'))
       
   178         ev.driver.popcolor()
       
   179 
       
   180     def on_mousedown(self, ev):
       
   181         self._dragging = False
       
   182         self._move = None
       
   183         # arrow buttons
       
   184         if ev.wx == 0 or ev.wx == self.width - 1:
       
   185             if ev.wx == 0:
       
   186                 self.move_up()
       
   187             else:
       
   188                 self.move_down()
       
   189             self.add_timeout(self.scroll_delay, self._continuous_scroll)
       
   190             return
       
   191         # thumb bar
       
   192         if ev.wx == 1 + self._thumb_pos:
       
   193             self._dragging = True
       
   194             return
       
   195 
       
   196     def on_mousemove(self, ev):
       
   197         if self._dragging:
       
   198             self.drag(ev.wx)
       
   199 
       
   200     def on_mouseup(self, ev):
       
   201         if self._dragging:
       
   202             self.drag(ev.wx)
       
   203             self._dragging = False
       
   204             return
       
   205         if self._move:
       
   206             self.remove_timeout(self._continuous_scroll)
       
   207             self._move = None
       
   208             return
       
   209 
       
   210     def _get_length(self):
       
   211         return self.width
       
   212