@@ -16,7 +16,10 @@ use settings::{
SettingsValue,
};
use smallvec::SmallVec;
-use ui::{NumericStepper, SwitchField, ToggleButtonGroup, ToggleButtonSimple, prelude::*};
+use ui::{
+ ContextMenu, DropdownMenu, NumericStepper, SwitchField, ToggleButtonGroup, ToggleButtonSimple,
+ prelude::*,
+};
use workspace::{
Workspace,
item::{Item, ItemEvent},
@@ -33,14 +36,14 @@ impl FeatureFlag for SettingsUiFeatureFlag {
actions!(
zed,
[
- /// Opens the settings editor.
- OpenSettingsEditor
+ /// Opens settings UI.
+ OpenSettingsUi
]
);
pub fn open_settings_editor(
workspace: &mut Workspace,
- _: &OpenSettingsEditor,
+ _: &OpenSettingsUi,
window: &mut Window,
cx: &mut Context<Workspace>,
) {
@@ -62,7 +65,7 @@ pub fn open_settings_editor(
pub fn init(cx: &mut App) {
cx.observe_new(|workspace: &mut Workspace, _, _| {
workspace.register_action_renderer(|div, _, _, cx| {
- let settings_ui_actions = [std::any::TypeId::of::<OpenSettingsEditor>()];
+ let settings_ui_actions = [std::any::TypeId::of::<OpenSettingsUi>()];
let has_flag = cx.has_flag::<SettingsUiFeatureFlag>();
command_palette_hooks::CommandPaletteFilter::update_global(cx, |filter, _| {
if has_flag {
@@ -635,8 +638,8 @@ fn render_item_single(
variants: values,
labels: titles,
} => render_toggle_button_group(settings_value, values, titles, window, cx),
- SettingsUiItemSingle::DropDown { .. } => {
- unimplemented!("This")
+ SettingsUiItemSingle::DropDown { variants, labels } => {
+ render_dropdown(settings_value, variants, labels, window, cx)
}
SettingsUiItemSingle::TextField => render_text_field(settings_value, window, cx),
}
@@ -896,6 +899,41 @@ fn render_toggle_button_group(
});
}
+fn render_dropdown(
+ value: SettingsValue<serde_json::Value>,
+ variants: &'static [&'static str],
+ labels: &'static [&'static str],
+ window: &mut Window,
+ cx: &mut App,
+) -> AnyElement {
+ let value = downcast_any_item::<String>(value);
+ let id = element_id_from_path(&value.path);
+
+ let menu = window.use_state(cx, |window, cx| {
+ let path = value.path.clone();
+ let handler = Rc::new(move |variant: &'static str, cx: &mut App| {
+ SettingsValue::write_value(&path, serde_json::Value::String(variant.to_string()), cx);
+ });
+
+ ContextMenu::build(window, cx, |mut menu, _, _| {
+ for (label, variant) in labels.iter().zip(variants) {
+ menu = menu.entry(*label, None, {
+ let handler = handler.clone();
+ move |_, cx| {
+ handler(variant, cx);
+ }
+ });
+ }
+
+ menu
+ })
+ });
+
+ DropdownMenu::new(id, value.read(), menu.read(cx).clone())
+ .style(ui::DropdownStyle::Outlined)
+ .into_any_element()
+}
+
fn render_toggle_button_group_inner(
title: SharedString,
labels: &'static [&'static str],
@@ -50,6 +50,10 @@ pub fn derive_settings_ui(input: proc_macro::TokenStream) -> proc_macro::TokenSt
meta.input.parse::<Token![=]>()?;
let lit: LitStr = meta.input.parse()?;
path_name = Some(lit.value());
+ } else if meta.path.is_ident("render") {
+ // Just consume the tokens even if we don't use them here
+ meta.input.parse::<Token![=]>()?;
+ let _lit: LitStr = meta.input.parse()?;
}
Ok(())
})
@@ -170,6 +174,7 @@ fn generate_ui_item_body(group_name: Option<&String>, input: &syn::DeriveInput)
}
(None, Data::Enum(data_enum)) => {
let serde_attrs = parse_serde_attributes(&input.attrs);
+ let render_as = parse_render_as(&input.attrs);
let length = data_enum.variants.len();
let mut variants = Vec::with_capacity(length);
@@ -187,13 +192,19 @@ fn generate_ui_item_body(group_name: Option<&String>, input: &syn::DeriveInput)
let is_not_union = data_enum.variants.iter().all(|v| v.fields.is_empty());
if is_not_union {
- return if length > 6 {
- quote! {
- settings::SettingsUiItem::Single(settings::SettingsUiItemSingle::DropDown{ variants: &[#(#variants),*], labels: &[#(#labels),*] })
+ return match render_as {
+ RenderAs::ToggleGroup if length > 6 => {
+ panic!("Can't set toggle group with more than six entries");
}
- } else {
- quote! {
- settings::SettingsUiItem::Single(settings::SettingsUiItemSingle::ToggleGroup{ variants: &[#(#variants),*], labels: &[#(#labels),*] })
+ RenderAs::ToggleGroup => {
+ quote! {
+ settings::SettingsUiItem::Single(settings::SettingsUiItemSingle::ToggleGroup{ variants: &[#(#variants),*], labels: &[#(#labels),*] })
+ }
+ }
+ RenderAs::Default => {
+ quote! {
+ settings::SettingsUiItem::Single(settings::SettingsUiItemSingle::DropDown{ variants: &[#(#variants),*], labels: &[#(#labels),*] })
+ }
}
};
}
@@ -369,6 +380,38 @@ impl SerdeOptions {
}
}
+enum RenderAs {
+ ToggleGroup,
+ Default,
+}
+
+fn parse_render_as(attrs: &[syn::Attribute]) -> RenderAs {
+ let mut render_as = RenderAs::Default;
+
+ for attr in attrs {
+ if !attr.path().is_ident("settings_ui") {
+ continue;
+ }
+
+ attr.parse_nested_meta(|meta| {
+ if meta.path.is_ident("render") {
+ meta.input.parse::<Token![=]>()?;
+ let lit = meta.input.parse::<LitStr>()?.value();
+
+ if lit == "toggle_group" {
+ render_as = RenderAs::ToggleGroup;
+ } else {
+ return Err(meta.error(format!("invalid `render` attribute: {}", lit)));
+ }
+ }
+ Ok(())
+ })
+ .unwrap();
+ }
+
+ render_as
+}
+
fn parse_serde_attributes(attrs: &[syn::Attribute]) -> SerdeOptions {
let mut options = SerdeOptions {
rename_all: SerdeRenameAll::None,