book/reader.py

78 lines
2.5 KiB
Python

import curses
import os
import textwrap
def read_file(filename):
with open(filename, 'r', encoding='utf-8') as f:
return f.read()
def main(stdscr):
curses.curs_set(0) # Hide cursor
stdscr.keypad(1) # Enable special keys
stdscr.timeout(100) # Set timeout for getch
current_chapter = 0
offset = 0 # To keep track of scrolling
update_needed = True # Flag to check whether an update is needed
while True:
# Only clear and refresh the screen if an update is needed
if update_needed:
stdscr.clear()
# Read the file
if current_chapter == 0:
text = read_file('chapters/title.txt')
else:
text = read_file(f'chapters/chapter{current_chapter}.txt')
# Split text by lines, then wrap each line
max_y, max_x = stdscr.getmaxyx()
lines = text.split('\n')
wrapped_lines = [textwrap.fill(line, width=max_x) for line in lines]
final_text = '\n'.join(wrapped_lines)
final_lines = final_text.split('\n')
# Display text
for i, line in enumerate(final_lines[offset:]):
if i >= max_y - 1:
break
stdscr.addstr(i, 0, line)
stdscr.refresh()
update_needed = False # Reset the flag after updating
# Get user input
c = stdscr.getch()
# Scroll up/down
if c == curses.KEY_UP and offset > 0:
offset -= 1
update_needed = True
elif c == curses.KEY_DOWN and offset < len(final_lines) - max_y:
offset += 1
update_needed = True
# Skip a whole screen up/down
elif c == curses.KEY_SR and offset > 0: # Ctrl+Up
offset = max(0, offset - max_y)
update_needed = True
elif c == curses.KEY_SF and offset < len(final_lines) - max_y: # Ctrl+Down
offset = min(len(final_lines) - max_y, offset + max_y)
update_needed = True
# Change chapters
elif c == curses.KEY_RIGHT:
current_chapter += 1
if not os.path.exists(f'chapters/chapter{current_chapter}.txt'):
current_chapter -= 1
offset = 0
update_needed = True
elif c == curses.KEY_LEFT and current_chapter > 0:
current_chapter -= 1
offset = 0
update_needed = True
# Quit
elif c == ord('q'):
break # No need to set update_needed since we are exiting
curses.wrapper(main)