feat(ui): wip session_view.py
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user