Skip to main content

glassy_ui/motion/
values.rs

1use std::collections::HashMap;
2use std::sync::{Arc, RwLock};
3
4use gpui::{App, Global, SharedString};
5
6/// Shared animatable scalar (motion.dev `MotionValue`).
7#[derive(Clone)]
8pub struct MotionValue {
9    name: SharedString,
10    store: Arc<RwLock<HashMap<SharedString, f32>>>,
11}
12
13impl MotionValue {
14    pub fn get(&self) -> f32 {
15        self.store
16            .read()
17            .ok()
18            .and_then(|map| map.get(&self.name).copied())
19            .unwrap_or(0.0)
20    }
21
22    pub fn set(&self, value: f32) {
23        if let Ok(mut map) = self.store.write() {
24            map.insert(self.name.clone(), value);
25        }
26    }
27
28    /// Set the value and refresh open windows so bound UI updates.
29    pub fn set_with_notify(&self, value: f32, cx: &mut App) {
30        self.set(value);
31        cx.refresh_windows();
32    }
33
34    pub fn name(&self) -> &SharedString {
35        &self.name
36    }
37}
38
39/// Global registry of named motion values.
40pub struct MotionValueStore {
41    values: Arc<RwLock<HashMap<SharedString, f32>>>,
42}
43
44impl Global for MotionValueStore {}
45
46impl MotionValueStore {
47    pub fn init(cx: &mut App) {
48        if !cx.has_global::<Self>() {
49            cx.set_global(Self {
50                values: Arc::new(RwLock::new(HashMap::new())),
51            });
52        }
53    }
54}
55
56pub fn init(cx: &mut App) {
57    MotionValueStore::init(cx);
58}
59
60/// Get or create a named [`MotionValue`]. Prefer calling [`init`] at startup.
61pub fn use_motion_value(cx: &App, name: impl Into<SharedString>) -> MotionValue {
62    let name = name.into();
63    let store = if cx.has_global::<MotionValueStore>() {
64        cx.global::<MotionValueStore>().values.clone()
65    } else {
66        // Ephemeral fallback if init was skipped — still usable within this handle.
67        Arc::new(RwLock::new(HashMap::new()))
68    };
69    {
70        let mut map = store.write().expect("motion value store poisoned");
71        map.entry(name.clone()).or_insert(0.0);
72    }
73    MotionValue { name, store }
74}