Skip to content

Commit 94511f1

Browse files
committed
Cleaned up code
1 parent 591a209 commit 94511f1

File tree

3 files changed

+145
-99
lines changed

3 files changed

+145
-99
lines changed

Magic_AI_Storybook/book.py

Lines changed: 103 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
15
import sys
26
import os
37
import time
48
from enum import Enum
59
import pygame
610

711
# Image Names
8-
WELCOME_IMAGE = 'welcome.png'
9-
BACKGROUND_IMAGE = 'paper_background.png'
10-
LOADING_IMAGE = 'loading.png'
11-
BUTTON_BACK_IMAGE = 'button_back.png'
12-
BUTTON_NEXT_IMAGE = 'button_next.png'
12+
WELCOME_IMAGE = "welcome.png"
13+
BACKGROUND_IMAGE = "paper_background.png"
14+
LOADING_IMAGE = "loading.png"
15+
BUTTON_BACK_IMAGE = "button_back.png"
16+
BUTTON_NEXT_IMAGE = "button_next.png"
1317

1418
# Asset Paths
15-
IMAGES_PATH = os.path.dirname(sys.argv[0]) + 'images/'
16-
FONTS_PATH = os.path.dirname(sys.argv[0]) + 'fonts/'
19+
IMAGES_PATH = os.path.dirname(sys.argv[0]) + "images/"
20+
FONTS_PATH = os.path.dirname(sys.argv[0]) + "fonts/"
1721

1822
# Font Path, Size
1923
TITLE_FONT = (FONTS_PATH + "lucida_black.ttf", 48)
@@ -29,22 +33,22 @@
2933
PARAGRAPH_DELAY = 2
3034

3135
# Letter by Letter
32-
#CHARACTER_DELAY = 0.1
33-
#WORD_DELAY = 0
34-
#SENTENCE_DELAY = 0
35-
#PARAGRAPH_DELAY = 0
36+
# CHARACTER_DELAY = 0.1
37+
# WORD_DELAY = 0
38+
# SENTENCE_DELAY = 0
39+
# PARAGRAPH_DELAY = 0
3640

3741
# Word by Word
38-
#CHARACTER_DELAY = 0
39-
#WORD_DELAY = 0.3
40-
#SENTENCE_DELAY = 0.5
41-
#PARAGRAPH_DELAY = 0
42+
# CHARACTER_DELAY = 0
43+
# WORD_DELAY = 0.3
44+
# SENTENCE_DELAY = 0.5
45+
# PARAGRAPH_DELAY = 0
4246

4347
# No Delays
44-
#CHARACTER_DELAY = 0
45-
#WORD_DELAY = 0
46-
#SENTENCE_DELAY = 0
47-
#PARAGRAPH_DELAY = 0
48+
# CHARACTER_DELAY = 0
49+
# WORD_DELAY = 0
50+
# SENTENCE_DELAY = 0
51+
# PARAGRAPH_DELAY = 0
4852

4953

5054
# Whitespace Settings in Pixels
@@ -55,13 +59,15 @@
5559
EXTRA_LINE_SPACING = 0
5660
PARAGRAPH_SPACING = 30
5761

62+
5863
class Position(Enum):
5964
TOP = 0
6065
CENTER = 1
6166
BOTTOM = 2
6267
LEFT = 3
6368
RIGHT = 4
6469

70+
6571
class Button:
6672
def __init__(self, x, y, image, action):
6773
self.x = x
@@ -72,7 +78,9 @@ def __init__(self, x, y, image, action):
7278
self._height = self.image.get_height()
7379

7480
def is_in_bounds(self, x, y):
75-
return self.x <= x <= self.x + self.width and self.y <= y <= self.y + self.height
81+
return (
82+
self.x <= x <= self.x + self.width and self.y <= y <= self.y + self.height
83+
)
7684

7785
def is_pressed(self):
7886
pass
@@ -85,6 +93,7 @@ def width(self):
8593
def height(self):
8694
return self._height
8795

96+
8897
class Textarea:
8998
def __init__(self, x, y, width, height):
9099
self.x = x
@@ -94,10 +103,8 @@ def __init__(self, x, y, width, height):
94103

95104
@property
96105
def size(self):
97-
return {
98-
"width": self.width,
99-
"height": self.height
100-
}
106+
return {"width": self.width, "height": self.height}
107+
101108

102109
class Book:
103110
def __init__(self, rotation=0):
@@ -113,14 +120,17 @@ def __init__(self, rotation=0):
113120
self.height = 0
114121
self.back_button = None
115122
self.next_button = None
123+
self.textarea = None
124+
self.screen = None
125+
self.cursor = None
116126

117127
def init(self):
118128
# Output to the LCD instead of the console
119-
os.putenv('DISPLAY', ':0')
129+
os.putenv("DISPLAY", ":0")
120130

121131
# Initialize the display
122132
pygame.init()
123-
self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
133+
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
124134
self.width = self.screen.get_height()
125135
self.height = self.screen.get_width()
126136

@@ -136,37 +146,40 @@ def init(self):
136146
# Add buttons
137147
back_button_image = pygame.image.load(IMAGES_PATH + BUTTON_BACK_IMAGE)
138148
next_button_image = pygame.image.load(IMAGES_PATH + BUTTON_NEXT_IMAGE)
139-
button_spacing = (self.width - (back_button_image.get_width() + next_button_image.get_width())) // 3
140-
button_ypos = self.height - PAGE_NAV_HEIGHT + (PAGE_NAV_HEIGHT - next_button_image.get_height()) // 2
149+
button_spacing = (
150+
self.width - (back_button_image.get_width() + next_button_image.get_width())
151+
) // 3
152+
button_ypos = (
153+
self.height
154+
- PAGE_NAV_HEIGHT
155+
+ (PAGE_NAV_HEIGHT - next_button_image.get_height()) // 2
156+
)
141157
self.back_button = Button(
142-
button_spacing,
143-
button_ypos,
144-
back_button_image,
145-
self.previous_page
158+
button_spacing, button_ypos, back_button_image, self.previous_page
146159
)
147160
self.next_button = Button(
148161
self.width - button_spacing - next_button_image.get_width(),
149162
button_ypos,
150163
next_button_image,
151-
self.next_page
164+
self.next_page,
152165
)
153166

154167
# Add Text Area
155168
self.textarea = Textarea(
156169
PAGE_SIDE_MARGIN,
157170
PAGE_TOP_MARGIN,
158171
self.width - PAGE_SIDE_MARGIN * 2,
159-
self.height - PAGE_NAV_HEIGHT - PAGE_TOP_MARGIN - PAGE_BOTTOM_MARGIN
172+
self.height - PAGE_NAV_HEIGHT - PAGE_TOP_MARGIN - PAGE_BOTTOM_MARGIN,
160173
)
161174

162175
pygame.mouse.set_visible(False)
163-
self.screen.fill((255,255,255))
176+
self.screen.fill((255, 255, 255))
164177

165178
def handle_events(self):
166179
for event in pygame.event.get():
167180
if event.type == pygame.QUIT:
168181
raise SystemExit
169-
elif event.type == pygame.MOUSEBUTTONDOWN:
182+
if event.type == pygame.MOUSEBUTTONDOWN:
170183
if event.button == 1:
171184
# If clicked in text area and book is still rendering, skip to the end
172185
print(f"Left mouse button pressed at {event.pos}")
@@ -177,35 +190,37 @@ def handle_events(self):
177190

178191
def add_page(self, paragraph=0, word=0):
179192
# Add rendered page information to make flipping between them easier
180-
self.pages.append({
181-
"paragraph": paragraph,
182-
"word": word,
183-
})
193+
self.pages.append(
194+
{
195+
"paragraph": paragraph,
196+
"word": word,
197+
}
198+
)
184199

185200
def load_image(self, name, filename):
186201
try:
187202
image = pygame.image.load(IMAGES_PATH + filename)
188203
self.images[name] = image
189204
except pygame.error:
190-
return None
205+
pass
191206

192207
def load_font(self, name, details):
193208
self.fonts[name] = pygame.font.Font(details[0], details[1])
194209

195-
def get_position(self, object, x, y):
210+
def get_position(self, obj, x, y):
196211
if x == Position.CENTER:
197-
x = (self.width - object.get_width()) // 2
212+
x = (self.width - obj.get_width()) // 2
198213
elif x == Position.RIGHT:
199-
x = self.width - object.get_width()
214+
x = self.width - obj.get_width()
200215
elif x == Position.LEFT:
201216
x = 0
202217
elif not isinstance(x, int):
203218
raise ValueError("Invalid x position")
204219

205220
if y == Position.CENTER:
206-
y = (self.height - object.get_height()) // 2
221+
y = (self.height - obj.get_height()) // 2
207222
elif y == Position.BOTTOM:
208-
y = self.height - object.get_height()
223+
y = self.height - obj.get_height()
209224
elif y == Position.TOP:
210225
y = 0
211226
elif not isinstance(y, int):
@@ -225,22 +240,21 @@ def display_image(self, image, x=Position.CENTER, y=Position.CENTER, surface=Non
225240
surface.blit(buffer, (0, 0))
226241

227242
def display_current_page(self):
228-
# This will be easier if we create a surface and just rotate that before rendering it to the screen
229-
230243
self.display_image(self.images["background"], Position.CENTER, Position.CENTER)
231244
pygame.display.update()
232245

233246
# Use a cursor to keep track of where we are on the page
234247
# These values are relative to the text area
235-
self.cursor = {
236-
"x": 0,
237-
"y": 0
238-
}
248+
self.cursor = {"x": 0, "y": 0}
239249

240250
# Display the title
241251
if self.page == 0:
242252
title = self.render_title()
243-
self.display_image(title, self.cursor["x"] + self.textarea.x, self.cursor["y"] + self.textarea.y)
253+
self.display_image(
254+
title,
255+
self.cursor["x"] + self.textarea.x,
256+
self.cursor["y"] + self.textarea.y,
257+
)
244258
pygame.display.update()
245259
self.cursor["y"] += title.get_height() + PARAGRAPH_SPACING
246260
time.sleep(PARAGRAPH_DELAY)
@@ -249,20 +263,23 @@ def display_current_page(self):
249263

250264
# Display the navigation buttons
251265
if self.page > 0:
252-
self.display_image(self.back_button.image, self.back_button.x, self.back_button.y)
266+
self.display_image(
267+
self.back_button.image, self.back_button.x, self.back_button.y
268+
)
253269

254270
# TODO: If we are on the last page, don't display the next button
255-
self.display_image(self.next_button.image, self.next_button.x, self.next_button.y)
271+
self.display_image(
272+
self.next_button.image, self.next_button.x, self.next_button.y
273+
)
256274
pygame.display.update()
257275

258276
def render_character(self, character):
259277
return self.fonts["text"].render(character, True, (0, 0, 0))
260278

261279
def display_page_text(self):
262-
# TODO: We need an accurate way to determine when a previous page has already been added so we don't add it again
280+
# TODO: We need an accurate way to determine when a
281+
# previous page has already been added so we don't add it again
263282

264-
# Display the paragraphs, one paragraph at a time, one word at a time until we reach the end of the line
265-
# then move to the next line. Once we are at the end of the page, stop displaying paragraphs
266283
paragraph_number = self.pages[self.page]["paragraph"]
267284
word_number = self.pages[self.page]["word"]
268285

@@ -272,19 +289,31 @@ def display_page_text(self):
272289
while word_number < len(paragraph):
273290
word = paragraph[word_number]
274291
# Check if there is enough space to display the word
275-
if self.cursor["x"] + self.fonts["text"].size(word)[0] > self.textarea.width:
292+
if (
293+
self.cursor["x"] + self.fonts["text"].size(word)[0]
294+
> self.textarea.width
295+
):
276296
# If not, move to the next line
277297
self.cursor["x"] = 0
278-
self.cursor["y"] += self.fonts["text"].get_height() + EXTRA_LINE_SPACING
298+
self.cursor["y"] += (
299+
self.fonts["text"].get_height() + EXTRA_LINE_SPACING
300+
)
279301
# If we have reached the end of the page, stop displaying paragraphs
280-
if self.cursor["y"] + self.fonts["text"].get_height() > self.textarea.height:
302+
if (
303+
self.cursor["y"] + self.fonts["text"].get_height()
304+
> self.textarea.height
305+
):
281306
self.add_page(paragraph_number, word_number)
282307
return
283308

284309
# Display the word one character at a time
285310
for character in word:
286311
character_surface = self.render_character(character)
287-
self.display_image(character_surface, self.cursor["x"] + self.textarea.x, self.cursor["y"] + self.textarea.y)
312+
self.display_image(
313+
character_surface,
314+
self.cursor["x"] + self.textarea.x,
315+
self.cursor["y"] + self.textarea.y,
316+
)
288317
pygame.display.update()
289318
self.cursor["x"] += character_surface.get_width() + 1
290319
if character != " ":
@@ -293,7 +322,8 @@ def display_page_text(self):
293322
# Advance the cursor by a spaces width
294323
self.cursor["x"] += self.render_character(" ").get_width() + 1
295324

296-
# Look at last character only to avoid long delays on stuff like "!!!" or "?!" or "..."
325+
# Look at last character only to avoid long delays on stuff
326+
# like "!!!" or "?!" or "..."
297327
if word[-1:] in [".", "!", "?"]:
298328
time.sleep(SENTENCE_DELAY)
299329
else:
@@ -308,16 +338,19 @@ def display_page_text(self):
308338
paragraph_number += 1
309339

310340
# If we have reached the end of the page, stop displaying paragraphs
311-
if self.cursor["y"] + self.fonts["text"].get_height() > self.textarea.height:
341+
if (
342+
self.cursor["y"] + self.fonts["text"].get_height()
343+
> self.textarea.height
344+
):
312345
self.add_page(paragraph_number, word_number)
313346
return
314347

315348
def create_transparent_buffer(self, size):
316349
if isinstance(size, (tuple, list)):
317350
(width, height) = size
318351
elif isinstance(size, dict):
319-
width = size['width']
320-
height = size['height']
352+
width = size["width"]
353+
height = size["height"]
321354
buffer = pygame.Surface((width, height), pygame.SRCALPHA, 32)
322355
buffer = buffer.convert_alpha()
323356
return buffer
@@ -331,7 +364,9 @@ def render_title(self):
331364
text_height = 0
332365
for line in lines:
333366
text = self.fonts["title"].render(line, True, TITLE_COLOR)
334-
buffer.blit(text, (buffer.get_width() // 2 - text.get_width() // 2, text_height))
367+
buffer.blit(
368+
text, (buffer.get_width() // 2 - text.get_width() // 2, text_height)
369+
)
335370
text_height += text.get_height()
336371

337372
new_buffer = self.create_transparent_buffer((self.textarea.width, text_height))
@@ -378,4 +413,4 @@ def parse_story(self, story):
378413
self.add_page()
379414

380415
# save settings
381-
# load settings
416+
# load settings

Magic_AI_Storybook/listener.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
15
from datetime import datetime, timedelta
26
from queue import Queue
37

48
import speech_recognition as sr
59

10+
611
class Listener:
7-
def __init__(self,
8-
energy_threshold=1000,
9-
phrase_timeout=3.0,
10-
record_timeout=30
11-
):
12+
def __init__(self, energy_threshold=1000, phrase_timeout=3.0, record_timeout=30):
1213
self.listener_handle = None
1314
self.recognizer = sr.Recognizer()
1415
self.recognizer.energy_threshold = energy_threshold

0 commit comments

Comments
 (0)