Add support for typing in the numeric stepper componenets
This commit is contained in:
parent
43b4363b34
commit
c5a258e0b8
9 changed files with 156 additions and 31 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -11095,6 +11095,7 @@ dependencies = [
|
||||||
"telemetry",
|
"telemetry",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
|
"ui_input",
|
||||||
"util",
|
"util",
|
||||||
"vim_mode_setting",
|
"vim_mode_setting",
|
||||||
"workspace",
|
"workspace",
|
||||||
|
@ -17514,6 +17515,7 @@ dependencies = [
|
||||||
"component",
|
"component",
|
||||||
"editor",
|
"editor",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"menu",
|
||||||
"settings",
|
"settings",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
|
|
|
@ -5,8 +5,7 @@ use project::project_settings::{InlineBlameSettings, ProjectSettings};
|
||||||
use settings::{EditableSettingControl, Settings};
|
use settings::{EditableSettingControl, Settings};
|
||||||
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer, SettingsGroup,
|
CheckboxWithLabel, ContextMenu, DropdownMenu, SettingsContainer, SettingsGroup, prelude::*,
|
||||||
prelude::*,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::EditorSettings;
|
use crate::EditorSettings;
|
||||||
|
@ -139,21 +138,12 @@ impl EditableSettingControl for BufferFontSizeControl {
|
||||||
|
|
||||||
impl RenderOnce for BufferFontSizeControl {
|
impl RenderOnce for BufferFontSizeControl {
|
||||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let value = Self::read(cx);
|
let _value = Self::read(cx);
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(Icon::new(IconName::FontSize))
|
.child(Icon::new(IconName::FontSize))
|
||||||
.child(NumericStepper::new(
|
.child(div()) // todo!(Numeric stepper was here)
|
||||||
"buffer-font-size",
|
|
||||||
value.to_string(),
|
|
||||||
move |_, _, cx| {
|
|
||||||
Self::write(value - px(1.), cx);
|
|
||||||
},
|
|
||||||
move |_, _, cx| {
|
|
||||||
Self::write(value + px(1.), cx);
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ settings.workspace = true
|
||||||
telemetry.workspace = true
|
telemetry.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
|
ui_input.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
vim_mode_setting.workspace = true
|
vim_mode_setting.workspace = true
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
|
|
|
@ -12,10 +12,10 @@ use project::project_settings::ProjectSettings;
|
||||||
use settings::{Settings as _, update_settings_file};
|
use settings::{Settings as _, update_settings_file};
|
||||||
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
ButtonLike, ListItem, ListItemSpacing, NumericStepper, PopoverMenu, SwitchField,
|
ButtonLike, ListItem, ListItemSpacing, PopoverMenu, SwitchField, ToggleButtonGroup,
|
||||||
ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, Tooltip,
|
ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, Tooltip, prelude::*,
|
||||||
prelude::*,
|
|
||||||
};
|
};
|
||||||
|
use ui_input::NumericStepper;
|
||||||
|
|
||||||
use crate::{ImportCursorSettings, ImportVsCodeSettings, SettingsImportState};
|
use crate::{ImportCursorSettings, ImportVsCodeSettings, SettingsImportState};
|
||||||
|
|
||||||
|
@ -350,14 +350,19 @@ fn render_font_customization_section(
|
||||||
NumericStepper::new(
|
NumericStepper::new(
|
||||||
"ui-font-size",
|
"ui-font-size",
|
||||||
ui_font_size.to_string(),
|
ui_font_size.to_string(),
|
||||||
|
move |size, cx| {
|
||||||
|
write_ui_font_size(Pixels::from(size), cx);
|
||||||
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
write_ui_font_size(ui_font_size - px(1.), cx);
|
write_ui_font_size(ui_font_size - px(1.), cx);
|
||||||
},
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
write_ui_font_size(ui_font_size + px(1.), cx);
|
write_ui_font_size(ui_font_size + px(1.), cx);
|
||||||
},
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
.style(ui::NumericStepperStyle::Outlined)
|
.style(ui_input::NumericStepperStyle::Outlined)
|
||||||
.tab_index({
|
.tab_index({
|
||||||
*tab_index += 2;
|
*tab_index += 2;
|
||||||
*tab_index - 2
|
*tab_index - 2
|
||||||
|
@ -414,14 +419,19 @@ fn render_font_customization_section(
|
||||||
NumericStepper::new(
|
NumericStepper::new(
|
||||||
"buffer-font-size",
|
"buffer-font-size",
|
||||||
buffer_font_size.to_string(),
|
buffer_font_size.to_string(),
|
||||||
|
move |size, cx| {
|
||||||
|
write_buffer_font_size(Pixels::from(size), cx);
|
||||||
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
write_buffer_font_size(buffer_font_size - px(1.), cx);
|
write_buffer_font_size(buffer_font_size - px(1.), cx);
|
||||||
},
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
write_buffer_font_size(buffer_font_size + px(1.), cx);
|
write_buffer_font_size(buffer_font_size + px(1.), cx);
|
||||||
},
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
.style(ui::NumericStepperStyle::Outlined)
|
.style(ui_input::NumericStepperStyle::Outlined)
|
||||||
.tab_index({
|
.tab_index({
|
||||||
*tab_index += 2;
|
*tab_index += 2;
|
||||||
*tab_index - 2
|
*tab_index - 2
|
||||||
|
|
|
@ -6,9 +6,10 @@ use theme::{
|
||||||
FontFamilyCache, FontFamilyName, SystemAppearance, ThemeMode, ThemeRegistry, ThemeSettings,
|
FontFamilyCache, FontFamilyName, SystemAppearance, ThemeMode, ThemeRegistry, ThemeSettings,
|
||||||
};
|
};
|
||||||
use ui::{
|
use ui::{
|
||||||
CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer, SettingsGroup,
|
CheckboxWithLabel, ContextMenu, DropdownMenu, SettingsContainer, SettingsGroup, ToggleButton,
|
||||||
ToggleButton, prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use ui_input::NumericStepper;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct AppearanceSettingsControls {}
|
pub struct AppearanceSettingsControls {}
|
||||||
|
@ -254,7 +255,7 @@ impl EditableSettingControl for UiFontSizeControl {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for UiFontSizeControl {
|
impl RenderOnce for UiFontSizeControl {
|
||||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let value = Self::read(cx);
|
let value = Self::read(cx);
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
|
@ -263,12 +264,17 @@ impl RenderOnce for UiFontSizeControl {
|
||||||
.child(NumericStepper::new(
|
.child(NumericStepper::new(
|
||||||
"ui-font-size",
|
"ui-font-size",
|
||||||
value.to_string(),
|
value.to_string(),
|
||||||
|
move |size, cx| {
|
||||||
|
Self::write(Pixels::from(size), cx);
|
||||||
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
Self::write(value - px(1.), cx);
|
Self::write(value - px(1.), cx);
|
||||||
},
|
},
|
||||||
move |_, _, cx| {
|
move |_, _, cx| {
|
||||||
Self::write(value + px(1.), cx);
|
Self::write(value + px(1.), cx);
|
||||||
},
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ mod list;
|
||||||
mod modal;
|
mod modal;
|
||||||
mod navigable;
|
mod navigable;
|
||||||
mod notification;
|
mod notification;
|
||||||
mod numeric_stepper;
|
|
||||||
mod popover;
|
mod popover;
|
||||||
mod popover_menu;
|
mod popover_menu;
|
||||||
mod progress;
|
mod progress;
|
||||||
|
@ -65,7 +64,6 @@ pub use list::*;
|
||||||
pub use modal::*;
|
pub use modal::*;
|
||||||
pub use navigable::*;
|
pub use navigable::*;
|
||||||
pub use notification::*;
|
pub use notification::*;
|
||||||
pub use numeric_stepper::*;
|
|
||||||
pub use popover::*;
|
pub use popover::*;
|
||||||
pub use popover_menu::*;
|
pub use popover_menu::*;
|
||||||
pub use progress::*;
|
pub use progress::*;
|
||||||
|
|
|
@ -15,6 +15,7 @@ path = "src/ui_input.rs"
|
||||||
component.workspace = true
|
component.workspace = true
|
||||||
editor.workspace = true
|
editor.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
|
menu.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use gpui::ClickEvent;
|
use editor::Editor;
|
||||||
|
use gpui::{ClickEvent, Entity, Focusable};
|
||||||
|
|
||||||
use crate::{IconButtonShape, prelude::*};
|
use ui::{IconButtonShape, prelude::*};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum NumericStepperStyle {
|
pub enum NumericStepperStyle {
|
||||||
|
@ -9,11 +10,21 @@ pub enum NumericStepperStyle {
|
||||||
Ghost,
|
Ghost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum NumericStepperMode {
|
||||||
|
#[default]
|
||||||
|
Read,
|
||||||
|
Edit,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoElement, RegisterComponent)]
|
#[derive(IntoElement, RegisterComponent)]
|
||||||
pub struct NumericStepper {
|
pub struct NumericStepper {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
value: SharedString,
|
value: SharedString,
|
||||||
style: NumericStepperStyle,
|
style: NumericStepperStyle,
|
||||||
|
input_field: Entity<Editor>,
|
||||||
|
mode: Entity<NumericStepperMode>,
|
||||||
|
set_value_to: Box<dyn Fn(usize, &mut App) + 'static>,
|
||||||
on_decrement: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
on_decrement: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
||||||
on_increment: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
on_increment: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
||||||
/// Whether to reserve space for the reset button.
|
/// Whether to reserve space for the reset button.
|
||||||
|
@ -26,15 +37,61 @@ impl NumericStepper {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: impl Into<ElementId>,
|
id: impl Into<ElementId>,
|
||||||
value: impl Into<SharedString>,
|
value: impl Into<SharedString>,
|
||||||
|
set_value_to: impl Fn(usize, &mut App) + 'static,
|
||||||
on_decrement: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
|
on_decrement: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
|
||||||
on_increment: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
|
on_increment: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let id = id.into();
|
||||||
|
let value = value.into();
|
||||||
|
|
||||||
|
let (input_field, mode) = window.with_global_id(id.clone(), |global_id, window| {
|
||||||
|
// todo! Make sure that using this api is inline and appropriate with the codebase
|
||||||
|
window.with_element_state::<(Entity<Editor>, Entity<NumericStepperMode>), _>(
|
||||||
|
global_id,
|
||||||
|
|mut editor, window| {
|
||||||
|
let state = editor
|
||||||
|
.get_or_insert_with(|| {
|
||||||
|
let mode = cx.new(|_| NumericStepperMode::default());
|
||||||
|
let weak_mode = mode.downgrade();
|
||||||
|
let editor = cx.new(|cx| {
|
||||||
|
let editor = Editor::single_line(window, cx);
|
||||||
|
|
||||||
|
cx.on_focus_out(
|
||||||
|
&editor.focus_handle(cx),
|
||||||
|
window,
|
||||||
|
move |this, _, window, cx| {
|
||||||
|
this.clear(window, cx);
|
||||||
|
|
||||||
|
weak_mode
|
||||||
|
.update(cx, |mode, _| *mode = NumericStepperMode::Read)
|
||||||
|
.ok();
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
editor
|
||||||
|
});
|
||||||
|
|
||||||
|
(editor, mode)
|
||||||
|
})
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
(state.clone(), state)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id,
|
||||||
value: value.into(),
|
value,
|
||||||
style: NumericStepperStyle::default(),
|
input_field,
|
||||||
|
mode,
|
||||||
|
set_value_to: Box::new(set_value_to),
|
||||||
on_decrement: Box::new(on_decrement),
|
on_decrement: Box::new(on_decrement),
|
||||||
on_increment: Box::new(on_increment),
|
on_increment: Box::new(on_increment),
|
||||||
|
style: NumericStepperStyle::default(),
|
||||||
reserve_space_for_reset: false,
|
reserve_space_for_reset: false,
|
||||||
on_reset: None,
|
on_reset: None,
|
||||||
tab_index: None,
|
tab_index: None,
|
||||||
|
@ -74,7 +131,7 @@ impl RenderOnce for NumericStepper {
|
||||||
let mut tab_index = self.tab_index;
|
let mut tab_index = self.tab_index;
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(self.id)
|
.id(self.id.clone())
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.map(|element| {
|
.map(|element| {
|
||||||
if let Some(on_reset) = self.on_reset {
|
if let Some(on_reset) = self.on_reset {
|
||||||
|
@ -146,7 +203,59 @@ impl RenderOnce for NumericStepper {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.child(Label::new(self.value).mx_3())
|
.child(if matches!(self.mode.read(cx), NumericStepperMode::Read) {
|
||||||
|
div()
|
||||||
|
.id(SharedString::new(format!(
|
||||||
|
"numeric_stepper_label{}",
|
||||||
|
&self.id,
|
||||||
|
)))
|
||||||
|
.child(Label::new(self.value).mx_3())
|
||||||
|
.on_click({
|
||||||
|
let mode = self.mode.downgrade();
|
||||||
|
let input_field_focus_handle = self.input_field.focus_handle(cx);
|
||||||
|
|
||||||
|
move |click, window, cx| {
|
||||||
|
if click.click_count() == 2 {
|
||||||
|
mode.update(cx, |mode, _| {
|
||||||
|
*mode = NumericStepperMode::Edit;
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
window.focus(&input_field_focus_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into_any_element()
|
||||||
|
} else {
|
||||||
|
div()
|
||||||
|
.child(self.input_field.clone())
|
||||||
|
.child("todo!(This should be removed. It's only here to get input_field to render correctly)")
|
||||||
|
.on_action::<menu::Confirm>({
|
||||||
|
let input_field = self.input_field.downgrade();
|
||||||
|
let mode = self.mode.downgrade();
|
||||||
|
let set_value = self.set_value_to;
|
||||||
|
|
||||||
|
move |_, _, cx| {
|
||||||
|
input_field
|
||||||
|
.update(cx, |input_field, cx| {
|
||||||
|
if let Some(number) =
|
||||||
|
input_field.text(cx).parse::<usize>().ok()
|
||||||
|
{
|
||||||
|
set_value(number, cx);
|
||||||
|
|
||||||
|
mode.update(cx, |mode, _| {
|
||||||
|
*mode = NumericStepperMode::Read
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.w_full()
|
||||||
|
.mx_3()
|
||||||
|
.into_any_element()
|
||||||
|
})
|
||||||
.map(|increment| {
|
.map(|increment| {
|
||||||
if is_outlined {
|
if is_outlined {
|
||||||
increment.child(
|
increment.child(
|
||||||
|
@ -201,7 +310,7 @@ impl Component for NumericStepper {
|
||||||
Some("A button used to increment or decrement a numeric value.")
|
Some("A button used to increment or decrement a numeric value.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||||
Some(
|
Some(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
|
@ -213,8 +322,11 @@ impl Component for NumericStepper {
|
||||||
NumericStepper::new(
|
NumericStepper::new(
|
||||||
"numeric-stepper-component-preview",
|
"numeric-stepper-component-preview",
|
||||||
"10",
|
"10",
|
||||||
|
move |_, _| {},
|
||||||
move |_, _, _| {},
|
move |_, _, _| {},
|
||||||
move |_, _, _| {},
|
move |_, _, _| {},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
|
@ -223,8 +335,11 @@ impl Component for NumericStepper {
|
||||||
NumericStepper::new(
|
NumericStepper::new(
|
||||||
"numeric-stepper-with-border-component-preview",
|
"numeric-stepper-with-border-component-preview",
|
||||||
"10",
|
"10",
|
||||||
|
move |_, _| {},
|
||||||
move |_, _, _| {},
|
move |_, _, _| {},
|
||||||
move |_, _, _| {},
|
move |_, _, _| {},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
.style(NumericStepperStyle::Outlined)
|
.style(NumericStepperStyle::Outlined)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
|
@ -4,10 +4,12 @@
|
||||||
//!
|
//!
|
||||||
//! It can't be located in the `ui` crate because it depends on `editor`.
|
//! It can't be located in the `ui` crate because it depends on `editor`.
|
||||||
//!
|
//!
|
||||||
|
mod numeric_stepper;
|
||||||
|
|
||||||
use component::{example_group, single_example};
|
use component::{example_group, single_example};
|
||||||
use editor::{Editor, EditorElement, EditorStyle};
|
use editor::{Editor, EditorElement, EditorStyle};
|
||||||
use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, TextStyle};
|
use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, TextStyle};
|
||||||
|
pub use numeric_stepper::*;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use theme::ThemeSettings;
|
use theme::ThemeSettings;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue