From 3328fe1b40965a540a7eecbb1fdf6340ad4c1c82 Mon Sep 17 00:00:00 2001 From: caeyo Date: Mon, 10 Aug 2026 14:39:35 +1000 Subject: [PATCH 1/2] Add text input setting --- src/runtime/settings/gui.rs | 83 +++++++++++++++++++++++++++++++++++++ src/runtime/sys.rs | 13 ++++++ 2 files changed, 96 insertions(+) diff --git a/src/runtime/settings/gui.rs b/src/runtime/settings/gui.rs index 469560c5..41dd63b1 100644 --- a/src/runtime/settings/gui.rs +++ b/src/runtime/settings/gui.rs @@ -166,6 +166,26 @@ pub fn add_file_select_mime_filter(key: &str, mime_type: &str) { } } +/// Adds a new text input setting widget that the user can modify. The key is +/// used to store the text in the settings [`Map`](super::Map) and needs to be +/// unique across all types of settings. The description is what's shown to the +/// user. The default value is used when the user hasn't set a value yet. +#[inline] +pub fn add_text_input(key: &str, description: &str, default_value: &str) { + // SAFETY: We provide valid pointers and lengths to key, description and + // default_value. They are also guaranteed to be valid UTF-8 strings. + unsafe { + sys::user_settings_add_text_input( + key.as_ptr(), + key.len(), + description.as_ptr(), + description.len(), + default_value.as_ptr(), + default_value.len(), + ) + } +} + /// Adds a tooltip to a setting widget based on its key. A tooltip is useful for /// explaining the purpose of a setting to the user. #[inline] @@ -357,3 +377,66 @@ impl Widget for FileSelect { } } } + +/// A text input widget. +/// +/// This is useful for settings where the user needs to enter arbitrary text, +/// such as a scene or level name to split on. +/// +/// # Example +/// +/// ```ignore +/// #[derive(Gui)] +/// struct Settings { +/// /// Screen Name +/// /// +/// /// Split when entering a scene with this name. +/// #[default = "prologue"] +/// level_name: TextInput, +/// } +/// +/// // In your auto splitter: +/// if current_scene == settings.level_name.value { +/// timer::split(); +/// } +/// ``` +#[derive(Clone, PartialEq, Eq)] +#[cfg(feature = "alloc")] +pub struct TextInput { + /// The text entered by the user, or the default if they haven't changed it. + pub value: alloc::string::String, +} + +/// The arguments that are needed to register a text input widget. This is an +/// internal type that you don't need to worry about. +#[cfg(feature = "alloc")] +#[doc(hidden)] +#[derive(Default)] +#[non_exhaustive] +pub struct TextInputArgs { + /// The default value of the setting, in case the user didn't set it yet. + pub default: &'static str, +} + +#[cfg(feature = "alloc")] +impl Widget for TextInput { + type Args = TextInputArgs; + + fn register(key: &str, description: &str, args: Self::Args) -> Self { + add_text_input(key, description, args.default); + let mut this = TextInput { + value: alloc::string::String::new(), + }; + this.update_from(&Map::load(), key, args); + this + } + + fn update_from(&mut self, settings_map: &Map, key: &str, args: Self::Args) { + if let Some(value) = settings_map.get(key) { + value.get_string_into(&mut self.value); + } else { + self.value.clear(); + self.value.push_str(args.default); + } + } +} diff --git a/src/runtime/sys.rs b/src/runtime/sys.rs index 002e218d..0723f23f 100644 --- a/src/runtime/sys.rs +++ b/src/runtime/sys.rs @@ -325,6 +325,19 @@ extern "C" { mime_type_ptr: *const u8, mime_type_len: usize, ); + /// Adds a new text input setting that the user can modify. The key is used + /// to store the text in the settings map and needs to be unique across all + /// types of settings. The description is what's shown to the user. The + /// pointers need to point to valid UTF-8 encoded text with the respective + /// given length. + pub fn user_settings_add_text_input( + key_ptr: *const u8, + key_len: usize, + description_ptr: *const u8, + description_len: usize, + default_value_ptr: *const u8, + default_value_len: usize, + ); /// Adds a tooltip to a setting based on its key. A tooltip is useful for /// explaining the purpose of a setting to the user. The pointers need to /// point to valid UTF-8 encoded text with the respective given length. From 7e6c0adf09eb8202a7939085b3f1238aa5f486de Mon Sep 17 00:00:00 2001 From: caeyo Date: Tue, 11 Aug 2026 17:19:08 +1000 Subject: [PATCH 2/2] Use clone_into instead of equivalent method calls --- src/runtime/settings/gui.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/runtime/settings/gui.rs b/src/runtime/settings/gui.rs index 41dd63b1..f9b349f9 100644 --- a/src/runtime/settings/gui.rs +++ b/src/runtime/settings/gui.rs @@ -6,6 +6,9 @@ use core::mem; #[cfg(feature = "derive")] pub use asr_derive::Gui; +#[cfg(feature = "alloc")] +use alloc::borrow::ToOwned; + use crate::{runtime::sys, watcher::Pair}; use super::map::Map; @@ -435,8 +438,7 @@ impl Widget for TextInput { if let Some(value) = settings_map.get(key) { value.get_string_into(&mut self.value); } else { - self.value.clear(); - self.value.push_str(args.default); + args.default.clone_into(&mut self.value); } } }