From 68d312934b5403e1ae8eac60714e87b8dff0bf33 Mon Sep 17 00:00:00 2001 From: Dominik Roth Date: Sun, 9 Aug 2026 20:32:06 +0200 Subject: [PATCH] Close the popover when 'Add X' opens a dialog or arms map placement Every menu popover (Units/Spotters/Reference Points/Targets/Scout Flights) stayed open on top of the modal dialog or map-click placement its own 'Add ' button just triggered, holding onto focus that should have gone to the new dialog or the map instead. _add_row() now takes a close() callback (threaded through from _make_menu_button, which already owns the Gtk.Popover) and pops the popover down right before calling on_click(). Verified end to end with a GTK smoke test: opens the real 'Scout Flights' popover, clicks its real 'Add scout flight' button, confirms the popover is no longer visible afterward. --- src/fenigma/app.py | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/fenigma/app.py b/src/fenigma/app.py index 4f05055..821160e 100644 --- a/src/fenigma/app.py +++ b/src/fenigma/app.py @@ -130,18 +130,23 @@ def _row( return box -def _add_row(label: str, on_click) -> Gtk.Widget: +def _add_row(label: str, on_click, close) -> Gtk.Widget: """The trailing 'Add ' row in a popover: just one button, not the full _row() layout (which always pairs a manual-input action with a per-item screenshot action). There's nothing to screenshot *into* yet for something that doesn't exist, and the universal clipboard button in the header already covers 'load everything from a screenshot' for every category, a second, category-specific - version of that here was redundant.""" + version of that here was redundant. + + Closes the popover before calling on_click(): every on_click here + either opens its own modal dialog or arms map-click placement, and + the popover staying open on top of that just holds onto focus the + dialog/map should have instead.""" box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, margin_top=4, margin_bottom=4, margin_start=8, margin_end=8) btn = Gtk.Button(label=label, hexpand=True) - btn.connect("clicked", lambda _b: on_click()) + btn.connect("clicked", lambda _b: (close(), on_click())) box.append(btn) return box @@ -341,17 +346,21 @@ class MainWindow(Adw.ApplicationWindow): # -- generic helpers ----------------------------------------------------- def _make_menu_button(self, label: str, build_popover) -> Gtk.MenuButton: - """build_popover(rebuild) returns the popover's content widget; - rebuild() lets a row's own callback refresh the popover in place - (e.g. after toggling hidden, or removing an item) instead of only - refreshing next time it's reopened.""" + """build_popover(rebuild, close) returns the popover's content + widget; rebuild() lets a row's own callback refresh the popover + in place (e.g. after toggling hidden, or removing an item) + instead of only refreshing next time it's reopened. close() + closes the popover outright, for an action that opens its own + modal dialog or arms map-click placement, where the popover + staying open on top just holds onto focus that dialog/the map + should have instead (see _add_row's use of it).""" button = Gtk.MenuButton(label=label) popover = Gtk.Popover() popover.set_size_request(280, -1) button.set_popover(popover) def rebuild(): - popover.set_child(build_popover(rebuild)) + popover.set_child(build_popover(rebuild, popover.popdown)) popover.connect("show", lambda _p: rebuild()) return button @@ -716,7 +725,7 @@ class MainWindow(Adw.ApplicationWindow): self.cursor_label.set_label(coord.label()) # -- Spotters -------------------------------------------------------------- - def _build_spotters_popover(self, rebuild) -> Gtk.Widget: + def _build_spotters_popover(self, rebuild, close) -> Gtk.Widget: box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) box.set_margin_top(6) box.set_margin_bottom(6) @@ -742,7 +751,7 @@ class MainWindow(Adw.ApplicationWindow): on_submit=lambda loc, id_, _t: self._add_spotter(loc, id_), show_id=True, id_placeholder=f"ID (blank = auto, next: {self.board.next_spotter_id()})", - ))) + ), close)) return box def _add_spotter(self, location: Location, id_text: str | None) -> None: @@ -762,7 +771,7 @@ class MainWindow(Adw.ApplicationWindow): rebuild() # -- Reference Points -------------------------------------------------------- - def _build_rp_popover(self, rebuild) -> Gtk.Widget: + def _build_rp_popover(self, rebuild, close) -> Gtk.Widget: box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) box.set_margin_top(6) box.set_margin_bottom(6) @@ -787,7 +796,7 @@ class MainWindow(Adw.ApplicationWindow): box.append(_add_row("Add RP", lambda: self._open_coord_dialog( title="Add reference point", on_submit=lambda loc, _id, _t: self._add_rp(loc), - ))) + ), close)) return box def _add_rp(self, location: Location) -> None: @@ -815,7 +824,7 @@ class MainWindow(Adw.ApplicationWindow): self.toast(f"{rp.name} converted to {new_target.name}.") # -- Targets ----------------------------------------------------------------- - def _build_targets_popover(self, rebuild) -> Gtk.Widget: + def _build_targets_popover(self, rebuild, close) -> Gtk.Widget: box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) box.set_margin_top(6) box.set_margin_bottom(6) @@ -844,7 +853,7 @@ class MainWindow(Adw.ApplicationWindow): on_submit=lambda loc, id_, type_: self._add_target(loc, id_, type_), show_id=True, show_type=True, - ))) + ), close)) return box def _add_target(self, location: Location, id_, type_) -> None: @@ -866,7 +875,7 @@ class MainWindow(Adw.ApplicationWindow): self.toast(f"{target.name} converted to {new_rp.name}.") # -- Units (Nest + Allies) ------------------------------------------------- - def _build_units_popover(self, rebuild) -> Gtk.Widget: + def _build_units_popover(self, rebuild, close) -> Gtk.Widget: """Your own side of the map: the Nest (always first, there's only ever one) plus every friendly contact ('FriendlyTank#1:', tracked entirely separately from Targets, see models.py's @@ -913,7 +922,7 @@ class MainWindow(Adw.ApplicationWindow): on_submit=lambda loc, id_, type_: self._add_ally(loc, id_, type_), show_id=True, show_type=True, - ))) + ), close)) return box def _add_ally(self, location: Location, id_, type_) -> None: @@ -926,7 +935,7 @@ class MainWindow(Adw.ApplicationWindow): rebuild() # -- Scout Flights ------------------------------------------------------------ - def _build_scout_flights_popover(self, rebuild) -> Gtk.Widget: + def _build_scout_flights_popover(self, rebuild, close) -> Gtk.Widget: box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) box.set_margin_top(6) box.set_margin_bottom(6) @@ -940,7 +949,7 @@ class MainWindow(Adw.ApplicationWindow): )) box.append(Gtk.Separator()) - box.append(_add_row("Add scout flight", self._add_scout_flight)) + box.append(_add_row("Add scout flight", self._add_scout_flight, close)) return box def _add_scout_flight(self) -> None: