diff options
Diffstat (limited to 'zellij-server/src/panes')
-rw-r--r-- | zellij-server/src/panes/floating_panes/floating_pane_grid.rs | 5 | ||||
-rw-r--r-- | zellij-server/src/panes/terminal_pane.rs | 14 | ||||
-rw-r--r-- | zellij-server/src/panes/tiled_panes/mod.rs | 121 | ||||
-rw-r--r-- | zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs | 119 |
4 files changed, 253 insertions, 6 deletions
diff --git a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs index 2245ee16a..55ea46dd5 100644 --- a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs +++ b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs @@ -766,6 +766,7 @@ fn half_size_middle_geom(space: &Viewport, offset: usize) -> PaneGeom { y: space.y + (space.rows as f64 / 4.0).round() as usize + offset, cols: Dimension::fixed(space.cols / 2), rows: Dimension::fixed(space.rows / 2), + is_stacked: false, }; geom.cols.set_inner(space.cols / 2); geom.rows.set_inner(space.rows / 2); @@ -778,6 +779,7 @@ fn half_size_top_left_geom(space: &Viewport, offset: usize) -> PaneGeom { y: space.y + 2 + offset, cols: Dimension::fixed(space.cols / 3), rows: Dimension::fixed(space.rows / 3), + is_stacked: false, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -790,6 +792,7 @@ fn half_size_top_right_geom(space: &Viewport, offset: usize) -> PaneGeom { y: space.y + 2 + offset, cols: Dimension::fixed(space.cols / 3), rows: Dimension::fixed(space.rows / 3), + is_stacked: false, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -802,6 +805,7 @@ fn half_size_bottom_left_geom(space: &Viewport, offset: usize) -> PaneGeom { y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset), cols: Dimension::fixed(space.cols / 3), rows: Dimension::fixed(space.rows / 3), + is_stacked: false, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -814,6 +818,7 @@ fn half_size_bottom_right_geom(space: &Viewport, offset: usize) -> PaneGeom { y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset), cols: Dimension::fixed(space.cols / 3), rows: Dimension::fixed(space.rows / 3), + is_stacked: false, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 0f29430fc..9cef98194 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -167,6 +167,10 @@ impl Pane for TerminalPane { } fn cursor_coordinates(&self) -> Option<(usize, usize)> { // (x, y) + if self.get_content_rows() < 1 || self.get_content_columns() < 1 { + // do not render cursor if there's no room for it + return None; + } let Offset { top, left, .. } = self.content_offset; self.grid .cursor_coordinates() @@ -285,6 +289,12 @@ impl Pane for TerminalPane { if self.should_render() { let content_x = self.get_content_x(); let content_y = self.get_content_y(); + let rows = self.get_content_rows(); + let columns = self.get_content_columns(); + if rows < 1 || columns < 1 { + // TODO: same for plugins!! + return Ok(None); + } match self.grid.render(content_x, content_y, &self.style) { Ok(rendered_assets) => { self.set_should_render(false); @@ -787,6 +797,10 @@ impl TerminalPane { } pub fn cursor_coordinates(&self) -> Option<(usize, usize)> { // (x, y) + if self.get_content_rows() < 1 || self.get_content_columns() < 1 { + // do not render cursor if there's no room for it + return None; + } self.grid.cursor_coordinates() } fn render_first_run_banner(&mut self) { diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 5a23f8870..82928b68d 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -20,7 +20,7 @@ use zellij_utils::{ data::{ModeInfo, ResizeStrategy, Style}, errors::prelude::*, input::{command::RunCommand, layout::SplitDirection}, - pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport}, + pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport, Dimension}, }; use std::{ @@ -292,6 +292,9 @@ impl TiledPanes { if let Some(active_pane_id) = &self.active_panes.get(&client_id) { if let Some(active_pane) = self.panes.get_mut(active_pane_id) { let full_pane_size = active_pane.position_and_size(); + if full_pane_size.is_stacked { + return false + } if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 { return false; } else { @@ -305,6 +308,9 @@ impl TiledPanes { if let Some(active_pane_id) = &self.active_panes.get(&client_id) { if let Some(active_pane) = self.panes.get_mut(active_pane_id) { let full_pane_size = active_pane.position_and_size(); + if full_pane_size.is_stacked { + return false + } if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 { return false; } @@ -320,6 +326,9 @@ impl TiledPanes { if full_pane_size.rows.is_fixed() { return false; } + if full_pane_size.is_stacked { + return false + } if split(SplitDirection::Horizontal, &full_pane_size).is_some() { true } else { @@ -351,6 +360,9 @@ impl TiledPanes { if full_pane_size.cols.is_fixed() { return false; } + if full_pane_size.is_stacked { + return false + } if split(SplitDirection::Vertical, &full_pane_size).is_some() { true } else { @@ -774,13 +786,61 @@ impl TiledPanes { true }, - None => false, + None => { + log::info!("can has none"); + match pane_grid.stacked_pane_id_below(&active_pane_id) { + Some(p) => { + log::info!("can has stacked_pane_id_below"); + let source_pane = self + .panes + .get_mut(self.active_panes.get(&client_id).unwrap()) + .unwrap(); + + // TODO: + // * set the y of the source_pane to be the y + rows of + // itself + // * set its rows size to be fixed 1 + // * reduce the y of the current pane by 1 + + let mut source_pane_geom = source_pane.position_and_size(); + let mut destination_pane_geom = source_pane_geom.clone(); + destination_pane_geom.y = source_pane_geom.y + 1; + source_pane_geom.rows = Dimension::fixed(1); + source_pane.set_geom(source_pane_geom); + + // render previously active pane so that its frame does not remain actively + // colored + source_pane.set_should_render(true); + // we render the full viewport to remove any ui elements that might have been + // there before (eg. another user's cursor) + source_pane.render_full_viewport(); + + let destination_pane = self.panes.get_mut(&p).unwrap(); + destination_pane.set_geom(destination_pane_geom); + + destination_pane.set_should_render(true); + // we render the full viewport to remove any ui elements that might have been + // there before (eg. another user's cursor) + destination_pane.render_full_viewport(); + + self.focus_pane(p, client_id); + self.set_pane_active_at(p); + self.set_pane_frames(self.draw_pane_frames); // TODO: do we need + // this? + + true + }, + None => false + } + } + // None => false, } }, None => false, } } pub fn move_focus_up(&mut self, client_id: ClientId) -> bool { + log::info!("initial panes: {:#?}", self.panes.iter().map(|(_, p)| p.position_and_size()).collect::<Vec<_>>()); match self.get_active_pane_id(client_id) { Some(active_pane_id) => { let pane_grid = TiledPaneGrid::new( @@ -815,7 +875,60 @@ impl TiledPanes { true }, - None => false, + None => { + match pane_grid.stacked_pane_id_above(&active_pane_id) { + Some(p) => { + let source_pane = self + .panes + .get_mut(self.active_panes.get(&client_id).unwrap()) + .unwrap(); + + // TODO: + // * set the y of the source_pane to be the y + rows of + // itself + // * set its rows size to be fixed 1 + // * reduce the y of the current pane by 1 + + let source_before = source_pane.position_and_size(); + + let mut source_pane_geom = source_pane.position_and_size(); + let mut destination_pane_geom = source_pane_geom.clone(); + let destination_before = destination_pane_geom.clone(); + source_pane_geom.y = (source_pane_geom.y + source_pane_geom.rows.as_usize()) - 1; // -1 because we want to be at the last line of the source pane, not the next line over + source_pane_geom.rows = Dimension::fixed(1); + source_pane.set_geom(source_pane_geom); + destination_pane_geom.y -= 1; + + log::info!("source after: {:?}", source_pane_geom); + log::info!("destination after: {:?}", destination_pane_geom); + + // render previously active pane so that its frame does not remain actively + // colored + source_pane.set_should_render(true); + // we render the full viewport to remove any ui elements that might have been + // there before (eg. another user's cursor) + source_pane.render_full_viewport(); + + let destination_pane = self.panes.get_mut(&p).unwrap(); + destination_pane.set_geom(destination_pane_geom); + + destination_pane.set_should_render(true); + // we render the full viewport to remove any ui elements that might have been + // there before (eg. another user's cursor) + destination_pane.render_full_viewport(); + + self.focus_pane(p, client_id); + self.set_pane_active_at(p); + self.set_pane_frames(self.draw_pane_frames); // TODO: do we need + // this? + + true + }, + None => false + } + + } + // None => false, } }, None => false, @@ -1075,6 +1188,7 @@ impl TiledPanes { self.panes.remove(&pane_id) } pub fn remove_pane(&mut self, pane_id: PaneId) -> Option<Box<dyn Pane>> { + log::info!("remove pane"); let mut pane_grid = TiledPaneGrid::new( &mut self.panes, &self.panes_to_hide, @@ -1082,6 +1196,7 @@ impl TiledPanes { *self.viewport.borrow(), ); if pane_grid.fill_space_over_pane(pane_id) { + log::info!("successfully fill_space_over_pane"); // successfully filled space over pane let closed_pane = self.panes.remove(&pane_id); self.move_clients_out_of_pane(pane_id); 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 bc1e7bbf4..9a534a45b 100644 --- a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs +++ b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs @@ -878,6 +878,26 @@ impl<'a> TiledPaneGrid<'a> { .copied(); next_index } + pub fn stacked_pane_id_below(&self, current_pane_id: &PaneId) -> Option<PaneId> { + let panes = self.panes.borrow(); + let current_pane = panes.get(current_pane_id)?; + let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + let next_index = panes + .iter() + .enumerate() + .filter(|(_, (_, c))| { + c.is_directly_below(Box::as_ref(current_pane)) + && c.vertically_overlaps_with(Box::as_ref(current_pane)) + }) + .max_by_key(|(_, (_, c))| c.active_at()) + .map(|(_, (pid, _))| pid) + .copied(); + next_index + } pub fn next_selectable_pane_id_below(&self, current_pane_id: &PaneId) -> Option<PaneId> { let panes = self.panes.borrow(); let current_pane = panes.get(current_pane_id)?; @@ -892,6 +912,29 @@ 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.position_and_size().rows.as_usize() > 1 // TODO: no!! use is_stacked!! + && !c.position_and_size().is_stacked + }) + .max_by_key(|(_, (_, c))| c.active_at()) + .map(|(_, (pid, _))| pid) + .copied(); + next_index + } + pub fn stacked_pane_id_above(&self, current_pane_id: &PaneId) -> Option<PaneId> { + let panes = self.panes.borrow(); + let current_pane = panes.get(current_pane_id)?; + let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + let next_index = panes + .iter() + .enumerate() + .filter(|(_, (_, c))| { + c.is_directly_above(Box::as_ref(current_pane)) + && c.vertically_overlaps_with(Box::as_ref(current_pane)) + && c.position_and_size().is_stacked }) .max_by_key(|(_, (_, c))| c.active_at()) .map(|(_, (pid, _))| pid) @@ -912,6 +955,8 @@ 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.position_and_size().rows.as_usize() > 1 // TODO: no!! use is stacked!! + && !c.position_and_size().is_stacked }) .max_by_key(|(_, (_, c))| c.active_at()) .map(|(_, (pid, _))| pid) @@ -1101,14 +1146,82 @@ impl<'a> TiledPaneGrid<'a> { pub fn fill_space_over_pane(&mut self, id: PaneId) -> bool { // true => successfully filled space over pane // false => didn't succeed, so didn't do anything - let (freed_width, freed_height) = { + let (freed_width, freed_height, pane_to_close_is_stacked) = { let panes = self.panes.borrow_mut(); let pane_to_close = panes.get(&id).unwrap(); let freed_space = pane_to_close.position_and_size(); let freed_width = freed_space.cols.as_percent(); let freed_height = freed_space.rows.as_percent(); - (freed_width, freed_height) + let pane_to_close_is_stacked = pane_to_close.position_and_size().is_stacked; + (freed_width, freed_height, pane_to_close_is_stacked) }; + if pane_to_close_is_stacked { + let mut panes = self.panes.borrow_mut(); + let pane_to_close = panes.get(&id).unwrap(); + let pane_to_close_is_one_liner = pane_to_close.position_and_size().rows.as_usize() == 1; + let mut all_stacked_pane_positions: Vec<(PaneId, PaneGeom)> = panes + .iter() + .filter(|(_pid, p)| p.position_and_size().is_stacked) + .filter(|(_pid, p)| p.position_and_size().x == pane_to_close.position_and_size().x && p.position_and_size().cols == pane_to_close.position_and_size().cols) + .map(|(pid, p)| (*pid, p.position_and_size())) + .collect(); + all_stacked_pane_positions.sort_by(|(_a_pid, a), (_b_pid, b)| { + a.y.cmp(&b.y) + }); + let position_of_current_pane = all_stacked_pane_positions.iter().position(|(pid, _p)| pid == &pane_to_close.pid()).unwrap(); // TODO: no unwrap + if pane_to_close_is_one_liner { + let position_of_flexible_pane = all_stacked_pane_positions.iter().position(|(_pid, p)| p.rows.is_percent()).unwrap(); // TODO: no unwrap + let id_of_flexible_pane = all_stacked_pane_positions.iter().nth(position_of_flexible_pane).map(|(pid, p)| *pid).unwrap(); + if position_of_current_pane > position_of_flexible_pane { + let mut flexible_pane = panes.get_mut(&id_of_flexible_pane).unwrap(); + let mut flexible_pane_position_and_size = flexible_pane.position_and_size(); + let before = flexible_pane_position_and_size.clone(); + // flexible_pane_position_and_size.y = flexible_pane_position_and_size.y.saturating_sub(1); + flexible_pane_position_and_size.rows.set_inner(flexible_pane_position_and_size.rows.as_usize() + 1); + flexible_pane.set_geom(flexible_pane_position_and_size); + for (i, (pid, position)) in all_stacked_pane_positions.iter().enumerate() { + if i > position_of_flexible_pane && i < position_of_current_pane { + let pane = panes.get_mut(pid).unwrap(); // TODO: no unwrap + let mut pane_position_and_size = pane.position_and_size(); + pane_position_and_size.y += 1; + pane.set_geom(pane_position_and_size); + } + } + } else { + let mut flexible_pane = panes.get_mut(&id_of_flexible_pane).unwrap(); + let mut flexible_pane_position_and_size = flexible_pane.position_and_size(); + flexible_pane_position_and_size.rows.set_inner(flexible_pane_position_and_size.rows.as_usize() + 1); + flexible_pane.set_geom(flexible_pane_position_and_size); + for (pid, position) in all_stacked_pane_positions.iter().skip(position_of_current_pane + 1).take(position_of_flexible_pane) { + let pane = panes.get_mut(pid).unwrap(); // TODO: no unwrap + let mut pane_position_and_size = pane.position_and_size(); + pane_position_and_size.y = pane_position_and_size.y.saturating_sub(1); + pane.set_geom(pane_position_and_size); + } + } + panes.remove(&id); + return true; + } else { + if all_stacked_pane_positions.len() > position_of_current_pane + 1 { + let mut pane_to_close_position_and_size = pane_to_close.position_and_size(); + pane_to_close_position_and_size.rows.set_inner(pane_to_close_position_and_size.rows.as_usize() + 1); + let pane_id_below = all_stacked_pane_positions.iter().nth(position_of_current_pane + 1).map(|(pid, _)| *pid).unwrap(); // TODO: no unwrap + let pane_below = panes.get_mut(&pane_id_below).unwrap(); // TODO: no unwrap + pane_below.set_geom(pane_to_close_position_and_size); + panes.remove(&id); + return true; + } else if position_of_current_pane > 0 { + let mut pane_to_close_position_and_size = pane_to_close.position_and_size(); + pane_to_close_position_and_size.rows.set_inner(pane_to_close_position_and_size.rows.as_usize() + 1); + pane_to_close_position_and_size.y -= 1; + let pane_id_above = all_stacked_pane_positions.iter().nth(position_of_current_pane - 1).map(|(pid, _)| *pid).unwrap(); // TODO: no unwrap + let pane_above = panes.get_mut(&pane_id_above).unwrap(); // TODO: no unwrap + pane_above.set_geom(pane_to_close_position_and_size); + panes.remove(&id); + return true; + } + } + } if let (Some(freed_width), Some(freed_height)) = (freed_width, freed_height) { if let Some((panes_to_grow, direction)) = self.find_panes_to_grow(id) { self.grow_panes(&panes_to_grow, direction, (freed_width, freed_height)); @@ -1130,7 +1243,7 @@ impl<'a> TiledPaneGrid<'a> { ) -> Option<(PaneId, SplitDirection)> { let panes = self.panes.borrow(); let pane_sequence: Vec<(&PaneId, &&mut Box<dyn Pane>)> = - panes.iter().filter(|(_, p)| p.selectable()).collect(); + panes.iter().filter(|(_, p)| p.selectable() && !p.position_and_size().is_stacked).collect(); let (_largest_pane_size, pane_id_to_split) = pane_sequence.iter().fold( (0, None), |(current_largest_pane_size, current_pane_id_to_split), id_and_pane_to_check| { |