222 lines
7.3 KiB
Python
222 lines
7.3 KiB
Python
# The MIT License (MIT)
|
|
#
|
|
# Copyright (c) 2019 Brent Rubell for Adafruit Industries
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
"""
|
|
`adafruit_cursorcontrol`
|
|
================================================================================
|
|
|
|
Mouse cursor for interaction with CircuitPython UI elements.
|
|
|
|
|
|
* Author(s): Brent Rubell
|
|
|
|
Implementation Notes
|
|
--------------------
|
|
|
|
**Software and Dependencies:**
|
|
|
|
* Adafruit CircuitPython firmware for the supported boards:
|
|
https://github.com/adafruit/circuitpython/releases
|
|
|
|
"""
|
|
import displayio
|
|
|
|
__version__ = "0.0.0-auto.0"
|
|
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Cursor.git"
|
|
|
|
class Cursor(object):
|
|
"""Mouse cursor interaction for CircuitPython.
|
|
|
|
:param ~displayio.Display display: CircuitPython display object.
|
|
:param ~displayio.Group display_group: CircuitPython group object to append the cursor to.
|
|
:param int cursor_speed: Speed of the cursor, in pixels.
|
|
:param int scale: Scale amount for the cursor in both directions.
|
|
:param bool is_hidden: Cursor is hidden on init.
|
|
|
|
Example for creating a cursor layer
|
|
|
|
.. code-block:: python
|
|
|
|
from adafruit_cursorcontrol import Cursor
|
|
# Create the display
|
|
display = board.DISPLAY
|
|
|
|
# Create the display context
|
|
splash = displayio.Group(max_size=22)
|
|
|
|
# initialize the mouse cursor object
|
|
mouse_cursor = Cursor(display, display_group=splash)
|
|
"""
|
|
# pylint: disable=too-many-arguments,line-too-long
|
|
def __init__(self, display=None, display_group=None, bmp=None, is_hidden=False, cursor_speed=5, scale=1):
|
|
self._display = display
|
|
self._scale = scale
|
|
self._speed = cursor_speed
|
|
self._is_hidden = is_hidden
|
|
self._display_grp = display_group
|
|
self._disp_sz = display.height - 1, display.width - 1
|
|
if bmp is None:
|
|
bmp = self._default_cursor_bitmap()
|
|
self.generate_cursor(bmp)
|
|
# pylint: enable=too-many-arguments,line-too-long
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exception_type, exception_value, traceback):
|
|
self.deinit()
|
|
|
|
def deinit(self):
|
|
"""deinitializes the cursor object."""
|
|
self._is_deinited()
|
|
self._scale = None
|
|
self._display_grp.remove(self._cursor_grp)
|
|
|
|
def _is_deinited(self):
|
|
"""checks cursor deinitialization"""
|
|
if self._scale is None:
|
|
raise ValueError("Cursor object has been deinitialized and can no longer "
|
|
"be used. Create a new cursor object.")
|
|
|
|
@property
|
|
def scale(self):
|
|
"""Returns the cursor's scale amount as an integer."""
|
|
return self._scale
|
|
|
|
@scale.setter
|
|
def scale(self, scale_value):
|
|
"""Scales the cursor by scale_value in both directions.
|
|
:param int scale_value: Amount to scale the cursor by.
|
|
"""
|
|
self._is_deinited()
|
|
if scale_value > 0:
|
|
self._scale = scale_value
|
|
self._cursor_grp.scale = scale_value
|
|
|
|
@property
|
|
def speed(self):
|
|
"""Returns the cursor's speed, in pixels."""
|
|
return self._speed
|
|
|
|
@speed.setter
|
|
def speed(self, speed):
|
|
"""Sets the speed of the cursor.
|
|
:param int speed: Cursor movement speed, in pixels.
|
|
"""
|
|
self._is_deinited()
|
|
if speed > 0:
|
|
self._speed = speed
|
|
|
|
@property
|
|
def x(self):
|
|
"""Returns the cursor's x-coordinate."""
|
|
return self._cursor_grp.x
|
|
|
|
@x.setter
|
|
def x(self, x_val):
|
|
"""Sets the x-value of the cursor.
|
|
:param int x_val: cursor x-position, in pixels.
|
|
"""
|
|
self._is_deinited()
|
|
if x_val < 0 and not self._is_hidden:
|
|
self._cursor_grp.x = self._cursor_grp.x
|
|
elif x_val > self._disp_sz[1] and not self._is_hidden:
|
|
self._cursor_grp.x = self._cursor_grp.x
|
|
elif not self._is_hidden:
|
|
self._cursor_grp.x = x_val
|
|
|
|
@property
|
|
def y(self):
|
|
"""Returns the cursor's y-coordinate."""
|
|
return self._cursor_grp.y
|
|
|
|
@y.setter
|
|
def y(self, y_val):
|
|
"""Sets the y-value of the cursor.
|
|
:param int y_val: cursor y-position, in pixels.
|
|
"""
|
|
self._is_deinited()
|
|
if y_val < 0 and not self._is_hidden:
|
|
self._cursor_grp.y = self._cursor_grp.y
|
|
elif y_val > self._disp_sz[0] and not self._is_hidden:
|
|
self._cursor_grp.y = self._cursor_grp.y
|
|
elif not self._is_hidden:
|
|
self._cursor_grp.y = y_val
|
|
|
|
@property
|
|
def hidden(self):
|
|
"""Returns True if the cursor is hidden or visible on the display."""
|
|
return self._is_hidden
|
|
|
|
@hidden.setter
|
|
def hidden(self, is_hidden):
|
|
self._is_deinited()
|
|
if is_hidden:
|
|
self._is_hidden = True
|
|
self._display_grp.remove(self._cursor_grp)
|
|
else:
|
|
self._is_hidden = False
|
|
self._display_grp.append(self._cursor_grp)
|
|
|
|
def hide(self):
|
|
"""Hide the cursor."""
|
|
self.hidden = True
|
|
|
|
def show(self):
|
|
"""Show the cursor."""
|
|
self.hidden = False
|
|
|
|
#pylint:disable=no-self-use
|
|
def _default_cursor_bitmap(self):
|
|
bmp = displayio.Bitmap(20, 20, 3)
|
|
# left edge, outline
|
|
for i in range(0, bmp.height):
|
|
bmp[0, i] = 2
|
|
# right diag outline, inside fill
|
|
for j in range(1, 15):
|
|
bmp[j, j] = 2
|
|
for i in range(j+1, bmp.height - j):
|
|
bmp[j, i] = 1
|
|
# bottom diag., outline
|
|
for i in range(1, 5):
|
|
bmp[i, bmp.height-i] = 2
|
|
# bottom flat line, right side fill
|
|
for i in range(5, 15):
|
|
bmp[i, 15] = 2
|
|
bmp[i-1, 14] = 1
|
|
bmp[i-2, 13] = 1
|
|
bmp[i-3, 12] = 1
|
|
bmp[i-4, 11] = 1
|
|
return bmp
|
|
#pylint:enable=no-self-use
|
|
|
|
def generate_cursor(self, bmp):
|
|
"""Generates a cursor icon"""
|
|
self._is_deinited()
|
|
self._cursor_grp = displayio.Group(max_size=1, scale=self._scale)
|
|
self._cur_palette = displayio.Palette(3)
|
|
self._cur_palette.make_transparent(0)
|
|
self._cur_palette[1] = 0xFFFFFF
|
|
self._cur_palette[2] = 0x0000
|
|
self._cur_sprite = displayio.TileGrid(bmp,
|
|
pixel_shader=self._cur_palette)
|
|
self._cursor_grp.append(self._cur_sprite)
|
|
self._display_grp.append(self._cursor_grp)
|