cosmic-comp/src/shell/grabs/menu/item.rs

228 lines
6.4 KiB
Rust
Raw Normal View History

2023-12-07 19:53:41 +00:00
use cosmic::{
iced::Element,
iced_core::{
2024-02-09 16:48:03 -08:00
Background, Border, Clipboard, Color, Event, Layout, Length, Rectangle,
2026-03-04 10:46:51 -05:00
Renderer as IcedRenderer, Shell, Size, layout, mouse, overlay,
2025-10-16 18:53:57 +02:00
renderer::{Quad, Style},
widget::{Id, Tree, Widget, tree},
2023-12-07 19:53:41 +00:00
},
2024-10-24 00:15:05 +02:00
widget::button::Catalog,
2023-12-07 19:53:41 +00:00
};
2024-02-09 16:48:03 -08:00
pub struct SubmenuItem<'a, Message> {
elem: cosmic::Element<'a, Message>,
2023-12-07 19:53:41 +00:00
idx: usize,
2024-10-24 00:15:05 +02:00
styling: <cosmic::Theme as Catalog>::Class,
2023-12-07 19:53:41 +00:00
}
2024-02-09 16:48:03 -08:00
impl<'a, Message> SubmenuItem<'a, Message> {
pub fn new(elem: impl Into<cosmic::Element<'a, Message>>, idx: usize) -> Self {
2023-12-07 19:53:41 +00:00
Self {
elem: elem.into(),
idx,
styling: Default::default(),
}
}
2024-10-24 00:15:05 +02:00
pub fn style(mut self, style: <cosmic::Theme as Catalog>::Class) -> Self {
2023-12-07 19:53:41 +00:00
self.styling = style;
self
}
}
pub trait CursorEvents {
fn cursor_entered(idx: usize, bounds: Rectangle<f32>) -> Self;
fn cursor_left(idx: usize, bounds: Rectangle<f32>) -> Self;
}
struct State {
cursor_over: bool,
}
2025-10-16 13:50:32 +02:00
impl<Message> Widget<Message, cosmic::Theme, cosmic::Renderer> for SubmenuItem<'_, Message>
2023-12-07 19:53:41 +00:00
where
Message: CursorEvents,
{
fn id(&self) -> Option<Id> {
None
}
2024-02-09 16:48:03 -08:00
fn size(&self) -> Size<Length> {
self.elem.as_widget().size()
2023-12-07 19:53:41 +00:00
}
2023-12-14 15:02:45 -08:00
fn layout(
2026-02-24 15:18:57 -05:00
&mut self,
2023-12-14 15:02:45 -08:00
state: &mut Tree,
2024-02-09 16:48:03 -08:00
renderer: &cosmic::Renderer,
2023-12-14 15:02:45 -08:00
limits: &layout::Limits,
) -> layout::Node {
let state = &mut state.children[0];
2026-02-24 15:18:57 -05:00
let node = self.elem.as_widget_mut().layout(state, renderer, limits);
2023-12-07 19:53:41 +00:00
layout::Node::with_children(node.size(), vec![node])
}
fn draw(
&self,
state: &Tree,
2024-02-09 16:48:03 -08:00
renderer: &mut cosmic::Renderer,
theme: &cosmic::Theme,
2023-12-07 19:53:41 +00:00
style: &Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
let widget_state = state.state.downcast_ref::<State>();
let styling = if widget_state.cursor_over {
2024-02-09 16:48:03 -08:00
theme.hovered(true, false, &self.styling)
2023-12-07 19:53:41 +00:00
} else {
2024-02-09 16:48:03 -08:00
theme.active(true, false, &self.styling)
2023-12-07 19:53:41 +00:00
};
renderer.fill_quad(
Quad {
2026-02-24 15:18:57 -05:00
snap: true,
2023-12-07 19:53:41 +00:00
bounds: layout.bounds(),
2024-02-09 16:48:03 -08:00
border: Border {
radius: styling.border_radius,
width: styling.border_width,
color: styling.border_color,
},
shadow: Default::default(),
2023-12-07 19:53:41 +00:00
},
styling
.background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
);
let state = &state.children[0];
let layout = layout.children().next().unwrap();
self.elem.as_widget().draw(
state,
renderer,
theme,
&Style {
text_color: styling.text_color.unwrap_or(style.text_color),
icon_color: styling.icon_color.unwrap_or(style.text_color),
..*style
},
layout,
cursor,
viewport,
)
}
fn tag(&self) -> tree::Tag {
tree::Tag::of::<State>()
}
fn state(&self) -> tree::State {
tree::State::new(State { cursor_over: false })
}
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.elem)]
}
fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(std::slice::from_mut(&mut self.elem))
}
fn operate(
2026-02-24 15:18:57 -05:00
&mut self,
2023-12-07 19:53:41 +00:00
state: &mut Tree,
layout: Layout<'_>,
2024-02-09 16:48:03 -08:00
renderer: &cosmic::Renderer,
2024-10-24 00:15:05 +02:00
operation: &mut dyn cosmic::widget::Operation<()>,
2023-12-07 19:53:41 +00:00
) {
let state = &mut state.children[0];
let layout = layout.children().next().unwrap();
self.elem
2026-02-24 15:18:57 -05:00
.as_widget_mut()
2023-12-07 19:53:41 +00:00
.operate(state, layout, renderer, operation)
}
2026-02-24 15:18:57 -05:00
fn update(
2023-12-07 19:53:41 +00:00
&mut self,
state: &mut Tree,
2026-02-24 15:18:57 -05:00
event: &Event,
2023-12-07 19:53:41 +00:00
layout: Layout<'_>,
cursor: mouse::Cursor,
2024-02-09 16:48:03 -08:00
renderer: &cosmic::Renderer,
2023-12-07 19:53:41 +00:00
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
2026-02-24 15:18:57 -05:00
) {
2023-12-08 17:52:44 +00:00
let mut bounds = layout.bounds();
// fix padding 1 and event... don't ask.
bounds.x -= 1.;
bounds.width += 2.;
let is_over = cursor.is_over(bounds);
2023-12-07 19:53:41 +00:00
let widget_state = state.state.downcast_mut::<State>();
match event {
Event::Mouse(mouse::Event::CursorEntered)
| Event::Mouse(mouse::Event::CursorMoved { .. })
if is_over && !widget_state.cursor_over =>
{
2023-12-08 17:52:44 +00:00
shell.publish(Message::cursor_entered(self.idx, bounds));
2023-12-07 19:53:41 +00:00
widget_state.cursor_over = true;
}
Event::Mouse(mouse::Event::CursorMoved { .. })
| Event::Mouse(mouse::Event::CursorLeft)
if !is_over && widget_state.cursor_over =>
{
2023-12-08 17:52:44 +00:00
shell.publish(Message::cursor_left(self.idx, bounds));
2023-12-07 19:53:41 +00:00
widget_state.cursor_over = false;
}
_ => {}
};
let state = &mut state.children[0];
let layout = layout.children().next().unwrap();
2026-02-24 15:18:57 -05:00
self.elem.as_widget_mut().update(
2023-12-07 19:53:41 +00:00
state, event, layout, cursor, renderer, clipboard, shell, viewport,
2026-02-24 15:18:57 -05:00
);
2023-12-07 19:53:41 +00:00
}
fn mouse_interaction(
&self,
state: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
2024-02-09 16:48:03 -08:00
renderer: &cosmic::Renderer,
2023-12-07 19:53:41 +00:00
) -> mouse::Interaction {
let state = &state.children[0];
let layout = layout.children().next().unwrap();
self.elem
.as_widget()
.mouse_interaction(state, layout, cursor, viewport, renderer)
}
fn overlay<'b>(
&'b mut self,
state: &'b mut Tree,
2026-02-24 15:18:57 -05:00
layout: Layout<'b>,
2024-02-09 16:48:03 -08:00
renderer: &cosmic::Renderer,
2026-02-24 15:18:57 -05:00
viewport: &Rectangle,
2024-10-24 00:15:05 +02:00
translation: cosmic::iced::Vector,
2024-02-09 16:48:03 -08:00
) -> Option<overlay::Element<'b, Message, cosmic::Theme, cosmic::Renderer>> {
2023-12-07 19:53:41 +00:00
let state = &mut state.children[0];
let layout = layout.children().next().unwrap();
2024-10-24 00:15:05 +02:00
self.elem
.as_widget_mut()
2026-02-24 15:18:57 -05:00
.overlay(state, layout, renderer, viewport, translation)
2023-12-07 19:53:41 +00:00
}
}
2025-10-16 13:50:32 +02:00
impl<'a, Message> From<SubmenuItem<'a, Message>> for cosmic::Element<'a, Message>
2023-12-07 19:53:41 +00:00
where
Message: CursorEvents + 'a,
{
2025-10-16 13:50:32 +02:00
fn from(val: SubmenuItem<'a, Message>) -> Self {
Element::new(val)
2023-12-07 19:53:41 +00:00
}
}