# -*- 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