Skip to content

Commit 386e235

Browse files
authored
Merge pull request #30 from tekktrik/feature/add-typing
Add type hints, documentation fixes
2 parents cb0d0f9 + 214cbc6 commit 386e235

File tree

2 files changed

+75
-50
lines changed

2 files changed

+75
-50
lines changed

adafruit_cursorcontrol/cursorcontrol.py

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
"""
2323
import displayio
2424

25+
try:
26+
from typing import Optional, Type
27+
from types import TracebackType
28+
except ImportError:
29+
pass
30+
2531
__version__ = "0.0.0-auto.0"
2632
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_CursorControl.git"
2733

@@ -31,9 +37,10 @@ class Cursor:
3137
3238
:param ~displayio.Display display: CircuitPython display object.
3339
:param ~displayio.Group display_group: CircuitPython group object to append the cursor to.
40+
:param ~displayio.Bitmap bmp: CircuitPython bitmap object to use as the cursor
41+
:param bool is_hidden: Cursor is hidden on init.
3442
:param int cursor_speed: Speed of the cursor, in pixels.
3543
:param int scale: Scale amount for the cursor in both directions.
36-
:param bool is_hidden: Cursor is hidden on init.
3744
3845
Example for creating a cursor layer
3946
@@ -53,12 +60,12 @@ class Cursor:
5360
# pylint: disable=too-many-arguments,line-too-long
5461
def __init__(
5562
self,
56-
display=None,
57-
display_group=None,
58-
bmp=None,
59-
is_hidden=False,
60-
cursor_speed=5,
61-
scale=1,
63+
display: Optional[displayio.Display] = None,
64+
display_group: Optional[displayio.Group] = None,
65+
bmp: Optional[displayio.Bitmap] = None,
66+
is_hidden: bool = False,
67+
cursor_speed: int = 5,
68+
scale: int = 1,
6269
):
6370
self._display = display
6471
self._scale = scale
@@ -75,19 +82,24 @@ def __init__(
7582

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

78-
def __enter__(self):
85+
def __enter__(self) -> "Cursor":
7986
return self
8087

81-
def __exit__(self, exception_type, exception_value, traceback):
88+
def __exit__(
89+
self,
90+
exception_type: Optional[Type[type]],
91+
exception_value: Optional[BaseException],
92+
traceback: Optional[TracebackType],
93+
) -> None:
8294
self.deinit()
8395

84-
def deinit(self):
96+
def deinit(self) -> None:
8597
"""deinitializes the cursor object."""
8698
self._is_deinited()
8799
self._scale = None
88100
self._display_grp.remove(self._cursor_grp)
89101

90-
def _is_deinited(self):
102+
def _is_deinited(self) -> None:
91103
"""checks cursor deinitialization"""
92104
if self._scale is None:
93105
raise ValueError(
@@ -96,12 +108,12 @@ def _is_deinited(self):
96108
)
97109

98110
@property
99-
def scale(self):
111+
def scale(self) -> int:
100112
"""Returns the cursor's scale amount as an integer."""
101113
return self._scale
102114

103115
@scale.setter
104-
def scale(self, scale_value):
116+
def scale(self, scale_value: int) -> None:
105117
"""Scales the cursor by scale_value in both directions.
106118
:param int scale_value: Amount to scale the cursor by.
107119
"""
@@ -111,12 +123,12 @@ def scale(self, scale_value):
111123
self._cursor_grp.scale = scale_value
112124

113125
@property
114-
def speed(self):
126+
def speed(self) -> int:
115127
"""Returns the cursor's speed, in pixels."""
116128
return self._speed
117129

118130
@speed.setter
119-
def speed(self, speed):
131+
def speed(self, speed: int) -> None:
120132
"""Sets the speed of the cursor.
121133
:param int speed: Cursor movement speed, in pixels.
122134
"""
@@ -125,12 +137,12 @@ def speed(self, speed):
125137
self._speed = speed
126138

127139
@property
128-
def x(self):
140+
def x(self) -> int:
129141
"""Returns the cursor's x-coordinate."""
130142
return self._cursor_grp.x
131143

132144
@x.setter
133-
def x(self, x_val):
145+
def x(self, x_val: int) -> None:
134146
"""Sets the x-value of the cursor.
135147
:param int x_val: cursor x-position, in pixels.
136148
"""
@@ -143,12 +155,12 @@ def x(self, x_val):
143155
self._cursor_grp.x = x_val
144156

145157
@property
146-
def y(self):
158+
def y(self) -> int:
147159
"""Returns the cursor's y-coordinate."""
148160
return self._cursor_grp.y
149161

150162
@y.setter
151-
def y(self, y_val):
163+
def y(self, y_val: int) -> None:
152164
"""Sets the y-value of the cursor.
153165
:param int y_val: cursor y-position, in pixels.
154166
"""
@@ -161,12 +173,12 @@ def y(self, y_val):
161173
self._cursor_grp.y = y_val
162174

163175
@property
164-
def hidden(self):
176+
def hidden(self) -> bool:
165177
"""Returns True if the cursor is hidden or visible on the display."""
166178
return self._is_hidden
167179

168180
@hidden.setter
169-
def hidden(self, is_hidden):
181+
def hidden(self, is_hidden: bool) -> None:
170182
self._is_deinited()
171183
if is_hidden:
172184
self._is_hidden = True
@@ -175,16 +187,16 @@ def hidden(self, is_hidden):
175187
self._is_hidden = False
176188
self._display_grp.append(self._cursor_grp)
177189

178-
def hide(self):
190+
def hide(self) -> None:
179191
"""Hide the cursor."""
180192
self.hidden = True
181193

182-
def show(self):
194+
def show(self) -> None:
183195
"""Show the cursor."""
184196
self.hidden = False
185197

186198
# pylint:disable=no-self-use
187-
def _default_cursor_bitmap(self):
199+
def _default_cursor_bitmap(self) -> displayio.Bitmap:
188200
bmp = displayio.Bitmap(20, 20, 3)
189201
# left edge, outline
190202
for i in range(0, bmp.height):
@@ -209,23 +221,26 @@ def _default_cursor_bitmap(self):
209221
# pylint:enable=no-self-use
210222

211223
@property
212-
def cursor_bitmap(self):
224+
def cursor_bitmap(self) -> displayio.Bitmap:
213225
"""Return the cursor bitmap."""
214226
return self._cursor_bitmap
215227

216228
@cursor_bitmap.setter
217-
def cursor_bitmap(self, bmp):
229+
def cursor_bitmap(self, bmp: displayio.Bitmap) -> None:
218230
"""Set a new cursor bitmap.
219231
220-
:param bmp: A Bitmap to use for the cursor
232+
:param ~displayio.Bitmap bmp: A Bitmap to use for the cursor
221233
"""
222234
self._cursor_bitmap = bmp
223235
self._cursor_grp.remove(self._cur_sprite)
224236
self._cur_sprite = displayio.TileGrid(bmp, pixel_shader=self._cur_palette)
225237
self._cursor_grp.append(self._cur_sprite)
226238

227-
def generate_cursor(self, bmp):
228-
"""Generates a cursor icon"""
239+
def generate_cursor(self, bmp: displayio.Bitmap) -> None:
240+
"""Generates a cursor icon
241+
242+
:param ~displayio.Bitmap bmp: A Bitmap to use for the cursor
243+
"""
229244
self._is_deinited()
230245
self._cursor_grp = displayio.Group(scale=self._scale)
231246
self._cur_palette = displayio.Palette(3)

adafruit_cursorcontrol/cursorcontrol_cursormanager.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
from keypad import ShiftRegisterKeys, Event
1515
from adafruit_debouncer import Debouncer
1616

17+
try:
18+
from typing import Optional, Type
19+
from types import TracebackType
20+
from adafruit_cursorcontrol.cursorcontrol import Cursor
21+
except ImportError:
22+
pass
23+
1724
__version__ = "0.0.0-auto.0"
1825
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_CursorControl.git"
1926

@@ -30,39 +37,44 @@
3037
class CursorManager:
3138
"""Simple interaction user interface interaction for Adafruit_CursorControl.
3239
33-
:param adafruit_cursorcontrol cursor: The cursor object we are using.
40+
:param Cursor cursor: The cursor object we are using.
3441
"""
3542

36-
def __init__(self, cursor):
43+
def __init__(self, cursor: Cursor) -> None:
3744
self._cursor = cursor
3845
self._is_clicked = False
3946
self._pad_states = 0
4047
self._event = Event()
4148
self._init_hardware()
4249

43-
def __enter__(self):
50+
def __enter__(self) -> "CursorManager":
4451
return self
4552

46-
def __exit__(self, exception_type, exception_value, traceback):
53+
def __exit__(
54+
self,
55+
exception_type: Optional[Type[type]],
56+
exception_value: Optional[BaseException],
57+
traceback: Optional[TracebackType],
58+
) -> None:
4759
self.deinit()
4860

49-
def deinit(self):
61+
def deinit(self) -> None:
5062
"""Deinitializes a CursorManager object."""
5163
self._is_deinited()
5264
self._pad.deinit()
5365
self._cursor.deinit()
5466
self._cursor = None
5567
self._event = None
5668

57-
def _is_deinited(self):
69+
def _is_deinited(self) -> None:
5870
"""Checks if CursorManager object has been deinitd."""
5971
if self._cursor is None:
6072
raise ValueError(
6173
"CursorManager object has been deinitialized and can no longer "
6274
"be used. Create a new CursorManager object."
6375
)
6476

65-
def _init_hardware(self):
77+
def _init_hardware(self) -> None:
6678
"""Initializes PyBadge or PyGamer hardware."""
6779
if hasattr(board, "BUTTON_CLOCK") and not hasattr(board, "JOYSTICK_X"):
6880
self._pad_btns = {
@@ -93,13 +105,13 @@ def _init_hardware(self):
93105
)
94106

95107
@property
96-
def is_clicked(self):
108+
def is_clicked(self) -> bool:
97109
"""Returns True if the cursor button was pressed
98110
during previous call to update()
99111
"""
100112
return self._is_clicked
101113

102-
def update(self):
114+
def update(self) -> None:
103115
"""Updates the cursor object."""
104116
if self._pad.events.get_into(self._event):
105117
self._store_button_states()
@@ -109,7 +121,7 @@ def update(self):
109121
elif self._pad_states & (1 << self._pad_btns["btn_a"]):
110122
self._is_clicked = True
111123

112-
def _read_joystick_x(self, samples=3):
124+
def _read_joystick_x(self, samples: int = 3) -> float:
113125
"""Read the X analog joystick on the PyGamer.
114126
:param int samples: How many samples to read and average.
115127
"""
@@ -121,7 +133,7 @@ def _read_joystick_x(self, samples=3):
121133
reading /= samples
122134
return reading
123135

124-
def _read_joystick_y(self, samples=3):
136+
def _read_joystick_y(self, samples: int = 3) -> float:
125137
"""Read the Y analog joystick on the PyGamer.
126138
:param int samples: How many samples to read and average.
127139
"""
@@ -133,18 +145,16 @@ def _read_joystick_y(self, samples=3):
133145
reading /= samples
134146
return reading
135147

136-
def _store_button_states(self):
148+
def _store_button_states(self) -> None:
137149
"""Stores the state of the PyBadge's D-Pad or the PyGamer's Joystick
138150
into a byte
139-
140-
:param Event event: The latest button press transition event detected.
141151
"""
142152
bit_index = self._event.key_number
143153
current_state = (self._pad_states >> bit_index) & 1
144154
if current_state != self._event.pressed:
145155
self._pad_states = (1 << bit_index) ^ self._pad_states
146156

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

185-
def __init__(self, cursor, debounce_interval=0.01):
195+
def __init__(self, cursor: Cursor, debounce_interval: float = 0.01) -> None:
186196
CursorManager.__init__(self, cursor)
187197
self._debouncer = Debouncer(
188198
lambda: bool(self._pad_states & (1 << self._pad_btns["btn_a"])),
189199
interval=debounce_interval,
190200
)
191201

192202
@property
193-
def is_clicked(self):
203+
def is_clicked(self) -> bool:
194204
"""Returns True if the cursor button was pressed
195205
during previous call to update()
196206
"""
@@ -199,18 +209,18 @@ def is_clicked(self):
199209
pressed = is_clicked
200210

201211
@property
202-
def released(self):
212+
def released(self) -> bool:
203213
"""Returns True if the cursor button was released
204214
during previous call to update()
205215
"""
206216
return self._debouncer.fell
207217

208218
@property
209-
def held(self):
219+
def held(self) -> bool:
210220
"""Returns True if the cursor button is currently being held"""
211221
return self._debouncer.value
212222

213-
def update(self):
223+
def update(self) -> None:
214224
"""Updates the cursor object."""
215225
if self._pad.events.get_into(self._event):
216226
self._store_button_states()

0 commit comments

Comments
 (0)