concinnity_core/components/setting_command.rs
1// src/components/setting_command.rs
2
3use alloc::string::String;
4
5use crate::components::InputKey;
6use crate::ecs::asset_id::AssetId;
7
8/// What a "setting:*" action does to its value: cycle one step (for a stepper
9/// row), jump to an absolute option index (for a dropdown pick), set an absolute
10/// position in [0, 1] (for a slider row's drag), or bind a key (for a key-rebind
11/// row).
12///
13/// Eq is intentionally not derived: SetFraction carries an f32.
14#[derive(Debug, Clone, Copy, PartialEq, Default)]
15pub enum SettingOp {
16 /// Step the value one option forward.
17 #[default]
18 Next,
19 /// Step the value one option back.
20 Prev,
21 /// Jump straight to this option index (clamped to the option count). Sent
22 /// once when the user picks an entry from an open dropdown list.
23 SetIndex(usize),
24 /// Set the value to this fraction of its range, 0.0..=1.0. Sent each frame
25 /// while a slider is dragged.
26 SetFraction(f32),
27 /// Bind the named action (the command's setting) to this key. Sent once when
28 /// the user presses a key while a rebind row is capturing.
29 Rebind(InputKey),
30 /// Bind the named gamepad action (the command's `pad_*` setting) to this
31 /// button. Sent once when the user presses a button while a gamepad rebind
32 /// row is capturing.
33 RebindButton(crate::components::GamepadButton),
34}
35
36/// Runtime-only event sent by UiInputSystem when a "setting:*" action fires.
37/// GraphicsSystem reads these each step: it applies the change to the named
38/// setting (cycling it or setting it from a fraction), updates the value_label
39/// text, and (when persist is set) writes the new value to the settings store.
40/// World authors never declare this type directly.
41#[derive(Debug, Clone)]
42pub struct SettingCommand {
43 /// Engine setting key (e.g. "vsync").
44 pub setting: String,
45 /// How to change the value.
46 pub op: SettingOp,
47 /// The value TextLabel to update with the new value, when known.
48 pub value_label: Option<AssetId>,
49 /// Whether to write the new value to the settings store. A cycle is one
50 /// discrete change and always persists; a slider drag persists only on
51 /// release (the in-progress frames apply live but skip the disk write).
52 pub persist: bool,
53}
54
55impl Default for SettingCommand {
56 fn default() -> Self {
57 Self {
58 setting: String::new(),
59 op: SettingOp::Next,
60 value_label: None,
61 persist: true,
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 // A command with nothing stated names no setting and writes through to the
71 // store: a cycle is one discrete change, and only a slider drag opts out.
72 #[test]
73 fn a_default_command_persists_and_advances() {
74 let command = SettingCommand::default();
75 assert!(command.setting.is_empty());
76 assert!(matches!(command.op, SettingOp::Next));
77 assert_eq!(command.value_label, None);
78 assert!(command.persist);
79 }
80}