import sys from dataclasses import dataclass from enum import Enum, auto from typing import Optional import wx from mind_reader.core import SessionState def enable_high_dpi_support(): if sys.platform == "win32": try: import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(2) except Exception: try: import ctypes ctypes.windll.user32.SetProcessDPIAware() except Exception: pass class CardState(Enum): SETTER_NOT_SET = auto() SETTER_HIDDEN = auto() SETTER_REVEALED = auto() GUESSER_DISABLED = auto() GUESSER_WAITING = auto() GUESSER_CORRECT = auto() GUESSER_WRONG = auto() class ArrowDirection(Enum): LEFT = auto() RIGHT = auto() @dataclass(frozen=True) class SetterCardColour: NOT_SET = wx.Colour(82, 97, 107) HIDDEN = wx.Colour(201, 214, 223) REVEALED = wx.Colour(240, 245, 249) @dataclass(frozen=True) class GuesserCardColour: DISABLED = wx.Colour(82, 97, 107) WAITING = wx.Colour(201, 214, 223) CORRECT = wx.Colour(76, 175, 80) WRONG = wx.Colour(229, 115, 115) @dataclass(frozen=True) class ArrowSymbol: LEFT: str = "◀" RIGHT: str = "▶" class Card(wx.Panel): def __init__(self, parent, state: CardState): super().__init__(parent, style=wx.BORDER_SIMPLE) self._direction: Optional[ArrowDirection] = None self._state = state self._setup() self._update() def _setup(self): self.SetMinSize(wx.Size(35, 35)) self.label = wx.StaticText(self, style=wx.ALIGN_CENTER) # font = self.label.GetFont() # font.SetPointSize(6) # self.label.SetFont(font) sizer = wx.BoxSizer(wx.VERTICAL) sizer.AddStretchSpacer() sizer.Add(self.label, 0, wx.ALIGN_CENTER) sizer.AddStretchSpacer() self.SetSizer(sizer) def _update(self): match self._state: case CardState.SETTER_NOT_SET: colour = SetterCardColour.NOT_SET show_arrow = False case CardState.SETTER_HIDDEN: colour = SetterCardColour.HIDDEN show_arrow = False case CardState.SETTER_REVEALED: colour = SetterCardColour.REVEALED show_arrow = True case CardState.GUESSER_DISABLED: colour = GuesserCardColour.DISABLED show_arrow = False case CardState.GUESSER_WAITING: colour = GuesserCardColour.WAITING show_arrow = False case CardState.GUESSER_CORRECT: colour = GuesserCardColour.CORRECT show_arrow = True case CardState.GUESSER_WRONG: colour = GuesserCardColour.WRONG show_arrow = True match self._direction: case ArrowDirection.LEFT: symbol = ArrowSymbol.LEFT case ArrowDirection.RIGHT: symbol = ArrowSymbol.RIGHT if show_arrow and self._direction: match self._direction: case ArrowDirection.LEFT: symbol = ArrowSymbol.LEFT case ArrowDirection.RIGHT: symbol = ArrowSymbol.RIGHT self.label.SetLabel(symbol) else: self.label.SetLabel("") self.SetBackgroundColour(colour) self.Layout() self.Refresh() def set( self, state: CardState, direction: Optional[ArrowDirection] = None, ) -> None: self._state = state self._direction = direction self._update() class SessionPanel(wx.Panel): def __init__(self, parent, sequence_length: int = 20): super().__init__(parent) self._sequence_length = sequence_length self._setter_sequence: list[Card] = [] self._guesser_sequence: list[Card] = [] self._setup() def _setup(self) -> None: main_sizer = wx.BoxSizer(wx.VERTICAL) setter_sizer = wx.BoxSizer(wx.HORIZONTAL) for _ in range(self._sequence_length): card = Card(self, CardState.SETTER_NOT_SET) setter_sizer.Add(card, 0, wx.ALL, 3) self._setter_sequence.append(card) guesser_sizer = wx.BoxSizer(wx.HORIZONTAL) for _ in range(self._sequence_length): card = Card(self, CardState.GUESSER_DISABLED) guesser_sizer.Add(card, 0, wx.ALL, 3) self._guesser_sequence.append(card) main_sizer.Add(setter_sizer, 0, wx.ALL, 5) main_sizer.Add(guesser_sizer, 0, wx.ALL, 5) self.SetSizer(main_sizer) def update_setter_card( self, index: int, state: CardState, direction: Optional[ArrowDirection] = None, ) -> None: self._setter_sequence[index].set(state, direction) def update_guesser_card( self, index: int, state: CardState, direction: Optional[ArrowDirection] = None, ) -> None: self._guesser_sequence[index].set(state, direction) class TestFrame(wx.Frame): def __init__(self): super().__init__(None, title="TestFrame", size=wx.Size(900, 500)) main_panel = SessionPanel(self) main_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.Add(main_panel, 1, wx.EXPAND) self.SetSizer(main_sizer) self.Layout() main_panel.update_setter_card( 0, CardState.SETTER_REVEALED, ArrowDirection.LEFT ) main_panel.update_guesser_card( 0, CardState.GUESSER_WRONG, ArrowDirection.RIGHT ) if __name__ == "__main__": enable_high_dpi_support() app = wx.App() frame = TestFrame() frame.Show() app.MainLoop()