1use std::ops::ControlFlow;
2
3use anathema_geometry::{Pos, Region};
4use anathema_value_resolver::{AttributeStorage, Attributes};
5
6use super::{Chain, Filter, Nodes, Query, QueryValue};
7use crate::nodes::element::Element;
8use crate::{WidgetId, WidgetKind};
9
10pub struct Elements<'children, 'tree, 'bp> {
11 pub(super) elements: &'children mut Nodes<'tree, 'bp>,
12}
13
14impl<'children, 'tree, 'bp> Elements<'children, 'tree, 'bp> {
15 pub fn by_tag<'a>(&mut self, tag: &'a str) -> ElementQuery<'_, 'tree, 'bp, Kind<'a>> {
16 self.make_query(Kind::ByTag(tag))
17 }
18
19 pub fn at_position<'a>(&mut self, pos: impl Into<Pos>) -> ElementQuery<'_, 'tree, 'bp, Kind<'a>> {
20 self.make_query(Kind::AtPosition(pos.into()))
21 }
22
23 pub fn first<F, U>(&mut self, f: F) -> Option<U>
24 where
25 F: FnMut(&mut Element<'_>, &mut Attributes<'_>) -> U,
26 {
27 self.make_query(Kind::All).first(f)
28 }
29
30 pub fn each<F>(&mut self, f: F)
31 where
32 F: FnMut(&mut Element<'_>, &mut Attributes<'_>),
33 {
34 self.make_query(Kind::All).each(f)
35 }
36
37 pub fn by_attribute<'a>(
38 &mut self,
39 key: &'a str,
40 value: impl Into<QueryValue<'a>>,
41 ) -> ElementQuery<'_, 'tree, 'bp, Kind<'a>> {
42 self.make_query(Kind::ByAttribute(key, value.into()))
43 }
44
45 pub fn by_id<'a>(&mut self, id: WidgetId) -> ElementQuery<'_, 'tree, 'bp, Kind<'a>> {
46 self.make_query(Kind::ById(id))
47 }
48
49 fn make_query<'a>(&mut self, kind: Kind<'a>) -> ElementQuery<'_, 'tree, 'bp, Kind<'a>> {
50 ElementQuery {
51 query: Query {
52 filter: kind,
53 elements: self.elements,
54 },
55 }
56 }
57}
58
59pub struct ElementQuery<'el, 'tree, 'bp, T>
60where
61 T: Filter<'bp, Kind = Element<'bp>> + Copy,
62{
63 query: Query<'el, 'tree, 'bp, T, Element<'bp>>,
64}
65
66impl<'el, 'tree, 'bp, T> ElementQuery<'el, 'tree, 'bp, T>
67where
68 T: Filter<'bp, Kind = Element<'bp>> + Copy,
69{
70 pub fn by_tag(self, name: &str) -> ElementQuery<'el, 'tree, 'bp, Chain<T, Kind<'_>>> {
71 ElementQuery {
72 query: Query {
73 filter: Chain::new(self.query.filter, Kind::ByTag(name)),
74 elements: self.query.elements,
75 },
76 }
77 }
78
79 pub fn at_position(self, pos: impl Into<Pos>) -> ElementQuery<'el, 'tree, 'bp, Chain<T, Kind<'static>>> {
80 ElementQuery {
81 query: Query {
82 filter: Chain::new(self.query.filter, Kind::AtPosition(pos.into())),
83 elements: self.query.elements,
84 },
85 }
86 }
87
88 pub fn by_attribute<'a>(
89 self,
90 key: &'a str,
91 value: impl Into<QueryValue<'a>>,
92 ) -> ElementQuery<'el, 'tree, 'bp, Chain<T, Kind<'a>>> {
93 ElementQuery {
94 query: Query {
95 filter: Chain::new(self.query.filter, Kind::ByAttribute(key, value.into())),
96 elements: self.query.elements,
97 },
98 }
99 }
100
101 pub fn first<F, U>(self, mut f: F) -> Option<U>
102 where
103 F: FnMut(&mut Element<'_>, &mut Attributes<'_>) -> U,
104 {
105 match self.query(&mut f, false) {
106 ControlFlow::Continue(_) => None,
107 ControlFlow::Break(val) => Some(val),
108 }
109 }
110
111 pub fn each<F>(self, mut f: F)
112 where
113 F: FnMut(&mut Element<'_>, &mut Attributes<'_>),
114 {
115 _ = self.query(&mut f, true);
116 }
117
118 fn query<F, U>(self, f: &mut F, continuous: bool) -> ControlFlow<U>
119 where
120 F: FnMut(&mut Element<'_>, &mut Attributes<'_>) -> U,
121 {
122 let ret_val = self.query.elements.children.for_each(|_path, container, children| {
123 if let WidgetKind::Element(ref mut element) = container.kind {
124 if self.query.filter.filter(element, self.query.elements.attributes) {
125 let attributes = self.query.elements.attributes.get_mut(element.id());
126 let ret_val = f(element, attributes);
127 element.invalidate_cache();
128 *self.query.elements.needs_layout = true;
129
130 if !continuous {
131 return ControlFlow::Break(ret_val);
132 }
133 }
134 }
135
136 let mut elements = Nodes::new(
137 children,
138 self.query.elements.attributes,
139 self.query.elements.needs_layout,
140 );
141
142 let query = ElementQuery {
143 query: Query {
144 elements: &mut elements,
145 filter: self.query.filter,
146 },
147 };
148
149 query.query(f, continuous)
150 });
151
152 match ret_val {
153 Some(val) => ControlFlow::Break(val),
154 None => ControlFlow::Continue(()),
155 }
156 }
157}
158
159#[derive(Debug, Copy, Clone)]
163pub enum Kind<'a> {
164 All,
165 ByTag(&'a str),
166 ByAttribute(&'a str, QueryValue<'a>),
167 AtPosition(Pos),
168 ById(WidgetId),
169}
170
171impl<'bp, 'a> Filter<'bp> for Kind<'a> {
172 type Kind = Element<'bp>;
173
174 fn filter(&self, el: &Element<'bp>, attributes: &mut AttributeStorage<'_>) -> bool {
175 match self {
176 Kind::All => true,
177 Kind::ByTag(tag) => el.ident == *tag,
178 Kind::ByAttribute(key, value) => {
179 let attribs = attributes.get(el.container.id);
180 attribs.get(key).map(|attribute| value.eq(attribute)).unwrap_or(false)
181 }
182 Kind::AtPosition(pos) => {
183 let region = Region::from((el.get_pos(), el.size()));
184 region.contains(*pos)
185 }
186 Kind::ById(id) => el.id() == *id,
187 }
188 }
189}