use crate::{h_flex, ActiveTheme, Disableable, StyledExt};
use gpui::{
prelude::FluentBuilder as _, AnyElement, App, ClickEvent, ElementId, InteractiveElement,
IntoElement, MouseButton, ParentElement, RenderOnce, SharedString,
StatefulInteractiveElement as _, StyleRefinement, Styled, Window,
};
use smallvec::SmallVec;
#[derive(IntoElement)]
pub(crate) struct MenuItemElement {
id: ElementId,
group_name: SharedString,
style: StyleRefinement,
disabled: bool,
selected: bool,
on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
on_hover: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
children: SmallVec<[AnyElement; 2]>,
}
impl MenuItemElement {
pub(crate) fn new(id: impl Into<ElementId>, group_name: impl Into<SharedString>) -> Self {
let id: ElementId = id.into();
Self {
id: id.clone(),
group_name: group_name.into(),
style: StyleRefinement::default(),
disabled: false,
selected: false,
on_click: None,
on_hover: None,
children: SmallVec::new(),
}
}
pub(crate) fn selected(mut self, selected: bool) -> Self {
self.selected = selected;
self
}
pub(crate) fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub(crate) fn on_click(
mut self,
handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
) -> Self {
self.on_click = Some(Box::new(handler));
self
}
#[allow(unused)]
pub fn on_hover(mut self, handler: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self {
self.on_hover = Some(Box::new(handler));
self
}
}
impl Disableable for MenuItemElement {
fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
}
impl Styled for MenuItemElement {
fn style(&mut self) -> &mut gpui::StyleRefinement {
&mut self.style
}
}
impl ParentElement for MenuItemElement {
fn extend(&mut self, elements: impl IntoIterator<Item = gpui::AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for MenuItemElement {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
h_flex()
.id(self.id)
.group(&self.group_name)
.gap_x_1()
.py_1()
.px_2()
.text_base()
.text_color(cx.theme().foreground)
.relative()
.items_center()
.justify_between()
.refine_style(&self.style)
.when_some(self.on_hover, |this, on_hover| {
this.on_hover(move |hovered, window, cx| (on_hover)(hovered, window, cx))
})
.when(!self.disabled, |this| {
this.group_hover(self.group_name, |this| {
this.bg(cx.theme().accent)
.text_color(cx.theme().accent_foreground)
})
.when(self.selected, |this| {
this.bg(cx.theme().accent)
.text_color(cx.theme().accent_foreground)
})
.when_some(self.on_click, |this, on_click| {
this.on_mouse_down(MouseButton::Left, move |_, _, cx| {
cx.stop_propagation();
})
.on_click(on_click)
})
})
.when(self.disabled, |this| {
this.text_color(cx.theme().muted_foreground)
})
.children(self.children)
}
}