settings ui: Add another batch of UX fixes and improvements (#39742)
Release Notes: - N/A
This commit is contained in:
@@ -9,7 +9,7 @@ use workspace::{
|
||||
item::{Item, ItemEvent},
|
||||
with_active_or_new_workspace,
|
||||
};
|
||||
use zed_actions::{Extensions, OpenSettings, agent, command_palette};
|
||||
use zed_actions::{Extensions, OpenSettingsEditor, agent, command_palette};
|
||||
|
||||
use crate::{Onboarding, OpenOnboarding};
|
||||
|
||||
@@ -53,7 +53,7 @@ const CONTENT: (Section<4>, Section<3>) = (
|
||||
SectionEntry {
|
||||
icon: IconName::Settings,
|
||||
title: "Open Settings",
|
||||
action: &OpenSettings,
|
||||
action: &OpenSettingsEditor,
|
||||
},
|
||||
SectionEntry {
|
||||
icon: IconName::ZedAssistant,
|
||||
|
||||
@@ -131,7 +131,7 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
files: USER,
|
||||
title: "Settings Profiles",
|
||||
description: "Any number of settings profiles that are temporarily applied on top of your existing user settings.",
|
||||
description: "Any number of settings profiles that are temporarily applied on top of your existing user settings",
|
||||
field: Box::new(
|
||||
SettingField {
|
||||
pick: |settings_content| &settings_content.workspace.use_system_prompts,
|
||||
@@ -295,6 +295,28 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Agent Panel UI Font Size",
|
||||
description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| &settings_content.theme.agent_ui_font_size,
|
||||
pick_mut: |settings_content| &mut settings_content.theme.agent_ui_font_size,
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Agent Panel Buffer Font Size",
|
||||
description: "Font size for user messages text in the agent panel",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| &settings_content.theme.agent_buffer_font_size,
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content.theme.agent_buffer_font_size
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SectionHeader("Keymap"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Base Keymap",
|
||||
@@ -1020,7 +1042,7 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Min Line Number Digits",
|
||||
description: "Minimum number of characters to reserve space for in the gutter.",
|
||||
description: "Minimum number of characters to reserve space for in the gutter",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(gutter) = &settings_content.editor.gutter {
|
||||
@@ -1638,6 +1660,27 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
title: "Workbench & Window",
|
||||
items: vec![
|
||||
SettingsPageItem::SectionHeader("Status Bar"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Project Panel Button",
|
||||
description: "Whether to show the project panel button in the status bar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(project_panel) = &settings_content.project_panel {
|
||||
&project_panel.button
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content
|
||||
.project_panel
|
||||
.get_or_insert_default()
|
||||
.button
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Active Language Button",
|
||||
description: "Whether to show the active language button in the status bar",
|
||||
@@ -1738,6 +1781,24 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Debugger Button",
|
||||
description: "Whether to show the debugger button in the status bar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(debugger) = &settings_content.debugger {
|
||||
&debugger.button
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content.debugger.get_or_insert_default().button
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SectionHeader("Tab Bar"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Editor Tabs",
|
||||
@@ -1844,7 +1905,7 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Show Onboarding Banner",
|
||||
description: "Whether to show onboarding banners in the titlebar",
|
||||
description: "Whether to show banners announcing new features in the titlebar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(title_bar) = &settings_content.title_bar {
|
||||
@@ -2255,27 +2316,6 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
title: "Panels",
|
||||
items: vec![
|
||||
SettingsPageItem::SectionHeader("Project Panel"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Project Panel Button",
|
||||
description: "Whether to show the project panel button in the status bar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(project_panel) = &settings_content.project_panel {
|
||||
&project_panel.button
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content
|
||||
.project_panel
|
||||
.get_or_insert_default()
|
||||
.button
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Project Panel Dock",
|
||||
description: "Where to dock the project panel",
|
||||
@@ -2884,8 +2924,8 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
}),
|
||||
SettingsPageItem::SectionHeader("Git Panel"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Button",
|
||||
description: "Whether to show the git panel button in the status bar",
|
||||
title: "Git Panel Button",
|
||||
description: "Whether to show the Git panel button in the status bar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(git_panel) = &settings_content.git_panel {
|
||||
@@ -2902,8 +2942,8 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Dock",
|
||||
description: "Where to dock the git panel",
|
||||
title: "Git Panel Dock",
|
||||
description: "Where to dock the Git panel",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(git_panel) = &settings_content.git_panel {
|
||||
@@ -2920,8 +2960,8 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Default Width",
|
||||
description: "Default width of the git panel in pixels",
|
||||
title: "Git Panel Default Width",
|
||||
description: "Default width of the Git panel in pixels",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(git_panel) = &settings_content.git_panel {
|
||||
@@ -2940,6 +2980,25 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SectionHeader("Debugger Panel"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Debugger Panel Dock",
|
||||
description: "The dock position of the debug panel",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(debugger) = &settings_content.debugger {
|
||||
&debugger.dock
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content.debugger.get_or_insert_default().dock
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SectionHeader("Notification Panel"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Notification Panel Button",
|
||||
@@ -3636,24 +3695,6 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Dock",
|
||||
description: "The dock position of the debug panel",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(debugger) = &settings_content.debugger {
|
||||
&debugger.dock
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content.debugger.get_or_insert_default().dock
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Log DAP Communications",
|
||||
description: "Whether to log messages between active debug adapters and Zed",
|
||||
@@ -3696,24 +3737,6 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Button",
|
||||
description: "Whether to show the debug button in the status bar",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
if let Some(debugger) = &settings_content.debugger {
|
||||
&debugger.button
|
||||
} else {
|
||||
&None
|
||||
}
|
||||
},
|
||||
pick_mut: |settings_content| {
|
||||
&mut settings_content.debugger.get_or_insert_default().button
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
],
|
||||
},
|
||||
SettingsPage {
|
||||
@@ -4006,7 +4029,7 @@ fn language_settings_data() -> Vec<SettingsPageItem> {
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Show Wrap Guides",
|
||||
description: "Whether to show wrap guides in the editor. Setting this to true will show a guide at the 'preferred_line_length' value if softwrap is set to 'preferred_line_length', and will show any additional guides as specified by the 'wrap_guides' setting",
|
||||
description: "Whether to show wrap guides in the editor",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
language_settings_field(settings_content, |language| &language.show_wrap_guides)
|
||||
@@ -4438,7 +4461,7 @@ fn language_settings_data() -> Vec<SettingsPageItem> {
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Always Treat Brackets As Autoclosed",
|
||||
description: "Controls how the editor handles the autoclosed characters. When set to `false`(default), skipping over and auto-removing of the closing characters happen only for auto-inserted characters. Otherwise(when `true`), the closing characters are always skipped over and auto-removed no matter how they were inserted",
|
||||
description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
language_settings_field(settings_content, |language| {
|
||||
@@ -4518,7 +4541,7 @@ fn language_settings_data() -> Vec<SettingsPageItem> {
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Linked Edits",
|
||||
description: "Whether to perform linked edits of associated ranges, if the language server supports it. For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well",
|
||||
description: "Whether to perform linked edits of associated ranges, if the LS supports it. For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well",
|
||||
field: Box::new(SettingField {
|
||||
pick: |settings_content| {
|
||||
language_settings_field(settings_content, |language| &language.linked_edits)
|
||||
|
||||
@@ -29,8 +29,9 @@ use std::{
|
||||
sync::{Arc, LazyLock, RwLock, atomic::AtomicBool},
|
||||
};
|
||||
use ui::{
|
||||
ContextMenu, Divider, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding, KeybindingHint,
|
||||
PopoverMenu, Switch, SwitchColor, TreeViewItem, WithScrollbar, prelude::*,
|
||||
ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding,
|
||||
KeybindingHint, PopoverMenu, Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar,
|
||||
prelude::*,
|
||||
};
|
||||
use ui_input::{NumberField, NumberFieldType};
|
||||
use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath};
|
||||
@@ -242,6 +243,9 @@ fn init_renderers(cx: &mut App) {
|
||||
.icon_color(Color::Error)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.tooltip(Tooltip::text(
|
||||
"This warning is only displayed in dev builds.",
|
||||
))
|
||||
.into_any_element()
|
||||
})
|
||||
.add_renderer::<bool>(|settings_field, file, _, _, cx| {
|
||||
@@ -554,14 +558,14 @@ impl SettingsPageItem {
|
||||
match self {
|
||||
SettingsPageItem::SectionHeader(header) => v_flex()
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
Label::new(SharedString::new_static(header))
|
||||
.size(LabelSize::XSmall)
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.buffer_font(cx),
|
||||
)
|
||||
.child(Divider::horizontal().color(ui::DividerColor::BorderVariant))
|
||||
.child(Divider::horizontal().color(DividerColor::BorderFaded))
|
||||
.into_any_element(),
|
||||
SettingsPageItem::SettingItem(setting_item) => {
|
||||
let renderer = cx.default_global::<SettingFieldRenderer>().clone();
|
||||
@@ -571,8 +575,8 @@ impl SettingsPageItem {
|
||||
h_flex()
|
||||
.id(setting_item.title)
|
||||
.w_full()
|
||||
.min_w_0()
|
||||
.gap_2()
|
||||
.flex_wrap()
|
||||
.justify_between()
|
||||
.map(|this| {
|
||||
if is_last {
|
||||
@@ -585,8 +589,8 @@ impl SettingsPageItem {
|
||||
})
|
||||
.child(
|
||||
v_flex()
|
||||
.w_full()
|
||||
.max_w_1_2()
|
||||
.flex_shrink()
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
@@ -620,6 +624,9 @@ impl SettingsPageItem {
|
||||
.icon_color(Color::Error)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.tooltip(Tooltip::text(
|
||||
"This warning is only displayed in dev builds.",
|
||||
))
|
||||
.into_any_element()
|
||||
} else {
|
||||
renderer.render(
|
||||
@@ -651,7 +658,6 @@ impl SettingsPageItem {
|
||||
)
|
||||
.child(
|
||||
Button::new(("sub-page".into(), sub_page_link.title), "Configure")
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ChevronRight)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
@@ -1218,6 +1224,7 @@ impl SettingsWindow {
|
||||
h_flex()
|
||||
.py_1()
|
||||
.px_1p5()
|
||||
.mb_3()
|
||||
.gap_1p5()
|
||||
.rounded_sm()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
@@ -1233,7 +1240,7 @@ impl SettingsWindow {
|
||||
cx: &mut Context<SettingsWindow>,
|
||||
) -> impl IntoElement {
|
||||
let visible_count = self.visible_navbar_entries().count();
|
||||
let nav_background = cx.theme().colors().panel_background;
|
||||
|
||||
let focus_keybind_label = if self.navbar_focus_handle.contains_focused(window, cx) {
|
||||
"Focus Content"
|
||||
} else {
|
||||
@@ -1244,15 +1251,14 @@ impl SettingsWindow {
|
||||
.w_64()
|
||||
.p_2p5()
|
||||
.pt_10()
|
||||
.gap_3()
|
||||
.flex_none()
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.bg(nav_background)
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
.child(self.render_search(window, cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.flex_grow()
|
||||
.size_full()
|
||||
.track_focus(&self.navbar_focus_handle)
|
||||
.tab_group()
|
||||
.tab_index(NAVBAR_GROUP_TAB_INDEX)
|
||||
@@ -1280,53 +1286,46 @@ impl SettingsWindow {
|
||||
},
|
||||
))
|
||||
})
|
||||
.on_click(cx.listener(
|
||||
move |this, evt: &gpui::ClickEvent, window, cx| {
|
||||
this.navbar_entry = ix;
|
||||
.on_click(cx.listener(move |this, _, _, cx| {
|
||||
this.navbar_entry = ix;
|
||||
|
||||
if !this.navbar_entries[ix].is_root {
|
||||
let mut selected_page_ix = ix;
|
||||
if !this.navbar_entries[ix].is_root {
|
||||
let mut selected_page_ix = ix;
|
||||
|
||||
while !this.navbar_entries[selected_page_ix]
|
||||
.is_root
|
||||
{
|
||||
selected_page_ix -= 1;
|
||||
}
|
||||
|
||||
let section_header = ix - selected_page_ix;
|
||||
|
||||
if let Some(section_index) = this
|
||||
.page_items()
|
||||
.enumerate()
|
||||
.filter(|item| {
|
||||
matches!(
|
||||
item.1,
|
||||
SettingsPageItem::SectionHeader(_)
|
||||
)
|
||||
})
|
||||
.take(section_header)
|
||||
.last()
|
||||
.map(|pair| pair.0)
|
||||
{
|
||||
this.scroll_handle
|
||||
.scroll_to_top_of_item(section_index);
|
||||
}
|
||||
while !this.navbar_entries[selected_page_ix].is_root
|
||||
{
|
||||
selected_page_ix -= 1;
|
||||
}
|
||||
|
||||
if evt.is_keyboard() {
|
||||
// todo(settings_ui): Focus the actual item and scroll to it
|
||||
this.focus_first_content_item(window, cx);
|
||||
let section_header = ix - selected_page_ix;
|
||||
|
||||
if let Some(section_index) = this
|
||||
.page_items()
|
||||
.enumerate()
|
||||
.filter(|item| {
|
||||
matches!(
|
||||
item.1,
|
||||
SettingsPageItem::SectionHeader(_)
|
||||
)
|
||||
})
|
||||
.take(section_header)
|
||||
.last()
|
||||
.map(|pair| pair.0)
|
||||
{
|
||||
this.scroll_handle
|
||||
.scroll_to_top_of_item(section_index);
|
||||
}
|
||||
cx.notify();
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
}))
|
||||
.into_any_element()
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
)
|
||||
.track_scroll(self.list_handle.clone())
|
||||
.flex_grow(),
|
||||
.size_full()
|
||||
.track_scroll(self.list_handle.clone()),
|
||||
)
|
||||
.vertical_scrollbar_for(self.list_handle.clone(), window, cx),
|
||||
)
|
||||
@@ -1335,6 +1334,7 @@ impl SettingsWindow {
|
||||
.w_full()
|
||||
.p_2()
|
||||
.pb_0p5()
|
||||
.flex_none()
|
||||
.border_t_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.children(
|
||||
@@ -1804,7 +1804,6 @@ fn render_number_field<T: NumberFieldType + Send + Sync>(
|
||||
.log_err(); // todo(settings_ui) don't log err
|
||||
}
|
||||
})
|
||||
.tab_index(0)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
|
||||
@@ -126,11 +126,12 @@ impl Toggleable for TreeViewItem {
|
||||
impl RenderOnce for TreeViewItem {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let selected_bg = cx.theme().colors().element_active.opacity(0.5);
|
||||
|
||||
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 item_size = rems_from_px(28.);
|
||||
let indentation_line = h_flex().size(item_size).flex_none().justify_center().child(
|
||||
div()
|
||||
.w_px()
|
||||
@@ -149,14 +150,12 @@ impl RenderOnce for TreeViewItem {
|
||||
.cursor_pointer()
|
||||
.size_full()
|
||||
.relative()
|
||||
.when_some(self.tab_index, |this, index| this.tab_index(index))
|
||||
.map(|this| {
|
||||
let label = self.label;
|
||||
|
||||
if self.root_item {
|
||||
this.h(item_size)
|
||||
.px_1()
|
||||
.mb_1()
|
||||
.gap_2p5()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
@@ -166,6 +165,7 @@ impl RenderOnce for TreeViewItem {
|
||||
})
|
||||
.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(
|
||||
@@ -190,13 +190,13 @@ impl RenderOnce for TreeViewItem {
|
||||
.px_1()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
.focusable()
|
||||
.border_color(transparent_border)
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.in_focus(|s| s.border_color(focused_border))
|
||||
.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)),
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
};
|
||||
|
||||
use editor::{Editor, EditorStyle};
|
||||
use gpui::{ClickEvent, Entity, FocusHandle, Focusable, FontWeight, Modifiers};
|
||||
use gpui::{ClickEvent, CursorStyle, Entity, FocusHandle, Focusable, FontWeight, Modifiers};
|
||||
|
||||
use settings::{CodeFade, MinimumContrast};
|
||||
use ui::prelude::*;
|
||||
@@ -344,6 +344,27 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
|
||||
}
|
||||
};
|
||||
|
||||
let bg_color = cx.theme().colors().surface_background;
|
||||
let hover_bg_color = cx.theme().colors().element_hover;
|
||||
|
||||
let border_color = cx.theme().colors().border_variant;
|
||||
let focus_border_color = cx.theme().colors().border_focused;
|
||||
|
||||
let base_button = |icon: IconName| {
|
||||
h_flex()
|
||||
.cursor(CursorStyle::PointingHand)
|
||||
.p_1p5()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.overflow_hidden()
|
||||
.border_1()
|
||||
.border_color(border_color)
|
||||
.bg(bg_color)
|
||||
.hover(|s| s.bg(hover_bg_color))
|
||||
.focus(|s| s.border_color(focus_border_color).bg(hover_bg_color))
|
||||
.child(Icon::new(icon).size(IconSize::Small))
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.id(self.id.clone())
|
||||
.track_focus(&self.focus_handle)
|
||||
@@ -376,28 +397,19 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
|
||||
};
|
||||
|
||||
decrement.child(
|
||||
h_flex()
|
||||
base_button(IconName::Dash)
|
||||
.id("decrement_button")
|
||||
.cursor(gpui::CursorStyle::PointingHand)
|
||||
.p_1p5()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.overflow_hidden()
|
||||
.rounded_tl_sm()
|
||||
.rounded_bl_sm()
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.bg(cx.theme().colors().surface_background)
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.child(Icon::new(IconName::Dash).size(IconSize::Small))
|
||||
.when_some(tab_index.as_mut(), |this, tab_index| {
|
||||
*tab_index += 1;
|
||||
this.tab_index(*tab_index - 1).focus(|style| {
|
||||
style
|
||||
.border_color(cx.theme().colors().border_focused)
|
||||
.bg(cx.theme().colors().element_hover)
|
||||
})
|
||||
})
|
||||
.tab_index(
|
||||
tab_index
|
||||
.as_mut()
|
||||
.map(|tab_index| {
|
||||
*tab_index += 1;
|
||||
*tab_index - 1
|
||||
})
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.on_click(decrement_handler),
|
||||
)
|
||||
})
|
||||
@@ -406,34 +418,23 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
|
||||
.min_w_16()
|
||||
.size_full()
|
||||
.border_y_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.bg(cx.theme().colors().surface_background)
|
||||
.in_focus(|this| this.border_color(cx.theme().colors().border_focused))
|
||||
.border_color(border_color)
|
||||
.bg(bg_color)
|
||||
.in_focus(|this| this.border_color(focus_border_color))
|
||||
.child(match *self.mode.read(cx) {
|
||||
NumberFieldMode::Read => h_flex()
|
||||
.id("numeric_stepper_label")
|
||||
.px_1()
|
||||
.flex_1()
|
||||
.justify_center()
|
||||
.child(Label::new((self.format)(&self.value)))
|
||||
.when_some(tab_index.as_mut(), |this, tab_index| {
|
||||
*tab_index += 1;
|
||||
this.tab_index(*tab_index - 1).focus(|style| {
|
||||
style
|
||||
.border_color(cx.theme().colors().border_focused)
|
||||
.bg(cx.theme().colors().element_hover)
|
||||
})
|
||||
})
|
||||
.on_click({
|
||||
let _mode = self.mode.clone();
|
||||
move |click, _, _cx| {
|
||||
if click.click_count() == 2 || click.is_keyboard() {
|
||||
// Edit mode is disabled until we implement center text alignment for editor
|
||||
// mode.write(cx, NumberFieldMode::Edit);
|
||||
}
|
||||
}
|
||||
})
|
||||
.into_any_element(),
|
||||
// Edit mode is disabled until we implement center text alignment for editor
|
||||
// mode.write(cx, NumberFieldMode::Edit);
|
||||
//
|
||||
// When we get to making Edit mode work, we shouldn't even focus the decrement/increment buttons.
|
||||
// Focus should go instead straight to the editor, avoiding any double-step focus.
|
||||
// In this world, the buttons become a mouse-only interaction, given users should be able
|
||||
// to do everything they'd do with the buttons straight in the editor anyway.
|
||||
NumberFieldMode::Edit => h_flex()
|
||||
.flex_1()
|
||||
.child(window.use_state(cx, {
|
||||
@@ -501,28 +502,19 @@ impl<T: NumberFieldType> RenderOnce for NumberField<T> {
|
||||
};
|
||||
|
||||
increment.child(
|
||||
h_flex()
|
||||
base_button(IconName::Plus)
|
||||
.id("increment_button")
|
||||
.cursor(gpui::CursorStyle::PointingHand)
|
||||
.p_1p5()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.overflow_hidden()
|
||||
.rounded_tr_sm()
|
||||
.rounded_br_sm()
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.bg(cx.theme().colors().surface_background)
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.child(Icon::new(IconName::Plus).size(IconSize::Small))
|
||||
.when_some(tab_index.as_mut(), |this, tab_index| {
|
||||
*tab_index += 1;
|
||||
this.tab_index(*tab_index - 1).focus(|style| {
|
||||
style
|
||||
.border_color(cx.theme().colors().border_focused)
|
||||
.bg(cx.theme().colors().element_hover)
|
||||
})
|
||||
})
|
||||
.tab_index(
|
||||
tab_index
|
||||
.as_mut()
|
||||
.map(|tab_index| {
|
||||
*tab_index += 1;
|
||||
*tab_index - 1
|
||||
})
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.on_click(increment_handler),
|
||||
)
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user