diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 48d0bfc5c86efea24dd83c1d9b2c0ddecb56c253..2cf82d76dcbd251d352bd05cfd451ce091d60abf 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -767,14 +767,16 @@ impl SettingsPageItem { }); let field = match field_renderer_or_warning { - Ok(field_renderer) => field_renderer( - settings_window, - setting_item, - file.clone(), - setting_item.metadata.as_deref(), - window, - cx, - ), + Ok(field_renderer) => window.with_id(item_index, |window| { + field_renderer( + settings_window, + setting_item, + file.clone(), + setting_item.metadata.as_deref(), + window, + cx, + ) + }), Err(warning) => render_settings_item( settings_window, setting_item, @@ -3257,30 +3259,32 @@ where } else { current_value_label.to_string() }, - ContextMenu::build(window, cx, move |mut menu, _, _| { - for (&value, &label) in std::iter::zip(variants(), labels()) { - let file = file.clone(); - menu = menu.toggleable_entry( - if should_do_titlecase { - label.to_title_case() - } else { - label.to_string() - }, - value == current_value, - IconPosition::End, - None, - move |_, cx| { - if value == current_value { - return; - } - update_settings_file(file.clone(), cx, move |settings, _cx| { - (field.write)(settings, Some(value)); - }) - .log_err(); // todo(settings_ui) don't log err - }, - ); - } - menu + window.use_state(cx, |window, cx| { + ContextMenu::new(window, cx, move |mut menu, _, _| { + for (&value, &label) in std::iter::zip(variants(), labels()) { + let file = file.clone(); + menu = menu.toggleable_entry( + if should_do_titlecase { + label.to_title_case() + } else { + label.to_string() + }, + value == current_value, + IconPosition::End, + None, + move |_, cx| { + if value == current_value { + return; + } + update_settings_file(file.clone(), cx, move |settings, _cx| { + (field.write)(settings, Some(value)); + }) + .log_err(); // todo(settings_ui) don't log err + }, + ); + } + menu + }) }), ) .trigger_size(ButtonSize::Medium) @@ -3308,7 +3312,7 @@ fn render_font_picker( field: SettingField, file: SettingsUiFile, _metadata: Option<&SettingsFieldMetadata>, - window: &mut Window, + _window: &mut Window, cx: &mut App, ) -> AnyElement { let current_value = SettingsStore::global(cx) @@ -3317,26 +3321,29 @@ fn render_font_picker( .cloned() .unwrap_or_else(|| SharedString::default().into()); - let font_picker = cx.new(|cx| { - font_picker( - current_value.clone().into(), - move |font_name, cx| { - update_settings_file(file.clone(), cx, move |settings, _cx| { - (field.write)(settings, Some(font_name.into())); - }) - .log_err(); // todo(settings_ui) don't log err - }, - window, - cx, - ) - }); - PopoverMenu::new("font-picker") - .menu(move |_window, _cx| Some(font_picker.clone())) .trigger(render_picker_trigger_button( "font_family_picker_trigger".into(), - current_value.into(), + current_value.clone().into(), )) + .menu(move |window, cx| { + let file = file.clone(); + let current_value = current_value.clone(); + + Some(cx.new(move |cx| { + font_picker( + current_value.clone().into(), + move |font_name, cx| { + update_settings_file(file.clone(), cx, move |settings, _cx| { + (field.write)(settings, Some(font_name.into())); + }) + .log_err(); // todo(settings_ui) don't log err + }, + window, + cx, + ) + })) + }) .anchor(gpui::Corner::TopLeft) .offset(gpui::Point { x: px(0.0), @@ -3350,7 +3357,7 @@ fn render_theme_picker( field: SettingField, file: SettingsUiFile, _metadata: Option<&SettingsFieldMetadata>, - window: &mut Window, + _window: &mut Window, cx: &mut App, ) -> AnyElement { let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); @@ -3359,26 +3366,28 @@ fn render_theme_picker( .map(|theme_name| theme_name.0.into()) .unwrap_or_else(|| cx.theme().name.clone()); - let theme_picker = cx.new(|cx| { - theme_picker( - current_value.clone(), - move |theme_name, cx| { - update_settings_file(file.clone(), cx, move |settings, _cx| { - (field.write)(settings, Some(settings::ThemeName(theme_name.into()))); - }) - .log_err(); // todo(settings_ui) don't log err - }, - window, - cx, - ) - }); - PopoverMenu::new("theme-picker") - .menu(move |_window, _cx| Some(theme_picker.clone())) .trigger(render_picker_trigger_button( "theme_picker_trigger".into(), - current_value, + current_value.clone(), )) + .menu(move |window, cx| { + Some(cx.new(|cx| { + let file = file.clone(); + let current_value = current_value.clone(); + theme_picker( + current_value, + move |theme_name, cx| { + update_settings_file(file.clone(), cx, move |settings, _cx| { + (field.write)(settings, Some(settings::ThemeName(theme_name.into()))); + }) + .log_err(); // todo(settings_ui) don't log err + }, + window, + cx, + ) + })) + }) .anchor(gpui::Corner::TopLeft) .offset(gpui::Point { x: px(0.0), @@ -3392,7 +3401,7 @@ fn render_icon_theme_picker( field: SettingField, file: SettingsUiFile, _metadata: Option<&SettingsFieldMetadata>, - window: &mut Window, + _window: &mut Window, cx: &mut App, ) -> AnyElement { let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); @@ -3401,26 +3410,31 @@ fn render_icon_theme_picker( .map(|theme_name| theme_name.0.into()) .unwrap_or_else(|| cx.theme().name.clone()); - let icon_theme_picker = cx.new(|cx| { - icon_theme_picker( - current_value.clone(), - move |theme_name, cx| { - update_settings_file(file.clone(), cx, move |settings, _cx| { - (field.write)(settings, Some(settings::IconThemeName(theme_name.into()))); - }) - .log_err(); // todo(settings_ui) don't log err - }, - window, - cx, - ) - }); - PopoverMenu::new("icon-theme-picker") - .menu(move |_window, _cx| Some(icon_theme_picker.clone())) .trigger(render_picker_trigger_button( "icon_theme_picker_trigger".into(), - current_value, + current_value.clone(), )) + .menu(move |window, cx| { + Some(cx.new(|cx| { + let file = file.clone(); + let current_value = current_value.clone(); + icon_theme_picker( + current_value, + move |theme_name, cx| { + update_settings_file(file.clone(), cx, move |settings, _cx| { + (field.write)( + settings, + Some(settings::IconThemeName(theme_name.into())), + ); + }) + .log_err(); // todo(settings_ui) don't log err + }, + window, + cx, + ) + })) + }) .anchor(gpui::Corner::TopLeft) .offset(gpui::Point { x: px(0.0), diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index bfafaee428edc47209391cd3a7abfd3d5f432fe5..72c16edfc58e27ef0d82573924a17505648ee291 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -206,39 +206,46 @@ impl EventEmitter for ContextMenu {} impl FluentBuilder for ContextMenu {} impl ContextMenu { + pub fn new( + window: &mut Window, + cx: &mut Context, + f: impl FnOnce(Self, &mut Window, &mut Context) -> Self, + ) -> Self { + let focus_handle = cx.focus_handle(); + let _on_blur_subscription = cx.on_blur( + &focus_handle, + window, + |this: &mut ContextMenu, window, cx| this.cancel(&menu::Cancel, window, cx), + ); + window.refresh(); + + f( + Self { + builder: None, + items: Default::default(), + focus_handle, + action_context: None, + selected_index: None, + delayed: false, + clicked: false, + key_context: "menu".into(), + _on_blur_subscription, + keep_open_on_confirm: false, + documentation_aside: None, + fixed_width: None, + end_slot_action: None, + }, + window, + cx, + ) + } + pub fn build( window: &mut Window, cx: &mut App, f: impl FnOnce(Self, &mut Window, &mut Context) -> Self, ) -> Entity { - cx.new(|cx| { - let focus_handle = cx.focus_handle(); - let _on_blur_subscription = cx.on_blur( - &focus_handle, - window, - |this: &mut ContextMenu, window, cx| this.cancel(&menu::Cancel, window, cx), - ); - window.refresh(); - f( - Self { - builder: None, - items: Default::default(), - focus_handle, - action_context: None, - selected_index: None, - delayed: false, - clicked: false, - key_context: "menu".into(), - _on_blur_subscription, - keep_open_on_confirm: false, - documentation_aside: None, - fixed_width: None, - end_slot_action: None, - }, - window, - cx, - ) - }) + cx.new(|cx| Self::new(window, cx, f)) } /// Builds a [`ContextMenu`] that will stay open when making changes instead of closing after each confirmation.