Add mouse events, event demo.
# -*- 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