96 lines
3.5 KiB
Python
96 lines
3.5 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""This module implements a scroll bar capability for widgets"""
|
||
|
from __future__ import division
|
||
|
from __future__ import absolute_import
|
||
|
from __future__ import print_function
|
||
|
from __future__ import unicode_literals
|
||
|
from builtins import range
|
||
|
from builtins import object
|
||
|
|
||
|
|
||
|
class _ScrollBar(object):
|
||
|
"""
|
||
|
Internal object to provide vertical scroll bars for widgets.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, canvas, palette, x, y, height, get_pos, set_pos, absolute=False):
|
||
|
"""
|
||
|
:param canvas: The canvas on which to draw the scroll bar.
|
||
|
:param palette: The palette of the parent Frame.
|
||
|
:param x: The x location of the top of the scroll bar.
|
||
|
:param y: The y location of the top of the scroll bar.
|
||
|
:param height: The height of the scroll bar.
|
||
|
:param get_pos: A function to return the current position of the scroll bar.
|
||
|
:param set_pos: A function to set the current position of the scroll bar.
|
||
|
:param absolute: Whether the scroll bar should use absolute co-ordinates when handling mouse
|
||
|
events.
|
||
|
|
||
|
The current position for the scroll bar is defined to be 0.0 at the top and 1.0 at the
|
||
|
bottom. The scroll bar will call `get_pos` to find the current position when drawing and
|
||
|
uses `set_pos` to update this position on a mouse click.
|
||
|
|
||
|
The widget using the scroll bar is responsible for maintaining its own state of where the
|
||
|
current view is scrolled (e.g. which is the top line in a text box) and for providing
|
||
|
these two functions to translate that internal state into a form the scroll bar can use.
|
||
|
"""
|
||
|
self._canvas = canvas
|
||
|
self.palette = palette
|
||
|
self.max_height = 0
|
||
|
self._x = x
|
||
|
self._y = y
|
||
|
self._height = height
|
||
|
self._absolute = absolute
|
||
|
self._get_pos = get_pos
|
||
|
self._set_pos = set_pos
|
||
|
|
||
|
def update(self):
|
||
|
"""
|
||
|
Draw the scroll bar.
|
||
|
"""
|
||
|
# Sort out chars
|
||
|
cursor = u"█" if self._canvas.unicode_aware else "O"
|
||
|
back = u"░" if self._canvas.unicode_aware else "|"
|
||
|
|
||
|
# Now draw...
|
||
|
try:
|
||
|
sb_pos = self._get_pos()
|
||
|
sb_pos = min(1, max(0, sb_pos))
|
||
|
sb_pos = max(int(self._height * sb_pos) - 1, 0)
|
||
|
except ZeroDivisionError:
|
||
|
sb_pos = 0
|
||
|
(colour, attr, bg) = self.palette["scroll"]
|
||
|
y = self._canvas.start_line if self._absolute else 0
|
||
|
for dy in range(self._height):
|
||
|
self._canvas.print_at(cursor if dy == sb_pos else back,
|
||
|
self._x, y + self._y + dy,
|
||
|
colour, attr, bg)
|
||
|
|
||
|
def is_mouse_over(self, event):
|
||
|
"""
|
||
|
Check whether a MouseEvent is over thus scroll bar.
|
||
|
|
||
|
:param event: The MouseEvent to check.
|
||
|
|
||
|
:returns: True if the mouse event is over the scroll bar.
|
||
|
"""
|
||
|
return event.x == self._x and self._y <= event.y < self._y + self._height
|
||
|
|
||
|
def process_event(self, event):
|
||
|
"""
|
||
|
Handle input on the scroll bar.
|
||
|
|
||
|
:param event: the event to be processed.
|
||
|
|
||
|
:returns: True if the scroll bar handled the event.
|
||
|
"""
|
||
|
# Convert into absolute coordinates if needed.
|
||
|
new_event = event
|
||
|
if self._absolute:
|
||
|
new_event.y -= self._canvas.start_line
|
||
|
|
||
|
# Process event if needed.
|
||
|
if self.is_mouse_over(new_event) and event.buttons != 0:
|
||
|
self._set_pos((new_event.y - self._y) / (self._height - 1))
|
||
|
return True
|
||
|
return False
|