From 5c321addec554c3985830b76c25acd67daa7bb31 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Sun, 4 Oct 2026 09:18:18 +0100 Subject: [PATCH] Inset panel highlights and align bar content --- shell/ferese-shell/src/bar.rs | 84 +++++++++++++++---------- shell/ferese-shell/src/main.rs | 10 ++- shell/ferese-shell/src/status_ui/bar.rs | 19 +++--- 3 files changed, 68 insertions(+), 45 deletions(-) diff --git a/shell/ferese-shell/src/bar.rs b/shell/ferese-shell/src/bar.rs index 86462d9..6d56911 100644 --- a/shell/ferese-shell/src/bar.rs +++ b/shell/ferese-shell/src/bar.rs @@ -69,7 +69,7 @@ impl FereseShell { }, owner.map_or(String::new(), |output| format!(", on {}", output.name)) )) - .height(bar.control_height) + .height(bar.group_item_height) .padding(0) .on_press(cosmic::Action::App(Message::ActivateWorkspace(workspace.id))); @@ -90,7 +90,8 @@ impl FereseShell { } workspace_row = workspace_row.push( container(workspace_buttons) - .padding([0, 3]) + .padding([2, 3]) + .height(bar.group_height) .class(theme::Container::custom(move |_| bar_group_style(shell_theme))), ); @@ -102,19 +103,22 @@ impl FereseShell { .scroller_width(0), )) .width(Length::Fill) - .height(bar.control_height); + .height(bar.group_height); let (date, time) = self.clock.split_once(", ").unwrap_or(("", &self.clock)); let clock = container(motion::button( button::custom( - row![ - text(date).size(12).class(theme::Text::Color(foreground)), - text(time).size(bar.text_size).class(theme::Text::Color(foreground)), - ] - .spacing(8) - .align_y(cosmic::iced::Alignment::Center), + container( + row![ + text(date).size(12).class(theme::Text::Color(foreground)), + text(time).size(bar.text_size).class(theme::Text::Color(foreground)), + ] + .spacing(8) + .align_y(cosmic::iced::Alignment::Center), + ) + .center_y(bar.group_item_height), ) - .padding([4, 8]) - .height(bar.control_height) + .padding([0, 8]) + .height(bar.group_item_height) .name("Open calendar") .on_press_with_rectangle(move |offset, bounds| { cosmic::Action::App(Message::OpenMenuOn( @@ -134,7 +138,8 @@ impl FereseShell { .is_some_and(|menu| menu.kind == status_ui::Menu::Calendar), 1.0, )) - .height(bar.control_height) + .padding([2, 3]) + .height(bar.group_height) .align_y(alignment::Vertical::Center) .class(theme::Container::custom(move |_| bar_group_style(shell_theme))); let mut right = row![ @@ -149,16 +154,19 @@ impl FereseShell { .align_y(cosmic::iced::Alignment::Center); if self.display_mode.external_connected() { right = right.push(motion::button( - button::custom(bar_icon(ferese_theme::icons::DISPLAY, bar.icon_size, foreground)) - .name("Display mode") - .height(bar.control_height) - .padding([0, 7]) - .on_press(cosmic::Action::App(Message::OpenDisplays( - self.outputs - .iter() - .find(|output| output.bar == id) - .and_then(|output| output.name.clone()), - ))), + button::custom(bar_content( + bar_icon(ferese_theme::icons::DISPLAY, bar.icon_size, foreground), + bar.control_height, + )) + .name("Display mode") + .height(bar.control_height) + .padding([0, 7]) + .on_press(cosmic::Action::App(Message::OpenDisplays( + self.outputs + .iter() + .find(|output| output.bar == id) + .and_then(|output| output.name.clone()), + ))), foreground, self.display_mode.open, 1.0, @@ -196,7 +204,7 @@ impl FereseShell { )) .anchor_right() .width(Length::Shrink) - .height(bar.control_height); + .height(bar.group_height); let content = row![ container(left).width(Length::Fill), center, @@ -223,16 +231,27 @@ impl FereseShell { } } +pub(super) fn bar_content<'a>( + content: impl Into>>, + height: f32, +) -> cosmic::widget::Container<'a, cosmic::Action, cosmic::Theme, cosmic::Renderer> { + // A one-pixel optical offset below the geometric center. Compact bars + // reduce the offset so the 20 px icons keep their full size. + container(content) + .padding(cosmic::iced::Padding { + top: (height - 20.0).clamp(0.0, 2.0), + ..Default::default() + }) + .center_y(height) +} + pub(super) fn overview_control(bar: BarMetrics, foreground: Color) -> Element<'static, cosmic::Action> { - container(bar_icon( - ferese_theme::icons::FERESE, - bar.overview_icon_size, - foreground, - )) + bar_content( + bar_icon(ferese_theme::icons::FERESE, bar.overview_icon_size, foreground), + bar.control_height, + ) .width(bar.overview_icon_size) - .height(bar.control_height) .align_x(alignment::Horizontal::Center) - .align_y(alignment::Vertical::Center) .into() } @@ -277,15 +296,14 @@ pub(super) fn workspace_indicator( } else { shell_theme.text_muted }; - container( + bar_content( text(name.to_owned()) .size(12) .class(theme::Text::Color(color(foreground))), + bar.group_item_height, ) .width(24) - .height(bar.control_height) .align_x(alignment::Horizontal::Center) - .align_y(alignment::Vertical::Center) .class(theme::Container::custom(move |_| { workspace_selector_style(active, active_elsewhere, occupied, shell_theme) })) diff --git a/shell/ferese-shell/src/main.rs b/shell/ferese-shell/src/main.rs index 35b2fea..6aae5ac 100644 --- a/shell/ferese-shell/src/main.rs +++ b/shell/ferese-shell/src/main.rs @@ -82,11 +82,17 @@ struct BarMetrics { icon_size: u16, overview_icon_size: u16, control_height: f32, + group_height: f32, + group_item_height: f32, } impl From for BarMetrics { fn from(theme: ShellTheme) -> Self { let height = theme.bar_height; + let control_height = (height - 4.0).max(21.0).min(height); + // Leave two logical pixels inside the group border on each side, + // including compact bars with 20 px icons. + let group_height = control_height.max(24.0).min(height); Self { height, @@ -95,7 +101,9 @@ impl From for BarMetrics { text_size: 14, icon_size: 20, overview_icon_size: 20, - control_height: (height - 4.0).max(21.0).min(height), + control_height, + group_height, + group_item_height: (group_height - 4.0).max(0.0), } } } diff --git a/shell/ferese-shell/src/status_ui/bar.rs b/shell/ferese-shell/src/status_ui/bar.rs index f26eed3..d13afd7 100644 --- a/shell/ferese-shell/src/status_ui/bar.rs +++ b/shell/ferese-shell/src/status_ui/bar.rs @@ -1,11 +1,13 @@ use cosmic::iced::border::Shape as BorderShape; -use cosmic::iced::{Alignment, Background, Border, Rectangle, alignment}; +use cosmic::iced::{Alignment, Background, Border, Rectangle}; use cosmic::widget::{button, container, row}; use cosmic::{Element, theme}; use super::Menu; use crate::status::Snapshot; -use crate::{BarMetrics, FereseShell, Message, accented_icon, bar_group_style, color, motion, recording, text}; +use crate::{ + BarMetrics, FereseShell, Message, accented_icon, bar_content, bar_group_style, color, motion, recording, text, +}; impl FereseShell { pub fn view_status_bar(&self) -> Element<'_, cosmic::Action> { @@ -91,13 +93,7 @@ impl FereseShell { }, ))); } - // A fixed button height does not center its child in libcosmic. - // center_y/center_x wrap the content in a centering layout, so use - // those rather than align_y/align_x on a fixed-size container. - let content = container(content) - .align_x(alignment::Horizontal::Center) - .height(metrics.control_height) - .center_y(metrics.control_height); + let content = bar_content(content, metrics.group_item_height); let recording_busy = kind == Menu::Recording && self.recorder.busy(); let control = button::custom(content) .name(if recording_busy { @@ -108,7 +104,7 @@ impl FereseShell { status_label(kind, &self.status) }) .padding([0.0, ((metrics.height - f32::from(metrics.icon_size)) * 0.5).max(4.0)]) - .height(metrics.control_height) + .height(metrics.group_item_height) .on_press_with_rectangle(move |offset, bounds| { if kind == Menu::Recording { return cosmic::Action::App(if recording_busy { @@ -130,7 +126,8 @@ impl FereseShell { controls = controls.push(motion::button(control, foreground, selected, 1.0)); } container(controls) - .padding([0, 3]) + .padding([2, 3]) + .height(metrics.group_height) .class(theme::Container::custom(move |_| bar_group_style(theme))) .into() }