diff --git a/screen_locker/_ui_flows_sick_panel.py b/screen_locker/_ui_flows_sick_panel.py index 15e7a9c..15a1cbc 100644 --- a/screen_locker/_ui_flows_sick_panel.py +++ b/screen_locker/_ui_flows_sick_panel.py @@ -95,13 +95,21 @@ class SickPanelFlowMixin: def open_sick_panel(self) -> None: """Lay today's KeepPanel over every monitor's surface.""" overlay = self._new_sick_overlay() - for backdrop in overlay: + panels = [ build_sick_panel( backdrop, self._colors, on_saved=self._on_sick_panel_saved, on_cancel=self._close_sick_panel, ) + for backdrop in overlay + ] + # Into the panel on the primary monitor: left on the link, Tab and + # Enter would reach the hidden buttons of the screen underneath. Tk + # skips unmapped widgets when traversing, so lay the panel out first. + for panel in panels[:1]: + panel.update_idletasks() + (panel.tk_focusNext() or panel).focus_set() def _new_sick_overlay(self) -> FrameGroup: """Replace any open overlay with a fresh full-surface backdrop group.""" @@ -152,10 +160,12 @@ class SickPanelFlowMixin: fg=self._colors.palette.warning, bg=self._colors.palette.bg, ).pack(pady=self._colors.space("md")) - self._button( + back = self._button( box, "Back", bg=self._colors.palette.accent, command=self._close_sick_panel, width=12, - ).pack(pady=self._colors.space("sm")) + ) + back.pack(pady=self._colors.space("sm")) + back.first.focus_set() diff --git a/screen_locker/tests/test_sick_panel.py b/screen_locker/tests/test_sick_panel.py index 4a61423..6fb3ef1 100644 --- a/screen_locker/tests/test_sick_panel.py +++ b/screen_locker/tests/test_sick_panel.py @@ -99,8 +99,6 @@ class TestLink: locker._show_retry_and_sick("nope") buttons = mock_tk.Button.call_args_list texts = _texts(mock_tk.Button) - assert "I'm sick" in texts - assert LINK_TEXT in texts sick = next(c for c in buttons if c.kwargs.get("text") == "I'm sick") link = next(c for c in buttons if c.kwargs.get("text") == LINK_TEXT) assert sick.kwargs["command"] == locker.mark_sick_and_unlock @@ -111,7 +109,6 @@ class TestLink: self, locker: ScreenLocker, panels: list[FakePanel] ) -> None: locker.open_sick_panel() - assert len(panels) == len(locker.container.surfaces) panel = panels[0] assert panel.day == sickdays.today() assert panel.packed @@ -121,11 +118,13 @@ class TestLink: ) @pytest.mark.usefixtures("dual_output") - def test_every_monitor_gets_a_panel( + def test_every_monitor_gets_a_panel_and_the_primary_gets_focus( self, locker: ScreenLocker, panels: list[FakePanel] ) -> None: locker.open_sick_panel() assert len(panels) == 2 + panels[0].parent.tk_focusNext.return_value.focus_set.assert_called_once_with() + panels[1].parent.tk_focusNext.return_value.focus_set.assert_not_called() def test_reopening_closes_the_previous_panel( self, locker: ScreenLocker, panels: list[FakePanel] @@ -189,6 +188,7 @@ class TestSaved: locker.close.assert_not_called() backdrop.destroy.assert_called_once_with() assert KEPT_NOTE in _texts(mock_tk.Label) + mock_tk.Button.return_value.focus_set.assert_called_once_with() back = next( c for c in mock_tk.Button.call_args_list if c.kwargs.get("text") == "Back" )