feat(ui): wip session_view.py
This commit is contained in:
@@ -39,6 +39,23 @@ class ArrowDirection(Enum):
|
||||
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)
|
||||
class SetterCardColour:
|
||||
NOT_SET = wx.Colour(82, 97, 107)
|
||||
@@ -56,8 +73,8 @@ class GuesserCardColour:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArrowSymbol:
|
||||
LEFT: str = "◀"
|
||||
RIGHT: str = "▶"
|
||||
LEFT: str = "←"
|
||||
RIGHT: str = "→"
|
||||
|
||||
|
||||
class Card(wx.Panel):
|
||||
@@ -69,18 +86,16 @@ class Card(wx.Panel):
|
||||
self._update()
|
||||
|
||||
def _setup(self):
|
||||
self.SetMinSize(wx.Size(35, 35))
|
||||
self.SetMinSize(wx.Size(45, 75))
|
||||
|
||||
self.label = wx.StaticText(self, style=wx.ALIGN_CENTER)
|
||||
|
||||
# font = self.label.GetFont()
|
||||
# font.SetPointSize(6)
|
||||
# self.label.SetFont(font)
|
||||
font = self.label.GetFont()
|
||||
font.SetPointSize(20)
|
||||
self.label.SetFont(font)
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.AddStretchSpacer()
|
||||
sizer.Add(self.label, 0, wx.ALIGN_CENTER)
|
||||
sizer.AddStretchSpacer()
|
||||
sizer.Add(self.label, 0, wx.EXPAND)
|
||||
|
||||
self.SetSizer(sizer)
|
||||
|
||||
@@ -114,13 +129,6 @@ class Card(wx.Panel):
|
||||
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:
|
||||
@@ -150,33 +158,109 @@ class Card(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)
|
||||
self._setter_name = setter_name
|
||||
self._guesser_name = guesser_name
|
||||
self._sequence_length = sequence_length
|
||||
self._setter_sequence: list[Card] = []
|
||||
self._guesser_sequence: list[Card] = []
|
||||
|
||||
self._statusbar = self._get_statusbar()
|
||||
|
||||
self._setup()
|
||||
self._fit_parent_frame()
|
||||
|
||||
def _setup(self) -> None:
|
||||
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
setter_title = wx.StaticText(
|
||||
self, label=f"Загадывает: {self._setter_name}"
|
||||
)
|
||||
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)
|
||||
setter_sizer.Add(card, 0, wx.ALL, 4)
|
||||
self._setter_sequence.append(card)
|
||||
|
||||
guesser_title = wx.StaticText(
|
||||
self, label=f"Отгадывает: {self._guesser_name}"
|
||||
)
|
||||
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)
|
||||
guesser_sizer.Add(card, 0, wx.ALL, 4)
|
||||
self._guesser_sequence.append(card)
|
||||
|
||||
main_sizer.Add(setter_sizer, 0, wx.ALL, 5)
|
||||
main_sizer.Add(guesser_sizer, 0, wx.ALL, 5)
|
||||
controls_sizer = self._create_controls_sizer()
|
||||
|
||||
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)
|
||||
|
||||
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(
|
||||
self,
|
||||
index: int,
|
||||
@@ -193,15 +277,40 @@ class SessionPanel(wx.Panel):
|
||||
) -> None:
|
||||
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):
|
||||
def __init__(self):
|
||||
super().__init__(None, title="TestFrame", size=wx.Size(900, 500))
|
||||
main_panel = SessionPanel(self)
|
||||
super().__init__(None, title="TestFrame")
|
||||
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
|
||||
@@ -211,6 +320,9 @@ class TestFrame(wx.Frame):
|
||||
0, CardState.GUESSER_WRONG, ArrowDirection.RIGHT
|
||||
)
|
||||
|
||||
s = SessionStats(20, 1, 0, 1, 5.1)
|
||||
main_panel.update_statusbar(None, s)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
enable_high_dpi_support()
|
||||
|
||||
Reference in New Issue
Block a user