pimoroni-pico/micropython/examples/badger2040/ebook.py

277 wiersze
8.0 KiB
Python

import badger2040
import machine
import time
import gc
# **** 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
open(text_file, "wb").write(witw.data())
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_SIZE = 0.5
TEXT_SPACING = int(34 * TEXT_SIZE)
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 current_page > 1:
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
next_page = True
prev_page = False
change_font_size = False
change_font = False
last_offset = 0
current_page = 0
# Create a new Badger and set it to update FAST
display = badger2040.Badger2040()
display.update_speed(badger2040.UPDATE_FAST)
# Set up the buttons
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
# Set up the activity LED
led = machine.Pin(badger2040.PIN_LED, machine.Pin.OUT)
offsets = []
# Button handling function
def button(pin):
global next_page, prev_page, change_font_size, change_font
if pin == button_down:
next_page = True
if pin == button_up:
prev_page = True
if pin == button_a:
change_font_size = True
if pin == button_b:
change_font = True
# Register the button handling function with the buttons
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
# ------------------------------
# Render page
# ------------------------------
def render_page():
row = 0
line = ""
pos = ebook.tell()
next_pos = pos
add_newline = False
display.font(FONTS[0])
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, 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, 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
# ------------------------------
# Open the book file
ebook = open(text_file, "r")
while True:
# Was the next page button pressed?
if next_page:
current_page += 1
# Is the next page one we've not displayed before?
if current_page > len(offsets):
offsets.append(ebook.tell()) # Add its start position to the offsets list
draw_frame()
render_page()
next_page = False # Clear the next page button flag
# Was the previous page button pressed?
if prev_page:
if current_page > 1:
current_page -= 1
ebook.seek(offsets[current_page - 1]) # Retrieve the start position of the last page
draw_frame()
render_page()
prev_page = False # Clear the prev page button flag
if change_font_size:
TEXT_SIZE += 0.1
if TEXT_SIZE > 0.8:
TEXT_SIZE = 0.5
TEXT_SPACING = int(34 * TEXT_SIZE)
offsets = [0]
ebook.seek(0)
current_page = 1
draw_frame()
render_page()
change_font_size = False
if change_font:
FONTS.append(FONTS.pop(0))
FONT_THICKNESSES.append(FONT_THICKNESSES.pop(0))
offsets = [0]
ebook.seek(0)
current_page = 1
draw_frame()
render_page()
change_font = False
time.sleep(0.1)