Skip to main content

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}