diff options
Diffstat (limited to 'src/app/layout_manager.rs')
-rw-r--r-- | src/app/layout_manager.rs | 133 |
1 files changed, 90 insertions, 43 deletions
diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 9b88fb8a..61d17924 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -997,9 +997,9 @@ Supported widget names: // --- New stuff --- /// Represents a row in the layout tree. -#[derive(PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct RowLayout { - last_selected_index: usize, + last_selected: Option<NodeId>, pub parent_rule: LayoutRule, pub bound: Rect, } @@ -1007,7 +1007,7 @@ pub struct RowLayout { impl RowLayout { fn new(parent_rule: LayoutRule) -> Self { Self { - last_selected_index: 0, + last_selected: None, parent_rule, bound: Rect::default(), } @@ -1015,9 +1015,9 @@ impl RowLayout { } /// Represents a column in the layout tree. -#[derive(PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct ColLayout { - last_selected_index: usize, + last_selected: Option<NodeId>, pub parent_rule: LayoutRule, pub bound: Rect, } @@ -1025,7 +1025,7 @@ pub struct ColLayout { impl ColLayout { fn new(parent_rule: LayoutRule) -> Self { Self { - last_selected_index: 0, + last_selected: None, parent_rule, bound: Rect::default(), } @@ -1033,7 +1033,7 @@ impl ColLayout { } /// Represents a widget in the layout tree. -#[derive(PartialEq, Eq, Clone, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Default)] pub struct WidgetLayout { pub bound: Rect, } @@ -1042,7 +1042,7 @@ pub struct WidgetLayout { /// - [`LayoutNode::Row`] (a non-leaf that distributes its children horizontally) /// - [`LayoutNode::Col`] (a non-leaf node that distributes its children vertically) /// - [`LayoutNode::Widget`] (a leaf node that contains the ID of the widget it is associated with) -#[derive(PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum LayoutNode { /// A non-leaf that distributes its children horizontally Row(RowLayout), @@ -1382,6 +1382,8 @@ pub fn create_layout_tree( )); } + correct_layout_last_selections(&mut arena, selected); + Ok(LayoutCreationOutput { layout_tree: arena, root: root_id, @@ -1391,6 +1393,35 @@ pub fn create_layout_tree( }) } +/// We may have situations where we also have to make sure the correct layout indices are selected. +/// For example, when we select a widget by clicking, we want to update the layout so that it's as if a user +/// manually moved to it via keybinds. +/// +/// We can do this by just going through the ancestors, starting from the widget itself. +pub fn correct_layout_last_selections(arena: &mut Arena<LayoutNode>, selected: NodeId) { + let mut selected_ancestors = selected.ancestors(&arena).collect::<Vec<_>>(); + let prev_node = selected_ancestors.pop(); + if let Some(mut prev_node) = prev_node { + for node in selected_ancestors { + if let Some(layout_node) = arena.get_mut(node).map(|n| n.get_mut()) { + match layout_node { + LayoutNode::Row(RowLayout { last_selected, .. }) + | LayoutNode::Col(ColLayout { last_selected, .. }) => { + *last_selected = Some(prev_node); + } + LayoutNode::Widget(_) => {} + } + } + prev_node = node; + } + } +} + +pub enum MoveWidgetResult { + ForceRedraw(NodeId), + NodeId(NodeId), +} + /// Attempts to find and return the selected [`BottomWidgetId`] after moving in a direction. /// /// Note this function assumes a properly built tree - if not, bad things may happen! We generally assume that: @@ -1399,7 +1430,7 @@ pub fn create_layout_tree( pub fn move_widget_selection( layout_tree: &mut Arena<LayoutNode>, current_widget: &mut TmpBottomWidget, current_widget_id: NodeId, direction: MovementDirection, -) -> NodeId { +) -> MoveWidgetResult { // We first give our currently-selected widget a chance to react to the movement - it may handle it internally! let handled = match direction { MovementDirection::Left => current_widget.handle_widget_selection_left(), @@ -1408,16 +1439,18 @@ pub fn move_widget_selection( MovementDirection::Down => current_widget.handle_widget_selection_down(), }; + // TODO: Do testing. + match handled { SelectionAction::Handled => { // If it was handled by the widget, then we don't have to do anything - return the current one. - current_widget_id + MoveWidgetResult::ForceRedraw(current_widget_id) } SelectionAction::NotHandled => { /// Keeps traversing up the `layout_tree` until it hits a parent where `current_id` is a child and parent /// is a [`LayoutNode::Row`], returning its parent's [`NodeId`] and the child's [`NodeId`] (in that order). /// If this crawl fails (i.e. hits a root, it is an invalid tree for some reason), it returns [`None`]. - fn find_first_row( + fn find_parent_row( layout_tree: &Arena<LayoutNode>, current_id: NodeId, ) -> Option<(NodeId, NodeId)> { layout_tree @@ -1430,7 +1463,7 @@ pub fn move_widget_selection( }) .and_then(|(parent_id, parent_node)| match parent_node.get() { LayoutNode::Row(_) => Some((parent_id, current_id)), - LayoutNode::Col(_) => find_first_row(layout_tree, parent_id), + LayoutNode::Col(_) => find_parent_row(layout_tree, parent_id), LayoutNode::Widget(_) => None, }) } @@ -1438,7 +1471,7 @@ pub fn move_widget_selection( /// Keeps traversing up the `layout_tree` until it hits a parent where `current_id` is a child and parent /// is a [`LayoutNode::Col`], returning its parent's [`NodeId`] and the child's [`NodeId`] (in that order). /// If this crawl fails (i.e. hits a root, it is an invalid tree for some reason), it returns [`None`]. - fn find_first_col( + fn find_parent_col( layout_tree: &Arena<LayoutNode>, current_id: NodeId, ) -> Option<(NodeId, NodeId)> { layout_tree @@ -1450,7 +1483,7 @@ pub fn move_widget_selection( .map(|parent_node| (parent_id, parent_node)) }) .and_then(|(parent_id, parent_node)| match parent_node.get() { - LayoutNode::Row(_) => find_first_col(layout_tree, parent_id), + LayoutNode::Row(_) => find_parent_col(layout_tree, parent_id), LayoutNode::Col(_) => Some((parent_id, current_id)), LayoutNode::Widget(_) => None, }) @@ -1461,21 +1494,19 @@ pub fn move_widget_selection( if let Some(current_node) = layout_tree.get(current_id) { match current_node.get() { LayoutNode::Row(RowLayout { - last_selected_index, + last_selected, parent_rule: _, bound: _, }) | LayoutNode::Col(ColLayout { - last_selected_index, + last_selected, parent_rule: _, bound: _, }) => { - if let Some(next_child) = - current_id.children(layout_tree).nth(*last_selected_index) - { + if let Some(next_child) = *last_selected { descend_to_leaf(layout_tree, next_child) } else { - current_id + current_node.first_child().unwrap_or(current_id) } } LayoutNode::Widget(_) => { @@ -1493,7 +1524,7 @@ pub fn move_widget_selection( // on the tree layout to help us decide where to go. // Movement logic is inspired by i3. When we enter a new column/row, we go to the *last* selected // element; if we can't, go to the nearest one. - match direction { + let proposed_id = match direction { MovementDirection::Left => { // When we move "left": // 1. Look for the parent of the current widget. @@ -1513,7 +1544,8 @@ pub fn move_widget_selection( fn find_left( layout_tree: &mut Arena<LayoutNode>, current_id: NodeId, ) -> NodeId { - if let Some((parent_id, child_id)) = find_first_row(layout_tree, current_id) + if let Some((parent_id, child_id)) = + find_parent_row(layout_tree, current_id) { if let Some(prev_sibling) = child_id.preceding_siblings(layout_tree).nth(1) @@ -1521,16 +1553,17 @@ pub fn move_widget_selection( // Subtract one from the currently selected index... if let Some(parent) = layout_tree.get_mut(parent_id) { if let LayoutNode::Row(row) = parent.get_mut() { - row.last_selected_index = - row.last_selected_index.saturating_sub(1); + row.last_selected = Some(prev_sibling); } } // Now descend downwards! descend_to_leaf(layout_tree, prev_sibling) - } else { + } else if parent_id != current_id { // Darn, we can't go further back! Recurse on this ID. - find_left(layout_tree, child_id) + find_left(layout_tree, parent_id) + } else { + current_id } } else { // Failed, just return the current ID. @@ -1546,23 +1579,26 @@ pub fn move_widget_selection( fn find_right( layout_tree: &mut Arena<LayoutNode>, current_id: NodeId, ) -> NodeId { - if let Some((parent_id, child_id)) = find_first_row(layout_tree, current_id) + if let Some((parent_id, child_id)) = + find_parent_row(layout_tree, current_id) { - if let Some(prev_sibling) = + if let Some(following_sibling) = child_id.following_siblings(layout_tree).nth(1) { // Add one to the currently selected index... if let Some(parent) = layout_tree.get_mut(parent_id) { if let LayoutNode::Row(row) = parent.get_mut() { - row.last_selected_index += 1; + row.last_selected = Some(following_sibling); } } // Now descend downwards! - descend_to_leaf(layout_tree, prev_sibling) - } else { + descend_to_leaf(layout_tree, following_sibling) + } else if parent_id != current_id { // Darn, we can't go further back! Recurse on this ID. - find_right(layout_tree, child_id) + find_right(layout_tree, parent_id) + } else { + current_id } } else { // Failed, just return the current ID. @@ -1578,7 +1614,8 @@ pub fn move_widget_selection( fn find_above( layout_tree: &mut Arena<LayoutNode>, current_id: NodeId, ) -> NodeId { - if let Some((parent_id, child_id)) = find_first_col(layout_tree, current_id) + if let Some((parent_id, child_id)) = + find_parent_col(layout_tree, current_id) { if let Some(prev_sibling) = child_id.preceding_siblings(layout_tree).nth(1) @@ -1586,16 +1623,17 @@ pub fn move_widget_selection( // Subtract one from the currently selected index... if let Some(parent) = layout_tree.get_mut(parent_id) { if let LayoutNode::Col(row) = parent.get_mut() { - row.last_selected_index = - row.last_selected_index.saturating_sub(1); + row.last_selected = Some(prev_sibling); } } // Now descend downwards! descend_to_leaf(layout_tree, prev_sibling) - } else { + } else if parent_id != current_id { // Darn, we can't go further back! Recurse on this ID. - find_above(layout_tree, child_id) + find_above(layout_tree, parent_id) + } else { + current_id } } else { // Failed, just return the current ID. @@ -1611,23 +1649,26 @@ pub fn move_widget_selection( fn find_below( layout_tree: &mut Arena<LayoutNode>, current_id: NodeId, ) -> NodeId { - if let Some((parent_id, child_id)) = find_first_col(layout_tree, current_id) + if let Some((parent_id, child_id)) = + find_parent_col(layout_tree, current_id) { - if let Some(prev_sibling) = + if let Some(following_sibling) = child_id.following_siblings(layout_tree).nth(1) { // Add one to the currently selected index... if let Some(parent) = layout_tree.get_mut(parent_id) { if let LayoutNode::Col(row) = parent.get_mut() { - row.last_selected_index += 1; + row.last_selected = Some(following_sibling); } } // Now descend downwards! - descend_to_leaf(layout_tree, prev_sibling) - } else { + descend_to_leaf(layout_tree, following_sibling) + } else if parent_id != current_id { // Darn, we can't go further back! Recurse on this ID. - find_below(layout_tree, child_id) + find_below(layout_tree, parent_id) + } else { + current_id } } else { // Failed, just return the current ID. @@ -1636,6 +1677,12 @@ pub fn move_widget_selection( } find_below(layout_tree, current_widget_id) } + }; + + if let Some(LayoutNode::Widget(_)) = layout_tree.get(proposed_id).map(|n| n.get()) { + MoveWidgetResult::NodeId(proposed_id) + } else { + MoveWidgetResult::NodeId(current_widget_id) } } } |