264 lines
7.8 KiB
Python
264 lines
7.8 KiB
Python
import badger2040
|
|
import time
|
|
import gc
|
|
import badger_os
|
|
|
|
# **** Put the name of your text file here *****
|
|
text_file = "book.txt" # File must be on the MicroPython device
|
|
|
|
|
|
try:
|
|
open(text_file, "r")
|
|
except OSError:
|
|
try:
|
|
# If the specified file doesn't exist,
|
|
# pre-populate with Wind In The Willows
|
|
import witw
|
|
with open(text_file, "wb") as f:
|
|
f.write(witw.data())
|
|
f.flush()
|
|
time.sleep(0.1)
|
|
del witw
|
|
except ImportError:
|
|
pass
|
|
|
|
|
|
gc.collect()
|
|
|
|
# Global Constants
|
|
WIDTH = badger2040.WIDTH
|
|
HEIGHT = badger2040.HEIGHT
|
|
|
|
ARROW_THICKNESS = 3
|
|
ARROW_WIDTH = 18
|
|
ARROW_HEIGHT = 14
|
|
ARROW_PADDING = 2
|
|
|
|
TEXT_PADDING = 4
|
|
TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH
|
|
|
|
FONTS = ["sans", "gothic", "cursive", "serif"]
|
|
FONT_THICKNESSES = [2, 1, 1, 2]
|
|
# ------------------------------
|
|
# Drawing functions
|
|
# ------------------------------
|
|
|
|
|
|
# Draw a upward arrow
|
|
def draw_up(x, y, width, height, thickness, padding):
|
|
border = (thickness // 4) + padding
|
|
display.line(x + border, y + height - border,
|
|
x + (width // 2), y + border)
|
|
display.line(x + (width // 2), y + border,
|
|
x + width - border, y + height - border)
|
|
|
|
|
|
# Draw a downward arrow
|
|
def draw_down(x, y, width, height, thickness, padding):
|
|
border = (thickness // 2) + padding
|
|
display.line(x + border, y + border,
|
|
x + (width // 2), y + height - border)
|
|
display.line(x + (width // 2), y + height - border,
|
|
x + width - border, y + border)
|
|
|
|
|
|
# Draw the frame of the reader
|
|
def draw_frame():
|
|
display.pen(15)
|
|
display.clear()
|
|
display.pen(12)
|
|
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
|
|
display.pen(0)
|
|
display.thickness(ARROW_THICKNESS)
|
|
if state["current_page"] > 0:
|
|
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
|
|
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
|
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
|
|
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
|
|
|
|
|
# ------------------------------
|
|
# Program setup
|
|
# ------------------------------
|
|
|
|
# Global variables
|
|
state = {
|
|
"last_offset": 0,
|
|
"current_page": 0,
|
|
"font_idx": 0,
|
|
"text_size": 0.5,
|
|
"offsets": []
|
|
}
|
|
badger_os.state_load("ebook", state)
|
|
|
|
text_spacing = int(34 * state["text_size"])
|
|
|
|
|
|
# Create a new Badger and set it to update FAST
|
|
display = badger2040.Badger2040()
|
|
display.led(128)
|
|
display.update_speed(badger2040.UPDATE_FAST)
|
|
|
|
|
|
# ------------------------------
|
|
# Render page
|
|
# ------------------------------
|
|
|
|
def render_page():
|
|
row = 0
|
|
line = ""
|
|
pos = ebook.tell()
|
|
next_pos = pos
|
|
add_newline = False
|
|
display.font(FONTS[state["font_idx"]])
|
|
|
|
while True:
|
|
# Read a full line and split it into words
|
|
words = ebook.readline().split(" ")
|
|
|
|
# Take the length of the first word and advance our position
|
|
next_word = words[0]
|
|
if len(words) > 1:
|
|
next_pos += len(next_word) + 1
|
|
else:
|
|
next_pos += len(next_word) # This is the last word on the line
|
|
|
|
# Advance our position further if the word contains special characters
|
|
if '\u201c' in next_word:
|
|
next_word = next_word.replace('\u201c', '\"')
|
|
next_pos += 2
|
|
if '\u201d' in next_word:
|
|
next_word = next_word.replace('\u201d', '\"')
|
|
next_pos += 2
|
|
if '\u2019' in next_word:
|
|
next_word = next_word.replace('\u2019', '\'')
|
|
next_pos += 2
|
|
|
|
# Rewind the file back from the line end to the start of the next word
|
|
ebook.seek(next_pos)
|
|
|
|
# Strip out any new line characters from the word
|
|
next_word = next_word.strip()
|
|
|
|
# If an empty word is encountered assume that means there was a blank line
|
|
if len(next_word) == 0:
|
|
add_newline = True
|
|
|
|
# Append the word to the current line and measure its length
|
|
appended_line = line
|
|
if len(line) > 0 and len(next_word) > 0:
|
|
appended_line += " "
|
|
appended_line += next_word
|
|
appended_length = display.measure_text(appended_line, state["text_size"])
|
|
|
|
# Would this appended line be longer than the text display area, or was a blank line spotted?
|
|
if appended_length >= TEXT_WIDTH or add_newline:
|
|
|
|
# Yes, so write out the line prior to the append
|
|
print(line)
|
|
display.pen(0)
|
|
display.thickness(FONT_THICKNESSES[0])
|
|
display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, state["text_size"])
|
|
|
|
# Clear the line and move on to the next row
|
|
line = ""
|
|
row += 1
|
|
|
|
# Have we reached the end of the page?
|
|
if (row * text_spacing) + text_spacing >= HEIGHT:
|
|
print("+++++")
|
|
display.update()
|
|
|
|
# Reset the position to the start of the word that made this line too long
|
|
ebook.seek(pos)
|
|
return
|
|
else:
|
|
# Set the line to the word and advance the current position
|
|
line = next_word
|
|
pos = next_pos
|
|
|
|
# A new line was spotted, so advance a row
|
|
if add_newline:
|
|
print("")
|
|
row += 1
|
|
if (row * text_spacing) + text_spacing >= HEIGHT:
|
|
print("+++++")
|
|
display.update()
|
|
return
|
|
add_newline = False
|
|
else:
|
|
# The appended line was not too long, so set it as the line and advance the current position
|
|
line = appended_line
|
|
pos = next_pos
|
|
|
|
|
|
# ------------------------------
|
|
# Main program loop
|
|
# ------------------------------
|
|
|
|
launch = True
|
|
changed = False
|
|
|
|
# Open the book file
|
|
ebook = open(text_file, "r")
|
|
if len(state["offsets"]) > state["current_page"]:
|
|
ebook.seek(state["offsets"][state["current_page"]])
|
|
else:
|
|
state["current_page"] = 0
|
|
state["offsets"] = []
|
|
|
|
while True:
|
|
# Was the next page button pressed?
|
|
if display.pressed(badger2040.BUTTON_DOWN):
|
|
state["current_page"] += 1
|
|
|
|
changed = True
|
|
|
|
# Was the previous page button pressed?
|
|
if display.pressed(badger2040.BUTTON_UP):
|
|
if state["current_page"] > 0:
|
|
state["current_page"] -= 1
|
|
if state["current_page"] == 0:
|
|
ebook.seek(0)
|
|
else:
|
|
ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page
|
|
changed = True
|
|
|
|
if display.pressed(badger2040.BUTTON_A):
|
|
state["text_size"] += 0.1
|
|
if state["text_size"] > 0.8:
|
|
state["text_size"] = 0.5
|
|
text_spacing = int(34 * state["text_size"])
|
|
state["offsets"] = []
|
|
ebook.seek(0)
|
|
state["current_page"] = 0
|
|
changed = True
|
|
|
|
if display.pressed(badger2040.BUTTON_B):
|
|
state["font_idx"] += 1
|
|
if (state["font_idx"] >= len(FONTS)):
|
|
state["font_idx"] = 0
|
|
state["offsets"] = []
|
|
ebook.seek(0)
|
|
state["current_page"] = 0
|
|
changed = True
|
|
|
|
if launch and not changed:
|
|
if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1:
|
|
ebook.seek(state["offsets"][state["current_page"] - 1])
|
|
changed = True
|
|
launch = False
|
|
|
|
if changed:
|
|
draw_frame()
|
|
render_page()
|
|
|
|
# Is the next page one we've not displayed before?
|
|
if state["current_page"] >= len(state["offsets"]):
|
|
state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list
|
|
badger_os.state_save("ebook", state)
|
|
|
|
changed = False
|
|
|
|
display.halt()
|