From d451ce5c2da96535154cfab7b40d4fa542cdf660 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 11 Mar 2025 11:18:43 +0800 Subject: [PATCH] menu: Add `menu_element_with_icon`, `menu_element_with_check` to PopupMenu. (#704) - Added `menu_element_with_icon` and `menu_element_with_check` method to PopupMenu. image ## Break changes - menu: Renamed `menu_with_element` method to `menu_element`. --- crates/story/src/popup_story.rs | 35 +++++++++++++++++-------- crates/ui/src/popup_menu.rs | 46 ++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/crates/story/src/popup_story.rs b/crates/story/src/popup_story.rs index 06800cf6..bf3388e8 100644 --- a/crates/story/src/popup_story.rs +++ b/crates/story/src/popup_story.rs @@ -262,17 +262,30 @@ impl Render for PopupStory { .separator() .menu_with_icon("Search", IconName::Search, Box::new(SearchAll)) .separator() - .menu_with_element( - |_, cx| { - v_flex().gap_1().child("Custom Element").child( - div() - .text_sm() - .text_color(cx.theme().muted_foreground) - .child("THis is sub-title"), - ) - }, - Box::new(Info(0)), - ) + .menu_element(Box::new(Info(0)), |_, cx| { + v_flex().child("Custom Element").child( + div() + .text_xs() + .text_color(cx.theme().muted_foreground) + .child("THis is sub-title"), + ) + }) + .menu_element_with_check(checked, Box::new(Info(0)), |_, cx| { + h_flex().gap_1().child("Custom Element").child( + div() + .text_xs() + .text_color(cx.theme().muted_foreground) + .child("checked"), + ) + }) + .menu_element_with_icon(IconName::Info, Box::new(Info(0)), |_, cx| { + h_flex().gap_1().child("Custom").child( + div() + .text_sm() + .text_color(cx.theme().muted_foreground) + .child("element"), + ) + }) .separator() .submenu("Links", window, cx, |menu, _, _| { menu.link_with_icon( diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs index fa67b6e8..e0d27d09 100644 --- a/crates/ui/src/popup_menu.rs +++ b/crates/ui/src/popup_menu.rs @@ -68,6 +68,7 @@ enum PopupMenuItem { handler: Rc, }, ElementItem { + icon: Option, render: Box AnyElement + 'static>, handler: Rc, }, @@ -238,7 +239,16 @@ impl PopupMenu { } /// Add Menu Item with custom element render. - pub fn menu_with_element(mut self, builder: F, action: Box) -> Self + pub fn menu_element(self, action: Box, builder: F) -> Self + where + F: Fn(&mut Window, &mut App) -> E + 'static, + E: IntoElement, + { + self.menu_element_with_check(false, action, builder) + } + + /// Add Menu Item with custom element render with icon. + pub fn menu_element_with_icon(mut self, icon: impl Into, action: Box, builder: F) -> Self where F: Fn(&mut Window, &mut App) -> E + 'static, E: IntoElement, @@ -246,7 +256,37 @@ impl PopupMenu { self.menu_items.push(PopupMenuItem::ElementItem { render: Box::new(move |window, cx| builder(window, cx).into_any_element()), handler: self.wrap_handler(action), + icon: Some(icon.into()) }); + self.has_icon = true; + self + } + + /// Add Menu Item with custom element render with check state + pub fn menu_element_with_check( + mut self, + checked: bool, + action: Box, + builder: F, + ) -> Self + where + F: Fn(&mut Window, &mut App) -> E + 'static, + E: IntoElement, + { + if checked { + self.menu_items.push(PopupMenuItem::ElementItem { + render: Box::new(move |window, cx| builder(window, cx).into_any_element()), + handler: self.wrap_handler(action), + icon: Some(IconName::Check.into()) + }); + self.has_icon = true; + } else { + self.menu_items.push(PopupMenuItem::ElementItem { + render: Box::new(move |window, cx| builder(window, cx).into_any_element()), + handler: self.wrap_handler(action), + icon: None, + }); + } self } @@ -515,14 +555,14 @@ impl PopupMenu { .my_0p5() .bg(cx.theme().muted), ), - PopupMenuItem::ElementItem { render, .. } => this + PopupMenuItem::ElementItem { render, icon, .. } => this .on_click(cx.listener(move |this, _, window, cx| this.on_click(ix, window, cx))) .child( h_flex() .min_h(ITEM_HEIGHT) .items_center() .gap_x_1() - .children(Self::render_icon(has_icon, None, window, cx)) + .children(Self::render_icon(has_icon, icon.clone(), window, cx)) .child((render)(window, cx)), ), PopupMenuItem::Item {