from typing import Callable, Optional import wx from wx.lib.pubsub import pub from ...core import LobbyState class RoleColumn(wx.Panel): def __init__( self, parent, role_key: str, button_label: str, on_role_selected: Optional[Callable[[str], None]] = None, ): super().__init__(parent) self.role_key = role_key self.on_role_selected = on_role_selected self.is_active = False sizer = wx.BoxSizer(wx.VERTICAL) self.button_select = wx.ToggleButton(self, label=button_label) self.button_select.Bind(wx.EVT_TOGGLEBUTTON, self._on_button_click) sizer.Add(self.button_select, 0, wx.EXPAND | wx.ALL, 5) self.list_players = wx.ListBox(self) sizer.Add(self.list_players, 1, wx.EXPAND | wx.ALL, 5) self.SetSizer(sizer) def _on_button_click(self, event): if self.is_active: self.button_select.SetValue(True) return if self.on_role_selected: self.on_role_selected(self.role_key) def set_players(self, players: list[str]): self.list_players.Clear() if players: self.list_players.AppendItems(players) def set_role_state(self, role: str): self.is_active = self.role_key == role self.button_select.SetValue(self.is_active) class LobbyPanel(wx.Panel): def __init__(self, parent, state: LobbyState): super().__init__(parent) self.state = state self._init_ui() self.Bind(wx.EVT_WINDOW_DESTROY, self._on_destroy) def _init_ui(self): main_sizer = wx.BoxSizer(wx.VERTICAL) columns_sizer = wx.BoxSizer(wx.HORIZONTAL) self.column_none = RoleColumn( self, "NONE", "👤 Без роли", self._on_role_click ) self.column_setter = RoleColumn( self, "SETTER", "🧠 Загадывает", self._on_role_click ) self.column_guesser = RoleColumn( self, "GUESSER", "🕵️ Угадывает", self._on_role_click ) columns_sizer.Add(self.column_none, 1, wx.EXPAND | wx.ALL, 5) columns_sizer.Add(self.column_setter, 1, wx.EXPAND | wx.ALL, 5) columns_sizer.Add(self.column_guesser, 1, wx.EXPAND | wx.ALL, 5) self.button_start = wx.Button(self, label="➔ Начать сессию") self.button_start.Bind(wx.EVT_BUTTON, self._on_start_click) main_sizer.Add(columns_sizer, 1, wx.EXPAND | wx.ALL, 5) main_sizer.Add( self.button_start, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10 ) self.SetSizer(main_sizer) pub.subscribe(self.refresh, "lobby.refresh") self.refresh(self.state) def _on_role_click(self, target_role: str): success = self.state.set_player_role(target_role) if not success: wx.MessageBox( f"Не удалось занять роль «{target_role}».", "Внимание", wx.OK | wx.ICON_WARNING, ) return self.refresh(self.state) def _on_start_click(self, event): wx.MessageBox("Сессия запущена!", "Старт", wx.OK | wx.ICON_INFORMATION) def _on_destroy(self, event): pub.unsubscribe(self.refresh, "lobby.refresh") event.Skip() def refresh(self, state: LobbyState): players_by_role = {"NONE": [], "SETTER": [], "GUESSER": []} for player, role in state.players.items(): if role in players_by_role: players_by_role[role].append(player) self.column_none.set_players(players_by_role["NONE"]) self.column_setter.set_players(players_by_role["SETTER"]) self.column_guesser.set_players(players_by_role["GUESSER"]) local_player_role = state.local_player_role self.column_none.set_role_state(local_player_role) self.column_setter.set_role_state(local_player_role) self.column_guesser.set_role_state(local_player_role) self.button_start.Enable(state.is_ready())