Skip to content

Commit

Permalink
Merge pull request #30 from tekktrik/feature/add-typing
Browse files Browse the repository at this point in the history
Add type hints, documentation fixes
  • Loading branch information
FoamyGuy committed Dec 16, 2021
2 parents cb0d0f9 + 214cbc6 commit 386e235
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 50 deletions.
73 changes: 44 additions & 29 deletions adafruit_cursorcontrol/cursorcontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
"""
import displayio

try:
from typing import Optional, Type
from types import TracebackType
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_CursorControl.git"

Expand All @@ -31,9 +37,10 @@ class Cursor:
:param ~displayio.Display display: CircuitPython display object.
:param ~displayio.Group display_group: CircuitPython group object to append the cursor to.
:param ~displayio.Bitmap bmp: CircuitPython bitmap object to use as the cursor
:param bool is_hidden: Cursor is hidden on init.
: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
Expand All @@ -53,12 +60,12 @@ class Cursor:
# 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,
display: Optional[displayio.Display] = None,
display_group: Optional[displayio.Group] = None,
bmp: Optional[displayio.Bitmap] = None,
is_hidden: bool = False,
cursor_speed: int = 5,
scale: int = 1,
):
self._display = display
self._scale = scale
Expand All @@ -75,19 +82,24 @@ def __init__(

# pylint: enable=too-many-arguments,line-too-long

def __enter__(self):
def __enter__(self) -> "Cursor":
return self

def __exit__(self, exception_type, exception_value, traceback):
def __exit__(
self,
exception_type: Optional[Type[type]],
exception_value: Optional[BaseException],
traceback: Optional[TracebackType],
) -> None:
self.deinit()

def deinit(self):
def deinit(self) -> None:
"""deinitializes the cursor object."""
self._is_deinited()
self._scale = None
self._display_grp.remove(self._cursor_grp)

def _is_deinited(self):
def _is_deinited(self) -> None:
"""checks cursor deinitialization"""
if self._scale is None:
raise ValueError(
Expand All @@ -96,12 +108,12 @@ def _is_deinited(self):
)

@property
def scale(self):
def scale(self) -> int:
"""Returns the cursor's scale amount as an integer."""
return self._scale

@scale.setter
def scale(self, scale_value):
def scale(self, scale_value: int) -> None:
"""Scales the cursor by scale_value in both directions.
:param int scale_value: Amount to scale the cursor by.
"""
Expand All @@ -111,12 +123,12 @@ def scale(self, scale_value):
self._cursor_grp.scale = scale_value

@property
def speed(self):
def speed(self) -> int:
"""Returns the cursor's speed, in pixels."""
return self._speed

@speed.setter
def speed(self, speed):
def speed(self, speed: int) -> None:
"""Sets the speed of the cursor.
:param int speed: Cursor movement speed, in pixels.
"""
Expand All @@ -125,12 +137,12 @@ def speed(self, speed):
self._speed = speed

@property
def x(self):
def x(self) -> int:
"""Returns the cursor's x-coordinate."""
return self._cursor_grp.x

@x.setter
def x(self, x_val):
def x(self, x_val: int) -> None:
"""Sets the x-value of the cursor.
:param int x_val: cursor x-position, in pixels.
"""
Expand All @@ -143,12 +155,12 @@ def x(self, x_val):
self._cursor_grp.x = x_val

@property
def y(self):
def y(self) -> int:
"""Returns the cursor's y-coordinate."""
return self._cursor_grp.y

@y.setter
def y(self, y_val):
def y(self, y_val: int) -> None:
"""Sets the y-value of the cursor.
:param int y_val: cursor y-position, in pixels.
"""
Expand All @@ -161,12 +173,12 @@ def y(self, y_val):
self._cursor_grp.y = y_val

@property
def hidden(self):
def hidden(self) -> bool:
"""Returns True if the cursor is hidden or visible on the display."""
return self._is_hidden

@hidden.setter
def hidden(self, is_hidden):
def hidden(self, is_hidden: bool) -> None:
self._is_deinited()
if is_hidden:
self._is_hidden = True
Expand All @@ -175,16 +187,16 @@ def hidden(self, is_hidden):
self._is_hidden = False
self._display_grp.append(self._cursor_grp)

def hide(self):
def hide(self) -> None:
"""Hide the cursor."""
self.hidden = True

def show(self):
def show(self) -> None:
"""Show the cursor."""
self.hidden = False

# pylint:disable=no-self-use
def _default_cursor_bitmap(self):
def _default_cursor_bitmap(self) -> displayio.Bitmap:
bmp = displayio.Bitmap(20, 20, 3)
# left edge, outline
for i in range(0, bmp.height):
Expand All @@ -209,23 +221,26 @@ def _default_cursor_bitmap(self):
# pylint:enable=no-self-use

@property
def cursor_bitmap(self):
def cursor_bitmap(self) -> displayio.Bitmap:
"""Return the cursor bitmap."""
return self._cursor_bitmap

@cursor_bitmap.setter
def cursor_bitmap(self, bmp):
def cursor_bitmap(self, bmp: displayio.Bitmap) -> None:
"""Set a new cursor bitmap.
:param bmp: A Bitmap to use for the cursor
:param ~displayio.Bitmap bmp: A Bitmap to use for the cursor
"""
self._cursor_bitmap = bmp
self._cursor_grp.remove(self._cur_sprite)
self._cur_sprite = displayio.TileGrid(bmp, pixel_shader=self._cur_palette)
self._cursor_grp.append(self._cur_sprite)

def generate_cursor(self, bmp):
"""Generates a cursor icon"""
def generate_cursor(self, bmp: displayio.Bitmap) -> None:
"""Generates a cursor icon
:param ~displayio.Bitmap bmp: A Bitmap to use for the cursor
"""
self._is_deinited()
self._cursor_grp = displayio.Group(scale=self._scale)
self._cur_palette = displayio.Palette(3)
Expand Down
52 changes: 31 additions & 21 deletions adafruit_cursorcontrol/cursorcontrol_cursormanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
from keypad import ShiftRegisterKeys, Event
from adafruit_debouncer import Debouncer

try:
from typing import Optional, Type
from types import TracebackType
from adafruit_cursorcontrol.cursorcontrol import Cursor
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_CursorControl.git"

Expand All @@ -30,39 +37,44 @@
class CursorManager:
"""Simple interaction user interface interaction for Adafruit_CursorControl.
:param adafruit_cursorcontrol cursor: The cursor object we are using.
:param Cursor cursor: The cursor object we are using.
"""

def __init__(self, cursor):
def __init__(self, cursor: Cursor) -> None:
self._cursor = cursor
self._is_clicked = False
self._pad_states = 0
self._event = Event()
self._init_hardware()

def __enter__(self):
def __enter__(self) -> "CursorManager":
return self

def __exit__(self, exception_type, exception_value, traceback):
def __exit__(
self,
exception_type: Optional[Type[type]],
exception_value: Optional[BaseException],
traceback: Optional[TracebackType],
) -> None:
self.deinit()

def deinit(self):
def deinit(self) -> None:
"""Deinitializes a CursorManager object."""
self._is_deinited()
self._pad.deinit()
self._cursor.deinit()
self._cursor = None
self._event = None

def _is_deinited(self):
def _is_deinited(self) -> None:
"""Checks if CursorManager object has been deinitd."""
if self._cursor is None:
raise ValueError(
"CursorManager object has been deinitialized and can no longer "
"be used. Create a new CursorManager object."
)

def _init_hardware(self):
def _init_hardware(self) -> None:
"""Initializes PyBadge or PyGamer hardware."""
if hasattr(board, "BUTTON_CLOCK") and not hasattr(board, "JOYSTICK_X"):
self._pad_btns = {
Expand Down Expand Up @@ -93,13 +105,13 @@ def _init_hardware(self):
)

@property
def is_clicked(self):
def is_clicked(self) -> bool:
"""Returns True if the cursor button was pressed
during previous call to update()
"""
return self._is_clicked

def update(self):
def update(self) -> None:
"""Updates the cursor object."""
if self._pad.events.get_into(self._event):
self._store_button_states()
Expand All @@ -109,7 +121,7 @@ def update(self):
elif self._pad_states & (1 << self._pad_btns["btn_a"]):
self._is_clicked = True

def _read_joystick_x(self, samples=3):
def _read_joystick_x(self, samples: int = 3) -> float:
"""Read the X analog joystick on the PyGamer.
:param int samples: How many samples to read and average.
"""
Expand All @@ -121,7 +133,7 @@ def _read_joystick_x(self, samples=3):
reading /= samples
return reading

def _read_joystick_y(self, samples=3):
def _read_joystick_y(self, samples: int = 3) -> float:
"""Read the Y analog joystick on the PyGamer.
:param int samples: How many samples to read and average.
"""
Expand All @@ -133,18 +145,16 @@ def _read_joystick_y(self, samples=3):
reading /= samples
return reading

def _store_button_states(self):
def _store_button_states(self) -> None:
"""Stores the state of the PyBadge's D-Pad or the PyGamer's Joystick
into a byte
:param Event event: The latest button press transition event detected.
"""
bit_index = self._event.key_number
current_state = (self._pad_states >> bit_index) & 1
if current_state != self._event.pressed:
self._pad_states = (1 << bit_index) ^ self._pad_states

def _check_cursor_movement(self):
def _check_cursor_movement(self) -> None:
"""Checks the PyBadge D-Pad or the PyGamer's Joystick for movement."""
if hasattr(board, "BUTTON_CLOCK") and not hasattr(board, "JOYSTICK_X"):
if self._pad_states & (1 << self._pad_btns["btn_right"]):
Expand Down Expand Up @@ -179,18 +189,18 @@ class DebouncedCursorManager(CursorManager):
the button is just pressed, and just released, as well it's current state. "Just" in this
context means "since the previous call to update."
:param adafruit_cursorcontrol cursor: The cursor object we are using.
:param Cursor cursor: The cursor object we are using.
"""

def __init__(self, cursor, debounce_interval=0.01):
def __init__(self, cursor: Cursor, debounce_interval: float = 0.01) -> None:
CursorManager.__init__(self, cursor)
self._debouncer = Debouncer(
lambda: bool(self._pad_states & (1 << self._pad_btns["btn_a"])),
interval=debounce_interval,
)

@property
def is_clicked(self):
def is_clicked(self) -> bool:
"""Returns True if the cursor button was pressed
during previous call to update()
"""
Expand All @@ -199,18 +209,18 @@ def is_clicked(self):
pressed = is_clicked

@property
def released(self):
def released(self) -> bool:
"""Returns True if the cursor button was released
during previous call to update()
"""
return self._debouncer.fell

@property
def held(self):
def held(self) -> bool:
"""Returns True if the cursor button is currently being held"""
return self._debouncer.value

def update(self):
def update(self) -> None:
"""Updates the cursor object."""
if self._pad.events.get_into(self._event):
self._store_button_states()
Expand Down

0 comments on commit 386e235

Please sign in to comment.