--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tuikit/widgets/scrollbar.py Sat Feb 21 12:01:57 2015 +0100
@@ -0,0 +1,212 @@
+# -*- coding: utf-8 -*-
+
+from tuikit.core.widget import Widget
+from tuikit.core.signal import Signal
+
+
+class Scrollbar(Widget):
+
+ """Abstract base class for scrollbars."""
+
+ def __init__(self):
+ Widget.__init__(self)
+
+ # Scrolling range is 0 .. _scroll_max
+ self._scroll_max = self._get_length() - 3
+ # Current position of scrollbar in scrolling range.
+ self._scroll_pos = 0
+ # Current position of thumb on scrollbar - used for draw.
+ self._thumb_pos = 0
+ # Auxilliary variable, True when user holds mouse on thumb.
+ self._dragging = False
+ # Auxilliary variable, 'up' or 'down' depending on last move direction.
+ self._move = None
+
+ #: delay before continuous scrolling when user holds mouse on scrollbar arrow
+ self.scroll_delay = 0.150
+ #: interval for continuous scrolling
+ self.scroll_interval = 0.030
+
+ # change event is emitted when user moves scrollbar (even programmatically)
+ self.sig_changed = Signal()
+
+ @property
+ def scroll_max(self):
+ """Maximum for scrolling position."""
+ return self._scroll_max
+
+ @scroll_max.setter
+ def scroll_max(self, value):
+ if value < 0:
+ value = 0
+ self._scroll_max = value
+ if self._scroll_pos > value:
+ self._scroll_pos = value
+ self.sig_changed()
+ self._update_thumb_pos()
+
+ @property
+ def scroll_pos(self):
+ """Scrolling position.
+
+ Integer number between 0 and 'max'.
+
+ """
+ return self._scroll_pos
+
+ @scroll_pos.setter
+ def scroll_pos(self, value):
+ if self._scroll_pos != value:
+ self._scroll_pos = value
+ self._update_thumb_pos()
+ self.sig_changed()
+
+ def move_up(self):
+ """Move scrolling position up/left."""
+ if self._scroll_pos > 0:
+ self.scroll_pos = self._scroll_pos - 1
+ self._move = 'up'
+
+ def move_down(self):
+ """Move scrolling position down/right."""
+ if self._scroll_pos < self._scroll_max:
+ self.scroll_pos = self._scroll_pos + 1
+ self._move = 'down'
+
+ def drag(self, mouse_pos):
+ """Scroll using mouse drag on thumb.
+
+ Args:
+ mouse_pos: new position of mouse, in range 0 .. self._get_length()
+
+ """
+ new_pos = int(round((mouse_pos - 1) / (self._get_length() - 3) * self._scroll_max))
+ if new_pos < 0:
+ new_pos = 0
+ if new_pos > self._scroll_max:
+ new_pos = self._scroll_max
+ if self._scroll_pos != new_pos:
+ self.scroll_pos = new_pos
+
+ def _get_length(self):
+ """Return length of scrollbar.
+
+ This will be widget height for vertical scrollbar,
+ width for horizontal scrollbar.
+
+ """
+ raise NotImplementedError()
+
+ def _update_thumb_pos(self):
+ """Update value of internal variable _thumb_pos."""
+ self._thumb_pos = 0
+ if self._scroll_max and self._scroll_pos <= self._scroll_max:
+ self._thumb_pos = int(round(self._scroll_pos / self._scroll_max * (self._get_length() - 3)))
+ #self.redraw()
+
+ def _continuous_scroll(self):
+ if self._move == 'up':
+ self.move_up()
+ if self._move == 'down':
+ self.move_down()
+ self.add_timeout(self.scroll_interval, self._continuous_scroll)
+
+
+class VScrollbar(Scrollbar):
+ def __init__(self):
+ Scrollbar.__init__(self)
+ self.sizereq.update(1, 20)
+
+ def draw(self, buffer):
+ Widget.draw(self, buffer)
+ ug = ev.driver.unigraph
+ ev.driver.pushcolor('normal')
+ ev.driver.putch(ev.x, ev.y, ug.get_char('sb_up'))
+ for i in range(1, self.height - 1):
+ ev.driver.putch(ev.x, ev.y + i, ug.get_char('sb_vtrack'))
+ ev.driver.putch(ev.x, ev.y + 1 + self._thumb_pos, ug.get_char('sb_thumb'))
+ ev.driver.putch(ev.x, ev.y + self.height - 1, ug.get_char('sb_down'))
+ ev.driver.popcolor()
+
+ def on_mousedown(self, ev):
+ self._dragging = False
+ self._move = None
+ # arrow buttons
+ if ev.wy == 0 or ev.wy == self.height - 1:
+ if ev.wy == 0:
+ self.move_up()
+ else:
+ self.move_down()
+ self.add_timeout(self.scroll_delay, self._continuous_scroll)
+ return
+ # thumb bar
+ if ev.wy == 1 + self._thumb_pos:
+ self._dragging = True
+ return
+
+ def on_mousemove(self, ev):
+ if self._dragging:
+ self.drag(ev.wy)
+
+ def on_mouseup(self, ev):
+ if self._dragging:
+ self.drag(ev.wy)
+ self._dragging = False
+ return
+ if self._move:
+ self.remove_timeout(self._continuous_scroll)
+ self._move = None
+ return
+
+ def _get_length(self):
+ return self.height
+
+
+class HScrollbar(Scrollbar):
+ def __init__(self):
+ Scrollbar.__init__(self)
+ self.sizereq.update(20, 1)
+
+ def on_draw(self, ev):
+ ug = ev.driver.unigraph
+ ev.driver.pushcolor('normal')
+ ev.driver.putch(ev.x, ev.y, ug.get_char('sb_left'))
+ for i in range(1, self.width - 1):
+ ev.driver.putch(ev.x + i, ev.y, ug.get_char('sb_htrack'))
+ ev.driver.putch(ev.x + 1 + self._thumb_pos, ev.y, ug.get_char('sb_thumb'))
+ ev.driver.putch(ev.x + self.width - 1, ev.y, ug.get_char('sb_right'))
+ ev.driver.popcolor()
+
+ def on_mousedown(self, ev):
+ self._dragging = False
+ self._move = None
+ # arrow buttons
+ if ev.wx == 0 or ev.wx == self.width - 1:
+ if ev.wx == 0:
+ self.move_up()
+ else:
+ self.move_down()
+ self.add_timeout(self.scroll_delay, self._continuous_scroll)
+ return
+ # thumb bar
+ if ev.wx == 1 + self._thumb_pos:
+ self._dragging = True
+ return
+
+ def on_mousemove(self, ev):
+ if self._dragging:
+ self.drag(ev.wx)
+
+ def on_mouseup(self, ev):
+ if self._dragging:
+ self.drag(ev.wx)
+ self._dragging = False
+ return
+ if self._move:
+ self.remove_timeout(self._continuous_scroll)
+ self._move = None
+ return
+
+ def _get_length(self):
+ return self.width
+