From 3dd149e711e6ff4fbea036824078b8c16c631f04 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 1 Aug 2024 15:41:00 +0800 Subject: [PATCH] Update PopupMenu to support checked style. (#96) image --- crates/story/src/popover_story.rs | 13 ++++--- crates/ui/src/icon.rs | 4 +++ crates/ui/src/popup_menu.rs | 57 ++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/crates/story/src/popover_story.rs b/crates/story/src/popover_story.rs index dd11c90e..46ab3c73 100644 --- a/crates/story/src/popover_story.rs +++ b/crates/story/src/popover_story.rs @@ -15,7 +15,10 @@ use ui::{ v_flex, Clickable, IconName, Size, }; -actions!(popover_story, [Copy, Paste, Cut, SearchAll]); +actions!( + popover_story, + [Copy, Paste, Cut, SearchAll, ToggleWindowMode] +); struct Form { input1: View, @@ -97,8 +100,8 @@ impl FocusableView for PopoverStory { impl Render for PopoverStory { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { let form = self.form.clone(); - let _focused = self.focus_handle.is_focused(cx); let focus_handle = self.focus_handle.clone(); + let window_mode = self.window_mode; v_flex() .track_focus(&self.focus_handle) @@ -176,7 +179,7 @@ impl Render for PopoverStory { .gap_3() .child( Popover::new("popup-menu") - .when(self.window_mode, |this| this.window_mode()) + .when(window_mode, |this| this.window_mode()) .trigger(Button::new("popup-menu-1", cx).icon(IconName::Info)) .content(move |cx| { let focus_handle = focus_handle.clone(); @@ -190,7 +193,9 @@ impl Render for PopoverStory { IconName::Search, "Search", Box::new(SearchAll), - ); + ) + .separator() + .menu_with_check("Check Menu", true, Box::new(SearchAll)); this }) diff --git a/crates/ui/src/icon.rs b/crates/ui/src/icon.rs index 008a899b..c5f7195a 100644 --- a/crates/ui/src/icon.rs +++ b/crates/ui/src/icon.rs @@ -184,6 +184,10 @@ impl Icon { self.base = self.base.with_transformation(transformation); self } + + pub fn empty() -> Self { + Self::default() + } } impl Styled for Icon { diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs index fe3960a6..6c5003ea 100644 --- a/crates/ui/src/popup_menu.rs +++ b/crates/ui/src/popup_menu.rs @@ -7,7 +7,7 @@ use gpui::{ VisualContext as _, WindowContext, }; -use crate::{h_flex, list::ListItem, theme::ActiveTheme, v_flex, Icon}; +use crate::{h_flex, list::ListItem, theme::ActiveTheme, v_flex, Icon, IconName}; actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]); @@ -42,6 +42,7 @@ pub struct PopupMenu { window_handle: AnyWindowHandle, action_context: Option, menu_items: Vec, + has_icon: bool, selected_index: Option, min_width: Pixels, max_width: Pixels, @@ -67,6 +68,7 @@ impl PopupMenu { selected_index: None, min_width: px(120.), max_width: px(500.), + has_icon: false, _subscriptions: [_on_blur_subscription], }; cx.refresh(); @@ -108,6 +110,20 @@ impl PopupMenu { self.add_menu_item(Some(icon.into()), label, action) } + /// Add Menu Item with check icon + pub fn menu_with_check( + &mut self, + label: impl Into, + checked: bool, + action: Box, + ) -> &mut Self { + if checked { + self.add_menu_item(Some(IconName::Check.into()), label, action) + } else { + self.add_menu_item(None, label, action) + } + } + fn add_menu_item( &mut self, icon: Option, @@ -115,6 +131,10 @@ impl PopupMenu { action: Box, ) -> &mut Self { let window_handle = self.window_handle; + if icon.is_some() { + self.has_icon = true; + } + self.menu_items.push(PopupMenuItem::Item { icon, label: label.into(), @@ -210,6 +230,12 @@ impl FocusableView for PopupMenu { impl Render for PopupMenu { fn render(&mut self, cx: &mut gpui::ViewContext) -> impl gpui::IntoElement { + let icon_placeholder = if self.has_icon { + Some(Icon::empty()) + } else { + None + }; + v_flex() .key_context("PopupMenu") .track_focus(&self.focus_handle) @@ -220,23 +246,36 @@ impl Render for PopupMenu { .on_mouse_down_out(cx.listener(|this, _, cx| this.dismiss(&Dismiss, cx))) .max_h(self.max_width) .min_w(self.min_width) - .p_1p5() + .p_0p5() .gap_y_0p5() .children(self.menu_items.iter_mut().enumerate().map(|(ix, item)| { let this = ListItem::new(("menu-item", ix)) + .p_0() .on_click(cx.listener(move |this, _, cx| this.on_click(ix, cx))); match item { - PopupMenuItem::Separator => this - .disabled(true) - .child(div().h(px(1.)).m_1().border_0().bg(cx.theme().border)), + PopupMenuItem::Separator => this.disabled(true).child( + div() + .h(px(1.)) + .w_full() + .my_px() + .border_0() + .bg(cx.theme().border), + ), PopupMenuItem::Item { icon, label, .. } => { - this.py_1().px_2().text_sm().rounded(px(4.)).child( + this.py(px(3.)).px_3().rounded_md().text_sm().child( h_flex() .size_full() - .gap_2() .items_center() - .children(icon.clone()) - .child(label.clone()), + .map(|this| { + this.child(div().absolute().text_sm().map(|this| { + if let Some(icon) = icon { + this.child(icon.clone()) + } else { + this.child(icon_placeholder.clone().unwrap()) + } + })) + }) + .child(div().pl_6().pr_2().child(label.clone())), ) } }