eave_api/widget.rs
1use std::fmt::Debug;
2
3use serde::de::DeserializeOwned;
4
5use crate::ui::{Action, Item, Notice, Panel};
6use crate::{Effect, Subscription, Task};
7
8/// Something that sits in the bar, with an optional popover.
9///
10/// It follows the same Elm shape as the host: state lives in `Self`, changes arrive as messages in
11/// [`update`](Widget::update), and the views are pure functions of state. `update` must not block:
12/// do I/O in a [`Task`] or a [`Subscription`].
13pub trait Widget: Sized + 'static {
14 /// Options from this widget's entry in `config.toml`, minus the `widget` key.
15 ///
16 /// The entry may be empty, so use `#[serde(default)]` for options that have one.
17 type Config: DeserializeOwned;
18 type Message: Clone + Debug + Send + Sync + 'static;
19
20 fn new(config: Self::Config) -> (Self, Task<Self::Message>);
21
22 fn update(&mut self, message: Self::Message) -> Effect<Self::Message>;
23
24 fn subscription(&self) -> Subscription<Self::Message> {
25 Subscription::none()
26 }
27
28 /// What the widget shows in the bar.
29 fn item(&self) -> Item<Self::Message>;
30
31 /// The popover contents, if this widget has one.
32 ///
33 /// When it returns `Some` and the item has no `on_press`, a click on the item opens and
34 /// closes the popover. Returning `None` while the popover is open closes it.
35 fn popover(&self) -> Option<Panel<Self::Message>> {
36 None
37 }
38
39 /// Notifications to show on screen now, newest first. Only for a notification engine: the
40 /// widget that serves `org.freedesktop.Notifications` lists here what it received. Any other
41 /// widget sends its notifications with `Notify` on the session bus, like any app.
42 ///
43 /// While there are any, the bar's right island turns into a panel of them, like a popover. The
44 /// host takes each one away once its key is no longer in the list. Keep the notices you mean to show in your state, and drop
45 /// one when it's dismissed or expires.
46 fn notices(&self) -> Vec<Notice<Self::Message>> {
47 Vec::new()
48 }
49
50 /// What the widget can do, for the dormer: the host's search dialog, which a keybind opens.
51 /// Typing finds an action by its title, subtitle and keywords, and picking it sends its message
52 /// to this widget, like a click would.
53 ///
54 /// The host reads them only while the dormer is open, after each of your messages, so they can
55 /// follow your state: "Mute" while sound plays, "Unmute" while muted. Leave out what can't be
56 /// done right now. Keep it pure and cheap, like the views.
57 fn actions(&self) -> Vec<Action<Self::Message>> {
58 Vec::new()
59 }
60}