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()