feat(ui): wip session_view.py

This commit is contained in:
2026-08-11 04:08:55 +03:00
parent 1da622cd7c
commit 6254de74e4
+136 -24
View File
@@ -39,6 +39,23 @@ class ArrowDirection(Enum):
RIGHT = auto() RIGHT = auto()
@dataclass
class SessionStats:
total: int
setted: int
correct: int
wrong: int
taken_time: float
@property
def accuracy(self) -> float:
accuracy: float
if self.total == 0:
accuracy = 0.0
accuracy = (self.correct / self.total) * 100
return round(accuracy, 1)
@dataclass(frozen=True) @dataclass(frozen=True)
class SetterCardColour: class SetterCardColour:
NOT_SET = wx.Colour(82, 97, 107) NOT_SET = wx.Colour(82, 97, 107)
@@ -56,8 +73,8 @@ class GuesserCardColour:
@dataclass(frozen=True) @dataclass(frozen=True)
class ArrowSymbol: class ArrowSymbol:
LEFT: str = "" LEFT: str = ""
RIGHT: str = "" RIGHT: str = ""
class Card(wx.Panel): class Card(wx.Panel):
@@ -69,18 +86,16 @@ class Card(wx.Panel):
self._update() self._update()
def _setup(self): def _setup(self):
self.SetMinSize(wx.Size(35, 35)) self.SetMinSize(wx.Size(45, 75))
self.label = wx.StaticText(self, style=wx.ALIGN_CENTER) self.label = wx.StaticText(self, style=wx.ALIGN_CENTER)
# font = self.label.GetFont() font = self.label.GetFont()
# font.SetPointSize(6) font.SetPointSize(20)
# self.label.SetFont(font) self.label.SetFont(font)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddStretchSpacer() sizer.Add(self.label, 0, wx.EXPAND)
sizer.Add(self.label, 0, wx.ALIGN_CENTER)
sizer.AddStretchSpacer()
self.SetSizer(sizer) self.SetSizer(sizer)
@@ -114,13 +129,6 @@ class Card(wx.Panel):
colour = GuesserCardColour.WRONG colour = GuesserCardColour.WRONG
show_arrow = True show_arrow = True
match self._direction:
case ArrowDirection.LEFT:
symbol = ArrowSymbol.LEFT
case ArrowDirection.RIGHT:
symbol = ArrowSymbol.RIGHT
if show_arrow and self._direction: if show_arrow and self._direction:
match self._direction: match self._direction:
case ArrowDirection.LEFT: case ArrowDirection.LEFT:
@@ -150,33 +158,109 @@ class Card(wx.Panel):
class SessionPanel(wx.Panel): class SessionPanel(wx.Panel):
def __init__(self, parent, sequence_length: int = 20): def __init__(
self,
parent,
setter_name: str,
guesser_name: str,
sequence_length: int = 20,
):
super().__init__(parent) super().__init__(parent)
self._setter_name = setter_name
self._guesser_name = guesser_name
self._sequence_length = sequence_length self._sequence_length = sequence_length
self._setter_sequence: list[Card] = [] self._setter_sequence: list[Card] = []
self._guesser_sequence: list[Card] = [] self._guesser_sequence: list[Card] = []
self._statusbar = self._get_statusbar()
self._setup() self._setup()
self._fit_parent_frame()
def _setup(self) -> None: def _setup(self) -> None:
main_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer = wx.BoxSizer(wx.VERTICAL)
setter_title = wx.StaticText(
self, label=f"Загадывает: {self._setter_name}"
)
setter_sizer = wx.BoxSizer(wx.HORIZONTAL) setter_sizer = wx.BoxSizer(wx.HORIZONTAL)
for _ in range(self._sequence_length): for _ in range(self._sequence_length):
card = Card(self, CardState.SETTER_NOT_SET) card = Card(self, CardState.SETTER_NOT_SET)
setter_sizer.Add(card, 0, wx.ALL, 3) setter_sizer.Add(card, 0, wx.ALL, 4)
self._setter_sequence.append(card) self._setter_sequence.append(card)
guesser_title = wx.StaticText(
self, label=f"Отгадывает: {self._guesser_name}"
)
guesser_sizer = wx.BoxSizer(wx.HORIZONTAL) guesser_sizer = wx.BoxSizer(wx.HORIZONTAL)
for _ in range(self._sequence_length): for _ in range(self._sequence_length):
card = Card(self, CardState.GUESSER_DISABLED) card = Card(self, CardState.GUESSER_DISABLED)
guesser_sizer.Add(card, 0, wx.ALL, 3) guesser_sizer.Add(card, 0, wx.ALL, 4)
self._guesser_sequence.append(card) self._guesser_sequence.append(card)
main_sizer.Add(setter_sizer, 0, wx.ALL, 5) controls_sizer = self._create_controls_sizer()
main_sizer.Add(guesser_sizer, 0, wx.ALL, 5)
secondary_sizer = wx.BoxSizer(wx.VERTICAL)
secondary_sizer.Add(setter_title, 0, wx.LEFT | wx.TOP, 9)
secondary_sizer.Add(setter_sizer, 0, wx.ALL, 5)
secondary_sizer.Add(guesser_title, 0, wx.LEFT | wx.TOP, 9)
secondary_sizer.Add(guesser_sizer, 0, wx.ALL, 5)
secondary_sizer.Add(
controls_sizer, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 25
)
main_sizer.Add(secondary_sizer, 0, wx.LEFT | wx.ALL, 0)
self.SetSizer(main_sizer) self.SetSizer(main_sizer)
def _create_controls_sizer(self) -> wx.Sizer:
left = wx.Button(self, label=ArrowSymbol.LEFT, size=wx.Size(145, 55))
right = wx.Button(self, label=ArrowSymbol.RIGHT, size=wx.Size(145, 55))
font = left.GetFont()
font.SetPointSize(22)
left.SetFont(font)
right.SetFont(font)
controls_sizer = wx.BoxSizer(wx.HORIZONTAL)
controls_sizer.Add(left, 0, wx.RIGHT, 10)
controls_sizer.Add(right, 0, wx.LEFT, 10)
return controls_sizer
def _get_statusbar(self) -> Optional[wx.StatusBar]:
top_frame = self.GetTopLevelParent()
if isinstance(top_frame, wx.Frame):
statusbar = top_frame.GetStatusBar()
if not statusbar:
statusbar = top_frame.CreateStatusBar(1)
statusbar.SetFieldsCount(4)
return statusbar
return None
def _autofit_statusbar(self, texts: list[str]) -> None:
if not self._statusbar:
return
dc = wx.ClientDC(self._statusbar)
width_1 = dc.GetTextExtent(texts[0]).width
width_2 = dc.GetTextExtent(texts[1]).width
width_3 = dc.GetTextExtent(texts[2]).width
self._statusbar.SetStatusWidths([-1, width_1, width_2, width_3])
def _fit_parent_frame(self) -> None:
top_frame = self.GetTopLevelParent()
if isinstance(top_frame, wx.Frame):
self.Layout()
best_size = self.GetBestSize()
min_size = top_frame.ClientToWindowSize(best_size)
top_frame.SetMinSize(min_size)
top_frame.Fit()
def update_setter_card( def update_setter_card(
self, self,
index: int, index: int,
@@ -193,15 +277,40 @@ class SessionPanel(wx.Panel):
) -> None: ) -> None:
self._guesser_sequence[index].set(state, direction) self._guesser_sequence[index].set(state, direction)
def update_statusbar(
self,
statusbar_text: Optional[str],
stats: SessionStats,
):
if not self._statusbar:
return
if statusbar_text is not None:
self._statusbar.SetStatusText(statusbar_text, 0)
progress = f" Прогресс {stats.setted}/{stats.total} "
self._statusbar.SetStatusText(progress, 1)
accuracy = (
f" Точность {stats.accuracy}% ({stats.correct}/{stats.wrong}) "
)
self._statusbar.SetStatusText(accuracy, 2)
minutes = int(stats.taken_time) // 60
seconds = int(stats.taken_time) % 60
taken_time = f" Время {minutes:02d}:{seconds:02d} "
self._statusbar.SetStatusText(taken_time, 3)
self._autofit_statusbar([progress, accuracy, taken_time])
class TestFrame(wx.Frame): class TestFrame(wx.Frame):
def __init__(self): def __init__(self):
super().__init__(None, title="TestFrame", size=wx.Size(900, 500)) super().__init__(None, title="TestFrame")
main_panel = SessionPanel(self) main_panel = SessionPanel(self, "Бывалый", "Балбес")
main_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(main_panel, 1, wx.EXPAND) main_sizer.Add(main_panel, 1, wx.EXPAND)
self.SetSizer(main_sizer) self.SetSizer(main_sizer)
self.Layout()
main_panel.update_setter_card( main_panel.update_setter_card(
0, CardState.SETTER_REVEALED, ArrowDirection.LEFT 0, CardState.SETTER_REVEALED, ArrowDirection.LEFT
@@ -211,6 +320,9 @@ class TestFrame(wx.Frame):
0, CardState.GUESSER_WRONG, ArrowDirection.RIGHT 0, CardState.GUESSER_WRONG, ArrowDirection.RIGHT
) )
s = SessionStats(20, 1, 0, 1, 5.1)
main_panel.update_statusbar(None, s)
if __name__ == "__main__": if __name__ == "__main__":
enable_high_dpi_support() enable_high_dpi_support()