Skip to content

Commit

Permalink
feat(core/tree): more intuitive selection of next focus pane after re…
Browse files Browse the repository at this point in the history
…move operation
  • Loading branch information
aravinda0 committed May 1, 2024
1 parent bad1593 commit 9489993
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
15 changes: 13 additions & 2 deletions src/qtile_bonsai/core/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,9 @@ def remove(
1. The `node` or an ancestor node that was the point of removal. This
branch is now unlinked from the main tree.
2. The sibling node of the removed node. Or `None` if no sibling exists.
3. The next pane under the sibling that ought to get focus.
3. The next pane that ought to get focus. Usually the sibling of the
removed node. But if the sibling is a Tab, then it is the MRU pane under
the nearest TC.
"""
rm_nodes = []
next_focus_pane = None
Expand All @@ -376,8 +378,17 @@ def remove(

rm_nodes.extend(br_rm_nodes)
if br_sib is not None:
# Find an appropriate pane to focus next. When a tab is closed, it's nicer
# to pick the MRU pane under the whole TC. eg. when we open some GUI
# application as a far-away tab from the 'current' window, it's nicer UX to
# return focus to the original window on closing it.
# Otherwise, it's generally nicest to give focus to the sibling node.
if isinstance(br_sib, Tab):
active_tc = br_sib.get_first_ancestor(TabContainer)
next_focus_pane = self.find_mru_pane(start_node=active_tc)
else:
next_focus_pane = self.find_mru_pane(start_node=br_sib)
rm_nodes.extend(self._do_post_removal_pruning(br_sib))
next_focus_pane = self.find_mru_pane()

self._notify_subscribers(TreeEvent.node_removed, rm_nodes)

Expand Down
21 changes: 18 additions & 3 deletions tests/unit/core/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -2091,13 +2091,29 @@ def test_when_all_panes_are_removed_then_tree_is_empty(self, tree: Tree):

assert tree.is_empty

def test_returns_mru_pane_as_next_focus_node(self, tree: Tree):
def test_when_non_tab_node_is_removed_then_pane_under_sibling_node_is_returned_as_next_focus_node(
self, tree: Tree
):
p1 = tree.tab()
p2 = tree.split(p1, "x")
p3 = tree.split(p2, "y")
p4 = tree.tab(p2, new_level=True)

tree.focus(p4)
tree.focus(p3)

_, _, p = tree.remove(p3)

assert p is p4

def test_when_tab_is_closed_then_returns_mru_pane_under_tc_as_next_focus_node(
self, tree: Tree
):
p1 = tree.tab()
p2 = tree.split(p1, "x")
_ = tree.tab()
p4 = tree.tab()

# focus from p2 to p4, skipping p3 sibling of p4
tree.focus(p2)
tree.focus(p4)

Expand Down Expand Up @@ -5588,7 +5604,6 @@ def test_when_node_is_sole_top_level_pane_under_subtab(
assert cb_add.mock_calls == []
assert cb_remove.mock_calls == [mock.call([sc, t])]

@pytest.mark.a
class TestWhenTCGetsPrunedAndRemnantsExistAlongSplitAxis:
def test_when_position_is_previous(self, tree: Tree, add_subscribers_to_tree):
tree.set_config("tab_bar.hide_when", "single_tab")
Expand Down

0 comments on commit 9489993

Please sign in to comment.