aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-server/src/ui
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2025-03-02 13:18:12 +0100
committerGitHub <noreply@github.com>2025-03-02 13:18:12 +0100
commitb7cc3f3a62930b233b36a5a51cf73c7a1be08bff (patch)
tree23df1cefca8ff74ab878a500a4dae93d5d92b029 /zellij-server/src/ui
parentFix compiler warnings (#4026) (diff)
downloadsl0ppij-b7cc3f3a62930b233b36a5a51cf73c7a1be08bff.tar.gz
sl0ppij-b7cc3f3a62930b233b36a5a51cf73c7a1be08bff.tar.xz
sl0ppij-b7cc3f3a62930b233b36a5a51cf73c7a1be08bff.zip
fix(panes): various fixes for rendering stacked panes without pane frames (#4035)
* initial work * fix rendering issues with stacked panes without pane frames * make mouse clicking work * test: rendering stacked panes without frames * style(fmt): rustfmt * docs(changelog): update pr
Diffstat (limited to 'zellij-server/src/ui')
-rw-r--r--zellij-server/src/ui/boundaries.rs67
-rw-r--r--zellij-server/src/ui/pane_boundaries_frame.rs24
-rw-r--r--zellij-server/src/ui/pane_contents_and_ui.rs12
3 files changed, 85 insertions, 18 deletions
diff --git a/zellij-server/src/ui/boundaries.rs b/zellij-server/src/ui/boundaries.rs
index 7f70b1c7..f0fdebd6 100644
--- a/zellij-server/src/ui/boundaries.rs
+++ b/zellij-server/src/ui/boundaries.rs
@@ -1,4 +1,4 @@
-use zellij_utils::pane_size::Viewport;
+use zellij_utils::pane_size::{Offset, Viewport};
use crate::output::CharacterChunk;
use crate::panes::terminal_character::{TerminalCharacter, EMPTY_TERMINAL_CHARACTER, RESET_STYLES};
@@ -444,25 +444,40 @@ impl Boundaries {
boundary_characters: HashMap::new(),
}
}
- pub fn add_rect(&mut self, rect: &dyn Pane, color: Option<PaletteColor>) {
+ pub fn add_rect(
+ &mut self,
+ rect: &dyn Pane,
+ color: Option<PaletteColor>,
+ pane_is_on_top_of_stack: bool,
+ pane_is_on_bottom_of_stack: bool,
+ pane_is_stacked_under: bool,
+ ) {
let pane_is_stacked = rect.current_geom().is_stacked();
+ let should_skip_top_boundary = pane_is_stacked && !pane_is_on_top_of_stack;
+ let should_skip_bottom_boundary = pane_is_stacked && !pane_is_on_bottom_of_stack;
+ let content_offset = rect.get_content_offset();
if !self.is_fully_inside_screen(rect) {
return;
}
if rect.x() > self.viewport.x {
// left boundary
let boundary_x_coords = rect.x() - 1;
- let first_row_coordinates = self.rect_right_boundary_row_start(rect);
+ let first_row_coordinates =
+ self.rect_right_boundary_row_start(rect, pane_is_stacked_under, content_offset);
let last_row_coordinates = self.rect_right_boundary_row_end(rect);
for row in first_row_coordinates..last_row_coordinates {
let coordinates = Coordinates::new(boundary_x_coords, row);
let symbol_to_add = if row == first_row_coordinates && row != self.viewport.y {
- BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
+ if pane_is_stacked {
+ BoundarySymbol::new(boundary_type::VERTICAL_RIGHT).color(color)
+ } else {
+ BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
+ }
} else if row == first_row_coordinates && pane_is_stacked {
BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
} else if row == last_row_coordinates - 1
&& row != self.viewport.y + self.viewport.rows - 1
- && !pane_is_stacked
+ && content_offset.bottom > 0
{
BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color)
} else {
@@ -476,7 +491,7 @@ impl Boundaries {
self.boundary_characters.insert(coordinates, next_symbol);
}
}
- if rect.y() > self.viewport.y && !pane_is_stacked {
+ if rect.y() > self.viewport.y && !should_skip_top_boundary {
// top boundary
let boundary_y_coords = rect.y() - 1;
let first_col_coordinates = self.rect_bottom_boundary_col_start(rect);
@@ -501,15 +516,22 @@ impl Boundaries {
if self.rect_right_boundary_is_before_screen_edge(rect) {
// right boundary
let boundary_x_coords = rect.right_boundary_x_coords() - 1;
- let first_row_coordinates = self.rect_right_boundary_row_start(rect);
+ let first_row_coordinates =
+ self.rect_right_boundary_row_start(rect, pane_is_stacked_under, content_offset);
let last_row_coordinates = self.rect_right_boundary_row_end(rect);
for row in first_row_coordinates..last_row_coordinates {
let coordinates = Coordinates::new(boundary_x_coords, row);
- let symbol_to_add = if row == first_row_coordinates && row != self.viewport.y {
- BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color)
+ let symbol_to_add = if row == first_row_coordinates && pane_is_stacked {
+ BoundarySymbol::new(boundary_type::VERTICAL_LEFT).color(color)
+ } else if row == first_row_coordinates && row != self.viewport.y {
+ if pane_is_stacked {
+ BoundarySymbol::new(boundary_type::VERTICAL_LEFT).color(color)
+ } else {
+ BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color)
+ }
} else if row == last_row_coordinates - 1
&& row != self.viewport.y + self.viewport.rows - 1
- && !pane_is_stacked
+ && content_offset.bottom > 0
{
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color)
} else {
@@ -523,7 +545,7 @@ impl Boundaries {
self.boundary_characters.insert(coordinates, next_symbol);
}
}
- if self.rect_bottom_boundary_is_before_screen_edge(rect) && !pane_is_stacked {
+ if self.rect_bottom_boundary_is_before_screen_edge(rect) && !should_skip_bottom_boundary {
// bottom boundary
let boundary_y_coords = rect.bottom_boundary_y_coords() - 1;
let first_col_coordinates = self.rect_bottom_boundary_col_start(rect);
@@ -575,11 +597,28 @@ impl Boundaries {
fn rect_bottom_boundary_is_before_screen_edge(&self, rect: &dyn Pane) -> bool {
rect.y() + rect.rows() < self.viewport.y + self.viewport.rows
}
- fn rect_right_boundary_row_start(&self, rect: &dyn Pane) -> usize {
+ fn rect_right_boundary_row_start(
+ &self,
+ rect: &dyn Pane,
+ pane_is_stacked_under: bool,
+ content_offset: Offset,
+ ) -> usize {
let pane_is_stacked = rect.current_geom().is_stacked();
- let horizontal_frame_offset = if pane_is_stacked { 0 } else { 1 };
+ let horizontal_frame_offset = if pane_is_stacked_under {
+ // these panes - panes that are in a stack below the flexible pane - need to have their
+ // content offset taken into account when rendering them (i.e. they are rendered
+ // one line above their actual y coordinates, since they are only 1 line)
+ // as opposed to panes that are in a stack above the flexible pane who do not because
+ // they are rendered in place (the content offset of the stack is "absorbed" by the
+ // flexible pane below them)
+ content_offset.bottom
+ } else if pane_is_stacked {
+ 0
+ } else {
+ 1
+ };
if rect.y() > self.viewport.y {
- rect.y() - horizontal_frame_offset
+ rect.y().saturating_sub(horizontal_frame_offset)
} else {
self.viewport.y
}
diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs
index 4e2c01fb..295e3bce 100644
--- a/zellij-server/src/ui/pane_boundaries_frame.rs
+++ b/zellij-server/src/ui/pane_boundaries_frame.rs
@@ -4,7 +4,7 @@ use crate::ui::boundaries::boundary_type;
use crate::ClientId;
use zellij_utils::data::{client_id_to_colors, PaletteColor, Style};
use zellij_utils::errors::prelude::*;
-use zellij_utils::pane_size::Viewport;
+use zellij_utils::pane_size::{Offset, Viewport};
use zellij_utils::position::Position;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
@@ -62,6 +62,7 @@ pub struct FrameParams {
pub pane_is_stacked_over: bool,
pub should_draw_pane_frames: bool,
pub pane_is_floating: bool,
+ pub content_offset: Offset,
}
#[derive(Default, PartialEq)]
@@ -82,6 +83,7 @@ pub struct PaneFrame {
should_draw_pane_frames: bool,
is_pinned: bool,
is_floating: bool,
+ content_offset: Offset,
}
impl PaneFrame {
@@ -108,6 +110,7 @@ impl PaneFrame {
should_draw_pane_frames: frame_params.should_draw_pane_frames,
is_pinned: false,
is_floating: frame_params.pane_is_floating,
+ content_offset: frame_params.content_offset,
}
}
pub fn is_pinned(mut self, is_pinned: bool) -> Self {
@@ -776,11 +779,26 @@ impl PaneFrame {
// if this is a stacked pane with pane frames off (and it doesn't necessarily have only
// 1 row because it could also be a flexible stacked pane)
// in this case we should always draw the pane title line, and only the title line
- let one_line_title = self.render_one_line_title().with_context(err_context)?;
+ let mut one_line_title = self.render_one_line_title().with_context(err_context)?;
+
+ if self.content_offset.right != 0 && !self.should_draw_pane_frames {
+ // here what happens is that the title should be offset to the right
+ // in order to give room to the boundaries between the panes to be drawn
+ one_line_title.pop();
+ }
+ let y_coords_of_title = if self.pane_is_stacked_under && !self.should_draw_pane_frames {
+ // we only want to use the bottom offset in this case because panes that are
+ // stacked above the flexible pane should actually appear exactly where they are on
+ // screen, the content offset being "absorbed" by the flexible pane below them
+ self.geom.y.saturating_sub(self.content_offset.bottom)
+ } else {
+ self.geom.y
+ };
+
character_chunks.push(CharacterChunk::new(
one_line_title,
self.geom.x,
- self.geom.y,
+ y_coords_of_title,
));
} else {
for row in 0..self.geom.rows {
diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs
index 1be18fd8..c47e68d8 100644
--- a/zellij-server/src/ui/pane_contents_and_ui.rs
+++ b/zellij-server/src/ui/pane_contents_and_ui.rs
@@ -223,6 +223,7 @@ impl<'a> PaneContentsAndUi<'a> {
pane_is_stacked_under: self.pane_is_stacked_under,
should_draw_pane_frames: self.should_draw_pane_frames,
pane_is_floating,
+ content_offset: self.pane.get_content_offset(),
}
} else {
FrameParams {
@@ -236,6 +237,7 @@ impl<'a> PaneContentsAndUi<'a> {
pane_is_stacked_under: self.pane_is_stacked_under,
should_draw_pane_frames: self.should_draw_pane_frames,
pane_is_floating,
+ content_offset: self.pane.get_content_offset(),
}
};
@@ -260,9 +262,17 @@ impl<'a> PaneContentsAndUi<'a> {
client_mode: InputMode,
boundaries: &mut Boundaries,
session_is_mirrored: bool,
+ pane_is_on_top_of_stack: bool,
+ pane_is_on_bottom_of_stack: bool,
) {
let color = self.frame_color(client_id, client_mode, session_is_mirrored);
- boundaries.add_rect(self.pane.as_ref(), color);
+ boundaries.add_rect(
+ self.pane.as_ref(),
+ color,
+ pane_is_on_top_of_stack,
+ pane_is_on_bottom_of_stack,
+ self.pane_is_stacked_under,
+ );
}
fn frame_color(
&self,