element: Refactor remaining libcosmic elements for blur

This commit is contained in:
Victoria Brekenfeld 2026-04-21 18:19:01 +02:00 committed by Victoria Brekenfeld
parent 6c76fdaa79
commit db06770a6b
9 changed files with 444 additions and 142 deletions

View file

@ -1,10 +1,11 @@
use std::sync::{Arc, Mutex};
use crate::{
backend::render::element::AsGlowRenderer,
config::Config,
fl,
shell::grabs::ResizeEdge,
utils::iced::{IcedElement, Program},
utils::iced::{IcedElement, IcedRenderElement, Program},
};
use calloop::LoopHandle;
@ -19,48 +20,233 @@ use cosmic::{
widget::{icon::from_name, text},
};
use cosmic_settings_config::shortcuts::action::{Action, ResizeDirection};
use smithay::utils::Size;
use smithay::{
backend::renderer::ImportMem,
desktop::space::SpaceElement,
output::Output,
utils::{Logical, Physical, Point, Rectangle, Scale, Size},
};
pub type ResizeIndicator = IcedElement<ResizeIndicatorInternal>;
#[derive(Debug, Clone)]
pub struct ResizeIndicator {
edges: ResizeEdge,
direction: Arc<Mutex<ResizeDirection>>,
size: Size<i32, Logical>,
pub fn resize_indicator(
direction: ResizeDirection,
config: &Config,
evlh: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> ResizeIndicator {
ResizeIndicator::new(
ResizeIndicatorInternal {
edges: Mutex::new(ResizeEdge::all()),
direction,
shortcut1: config
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Outwards)).then_some(pattern)
})
.map(|pattern| format!("{}: ", pattern.to_string()))
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
shortcut2: config
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Inwards)).then_some(pattern)
})
.map(|pattern| format!("{}: ", pattern.to_string()))
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
},
Size::from((1, 1)),
evlh,
theme,
)
center_elem: IcedElement<ResizeIndicatorInternal>,
left_elem: IcedElement<ResizeIndicatorArrow>,
top_elem: IcedElement<ResizeIndicatorArrow>,
right_elem: IcedElement<ResizeIndicatorArrow>,
down_elem: IcedElement<ResizeIndicatorArrow>,
}
const ARROW_SIZE: i32 = 36;
impl ResizeIndicator {
pub fn new(
direction: ResizeDirection,
config: &Config,
evlh: LoopHandle<'static, crate::state::State>,
mut theme: cosmic::Theme,
) -> ResizeIndicator {
theme.transparent = theme.cosmic().frosted_system_interface;
let direction = Arc::new(Mutex::new(direction));
ResizeIndicator {
edges: ResizeEdge::all(),
direction: direction.clone(),
size: Size::default(),
center_elem: IcedElement::new(
ResizeIndicatorInternal {
shortcut1: config
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Outwards))
.then_some(pattern)
})
.map(|pattern| format!("{}: ", pattern.to_string()))
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
shortcut2: config
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Inwards))
.then_some(pattern)
})
.map(|pattern| format!("{}: ", pattern.to_string()))
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
},
Size::from((1, 1)),
evlh.clone(),
theme.clone(),
),
left_elem: IcedElement::new(
ResizeIndicatorArrow {
direction: direction.clone(),
icon_outwards: "go-previous-symbolic",
icon_inwards: "go-next-symbolic",
},
Size::from((ARROW_SIZE, ARROW_SIZE)),
evlh.clone(),
theme.clone(),
),
top_elem: IcedElement::new(
ResizeIndicatorArrow {
direction: direction.clone(),
icon_outwards: "go-up-symbolic",
icon_inwards: "go-down-symbolic",
},
Size::from((ARROW_SIZE, ARROW_SIZE)),
evlh.clone(),
theme.clone(),
),
right_elem: IcedElement::new(
ResizeIndicatorArrow {
direction: direction.clone(),
icon_outwards: "go-next-symbolic",
icon_inwards: "go-previous-symbolic",
},
Size::from((ARROW_SIZE, ARROW_SIZE)),
evlh.clone(),
theme.clone(),
),
down_elem: IcedElement::new(
ResizeIndicatorArrow {
direction,
icon_outwards: "go-down-symbolic",
icon_inwards: "go-up-symbolic",
},
Size::from((ARROW_SIZE, ARROW_SIZE)),
evlh.clone(),
theme.clone(),
),
}
}
pub fn resize(&mut self, size: Size<i32, Logical>) {
let minimum = self.center_elem.minimum_size();
let new_size = Size::<i32, Logical>::new(size.w.min(minimum.w), size.h.min(minimum.h));
self.center_elem.resize(new_size);
self.size = size;
}
pub fn push_render_elements<R>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
alpha: f32,
push_above: &mut dyn FnMut(IcedRenderElement<R>),
mut push_below: Option<&mut dyn FnMut(IcedRenderElement<R>)>,
) where
R: AsGlowRenderer + ImportMem,
R::TextureId: Send + Clone + 'static,
{
let elem_size = self.center_elem.current_size();
let center_location = Point::new(
self.size.w.saturating_sub(elem_size.w) / 2,
self.size.h.saturating_sub(elem_size.h) / 2,
);
let left_location = Point::new(0, self.size.h.saturating_sub(ARROW_SIZE) / 2);
let top_location = Point::new(self.size.w.saturating_sub(ARROW_SIZE) / 2, 0);
let right_location = Point::new(
self.size.w.saturating_sub(ARROW_SIZE),
self.size.h.saturating_sub(ARROW_SIZE) / 2,
);
let down_location = Point::new(
self.size.w.saturating_sub(ARROW_SIZE) / 2,
self.size.h.saturating_sub(ARROW_SIZE),
);
let radii = self
.center_elem
.with_theme(|theme| theme.cosmic().radius_s())
.map(|x| x.round() as u8);
self.center_elem.push_render_elements(
renderer,
location + center_location.to_physical_precise_round(scale),
scale,
alpha,
radii,
push_above,
if let Some(push_below) = push_below.as_mut() {
Some(&mut **push_below)
} else {
None
},
);
let mut render = move |elem: &IcedElement<ResizeIndicatorArrow>,
loc: Point<i32, Logical>| {
elem.push_render_elements(
renderer,
location + loc.to_physical_precise_round(scale),
scale,
alpha,
radii,
push_above,
if let Some(push_below) = push_below.as_mut() {
Some(&mut **push_below)
} else {
None
},
);
};
if self.edges.contains(ResizeEdge::LEFT) {
render(&self.left_elem, left_location);
}
if self.edges.contains(ResizeEdge::TOP) {
render(&self.top_elem, top_location);
}
if self.edges.contains(ResizeEdge::RIGHT) {
render(&self.right_elem, right_location);
}
if self.edges.contains(ResizeEdge::BOTTOM) {
render(&self.down_elem, down_location);
}
}
pub fn set_edges(&mut self, edges: ResizeEdge) {
self.edges = edges;
}
pub fn set_direction(&self, direction: ResizeDirection) {
let mut dir_ref = self.direction.lock().unwrap();
if *dir_ref != direction {
*dir_ref = direction;
self.left_elem.force_redraw();
self.top_elem.force_redraw();
self.right_elem.force_redraw();
self.down_elem.force_redraw();
}
}
pub fn output_enter(&self, output: &Output) {
self.center_elem
.output_enter(output, Rectangle::default() /*unused*/);
self.left_elem
.output_enter(output, Rectangle::default() /*unused*/);
self.top_elem
.output_enter(output, Rectangle::default() /*unused*/);
self.right_elem
.output_enter(output, Rectangle::default() /*unused*/);
self.down_elem
.output_enter(output, Rectangle::default() /*unused*/);
}
pub fn output_leave(&self, output: &Output) {
self.center_elem.output_leave(output);
self.left_elem.output_leave(output);
self.top_elem.output_leave(output);
self.right_elem.output_leave(output);
self.down_elem.output_leave(output);
}
}
pub struct ResizeIndicatorInternal {
pub edges: Mutex<ResizeEdge>,
pub direction: ResizeDirection,
pub shortcut1: String,
pub shortcut2: String,
shortcut1: String,
shortcut2: String,
}
impl Program for ResizeIndicatorInternal {
@ -94,7 +280,7 @@ impl Program for ResizeIndicatorInternal {
text_color: Some(Color::from(theme.cosmic().accent.on)),
background: Some(Background::Color(background.into())),
border: Border {
radius: 18.0.into(),
radius: theme.cosmic().radius_s().into(),
width: 0.0,
color: Color::TRANSPARENT,
},