Skip to main content

gpui_motion_kit/
motions.rs

1//! Kit clock and frame conversion for the shared keyed collection.
2use crate::{Clock, Frame};
3use gpui_ce_motion::Motion;
4use gpui_kit::{App, Window};
5
6use std::{
7    hash::Hash,
8    ops::{Deref, DerefMut},
9    time::Duration,
10};
11
12/// Component-owned keyed transitions using the shared engine and Kit's clock.
13///
14/// Batch results follow declaration order; stable keys preserve interruption
15/// history through reordering. Omitted entries stay retained. Cleanup and capacity
16/// methods are available through [`core::Motions`](gpui_ce_motion::Motions).
17/// Retain this collection in the view and notify after changing model targets.
18#[derive(Debug)]
19pub struct Motions<K> {
20    inner: gpui_ce_motion::Motions<K>,
21    clock: Clock,
22}
23
24impl<K> Default for Motions<K> {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl<K> Motions<K> {
31    /// Creates an empty collection without allocating.
32    pub fn new() -> Self {
33        Self::with_capacity(0)
34    }
35
36    /// Reserves space for at least `capacity` keys, without creating trajectories.
37    pub fn with_capacity(capacity: usize) -> Self {
38        Self {
39            inner: gpui_ce_motion::Motions::with_capacity(capacity),
40            clock: Clock::default(),
41        }
42    }
43}
44
45impl<K> Deref for Motions<K> {
46    type Target = gpui_ce_motion::Motions<K>;
47
48    fn deref(&self) -> &Self::Target {
49        &self.inner
50    }
51}
52
53impl<K> DerefMut for Motions<K> {
54    fn deref_mut(&mut self) -> &mut Self::Target {
55        &mut self.inner
56    }
57}
58
59impl<K: Eq + Hash> Motions<K> {
60    /// Samples a batch during render using one executor timestamp and Kit's
61    /// reduced-motion preference. Requests one frame if any returned frame is active.
62    /// Omitted entries do not request frames. Do not mix with explicit sample times.
63    ///
64    /// # Panics
65    /// Panics on duplicate keys. Earlier entries may already have been sampled.
66    pub fn frame<const N: usize>(
67        &mut self,
68        declarations: [(K, Motion); N],
69        window: &mut Window,
70        cx: &App,
71    ) -> [Frame; N] {
72        let now = self.clock.tick(cx);
73        let frames = self.sample(declarations, now, cx.reduce_motion());
74
75        if frames.iter().any(|frame| frame.is_animating()) {
76            window.request_animation_frame();
77        }
78
79        frames
80    }
81
82    /// Samples one native entry. Use [`Self::frame`] to synchronize several entries.
83    pub fn frame_one(&mut self, key: K, motion: Motion, window: &mut Window, cx: &App) -> Frame {
84        let [frame] = self.frame([(key, motion)], window, cx);
85
86        frame
87    }
88
89    /// Samples explicit elapsed time, returning Kit-ready frames. Do not mix
90    /// this clock with [`Self::frame`]. See the shared engine for lifecycle details.
91    ///
92    /// # Panics
93    /// Panics on duplicate keys. Earlier entries may already have been sampled.
94    pub fn sample<const N: usize>(
95        &mut self,
96        declarations: [(K, Motion); N],
97        now: Duration,
98        reduced_motion: bool,
99    ) -> [Frame; N] {
100        self.inner
101            .sample(declarations, now, reduced_motion)
102            .map(Into::into)
103    }
104
105    /// Samples one key at explicit elapsed time, returning a Kit-ready frame.
106    pub fn sample_one(
107        &mut self,
108        key: K,
109        motion: Motion,
110        now: Duration,
111        reduced_motion: bool,
112    ) -> Frame {
113        self.inner
114            .sample_one(key, motion, now, reduced_motion)
115            .into()
116    }
117}