settings_ui.rs

  1mod appearance_settings_controls;
  2
  3use std::any::TypeId;
  4
  5use command_palette_hooks::CommandPaletteFilter;
  6use editor::EditorSettingsControls;
  7use feature_flags::{FeatureFlag, FeatureFlagViewExt};
  8use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, actions};
  9use ui::prelude::*;
 10use workspace::item::{Item, ItemEvent};
 11use workspace::{Workspace, with_active_or_new_workspace};
 12
 13use crate::appearance_settings_controls::AppearanceSettingsControls;
 14
 15pub mod keybindings;
 16pub mod ui_components;
 17
 18pub struct SettingsUiFeatureFlag;
 19
 20impl FeatureFlag for SettingsUiFeatureFlag {
 21    const NAME: &'static str = "settings-ui";
 22}
 23
 24actions!(
 25    zed,
 26    [
 27        /// Opens the settings editor.
 28        OpenSettingsEditor
 29    ]
 30);
 31
 32pub fn init(cx: &mut App) {
 33    cx.on_action(|_: &OpenSettingsEditor, cx| {
 34        with_active_or_new_workspace(cx, move |workspace, window, cx| {
 35            let existing = workspace
 36                .active_pane()
 37                .read(cx)
 38                .items()
 39                .find_map(|item| item.downcast::<SettingsPage>());
 40
 41            if let Some(existing) = existing {
 42                workspace.activate_item(&existing, true, true, window, cx);
 43            } else {
 44                let settings_page = SettingsPage::new(workspace, cx);
 45                workspace.add_item_to_active_pane(Box::new(settings_page), None, true, window, cx)
 46            }
 47        });
 48    });
 49
 50    cx.observe_new(|_workspace: &mut Workspace, window, cx| {
 51        let Some(window) = window else {
 52            return;
 53        };
 54
 55        let settings_ui_actions = [TypeId::of::<OpenSettingsEditor>()];
 56
 57        CommandPaletteFilter::update_global(cx, |filter, _cx| {
 58            filter.hide_action_types(&settings_ui_actions);
 59        });
 60
 61        cx.observe_flag::<SettingsUiFeatureFlag, _>(
 62            window,
 63            move |is_enabled, _workspace, _, cx| {
 64                if is_enabled {
 65                    CommandPaletteFilter::update_global(cx, |filter, _cx| {
 66                        filter.show_action_types(settings_ui_actions.iter());
 67                    });
 68                } else {
 69                    CommandPaletteFilter::update_global(cx, |filter, _cx| {
 70                        filter.hide_action_types(&settings_ui_actions);
 71                    });
 72                }
 73            },
 74        )
 75        .detach();
 76    })
 77    .detach();
 78
 79    keybindings::init(cx);
 80}
 81
 82pub struct SettingsPage {
 83    focus_handle: FocusHandle,
 84}
 85
 86impl SettingsPage {
 87    pub fn new(_workspace: &Workspace, cx: &mut Context<Workspace>) -> Entity<Self> {
 88        cx.new(|cx| Self {
 89            focus_handle: cx.focus_handle(),
 90        })
 91    }
 92}
 93
 94impl EventEmitter<ItemEvent> for SettingsPage {}
 95
 96impl Focusable for SettingsPage {
 97    fn focus_handle(&self, _cx: &App) -> FocusHandle {
 98        self.focus_handle.clone()
 99    }
100}
101
102impl Item for SettingsPage {
103    type Event = ItemEvent;
104
105    fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
106        Some(Icon::new(IconName::Settings))
107    }
108
109    fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
110        "Settings".into()
111    }
112
113    fn show_toolbar(&self) -> bool {
114        false
115    }
116
117    fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
118        f(*event)
119    }
120}
121
122impl Render for SettingsPage {
123    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
124        v_flex()
125            .p_4()
126            .size_full()
127            .gap_4()
128            .child(Label::new("Settings").size(LabelSize::Large))
129            .child(
130                v_flex().gap_1().child(Label::new("Appearance")).child(
131                    v_flex()
132                        .elevation_2(cx)
133                        .child(AppearanceSettingsControls::new()),
134                ),
135            )
136            .child(
137                v_flex().gap_1().child(Label::new("Editor")).child(
138                    v_flex()
139                        .elevation_2(cx)
140                        .child(EditorSettingsControls::new()),
141                ),
142            )
143    }
144}