Skip to main content

iced_selector/
find.rs

1use crate::Selector;
2use crate::core::widget::operation::accessible::Accessible;
3use crate::core::widget::operation::{Focusable, Outcome, Scrollable, TextInput};
4use crate::core::widget::{Id, Operation};
5use crate::core::{Rectangle, Vector};
6use crate::target::Candidate;
7
8use std::any::Any;
9
10/// An [`Operation`] that runs the [`Selector`] and stops after
11/// the first [`Output`](Selector::Output) is produced.
12pub type Find<S> = Finder<One<S>>;
13
14/// An [`Operation`] that runs the [`Selector`] for the entire
15/// widget tree and aggregates all of its [`Output`](Selector::Output).
16pub type FindAll<S> = Finder<All<S>>;
17
18#[derive(Debug)]
19pub struct One<S>
20where
21    S: Selector,
22{
23    selector: S,
24    output: Option<S::Output>,
25}
26
27impl<S> One<S>
28where
29    S: Selector,
30{
31    pub fn new(selector: S) -> Self {
32        Self {
33            selector,
34            output: None,
35        }
36    }
37}
38
39impl<S> Strategy for One<S>
40where
41    S: Selector,
42    S::Output: Clone,
43{
44    type Output = Option<S::Output>;
45
46    fn feed(&mut self, target: Candidate<'_>) {
47        if let Some(output) = self.selector.select(target) {
48            self.output = Some(output);
49        }
50    }
51
52    fn is_done(&self) -> bool {
53        self.output.is_some()
54    }
55
56    fn finish(&self) -> Self::Output {
57        self.output.clone()
58    }
59}
60
61#[derive(Debug)]
62pub struct All<S>
63where
64    S: Selector,
65{
66    selector: S,
67    outputs: Vec<S::Output>,
68}
69
70impl<S> All<S>
71where
72    S: Selector,
73{
74    pub fn new(selector: S) -> Self {
75        Self {
76            selector,
77            outputs: Vec::new(),
78        }
79    }
80}
81
82impl<S> Strategy for All<S>
83where
84    S: Selector,
85    S::Output: Clone,
86{
87    type Output = Vec<S::Output>;
88
89    fn feed(&mut self, target: Candidate<'_>) {
90        if let Some(output) = self.selector.select(target) {
91            self.outputs.push(output);
92        }
93    }
94
95    fn is_done(&self) -> bool {
96        false
97    }
98
99    fn finish(&self) -> Self::Output {
100        self.outputs.clone()
101    }
102}
103
104pub trait Strategy {
105    type Output;
106
107    fn feed(&mut self, target: Candidate<'_>);
108
109    fn is_done(&self) -> bool;
110
111    fn finish(&self) -> Self::Output;
112}
113
114#[derive(Debug)]
115pub struct Finder<S> {
116    strategy: S,
117    stack: Vec<(Rectangle, Vector)>,
118    viewport: Rectangle,
119    translation: Vector,
120}
121
122impl<S> Finder<S> {
123    pub fn new(strategy: S) -> Self {
124        Self {
125            strategy,
126            stack: vec![(Rectangle::INFINITE, Vector::ZERO)],
127            viewport: Rectangle::INFINITE,
128            translation: Vector::ZERO,
129        }
130    }
131}
132
133impl<S> Operation<S::Output> for Finder<S>
134where
135    S: Strategy + Send,
136    S::Output: Send,
137{
138    fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<S::Output>)) {
139        if self.strategy.is_done() {
140            return;
141        }
142
143        self.stack.push((self.viewport, self.translation));
144        operate(self);
145        let _ = self.stack.pop();
146
147        let (viewport, translation) = self.stack.last().unwrap();
148        self.viewport = *viewport;
149        self.translation = *translation;
150    }
151
152    fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
153        if self.strategy.is_done() {
154            return;
155        }
156
157        self.strategy.feed(Candidate::Container {
158            id,
159            bounds,
160            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
161        });
162    }
163
164    fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
165        if self.strategy.is_done() {
166            return;
167        }
168
169        self.strategy.feed(Candidate::Focusable {
170            id,
171            bounds,
172            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
173            state,
174        });
175    }
176
177    fn scrollable(
178        &mut self,
179        id: Option<&Id>,
180        bounds: Rectangle,
181        content_bounds: Rectangle,
182        translation: Vector,
183        state: &mut dyn Scrollable,
184    ) {
185        if self.strategy.is_done() {
186            return;
187        }
188
189        let visible_bounds = self.viewport.intersection(&(bounds + self.translation));
190
191        self.strategy.feed(Candidate::Scrollable {
192            id,
193            bounds,
194            visible_bounds,
195            content_bounds,
196            translation,
197            state,
198        });
199
200        self.translation -= translation;
201        self.viewport = visible_bounds.unwrap_or_default();
202    }
203
204    fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
205        if self.strategy.is_done() {
206            return;
207        }
208
209        self.strategy.feed(Candidate::TextInput {
210            id,
211            bounds,
212            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
213            state,
214        });
215    }
216
217    fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
218        if self.strategy.is_done() {
219            return;
220        }
221
222        self.strategy.feed(Candidate::Text {
223            id,
224            bounds,
225            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
226            content: text,
227        });
228    }
229
230    fn accessible(&mut self, id: Option<&Id>, bounds: Rectangle, accessible: &Accessible<'_>) {
231        if self.strategy.is_done() {
232            return;
233        }
234
235        self.strategy.feed(Candidate::Accessible {
236            id,
237            bounds,
238            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
239            accessible,
240        });
241    }
242
243    fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
244        if self.strategy.is_done() {
245            return;
246        }
247
248        self.strategy.feed(Candidate::Custom {
249            id,
250            bounds,
251            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),
252            state,
253        });
254    }
255
256    fn finish(&self) -> Outcome<S::Output> {
257        Outcome::Some(self.strategy.finish())
258    }
259}