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)