diff options
Diffstat (limited to 'zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs')
-rw-r--r-- | zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs | 445 |
1 files changed, 302 insertions, 143 deletions
diff --git a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs index e34164f9e..8fc40d2b4 100644 --- a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs +++ b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs @@ -1,5 +1,6 @@ use super::is_inside_viewport; use super::pane_resizer::PaneResizer; +use super::stacked_panes::StackedPanes; use crate::tab::{MIN_TERMINAL_HEIGHT, MIN_TERMINAL_WIDTH}; use crate::{panes::PaneId, tab::Pane}; use std::cmp::Reverse; @@ -49,42 +50,32 @@ impl<'a> TiledPaneGrid<'a> { } } - /// Calculates an area for each pane and sums them all. - /// - /// Returns the product of "rows * columns", summed across all panes. - #[cfg(debug_assertions)] - fn total_panes_area(&self) -> f64 { - let mut summed_area: f64 = 0.0; - - for pane in self.panes.clone().borrow().values() { - let geom = pane.current_geom(); - summed_area += match (geom.rows.as_percent(), geom.cols.as_percent()) { - (Some(rows), Some(cols)) => rows * cols, - _ => continue, - }; - } - - summed_area / (100.0 * 100.0) - } - pub fn layout(&mut self, direction: SplitDirection, space: usize) -> Result<()> { let mut pane_resizer = PaneResizer::new(self.panes.clone()); pane_resizer.layout(direction, space) } + fn get_pane_geom(&self, pane_id: &PaneId) -> Option<PaneGeom> { + let panes = self.panes.borrow(); + let pane_to_check = panes.get(pane_id)?; + let pane_geom = pane_to_check.current_geom(); + if pane_geom.is_stacked { + StackedPanes::new(self.panes.clone()).position_and_size_of_stack(&pane_id) + } else { + Some(pane_geom) + } + } fn pane_is_flexible(&self, direction: SplitDirection, pane_id: &PaneId) -> Result<bool> { let err_context = || format!("failed to determine if pane {pane_id:?} is flexible in {direction:?}"); - let panes = self.panes.borrow(); - let pane_to_check = panes - .get(pane_id) + let pane_geom = self + .get_pane_geom(pane_id) .with_context(|| no_pane_id(pane_id)) .with_context(err_context)?; - let geom = pane_to_check.current_geom(); Ok(!match direction { - SplitDirection::Vertical => geom.rows, - SplitDirection::Horizontal => geom.cols, + SplitDirection::Vertical => pane_geom.rows, + SplitDirection::Horizontal => pane_geom.cols, } .is_fixed()) } @@ -99,12 +90,12 @@ impl<'a> TiledPaneGrid<'a> { let neighbor_terminal_borders: HashSet<_> = if direction.is_horizontal() { neighbor_terminals .iter() - .map(|t| self.panes.borrow().get(t).unwrap().y()) + .filter_map(|t| self.get_pane_geom(t).map(|p| p.y)) .collect() } else { neighbor_terminals .iter() - .map(|t| self.panes.borrow().get(t).unwrap().x()) + .filter_map(|t| self.get_pane_geom(t).map(|p| p.x)) .collect() }; @@ -300,12 +291,12 @@ impl<'a> TiledPaneGrid<'a> { let neighbor_terminal_borders: HashSet<_> = if direction.is_horizontal() { neighbor_terminals .iter() - .map(|t| self.panes.borrow().get(t).unwrap().y()) + .filter_map(|p| self.get_pane_geom(p).map(|p| p.y)) .collect() } else { neighbor_terminals .iter() - .map(|t| self.panes.borrow().get(t).unwrap().x()) + .filter_map(|p| self.get_pane_geom(p).map(|p| p.x)) .collect() }; @@ -408,34 +399,34 @@ impl<'a> TiledPaneGrid<'a> { ]; // For the borrow checker { - let panes = self.panes.borrow(); - let active_pane = panes - .get(pane_id) + // let panes = self.panes.borrow(); + let active_pane = self + .get_pane_geom(pane_id) .with_context(|| no_pane_id(pane_id)) .with_context(err_context)?; for p_id in self.viewport_pane_ids_directly_below(pane_id) { - let pane = panes - .get(&p_id) + let pane = self + .get_pane_geom(&p_id) .with_context(|| no_pane_id(&p_id)) .with_context(err_context)?; - if active_pane.x() + active_pane.cols() == pane.x() { + if active_pane.x + active_pane.cols.as_usize() == pane.x { // right aligned aligned_panes[0] = Some(p_id); - } else if active_pane.x() == pane.x() + pane.cols() { + } else if active_pane.x == pane.x + pane.cols.as_usize() { // left aligned aligned_panes[1] = Some(p_id); } } for p_id in self.viewport_pane_ids_directly_above(pane_id) { - let pane = panes - .get(&p_id) + let pane = self + .get_pane_geom(&p_id) .with_context(|| no_pane_id(&p_id)) .with_context(err_context)?; - if active_pane.x() + active_pane.cols() == pane.x() { + if active_pane.x + active_pane.cols.as_usize() == pane.x { // right aligned aligned_panes[2] = Some(p_id); - } else if active_pane.x() == pane.x() + pane.cols() { + } else if active_pane.x == pane.x + pane.cols.as_usize() { // left aligned aligned_panes[3] = Some(p_id); } @@ -467,8 +458,15 @@ impl<'a> TiledPaneGrid<'a> { ..strategy }; - if self.can_change_pane_size(pane_id, &main_strategy, change_by)? - && self.can_change_pane_size(pane_id, &sub_strategy, change_by)? + // TODO: instead of unwrap_or(false) here we need to do the same with the fixed + // panes error above, only make sure that we only error if we cannot resize in + // any directions and have blocking fixed panes + if self + .can_change_pane_size(pane_id, &main_strategy, change_by) + .unwrap_or(false) + && self + .can_change_pane_size(pane_id, &sub_strategy, change_by) + .unwrap_or(false) { let result = self .change_pane_size(pane_id, &main_strategy, change_by) @@ -512,16 +510,6 @@ impl<'a> TiledPaneGrid<'a> { return Ok(false); } - #[cfg(debug_assertions)] - { - let area = self.total_panes_area() * 100.0; - debug_assert!( - f64::abs(area - 100.0) < 1.0, // Tolerate a little rounding error - "area consumed by panes doesn't fill the viewport! Total area is {area} % - During operation: '{strategy}', on pane {pane_id:?}", - ); - } - Ok(true) } @@ -529,16 +517,15 @@ impl<'a> TiledPaneGrid<'a> { let err_context = || format!("failed to determine if pane {pane_id:?} can reduce width by {reduce_by} %"); - let panes = self.panes.borrow(); - let pane = panes - .get(pane_id) + let pane = self + .get_pane_geom(pane_id) .with_context(|| no_pane_id(pane_id)) .with_context(err_context)?; - let current_fixed_cols = pane.position_and_size().cols.as_usize(); + let current_fixed_cols = pane.cols.as_usize(); let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize; - if current_fixed_cols.saturating_sub(will_reduce_by) < pane.min_width() { + if current_fixed_cols.saturating_sub(will_reduce_by) < MIN_TERMINAL_WIDTH { Ok(false) - } else if let Some(cols) = pane.position_and_size().cols.as_percent() { + } else if let Some(cols) = pane.cols.as_percent() { Ok(cols - reduce_by >= RESIZE_PERCENT) } else { Ok(false) @@ -549,16 +536,20 @@ impl<'a> TiledPaneGrid<'a> { format!("failed to determine if pane {pane_id:?} can reduce height by {reduce_by} %") }; - let panes = self.panes.borrow(); - let pane = panes - .get(pane_id) + let pane = self + .get_pane_geom(pane_id) .with_context(|| no_pane_id(pane_id)) .with_context(err_context)?; - let current_fixed_rows = pane.position_and_size().rows.as_usize(); + let min_terminal_height = if pane.is_stacked { + StackedPanes::new(self.panes.clone()).min_stack_height(pane_id)? + } else { + MIN_TERMINAL_HEIGHT + }; + let current_fixed_rows = pane.rows.as_usize(); let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize; - if current_fixed_rows.saturating_sub(will_reduce_by) < pane.min_height() { + if current_fixed_rows.saturating_sub(will_reduce_by) < min_terminal_height { Ok(false) - } else if let Some(rows) = pane.position_and_size().rows.as_percent() { + } else if let Some(rows) = pane.rows.as_percent() { Ok(rows - reduce_by >= RESIZE_PERCENT) } else { Ok(false) @@ -567,26 +558,70 @@ impl<'a> TiledPaneGrid<'a> { fn reduce_pane_height(&mut self, id: &PaneId, percent: f64) { if self.can_reduce_pane_height(id, percent).unwrap() { - let mut panes = self.panes.borrow_mut(); - let terminal = panes.get_mut(id).unwrap(); - terminal.reduce_height(percent); + let current_pane_is_stacked = self + .panes + .borrow() + .get(id) + .unwrap() + .current_geom() + .is_stacked; + if current_pane_is_stacked { + let _ = StackedPanes::new(self.panes.clone()).reduce_stack_height(&id, percent); + } else { + let mut panes = self.panes.borrow_mut(); + let terminal = panes.get_mut(id).unwrap(); + terminal.reduce_height(percent); + } } } fn increase_pane_height(&mut self, id: &PaneId, percent: f64) { - let mut panes = self.panes.borrow_mut(); - let terminal = panes.get_mut(id).unwrap(); - terminal.increase_height(percent); + let current_pane_is_stacked = self + .panes + .borrow() + .get(id) + .unwrap() + .current_geom() + .is_stacked; + if current_pane_is_stacked { + let _ = StackedPanes::new(self.panes.clone()).increase_stack_height(&id, percent); + } else { + let mut panes = self.panes.borrow_mut(); + let terminal = panes.get_mut(id).unwrap(); + terminal.increase_height(percent); + } } fn increase_pane_width(&mut self, id: &PaneId, percent: f64) { - let mut panes = self.panes.borrow_mut(); - let terminal = panes.get_mut(id).unwrap(); - terminal.increase_width(percent); + let current_pane_is_stacked = self + .panes + .borrow() + .get(id) + .unwrap() + .current_geom() + .is_stacked; + if current_pane_is_stacked { + let _ = StackedPanes::new(self.panes.clone()).increase_stack_width(&id, percent); + } else { + let mut panes = self.panes.borrow_mut(); + let pane = panes.get_mut(id).unwrap(); + pane.increase_width(percent); + } } fn reduce_pane_width(&mut self, id: &PaneId, percent: f64) { if self.can_reduce_pane_width(id, percent).unwrap() { - let mut panes = self.panes.borrow_mut(); - let terminal = panes.get_mut(id).unwrap(); - terminal.reduce_width(percent); + let current_pane_is_stacked = self + .panes + .borrow() + .get(id) + .unwrap() + .current_geom() + .is_stacked; + if current_pane_is_stacked { + let _ = StackedPanes::new(self.panes.clone()).reduce_stack_width(&id, percent); + } else { + let mut panes = self.panes.borrow_mut(); + let terminal = panes.get_mut(id).unwrap(); + terminal.reduce_width(percent); + } } } @@ -597,27 +632,38 @@ impl<'a> TiledPaneGrid<'a> { fn pane_ids_directly_next_to(&self, id: &PaneId, direction: &Direction) -> Result<Vec<PaneId>> { let err_context = || format!("failed to find panes {direction} from pane {id:?}"); - let panes = self.panes.borrow(); let mut ids = vec![]; - let terminal_to_check = panes - .get(id) + let pane_geom_to_check = self + .get_pane_geom(id) .with_context(|| no_pane_id(id)) .with_context(err_context)?; - for (&pid, terminal) in panes.iter() { + let panes = self.panes.borrow(); + let mut seen = HashSet::new(); + for pid in panes.keys() { + let pane = self + .get_pane_geom(pid) + .with_context(|| no_pane_id(id)) + .with_context(err_context)?; + if seen.contains(&pane) { + continue; + } else { + seen.insert(pane); + } if match direction { - Direction::Left => (terminal.x() + terminal.cols()) == terminal_to_check.x(), + Direction::Left => (pane.x + pane.cols.as_usize()) == pane_geom_to_check.x, Direction::Down => { - terminal.y() == (terminal_to_check.y() + terminal_to_check.rows()) + pane.y == (pane_geom_to_check.y + pane_geom_to_check.rows.as_usize()) }, - Direction::Up => (terminal.y() + terminal.rows()) == terminal_to_check.y(), + Direction::Up => (pane.y + pane.rows.as_usize()) == pane_geom_to_check.y, Direction::Right => { - terminal.x() == (terminal_to_check.x() + terminal_to_check.cols()) + pane.x == (pane_geom_to_check.x + pane_geom_to_check.cols.as_usize()) }, } { - ids.push(pid); + ids.push(*pid); } } + Ok(ids) } @@ -629,29 +675,38 @@ impl<'a> TiledPaneGrid<'a> { ) -> Result<Vec<PaneId>> { let err_context = || format!("failed to find panes aligned {direction} with {pane_id:?}"); - let panes = self.panes.borrow(); - let pane_to_check = panes - .get(pane_id) + let pane_to_check = self + .get_pane_geom(pane_id) .with_context(|| no_pane_id(pane_id)) .with_context(err_context)?; let mut result = vec![]; - for (p_id, pane) in panes.iter() { - if p_id == pane_id { + let panes = self.panes.borrow(); + let mut seen = HashSet::new(); + for (pid, _pane) in panes.iter() { + let pane = self + .get_pane_geom(pid) + .with_context(|| no_pane_id(pane_id)) + .with_context(err_context)?; + if seen.contains(&pane) || pid == pane_id { continue; + } else { + seen.insert(pane); } if match direction { - Direction::Left => pane.x() == pane_to_check.x(), + Direction::Left => pane.x == pane_to_check.x, Direction::Down => { - (pane.y() + pane.rows()) == (pane_to_check.y() + pane_to_check.rows()) + (pane.y + pane.rows.as_usize()) + == (pane_to_check.y + pane_to_check.rows.as_usize()) }, - Direction::Up => pane.y() == pane_to_check.y(), + Direction::Up => pane.y == pane_to_check.y, Direction::Right => { - (pane.x() + pane.cols()) == (pane_to_check.x() + pane_to_check.cols()) + (pane.x + pane.cols.as_usize()) + == (pane_to_check.x + pane_to_check.cols.as_usize()) }, } { - result.push(*p_id) + result.push(*pid) } } Ok(result) @@ -671,9 +726,8 @@ impl<'a> TiledPaneGrid<'a> { let input_error = anyhow!("Invalid combination of alignment ({alignment}) and direction ({direction})"); - let panes = self.panes.borrow(); - let pane_to_check = panes - .get(id) + let pane_to_check = self + .get_pane_geom(id) .with_context(|| no_pane_id(id)) .with_context(err_context)?; let mut result = vec![]; @@ -682,7 +736,7 @@ impl<'a> TiledPaneGrid<'a> { .and_then(|pane_ids| { Ok(pane_ids .iter() - .map(|p_id| panes.get(p_id).unwrap()) // <-- TODO: Bad unwrap! + .filter_map(|p_id| self.get_pane_geom(p_id).map(|pane_geom| (*p_id, pane_geom))) .collect()) }) .with_context(err_context)?; @@ -693,23 +747,26 @@ impl<'a> TiledPaneGrid<'a> { use Direction::Up as U; match (alignment, direction) { - (&R, &U) | (&L, &U) => aligned_panes.sort_by_key(|a| Reverse(a.y())), - (&R, &D) | (&L, &D) => aligned_panes.sort_by_key(|a| a.y()), - (&D, &L) | (&U, &L) => aligned_panes.sort_by_key(|a| Reverse(a.x())), - (&D, &R) | (&U, &R) => aligned_panes.sort_by_key(|a| a.x()), + (&R, &U) | (&L, &U) => aligned_panes.sort_by_key(|(_, a)| Reverse(a.y)), + (&R, &D) | (&L, &D) => aligned_panes.sort_by_key(|(_, a)| a.y), + (&D, &L) | (&U, &L) => aligned_panes.sort_by_key(|(_, a)| Reverse(a.x)), + (&D, &R) | (&U, &R) => aligned_panes.sort_by_key(|(_, a)| a.x), _ => return Err(input_error).with_context(err_context), }; - for pane in aligned_panes { - let pane_to_check = result.last().unwrap_or(&pane_to_check); + for (pid, pane) in aligned_panes { + let pane_to_check = result + .last() + .map(|(_pid, pane)| pane) + .unwrap_or(&pane_to_check); if match (alignment, direction) { - (&R, &U) | (&L, &U) => (pane.y() + pane.rows()) == pane_to_check.y(), - (&R, &D) | (&L, &D) => pane.y() == (pane_to_check.y() + pane_to_check.rows()), - (&D, &L) | (&U, &L) => (pane.x() + pane.cols()) == pane_to_check.x(), - (&D, &R) | (&U, &R) => pane.x() == (pane_to_check.x() + pane_to_check.cols()), + (&R, &U) | (&L, &U) => (pane.y + pane.rows.as_usize()) == pane_to_check.y, + (&R, &D) | (&L, &D) => pane.y == (pane_to_check.y + pane_to_check.rows.as_usize()), + (&D, &L) | (&U, &L) => (pane.x + pane.cols.as_usize()) == pane_to_check.x, + (&D, &R) | (&U, &R) => pane.x == (pane_to_check.x + pane_to_check.cols.as_usize()), _ => return Err(input_error).with_context(err_context), } { - result.push(pane); + result.push((pid, pane)); } } @@ -720,12 +777,12 @@ impl<'a> TiledPaneGrid<'a> { &R => self.viewport.x + self.viewport.cols, }; - for pane in &result { + for (_, pane) in &result { let pane_boundary = match direction { - &L => pane.x() + pane.cols(), - &D => pane.y(), - &U => pane.y() + pane.rows(), - &R => pane.x(), + &L => pane.x + pane.cols.as_usize(), + &D => pane.y, + &U => pane.y + pane.rows.as_usize(), + &R => pane.x, }; if border.get(&pane_boundary).is_some() { match direction { @@ -742,24 +799,24 @@ impl<'a> TiledPaneGrid<'a> { } } } - result.retain(|pane| match direction { - &L => pane.x() >= resize_border, - &D => (pane.y() + pane.rows()) <= resize_border, - &U => pane.y() >= resize_border, - &R => (pane.x() + pane.cols()) <= resize_border, + result.retain(|(_pid, pane)| match direction { + &L => pane.x >= resize_border, + &D => (pane.y + pane.rows.as_usize()) <= resize_border, + &U => pane.y >= resize_border, + &R => (pane.x + pane.cols.as_usize()) <= resize_border, }); let resize_border = if result.is_empty() { match direction { - &L => pane_to_check.x(), - &D => pane_to_check.y() + pane_to_check.rows(), - &U => pane_to_check.y(), - &R => pane_to_check.x() + pane_to_check.cols(), + &L => pane_to_check.x, + &D => pane_to_check.y + pane_to_check.rows.as_usize(), + &U => pane_to_check.y, + &R => pane_to_check.x + pane_to_check.cols.as_usize(), } } else { resize_border }; - let pane_ids: Vec<PaneId> = result.iter().map(|t| t.pid()).collect(); + let pane_ids: Vec<PaneId> = result.iter().map(|(pid, _t)| *pid).collect(); Ok((resize_border, pane_ids)) } @@ -770,9 +827,8 @@ impl<'a> TiledPaneGrid<'a> { left_border_x: usize, right_border_x: usize, ) -> bool { - let panes = self.panes.borrow(); - let pane = panes.get(id).unwrap(); - pane.x() >= left_border_x && pane.x() + pane.cols() <= right_border_x + let pane = self.get_pane_geom(id).unwrap(); + pane.x >= left_border_x && pane.x + pane.cols.as_usize() <= right_border_x } fn pane_is_between_horizontal_borders( @@ -781,9 +837,8 @@ impl<'a> TiledPaneGrid<'a> { top_border_y: usize, bottom_border_y: usize, ) -> bool { - let panes = self.panes.borrow(); - let pane = panes.get(id).unwrap(); - pane.y() >= top_border_y && pane.y() + pane.rows() <= bottom_border_y + let pane = self.get_pane_geom(id).unwrap(); + pane.y >= top_border_y && pane.y + pane.rows.as_usize() <= bottom_border_y } fn viewport_pane_ids_directly_above(&self, pane_id: &PaneId) -> Vec<PaneId> { @@ -863,7 +918,7 @@ impl<'a> TiledPaneGrid<'a> { .filter(|(_, p)| p.selectable()) .map(|(p_id, p)| (*p_id, p)) .collect(); - let next_index = panes + let next_pane = panes .iter() .enumerate() .filter(|(_, (_, c))| { @@ -871,9 +926,83 @@ impl<'a> TiledPaneGrid<'a> { && c.horizontally_overlaps_with(Box::as_ref(current_pane)) }) .max_by_key(|(_, (_, c))| c.active_at()) - .map(|(_, (pid, _))| pid) - .copied(); - next_index + .map(|(_, (_, pane))| pane); + let next_pane_is_stacked = next_pane + .map(|p| p.current_geom().is_stacked) + .unwrap_or(false); + if next_pane_is_stacked { + if let Some(next_pane_id) = next_pane.map(|p| p.pid()) { + return StackedPanes::new(self.panes.clone()) + .flexible_pane_id_in_stack(&next_pane_id); + } + } + next_pane.map(|p| p.pid()) + } + pub fn progress_stack_up_if_in_stack(&mut self, source_pane_id: &PaneId) -> Option<PaneId> { + let destination_pane_id_in_stack = { + let panes = self.panes.borrow(); + let source_pane = panes.get(source_pane_id)?; + let pane_list: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + let destination_pane_id = pane_list + .iter() + .enumerate() + .filter(|(_, (_, c))| { + c.is_directly_above(Box::as_ref(source_pane)) + && c.vertically_overlaps_with(Box::as_ref(source_pane)) + && c.current_geom().is_stacked + }) + .max_by_key(|(_, (_, c))| c.active_at()) + .map(|(_, (pid, _))| pid) + .copied(); + destination_pane_id + }; + + match destination_pane_id_in_stack { + Some(destination_pane_id) => { + StackedPanes::new(self.panes.clone()) + .move_up(source_pane_id, &destination_pane_id) + .ok()?; + Some(destination_pane_id) + }, + None => None, + } + } + pub fn progress_stack_down_if_in_stack(&mut self, source_pane_id: &PaneId) -> Option<PaneId> { + let destination_pane_id_in_stack = { + let panes = self.panes.borrow(); + let source_pane = panes.get(source_pane_id)?; + let pane_list: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + let destination_pane_id = pane_list + .iter() + .enumerate() + .filter(|(_, (_, c))| { + c.is_directly_below(Box::as_ref(source_pane)) + && c.vertically_overlaps_with(Box::as_ref(source_pane)) + && c.current_geom().is_stacked + }) + .max_by_key(|(_, (_, c))| c.active_at()) + .map(|(_, (pid, _))| pid) + .copied(); + destination_pane_id + }; + + match destination_pane_id_in_stack { + Some(destination_pane_id) => { + StackedPanes::new(self.panes.clone()) + .move_down(source_pane_id, &destination_pane_id) + .ok()?; + Some(destination_pane_id) + }, + None => None, + } } pub fn next_selectable_pane_id_below(&self, current_pane_id: &PaneId) -> Option<PaneId> { let panes = self.panes.borrow(); @@ -889,6 +1018,7 @@ impl<'a> TiledPaneGrid<'a> { .filter(|(_, (_, c))| { c.is_directly_below(Box::as_ref(current_pane)) && c.vertically_overlaps_with(Box::as_ref(current_pane)) + && !c.current_geom().is_stacked }) .max_by_key(|(_, (_, c))| c.active_at()) .map(|(_, (pid, _))| pid) @@ -909,6 +1039,7 @@ impl<'a> TiledPaneGrid<'a> { .filter(|(_, (_, c))| { c.is_directly_above(Box::as_ref(current_pane)) && c.vertically_overlaps_with(Box::as_ref(current_pane)) + && !c.current_geom().is_stacked }) .max_by_key(|(_, (_, c))| c.active_at()) .map(|(_, (pid, _))| pid) @@ -923,7 +1054,7 @@ impl<'a> TiledPaneGrid<'a> { .filter(|(_, p)| p.selectable()) |