cosmic/widget/rectangle_tracker/
subscription.rs
1use iced::{
2 Rectangle,
3 futures::{
4 StreamExt,
5 channel::mpsc::{UnboundedReceiver, unbounded},
6 stream,
7 },
8};
9use iced_futures::Subscription;
10use std::{collections::HashMap, fmt::Debug, hash::Hash};
11
12use super::RectangleTracker;
13
14#[cold]
15pub fn rectangle_tracker_subscription<
16 I: 'static + Hash + Copy + Send + Sync + Debug,
17 R: 'static + Hash + Copy + Send + Sync + Debug + Eq,
18>(
19 id: I,
20) -> Subscription<(I, RectangleUpdate<R>)> {
21 Subscription::run_with_id(
22 id,
23 stream::unfold(State::Ready, move |state| start_listening(id, state)),
24 )
25}
26
27pub enum State<I> {
28 Ready,
29 Waiting(UnboundedReceiver<(I, Rectangle)>, HashMap<I, Rectangle>),
30 Finished,
31}
32
33async fn start_listening<I: Copy, R: 'static + Hash + Copy + Send + Sync + Debug + Eq>(
34 id: I,
35 mut state: State<R>,
36) -> Option<((I, RectangleUpdate<R>), State<R>)> {
37 loop {
38 let (update, new_state) = match state {
39 State::Ready => {
40 let (tx, rx) = unbounded();
41
42 (
43 Some((id, RectangleUpdate::Init(RectangleTracker { tx }))),
44 State::Waiting(rx, HashMap::new()),
45 )
46 }
47 State::Waiting(mut rx, mut map) => match rx.next().await {
48 Some(u) => {
49 if let Some(prev) = map.get(&u.0) {
50 let new = u.1;
51 if (prev.width - new.width).abs() > 0.1
52 || (prev.height - new.height).abs() > 0.1
53 || (prev.x - new.x).abs() > 0.1
54 || (prev.y - new.y).abs() > 0.1
55 {
56 map.insert(u.0, new);
57 (
58 Some((id, RectangleUpdate::Rectangle(u))),
59 State::Waiting(rx, map),
60 )
61 } else {
62 (None, State::Waiting(rx, map))
63 }
64 } else {
65 map.insert(u.0, u.1);
66 (
67 Some((id, RectangleUpdate::Rectangle(u))),
68 State::Waiting(rx, map),
69 )
70 }
71 }
72 None => (None, State::Finished),
73 },
74 State::Finished => return None,
75 };
76 state = new_state;
77 if let Some(u) = update {
78 return Some((u, state));
79 }
80 }
81}
82
83#[derive(Clone, Debug)]
84pub enum RectangleUpdate<I>
85where
86 I: 'static + Hash + Copy + Send + Sync + Debug,
87{
88 Rectangle((I, Rectangle)),
89 Init(RectangleTracker<I>),
90}