diff --git a/adafruit_cursorcontrol/cursorcontrol.py b/adafruit_cursorcontrol/cursorcontrol.py index 2e6e6a3..7eec0cf 100644 --- a/adafruit_cursorcontrol/cursorcontrol.py +++ b/adafruit_cursorcontrol/cursorcontrol.py @@ -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" @@ -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 @@ -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 @@ -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( @@ -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. """ @@ -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. """ @@ -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. """ @@ -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. """ @@ -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 @@ -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): @@ -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) diff --git a/adafruit_cursorcontrol/cursorcontrol_cursormanager.py b/adafruit_cursorcontrol/cursorcontrol_cursormanager.py index 3ebe4c6..7526ff3 100755 --- a/adafruit_cursorcontrol/cursorcontrol_cursormanager.py +++ b/adafruit_cursorcontrol/cursorcontrol_cursormanager.py @@ -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" @@ -30,23 +37,28 @@ 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() @@ -54,7 +66,7 @@ def deinit(self): 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( @@ -62,7 +74,7 @@ def _is_deinited(self): "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 = { @@ -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() @@ -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. """ @@ -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. """ @@ -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"]): @@ -179,10 +189,10 @@ 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"])), @@ -190,7 +200,7 @@ def __init__(self, cursor, debounce_interval=0.01): ) @property - def is_clicked(self): + def is_clicked(self) -> bool: """Returns True if the cursor button was pressed during previous call to update() """ @@ -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()