diff --git a/README.md b/README.md index 86316fe..32ddd6e 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,10 @@ Two views, switched from the top bar (Ctrl+1 / Ctrl+2): filters. Click a game to open it in the Match view ("Back to live" returns). Games from the previous MTGA session (`Player-prev.log`) are imported on startup. -*⚙ Customize* shows or hides the match panels, turn stats, deck sections and the preview. -*Customize → Arrange…* reorders (drag, or ↑/↓) and shows/hides the My deck and Opponent sections -and the turn stats. Your choices are remembered. +*⚙ Customize* shows or hides each panel of the Match page (You, Match, Opponent, Turn stats, +My deck, Preview, Opponent's cards) and the details in the player panels. *Customize → Arrange…* +reorders (drag, or ↑/↓) and shows/hides the My deck and Opponent sections and the turn stats. +Your choices are remembered. Card names, mana costs and types come from MTGA's own local card database, so they work offline. diff --git a/src/mtga_assistant/ui/deck_view.py b/src/mtga_assistant/ui/deck_view.py index 7e441cc..38083d2 100644 --- a/src/mtga_assistant/ui/deck_view.py +++ b/src/mtga_assistant/ui/deck_view.py @@ -74,9 +74,11 @@ class DeckView(QWidget): self.preview.cleared.connect(self._clear_selection) split = QSplitter(Qt.Orientation.Horizontal) - split.addWidget(card_frame("My deck", self.mine)) - split.addWidget(card_frame("Preview", self.preview)) - split.addWidget(card_frame("Opponent", self.opp)) + self.my_frame = card_frame("My deck", self.mine) + self.preview_frame = card_frame("Preview", self.preview) + self.opp_frame = card_frame("Opponent", self.opp) + for frame in (self.my_frame, self.preview_frame, self.opp_frame): + split.addWidget(frame) split.setStretchFactor(0, 3) split.setStretchFactor(1, 2) split.setStretchFactor(2, 3) @@ -86,6 +88,12 @@ class DeckView(QWidget): lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(split) + def show_panels(self, my_deck: bool, preview: bool, opp_deck: bool) -> None: + self.my_frame.setVisible(my_deck) + self.preview_frame.setVisible(preview) + self.opp_frame.setVisible(opp_deck) + self.setVisible(my_deck or preview or opp_deck) + def _clear_selection(self) -> None: for lst in (self.mine, self.opp): lst.setCurrentItem(None) diff --git a/src/mtga_assistant/ui/main_window.py b/src/mtga_assistant/ui/main_window.py index ead0134..a151534 100644 --- a/src/mtga_assistant/ui/main_window.py +++ b/src/mtga_assistant/ui/main_window.py @@ -39,7 +39,16 @@ from .toggles import StayOpenMenu, Toggles from .turn_view import TURN_DEFAULTS_OFF, TURN_TOGGLES, TurnView REFRESH_MS = 150 -DECK_TOGGLES = [("preview", "Card preview pane")] +# Panels of the Match page that can be hidden (rows disappear when all their panels are hidden). +SECTION_TOGGLES = [ + ("you", "You"), + ("match", "Match"), + ("opponent", "Opponent"), + ("turns", "Turn stats"), + ("my_deck", "My deck"), + ("preview", "Preview"), + ("opp_deck", "Opponent's cards"), +] VIEWS = ["Match", "History"] MATCH, HISTORY = 0, 1 @@ -91,7 +100,7 @@ class MainWindow(QMainWindow): self._settings = QSettings("mtga-assistant", "mtga-assistant") self.toggles = [ - Toggles("deck", DECK_TOGGLES, parent=self), + Toggles("sections", SECTION_TOGGLES, parent=self), Toggles("match", MATCH_TOGGLES, parent=self), Toggles("turn", TURN_TOGGLES, TURN_DEFAULTS_OFF, parent=self), ] @@ -244,14 +253,22 @@ class MainWindow(QMainWindow): def _fill_customize(self) -> None: menu = self.customize_menu menu.clear() - self.toggles[1].fill_menu(menu) # match panels - for title, tg in (("Turn stats", self.toggles[2]), ("My deck sections", self.my_sections), - ("Opponent sections", self.opp_sections), ("Preview", self.toggles[0])): - sub = StayOpenMenu(title, menu) - tg.fill_menu(sub) - menu.addMenu(sub) - menu.addSeparator() - menu.addAction("Arrange sections and stats…").triggered.connect(self._open_arrange) + for heading, tg in (("Sections", self.toggles[0]), ("Player panel details", self.toggles[1])): + title = menu.addAction(heading) + title.setEnabled(False) # a heading, not an option + font = title.font() + font.setBold(True) + title.setFont(font) + tg.fill_menu(menu) + menu.addSeparator() + # Deck sections and turn stats (order and visibility) live in the Arrange dialog. + menu.addAction("Arrange deck sections and turn stats…").triggered.connect(self._open_arrange) + + def _apply_sections(self) -> None: + on = self.toggles[0].on + self.match_view.show_panels(you=on("you"), match=on("match"), opponent=on("opponent"), + turns=on("turns")) + self.deck_view.show_panels(my_deck=on("my_deck"), preview=on("preview"), opp_deck=on("opp_deck")) def _open_arrange(self) -> None: ArrangeDialog(self._arrangeable(), "Arrange sections and stats", self).exec() @@ -380,16 +397,20 @@ class MainWindow(QMainWindow): if self._rendered.get(index) == key: return self._rendered[index] = key - self._render_header(t) - self.deck_view.preview.parentWidget().setVisible(self.toggles[0].on("preview")) + self._render_header(t, show_match=index == MATCH) + self._apply_sections() if index == MATCH: self.deck_view.render(t) self.match_view.render(t, self.now_ms()) self.turn_view.render(t) - def _render_header(self, t: MatchTracker) -> None: + def _render_header(self, t: MatchTracker, show_match: bool = True) -> None: g = t.game - if g is None: + if not show_match: + # The match summary belongs to the Match tab only. + self.header.setText("") + self.header.setToolTip("") + elif g is None: self.header.setText("Waiting for a match…") else: parts = [f"vs {t.opponent_name or 'opponent'}"] diff --git a/src/mtga_assistant/ui/match_view.py b/src/mtga_assistant/ui/match_view.py index bb0e4d8..eb4c080 100644 --- a/src/mtga_assistant/ui/match_view.py +++ b/src/mtga_assistant/ui/match_view.py @@ -214,7 +214,8 @@ class MatchView(QWidget): grid.addWidget(w, row, 0, Qt.AlignmentFlag.AlignHCenter) grid.setRowStretch(7, 1) - top = QWidget() + self.turn_view = turn_view + top = self.top = QWidget() top_lay = QHBoxLayout(top) top_lay.setContentsMargins(0, 0, 0, 0) top_lay.addWidget(self.me, 3) @@ -233,11 +234,26 @@ class MatchView(QWidget): lay = QVBoxLayout(self) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self.split) + self._panels = {"you": True, "match": True, "opponent": True} + self._has_game = False + + def show_panels(self, you: bool, match: bool, opponent: bool, turns: bool) -> None: + """Hide/show panels; a row with every panel hidden collapses out of the splitter.""" + self._panels = {"you": you, "match": match, "opponent": opponent} + self.top.setVisible(you or match or opponent) + self.turn_view.setVisible(turns) + self._apply_panels() + + def _apply_panels(self) -> None: + # render() toggles these for "no game yet", so combine both conditions. + self.me.setVisible(self._has_game and self._panels["you"]) + self.info.setVisible(self._has_game and self._panels["match"]) + self.opp.setVisible(self._has_game and self._panels["opponent"]) def render(self, t: MatchTracker, now_ms: int) -> None: g = t.game - for w in (self.me, self.opp, self.info): - w.setVisible(g is not None) + self._has_game = g is not None + self._apply_panels() if g is None: return self.me.render(g, g.my_seat, "You", now_ms)