411 lines
18 KiB
Rust
411 lines
18 KiB
Rust
use gpui::{
|
|
App, AppContext, Axis, Context, Element, Entity, FocusHandle, Focusable, Global, IntoElement,
|
|
ParentElement as _, Render, SharedString, Styled, Window, px,
|
|
};
|
|
|
|
use gpui_component::{
|
|
ActiveTheme, Icon, IconName, Sizable, Size, Theme, ThemeMode,
|
|
button::Button,
|
|
group_box::GroupBoxVariant,
|
|
h_flex,
|
|
label::Label,
|
|
setting::{
|
|
NumberFieldOptions, RenderOptions, SettingField, SettingFieldElement, SettingGroup,
|
|
SettingItem, SettingPage, Settings,
|
|
},
|
|
text::TextView,
|
|
v_flex,
|
|
};
|
|
|
|
struct AppSettings {
|
|
auto_switch_theme: bool,
|
|
cli_path: SharedString,
|
|
font_family: SharedString,
|
|
font_size: f64,
|
|
notifications_enabled: bool,
|
|
auto_update: bool,
|
|
resettable: bool,
|
|
}
|
|
|
|
impl Default for AppSettings {
|
|
fn default() -> Self {
|
|
Self {
|
|
auto_switch_theme: false,
|
|
cli_path: "/usr/local/bin/bash".into(),
|
|
font_family: "Arial".into(),
|
|
font_size: 14.0,
|
|
notifications_enabled: true,
|
|
auto_update: true,
|
|
resettable: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Global for AppSettings {}
|
|
|
|
impl AppSettings {
|
|
fn global(cx: &App) -> &AppSettings {
|
|
cx.global::<AppSettings>()
|
|
}
|
|
|
|
pub fn global_mut(cx: &mut App) -> &mut AppSettings {
|
|
cx.global_mut::<AppSettings>()
|
|
}
|
|
}
|
|
|
|
pub struct SettingsStory {
|
|
focus_handle: FocusHandle,
|
|
group_variant: GroupBoxVariant,
|
|
size: Size,
|
|
}
|
|
|
|
struct OpenURLSettingField {
|
|
label: SharedString,
|
|
url: SharedString,
|
|
}
|
|
|
|
impl OpenURLSettingField {
|
|
fn new(label: impl Into<SharedString>, url: impl Into<SharedString>) -> Self {
|
|
Self {
|
|
label: label.into(),
|
|
url: url.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SettingFieldElement for OpenURLSettingField {
|
|
type Element = Button;
|
|
fn render_field(&self, options: &RenderOptions, _: &mut Window, _: &mut App) -> Self::Element {
|
|
let url = self.url.clone();
|
|
Button::new("open-url")
|
|
.outline()
|
|
.label(self.label.clone())
|
|
.with_size(options.size)
|
|
.on_click(move |_, _window, cx| {
|
|
cx.open_url(url.as_str());
|
|
})
|
|
}
|
|
}
|
|
|
|
impl super::Story for SettingsStory {
|
|
fn title() -> &'static str {
|
|
"Settings"
|
|
}
|
|
|
|
fn description() -> &'static str {
|
|
"A collection of settings groups and items for the application."
|
|
}
|
|
|
|
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
|
|
Self::view(window, cx)
|
|
}
|
|
|
|
fn paddings() -> gpui::Pixels {
|
|
px(0.)
|
|
}
|
|
}
|
|
|
|
impl SettingsStory {
|
|
pub fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
|
|
cx.new(|cx| Self::new(window, cx))
|
|
}
|
|
|
|
fn new(_: &mut Window, cx: &mut Context<Self>) -> Self {
|
|
cx.set_global::<AppSettings>(AppSettings::default());
|
|
|
|
Self {
|
|
focus_handle: cx.focus_handle(),
|
|
group_variant: GroupBoxVariant::Outline,
|
|
size: Size::default(),
|
|
}
|
|
}
|
|
|
|
fn setting_pages(&self, window: &mut Window, cx: &mut Context<Self>) -> Vec<SettingPage> {
|
|
let view = cx.entity();
|
|
let default_settings = AppSettings::default();
|
|
let resettable = AppSettings::global(cx).resettable;
|
|
|
|
vec![
|
|
SettingPage::new("General")
|
|
.resettable(resettable)
|
|
.default_open(true)
|
|
.groups(vec![
|
|
SettingGroup::new().title("Appearance").items(vec![
|
|
SettingItem::new(
|
|
"Dark Mode",
|
|
SettingField::switch(
|
|
|cx: &App| cx.theme().mode.is_dark(),
|
|
|val: bool, cx: &mut App| {
|
|
let mode = if val {
|
|
ThemeMode::Dark
|
|
} else {
|
|
ThemeMode::Light
|
|
};
|
|
Theme::global_mut(cx).mode = mode;
|
|
Theme::change(mode, None, cx);
|
|
},
|
|
)
|
|
.default_value(false),
|
|
)
|
|
.description("Switch between light and dark themes."),
|
|
SettingItem::new(
|
|
"Auto Switch Theme",
|
|
SettingField::checkbox(
|
|
|cx: &App| AppSettings::global(cx).auto_switch_theme,
|
|
|val: bool, cx: &mut App| {
|
|
AppSettings::global_mut(cx).auto_switch_theme = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.auto_switch_theme),
|
|
)
|
|
.description("Automatically switch theme based on system settings."),
|
|
SettingItem::new(
|
|
"resettable",
|
|
SettingField::switch(
|
|
|cx: &App| AppSettings::global(cx).resettable,
|
|
|checked: bool, cx: &mut App| {
|
|
AppSettings::global_mut(cx).resettable = checked
|
|
},
|
|
),
|
|
)
|
|
.description("Enable/Disable reset button for settings."),
|
|
SettingItem::new(
|
|
"Group Variant",
|
|
SettingField::dropdown(
|
|
vec![
|
|
(GroupBoxVariant::Normal.as_str().into(), "Normal".into()),
|
|
(GroupBoxVariant::Outline.as_str().into(), "Outline".into()),
|
|
(GroupBoxVariant::Fill.as_str().into(), "Fill".into()),
|
|
],
|
|
{
|
|
let view = view.clone();
|
|
move |cx: &App| {
|
|
SharedString::from(
|
|
view.read(cx).group_variant.as_str().to_string(),
|
|
)
|
|
}
|
|
},
|
|
{
|
|
let view = view.clone();
|
|
move |val: SharedString, cx: &mut App| {
|
|
view.update(cx, |view, cx| {
|
|
view.group_variant =
|
|
GroupBoxVariant::from_str(val.as_str());
|
|
cx.notify();
|
|
});
|
|
}
|
|
},
|
|
)
|
|
.default_value(GroupBoxVariant::Outline.as_str().to_string()),
|
|
)
|
|
.description("Select the variant for setting groups."),
|
|
SettingItem::new(
|
|
"Group Size",
|
|
SettingField::dropdown(
|
|
vec![
|
|
(Size::Medium.as_str().into(), "Medium".into()),
|
|
(Size::Small.as_str().into(), "Small".into()),
|
|
(Size::XSmall.as_str().into(), "XSmall".into()),
|
|
],
|
|
{
|
|
let view = view.clone();
|
|
move |cx: &App| {
|
|
SharedString::from(view.read(cx).size.as_str().to_string())
|
|
}
|
|
},
|
|
{
|
|
let view = view.clone();
|
|
move |val: SharedString, cx: &mut App| {
|
|
view.update(cx, |view, cx| {
|
|
view.size = Size::from_str(val.as_str());
|
|
cx.notify();
|
|
});
|
|
}
|
|
},
|
|
)
|
|
.default_value(Size::default().as_str().to_string()),
|
|
)
|
|
.description("Select the size for the setting group."),
|
|
]),
|
|
SettingGroup::new()
|
|
.title("Font")
|
|
.item(
|
|
SettingItem::new(
|
|
"Font Family",
|
|
SettingField::dropdown(
|
|
vec![
|
|
("Arial".into(), "Arial".into()),
|
|
("Helvetica".into(), "Helvetica".into()),
|
|
("Times New Roman".into(), "Times New Roman".into()),
|
|
("Courier New".into(), "Courier New".into()),
|
|
],
|
|
|cx: &App| AppSettings::global(cx).font_family.clone(),
|
|
|val: SharedString, cx: &mut App| {
|
|
AppSettings::global_mut(cx).font_family = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.font_family),
|
|
)
|
|
.description("Select the font family for the story."),
|
|
)
|
|
.item(
|
|
SettingItem::new(
|
|
"Font Size",
|
|
SettingField::number_input(
|
|
NumberFieldOptions {
|
|
min: 8.0,
|
|
max: 72.0,
|
|
..Default::default()
|
|
},
|
|
|cx: &App| AppSettings::global(cx).font_size,
|
|
|val: f64, cx: &mut App| {
|
|
AppSettings::global_mut(cx).font_size = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.font_size),
|
|
)
|
|
.description("Adjust the font size for better readability."),
|
|
),
|
|
SettingGroup::new().title("Other").items(vec![
|
|
SettingItem::render(|options, _, _| {
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.flex_wrap()
|
|
.gap_3()
|
|
.child("This is a custom element item by use SettingItem::element.")
|
|
.child(
|
|
Button::new("action")
|
|
.icon(IconName::Globe)
|
|
.label("Repository...")
|
|
.outline()
|
|
.with_size(options.size)
|
|
.on_click(|_, _, cx| {
|
|
cx.open_url(
|
|
"https://github.com/longbridge/gpui-component",
|
|
);
|
|
}),
|
|
)
|
|
.into_any_element()
|
|
}),
|
|
SettingItem::new(
|
|
"CLI Path",
|
|
SettingField::input(
|
|
|cx: &App| AppSettings::global(cx).cli_path.clone(),
|
|
|val: SharedString, cx: &mut App| {
|
|
println!("cli-path set value: {}", val);
|
|
AppSettings::global_mut(cx).cli_path = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.cli_path),
|
|
)
|
|
.layout(Axis::Vertical)
|
|
.description(
|
|
"Path to the CLI executable. \n\
|
|
This item uses Vertical layout. The title,\
|
|
description, and field are all aligned vertically with width 100%.",
|
|
),
|
|
]),
|
|
]),
|
|
SettingPage::new("Software Update")
|
|
.resettable(resettable)
|
|
.groups(vec![SettingGroup::new().title("Updates").items(vec![
|
|
SettingItem::new(
|
|
"Enable Notifications",
|
|
SettingField::switch(
|
|
|cx: &App| AppSettings::global(cx).notifications_enabled,
|
|
|val: bool, cx: &mut App| {
|
|
AppSettings::global_mut(cx).notifications_enabled = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.notifications_enabled),
|
|
)
|
|
.description("Receive notifications about updates and news."),
|
|
SettingItem::new(
|
|
"Auto Update",
|
|
SettingField::switch(
|
|
|cx: &App| AppSettings::global(cx).auto_update,
|
|
|val: bool, cx: &mut App| {
|
|
AppSettings::global_mut(cx).auto_update = val;
|
|
},
|
|
)
|
|
.default_value(default_settings.auto_update),
|
|
)
|
|
.description("Automatically download and install updates."),
|
|
])]),
|
|
SettingPage::new("About")
|
|
.resettable(resettable)
|
|
.group(
|
|
SettingGroup::new().item(SettingItem::render(|_options, _, cx| {
|
|
v_flex()
|
|
.gap_3()
|
|
.w_full()
|
|
.items_center()
|
|
.justify_center()
|
|
.child(Icon::new(IconName::GalleryVerticalEnd).size_16())
|
|
.child("GPUI Component")
|
|
.child(
|
|
Label::new(
|
|
"Rust GUI components for building fantastic cross-platform \
|
|
desktop application by using GPUI.",
|
|
)
|
|
.text_sm()
|
|
.text_color(cx.theme().muted_foreground),
|
|
)
|
|
.into_any()
|
|
})),
|
|
)
|
|
.group(SettingGroup::new().title("Links").items(vec![
|
|
SettingItem::new(
|
|
"GitHub Repository",
|
|
SettingField::element(OpenURLSettingField::new(
|
|
"Repository...",
|
|
"https://github.com/longbridge/gpui-component",
|
|
)),
|
|
)
|
|
.description("Open the GitHub repository in your default browser."),
|
|
SettingItem::new(
|
|
"Documentation",
|
|
SettingField::element(OpenURLSettingField::new(
|
|
"Rust Docs...",
|
|
"https://docs.rs/gpui-component"
|
|
)),
|
|
)
|
|
.description(TextView::markdown(
|
|
"desc",
|
|
"Rust doc for the `gpui-component` crate.",
|
|
window,
|
|
cx,
|
|
)),
|
|
SettingItem::new(
|
|
"Website",
|
|
SettingField::render(|options, _window, _cx| {
|
|
Button::new("open-url")
|
|
.outline()
|
|
.label("Website...")
|
|
.with_size(options.size)
|
|
.on_click(|_, _window, cx| {
|
|
cx.open_url("https://longbridge.github.io/gpui-component/");
|
|
})
|
|
}),
|
|
)
|
|
.description("Official website and documentation for the GPUI Component."),
|
|
])),
|
|
]
|
|
}
|
|
}
|
|
|
|
impl Focusable for SettingsStory {
|
|
fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
|
|
self.focus_handle.clone()
|
|
}
|
|
}
|
|
|
|
impl Render for SettingsStory {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
Settings::new("app-settings")
|
|
.with_size(self.size)
|
|
.with_group_variant(self.group_variant)
|
|
.pages(self.setting_pages(window, cx))
|
|
}
|
|
}
|