summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs
diff options
context:
space:
mode:
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.rs445
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())