setting: Use precise subscripts for use_keyed_state (#1735)
This commit is contained in:
parent
a50b1e9341
commit
514aea00be
7 changed files with 121 additions and 65 deletions
|
|
@ -22,6 +22,7 @@ struct AppSettings {
|
||||||
cli_path: SharedString,
|
cli_path: SharedString,
|
||||||
font_family: SharedString,
|
font_family: SharedString,
|
||||||
font_size: f64,
|
font_size: f64,
|
||||||
|
line_height: f64,
|
||||||
notifications_enabled: bool,
|
notifications_enabled: bool,
|
||||||
auto_update: bool,
|
auto_update: bool,
|
||||||
resettable: bool,
|
resettable: bool,
|
||||||
|
|
@ -34,6 +35,7 @@ impl Default for AppSettings {
|
||||||
cli_path: "/usr/local/bin/bash".into(),
|
cli_path: "/usr/local/bin/bash".into(),
|
||||||
font_family: "Arial".into(),
|
font_family: "Arial".into(),
|
||||||
font_size: 14.0,
|
font_size: 14.0,
|
||||||
|
line_height: 12.0,
|
||||||
notifications_enabled: true,
|
notifications_enabled: true,
|
||||||
auto_update: true,
|
auto_update: true,
|
||||||
resettable: true,
|
resettable: true,
|
||||||
|
|
@ -265,6 +267,24 @@ impl SettingsStory {
|
||||||
.default_value(default_settings.font_size),
|
.default_value(default_settings.font_size),
|
||||||
)
|
)
|
||||||
.description("Adjust the font size for better readability."),
|
.description("Adjust the font size for better readability."),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
SettingItem::new(
|
||||||
|
"Line Height",
|
||||||
|
SettingField::number_input(
|
||||||
|
NumberFieldOptions {
|
||||||
|
min: 8.0,
|
||||||
|
max: 32.0,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|cx: &App| AppSettings::global(cx).line_height,
|
||||||
|
|val: f64, cx: &mut App| {
|
||||||
|
AppSettings::global_mut(cx).line_height = val;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.default_value(default_settings.line_height),
|
||||||
|
)
|
||||||
|
.description("Adjust the line height for better readability."),
|
||||||
),
|
),
|
||||||
SettingGroup::new().title("Other").items(vec![
|
SettingGroup::new().title("Other").items(vec![
|
||||||
SettingItem::render(|options, _, _| {
|
SettingItem::render(|options, _, _| {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
prelude::FluentBuilder as _, AnyElement, App, AppContext as _, Entity, IntoElement,
|
AnyElement, App, AppContext as _, Entity, IntoElement, SharedString, StyleRefinement, Styled,
|
||||||
SharedString, StyleRefinement, Styled, Window,
|
Window, prelude::FluentBuilder as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
AxisExt, Sizable, StyledExt,
|
||||||
input::{InputState, NumberInput, NumberInputEvent},
|
input::{InputState, NumberInput, NumberInputEvent},
|
||||||
setting::{
|
setting::{
|
||||||
fields::{get_value, set_value, SettingFieldRender},
|
|
||||||
AnySettingField, RenderOptions,
|
AnySettingField, RenderOptions,
|
||||||
|
fields::{SettingFieldRender, get_value, set_value},
|
||||||
},
|
},
|
||||||
AxisExt, Sizable, StyledExt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -65,35 +65,43 @@ impl SettingFieldRender for NumberField {
|
||||||
let num_options = self.options.clone();
|
let num_options = self.options.clone();
|
||||||
|
|
||||||
let state = window
|
let state = window
|
||||||
.use_keyed_state("number-state", cx, |window, cx| {
|
.use_keyed_state(
|
||||||
let input =
|
SharedString::from(format!(
|
||||||
cx.new(|cx| InputState::new(window, cx).default_value(value.to_string()));
|
"number-state-{}-{}-{}",
|
||||||
let _subscription = cx.subscribe_in(&input, window, {
|
options.page_ix, options.group_ix, options.item_ix
|
||||||
move |_, input, event: &NumberInputEvent, window, cx| match event {
|
)),
|
||||||
NumberInputEvent::Step(action) => input.update(cx, |input, cx| {
|
cx,
|
||||||
let value = input.value();
|
|window, cx| {
|
||||||
if let Ok(value) = value.parse::<f64>() {
|
let input =
|
||||||
let new_value = if *action == crate::input::StepAction::Increment {
|
cx.new(|cx| InputState::new(window, cx).default_value(value.to_string()));
|
||||||
(value + num_options.step).min(num_options.max)
|
let _subscription = cx.subscribe_in(&input, window, {
|
||||||
} else {
|
move |_, input, event: &NumberInputEvent, window, cx| match event {
|
||||||
(value - num_options.step).max(num_options.min)
|
NumberInputEvent::Step(action) => input.update(cx, |input, cx| {
|
||||||
};
|
let value = input.value();
|
||||||
set_value(new_value, cx);
|
if let Ok(value) = value.parse::<f64>() {
|
||||||
input.set_value(
|
let new_value =
|
||||||
SharedString::from(new_value.to_string()),
|
if *action == crate::input::StepAction::Increment {
|
||||||
window,
|
(value + num_options.step).min(num_options.max)
|
||||||
cx,
|
} else {
|
||||||
);
|
(value - num_options.step).max(num_options.min)
|
||||||
}
|
};
|
||||||
}),
|
set_value(new_value, cx);
|
||||||
}
|
input.set_value(
|
||||||
});
|
SharedString::from(new_value.to_string()),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
State {
|
State {
|
||||||
input,
|
input,
|
||||||
_subscription,
|
_subscription,
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
.read(cx);
|
.read(cx);
|
||||||
|
|
||||||
NumberInput::new(&state.input)
|
NumberInput::new(&state.input)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
prelude::FluentBuilder as _, AnyElement, App, AppContext as _, Entity, IntoElement,
|
AnyElement, App, AppContext as _, Entity, IntoElement, SharedString, StyleRefinement, Styled,
|
||||||
SharedString, StyleRefinement, Styled, Window,
|
Window, prelude::FluentBuilder as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
AxisExt as _, Sizable, StyledExt,
|
||||||
input::{Input, InputEvent, InputState},
|
input::{Input, InputEvent, InputState},
|
||||||
setting::{
|
setting::{
|
||||||
fields::{get_value, set_value, SettingFieldRender},
|
|
||||||
AnySettingField, RenderOptions,
|
AnySettingField, RenderOptions,
|
||||||
|
fields::{SettingFieldRender, get_value, set_value},
|
||||||
},
|
},
|
||||||
AxisExt as _, Sizable, StyledExt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct StringField<T> {
|
pub(crate) struct StringField<T> {
|
||||||
|
|
@ -47,23 +47,30 @@ where
|
||||||
let set_value = set_value::<T>(&field, cx);
|
let set_value = set_value::<T>(&field, cx);
|
||||||
|
|
||||||
let state = window
|
let state = window
|
||||||
.use_keyed_state("string-state", cx, |window, cx| {
|
.use_keyed_state(
|
||||||
let input = cx.new(|cx| InputState::new(window, cx).default_value(value));
|
SharedString::from(format!(
|
||||||
let _subscription = cx.subscribe(&input, {
|
"string-state-{}-{}-{}",
|
||||||
move |_, input, event: &InputEvent, cx| match event {
|
options.page_ix, options.group_ix, options.item_ix
|
||||||
InputEvent::Change => {
|
)),
|
||||||
let value = input.read(cx).value();
|
cx,
|
||||||
set_value(value.into(), cx);
|
|window, cx| {
|
||||||
|
let input = cx.new(|cx| InputState::new(window, cx).default_value(value));
|
||||||
|
let _subscription = cx.subscribe(&input, {
|
||||||
|
move |_, input, event: &InputEvent, cx| match event {
|
||||||
|
InputEvent::Change => {
|
||||||
|
let value = input.read(cx).value();
|
||||||
|
set_value(value.into(), cx);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
State {
|
State {
|
||||||
input,
|
input,
|
||||||
_subscription,
|
_subscription,
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
.read(cx);
|
.read(cx);
|
||||||
|
|
||||||
Input::new(&state.input)
|
Input::new(&state.input)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
prelude::FluentBuilder as _, App, IntoElement, ParentElement as _, SharedString,
|
App, IntoElement, ParentElement as _, SharedString, StyleRefinement, Styled, Window,
|
||||||
StyleRefinement, Styled, Window,
|
prelude::FluentBuilder as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ActiveTheme, StyledExt,
|
||||||
group_box::{GroupBox, GroupBoxVariants},
|
group_box::{GroupBox, GroupBoxVariants},
|
||||||
label::Label,
|
label::Label,
|
||||||
setting::{RenderOptions, SettingItem},
|
setting::{RenderOptions, SettingItem},
|
||||||
v_flex, ActiveTheme, StyledExt,
|
v_flex,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A setting group that can contain multiple setting items.
|
/// A setting group that can contain multiple setting items.
|
||||||
|
|
@ -75,14 +76,13 @@ impl SettingGroup {
|
||||||
|
|
||||||
pub(crate) fn render(
|
pub(crate) fn render(
|
||||||
self,
|
self,
|
||||||
group_ix: usize,
|
|
||||||
query: &str,
|
query: &str,
|
||||||
options: &RenderOptions,
|
options: &RenderOptions,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
GroupBox::new()
|
GroupBox::new()
|
||||||
.id(SharedString::from(format!("group-{}", group_ix)))
|
.id(SharedString::from(format!("group-{}", options.group_ix)))
|
||||||
.with_variant(options.group_variant)
|
.with_variant(options.group_variant)
|
||||||
.when_some(self.title.clone(), |this, title| {
|
.when_some(self.title.clone(), |this, title| {
|
||||||
this.title(v_flex().gap_1().child(title).when_some(
|
this.title(v_flex().gap_1().child(title).when_some(
|
||||||
|
|
@ -99,7 +99,14 @@ impl SettingGroup {
|
||||||
.gap_4()
|
.gap_4()
|
||||||
.children(self.items.iter().enumerate().filter_map(|(item_ix, item)| {
|
.children(self.items.iter().enumerate().filter_map(|(item_ix, item)| {
|
||||||
if item.is_match(&query) {
|
if item.is_match(&query) {
|
||||||
Some(item.clone().render_item(item_ix, options, window, cx))
|
Some(item.clone().render_item(
|
||||||
|
&RenderOptions {
|
||||||
|
item_ix,
|
||||||
|
..*options
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,13 +150,12 @@ impl SettingItem {
|
||||||
|
|
||||||
pub(super) fn render_item(
|
pub(super) fn render_item(
|
||||||
self,
|
self,
|
||||||
ix: usize,
|
|
||||||
options: &RenderOptions,
|
options: &RenderOptions,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Stateful<Div> {
|
) -> Stateful<Div> {
|
||||||
div()
|
div()
|
||||||
.id(SharedString::from(format!("item-{}", ix)))
|
.id(SharedString::from(format!("item-{}", options.item_ix)))
|
||||||
.w_full()
|
.w_full()
|
||||||
.child(match self {
|
.child(match self {
|
||||||
SettingItem::Item {
|
SettingItem::Item {
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,20 @@ impl SettingPage {
|
||||||
list(list_state.clone(), {
|
list(list_state.clone(), {
|
||||||
let query = query.clone();
|
let query = query.clone();
|
||||||
let options = *options;
|
let options = *options;
|
||||||
move |ix, window, cx| {
|
move |group_ix, window, cx| {
|
||||||
let group = groups[ix].clone();
|
let group = groups[group_ix].clone();
|
||||||
group
|
group
|
||||||
.py_4()
|
.py_4()
|
||||||
.render(ix, &query, &options, window, cx)
|
.render(
|
||||||
|
&query,
|
||||||
|
&RenderOptions {
|
||||||
|
page_ix: ix,
|
||||||
|
group_ix,
|
||||||
|
..options
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
IconName, Sizable, Size, StyledExt,
|
||||||
group_box::GroupBoxVariant,
|
group_box::GroupBoxVariant,
|
||||||
input::{Input, InputState},
|
input::{Input, InputState},
|
||||||
resizable::{h_resizable, resizable_panel},
|
resizable::{h_resizable, resizable_panel},
|
||||||
setting::{SettingGroup, SettingPage},
|
setting::{SettingGroup, SettingPage},
|
||||||
sidebar::{Sidebar, SidebarMenu, SidebarMenuItem},
|
sidebar::{Sidebar, SidebarMenu, SidebarMenuItem},
|
||||||
IconName, Sizable, Size, StyledExt,
|
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, relative, App, AppContext as _, Axis, ElementId, Entity,
|
App, AppContext as _, Axis, ElementId, Entity, IntoElement, ParentElement as _, Pixels,
|
||||||
IntoElement, ParentElement as _, Pixels, RenderOnce, StyleRefinement, Styled, Window,
|
RenderOnce, StyleRefinement, Styled, Window, div, prelude::FluentBuilder as _, px, relative,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
|
|
@ -221,6 +221,9 @@ pub(super) struct SettingsState {
|
||||||
/// Options for rendering setting item.
|
/// Options for rendering setting item.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct RenderOptions {
|
pub struct RenderOptions {
|
||||||
|
pub page_ix: usize,
|
||||||
|
pub group_ix: usize,
|
||||||
|
pub item_ix: usize,
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub group_variant: GroupBoxVariant,
|
pub group_variant: GroupBoxVariant,
|
||||||
pub layout: Axis,
|
pub layout: Axis,
|
||||||
|
|
@ -251,6 +254,9 @@ impl RenderOnce for Settings {
|
||||||
let query = state.read(cx).search_input.read(cx).value();
|
let query = state.read(cx).search_input.read(cx).value();
|
||||||
let filtered_pages = self.filtered_pages(&query);
|
let filtered_pages = self.filtered_pages(&query);
|
||||||
let options = RenderOptions {
|
let options = RenderOptions {
|
||||||
|
page_ix: 0,
|
||||||
|
group_ix: 0,
|
||||||
|
item_ix: 0,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
group_variant: self.group_variant,
|
group_variant: self.group_variant,
|
||||||
layout: Axis::Horizontal,
|
layout: Axis::Horizontal,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue