Skip to main content

eave_api/
effect.rs

1use std::time::Duration;
2
3use crate::Task;
4
5/// What [`Widget::update`](crate::Widget::update) asks for: async work, plus requests to the host.
6pub struct Effect<M> {
7    task: Task<M>,
8    popover: Option<PopoverRequest>,
9    dialog: Option<DialogRequest>,
10    nudge: Option<NudgeRequest>,
11}
12
13#[doc(hidden)]
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum PopoverRequest {
16    Open,
17    Close,
18}
19
20#[doc(hidden)]
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum DialogRequest {
23    Open,
24    Close,
25}
26
27/// Which way something just went, so the host can give the widget's island a nudge that way.
28///
29/// It says what happened, not how to move: the host picks the motion. A value going up or down
30/// (a volume, a brightness) bumps the island's top or bottom edge out at the widget's item; moving
31/// to the next or previous thing (a workspace, a track) pushes the whole island left or right,
32/// and it springs back into place.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Nudge {
35    Up,
36    Down,
37    Left,
38    Right,
39}
40
41/// A nudge as the host gets it: which way, and how long what it follows takes on screen, if the
42/// widget knows.
43#[doc(hidden)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct NudgeRequest {
46    pub nudge: Nudge,
47    pub lasting: Option<Duration>,
48}
49
50impl From<Nudge> for NudgeRequest {
51    fn from(nudge: Nudge) -> Self {
52        Self {
53            nudge,
54            lasting: None,
55        }
56    }
57}
58
59impl<M> Effect<M> {
60    pub fn none() -> Self {
61        Self {
62            task: Task::none(),
63            popover: None,
64            dialog: None,
65            nudge: None,
66        }
67    }
68
69    pub fn task(task: Task<M>) -> Self {
70        Self {
71            task,
72            popover: None,
73            dialog: None,
74            nudge: None,
75        }
76    }
77
78    /// Runs `task` too, alongside the one it has.
79    pub fn and_task(mut self, task: Task<M>) -> Self
80    where
81        M: Send + 'static,
82    {
83        self.task = Task::batch([self.task, task]);
84        self
85    }
86
87    /// Opens this widget's popover, under its item. Ignored if the widget has no popover.
88    /// Before the item was ever clicked, it opens on the bar the notifications show on.
89    pub fn open_popover(mut self) -> Self {
90        self.popover = Some(PopoverRequest::Open);
91        self
92    }
93
94    pub fn close_popover(mut self) -> Self {
95        self.popover = Some(PopoverRequest::Close);
96        self
97    }
98
99    /// Opens this widget's dialog: its panel in the middle of the screen, for what needs more room
100    /// than a popover. Ignored if the widget has no dialog.
101    ///
102    /// The host picks where it comes from: out of what was just acted on (the popover, which folds
103    /// away, the item, a notification or the dormer), or out of the top of the screen, and it goes
104    /// back there when it closes. Opening it closes any popover and the dormer.
105    pub fn open_dialog(mut self) -> Self {
106        self.dialog = Some(DialogRequest::Open);
107        self
108    }
109
110    pub fn close_dialog(mut self) -> Self {
111        self.dialog = Some(DialogRequest::Close);
112        self
113    }
114
115    /// Nudges this widget's island. Ignored while the island is held or has a popover.
116    pub fn nudge(mut self, nudge: Nudge) -> Self {
117        self.nudge = Some(NudgeRequest {
118            nudge,
119            lasting: None,
120        });
121        self
122    }
123
124    /// Nudges this widget's island in step with something else on screen that takes `lasting`,
125    /// like the compositor's own workspace animation: the host plays the same motion, slowed down
126    /// or sped up to settle over about that long.
127    pub fn nudge_lasting(mut self, nudge: Nudge, lasting: Duration) -> Self {
128        self.nudge = Some(NudgeRequest {
129            nudge,
130            lasting: Some(lasting),
131        });
132        self
133    }
134
135    #[doc(hidden)]
136    pub fn into_parts(self) -> (Task<M>, Option<PopoverRequest>, Option<NudgeRequest>) {
137        (self.task, self.popover, self.nudge)
138    }
139
140    /// The dialog request, read before [`Effect::into_parts`], which leaves it out to keep its
141    /// shape.
142    #[doc(hidden)]
143    pub fn dialog_request(&self) -> Option<DialogRequest> {
144        self.dialog
145    }
146}
147
148impl<M> From<Task<M>> for Effect<M> {
149    fn from(task: Task<M>) -> Self {
150        Self::task(task)
151    }
152}