feat: padding overlap

This commit is contained in:
Ashley Wulber 2025-10-15 14:53:11 -04:00
parent 071c77c1a4
commit 89029994a5
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
3 changed files with 102 additions and 48 deletions

View file

@ -325,6 +325,7 @@ where
.zip(&mut tree.children)
.zip(layout.children())
.map(|(((i, child), state), c_layout)| {
let mut cursor_virtual = cursor;
if matches!(
event,
Event::Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::CursorEntered)
@ -335,6 +336,8 @@ where
) && cursor.is_over(c_layout.bounds())
{
my_state.hovered = Some(i);
} else if my_state.hovered.is_some_and(|h| i == h) {
cursor_virtual = mouse::Cursor::Unavailable;
}
child.as_widget_mut().on_event(

View file

@ -8,7 +8,7 @@ use crate::{
cctk::sctk,
iced::{
self, Color, Length, Limits, Rectangle,
alignment::{Horizontal, Vertical},
alignment::{Alignment, Horizontal, Vertical},
widget::Container,
window,
},
@ -17,12 +17,16 @@ use crate::{
widget::{
self,
autosize::{self, Autosize, autosize},
layer_container,
column::Column,
horizontal_space, layer_container,
row::Row,
vertical_space,
},
};
pub use cosmic_panel_config;
use cosmic_panel_config::{CosmicPanelBackground, PanelAnchor, PanelSize};
use iced_core::{Padding, Shadow};
use iced_widget::Text;
use iced_widget::runtime::platform_specific::wayland::popup::{SctkPopupSettings, SctkPositioner};
use sctk::reexports::protocols::xdg::shell::client::xdg_positioner::{Anchor, Gravity};
use std::{borrow::Cow, num::NonZeroU32, rc::Rc, sync::LazyLock, time::Duration};
@ -49,6 +53,8 @@ pub struct Context {
/// Includes the configured size of the window.
/// This can be used by apples to handle overflow themselves.
pub suggested_bounds: Option<iced::Size>,
/// Ratio of overlap for applet padding.
pub padding_overlap: f32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -107,6 +113,10 @@ impl Default for Context {
.unwrap_or(CosmicPanelBackground::ThemeDefault),
output_name: std::env::var("COSMIC_PANEL_OUTPUT").unwrap_or_default(),
panel_type: PanelType::from(std::env::var("COSMIC_PANEL_NAME").unwrap_or_default()),
padding_overlap: str::parse(
&std::env::var("COSMIC_PANEL_PADDING_OVERLAP").unwrap_or_default(),
)
.unwrap_or(0.0),
suggested_bounds: None,
}
}
@ -212,25 +222,76 @@ impl Context {
(applet_padding_minor_axis, applet_padding_major_axis)
};
let symbolic = icon.symbolic;
let icon = widget::icon(icon)
.class(if symbolic {
theme::Svg::Custom(Rc::new(|theme| crate::iced_widget::svg::Style {
color: Some(theme.cosmic().background.on.into()),
}))
} else {
theme::Svg::default()
})
.width(Length::Fixed(suggested.0 as f32))
.height(Length::Fixed(suggested.1 as f32));
self.button_from_element(icon, symbolic)
}
pub fn button_from_element<'a, Message: Clone + 'static>(
&self,
content: impl Into<Element<'a, Message>>,
use_symbolic_size: bool,
) -> crate::widget::Button<'a, Message> {
let suggested = self.suggested_size(use_symbolic_size);
let (applet_padding_major_axis, applet_padding_minor_axis) = self.suggested_padding(true);
let (horizontal_padding, vertical_padding) = if self.is_horizontal() {
(applet_padding_major_axis, applet_padding_minor_axis)
} else {
(applet_padding_minor_axis, applet_padding_major_axis)
};
crate::widget::button::custom(layer_container(content).center(Length::Fill))
.width(Length::Fixed((suggested.0 + 2 * horizontal_padding) as f32))
.height(Length::Fixed((suggested.1 + 2 * vertical_padding) as f32))
.class(Button::AppletIcon)
}
pub fn text_button<'a, Message: Clone + 'static>(
&self,
text: impl Into<Text<'a, crate::Theme, crate::Renderer>>,
message: Message,
) -> crate::widget::Button<'a, Message> {
let text = text.into();
let suggested = self.suggested_size(true);
let (applet_padding_major_axis, applet_padding_minor_axis) = self.suggested_padding(true);
let (horizontal_padding, vertical_padding) = if self.is_horizontal() {
(applet_padding_major_axis, applet_padding_minor_axis)
} else {
(applet_padding_minor_axis, applet_padding_major_axis)
};
crate::widget::button::custom(
layer_container(
widget::icon(icon)
.class(if symbolic {
theme::Svg::Custom(Rc::new(|theme| crate::iced_widget::svg::Style {
color: Some(theme.cosmic().background.on.into()),
}))
} else {
theme::Svg::default()
})
.width(Length::Fixed(suggested.0 as f32))
.height(Length::Fixed(suggested.1 as f32)),
)
.center(Length::Fill),
Row::with_children(vec![
Column::with_children(vec![
Text::from(text).into(),
horizontal_space()
.width(Length::Fixed(
(suggested.0 as f32 + 2. * horizontal_padding as f32),
))
.width(Length::Shrink)
.height(Length::Shrink)
.into(),
])
.align_x(Alignment::Center)
.into(),
vertical_space()
.height(Length::Fixed(
(suggested.1 as f32 + 2. * vertical_padding as f32),
))
.into(),
])
.align_y(Alignment::Center),
)
.width(Length::Fixed((suggested.0 + 2 * horizontal_padding) as f32))
.height(Length::Fixed((suggested.1 + 2 * vertical_padding) as f32))
.class(Button::AppletIcon)
.on_press_down(message)
.class(crate::theme::Button::AppletIcon)
}
pub fn icon_button<'a, Message: Clone + 'static>(

View file

@ -50,6 +50,24 @@ pub static HSV_RAINBOW: LazyLock<Vec<Color>> = LazyLock::new(|| {
.collect()
});
fn hsv_rainbow(low_hue: f32, high_hue: f32) -> Vec<ColorStop> {
let mut colors = Vec::new();
let steps: u8 = 7;
let step_size = (high_hue - low_hue) / f32::from(steps);
for i in 0..=steps {
let hue = low_hue + step_size * f32::from(i);
colors.push(ColorStop {
color: Color::from(palette::Srgba::from_color(palette::Hsv::new_srgb_const(
RgbHue::new(hue),
1.0,
1.0,
))),
offset: f32::from(i) / f32::from(steps),
});
}
colors
}
const MAX_RECENT: usize = 20;
#[derive(Debug, Clone)]
@ -290,37 +308,9 @@ where
copied_to_clipboard_label: T,
) -> ColorPicker<'a, Message> {
fn rail_backgrounds(hue: f32) -> (Background, Background) {
let pivot = hue * 7.0 / 360.;
let low_range = hsv_rainbow(0., hue);
let high_range = hsv_rainbow(hue, 360.);
let low_end = pivot.floor() as usize;
let high_start = pivot.ceil() as usize;
let pivot_color = palette::Hsv::new_srgb(RgbHue::new(hue), 1.0, 1.0);
let low_range = HSV_RAINBOW[0..=low_end]
.iter()
.enumerate()
.map(|(i, color)| ColorStop {
color: *color,
offset: i as f32 / pivot.max(0.0001),
})
.chain(iter::once(ColorStop {
color: iced::Color::from(palette::Srgba::from_color(pivot_color)),
offset: 1.,
}))
.collect::<Vec<_>>();
let high_range = iter::once(ColorStop {
color: iced::Color::from(palette::Srgba::from_color(pivot_color)),
offset: 0.,
})
.chain(
HSV_RAINBOW[high_start..]
.iter()
.enumerate()
.map(|(i, color)| ColorStop {
color: *color,
offset: (i as f32 + (1. - pivot.fract())) / (7. - pivot).max(0.0001),
}),
)
.collect::<Vec<_>>();
(
Background::Gradient(iced::Gradient::Linear(
Linear::new(Radians(90.0)).add_stops(low_range),