1use std::{borrow::Cow, future::Future, sync::Arc};
2
3use super::{
4 async_handler, AnimationBinding, BackdropBlurStyle, Color, ComponentId, CompositingLayerSpec,
5 CustomPaintStyle, EventPolicy, HostTreeBuilder, IconStyle, ImageFit, ImageRequest,
6 InteractionRole, LayoutSpec, OverlayStyle, PathStyle, RenderPhase, ScrollRasterSpec,
7 StaticLayerSpec, TextStyle, UiAction, UiAsyncContext, UiEventContext, UiEventHandler,
8 UiEventKind, UiEventPayload, UiId, UiImageSource, UiInputEventHandler, UiNode, UiNodeKind,
9 UiPath, UiRect, VisualStyle,
10};
11
12#[derive(Clone)]
13pub struct UiElement {
14 node: UiNode,
15 children: Arc<Vec<UiElement>>,
16 component_boundary: Option<ComponentBoundary>,
17}
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub(crate) struct ComponentBoundary {
21 pub id: ComponentId,
22 pub retain_children: bool,
23}
24
25pub trait UiComponent {
26 fn render(self) -> UiElement;
27}
28
29impl UiComponent for UiElement {
30 fn render(self) -> UiElement {
31 self
32 }
33}
34
35impl UiElement {
36 pub fn new(id: UiId, kind: UiNodeKind, rect: UiRect) -> Self {
37 Self {
38 node: UiNode::new(id, kind, rect),
39 children: Arc::new(Vec::new()),
40 component_boundary: None,
41 }
42 }
43
44 pub(crate) fn estimated_bytes(&self) -> usize {
45 self.node
46 .estimated_bytes()
47 .saturating_add(
48 self.children
49 .capacity()
50 .saturating_mul(std::mem::size_of::<UiElement>()),
51 )
52 .saturating_add(
53 self.children
54 .iter()
55 .map(UiElement::estimated_bytes)
56 .sum::<usize>(),
57 )
58 }
59
60 pub fn group(id: UiId, rect: UiRect) -> Self {
61 Self::new(id, UiNodeKind::Group, rect)
62 }
63
64 pub fn panel(id: UiId, rect: UiRect, style: VisualStyle) -> Self {
65 Self::new(id, UiNodeKind::Panel, rect).style(style)
66 }
67
68 pub fn button(id: UiId, rect: UiRect, style: VisualStyle) -> Self {
69 Self::new(id, UiNodeKind::Button, rect)
70 .style(style)
71 .interaction(InteractionRole::Button)
72 }
73
74 pub fn text(
75 id: UiId,
76 rect: UiRect,
77 text: impl Into<Cow<'static, str>>,
78 style: TextStyle,
79 ) -> Self {
80 Self::new(id, UiNodeKind::Text, rect).text_content(text, style)
81 }
82
83 pub fn custom(id: UiId, rect: UiRect, key: &'static str) -> Self {
84 Self::new(id, UiNodeKind::Custom(key), rect)
85 }
86
87 pub fn custom_paint(
88 id: UiId,
89 rect: UiRect,
90 key: &'static str,
91 style: CustomPaintStyle,
92 ) -> Self {
93 Self::custom(id, rect, key).custom_style(style)
94 }
95
96 pub fn image(id: UiId, rect: UiRect, source: &'static str, fit: ImageFit) -> Self {
97 Self::new(id, UiNodeKind::Image, rect).image_source(source, fit)
98 }
99
100 pub fn file_image(
101 id: UiId,
102 rect: UiRect,
103 source: impl Into<std::path::PathBuf>,
104 fit: ImageFit,
105 ) -> Self {
106 Self::new(id, UiNodeKind::Image, rect).image_source(UiImageSource::file(source), fit)
107 }
108
109 pub fn requested_image(
110 id: UiId,
111 rect: UiRect,
112 request: impl Into<ImageRequest>,
113 fit: ImageFit,
114 ) -> Self {
115 Self::new(id, UiNodeKind::Image, rect).image_request(request, fit)
116 }
117
118 pub fn icon(id: UiId, rect: UiRect, key: &'static str) -> Self {
119 Self::new(id, UiNodeKind::Icon, rect).icon_key(key)
120 }
121
122 pub fn glow(id: UiId, rect: UiRect, color: Color, alpha: u8) -> Self {
123 Self::new(id, UiNodeKind::Glow, rect).glow_effect(color, alpha)
124 }
125
126 pub fn backdrop_blur(id: UiId, rect: UiRect, style: BackdropBlurStyle) -> Self {
127 Self::new(id, UiNodeKind::BackdropBlur, rect).backdrop_blur_style(style)
128 }
129
130 pub fn backdrop_blur_path(
131 id: UiId,
132 rect: UiRect,
133 path: UiPath,
134 style: BackdropBlurStyle,
135 ) -> Self {
136 Self::new(id, UiNodeKind::BackdropBlurPath, rect)
137 .path_content(path, PathStyle::default())
138 .backdrop_blur_style(style)
139 }
140
141 pub fn overlay(id: UiId, rect: UiRect, style: OverlayStyle) -> Self {
142 Self::new(id, UiNodeKind::Overlay, rect).overlay_style(style)
143 }
144
145 pub fn static_layer(id: UiId, rect: UiRect, spec: StaticLayerSpec) -> Self {
146 Self::new(id, UiNodeKind::StaticLayer, rect).static_layer_spec(spec)
147 }
148
149 pub fn compositing_layer(id: UiId, rect: UiRect, spec: CompositingLayerSpec) -> Self {
150 Self::new(id, UiNodeKind::CompositingLayer, rect).compositing_layer_spec(spec)
151 }
152
153 pub fn scroll_raster(id: UiId, viewport: UiRect, spec: ScrollRasterSpec) -> Self {
154 Self::new(id, UiNodeKind::ScrollRaster, viewport).scroll_raster_spec(spec)
155 }
156
157 pub fn clip(id: UiId, rect: UiRect, offset_x: f32, offset_y: f32) -> Self {
158 Self::new(id, UiNodeKind::Clip, rect).clip_content(rect, offset_x, offset_y)
159 }
160
161 pub fn clip_path(id: UiId, rect: UiRect, path: UiPath) -> Self {
162 Self::new(id, UiNodeKind::ClipPath, rect).path_content(path, PathStyle::default())
163 }
164
165 pub fn line(id: UiId, rect: UiRect, style: VisualStyle) -> Self {
166 Self::new(id, UiNodeKind::Line, rect).style(style)
167 }
168
169 pub fn path(id: UiId, rect: UiRect, path: UiPath, style: PathStyle) -> Self {
170 Self::new(id, UiNodeKind::Path, rect).path_content(path, style)
171 }
172
173 pub fn ellipse(id: UiId, rect: UiRect, style: VisualStyle) -> Self {
174 Self::new(id, UiNodeKind::Ellipse, rect).style(style)
175 }
176
177 pub fn node(&self) -> &UiNode {
178 &self.node
179 }
180
181 pub fn children_ref(&self) -> &[UiElement] {
182 self.children.as_slice()
183 }
184
185 pub fn child(mut self, child: UiElement) -> Self {
186 Arc::make_mut(&mut self.children).push(child);
187 self
188 }
189
190 pub fn children(mut self, children: impl IntoIterator<Item = UiElement>) -> Self {
191 Arc::make_mut(&mut self.children).extend(children);
192 self
193 }
194
195 pub fn interaction(mut self, interaction: InteractionRole) -> Self {
196 self.node = self.node.interaction(interaction);
197 self
198 }
199
200 pub fn semantics(mut self, semantics: super::Semantics) -> Self {
201 self.node = self.node.semantics(semantics);
202 self
203 }
204
205 pub fn window_drag_region(mut self) -> Self {
210 self.node = self
211 .node
212 .interaction(InteractionRole::WindowDragRegion)
213 .event_policy(EventPolicy::NONE);
214 self
215 }
216
217 pub fn on_click<F>(mut self, handler: F) -> Self
218 where
219 F: Fn(&mut UiEventContext) + Send + Sync + 'static,
220 {
221 self.node = self.node.on_click(handler);
222 self
223 }
224
225 pub fn on_click_handler(mut self, handler: UiEventHandler) -> Self {
226 self.node = self.node.on_click_handler(handler);
227 self
228 }
229
230 pub fn on_click_async<F, Fut>(mut self, handler: F) -> Self
231 where
232 F: Fn(UiAsyncContext) -> Fut + Send + Sync + 'static,
233 Fut: Future<Output = ()> + Send + 'static,
234 {
235 self.node = self.node.on_click_handler(async_handler(handler));
236 self
237 }
238
239 pub fn on_click_capture<F>(mut self, handler: F) -> Self
240 where
241 F: Fn(&mut UiEventContext) + Send + Sync + 'static,
242 {
243 self.node = self.node.on_click_capture(handler);
244 self
245 }
246
247 pub fn on_event_handler(
248 mut self,
249 kind: UiEventKind,
250 capture: bool,
251 handler: UiInputEventHandler,
252 ) -> Self {
253 self.node = self.node.on_event_handler(kind, capture, handler);
254 self
255 }
256
257 pub fn on_event<F>(mut self, kind: UiEventKind, handler: F) -> Self
258 where
259 F: Fn(&mut UiEventContext, &UiEventPayload) + Send + Sync + 'static,
260 {
261 self.node = self.node.on_event(kind, handler);
262 self
263 }
264
265 pub fn on_event_capture<F>(mut self, kind: UiEventKind, handler: F) -> Self
266 where
267 F: Fn(&mut UiEventContext, &UiEventPayload) + Send + Sync + 'static,
268 {
269 self.node = self.node.on_event_capture(kind, handler);
270 self
271 }
272
273 pub fn on_click_capture_handler(mut self, handler: UiEventHandler) -> Self {
274 self.node = self.node.on_click_capture_handler(handler);
275 self
276 }
277
278 pub fn wheel_action(mut self, action: UiAction) -> Self {
279 self.node = self.node.wheel_action(action);
280 self
281 }
282
283 pub fn click_action(mut self, action: UiAction) -> Self {
284 self.node = self.node.click_action(action);
285 self
286 }
287
288 pub fn action_target(mut self, target: UiId) -> Self {
289 self.node = self.node.action_target(target);
290 self
291 }
292
293 pub fn on_action<F>(mut self, id: impl Into<super::ActionId>, handler: F) -> Self
294 where
295 F: Fn(&mut UiEventContext, &UiAction) + Send + Sync + 'static,
296 {
297 self.node = self.node.on_action(id, handler);
298 self
299 }
300
301 pub fn event_policy(mut self, policy: EventPolicy) -> Self {
302 self.node = self.node.event_policy(policy);
303 self
304 }
305
306 pub fn auto_focus(mut self) -> Self {
307 self.node = self.node.auto_focus(true);
308 self
309 }
310
311 pub fn focus_scope(mut self) -> Self {
312 self.node = self.node.focus_scope(true);
313 self
314 }
315
316 pub fn animation(mut self, binding: AnimationBinding) -> Self {
317 self.node = self.node.animation(binding);
318 self
319 }
320
321 pub fn animation_target(mut self, property: super::AnimProperty, active: bool) -> Self {
322 self.node = self.node.animation_target(property, active);
323 self
324 }
325
326 pub fn animation_outset(mut self, x: f32, y: f32) -> Self {
327 self.node = self.node.animation_outset(x, y);
328 self
329 }
330
331 pub fn layout(mut self, layout: LayoutSpec) -> Self {
332 self.node = self.node.layout(layout);
333 self
334 }
335
336 pub fn style(mut self, style: VisualStyle) -> Self {
337 self.node = self.node.style(style);
338 self
339 }
340
341 pub fn path_content(mut self, path: UiPath, style: PathStyle) -> Self {
342 self.node = self.node.path(path, style);
343 self
344 }
345
346 pub fn text_content(mut self, text: impl Into<Cow<'static, str>>, style: TextStyle) -> Self {
347 self.node = self.node.text(text, style);
348 self
349 }
350
351 pub fn image_source(mut self, source: impl Into<UiImageSource>, fit: ImageFit) -> Self {
352 self.node = self.node.image(source, fit);
353 self
354 }
355
356 pub fn image_request(mut self, request: impl Into<ImageRequest>, fit: ImageFit) -> Self {
357 self.node = self.node.image_request(request, fit);
358 self
359 }
360
361 pub fn icon_key(mut self, key: &'static str) -> Self {
362 self.node = self.node.icon(key);
363 self
364 }
365
366 pub fn icon_style(mut self, style: IconStyle) -> Self {
367 self.node = self.node.icon_style(style);
368 self
369 }
370
371 pub fn glow_effect(mut self, color: Color, alpha: u8) -> Self {
372 self.node = self.node.glow(color, alpha);
373 self
374 }
375
376 pub fn overlay_style(mut self, style: OverlayStyle) -> Self {
377 self.node = self.node.overlay(style);
378 self
379 }
380
381 pub fn backdrop_blur_style(mut self, style: BackdropBlurStyle) -> Self {
382 self.node = self.node.backdrop_blur(style);
383 self
384 }
385
386 pub fn custom_style(mut self, style: CustomPaintStyle) -> Self {
387 self.node = self.node.custom_style(style);
388 self
389 }
390
391 pub fn static_layer_spec(mut self, spec: StaticLayerSpec) -> Self {
392 self.node = self.node.static_layer(spec);
393 self
394 }
395
396 pub fn compositing_layer_spec(mut self, spec: CompositingLayerSpec) -> Self {
397 self.node = self.node.compositing_layer(spec);
398 self
399 }
400
401 pub fn shadow(mut self, style: super::ShadowStyle) -> Self {
403 self.node = self.node.shadow(style);
404 self
405 }
406
407 pub fn scroll_raster_spec(mut self, spec: ScrollRasterSpec) -> Self {
408 self.node = self.node.scroll_raster(spec);
409 self
410 }
411
412 pub fn clip_content(mut self, rect: UiRect, offset_x: f32, offset_y: f32) -> Self {
413 self.node = self.node.clip(rect, offset_x, offset_y);
414 self
415 }
416
417 pub fn hit_rect(mut self, rect: UiRect) -> Self {
418 self.node = self.node.hit_rect(rect);
419 self
420 }
421
422 pub fn paint_bounds(mut self, rect: UiRect) -> Self {
423 self.node = self.node.paint_bounds(rect);
424 self
425 }
426
427 pub fn ime_cursor_rect(mut self, rect: UiRect) -> Self {
428 self.node = self.node.ime_cursor_rect(rect);
429 self
430 }
431
432 pub fn render_phase(mut self, phase: RenderPhase) -> Self {
433 self.node = self.node.render_phase(phase);
434 self
435 }
436
437 pub fn translate(mut self, x: f32, y: f32) -> Self {
438 self.node = self.node.translate(x, y);
439 self.children = Arc::new(
440 self.children
441 .iter()
442 .cloned()
443 .map(|child| child.translate(x, y))
444 .collect(),
445 );
446 self
447 }
448
449 pub(crate) fn claim_component_owner(mut self, owner: ComponentId) -> Self {
450 if self.node.component_owner.is_none() {
451 self.node = self.node.component_owner(owner);
452 }
453 self.children = Arc::new(
454 self.children
455 .iter()
456 .cloned()
457 .map(|child| child.claim_component_owner(owner))
458 .collect(),
459 );
460 self
461 }
462
463 pub(crate) fn component_boundary(mut self, id: ComponentId) -> Self {
464 if self.component_boundary.is_none() {
465 self.component_boundary = Some(ComponentBoundary {
466 id,
467 retain_children: false,
468 });
469 }
470 self
471 }
472
473 pub(crate) fn into_retained_boundary(mut self, id: ComponentId) -> Self {
474 self.component_boundary = Some(ComponentBoundary {
475 id,
476 retain_children: true,
477 });
478 self
479 }
480
481 pub(crate) fn into_parts(self) -> (UiNode, Arc<Vec<UiElement>>, Option<ComponentBoundary>) {
482 (self.node, self.children, self.component_boundary)
483 }
484
485 pub fn mount(self, builder: &mut HostTreeBuilder) -> UiId {
486 builder.mount_element(self)
487 }
488}