feat: allow configuring terminal pane borders

This commit is contained in:
Ben Gubler 2026-04-06 18:38:10 -06:00 • committed by Ashley Wulber
parent 117644e9c1
commit 5db18f3fac
4 changed files with 74 additions and 23 deletions

View file

@ -58,6 +58,7 @@ use-bright-bold = Make bold text brighter
### Splits ### Splits
splits = Splits splits = Splits
focus-follow-mouse = Typing focus follows mouse focus-follow-mouse = Typing focus follows mouse
show-pane-borders = Show pane borders
### Advanced ### Advanced
advanced = Advanced advanced = Advanced

View file

@ -231,6 +231,7 @@ pub struct Config {
pub opacity: u8, pub opacity: u8,
pub profiles: BTreeMap<ProfileId, Profile>, pub profiles: BTreeMap<ProfileId, Profile>,
pub show_headerbar: bool, pub show_headerbar: bool,
pub show_pane_borders: bool,
pub use_bright_bold: bool, pub use_bright_bold: bool,
pub syntax_theme_dark: String, pub syntax_theme_dark: String,
pub syntax_theme_light: String, pub syntax_theme_light: String,
@ -260,6 +261,7 @@ impl Default for Config {
opacity: 100, opacity: 100,
profiles: BTreeMap::new(), profiles: BTreeMap::new(),
show_headerbar: true, show_headerbar: true,
show_pane_borders: false,
syntax_theme_dark: COSMIC_THEME_DARK.to_string(), syntax_theme_dark: COSMIC_THEME_DARK.to_string(),
syntax_theme_light: COSMIC_THEME_LIGHT.to_string(), syntax_theme_light: COSMIC_THEME_LIGHT.to_string(),
use_bright_bold: false, use_bright_bold: false,

View file

@ -429,6 +429,7 @@ pub enum Message {
SelectAll(Option<segmented_button::Entity>), SelectAll(Option<segmented_button::Entity>),
ShowAdvancedFontSettings(bool), ShowAdvancedFontSettings(bool),
ShowHeaderBar(bool), ShowHeaderBar(bool),
ShowPaneBorders(bool),
SyntaxTheme(ColorSchemeKind, usize), SyntaxTheme(ColorSchemeKind, usize),
SystemThemeChange, SystemThemeChange,
TabNewInheritWorkingDirectory(bool), TabNewInheritWorkingDirectory(bool),
@ -1502,10 +1503,16 @@ impl App {
font_section = font_section.add(advanced_font_settings()); font_section = font_section.add(advanced_font_settings());
} }
let splits_section = widget::settings::section().title(fl!("splits")).add( let splits_section = widget::settings::section()
widget::settings::item::builder(fl!("focus-follow-mouse")) .title(fl!("splits"))
.toggler(self.config.focus_follow_mouse, Message::FocusFollowMouse), .add(
); widget::settings::item::builder(fl!("focus-follow-mouse"))
.toggler(self.config.focus_follow_mouse, Message::FocusFollowMouse),
)
.add(
widget::settings::item::builder(fl!("show-pane-borders"))
.toggler(self.config.show_pane_borders, Message::ShowPaneBorders),
);
let advanced_section = widget::settings::section() let advanced_section = widget::settings::section()
.title(fl!("advanced")) .title(fl!("advanced"))
@ -2782,6 +2789,11 @@ impl Application for App {
tab_new_inherit_working_directory tab_new_inherit_working_directory
); );
} }
Message::ShowPaneBorders(show_pane_borders) => {
if show_pane_borders != self.config.show_pane_borders {
config_set!(show_pane_borders, show_pane_borders);
}
}
Message::UseBrightBold(use_bright_bold) => { Message::UseBrightBold(use_bright_bold) => {
if use_bright_bold != self.config.use_bright_bold { if use_bright_bold != self.config.use_bright_bold {
config_set!(use_bright_bold, use_bright_bold); config_set!(use_bright_bold, use_bright_bold);
@ -3431,8 +3443,21 @@ impl Application for App {
fn view(&self) -> Element<'_, Self::Message> { fn view(&self) -> Element<'_, Self::Message> {
let t = self.core().system_theme(); let t = self.core().system_theme();
let cosmic = t.cosmic(); let cosmic = t.cosmic();
let cosmic_theme::Spacing { space_xxs, .. } = cosmic.spacing; let cosmic_theme::Spacing {
space_xxxs,
space_xxs,
..
} = cosmic.spacing;
let show_pane_borders =
self.config.show_pane_borders && self.pane_model.panes.panes.len() > 1;
let pane_corner_radius: iced::border::Radius = {
let pad = f32::from(space_xxxs) / 2.0;
cosmic
.radius_s()
.map(|r| if r > 0.0 { r + pad } else { 0.0 })
.into()
};
let pane_grid = PaneGrid::new(&self.pane_model.panes, |pane, tab_model, _is_maximized| { let pane_grid = PaneGrid::new(&self.pane_model.panes, |pane, tab_model, _is_maximized| {
let mut tab_column = widget::column::with_capacity(1); let mut tab_column = widget::column::with_capacity(1);
@ -3488,7 +3513,8 @@ impl Application for App {
}) })
.padding(space_xxs) .padding(space_xxs)
.sharp_corners(self.core.window.sharp_corners) .sharp_corners(self.core.window.sharp_corners)
.show_headerbar(self.config.show_headerbar); .show_headerbar(self.config.show_headerbar)
.pane_border_radius(show_pane_borders.then_some(pane_corner_radius));
if self.config.focus_follow_mouse { if self.config.focus_follow_mouse {
terminal_box = terminal_box.on_mouse_enter(move || Message::MouseEnter(pane)); terminal_box = terminal_box.on_mouse_enter(move || Message::MouseEnter(pane));
@ -3622,7 +3648,21 @@ impl Application for App {
.on_drag(Message::PaneDragged); .on_drag(Message::PaneDragged);
//TODO: apply window border radius xs at bottom of window //TODO: apply window border radius xs at bottom of window
pane_grid.into() if show_pane_borders {
let bg_divider = Color::from(cosmic.bg_divider());
let pane_grid = pane_grid.spacing(space_xxxs);
widget::container(pane_grid)
.width(Length::Fill)
.height(Length::Fill)
.padding(space_xxxs)
.style(move |_theme| widget::container::Style {
background: Some(bg_divider.into()),
..Default::default()
})
.into()
} else {
pane_grid.into()
}
} }
fn system_theme_update( fn system_theme_update(

View file

@ -11,7 +11,7 @@ use cosmic::{
Renderer, Renderer,
cosmic_theme::palette::{WithAlpha, blend::Compose}, cosmic_theme::palette::{WithAlpha, blend::Compose},
iced::core::{ iced::core::{
Border, Shell, Border, Shell, border::Radius,
clipboard::Clipboard, clipboard::Clipboard,
input_method::{self, InputMethod}, input_method::{self, InputMethod},
keyboard::key::Named, keyboard::key::Named,
@ -109,6 +109,7 @@ pub struct TerminalBox<'a, Message> {
border: Border, border: Border,
padding: Padding, padding: Padding,
show_headerbar: bool, show_headerbar: bool,
pane_border_radius: Option<Radius>,
click_timing: Duration, click_timing: Duration,
context_menu: Option<Point>, context_menu: Option<Point>,
on_context_menu: Option<Box<dyn Fn(Option<MenuState>) -> Message + 'a>>, on_context_menu: Option<Box<dyn Fn(Option<MenuState>) -> Message + 'a>>,
@ -135,6 +136,7 @@ where
border: Border::default(), border: Border::default(),
padding: Padding::new(0.0), padding: Padding::new(0.0),
show_headerbar: true, show_headerbar: true,
pane_border_radius: None,
click_timing: Duration::from_millis(500), click_timing: Duration::from_millis(500),
context_menu: None, context_menu: None,
on_context_menu: None, on_context_menu: None,
@ -171,6 +173,11 @@ where
self self
} }
pub fn pane_border_radius(mut self, pane_border_radius: Option<Radius>) -> Self {
self.pane_border_radius = pane_border_radius;
self
}
pub fn click_timing(mut self, click_timing: Duration) -> Self { pub fn click_timing(mut self, click_timing: Duration) -> Self {
self.click_timing = click_timing; self.click_timing = click_timing;
self self
@ -409,13 +416,22 @@ where
let state = tree.state.downcast_ref::<State>(); let state = tree.state.downcast_ref::<State>();
let cosmic_theme = theme.cosmic(); let cosmic_theme = theme.cosmic();
// matches the corners to the window border let corner_radius = if let Some(r) = self.pane_border_radius {
let corner_radius = if self.sharp_corners { r.into()
} else if self.sharp_corners {
// matches the corners to the window border
cosmic_theme.radius_0() cosmic_theme.radius_0()
} else { } else {
cosmic_theme.radius_s() cosmic_theme
} .radius_s()
.map(|x| if x < 4.0 { x - 1.0 } else { x + 3.0 }); .map(|x| if x < 4.0 { x - 1.0 } else { x + 3.0 })
};
// When there's a headerbar and no pane border, only round the bottom corners
let border_radius: Radius = if self.show_headerbar && self.pane_border_radius.is_none() {
[0.0, 0.0, corner_radius[2], corner_radius[3]].into()
} else {
corner_radius.into()
};
let scrollbar_w = f32::from(cosmic_theme.spacing.space_xxs); let scrollbar_w = f32::from(cosmic_theme.spacing.space_xxs);
let view_position = layout.position() + [self.padding.left, self.padding.top].into(); let view_position = layout.position() + [self.padding.left, self.padding.top].into();
@ -433,11 +449,7 @@ where
Quad { Quad {
bounds: layout.bounds(), bounds: layout.bounds(),
border: Border { border: Border {
radius: if self.show_headerbar { radius: border_radius,
[0.0, 0.0, corner_radius[2], corner_radius[3]].into()
} else {
corner_radius.into()
},
width: self.border.width, width: self.border.width,
color: self.border.color, color: self.border.color,
}, },
@ -475,11 +487,7 @@ where
Quad { Quad {
bounds: layout.bounds(), bounds: layout.bounds(),
border: Border { border: Border {
radius: if self.show_headerbar { radius: border_radius,
[0.0, 0.0, corner_radius[2], corner_radius[3]].into()
} else {
corner_radius.into()
},
width: self.border.width, width: self.border.width,
color: self.border.color, color: self.border.color,
}, },