Skip to content
Permalink
main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
# -*- coding: utf-8 -*-
__all__ = (
'App',
'Text'
)
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from dataclasses import dataclass, field
from functools import partial, partialmethod
from contextlib import contextmanager
from collections.abc import Iterable, Iterator
from typing import (
Any,
Callable,
Optional,
TypeAlias,
Protocol,
ClassVar,
final
)
from stanley import Equipment, Chapter
class Text(Protocol):
def append(self, text: str) -> None:
""" Appends text to text box """
def clear(self) -> None:
""" Clears text box """
def write(self, text: str) -> None:
""" Clears text box then writes text to it """
@final
class Textbox(ScrolledText):
clear = partialmethod(tk.Text.delete, "0.1", tk.END)
append = partialmethod(tk.Text.insert, tk.END)
def write(self, text: str, *args) -> None:
self.clear()
self.append(text, *args)
@contextmanager
def editable(widget: tk.Text) -> tk.Text:
widget.configure(state=tk.NORMAL)
try:
yield widget
finally:
widget.configure(state=tk.DISABLED)
@dataclass
class Page:
chapter: Chapter
equipment_index: tk.IntVar = field(default_factory=tk.IntVar)
def selected_equipment(self) -> Equipment:
return self.chapter.equipments[self.equipment_index.get()]
@final
class App(tk.Tk):
WIDTH: ClassVar[int] = 750
HEIGHT: ClassVar[int] = 520
__slots__ = 'text', 'options', 'button', 'parts', 'pages'
def __init__(self):
super().__init__()
# Configure window
self.title("Stanley")
self.geometry(f"{App.WIDTH}x{App.HEIGHT}")
# Item index of choosen equipment in chapter
self.text = Textbox(self)
self.text.pack(expand=True, fill=tk.BOTH)
# Button pressed after choice
self.button = tk.Button(self, text="Choose Part")
self.button.pack(side=tk.RIGHT)
# List of radio buttons
self.options: list[tk.Radiobutton] = []
# Story section
self.parts: list[Equipment] = []
self.pages: list[Page] = []
Handler: TypeAlias = Callable[[list[Equipment], Text], Any]
def from_page(self, page: Page) -> None:
with editable(self.text) as text:
text.write(page.chapter.text)
self.options = [
tk.Radiobutton(self, text=e.name, var=page.equipment_index, value=i) for i, e in enumerate(page.chapter.equipments)
]
for button in self.options:
button.pack(side=tk.LEFT)
def from_chapters(self, chapters: Iterable[Chapter], *, on_end: Optional[Handler] = None) -> None:
chapters = iter(chapters)
next_chapter = partial(self.next_chapter, chapters, on_end=on_end)
next_chapter()
self.button.configure(command=next_chapter)
def next_chapter(self, chapters: Iterator[Chapter], *, on_end: Optional[Handler] = None) -> None:
for button in self.options:
button.destroy()
if page := next(reversed(self.pages), None):
self.parts.append(page.selected_equipment())
if chapter := next(chapters, None):
page = Page(chapter)
self.from_page(page)
self.pages.append(page)
else:
self.on_end(on_end)
def on_end(self, /, user_end_procedure: Optional[Handler] = None) -> None:
self.button.destroy()
with editable(self.text) as text:
text.clear()
if user_end_procedure:
user_end_procedure(self.parts, text)