diff --git a/Cargo.lock b/Cargo.lock index cbf1d3b4896dac1e992641695f712a0a146ba745..e4f0338896be7f44379d8ac0086be6bc4f8d07b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14363,7 +14363,6 @@ dependencies = [ "anyhow", "assets", "client", - "command_palette_hooks", "editor", "feature_flags", "fs", diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 444b60ac154424c423c3cd6a827b22cd7024694f..173dbe2365088f9f736cf4bf845f44446e4cffb2 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -1213,6 +1213,11 @@ impl WindowBounds { WindowBounds::Fullscreen(bounds) => *bounds, } } + + /// Creates a new window bounds that centers the window on the screen. + pub fn centered(size: Size, cx: &App) -> Self { + WindowBounds::Windowed(Bounds::centered(None, size, cx)) + } } impl Default for WindowOptions { diff --git a/crates/settings_ui/Cargo.toml b/crates/settings_ui/Cargo.toml index 0f8aebb3a4ae37de1ed61ed5f5827e0575216c30..81075ddf9839d5b9167283a011bb6b22ccd8ed64 100644 --- a/crates/settings_ui/Cargo.toml +++ b/crates/settings_ui/Cargo.toml @@ -17,7 +17,6 @@ test-support = [] [dependencies] anyhow.workspace = true -command_palette_hooks.workspace = true heck.workspace = true editor.workspace = true feature_flags.workspace = true diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index c9fce16f890ca63d03e27b5ae9b0dd205133f8d3..11a520e77f7b92812cb5d7c57f4d632f345e5e1c 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -4,12 +4,12 @@ mod page_data; use anyhow::Result; use editor::{Editor, EditorEvent}; -use feature_flags::{FeatureFlag, FeatureFlagAppExt as _}; +use feature_flags::FeatureFlag; use fuzzy::StringMatchCandidate; use gpui::{ Action, App, Div, Entity, FocusHandle, Focusable, FontWeight, Global, ReadGlobal as _, - ScrollHandle, Task, TitlebarOptions, UniformListScrollHandle, Window, WindowHandle, - WindowOptions, actions, div, point, prelude::*, px, size, uniform_list, + ScrollHandle, Task, TitlebarOptions, UniformListScrollHandle, Window, WindowBounds, + WindowHandle, WindowOptions, actions, div, point, prelude::*, px, size, uniform_list, }; use heck::ToTitleCase as _; use project::WorktreeId; @@ -29,9 +29,8 @@ use std::{ sync::{Arc, LazyLock, RwLock, atomic::AtomicBool}, }; use ui::{ - ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding, - KeybindingHint, PopoverMenu, Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar, - prelude::*, + ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, PopoverMenu, + Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar, prelude::*, }; use ui_input::{NumberField, NumberFieldType}; use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath}; @@ -42,8 +41,12 @@ use crate::components::SettingsEditor; const NAVBAR_CONTAINER_TAB_INDEX: isize = 0; const NAVBAR_GROUP_TAB_INDEX: isize = 1; -const CONTENT_CONTAINER_TAB_INDEX: isize = 2; -const CONTENT_GROUP_TAB_INDEX: isize = 3; + +const HEADER_CONTAINER_TAB_INDEX: isize = 2; +const HEADER_GROUP_TAB_INDEX: isize = 3; + +const CONTENT_CONTAINER_TAB_INDEX: isize = 4; +const CONTENT_GROUP_TAB_INDEX: isize = 5; actions!( settings_editor, @@ -206,35 +209,12 @@ pub fn init(cx: &mut App) { init_renderers(cx); cx.observe_new(|workspace: &mut workspace::Workspace, _, _| { - workspace.register_action_renderer(|div, _, _, cx| { - let settings_ui_actions = [ - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - ]; - let has_flag = cx.has_flag::(); - command_palette_hooks::CommandPaletteFilter::update_global(cx, |filter, _| { - if has_flag { - filter.show_action_types(&settings_ui_actions); - } else { - filter.hide_action_types(&settings_ui_actions); - } - }); - if has_flag { - div.on_action( - cx.listener(|workspace, _: &OpenSettingsEditor, window, cx| { - let window_handle = window - .window_handle() - .downcast::() - .expect("Workspaces are root Windows"); - open_settings_editor(workspace, window_handle, cx); - }), - ) - } else { - div - } + workspace.register_action(|workspace, _: &OpenSettingsEditor, window, cx| { + let window_handle = window + .window_handle() + .downcast::() + .expect("Workspaces are root Windows"); + open_settings_editor(workspace, window_handle, cx); }); }) .detach(); @@ -472,7 +452,8 @@ pub fn open_settings_editor( show: true, kind: gpui::WindowKind::Normal, window_background: cx.theme().window_background_appearance(), - window_min_size: Some(size(px(800.), px(600.))), // 4:3 Aspect Ratio + window_min_size: Some(size(px(900.), px(750.))), // 4:3 Aspect Ratio + window_bounds: Some(WindowBounds::centered(size(px(900.), px(750.)), cx)), ..Default::default() }, |window, cx| cx.new(|cx| SettingsWindow::new(Some(workspace_handle), window, cx)), @@ -886,7 +867,10 @@ impl SettingsWindow { .focus_handle() .tab_index(CONTENT_CONTAINER_TAB_INDEX) .tab_stop(false), - files_focus_handle: cx.focus_handle().tab_stop(false), + files_focus_handle: cx + .focus_handle() + .tab_index(HEADER_CONTAINER_TAB_INDEX) + .tab_stop(false), }; this.fetch_files(cx); @@ -1206,7 +1190,7 @@ impl SettingsWindow { .find_map(|(prev_file, handle)| { (prev_file == &settings_ui_file).then(|| handle.clone()) }) - .unwrap_or_else(|| cx.focus_handle()); + .unwrap_or_else(|| cx.focus_handle().tab_index(0).tab_stop(true)); ui_files.push((settings_ui_file, focus_handle)); } ui_files.reverse(); @@ -1223,14 +1207,22 @@ impl SettingsWindow { fn change_file(&mut self, ix: usize, cx: &mut Context) { if ix >= self.files.len() { self.current_file = SettingsUiFile::User; + self.build_ui(cx); return; } if self.files[ix].0 == self.current_file { return; } self.current_file = self.files[ix].0.clone(); - // self.navbar_entry = 0; + self.navbar_entry = 0; self.build_ui(cx); + + let first_navbar_entry_index = self + .visible_navbar_entries() + .next() + .map(|e| e.0) + .unwrap_or(0); + self.navbar_entry = first_navbar_entry_index; } fn render_files_header( @@ -1242,6 +1234,9 @@ impl SettingsWindow { .w_full() .gap_1() .justify_between() + .tab_group() + .track_focus(&self.files_focus_handle) + .tab_index(HEADER_GROUP_TAB_INDEX) .child( h_flex() .id("file_buttons_container") @@ -1261,26 +1256,23 @@ impl SettingsWindow { .toggle_state(file == &self.current_file) .selected_style(ButtonStyle::Tinted(ui::TintColor::Accent)) .track_focus(focus_handle) - .on_click(cx.listener( - move |this, evt: &gpui::ClickEvent, window, cx| { + .on_click(cx.listener({ + let focus_handle = focus_handle.clone(); + move |this, _: &gpui::ClickEvent, window, cx| { this.change_file(ix, cx); - if evt.is_keyboard() { - this.focus_first_nav_item(window, cx); - } - }, - )) + focus_handle.focus(window); + } + })) }), ), ) .child( - Button::new( - "edit-in-json", - format!("Edit in {}", self.file_location_str()), - ) - .style(ButtonStyle::Outlined) - .on_click(cx.listener(|this, _, _, cx| { - this.open_current_settings_file(cx); - })), + Button::new("edit-in-json", "Edit in settings.json") + .tab_index(0_isize) + .style(ButtonStyle::Outlined) + .on_click(cx.listener(|this, _, _, cx| { + this.open_current_settings_file(cx); + })), ) } @@ -1307,26 +1299,28 @@ impl SettingsWindow { } } - fn file_location_str(&self) -> String { - match &self.current_file { - SettingsUiFile::User => "settings.json".to_string(), - SettingsUiFile::Project((worktree_id, path)) => self - .worktree_root_dirs - .get(&worktree_id) - .map(|directory_name| { - let path_style = PathStyle::local(); - let file_path = path.join(paths::local_settings_file_relative_path()); - format!( - "{}{}{}", - directory_name, - path_style.separator(), - file_path.display(path_style) - ) - }) - .expect("Current file should always be present in root dir map"), - SettingsUiFile::Server(file) => file.to_string(), - } - } + // TODO: + // Reconsider this after preview launch + // fn file_location_str(&self) -> String { + // match &self.current_file { + // SettingsUiFile::User => "settings.json".to_string(), + // SettingsUiFile::Project((worktree_id, path)) => self + // .worktree_root_dirs + // .get(&worktree_id) + // .map(|directory_name| { + // let path_style = PathStyle::local(); + // let file_path = path.join(paths::local_settings_file_relative_path()); + // format!( + // "{}{}{}", + // directory_name, + // path_style.separator(), + // file_path.display(path_style) + // ) + // }) + // .expect("Current file should always be present in root dir map"), + // SettingsUiFile::Server(file) => file.to_string(), + // } + // } fn render_search(&self, _window: &mut Window, cx: &mut App) -> Div { h_flex() @@ -1349,11 +1343,11 @@ impl SettingsWindow { ) -> impl IntoElement { let visible_count = self.visible_navbar_entries().count(); - let focus_keybind_label = if self.navbar_focus_handle.contains_focused(window, cx) { - "Focus Content" - } else { - "Focus Navbar" - }; + // let focus_keybind_label = if self.navbar_focus_handle.contains_focused(window, cx) { + // "Focus Content" + // } else { + // "Focus Navbar" + // }; v_flex() .w_64() @@ -1437,24 +1431,25 @@ impl SettingsWindow { ) .vertical_scrollbar_for(self.list_handle.clone(), window, cx), ) - .child( - h_flex() - .w_full() - .p_2() - .pb_0p5() - .flex_none() - .border_t_1() - .border_color(cx.theme().colors().border_variant) - .children( - KeyBinding::for_action(&ToggleFocusNav, window, cx).map(|this| { - KeybindingHint::new( - this, - cx.theme().colors().surface_background.opacity(0.5), - ) - .suffix(focus_keybind_label) - }), - ), - ) + // TODO: Restore this once we've fixed the ToggleFocusNav action + // .child( + // h_flex() + // .w_full() + // .p_2() + // .pb_0p5() + // .flex_none() + // .border_t_1() + // .border_color(cx.theme().colors().border_variant) + // .children( + // KeyBinding::for_action(&ToggleFocusNav, window, cx).map(|this| { + // KeybindingHint::new( + // this, + // cx.theme().colors().surface_background.opacity(0.5), + // ) + // .suffix(focus_keybind_label) + // }), + // ), + // ) } fn focus_first_nav_item(&self, window: &mut Window, cx: &mut Context) { diff --git a/crates/ui/src/components/tree_view_item.rs b/crates/ui/src/components/tree_view_item.rs index babc52029af25d4d7babedd9c0a1ffa0aecabf4e..5c038585eb600fbb335bb1a52be2fe65d68beffa 100644 --- a/crates/ui/src/components/tree_view_item.rs +++ b/crates/ui/src/components/tree_view_item.rs @@ -129,7 +129,6 @@ impl RenderOnce for TreeViewItem { let selected_border = cx.theme().colors().border.opacity(0.6); let focused_border = cx.theme().colors().border_focused; - let transparent_border = cx.theme().colors().border_transparent; let item_size = rems_from_px(28.); let indentation_line = h_flex().size(item_size).flex_none().justify_center().child( @@ -150,6 +149,13 @@ impl RenderOnce for TreeViewItem { .cursor_pointer() .size_full() .relative() + .border_1() + .focus(|s| s.border_color(focused_border)) + .when_some(self.tab_index, |this, index| this.tab_index(index)) + .when(self.selected, |this| { + this.border_color(selected_border).bg(selected_bg) + }) + .hover(|s| s.bg(cx.theme().colors().element_hover)) .map(|this| { let label = self.label; @@ -158,14 +164,6 @@ impl RenderOnce for TreeViewItem { .px_1() .gap_2p5() .rounded_sm() - .border_1() - .border_color(transparent_border) - .when(self.selected, |this| { - this.border_color(selected_border).bg(selected_bg) - }) - .focus(|s| s.border_color(focused_border)) - .hover(|s| s.bg(cx.theme().colors().element_hover)) - .when_some(self.tab_index, |this, index| this.tab_index(index)) .child( Disclosure::new("toggle", self.expanded) .when_some( @@ -189,14 +187,7 @@ impl RenderOnce for TreeViewItem { .flex_grow() .px_1() .rounded_sm() - .border_1() - .border_color(transparent_border) - .when(self.selected, |this| { - this.border_color(selected_border).bg(selected_bg) - }) - .focus(|s| s.border_color(focused_border)) .hover(|s| s.bg(cx.theme().colors().element_hover)) - .when_some(self.tab_index, |this, index| this.tab_index(index)) .child( Label::new(label) .when(!self.selected, |this| this.color(Color::Muted)),