You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bingo-cli/bingo.py

126 lines
3.8 KiB
Python

#!/usr/bin/env python3
from textual.app import App, ComposeResult
from textual.widgets import Header, Input, Static, Button
from textual.containers import Horizontal, Container
from textual.validation import Number
from textual.reactive import reactive
from datetime import datetime
from BingoBoard import BingoBoard
from AboutCommand import AboutCommand
MESSAGE = '''
Be excellent to each other!
Made with :red_heart: by Panki
[@click="app.open_link('https://tty0.social/@panki')"]Mastodon:[/] tty0.social/@panki
[@click="app.open_link('https://git.theresno.cloud/panki/bingo-cli')"]Source:[/] git.theresno.cloud/panki/bingo-cli
Built using [@click="app.open_link('https://textual.textualize.io/')"]Textual[/]
'''
class Sidebar(Container):
'''Class to represent the sidebar'''
def compose(self) -> ComposeResult:
'''Create the widgets that make up the sidebar'''
yield Static('CCC Bingo', classes='title')
yield Static(MESSAGE, classes='message')
self.button = Button('< Back', variant='primary', classes='btn_sidebar')
self.button.disabled = True
yield self.button
def on_button_pressed(self, event: Button.Pressed) -> None:
'''Closes the sidebar'''
self.app.action_toggle_sidebar()
class BingoApp(App):
'''
A Textual app to run a Bingo board.
Contains the sidebar, header, and BingoDisplay.
'''
CSS_PATH = "bingo.tcss"
COMMANDS = App.COMMANDS | {AboutCommand}
AUTO_FOCUS = 'Input'
show_sidebar = reactive(False)
def action_toggle_sidebar(self) -> None:
'''Toggle the sidebar on or off'''
sidebar = self.query_one(Sidebar)
self.set_focus(None)
if sidebar.has_class("-hidden"):
sidebar.remove_class("-hidden")
sidebar.button.disabled = False
else:
if sidebar.query("*:focus"):
self.screen.set_focus(None)
sidebar.add_class("-hidden")
sidebar.button.disabled = True
def compose(self) -> ComposeResult:
'''Create child widgets for the app.'''
yield Sidebar(classes="-hidden")
yield Header(show_clock=True)
yield BingoDisplay()
def on_mount(self) -> None:
'''Set title of the app'''
self.title = 'CCC Bingo'
self.sub_title = 'GPN22 Edition'
class BingoDisplay(Static):
'''
A Widget to represent the bingo UI.
Contains the board, input field and re-roll button.
Attributes
----------
board : BingoBoard
The BingoBoard object
input_field : Input
User input for game seed
'''
def compose(self) -> ComposeResult:
'''Create child widgets for the app.'''
self.board = BingoBoard()
yield self.board
self.input_field = Input(
str(self.board.seed),
type='integer',
placeholder='UNIX timestamp',
max_length=10,
classes='seed_input',
validators=[
Number(minimum=1000000000, maximum = 2000000000)
]
)
self.input_field.border_title = 'Seed'
yield Horizontal(
self.input_field,
Button.error(':game_die: re-roll', classes='roll_btn'),
classes='bottom_line'
)
def on_button_pressed(self, event: Button.Pressed) -> None:
'''Re-roll the board state with current time as seed'''
self.board.roll_board(int(datetime.now().timestamp()))
self.input_field.value = str(self.board.seed)
def on_input_submitted(self, event: Input.Submitted) -> None:
'''Re-roll the board state with the seed from the input'''
if event.validation_result.is_valid:
self.board.roll_board(int(event.value))
if __name__ == "__main__":
app = BingoApp()
app.run()