1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::hash::Hash;
4use std::panic::Location;
5use std::sync::Arc;
6use std::sync::atomic::{AtomicU64, Ordering};
7use std::time::Duration;
8
9use smallvec::SmallVec;
10
11use fret_core::input::PointerType;
12use fret_core::window::{ColorScheme, ContrastPreference, ForcedColorsMode};
13use fret_core::{
14 AppWindowId, Color, Edges, EffectChain, EffectMode, EffectQuality, NodeId, Px, Rect,
15};
16use fret_runtime::{Effect, FrameId, Model, ModelId, ModelUpdateError, TimerToken};
17
18use crate::action::OnHoverChange;
19use crate::action::{
20 ActionRouteHooks, CommandActionHooks, CommandAvailabilityActionHooks, DismissibleActionHooks,
21 KeyActionHooks, OnActivate, OnCommand, OnCommandAvailability, OnDismissRequest,
22 OnDismissiblePointerMove, OnKeyDown, OnPinchGesture, OnPointerCancel, OnPointerDown,
23 OnPointerMove, OnPointerUp, OnPressablePointerDown, OnPressablePointerMove,
24 OnPressablePointerUp, OnRovingActiveChange, OnRovingNavigate, OnRovingTypeahead,
25 OnSelectableTextActivateSpan, OnTimer, OnWheel, PointerActionHooks, PressableActionHooks,
26 PressableHoverActionHooks, PressablePointerUpResult, RovingActionHooks,
27 SelectableTextActionHooks, TimerActionHooks,
28};
29use crate::canvas::{CanvasPaintHooks, CanvasPainter, OnCanvasPaint};
30use crate::element::{
31 AnyElement, BackdropSourceGroupProps, CanvasProps, ColumnProps, CompositeGroupProps,
32 ContainerProps, EffectLayerProps, ElementKind, FlexProps, FocusTraversalGateProps,
33 ForegroundScopeProps, GridProps, HitTestGateProps, HoverRegionProps, ImageProps,
34 InteractivityGateProps, LayoutQueryRegionProps, LayoutStyle, MaskLayerProps, OpacityProps,
35 PointerRegionProps, PressableProps, PressableState, ResizablePanelGroupProps, RowProps,
36 ScrollProps, ScrollbarProps, SelectableTextProps, SpacerProps, SpinnerProps, StackProps,
37 StyledTextProps, SvgIconProps, TextAreaProps, TextInputProps, TextProps, ViewportSurfaceProps,
38 VirtualListOptions, VirtualListProps, VirtualListState, VisualTransformProps,
39};
40use crate::overlay_placement::{AnchoredPanelLayoutTrace, Side};
41use crate::widget::Invalidation;
42use crate::{SvgSource, Theme, UiHost};
43use fret_core::window::WindowMetricsService;
44
45use super::hash::{callsite_hash, derive_child_id, stable_hash};
46use super::runtime::{EnvironmentQueryKey, LayoutQueryRegionMarker};
47use super::{ContinuousFrames, ElementRuntime, GlobalElementId, WindowElementState, global_root};
48
49pub struct ElementContext<'a, H: UiHost> {
59 pub app: &'a mut H,
60 pub window: AppWindowId,
61 pub frame_id: FrameId,
62 pub bounds: Rect,
63 render_pass_id: u64,
64 window_state: &'a mut WindowElementState,
65 stack: Vec<GlobalElementId>,
66 callsite_counters: Vec<CallsiteCounters>,
67 view_cache_should_reuse: Option<&'a mut dyn FnMut(NodeId) -> bool>,
68}
69
70pub trait ElementContextAccess<'a, H: UiHost> {
76 fn elements(&mut self) -> &mut ElementContext<'a, H>;
77}
78
79impl<'a, H: UiHost> ElementContextAccess<'a, H> for ElementContext<'a, H> {
80 fn elements(&mut self) -> &mut ElementContext<'a, H> {
81 self
82 }
83}
84
85type CallsiteCounters = SmallVec<[(u64, u32); 16]>;
86
87static NEXT_RENDER_PASS_ID: AtomicU64 = AtomicU64::new(1);
88
89fn next_render_pass_id() -> u64 {
90 NEXT_RENDER_PASS_ID.fetch_add(1, Ordering::Relaxed)
91}
92
93#[derive(Debug)]
94struct ProvidedState<T> {
95 value: Option<T>,
96}
97
98struct LocalModelSlot<T> {
99 model: Option<Model<T>>,
100}
101
102#[cfg(debug_assertions)]
103#[derive(Default)]
104struct RenderEvaluationCallsiteDiagnostics {
105 last_render_pass_id: u64,
106 calls_in_render_pass: u32,
107}
108
109#[cfg(debug_assertions)]
110fn note_call_in_render_evaluation(
111 diagnostics: &mut RenderEvaluationCallsiteDiagnostics,
112 render_pass_id: u64,
113) -> bool {
114 if diagnostics.last_render_pass_id != render_pass_id {
115 diagnostics.last_render_pass_id = render_pass_id;
116 diagnostics.calls_in_render_pass = 0;
117 }
118 diagnostics.calls_in_render_pass = diagnostics.calls_in_render_pass.saturating_add(1);
119 diagnostics.calls_in_render_pass == 2
120}
121
122impl<T> Default for LocalModelSlot<T> {
123 fn default() -> Self {
124 Self { model: None }
125 }
126}
127
128impl<T> Default for ProvidedState<T> {
129 fn default() -> Self {
130 Self { value: None }
131 }
132}
133
134fn bump_callsite_counter(counters: &mut CallsiteCounters, callsite: u64) -> u64 {
135 for (seen, next) in counters.iter_mut() {
136 if *seen != callsite {
137 continue;
138 }
139 let slot = (*next) as u64;
140 *next = next.saturating_add(1);
141 return slot;
142 }
143 counters.push((callsite, 1));
144 0
145}
146
147impl<'a, H: UiHost> ElementContext<'a, H> {
148 pub(crate) fn collect_children(
149 &mut self,
150 children: impl IntoIterator<Item = AnyElement>,
151 ) -> Vec<AnyElement> {
152 let iter = children.into_iter();
153 let (min, _) = iter.size_hint();
154 let mut out = self.window_state.take_scratch_element_children_vec(min);
155 out.extend(iter);
156 out
157 }
158
159 pub(crate) fn retained_virtual_list_row_any_element(
160 &mut self,
161 key: crate::ItemKey,
162 index: usize,
163 row: &crate::windowed_surface_host::RetainedVirtualListRowFn<H>,
164 ) -> AnyElement {
165 self.keyed(key, |cx| (row)(cx, index))
166 }
167
168 pub fn new(
169 app: &'a mut H,
170 runtime: &'a mut ElementRuntime,
171 window: AppWindowId,
172 bounds: Rect,
173 root: GlobalElementId,
174 ) -> Self {
175 let frame_id = app.frame_id();
176 runtime.prepare_window_for_frame(window, frame_id);
177
178 let window_state = runtime.for_window_mut(window);
179 window_state.mark_authoring_identity_seen(root);
180
181 Self {
182 app,
183 window,
184 frame_id,
185 bounds,
186 render_pass_id: next_render_pass_id(),
187 window_state,
188 stack: vec![root],
189 callsite_counters: vec![CallsiteCounters::new()],
190 view_cache_should_reuse: None,
191 }
192 }
193
194 pub(crate) fn set_view_cache_should_reuse(&mut self, f: &'a mut dyn FnMut(NodeId) -> bool) {
195 self.view_cache_should_reuse = Some(f);
196 }
197
198 pub fn new_for_root_name(
199 app: &'a mut H,
200 runtime: &'a mut ElementRuntime,
201 window: AppWindowId,
202 bounds: Rect,
203 root_name: &str,
204 ) -> Self {
205 let root = global_root(window, root_name);
206 #[cfg(feature = "diagnostics")]
207 {
208 let cx = Self::new(app, runtime, window, bounds, root);
209 cx.window_state
210 .record_debug_root(cx.frame_id, root, root_name);
211 cx
212 }
213 #[cfg(not(feature = "diagnostics"))]
214 {
215 Self::new(app, runtime, window, bounds, root)
216 }
217 }
218
219 pub(crate) fn new_for_existing_window_state(
220 app: &'a mut H,
221 window: AppWindowId,
222 bounds: Rect,
223 root: GlobalElementId,
224 window_state: &'a mut WindowElementState,
225 ) -> Self {
226 let frame_id = app.frame_id();
227 window_state.mark_authoring_identity_seen(root);
228 Self {
229 app,
230 window,
231 frame_id,
232 bounds,
233 render_pass_id: next_render_pass_id(),
234 window_state,
235 stack: vec![root],
236 callsite_counters: vec![CallsiteCounters::new()],
237 view_cache_should_reuse: None,
238 }
239 }
240
241 #[cfg(debug_assertions)]
247 #[doc(hidden)]
248 pub fn note_repeated_call_in_render_evaluation_at(
249 &mut self,
250 loc: &'static Location<'static>,
251 ) -> bool {
252 let key = (loc.file(), loc.line(), loc.column());
253 self.keyed_at(loc, key, |cx| {
254 let render_pass_id = cx.render_pass_id;
255 cx.root_state(
256 RenderEvaluationCallsiteDiagnostics::default,
257 |diagnostics| note_call_in_render_evaluation(diagnostics, render_pass_id),
258 )
259 })
260 }
261
262 #[cfg(not(debug_assertions))]
263 #[doc(hidden)]
264 pub fn note_repeated_call_in_render_evaluation_at(
265 &mut self,
266 _loc: &'static Location<'static>,
267 ) -> bool {
268 false
269 }
270
271 pub fn root_id(&self) -> GlobalElementId {
272 *self.stack.last().expect("root exists")
273 }
274
275 fn new_any_element(
276 &mut self,
277 id: GlobalElementId,
278 kind: ElementKind,
279 children: Vec<AnyElement>,
280 ) -> AnyElement {
281 AnyElement::new(id, kind, children)
282 }
283
284 pub fn inherited_state<S: Any>(&self) -> Option<&S> {
289 self.inherited_state_where(|_state: &S| true)
290 }
291
292 pub fn inherited_state_where<S: Any>(&self, predicate: impl Fn(&S) -> bool) -> Option<&S> {
297 let ty = TypeId::of::<S>();
298 for &id in self.stack.iter().rev() {
299 let key = (id, ty);
300 let Some(any) = self.window_state.state_any_ref(&key) else {
301 continue;
302 };
303 let Some(state) = any.downcast_ref::<S>() else {
304 continue;
305 };
306 if predicate(state) {
307 return Some(state);
308 }
309 }
310 None
311 }
312
313 pub fn provided<S: Any>(&self) -> Option<&S> {
315 self.provided_where(|_state: &S| true)
316 }
317
318 pub fn provided_where<S: Any>(&self, predicate: impl Fn(&S) -> bool) -> Option<&S> {
320 self.inherited_state_where::<ProvidedState<S>>(|slot| {
321 slot.value.as_ref().is_some_and(&predicate)
322 })
323 .and_then(|slot| slot.value.as_ref())
324 }
325
326 pub fn node_for_element(&self, element: GlobalElementId) -> Option<NodeId> {
335 self.window_state.node_entry(element).map(|e| e.node)
336 }
337
338 pub fn live_node_for_element(&mut self, element: GlobalElementId) -> Option<NodeId> {
343 self.window_state
344 .node_entry(element)
345 .and_then(|entry| (entry.last_seen_frame == self.frame_id).then_some(entry.node))
346 }
347
348 pub fn focused_element(&self) -> Option<GlobalElementId> {
349 self.window_state.focused_element
350 }
351
352 pub fn is_focused_element(&self, element: GlobalElementId) -> bool {
353 self.window_state.focused_element == Some(element)
354 }
355
356 pub fn is_focus_within_element(&mut self, element: GlobalElementId) -> bool {
359 let Some(focused) = self.focused_element() else {
360 return false;
361 };
362 if focused == element {
363 return true;
364 }
365
366 let root_node = crate::declarative::node_for_element_in_window_frame(
367 &mut *self.app,
368 self.window,
369 element,
370 )
371 .or_else(|| self.window_state.node_entry(element).map(|e| e.node));
372 let Some(root_node) = root_node else {
373 return false;
374 };
375 let focused_node = crate::declarative::node_for_element_in_window_frame(
376 &mut *self.app,
377 self.window,
378 focused,
379 )
380 .or_else(|| self.window_state.node_entry(focused).map(|e| e.node));
381 let Some(focused_node) = focused_node else {
382 return false;
383 };
384
385 crate::declarative::node_contains_in_window_frame(
386 &mut *self.app,
387 self.window,
388 root_node,
389 focused_node,
390 )
391 }
392
393 pub fn has_active_text_selection(&self) -> bool {
394 self.window_state.active_text_selection().is_some()
395 }
396
397 pub fn has_active_text_selection_in_root(&self, root: GlobalElementId) -> bool {
398 self.window_state
399 .active_text_selection()
400 .is_some_and(|selection| selection.root == root)
401 }
402
403 pub(crate) fn sync_focused_element_from_focused_node(&mut self, focused: Option<NodeId>) {
404 self.window_state.focused_element = focused.and_then(|node| {
405 crate::declarative::frame::element_record_for_node(&mut *self.app, self.window, node)
406 .map(|record| record.element)
407 .or_else(|| self.window_state.element_for_node(node))
408 });
409 }
410
411 pub fn last_bounds_for_element(&self, element: GlobalElementId) -> Option<Rect> {
416 self.window_state.last_bounds(element)
417 }
418
419 pub fn last_visual_bounds_for_element(&self, element: GlobalElementId) -> Option<Rect> {
425 self.window_state
426 .last_visual_bounds(element)
427 .or_else(|| self.window_state.last_bounds(element))
428 }
429
430 pub fn root_bounds_for_element(&self, element: GlobalElementId) -> Option<Rect> {
435 let root = self.window_state.node_entry(element).map(|e| e.root)?;
436 self.window_state.root_bounds(root)
437 }
438
439 pub fn take_transient(&mut self, key: u64) -> bool {
443 let element = self.root_id();
444 self.take_transient_for(element, key)
445 }
446
447 pub fn take_transient_for(&mut self, element: GlobalElementId, key: u64) -> bool {
451 self.window_state.take_transient_event(element, key)
452 }
453
454 pub fn with_root_name<R>(&mut self, root_name: &str, f: impl FnOnce(&mut Self) -> R) -> R {
455 let root = global_root(self.window, root_name);
456
457 let prev_stack = std::mem::take(&mut self.stack);
458 let prev_counters = std::mem::take(&mut self.callsite_counters);
459
460 self.stack = vec![root];
461 self.callsite_counters = vec![CallsiteCounters::new()];
462 self.window_state.mark_authoring_identity_seen(root);
463
464 let out = f(self);
465
466 self.stack = prev_stack;
467 self.callsite_counters = prev_counters;
468
469 out
470 }
471
472 pub fn with_callsite_counters_snapshot<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
478 let prev_stack = self.stack.clone();
479 let prev_counters = self.callsite_counters.clone();
480
481 let out = f(self);
482
483 debug_assert_eq!(
484 self.stack.len(),
485 prev_stack.len(),
486 "element stack depth must be balanced"
487 );
488 debug_assert_eq!(
489 self.callsite_counters.len(),
490 prev_counters.len(),
491 "callsite counters stack depth must be balanced"
492 );
493
494 self.stack = prev_stack;
495 self.callsite_counters = prev_counters;
496 debug_assert_eq!(self.callsite_counters.len(), self.stack.len());
497 out
498 }
499
500 pub fn request_frame(&mut self) {
510 self.app.request_redraw(self.window);
511 }
512
513 pub fn notify_for_animation_frame(&mut self) {
518 self.window_state
521 .request_notify_for_animation_frame(self.root_id());
522 }
523
524 pub fn request_animation_frame(&mut self) {
531 self.notify_for_animation_frame();
532 self.app
533 .push_effect(Effect::RequestAnimationFrame(self.window));
534 }
535
536 pub fn begin_continuous_frames(&mut self) -> ContinuousFrames {
541 let lease = self
542 .window_state
543 .begin_continuous_frames(Some(self.root_id()));
544 self.request_animation_frame();
545 lease
546 }
547
548 pub fn set_timer_for(&mut self, element: GlobalElementId, token: TimerToken, after: Duration) {
553 self.window_state.timer_targets.insert(
554 token,
555 crate::elements::runtime::TimerTarget::Element(element),
556 );
557 self.app.push_effect(Effect::SetTimer {
558 window: Some(self.window),
559 token,
560 after,
561 repeat: None,
562 });
563 }
564
565 pub fn set_timer(&mut self, token: TimerToken, after: Duration) {
567 let element = self.root_id();
568 self.set_timer_for(element, token, after);
569 }
570
571 pub fn cancel_timer(&mut self, token: TimerToken) {
573 self.window_state.timer_targets.remove(&token);
574 self.app.push_effect(Effect::CancelTimer { token });
575 }
576
577 #[track_caller]
578 pub fn scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
579 let loc = Location::caller();
580 let callsite = callsite_hash(loc);
581 self.enter_with_callsite(loc, callsite, None, None, f)
582 }
583
584 #[doc(hidden)]
585 pub fn scope_at<R>(
586 &mut self,
587 loc: &'static Location<'static>,
588 f: impl FnOnce(&mut Self) -> R,
589 ) -> R {
590 let callsite = callsite_hash(loc);
591 self.enter_with_callsite(loc, callsite, None, None, f)
592 }
593
594 #[track_caller]
595 pub fn keyed<K: Hash, R>(&mut self, key: K, f: impl FnOnce(&mut Self) -> R) -> R {
596 let loc = Location::caller();
597 self.keyed_at(loc, key, f)
598 }
599
600 #[doc(hidden)]
601 pub fn keyed_at<K: Hash, R>(
602 &mut self,
603 loc: &'static Location<'static>,
604 key: K,
605 f: impl FnOnce(&mut Self) -> R,
606 ) -> R {
607 let caller = callsite_hash(loc);
608 let key_hash = stable_hash(&key);
609 self.enter_with_callsite(loc, caller, Some(key_hash), None, f)
610 }
611
612 #[track_caller]
613 pub fn named<R>(&mut self, name: &str, f: impl FnOnce(&mut Self) -> R) -> R {
614 let loc = Location::caller();
615 let caller = callsite_hash(loc);
616 let key_hash = stable_hash(&name);
617 self.enter_with_callsite(loc, caller, Some(key_hash), Some(name), f)
618 }
619
620 pub fn root_state<S: Any, R>(
628 &mut self,
629 init: impl FnOnce() -> S,
630 f: impl FnOnce(&mut S) -> R,
631 ) -> R {
632 let id = self.root_id();
633 self.state_for(id, init, f)
634 }
635
636 #[deprecated(note = "use root_state(...) for root-scoped shared element state")]
641 pub fn with_state<S: Any, R>(
642 &mut self,
643 init: impl FnOnce() -> S,
644 f: impl FnOnce(&mut S) -> R,
645 ) -> R {
646 self.root_state(init, f)
647 }
648
649 #[track_caller]
669 pub fn slot_state<S: Any, R>(
670 &mut self,
671 init: impl FnOnce() -> S,
672 f: impl FnOnce(&mut S) -> R,
673 ) -> R {
674 let loc = Location::caller();
675 let id = self.callsite_state_slot_id(loc, None);
676 self.state_for(id, init, f)
677 }
678
679 #[track_caller]
684 pub fn keyed_slot_state<K: Hash, S: Any, R>(
685 &mut self,
686 key: K,
687 init: impl FnOnce() -> S,
688 f: impl FnOnce(&mut S) -> R,
689 ) -> R {
690 let loc = Location::caller();
691 let id = self.callsite_state_slot_id(loc, Some(stable_hash(&key)));
692 self.state_for(id, init, f)
693 }
694
695 #[track_caller]
700 pub fn slot_id(&mut self) -> GlobalElementId {
701 let loc = Location::caller();
702 self.slot_id_at(loc)
703 }
704
705 #[track_caller]
710 pub fn keyed_slot_id<K: Hash>(&mut self, key: K) -> GlobalElementId {
711 let loc = Location::caller();
712 self.keyed_slot_id_at(loc, key)
713 }
714
715 #[doc(hidden)]
717 pub fn slot_id_at(&mut self, loc: &'static Location<'static>) -> GlobalElementId {
718 self.callsite_state_slot_id(loc, None)
719 }
720
721 #[doc(hidden)]
724 pub fn keyed_slot_id_at<K: Hash>(
725 &mut self,
726 loc: &'static Location<'static>,
727 key: K,
728 ) -> GlobalElementId {
729 self.callsite_state_slot_id(loc, Some(stable_hash(&key)))
730 }
731
732 #[track_caller]
739 pub fn local_model<T: Any>(&mut self, init: impl FnOnce() -> T) -> Model<T> {
740 let slot = self.slot_id();
741 self.local_model_for(slot, init)
742 }
743
744 #[doc(hidden)]
746 pub fn local_model_at<T: Any>(
747 &mut self,
748 loc: &'static Location<'static>,
749 init: impl FnOnce() -> T,
750 ) -> Model<T> {
751 let slot = self.slot_id_at(loc);
752 self.local_model_for(slot, init)
753 }
754
755 #[track_caller]
760 pub fn local_model_keyed<K: Hash, T: Any>(
761 &mut self,
762 key: K,
763 init: impl FnOnce() -> T,
764 ) -> Model<T> {
765 let slot = self.keyed_slot_id(key);
766 self.local_model_for(slot, init)
767 }
768
769 #[doc(hidden)]
772 pub fn local_model_keyed_at<K: Hash, T: Any>(
773 &mut self,
774 loc: &'static Location<'static>,
775 key: K,
776 init: impl FnOnce() -> T,
777 ) -> Model<T> {
778 let slot = self.keyed_slot_id_at(loc, key);
779 self.local_model_for(slot, init)
780 }
781
782 pub fn state_for<S: Any, R>(
784 &mut self,
785 element: GlobalElementId,
786 init: impl FnOnce() -> S,
787 f: impl FnOnce(&mut S) -> R,
788 ) -> R {
789 self.window_state.with_state_mut(element, init, f)
790 }
791
792 #[deprecated(note = "use state_for(...) for explicit-identity element state")]
797 pub fn with_state_for<S: Any, R>(
798 &mut self,
799 element: GlobalElementId,
800 init: impl FnOnce() -> S,
801 f: impl FnOnce(&mut S) -> R,
802 ) -> R {
803 self.state_for(element, init, f)
804 }
805
806 pub fn model_for<T: Any>(
817 &mut self,
818 element: GlobalElementId,
819 init: impl FnOnce() -> T,
820 ) -> Model<T> {
821 self.local_model_for(element, init)
822 }
823
824 fn local_model_for<T: Any>(
825 &mut self,
826 slot: GlobalElementId,
827 init: impl FnOnce() -> T,
828 ) -> Model<T> {
829 let model = self.state_for(slot, LocalModelSlot::<T>::default, |st| st.model.clone());
830 match model {
831 Some(model) => model,
832 None => {
833 let model = self.app.models_mut().insert(init());
834 self.state_for(slot, LocalModelSlot::<T>::default, |st| {
835 st.model = Some(model.clone());
836 });
837 model
838 }
839 }
840 }
841
842 pub fn provide<S: Any, R>(&mut self, value: S, f: impl FnOnce(&mut Self) -> R) -> R {
847 let prev = self.root_state(ProvidedState::<S>::default, |slot| {
848 slot.value.replace(value)
849 });
850 let out = f(self);
851 self.root_state(ProvidedState::<S>::default, |slot| {
852 slot.value = prev;
853 });
854 out
855 }
856
857 pub fn observe_model<T>(&mut self, model: &Model<T>, invalidation: Invalidation) {
858 self.observe_model_id(model.id(), invalidation);
859 }
860
861 pub fn read_model<T: Any, R>(
862 &mut self,
863 model: &Model<T>,
864 invalidation: Invalidation,
865 f: impl FnOnce(&mut H, &T) -> R,
866 ) -> Result<R, ModelUpdateError> {
867 self.observe_model(model, invalidation);
868 model.read(&mut *self.app, f)
869 }
870
871 pub fn read_model_ref<T: Any, R>(
872 &mut self,
873 model: &Model<T>,
874 invalidation: Invalidation,
875 f: impl FnOnce(&T) -> R,
876 ) -> Result<R, ModelUpdateError> {
877 self.observe_model(model, invalidation);
878 self.app.models().read(model, f)
879 }
880
881 pub fn get_model_copied<T: Any + Copy>(
882 &mut self,
883 model: &Model<T>,
884 invalidation: Invalidation,
885 ) -> Option<T> {
886 self.read_model_ref(model, invalidation, |v| *v).ok()
887 }
888
889 pub fn get_model_cloned<T: Any + Clone>(
890 &mut self,
891 model: &Model<T>,
892 invalidation: Invalidation,
893 ) -> Option<T> {
894 self.read_model_ref(model, invalidation, Clone::clone).ok()
895 }
896
897 pub fn observe_model_id(&mut self, model: ModelId, invalidation: Invalidation) {
898 let id = self
899 .window_state
900 .current_view_cache_root()
901 .unwrap_or_else(|| self.root_id());
902 let list = self
903 .window_state
904 .observed_models_next
905 .entry(id)
906 .or_default();
907 if list
908 .iter()
909 .any(|(m, inv)| *m == model && *inv == invalidation)
910 {
911 return;
912 }
913 list.push((model, invalidation));
914 }
915
916 pub fn observe_global<T: Any>(&mut self, invalidation: Invalidation) {
917 self.observe_global_id(TypeId::of::<T>(), invalidation);
918 }
919
920 pub fn observe_global_id(&mut self, global: TypeId, invalidation: Invalidation) {
921 let id = self
922 .window_state
923 .current_view_cache_root()
924 .unwrap_or_else(|| self.root_id());
925 let list = self
926 .window_state
927 .observed_globals_next
928 .entry(id)
929 .or_default();
930 if list
931 .iter()
932 .any(|(g, inv)| *g == global && *inv == invalidation)
933 {
934 return;
935 }
936 list.push((global, invalidation));
937 }
938
939 fn observe_environment_query(&mut self, key: EnvironmentQueryKey, invalidation: Invalidation) {
940 let id = self
941 .window_state
942 .current_view_cache_root()
943 .unwrap_or_else(|| self.root_id());
944 let list = self
945 .window_state
946 .observed_environment_next
947 .entry(id)
948 .or_default();
949 if list
950 .iter()
951 .any(|(k, inv)| *k == key && *inv == invalidation)
952 {
953 return;
954 }
955 list.push((key, invalidation));
956 }
957
958 pub fn observe_layout_query_region(
959 &mut self,
960 region: GlobalElementId,
961 invalidation: Invalidation,
962 ) {
963 let id = self
964 .window_state
965 .current_view_cache_root()
966 .unwrap_or_else(|| self.root_id());
967 let list = self
968 .window_state
969 .observed_layout_queries_next
970 .entry(id)
971 .or_default();
972 if list
973 .iter()
974 .any(|(r, inv)| *r == region && *inv == invalidation)
975 {
976 return;
977 }
978 list.push((region, invalidation));
979 }
980
981 pub fn layout_query_bounds(
982 &mut self,
983 region: GlobalElementId,
984 invalidation: Invalidation,
985 ) -> Option<Rect> {
986 self.observe_layout_query_region(region, invalidation);
987 self.last_bounds_for_element(region)
988 }
989
990 pub fn environment_viewport_bounds(&mut self, invalidation: Invalidation) -> Rect {
991 self.observe_environment_query(EnvironmentQueryKey::ViewportSize, invalidation);
992 self.window_state.committed_viewport_bounds()
993 }
994
995 pub fn environment_viewport_width(&mut self, invalidation: Invalidation) -> Px {
996 self.environment_viewport_bounds(invalidation).size.width
997 }
998
999 pub fn environment_viewport_height(&mut self, invalidation: Invalidation) -> Px {
1000 self.environment_viewport_bounds(invalidation).size.height
1001 }
1002
1003 pub fn environment_scale_factor(&mut self, invalidation: Invalidation) -> f32 {
1004 self.observe_environment_query(EnvironmentQueryKey::ScaleFactor, invalidation);
1005 self.window_state.committed_scale_factor()
1006 }
1007
1008 pub fn environment_color_scheme(&mut self, invalidation: Invalidation) -> Option<ColorScheme> {
1009 self.observe_environment_query(EnvironmentQueryKey::ColorScheme, invalidation);
1010 self.window_state.committed_color_scheme()
1011 }
1012
1013 pub fn environment_prefers_reduced_motion(
1014 &mut self,
1015 invalidation: Invalidation,
1016 ) -> Option<bool> {
1017 self.observe_environment_query(EnvironmentQueryKey::PrefersReducedMotion, invalidation);
1018 self.window_state.committed_prefers_reduced_motion()
1019 }
1020
1021 pub fn environment_text_scale_factor(&mut self, invalidation: Invalidation) -> Option<f32> {
1022 self.observe_environment_query(EnvironmentQueryKey::TextScaleFactor, invalidation);
1023 self.window_state.committed_text_scale_factor()
1024 }
1025
1026 pub fn environment_prefers_reduced_transparency(
1027 &mut self,
1028 invalidation: Invalidation,
1029 ) -> Option<bool> {
1030 self.observe_environment_query(
1031 EnvironmentQueryKey::PrefersReducedTransparency,
1032 invalidation,
1033 );
1034 self.window_state.committed_prefers_reduced_transparency()
1035 }
1036
1037 pub fn environment_accent_color(&mut self, invalidation: Invalidation) -> Option<Color> {
1038 self.observe_environment_query(EnvironmentQueryKey::AccentColor, invalidation);
1039 self.window_state.committed_accent_color()
1040 }
1041
1042 pub fn environment_prefers_contrast(
1043 &mut self,
1044 invalidation: Invalidation,
1045 ) -> Option<ContrastPreference> {
1046 self.observe_environment_query(EnvironmentQueryKey::PrefersContrast, invalidation);
1047 self.window_state.committed_contrast_preference()
1048 }
1049
1050 pub fn environment_forced_colors_mode(
1051 &mut self,
1052 invalidation: Invalidation,
1053 ) -> Option<ForcedColorsMode> {
1054 self.observe_environment_query(EnvironmentQueryKey::ForcedColorsMode, invalidation);
1055 self.window_state.committed_forced_colors_mode()
1056 }
1057
1058 pub fn environment_safe_area_insets(&mut self, invalidation: Invalidation) -> Option<Edges> {
1059 self.observe_environment_query(EnvironmentQueryKey::SafeAreaInsets, invalidation);
1060 self.window_state.committed_safe_area_insets()
1061 }
1062
1063 pub fn environment_occlusion_insets(&mut self, invalidation: Invalidation) -> Option<Edges> {
1064 self.observe_environment_query(EnvironmentQueryKey::OcclusionInsets, invalidation);
1065 self.window_state.committed_occlusion_insets()
1066 }
1067
1068 pub fn environment_primary_pointer_type(&mut self, invalidation: Invalidation) -> PointerType {
1069 self.observe_environment_query(EnvironmentQueryKey::PrimaryPointerType, invalidation);
1070 self.window_state.committed_primary_pointer_type()
1071 }
1072
1073 pub fn environment_primary_pointer_can_hover(
1074 &mut self,
1075 invalidation: Invalidation,
1076 default_when_unknown: bool,
1077 ) -> bool {
1078 match self.environment_primary_pointer_type(invalidation) {
1079 PointerType::Touch => false,
1080 PointerType::Unknown => default_when_unknown,
1081 PointerType::Mouse | PointerType::Pen => true,
1082 }
1083 }
1084
1085 pub fn environment_primary_pointer_is_coarse(
1086 &mut self,
1087 invalidation: Invalidation,
1088 default_when_unknown: bool,
1089 ) -> bool {
1090 match self.environment_primary_pointer_type(invalidation) {
1091 PointerType::Touch => true,
1092 PointerType::Unknown => default_when_unknown,
1093 PointerType::Mouse | PointerType::Pen => false,
1094 }
1095 }
1096
1097 pub fn diagnostics_record_overlay_placement_anchored_panel(
1098 &mut self,
1099 overlay_root_name: Option<&str>,
1100 anchor_element: Option<GlobalElementId>,
1101 content_element: Option<GlobalElementId>,
1102 trace: AnchoredPanelLayoutTrace,
1103 ) {
1104 #[cfg(feature = "diagnostics")]
1105 self.window_state.record_overlay_placement_anchored_panel(
1106 self.frame_id,
1107 overlay_root_name.map(Arc::<str>::from),
1108 anchor_element,
1109 content_element,
1110 trace,
1111 );
1112 #[cfg(not(feature = "diagnostics"))]
1113 let _ = (overlay_root_name, anchor_element, content_element, trace);
1114 }
1115
1116 #[allow(clippy::too_many_arguments)]
1117 pub fn diagnostics_record_overlay_placement_placed_rect(
1118 &mut self,
1119 overlay_root_name: Option<&str>,
1120 anchor_element: Option<GlobalElementId>,
1121 content_element: Option<GlobalElementId>,
1122 outer: Rect,
1123 anchor: Rect,
1124 placed: Rect,
1125 side: Option<Side>,
1126 ) {
1127 #[cfg(feature = "diagnostics")]
1128 self.window_state.record_overlay_placement_placed_rect(
1129 self.frame_id,
1130 overlay_root_name.map(Arc::<str>::from),
1131 anchor_element,
1132 content_element,
1133 outer,
1134 anchor,
1135 placed,
1136 side,
1137 );
1138 #[cfg(not(feature = "diagnostics"))]
1139 let _ = (
1140 overlay_root_name,
1141 anchor_element,
1142 content_element,
1143 outer,
1144 anchor,
1145 placed,
1146 side,
1147 );
1148 }
1149
1150 pub fn theme(&mut self) -> &Theme {
1151 self.observe_global::<Theme>(Invalidation::Layout);
1152 Theme::global(&*self.app)
1153 }
1154
1155 #[track_caller]
1156 pub fn for_each_keyed<T, K: Hash>(
1157 &mut self,
1158 items: &[T],
1159 mut key: impl FnMut(&T) -> K,
1160 mut f: impl FnMut(&mut Self, usize, &T),
1161 ) {
1162 let loc = Location::caller();
1163 self.scope(|cx| {
1164 let mut first_dup: Option<(u64, usize, usize)> = None;
1165 let mut seen: HashMap<u64, usize> = HashMap::new();
1166 for (index, item) in items.iter().enumerate() {
1167 let k = key(item);
1168 let key_hash = stable_hash(&k);
1169 if first_dup.is_none()
1170 && let Some(prev) = seen.insert(key_hash, index)
1171 {
1172 first_dup = Some((key_hash, prev, index));
1173 }
1174 cx.keyed(k, |cx| f(cx, index, item));
1175 }
1176
1177 if let Some((key_hash, a, b)) = first_dup
1178 && cfg!(debug_assertions)
1179 && items.len() > 1
1180 {
1181 let element_path: Option<String> = {
1182 #[cfg(feature = "diagnostics")]
1183 {
1184 cx.window_state.debug_path_for_element(cx.root_id())
1185 }
1186 #[cfg(not(feature = "diagnostics"))]
1187 {
1188 None
1189 }
1190 };
1191
1192 tracing::warn!(
1193 file = loc.file(),
1194 line = loc.line(),
1195 column = loc.column(),
1196 key_hash = format_args!("{key_hash:#x}"),
1197 first_index = a,
1198 second_index = b,
1199 element_path = element_path.as_deref().unwrap_or("<unknown>"),
1200 "duplicate keyed list item key hash; element state may collide"
1201 );
1202 }
1203 });
1204 }
1205
1206 #[track_caller]
1207 pub fn for_each_unkeyed<T: Hash>(
1208 &mut self,
1209 items: &[T],
1210 mut f: impl FnMut(&mut Self, usize, &T),
1211 ) {
1212 let loc = Location::caller();
1213 let list_id = callsite_hash(loc);
1214 let fingerprints: Vec<u64> = items.iter().map(stable_hash).collect();
1215 self.window_state
1216 .cur_unkeyed_fingerprints
1217 .insert(list_id, fingerprints.clone());
1218
1219 if let Some(prev) = self.window_state.prev_unkeyed_fingerprints.get(&list_id)
1220 && prev != &fingerprints
1221 && items.len() > 1
1222 && cfg!(debug_assertions)
1223 {
1224 let element_path: Option<String> = {
1225 #[cfg(feature = "diagnostics")]
1226 {
1227 self.window_state.debug_path_for_element(self.root_id())
1228 }
1229 #[cfg(not(feature = "diagnostics"))]
1230 {
1231 None
1232 }
1233 };
1234 tracing::warn!(
1235 list_id = format_args!("{list_id:#x}"),
1236 file = loc.file(),
1237 line = loc.line(),
1238 column = loc.column(),
1239 element_path = element_path.as_deref().unwrap_or("<unknown>"),
1240 "unkeyed element list order changed; add explicit keys to preserve state"
1241 );
1242 }
1243
1244 self.scope(|cx| {
1245 for (index, item) in items.iter().enumerate() {
1246 let index_key = index as u64;
1247 cx.enter_with_callsite(loc, list_id, Some(index_key), None, |cx| {
1248 f(cx, index, item)
1249 });
1250 }
1251 });
1252 }
1253
1254 fn enter_with_callsite<R>(
1255 &mut self,
1256 _loc: &'static Location<'static>,
1257 callsite: u64,
1258 key_hash: Option<u64>,
1259 _debug_name: Option<&str>,
1260 f: impl FnOnce(&mut Self) -> R,
1261 ) -> R {
1262 let parent = self.root_id();
1263 let counters = self
1264 .callsite_counters
1265 .last_mut()
1266 .expect("callsite counters exist");
1267 let slot = bump_callsite_counter(counters, callsite);
1268
1269 let child_salt = key_hash.unwrap_or(slot);
1270 let id = derive_child_id(parent, callsite, child_salt);
1271 self.window_state.mark_authoring_identity_seen(id);
1272
1273 #[cfg(feature = "diagnostics")]
1274 self.window_state.record_debug_child(
1275 self.frame_id,
1276 parent,
1277 id,
1278 _loc.file(),
1279 _loc.line(),
1280 _loc.column(),
1281 key_hash,
1282 _debug_name,
1283 slot,
1284 );
1285
1286 self.stack.push(id);
1287 self.callsite_counters.push(CallsiteCounters::new());
1288 let out = f(self);
1289 self.callsite_counters.pop();
1290 self.stack.pop();
1291 out
1292 }
1293
1294 fn callsite_state_slot_id(
1295 &mut self,
1296 loc: &'static Location<'static>,
1297 key_hash: Option<u64>,
1298 ) -> GlobalElementId {
1299 let parent = self.root_id();
1300 let callsite = callsite_hash(loc);
1301 let counters = self
1302 .callsite_counters
1303 .last_mut()
1304 .expect("callsite counters exist");
1305 let slot = bump_callsite_counter(counters, callsite);
1306 let child_salt = key_hash.unwrap_or(slot);
1307 derive_child_id(parent, callsite, child_salt)
1308 }
1309
1310 #[track_caller]
1311 pub fn container<I>(
1312 &mut self,
1313 props: ContainerProps,
1314 f: impl FnOnce(&mut Self) -> I,
1315 ) -> AnyElement
1316 where
1317 I: IntoIterator<Item = AnyElement>,
1318 {
1319 self.scope(|cx| {
1320 let id = cx.root_id();
1321 let built = f(cx);
1322 let children = cx.collect_children(built);
1323 cx.new_any_element(id, ElementKind::Container(props), children)
1324 })
1325 }
1326
1327 #[track_caller]
1337 pub fn semantics<I>(
1338 &mut self,
1339 props: crate::element::SemanticsProps,
1340 f: impl FnOnce(&mut Self) -> I,
1341 ) -> AnyElement
1342 where
1343 I: IntoIterator<Item = AnyElement>,
1344 {
1345 self.scope(|cx| {
1346 let id = cx.root_id();
1347 let built = f(cx);
1348 let children = cx.collect_children(built);
1349 cx.new_any_element(id, ElementKind::Semantics(props), children)
1350 })
1351 }
1352
1353 #[track_caller]
1354 pub fn semantic_flex<I>(
1355 &mut self,
1356 props: crate::element::SemanticFlexProps,
1357 f: impl FnOnce(&mut Self) -> I,
1358 ) -> AnyElement
1359 where
1360 I: IntoIterator<Item = AnyElement>,
1361 {
1362 self.scope(|cx| {
1363 let id = cx.root_id();
1364 let built = f(cx);
1365 let children = cx.collect_children(built);
1366 cx.new_any_element(id, ElementKind::SemanticFlex(props), children)
1367 })
1368 }
1369
1370 #[track_caller]
1371 pub fn focus_scope<I>(
1372 &mut self,
1373 props: crate::element::FocusScopeProps,
1374 f: impl FnOnce(&mut Self) -> I,
1375 ) -> AnyElement
1376 where
1377 I: IntoIterator<Item = AnyElement>,
1378 {
1379 self.scope(|cx| {
1380 let id = cx.root_id();
1381 let built = f(cx);
1382 let children = cx.collect_children(built);
1383 cx.new_any_element(id, ElementKind::FocusScope(props), children)
1384 })
1385 }
1386
1387 #[track_caller]
1388 pub fn view_cache<I>(
1389 &mut self,
1390 props: crate::element::ViewCacheProps,
1391 f: impl FnOnce(&mut Self) -> I,
1392 ) -> AnyElement
1393 where
1394 I: IntoIterator<Item = AnyElement>,
1395 {
1396 self.scope(|cx| {
1397 let id = cx.root_id();
1398 let should_reuse = cx
1399 .window_state
1400 .node_entry(id)
1401 .map(|e| e.node)
1402 .and_then(|node| cx.view_cache_should_reuse.as_mut().map(|f| f(node)))
1403 .unwrap_or(false);
1404
1405 let theme_revision = Theme::global(&*cx.app).revision();
1406 let scale_factor = cx
1407 .app
1408 .global::<WindowMetricsService>()
1409 .and_then(|svc| svc.scale_factor(cx.window))
1410 .unwrap_or(1.0);
1411
1412 let scale_bits = scale_factor.to_bits();
1419 let deps_key_rendered = if should_reuse {
1420 (
1421 cx.window_state.environment_deps_fingerprint_rendered(id),
1422 cx.window_state.layout_query_deps_fingerprint_rendered(id),
1423 )
1424 } else {
1425 (0, 0)
1426 };
1427 let key = stable_hash(&(
1428 theme_revision,
1429 scale_bits,
1430 props.cache_key,
1431 deps_key_rendered.0,
1432 deps_key_rendered.1,
1433 ));
1434
1435 let key_matches = if should_reuse {
1436 let matches = cx.window_state.view_cache_key_matches_and_touch(id, key);
1437 if !matches {
1438 cx.window_state.record_view_cache_key_mismatch(id);
1439 }
1440 matches
1441 } else {
1442 false
1443 };
1444
1445 let reuse = should_reuse && key_matches;
1446
1447 let children: Vec<AnyElement> = if reuse {
1448 cx.window_state.mark_view_cache_reuse_root(id);
1449 cx.window_state.touch_view_cache_state_keys_if_recorded(id);
1450 cx.window_state
1451 .touch_observed_models_for_element_if_recorded(id);
1452 cx.window_state
1453 .touch_observed_globals_for_element_if_recorded(id);
1454 cx.window_state
1455 .touch_observed_environment_for_element_if_recorded(id);
1456 cx.window_state
1457 .touch_observed_layout_queries_for_element_if_recorded(id);
1458 Vec::new()
1459 } else {
1460 cx.window_state.begin_view_cache_scope(id);
1461 let built = f(cx);
1462 let children = cx.collect_children(built);
1463 cx.window_state.end_view_cache_scope(id);
1464
1465 let deps_key_next = (
1466 cx.window_state.environment_deps_fingerprint_next(id),
1467 cx.window_state.layout_query_deps_fingerprint_next(id),
1468 );
1469 let key = stable_hash(&(
1470 theme_revision,
1471 scale_bits,
1472 props.cache_key,
1473 deps_key_next.0,
1474 deps_key_next.1,
1475 ));
1476 cx.window_state.set_view_cache_key(id, key);
1477 children
1478 };
1479 cx.new_any_element(id, ElementKind::ViewCache(props), children)
1480 })
1481 }
1482
1483 #[track_caller]
1492 pub fn view_cache_keep_alive<I>(
1493 &mut self,
1494 props: crate::element::ViewCacheProps,
1495 keep_alive: bool,
1496 f: impl FnOnce(&mut Self) -> I,
1497 ) -> AnyElement
1498 where
1499 I: IntoIterator<Item = AnyElement>,
1500 {
1501 self.scope(|cx| {
1502 let id = cx.root_id();
1503
1504 let theme_revision = Theme::global(&*cx.app).revision();
1505 let scale_factor = cx
1506 .app
1507 .global::<WindowMetricsService>()
1508 .and_then(|svc| svc.scale_factor(cx.window))
1509 .unwrap_or(1.0);
1510 let scale_bits = scale_factor.to_bits();
1511
1512 if keep_alive {
1513 cx.window_state.mark_view_cache_reuse_root(id);
1514 cx.window_state.touch_view_cache_state_keys_if_recorded(id);
1515 cx.window_state
1516 .touch_observed_models_for_element_if_recorded(id);
1517 cx.window_state
1518 .touch_observed_globals_for_element_if_recorded(id);
1519 cx.window_state
1520 .touch_observed_environment_for_element_if_recorded(id);
1521 cx.window_state
1522 .touch_observed_layout_queries_for_element_if_recorded(id);
1523
1524 let _ = (theme_revision, scale_bits);
1527 return cx.new_any_element(id, ElementKind::ViewCache(props), Vec::new());
1528 }
1529
1530 cx.window_state.begin_view_cache_scope(id);
1531 let built = f(cx);
1532 let children = cx.collect_children(built);
1533 cx.window_state.end_view_cache_scope(id);
1534
1535 let deps_key_next = (
1536 cx.window_state.environment_deps_fingerprint_next(id),
1537 cx.window_state.layout_query_deps_fingerprint_next(id),
1538 );
1539 let key = stable_hash(&(
1540 theme_revision,
1541 scale_bits,
1542 props.cache_key,
1543 deps_key_next.0,
1544 deps_key_next.1,
1545 ));
1546 cx.window_state.set_view_cache_key(id, key);
1547
1548 cx.new_any_element(id, ElementKind::ViewCache(props), children)
1549 })
1550 }
1551
1552 #[track_caller]
1553 pub fn focus_scope_with_id<I>(
1554 &mut self,
1555 props: crate::element::FocusScopeProps,
1556 f: impl FnOnce(&mut Self, GlobalElementId) -> I,
1557 ) -> AnyElement
1558 where
1559 I: IntoIterator<Item = AnyElement>,
1560 {
1561 self.scope(|cx| {
1562 let id = cx.root_id();
1563 let built = f(cx, id);
1564 let children = cx.collect_children(built);
1565 cx.new_any_element(id, ElementKind::FocusScope(props), children)
1566 })
1567 }
1568
1569 #[track_caller]
1570 pub fn layout_query_region_with_id<I>(
1571 &mut self,
1572 props: LayoutQueryRegionProps,
1573 f: impl FnOnce(&mut Self, GlobalElementId) -> I,
1574 ) -> AnyElement
1575 where
1576 I: IntoIterator<Item = AnyElement>,
1577 {
1578 self.scope(|cx| {
1579 let id = cx.root_id();
1580 let name = props.name.clone();
1581 cx.state_for(id, LayoutQueryRegionMarker::default, |marker| {
1582 marker.name = name.clone();
1583 });
1584 let built = f(cx, id);
1585 let children = cx.collect_children(built);
1586 cx.new_any_element(id, ElementKind::LayoutQueryRegion(props), children)
1587 })
1588 }
1589
1590 #[track_caller]
1591 pub fn layout_query_region<I>(
1592 &mut self,
1593 props: LayoutQueryRegionProps,
1594 f: impl FnOnce(&mut Self) -> I,
1595 ) -> AnyElement
1596 where
1597 I: IntoIterator<Item = AnyElement>,
1598 {
1599 self.layout_query_region_with_id(props, |cx, _id| f(cx))
1600 }
1601
1602 #[track_caller]
1607 pub fn semantics_with_id<I>(
1608 &mut self,
1609 props: crate::element::SemanticsProps,
1610 f: impl FnOnce(&mut Self, GlobalElementId) -> I,
1611 ) -> AnyElement
1612 where
1613 I: IntoIterator<Item = AnyElement>,
1614 {
1615 self.scope(|cx| {
1616 let id = cx.root_id();
1617 let built = f(cx, id);
1618 let children = cx.collect_children(built);
1619 cx.new_any_element(id, ElementKind::Semantics(props), children)
1620 })
1621 }
1622
1623 #[track_caller]
1624 pub fn opacity<I>(&mut self, opacity: f32, f: impl FnOnce(&mut Self) -> I) -> AnyElement
1625 where
1626 I: IntoIterator<Item = AnyElement>,
1627 {
1628 let props = OpacityProps {
1629 opacity: opacity.clamp(0.0, 1.0),
1630 ..Default::default()
1631 };
1632 self.opacity_props(props, f)
1633 }
1634
1635 #[track_caller]
1636 pub fn opacity_props<I>(
1637 &mut self,
1638 props: OpacityProps,
1639 f: impl FnOnce(&mut Self) -> I,
1640 ) -> AnyElement
1641 where
1642 I: IntoIterator<Item = AnyElement>,
1643 {
1644 self.scope(|cx| {
1645 let id = cx.root_id();
1646 let built = f(cx);
1647 let children = cx.collect_children(built);
1648 cx.new_any_element(id, ElementKind::Opacity(props), children)
1649 })
1650 }
1651
1652 #[track_caller]
1653 pub fn foreground_scope<I>(
1654 &mut self,
1655 foreground: fret_core::Color,
1656 f: impl FnOnce(&mut Self) -> I,
1657 ) -> AnyElement
1658 where
1659 I: IntoIterator<Item = AnyElement>,
1660 {
1661 self.foreground_scope_props(
1662 ForegroundScopeProps {
1663 foreground: Some(foreground),
1664 ..Default::default()
1665 },
1666 f,
1667 )
1668 }
1669
1670 #[track_caller]
1671 pub fn foreground_scope_props<I>(
1672 &mut self,
1673 props: ForegroundScopeProps,
1674 f: impl FnOnce(&mut Self) -> I,
1675 ) -> AnyElement
1676 where
1677 I: IntoIterator<Item = AnyElement>,
1678 {
1679 self.scope(|cx| {
1680 let id = cx.root_id();
1681 let built = f(cx);
1682 let children = cx.collect_children(built);
1683 cx.new_any_element(id, ElementKind::ForegroundScope(props), children)
1684 })
1685 }
1686
1687 #[track_caller]
1688 pub fn effect_layer<I>(
1689 &mut self,
1690 mode: EffectMode,
1691 chain: EffectChain,
1692 f: impl FnOnce(&mut Self) -> I,
1693 ) -> AnyElement
1694 where
1695 I: IntoIterator<Item = AnyElement>,
1696 {
1697 self.effect_layer_props(
1698 EffectLayerProps {
1699 mode,
1700 chain,
1701 ..Default::default()
1702 },
1703 f,
1704 )
1705 }
1706
1707 #[track_caller]
1708 pub fn effect_layer_props<I>(
1709 &mut self,
1710 props: EffectLayerProps,
1711 f: impl FnOnce(&mut Self) -> I,
1712 ) -> AnyElement
1713 where
1714 I: IntoIterator<Item = AnyElement>,
1715 {
1716 self.scope(|cx| {
1717 let id = cx.root_id();
1718 let built = f(cx);
1719 let children = cx.collect_children(built);
1720 cx.new_any_element(id, ElementKind::EffectLayer(props), children)
1721 })
1722 }
1723
1724 #[track_caller]
1725 pub fn backdrop_source_group_v1<I>(
1726 &mut self,
1727 pyramid: Option<fret_core::scene::CustomEffectPyramidRequestV1>,
1728 quality: EffectQuality,
1729 f: impl FnOnce(&mut Self) -> I,
1730 ) -> AnyElement
1731 where
1732 I: IntoIterator<Item = AnyElement>,
1733 {
1734 self.backdrop_source_group_v1_props(
1735 BackdropSourceGroupProps {
1736 pyramid,
1737 quality,
1738 ..Default::default()
1739 },
1740 f,
1741 )
1742 }
1743
1744 #[track_caller]
1745 pub fn backdrop_source_group_v1_props<I>(
1746 &mut self,
1747 props: BackdropSourceGroupProps,
1748 f: impl FnOnce(&mut Self) -> I,
1749 ) -> AnyElement
1750 where
1751 I: IntoIterator<Item = AnyElement>,
1752 {
1753 self.scope(|cx| {
1754 let id = cx.root_id();
1755 let built = f(cx);
1756 let children = cx.collect_children(built);
1757 cx.new_any_element(id, ElementKind::BackdropSourceGroup(props), children)
1758 })
1759 }
1760
1761 #[track_caller]
1762 pub fn mask_layer<I>(
1763 &mut self,
1764 mask: fret_core::scene::Mask,
1765 f: impl FnOnce(&mut Self) -> I,
1766 ) -> AnyElement
1767 where
1768 I: IntoIterator<Item = AnyElement>,
1769 {
1770 self.mask_layer_props(
1771 MaskLayerProps {
1772 layout: LayoutStyle::default(),
1773 mask,
1774 },
1775 f,
1776 )
1777 }
1778
1779 #[track_caller]
1780 pub fn mask_layer_props<I>(
1781 &mut self,
1782 props: MaskLayerProps,
1783 f: impl FnOnce(&mut Self) -> I,
1784 ) -> AnyElement
1785 where
1786 I: IntoIterator<Item = AnyElement>,
1787 {
1788 self.scope(|cx| {
1789 let id = cx.root_id();
1790 let built = f(cx);
1791 let children = cx.collect_children(built);
1792 cx.new_any_element(id, ElementKind::MaskLayer(props), children)
1793 })
1794 }
1795
1796 #[track_caller]
1797 pub fn composite_group<I>(
1798 &mut self,
1799 mode: fret_core::scene::BlendMode,
1800 f: impl FnOnce(&mut Self) -> I,
1801 ) -> AnyElement
1802 where
1803 I: IntoIterator<Item = AnyElement>,
1804 {
1805 self.composite_group_props(
1806 CompositeGroupProps {
1807 layout: LayoutStyle::default(),
1808 mode,
1809 quality: EffectQuality::Auto,
1810 },
1811 f,
1812 )
1813 }
1814
1815 #[track_caller]
1816 pub fn composite_group_props<I>(
1817 &mut self,
1818 props: CompositeGroupProps,
1819 f: impl FnOnce(&mut Self) -> I,
1820 ) -> AnyElement
1821 where
1822 I: IntoIterator<Item = AnyElement>,
1823 {
1824 self.scope(|cx| {
1825 let id = cx.root_id();
1826 let built = f(cx);
1827 let children = cx.collect_children(built);
1828 cx.new_any_element(id, ElementKind::CompositeGroup(props), children)
1829 })
1830 }
1831
1832 #[track_caller]
1833 pub fn visual_transform<I>(
1834 &mut self,
1835 transform: fret_core::Transform2D,
1836 f: impl FnOnce(&mut Self) -> I,
1837 ) -> AnyElement
1838 where
1839 I: IntoIterator<Item = AnyElement>,
1840 {
1841 self.visual_transform_props(
1842 VisualTransformProps {
1843 layout: LayoutStyle::default(),
1844 transform,
1845 },
1846 f,
1847 )
1848 }
1849
1850 #[track_caller]
1851 pub fn render_transform<I>(
1852 &mut self,
1853 transform: fret_core::Transform2D,
1854 f: impl FnOnce(&mut Self) -> I,
1855 ) -> AnyElement
1856 where
1857 I: IntoIterator<Item = AnyElement>,
1858 {
1859 self.render_transform_props(
1860 crate::element::RenderTransformProps {
1861 layout: LayoutStyle::default(),
1862 transform,
1863 },
1864 f,
1865 )
1866 }
1867
1868 #[track_caller]
1869 pub fn fractional_render_transform<I>(
1870 &mut self,
1871 translate_x_fraction: f32,
1872 translate_y_fraction: f32,
1873 f: impl FnOnce(&mut Self) -> I,
1874 ) -> AnyElement
1875 where
1876 I: IntoIterator<Item = AnyElement>,
1877 {
1878 self.fractional_render_transform_props(
1879 crate::element::FractionalRenderTransformProps {
1880 layout: LayoutStyle::default(),
1881 translate_x_fraction,
1882 translate_y_fraction,
1883 },
1884 f,
1885 )
1886 }
1887
1888 #[track_caller]
1889 pub fn visual_transform_props<I>(
1890 &mut self,
1891 props: VisualTransformProps,
1892 f: impl FnOnce(&mut Self) -> I,
1893 ) -> AnyElement
1894 where
1895 I: IntoIterator<Item = AnyElement>,
1896 {
1897 self.scope(|cx| {
1898 let id = cx.root_id();
1899 let built = f(cx);
1900 let children = cx.collect_children(built);
1901 cx.new_any_element(id, ElementKind::VisualTransform(props), children)
1902 })
1903 }
1904
1905 #[track_caller]
1906 pub fn render_transform_props<I>(
1907 &mut self,
1908 props: crate::element::RenderTransformProps,
1909 f: impl FnOnce(&mut Self) -> I,
1910 ) -> AnyElement
1911 where
1912 I: IntoIterator<Item = AnyElement>,
1913 {
1914 self.scope(|cx| {
1915 let id = cx.root_id();
1916 let built = f(cx);
1917 let children = cx.collect_children(built);
1918 cx.new_any_element(id, ElementKind::RenderTransform(props), children)
1919 })
1920 }
1921
1922 #[track_caller]
1923 pub fn fractional_render_transform_props<I>(
1924 &mut self,
1925 props: crate::element::FractionalRenderTransformProps,
1926 f: impl FnOnce(&mut Self) -> I,
1927 ) -> AnyElement
1928 where
1929 I: IntoIterator<Item = AnyElement>,
1930 {
1931 self.scope(|cx| {
1932 let id = cx.root_id();
1933 let built = f(cx);
1934 let children = cx.collect_children(built);
1935 cx.new_any_element(id, ElementKind::FractionalRenderTransform(props), children)
1936 })
1937 }
1938
1939 #[track_caller]
1940 pub fn anchored_props<I>(
1941 &mut self,
1942 props: crate::element::AnchoredProps,
1943 f: impl FnOnce(&mut Self) -> I,
1944 ) -> AnyElement
1945 where
1946 I: IntoIterator<Item = AnyElement>,
1947 {
1948 self.scope(|cx| {
1949 let id = cx.root_id();
1950 let built = f(cx);
1951 let children = cx.collect_children(built);
1952 cx.new_any_element(id, ElementKind::Anchored(props), children)
1953 })
1954 }
1955
1956 #[track_caller]
1957 pub fn interactivity_gate<I>(
1958 &mut self,
1959 present: bool,
1960 interactive: bool,
1961 f: impl FnOnce(&mut Self) -> I,
1962 ) -> AnyElement
1963 where
1964 I: IntoIterator<Item = AnyElement>,
1965 {
1966 self.interactivity_gate_props(
1967 InteractivityGateProps {
1968 present,
1969 interactive,
1970 ..Default::default()
1971 },
1972 f,
1973 )
1974 }
1975
1976 #[track_caller]
1977 pub fn interactivity_gate_props<I>(
1978 &mut self,
1979 props: InteractivityGateProps,
1980 f: impl FnOnce(&mut Self) -> I,
1981 ) -> AnyElement
1982 where
1983 I: IntoIterator<Item = AnyElement>,
1984 {
1985 self.scope(|cx| {
1986 let id = cx.root_id();
1987 let built = f(cx);
1988 let children = cx.collect_children(built);
1989 cx.new_any_element(id, ElementKind::InteractivityGate(props), children)
1990 })
1991 }
1992
1993 #[track_caller]
1994 pub fn hit_test_gate<I>(&mut self, hit_test: bool, f: impl FnOnce(&mut Self) -> I) -> AnyElement
1995 where
1996 I: IntoIterator<Item = AnyElement>,
1997 {
1998 self.hit_test_gate_props(
1999 HitTestGateProps {
2000 hit_test,
2001 ..Default::default()
2002 },
2003 f,
2004 )
2005 }
2006
2007 #[track_caller]
2008 pub fn hit_test_gate_props<I>(
2009 &mut self,
2010 props: HitTestGateProps,
2011 f: impl FnOnce(&mut Self) -> I,
2012 ) -> AnyElement
2013 where
2014 I: IntoIterator<Item = AnyElement>,
2015 {
2016 self.scope(|cx| {
2017 let id = cx.root_id();
2018 let built = f(cx);
2019 let children = cx.collect_children(built);
2020 cx.new_any_element(id, ElementKind::HitTestGate(props), children)
2021 })
2022 }
2023
2024 #[track_caller]
2025 pub fn focus_traversal_gate<I>(
2026 &mut self,
2027 traverse: bool,
2028 f: impl FnOnce(&mut Self) -> I,
2029 ) -> AnyElement
2030 where
2031 I: IntoIterator<Item = AnyElement>,
2032 {
2033 self.focus_traversal_gate_props(
2034 FocusTraversalGateProps {
2035 traverse,
2036 ..Default::default()
2037 },
2038 f,
2039 )
2040 }
2041
2042 #[track_caller]
2043 pub fn focus_traversal_gate_props<I>(
2044 &mut self,
2045 props: FocusTraversalGateProps,
2046 f: impl FnOnce(&mut Self) -> I,
2047 ) -> AnyElement
2048 where
2049 I: IntoIterator<Item = AnyElement>,
2050 {
2051 self.scope(|cx| {
2052 let id = cx.root_id();
2053 let built = f(cx);
2054 let children = cx.collect_children(built);
2055 cx.new_any_element(id, ElementKind::FocusTraversalGate(props), children)
2056 })
2057 }
2058
2059 #[track_caller]
2060 pub fn pressable<I>(
2061 &mut self,
2062 props: PressableProps,
2063 f: impl FnOnce(&mut Self, PressableState) -> I,
2064 ) -> AnyElement
2065 where
2066 I: IntoIterator<Item = AnyElement>,
2067 {
2068 self.scope(|cx| {
2069 let id = cx.root_id();
2070 let hovered = cx.window_state.hovered_pressable == Some(id);
2071 let hovered_raw = cx.window_state.hovered_pressable_raw == Some(id);
2072 let hovered_raw_below_barrier =
2073 cx.window_state.hovered_pressable_raw_below_barrier == Some(id);
2074 let pressed = cx.window_state.pressed_pressable == Some(id);
2075 let focused = cx.window_state.focused_element == Some(id);
2076 cx.pressable_clear_on_activate();
2077 cx.pressable_clear_on_clipboard_write_completed();
2078 cx.pressable_clear_on_hover_change();
2079 let built = f(
2080 cx,
2081 PressableState {
2082 hovered,
2083 hovered_raw,
2084 hovered_raw_below_barrier,
2085 pressed,
2086 focused,
2087 },
2088 );
2089 let children = cx.collect_children(built);
2090 cx.new_any_element(id, ElementKind::Pressable(props), children)
2091 })
2092 }
2093
2094 #[track_caller]
2095 pub fn pressable_with_id<I>(
2096 &mut self,
2097 props: PressableProps,
2098 f: impl FnOnce(&mut Self, PressableState, GlobalElementId) -> I,
2099 ) -> AnyElement
2100 where
2101 I: IntoIterator<Item = AnyElement>,
2102 {
2103 self.scope(|cx| {
2104 let id = cx.root_id();
2105 let hovered = cx.window_state.hovered_pressable == Some(id);
2106 let hovered_raw = cx.window_state.hovered_pressable_raw == Some(id);
2107 let hovered_raw_below_barrier =
2108 cx.window_state.hovered_pressable_raw_below_barrier == Some(id);
2109 let pressed = cx.window_state.pressed_pressable == Some(id);
2110 let focused = cx.window_state.focused_element == Some(id);
2111 cx.pressable_clear_on_activate();
2112 cx.pressable_clear_on_clipboard_write_completed();
2113 cx.pressable_clear_on_hover_change();
2114 let built = f(
2115 cx,
2116 PressableState {
2117 hovered,
2118 hovered_raw,
2119 hovered_raw_below_barrier,
2120 pressed,
2121 focused,
2122 },
2123 id,
2124 );
2125 let children = cx.collect_children(built);
2126 cx.new_any_element(id, ElementKind::Pressable(props), children)
2127 })
2128 }
2129
2130 #[track_caller]
2131 pub fn pressable_with_id_props<I>(
2132 &mut self,
2133 f: impl FnOnce(&mut Self, PressableState, GlobalElementId) -> (PressableProps, I),
2134 ) -> AnyElement
2135 where
2136 I: IntoIterator<Item = AnyElement>,
2137 {
2138 self.scope(|cx| {
2139 let id = cx.root_id();
2140 let hovered = cx.window_state.hovered_pressable == Some(id);
2141 let hovered_raw = cx.window_state.hovered_pressable_raw == Some(id);
2142 let hovered_raw_below_barrier =
2143 cx.window_state.hovered_pressable_raw_below_barrier == Some(id);
2144 let pressed = cx.window_state.pressed_pressable == Some(id);
2145 let focused = cx.window_state.focused_element == Some(id);
2146 cx.pressable_clear_on_activate();
2147 cx.pressable_clear_on_clipboard_write_completed();
2148 cx.pressable_clear_on_pointer_down();
2149 cx.pressable_clear_on_hover_change();
2150 let (props, children) = f(
2151 cx,
2152 PressableState {
2153 hovered,
2154 hovered_raw,
2155 hovered_raw_below_barrier,
2156 pressed,
2157 focused,
2158 },
2159 id,
2160 );
2161 let children = cx.collect_children(children);
2162 cx.new_any_element(id, ElementKind::Pressable(props), children)
2163 })
2164 }
2165
2166 pub fn pressable_on_activate(&mut self, handler: OnActivate) {
2171 self.root_state(PressableActionHooks::default, |hooks| {
2172 hooks.on_activate = Some(handler);
2173 });
2174 }
2175
2176 pub fn pressable_on_activate_for(&mut self, element: GlobalElementId, handler: OnActivate) {
2177 self.state_for(element, PressableActionHooks::default, |hooks| {
2178 hooks.on_activate = Some(handler);
2179 });
2180 }
2181
2182 pub fn pressable_add_on_activate(&mut self, handler: OnActivate) {
2183 self.root_state(PressableActionHooks::default, |hooks| {
2184 hooks.on_activate = match hooks.on_activate.clone() {
2185 None => Some(handler),
2186 Some(prev) => {
2187 let next = handler.clone();
2188 Some(Arc::new(move |host, cx, reason| {
2189 prev(host, cx, reason);
2190 next(host, cx, reason);
2191 }))
2192 }
2193 };
2194 });
2195 }
2196
2197 pub fn pressable_add_on_activate_for(&mut self, element: GlobalElementId, handler: OnActivate) {
2198 self.state_for(element, PressableActionHooks::default, |hooks| {
2199 hooks.on_activate = match hooks.on_activate.clone() {
2200 None => Some(handler),
2201 Some(prev) => {
2202 let next = handler.clone();
2203 Some(Arc::new(move |host, cx, reason| {
2204 prev(host, cx, reason);
2205 next(host, cx, reason);
2206 }))
2207 }
2208 };
2209 });
2210 }
2211
2212 pub fn pressable_clear_on_activate(&mut self) {
2213 self.root_state(PressableActionHooks::default, |hooks| {
2214 hooks.on_activate = None;
2215 });
2216 }
2217
2218 pub fn selectable_text_on_activate_span(&mut self, handler: OnSelectableTextActivateSpan) {
2224 self.root_state(SelectableTextActionHooks::default, |hooks| {
2225 hooks.on_activate_span = Some(handler);
2226 });
2227 }
2228
2229 pub fn selectable_text_on_activate_span_for(
2230 &mut self,
2231 element: GlobalElementId,
2232 handler: OnSelectableTextActivateSpan,
2233 ) {
2234 self.state_for(element, SelectableTextActionHooks::default, |hooks| {
2235 hooks.on_activate_span = Some(handler);
2236 });
2237 }
2238
2239 pub fn selectable_text_clear_on_activate_span(&mut self) {
2240 self.root_state(SelectableTextActionHooks::default, |hooks| {
2241 hooks.on_activate_span = None;
2242 });
2243 }
2244
2245 pub fn selectable_text_clear_on_activate_span_for(&mut self, element: GlobalElementId) {
2246 self.state_for(element, SelectableTextActionHooks::default, |hooks| {
2247 hooks.on_activate_span = None;
2248 });
2249 }
2250
2251 pub fn pressable_on_pointer_down(&mut self, handler: OnPressablePointerDown) {
2256 self.root_state(PressableActionHooks::default, |hooks| {
2257 hooks.on_pointer_down = Some(handler);
2258 });
2259 }
2260
2261 pub fn pressable_on_pointer_move(&mut self, handler: OnPressablePointerMove) {
2262 self.root_state(PressableActionHooks::default, |hooks| {
2263 hooks.on_pointer_move = Some(handler);
2264 });
2265 }
2266
2267 pub fn pressable_on_pointer_up(&mut self, handler: OnPressablePointerUp) {
2268 self.root_state(PressableActionHooks::default, |hooks| {
2269 hooks.on_pointer_up = Some(handler);
2270 });
2271 }
2272
2273 pub fn pressable_on_clipboard_write_completed(
2274 &mut self,
2275 handler: crate::action::OnPressableClipboardWriteCompleted,
2276 ) {
2277 self.root_state(PressableActionHooks::default, |hooks| {
2278 hooks.on_clipboard_write_completed = Some(handler);
2279 });
2280 }
2281
2282 pub fn pressable_on_pointer_down_for(
2283 &mut self,
2284 element: GlobalElementId,
2285 handler: OnPressablePointerDown,
2286 ) {
2287 self.state_for(element, PressableActionHooks::default, |hooks| {
2288 hooks.on_pointer_down = Some(handler);
2289 });
2290 }
2291
2292 pub fn pressable_on_pointer_move_for(
2293 &mut self,
2294 element: GlobalElementId,
2295 handler: OnPressablePointerMove,
2296 ) {
2297 self.state_for(element, PressableActionHooks::default, |hooks| {
2298 hooks.on_pointer_move = Some(handler);
2299 });
2300 }
2301
2302 pub fn pressable_on_pointer_up_for(
2303 &mut self,
2304 element: GlobalElementId,
2305 handler: OnPressablePointerUp,
2306 ) {
2307 self.state_for(element, PressableActionHooks::default, |hooks| {
2308 hooks.on_pointer_up = Some(handler);
2309 });
2310 }
2311
2312 pub fn pressable_on_clipboard_write_completed_for(
2313 &mut self,
2314 element: GlobalElementId,
2315 handler: crate::action::OnPressableClipboardWriteCompleted,
2316 ) {
2317 self.state_for(element, PressableActionHooks::default, |hooks| {
2318 hooks.on_clipboard_write_completed = Some(handler);
2319 });
2320 }
2321
2322 pub fn pressable_add_on_pointer_down(&mut self, handler: OnPressablePointerDown) {
2323 self.root_state(PressableActionHooks::default, |hooks| {
2324 hooks.on_pointer_down = match hooks.on_pointer_down.clone() {
2325 None => Some(handler),
2326 Some(prev) => {
2327 let next = handler.clone();
2328 Some(Arc::new(move |host, cx, down| {
2329 let prev_result = prev(host, cx, down);
2330 let next_result = next(host, cx, down);
2331 use crate::action::PressablePointerDownResult as R;
2332 match (prev_result, next_result) {
2333 (R::SkipDefaultAndStopPropagation, _)
2334 | (_, R::SkipDefaultAndStopPropagation) => {
2335 R::SkipDefaultAndStopPropagation
2336 }
2337 (R::SkipDefault, _) | (_, R::SkipDefault) => R::SkipDefault,
2338 _ => R::Continue,
2339 }
2340 }))
2341 }
2342 };
2343 });
2344 }
2345
2346 pub fn pressable_add_on_pointer_move(&mut self, handler: OnPressablePointerMove) {
2347 self.root_state(PressableActionHooks::default, |hooks| {
2348 hooks.on_pointer_move = match hooks.on_pointer_move.clone() {
2349 None => Some(handler),
2350 Some(prev) => {
2351 let next = handler.clone();
2352 Some(Arc::new(move |host, cx, mv| {
2353 let prev_handled = prev(host, cx, mv);
2354 let next_handled = next(host, cx, mv);
2355 prev_handled || next_handled
2356 }))
2357 }
2358 };
2359 });
2360 }
2361
2362 pub fn pressable_add_on_pointer_up(&mut self, handler: OnPressablePointerUp) {
2363 self.root_state(PressableActionHooks::default, |hooks| {
2364 hooks.on_pointer_up = match hooks.on_pointer_up.clone() {
2365 None => Some(handler),
2366 Some(prev) => {
2367 let next = handler.clone();
2368 Some(Arc::new(move |host, cx, up| {
2369 let prev_result = prev(host, cx, up);
2370 let next_result = next(host, cx, up);
2371 match (prev_result, next_result) {
2372 (PressablePointerUpResult::SkipActivate, _)
2373 | (_, PressablePointerUpResult::SkipActivate) => {
2374 PressablePointerUpResult::SkipActivate
2375 }
2376 _ => PressablePointerUpResult::Continue,
2377 }
2378 }))
2379 }
2380 };
2381 });
2382 }
2383
2384 pub fn pressable_add_on_pointer_down_for(
2385 &mut self,
2386 element: GlobalElementId,
2387 handler: OnPressablePointerDown,
2388 ) {
2389 self.state_for(element, PressableActionHooks::default, |hooks| {
2390 hooks.on_pointer_down = match hooks.on_pointer_down.clone() {
2391 None => Some(handler),
2392 Some(prev) => {
2393 let next = handler.clone();
2394 Some(Arc::new(move |host, cx, down| {
2395 let prev_result = prev(host, cx, down);
2396 let next_result = next(host, cx, down);
2397 use crate::action::PressablePointerDownResult as R;
2398 match (prev_result, next_result) {
2399 (R::SkipDefaultAndStopPropagation, _)
2400 | (_, R::SkipDefaultAndStopPropagation) => {
2401 R::SkipDefaultAndStopPropagation
2402 }
2403 (R::SkipDefault, _) | (_, R::SkipDefault) => R::SkipDefault,
2404 _ => R::Continue,
2405 }
2406 }))
2407 }
2408 };
2409 });
2410 }
2411
2412 pub fn pressable_add_on_pointer_move_for(
2413 &mut self,
2414 element: GlobalElementId,
2415 handler: OnPressablePointerMove,
2416 ) {
2417 self.state_for(element, PressableActionHooks::default, |hooks| {
2418 hooks.on_pointer_move = match hooks.on_pointer_move.clone() {
2419 None => Some(handler),
2420 Some(prev) => {
2421 let next = handler.clone();
2422 Some(Arc::new(move |host, cx, mv| {
2423 let prev_handled = prev(host, cx, mv);
2424 let next_handled = next(host, cx, mv);
2425 prev_handled || next_handled
2426 }))
2427 }
2428 };
2429 });
2430 }
2431
2432 pub fn pressable_add_on_pointer_up_for(
2433 &mut self,
2434 element: GlobalElementId,
2435 handler: OnPressablePointerUp,
2436 ) {
2437 self.state_for(element, PressableActionHooks::default, |hooks| {
2438 hooks.on_pointer_up = match hooks.on_pointer_up.clone() {
2439 None => Some(handler),
2440 Some(prev) => {
2441 let next = handler.clone();
2442 Some(Arc::new(move |host, cx, up| {
2443 let prev_result = prev(host, cx, up);
2444 let next_result = next(host, cx, up);
2445 match (prev_result, next_result) {
2446 (PressablePointerUpResult::SkipActivate, _)
2447 | (_, PressablePointerUpResult::SkipActivate) => {
2448 PressablePointerUpResult::SkipActivate
2449 }
2450 _ => PressablePointerUpResult::Continue,
2451 }
2452 }))
2453 }
2454 };
2455 });
2456 }
2457
2458 pub fn pressable_clear_on_pointer_down(&mut self) {
2459 self.root_state(PressableActionHooks::default, |hooks| {
2460 hooks.on_pointer_down = None;
2461 });
2462 }
2463
2464 pub fn pressable_clear_on_pointer_move(&mut self) {
2465 self.root_state(PressableActionHooks::default, |hooks| {
2466 hooks.on_pointer_move = None;
2467 });
2468 }
2469
2470 pub fn pressable_clear_on_pointer_up(&mut self) {
2471 self.root_state(PressableActionHooks::default, |hooks| {
2472 hooks.on_pointer_up = None;
2473 });
2474 }
2475
2476 pub fn pressable_clear_on_clipboard_write_completed(&mut self) {
2477 self.root_state(PressableActionHooks::default, |hooks| {
2478 hooks.on_clipboard_write_completed = None;
2479 });
2480 }
2481
2482 pub fn pressable_on_hover_change(&mut self, handler: OnHoverChange) {
2487 self.root_state(PressableHoverActionHooks::default, |hooks| {
2488 hooks.on_hover_change = Some(handler);
2489 });
2490 }
2491
2492 pub fn pressable_add_on_hover_change(&mut self, handler: OnHoverChange) {
2493 self.root_state(PressableHoverActionHooks::default, |hooks| {
2494 hooks.on_hover_change = match hooks.on_hover_change.clone() {
2495 None => Some(handler),
2496 Some(prev) => {
2497 let next = handler.clone();
2498 Some(Arc::new(move |host, cx, hovered| {
2499 prev(host, cx, hovered);
2500 next(host, cx, hovered);
2501 }))
2502 }
2503 };
2504 });
2505 }
2506
2507 pub fn pressable_clear_on_hover_change(&mut self) {
2508 self.root_state(PressableHoverActionHooks::default, |hooks| {
2509 hooks.on_hover_change = None;
2510 });
2511 }
2512
2513 #[track_caller]
2514 pub fn pointer_region<I>(
2515 &mut self,
2516 props: PointerRegionProps,
2517 f: impl FnOnce(&mut Self) -> I,
2518 ) -> AnyElement
2519 where
2520 I: IntoIterator<Item = AnyElement>,
2521 {
2522 self.scope(|cx| {
2523 let id = cx.root_id();
2524 cx.pointer_region_clear_on_pointer_down();
2525 cx.pointer_region_clear_on_pointer_move();
2526 cx.pointer_region_clear_on_pointer_up();
2527 cx.pointer_region_clear_on_wheel();
2528 cx.pointer_region_clear_on_pinch_gesture();
2529 let built = f(cx);
2530 let children = cx.collect_children(built);
2531 cx.new_any_element(id, ElementKind::PointerRegion(props), children)
2532 })
2533 }
2534
2535 #[track_caller]
2536 pub fn text_input_region<I>(
2537 &mut self,
2538 props: crate::element::TextInputRegionProps,
2539 f: impl FnOnce(&mut Self) -> I,
2540 ) -> AnyElement
2541 where
2542 I: IntoIterator<Item = AnyElement>,
2543 {
2544 self.scope(|cx| {
2545 let id = cx.root_id();
2546 cx.text_input_region_clear_on_text_input();
2547 cx.text_input_region_clear_on_ime();
2548 cx.text_input_region_clear_on_clipboard_read_text();
2549 cx.text_input_region_clear_on_clipboard_read_failed();
2550 cx.text_input_region_clear_on_set_selection();
2551 let built = f(cx);
2552 let children = cx.collect_children(built);
2553 cx.new_any_element(id, ElementKind::TextInputRegion(props), children)
2554 })
2555 }
2556
2557 pub fn internal_drag_region<I>(
2558 &mut self,
2559 props: crate::element::InternalDragRegionProps,
2560 f: impl FnOnce(&mut Self) -> I,
2561 ) -> AnyElement
2562 where
2563 I: IntoIterator<Item = AnyElement>,
2564 {
2565 self.scope(|cx| {
2566 let id = cx.root_id();
2567 cx.internal_drag_region_clear_on_internal_drag();
2568 let built = f(cx);
2569 let children = cx.collect_children(built);
2570 cx.new_any_element(id, ElementKind::InternalDragRegion(props), children)
2571 })
2572 }
2573
2574 pub fn internal_drag_region_on_internal_drag(
2575 &mut self,
2576 handler: crate::action::OnInternalDrag,
2577 ) {
2578 self.root_state(crate::action::InternalDragActionHooks::default, |hooks| {
2579 hooks.on_internal_drag = Some(handler);
2580 });
2581 }
2582
2583 pub fn internal_drag_region_clear_on_internal_drag(&mut self) {
2584 self.root_state(crate::action::InternalDragActionHooks::default, |hooks| {
2585 hooks.on_internal_drag = None;
2586 });
2587 }
2588
2589 pub fn external_drag_region<I>(
2590 &mut self,
2591 props: crate::element::ExternalDragRegionProps,
2592 f: impl FnOnce(&mut Self) -> I,
2593 ) -> AnyElement
2594 where
2595 I: IntoIterator<Item = AnyElement>,
2596 {
2597 self.scope(|cx| {
2598 let id = cx.root_id();
2599 cx.external_drag_region_clear_on_external_drag();
2600 let built = f(cx);
2601 let children = cx.collect_children(built);
2602 cx.new_any_element(id, ElementKind::ExternalDragRegion(props), children)
2603 })
2604 }
2605
2606 pub fn external_drag_region_on_external_drag(
2607 &mut self,
2608 handler: crate::action::OnExternalDrag,
2609 ) {
2610 self.root_state(crate::action::ExternalDragActionHooks::default, |hooks| {
2611 hooks.on_external_drag = Some(handler);
2612 });
2613 }
2614
2615 pub fn external_drag_region_clear_on_external_drag(&mut self) {
2616 self.root_state(crate::action::ExternalDragActionHooks::default, |hooks| {
2617 hooks.on_external_drag = None;
2618 });
2619 }
2620
2621 pub fn pointer_region_on_pointer_down(&mut self, handler: OnPointerDown) {
2626 self.root_state(PointerActionHooks::default, |hooks| {
2627 hooks.on_pointer_down = Some(handler);
2628 });
2629 }
2630
2631 pub fn pointer_region_add_on_pointer_down(&mut self, handler: OnPointerDown) {
2632 self.root_state(PointerActionHooks::default, |hooks| {
2633 hooks.on_pointer_down = match hooks.on_pointer_down.clone() {
2634 None => Some(handler),
2635 Some(prev) => {
2636 let next = handler.clone();
2637 Some(Arc::new(move |host, cx, down| {
2638 prev(host, cx, down) || next(host, cx, down)
2639 }))
2640 }
2641 };
2642 });
2643 }
2644
2645 pub fn pointer_region_clear_on_pointer_down(&mut self) {
2646 self.root_state(PointerActionHooks::default, |hooks| {
2647 hooks.on_pointer_down = None;
2648 });
2649 }
2650
2651 pub fn pointer_region_on_pointer_move(&mut self, handler: OnPointerMove) {
2656 self.root_state(PointerActionHooks::default, |hooks| {
2657 hooks.on_pointer_move = Some(handler);
2658 });
2659 }
2660
2661 pub fn pointer_region_add_on_pointer_move(&mut self, handler: OnPointerMove) {
2662 self.root_state(PointerActionHooks::default, |hooks| {
2663 hooks.on_pointer_move = match hooks.on_pointer_move.clone() {
2664 None => Some(handler),
2665 Some(prev) => {
2666 let next = handler.clone();
2667 Some(Arc::new(move |host, cx, mv| {
2668 prev(host, cx, mv) || next(host, cx, mv)
2669 }))
2670 }
2671 };
2672 });
2673 }
2674
2675 pub fn pointer_region_clear_on_pointer_move(&mut self) {
2676 self.root_state(PointerActionHooks::default, |hooks| {
2677 hooks.on_pointer_move = None;
2678 });
2679 }
2680
2681 pub fn pointer_region_on_pointer_up(&mut self, handler: OnPointerUp) {
2686 self.root_state(PointerActionHooks::default, |hooks| {
2687 hooks.on_pointer_up = Some(handler);
2688 });
2689 }
2690
2691 pub fn pointer_region_on_pointer_cancel(&mut self, handler: OnPointerCancel) {
2696 self.root_state(PointerActionHooks::default, |hooks| {
2697 hooks.on_pointer_cancel = Some(handler);
2698 });
2699 }
2700
2701 pub fn pointer_region_on_wheel(&mut self, handler: OnWheel) {
2702 self.root_state(PointerActionHooks::default, |hooks| {
2703 hooks.on_wheel = Some(handler);
2704 });
2705 }
2706
2707 pub fn pointer_region_on_pinch_gesture(&mut self, handler: OnPinchGesture) {
2708 self.root_state(PointerActionHooks::default, |hooks| {
2709 hooks.on_pinch_gesture = Some(handler);
2710 });
2711 }
2712
2713 pub fn pointer_region_add_on_pointer_up(&mut self, handler: OnPointerUp) {
2714 self.root_state(PointerActionHooks::default, |hooks| {
2715 hooks.on_pointer_up = match hooks.on_pointer_up.clone() {
2716 None => Some(handler),
2717 Some(prev) => {
2718 let next = handler.clone();
2719 Some(Arc::new(move |host, cx, up| {
2720 prev(host, cx, up) || next(host, cx, up)
2721 }))
2722 }
2723 };
2724 });
2725 }
2726
2727 pub fn pointer_region_add_on_wheel(&mut self, handler: OnWheel) {
2728 self.root_state(PointerActionHooks::default, |hooks| {
2729 hooks.on_wheel = match hooks.on_wheel.clone() {
2730 None => Some(handler),
2731 Some(prev) => {
2732 let next = handler.clone();
2733 Some(Arc::new(move |host, cx, wheel| {
2734 prev(host, cx, wheel) || next(host, cx, wheel)
2735 }))
2736 }
2737 };
2738 });
2739 }
2740
2741 pub fn pointer_region_add_on_pinch_gesture(&mut self, handler: OnPinchGesture) {
2742 self.root_state(PointerActionHooks::default, |hooks| {
2743 hooks.on_pinch_gesture = match hooks.on_pinch_gesture.clone() {
2744 None => Some(handler),
2745 Some(prev) => {
2746 let next = handler.clone();
2747 Some(Arc::new(move |host, cx, pinch| {
2748 prev(host, cx, pinch) || next(host, cx, pinch)
2749 }))
2750 }
2751 };
2752 });
2753 }
2754
2755 pub fn pointer_region_clear_on_pointer_up(&mut self) {
2756 self.root_state(PointerActionHooks::default, |hooks| {
2757 hooks.on_pointer_up = None;
2758 });
2759 }
2760
2761 pub fn pointer_region_clear_on_wheel(&mut self) {
2762 self.root_state(PointerActionHooks::default, |hooks| {
2763 hooks.on_wheel = None;
2764 });
2765 }
2766
2767 pub fn pointer_region_clear_on_pinch_gesture(&mut self) {
2768 self.root_state(PointerActionHooks::default, |hooks| {
2769 hooks.on_pinch_gesture = None;
2770 });
2771 }
2772
2773 pub fn text_input_region_on_text_input(
2774 &mut self,
2775 handler: crate::action::OnTextInputRegionTextInput,
2776 ) {
2777 self.root_state(
2778 crate::action::TextInputRegionActionHooks::default,
2779 |hooks| {
2780 hooks.on_text_input = Some(handler);
2781 },
2782 );
2783 }
2784
2785 pub fn text_input_region_clear_on_text_input(&mut self) {
2786 self.root_state(
2787 crate::action::TextInputRegionActionHooks::default,
2788 |hooks| {
2789 hooks.on_text_input = None;
2790 },
2791 );
2792 }
2793
2794 pub fn text_input_region_on_ime(&mut self, handler: crate::action::OnTextInputRegionIme) {
2795 self.root_state(
2796 crate::action::TextInputRegionActionHooks::default,
2797 |hooks| {
2798 hooks.on_ime = Some(handler);
2799 },
2800 );
2801 }
2802
2803 pub fn text_input_region_clear_on_ime(&mut self) {
2804 self.root_state(
2805 crate::action::TextInputRegionActionHooks::default,
2806 |hooks| {
2807 hooks.on_ime = None;
2808 },
2809 );
2810 }
2811
2812 pub fn text_input_region_on_clipboard_read_text(
2813 &mut self,
2814 handler: crate::action::OnTextInputRegionClipboardReadText,
2815 ) {
2816 self.root_state(
2817 crate::action::TextInputRegionActionHooks::default,
2818 |hooks| {
2819 hooks.on_clipboard_read_text = Some(handler);
2820 },
2821 );
2822 }
2823
2824 pub fn text_input_region_clear_on_clipboard_read_text(&mut self) {
2825 self.root_state(
2826 crate::action::TextInputRegionActionHooks::default,
2827 |hooks| {
2828 hooks.on_clipboard_read_text = None;
2829 },
2830 );
2831 }
2832
2833 pub fn text_input_region_on_clipboard_read_failed(
2834 &mut self,
2835 handler: crate::action::OnTextInputRegionClipboardReadFailed,
2836 ) {
2837 self.root_state(
2838 crate::action::TextInputRegionActionHooks::default,
2839 |hooks| {
2840 hooks.on_clipboard_read_failed = Some(handler);
2841 },
2842 );
2843 }
2844
2845 pub fn text_input_region_clear_on_clipboard_read_failed(&mut self) {
2846 self.root_state(
2847 crate::action::TextInputRegionActionHooks::default,
2848 |hooks| {
2849 hooks.on_clipboard_read_failed = None;
2850 },
2851 );
2852 }
2853
2854 pub fn text_input_region_on_set_selection(
2855 &mut self,
2856 handler: crate::action::OnTextInputRegionSetSelection,
2857 ) {
2858 self.root_state(
2859 crate::action::TextInputRegionActionHooks::default,
2860 |hooks| {
2861 hooks.on_set_selection = Some(handler);
2862 },
2863 );
2864 }
2865
2866 pub fn text_input_region_clear_on_set_selection(&mut self) {
2867 self.root_state(
2868 crate::action::TextInputRegionActionHooks::default,
2869 |hooks| {
2870 hooks.on_set_selection = None;
2871 },
2872 );
2873 }
2874
2875 pub fn text_input_region_on_platform_text_input_query(
2876 &mut self,
2877 handler: crate::action::OnTextInputRegionPlatformTextInputQuery,
2878 ) {
2879 self.root_state(
2880 crate::action::TextInputRegionActionHooks::default,
2881 |hooks| {
2882 hooks.on_platform_text_input_query = Some(handler);
2883 },
2884 );
2885 }
2886
2887 pub fn text_input_region_clear_on_platform_text_input_query(&mut self) {
2888 self.root_state(
2889 crate::action::TextInputRegionActionHooks::default,
2890 |hooks| {
2891 hooks.on_platform_text_input_query = None;
2892 },
2893 );
2894 }
2895
2896 pub fn text_input_region_on_platform_text_input_replace_text_in_range_utf16(
2897 &mut self,
2898 handler: crate::action::OnTextInputRegionPlatformTextInputReplaceTextInRangeUtf16,
2899 ) {
2900 self.root_state(
2901 crate::action::TextInputRegionActionHooks::default,
2902 |hooks| {
2903 hooks.on_platform_text_input_replace_text_in_range_utf16 = Some(handler);
2904 },
2905 );
2906 }
2907
2908 pub fn text_input_region_clear_on_platform_text_input_replace_text_in_range_utf16(&mut self) {
2909 self.root_state(
2910 crate::action::TextInputRegionActionHooks::default,
2911 |hooks| {
2912 hooks.on_platform_text_input_replace_text_in_range_utf16 = None;
2913 },
2914 );
2915 }
2916
2917 pub fn text_input_region_on_platform_text_input_replace_and_mark_text_in_range_utf16(
2918 &mut self,
2919 handler: crate::action::OnTextInputRegionPlatformTextInputReplaceAndMarkTextInRangeUtf16,
2920 ) {
2921 self.root_state(
2922 crate::action::TextInputRegionActionHooks::default,
2923 |hooks| {
2924 hooks.on_platform_text_input_replace_and_mark_text_in_range_utf16 = Some(handler);
2925 },
2926 );
2927 }
2928
2929 pub fn text_input_region_clear_on_platform_text_input_replace_and_mark_text_in_range_utf16(
2930 &mut self,
2931 ) {
2932 self.root_state(
2933 crate::action::TextInputRegionActionHooks::default,
2934 |hooks| {
2935 hooks.on_platform_text_input_replace_and_mark_text_in_range_utf16 = None;
2936 },
2937 );
2938 }
2939
2940 pub fn key_on_key_down_for(&mut self, element: GlobalElementId, handler: OnKeyDown) {
2941 self.state_for(element, KeyActionHooks::default, |hooks| {
2942 hooks.on_key_down = Some(handler);
2943 });
2944 }
2945
2946 pub fn key_on_key_down_focused_for(&mut self, element: GlobalElementId, handler: OnKeyDown) {
2947 self.state_for(element, KeyActionHooks::default, |hooks| {
2948 hooks.on_key_down_focused = Some(handler);
2949 });
2950 }
2951
2952 pub fn key_add_on_key_down_for(&mut self, element: GlobalElementId, handler: OnKeyDown) {
2953 self.state_for(element, KeyActionHooks::default, |hooks| {
2954 hooks.on_key_down = match hooks.on_key_down.clone() {
2955 None => Some(handler),
2956 Some(prev) => {
2957 let next = handler.clone();
2958 Some(Arc::new(move |host, cx, down| {
2959 prev(host, cx, down) || next(host, cx, down)
2960 }))
2961 }
2962 };
2963 });
2964 }
2965
2966 pub fn key_prepend_on_key_down_for(&mut self, element: GlobalElementId, handler: OnKeyDown) {
2967 self.state_for(element, KeyActionHooks::default, |hooks| {
2968 hooks.on_key_down = match hooks.on_key_down.clone() {
2969 None => Some(handler),
2970 Some(prev) => {
2971 let next = handler.clone();
2972 Some(Arc::new(move |host, cx, down| {
2973 next(host, cx, down) || prev(host, cx, down)
2974 }))
2975 }
2976 };
2977 });
2978 }
2979
2980 pub fn key_clear_on_key_down_for(&mut self, element: GlobalElementId) {
2981 self.state_for(element, KeyActionHooks::default, |hooks| {
2982 hooks.on_key_down = None;
2983 });
2984 }
2985
2986 pub fn key_clear_on_key_down_focused_for(&mut self, element: GlobalElementId) {
2987 self.state_for(element, KeyActionHooks::default, |hooks| {
2988 hooks.on_key_down_focused = None;
2989 });
2990 }
2991
2992 pub fn key_on_key_down_capture_for(&mut self, element: GlobalElementId, handler: OnKeyDown) {
2993 self.state_for(element, KeyActionHooks::default, |hooks| {
2994 hooks.on_key_down_capture = Some(handler);
2995 });
2996 }
2997
2998 pub fn key_add_on_key_down_capture_for(
2999 &mut self,
3000 element: GlobalElementId,
3001 handler: OnKeyDown,
3002 ) {
3003 self.state_for(element, KeyActionHooks::default, |hooks| {
3004 hooks.on_key_down_capture = match hooks.on_key_down_capture.clone() {
3005 None => Some(handler),
3006 Some(prev) => {
3007 let next = handler.clone();
3008 Some(Arc::new(move |host, cx, down| {
3009 prev(host, cx, down) || next(host, cx, down)
3010 }))
3011 }
3012 };
3013 });
3014 }
3015
3016 pub fn key_prepend_on_key_down_capture_for(
3017 &mut self,
3018 element: GlobalElementId,
3019 handler: OnKeyDown,
3020 ) {
3021 self.state_for(element, KeyActionHooks::default, |hooks| {
3022 hooks.on_key_down_capture = match hooks.on_key_down_capture.clone() {
3023 None => Some(handler),
3024 Some(prev) => {
3025 let next = handler.clone();
3026 Some(Arc::new(move |host, cx, down| {
3027 next(host, cx, down) || prev(host, cx, down)
3028 }))
3029 }
3030 };
3031 });
3032 }
3033
3034 pub fn key_clear_on_key_down_capture_for(&mut self, element: GlobalElementId) {
3035 self.state_for(element, KeyActionHooks::default, |hooks| {
3036 hooks.on_key_down_capture = None;
3037 });
3038 }
3039
3040 pub fn command_on_command_for(&mut self, element: GlobalElementId, handler: OnCommand) {
3041 self.state_for(element, CommandActionHooks::default, |hooks| {
3042 hooks.on_command = Some(handler);
3043 });
3044 }
3045
3046 pub fn action_on_command_for_owner<Owner: Any>(
3047 &mut self,
3048 element: GlobalElementId,
3049 handler: OnCommand,
3050 ) {
3051 let owner = TypeId::of::<Owner>();
3052 self.state_for(element, ActionRouteHooks::default, |hooks| {
3053 hooks.set_on_command(owner, handler);
3054 });
3055 }
3056
3057 pub fn action_add_on_command_for_owner<Owner: Any>(
3058 &mut self,
3059 element: GlobalElementId,
3060 handler: OnCommand,
3061 ) {
3062 let owner = TypeId::of::<Owner>();
3063 self.state_for(element, ActionRouteHooks::default, |hooks| {
3064 hooks.add_on_command(owner, handler);
3065 });
3066 }
3067
3068 pub fn action_clear_on_command_for_owner<Owner: Any>(&mut self, element: GlobalElementId) {
3069 let owner = TypeId::of::<Owner>();
3070 self.state_for(element, ActionRouteHooks::default, |hooks| {
3071 hooks.clear_on_command(owner);
3072 });
3073 }
3074
3075 pub fn command_add_on_command_for(&mut self, element: GlobalElementId, handler: OnCommand) {
3076 self.state_for(element, CommandActionHooks::default, |hooks| {
3077 hooks.on_command = match hooks.on_command.clone() {
3078 None => Some(handler),
3079 Some(prev) => {
3080 let next = handler.clone();
3081 Some(Arc::new(move |host, cx, command| {
3082 prev(host, cx, command.clone()) || next(host, cx, command)
3083 }))
3084 }
3085 };
3086 });
3087 }
3088
3089 pub fn command_prepend_on_command_for(&mut self, element: GlobalElementId, handler: OnCommand) {
3090 self.state_for(element, CommandActionHooks::default, |hooks| {
3091 hooks.on_command = match hooks.on_command.clone() {
3092 None => Some(handler),
3093 Some(prev) => {
3094 let next = handler.clone();
3095 Some(Arc::new(move |host, cx, command| {
3096 next(host, cx, command.clone()) || prev(host, cx, command)
3097 }))
3098 }
3099 };
3100 });
3101 }
3102
3103 pub fn command_clear_on_command_for(&mut self, element: GlobalElementId) {
3104 self.state_for(element, CommandActionHooks::default, |hooks| {
3105 hooks.on_command = None;
3106 });
3107 }
3108
3109 pub fn command_on_command_availability_for(
3110 &mut self,
3111 element: GlobalElementId,
3112 handler: OnCommandAvailability,
3113 ) {
3114 self.state_for(element, CommandAvailabilityActionHooks::default, |hooks| {
3115 hooks.on_command_availability = Some(handler);
3116 });
3117 }
3118
3119 pub fn action_on_command_availability_for_owner<Owner: Any>(
3120 &mut self,
3121 element: GlobalElementId,
3122 handler: OnCommandAvailability,
3123 ) {
3124 let owner = TypeId::of::<Owner>();
3125 self.state_for(element, ActionRouteHooks::default, |hooks| {
3126 hooks.set_on_command_availability(owner, handler);
3127 });
3128 }
3129
3130 pub fn action_add_on_command_availability_for_owner<Owner: Any>(
3131 &mut self,
3132 element: GlobalElementId,
3133 handler: OnCommandAvailability,
3134 ) {
3135 let owner = TypeId::of::<Owner>();
3136 self.state_for(element, ActionRouteHooks::default, |hooks| {
3137 hooks.add_on_command_availability(owner, handler);
3138 });
3139 }
3140
3141 pub fn action_clear_on_command_availability_for_owner<Owner: Any>(
3142 &mut self,
3143 element: GlobalElementId,
3144 ) {
3145 let owner = TypeId::of::<Owner>();
3146 self.state_for(element, ActionRouteHooks::default, |hooks| {
3147 hooks.clear_on_command_availability(owner);
3148 });
3149 }
3150
3151 pub fn command_add_on_command_availability_for(
3152 &mut self,
3153 element: GlobalElementId,
3154 handler: OnCommandAvailability,
3155 ) {
3156 self.state_for(element, CommandAvailabilityActionHooks::default, |hooks| {
3157 hooks.on_command_availability = match hooks.on_command_availability.clone() {
3158 None => Some(handler),
3159 Some(prev) => {
3160 let next = handler.clone();
3161 Some(Arc::new(move |host, cx, command| {
3162 let availability = prev(host, cx.clone(), command.clone());
3163 if availability != crate::widget::CommandAvailability::NotHandled {
3164 return availability;
3165 }
3166 next(host, cx, command)
3167 }))
3168 }
3169 };
3170 });
3171 }
3172
3173 pub fn command_prepend_on_command_availability_for(
3174 &mut self,
3175 element: GlobalElementId,
3176 handler: OnCommandAvailability,
3177 ) {
3178 self.state_for(element, CommandAvailabilityActionHooks::default, |hooks| {
3179 hooks.on_command_availability = match hooks.on_command_availability.clone() {
3180 None => Some(handler),
3181 Some(prev) => {
3182 let next = handler.clone();
3183 Some(Arc::new(move |host, cx, command| {
3184 let availability = next(host, cx.clone(), command.clone());
3185 if availability != crate::widget::CommandAvailability::NotHandled {
3186 return availability;
3187 }
3188 prev(host, cx, command)
3189 }))
3190 }
3191 };
3192 });
3193 }
3194
3195 pub fn command_clear_on_command_availability_for(&mut self, element: GlobalElementId) {
3196 self.state_for(element, CommandAvailabilityActionHooks::default, |hooks| {
3197 hooks.on_command_availability = None;
3198 });
3199 }
3200
3201 pub fn timer_on_timer_for(&mut self, element: GlobalElementId, handler: OnTimer) {
3202 self.state_for(element, TimerActionHooks::default, |hooks| {
3203 hooks.on_timer = Some(handler);
3204 });
3205 }
3206
3207 pub fn timer_add_on_timer_for(&mut self, element: GlobalElementId, handler: OnTimer) {
3208 self.state_for(element, TimerActionHooks::default, |hooks| {
3209 hooks.on_timer = match hooks.on_timer.clone() {
3210 None => Some(handler),
3211 Some(prev) => {
3212 let next = handler.clone();
3213 Some(Arc::new(move |host, cx, token| {
3214 prev(host, cx, token) || next(host, cx, token)
3215 }))
3216 }
3217 };
3218 });
3219 }
3220
3221 pub fn timer_clear_on_timer_for(&mut self, element: GlobalElementId) {
3222 self.state_for(element, TimerActionHooks::default, |hooks| {
3223 hooks.on_timer = None;
3224 });
3225 }
3226
3227 pub fn dismissible_on_dismiss_request(&mut self, handler: OnDismissRequest) {
3233 self.root_state(DismissibleActionHooks::default, |hooks| {
3234 hooks.on_dismiss_request = Some(handler);
3235 });
3236 }
3237
3238 pub fn dismissible_on_pointer_move(&mut self, handler: OnDismissiblePointerMove) {
3243 self.root_state(DismissibleActionHooks::default, |hooks| {
3244 hooks.on_pointer_move = Some(handler);
3245 });
3246 }
3247
3248 pub fn dismissible_add_on_dismiss_request(&mut self, handler: OnDismissRequest) {
3249 self.root_state(DismissibleActionHooks::default, |hooks| {
3250 hooks.on_dismiss_request = match hooks.on_dismiss_request.clone() {
3251 None => Some(handler),
3252 Some(prev) => {
3253 let next = handler.clone();
3254 Some(Arc::new(move |host, cx, req| {
3255 prev(host, cx, req);
3256 next(host, cx, req);
3257 }))
3258 }
3259 };
3260 });
3261 }
3262
3263 pub fn dismissible_add_on_pointer_move(&mut self, handler: OnDismissiblePointerMove) {
3264 self.root_state(DismissibleActionHooks::default, |hooks| {
3265 hooks.on_pointer_move = match hooks.on_pointer_move.clone() {
3266 None => Some(handler),
3267 Some(prev) => {
3268 let next = handler.clone();
3269 Some(Arc::new(move |host, cx, mv| {
3270 prev(host, cx, mv) || next(host, cx, mv)
3271 }))
3272 }
3273 };
3274 });
3275 }
3276
3277 pub fn dismissible_clear_on_dismiss_request(&mut self) {
3278 self.root_state(DismissibleActionHooks::default, |hooks| {
3279 hooks.on_dismiss_request = None;
3280 });
3281 }
3282
3283 pub fn dismissible_clear_on_pointer_move(&mut self) {
3284 self.root_state(DismissibleActionHooks::default, |hooks| {
3285 hooks.on_pointer_move = None;
3286 });
3287 }
3288
3289 pub fn roving_on_active_change(&mut self, handler: OnRovingActiveChange) {
3297 self.root_state(RovingActionHooks::default, |hooks| {
3298 hooks.on_active_change = Some(handler);
3299 });
3300 }
3301
3302 pub fn roving_add_on_active_change(&mut self, handler: OnRovingActiveChange) {
3303 self.root_state(RovingActionHooks::default, |hooks| {
3304 hooks.on_active_change = match hooks.on_active_change.clone() {
3305 None => Some(handler),
3306 Some(prev) => {
3307 let next = handler.clone();
3308 Some(Arc::new(move |host, cx, idx| {
3309 prev(host, cx, idx);
3310 next(host, cx, idx);
3311 }))
3312 }
3313 };
3314 });
3315 }
3316
3317 pub fn roving_clear_on_active_change(&mut self) {
3318 self.root_state(RovingActionHooks::default, |hooks| {
3319 hooks.on_active_change = None;
3320 });
3321 }
3322
3323 pub fn roving_on_typeahead(&mut self, handler: OnRovingTypeahead) {
3328 self.root_state(RovingActionHooks::default, |hooks| {
3329 hooks.on_typeahead = Some(handler);
3330 });
3331 }
3332
3333 pub fn roving_add_on_typeahead(&mut self, handler: OnRovingTypeahead) {
3334 self.root_state(RovingActionHooks::default, |hooks| {
3335 hooks.on_typeahead = match hooks.on_typeahead.clone() {
3336 None => Some(handler),
3337 Some(prev) => {
3338 let next = handler.clone();
3339 Some(Arc::new(move |host, cx, it| {
3340 prev(host, cx, it.clone()).or_else(|| next(host, cx, it))
3341 }))
3342 }
3343 };
3344 });
3345 }
3346
3347 pub fn roving_clear_on_typeahead(&mut self) {
3348 self.root_state(RovingActionHooks::default, |hooks| {
3349 hooks.on_typeahead = None;
3350 });
3351 }
3352
3353 pub fn roving_on_key_down(&mut self, handler: OnKeyDown) {
3354 self.root_state(RovingActionHooks::default, |hooks| {
3355 hooks.on_key_down.clear();
3356 hooks.on_key_down.push(handler);
3357 });
3358 }
3359
3360 pub fn roving_add_on_key_down(&mut self, handler: OnKeyDown) {
3361 self.root_state(RovingActionHooks::default, |hooks| {
3362 hooks.on_key_down.push(handler);
3363 });
3364 }
3365
3366 pub fn roving_clear_on_key_down(&mut self) {
3367 self.root_state(RovingActionHooks::default, |hooks| {
3368 hooks.on_key_down.clear();
3369 });
3370 }
3371
3372 pub fn roving_on_navigate(&mut self, handler: OnRovingNavigate) {
3377 self.root_state(RovingActionHooks::default, |hooks| {
3378 hooks.on_navigate = Some(handler);
3379 });
3380 }
3381
3382 pub fn roving_add_on_navigate(&mut self, handler: OnRovingNavigate) {
3383 self.root_state(RovingActionHooks::default, |hooks| {
3384 hooks.on_navigate = match hooks.on_navigate.clone() {
3385 None => Some(handler),
3386 Some(prev) => {
3387 let next = handler.clone();
3388 Some(Arc::new(move |host, cx, it| {
3389 match prev(host, cx, it.clone()) {
3390 crate::action::RovingNavigateResult::NotHandled => next(host, cx, it),
3391 other => other,
3392 }
3393 }))
3394 }
3395 };
3396 });
3397 }
3398
3399 pub fn roving_clear_on_navigate(&mut self) {
3400 self.root_state(RovingActionHooks::default, |hooks| {
3401 hooks.on_navigate = None;
3402 });
3403 }
3404
3405 #[track_caller]
3406 pub fn stack<I>(&mut self, f: impl FnOnce(&mut Self) -> I) -> AnyElement
3407 where
3408 I: IntoIterator<Item = AnyElement>,
3409 {
3410 self.stack_props(StackProps::default(), f)
3411 }
3412
3413 #[track_caller]
3414 pub fn stack_props<I>(
3415 &mut self,
3416 props: StackProps,
3417 f: impl FnOnce(&mut Self) -> I,
3418 ) -> AnyElement
3419 where
3420 I: IntoIterator<Item = AnyElement>,
3421 {
3422 self.scope(|cx| {
3423 let id = cx.root_id();
3424 let built = f(cx);
3425 let children = cx.collect_children(built);
3426 cx.new_any_element(id, ElementKind::Stack(props), children)
3427 })
3428 }
3429
3430 #[track_caller]
3431 pub fn column<I>(&mut self, props: ColumnProps, f: impl FnOnce(&mut Self) -> I) -> AnyElement
3432 where
3433 I: IntoIterator<Item = AnyElement>,
3434 {
3435 self.scope(|cx| {
3436 let id = cx.root_id();
3437 let built = f(cx);
3438 let children = cx.collect_children(built);
3439 cx.new_any_element(id, ElementKind::Column(props), children)
3440 })
3441 }
3442
3443 #[track_caller]
3444 pub fn row<I>(&mut self, props: RowProps, f: impl FnOnce(&mut Self) -> I) -> AnyElement
3445 where
3446 I: IntoIterator<Item = AnyElement>,
3447 {
3448 self.scope(|cx| {
3449 let id = cx.root_id();
3450 let built = f(cx);
3451 let children = cx.collect_children(built);
3452 cx.new_any_element(id, ElementKind::Row(props), children)
3453 })
3454 }
3455
3456 #[track_caller]
3457 pub fn spacer(&mut self, props: SpacerProps) -> AnyElement {
3458 self.scope(|cx| {
3459 let id = cx.root_id();
3460 cx.new_any_element(id, ElementKind::Spacer(props), Vec::new())
3461 })
3462 }
3463
3464 #[track_caller]
3465 pub fn text(&mut self, text: impl Into<std::sync::Arc<str>>) -> AnyElement {
3466 self.scope(|cx| {
3467 let id = cx.root_id();
3468 cx.new_any_element(id, ElementKind::Text(TextProps::new(text)), Vec::new())
3469 })
3470 }
3471
3472 #[track_caller]
3473 pub fn text_props(&mut self, props: TextProps) -> AnyElement {
3474 self.scope(|cx| {
3475 let id = cx.root_id();
3476 cx.new_any_element(id, ElementKind::Text(props), Vec::new())
3477 })
3478 }
3479
3480 #[track_caller]
3481 pub fn styled_text(&mut self, rich: fret_core::AttributedText) -> AnyElement {
3482 self.scope(|cx| {
3483 let id = cx.root_id();
3484 cx.new_any_element(
3485 id,
3486 ElementKind::StyledText(StyledTextProps::new(rich)),
3487 Vec::new(),
3488 )
3489 })
3490 }
3491
3492 #[track_caller]
3493 pub fn styled_text_props(&mut self, props: StyledTextProps) -> AnyElement {
3494 self.scope(|cx| {
3495 let id = cx.root_id();
3496 cx.new_any_element(id, ElementKind::StyledText(props), Vec::new())
3497 })
3498 }
3499
3500 #[track_caller]
3501 pub fn selectable_text(&mut self, rich: fret_core::AttributedText) -> AnyElement {
3502 self.scope(|cx| {
3503 let id = cx.root_id();
3504 cx.selectable_text_clear_on_activate_span();
3505 cx.new_any_element(
3506 id,
3507 ElementKind::SelectableText(SelectableTextProps::new(rich)),
3508 Vec::new(),
3509 )
3510 })
3511 }
3512
3513 #[track_caller]
3514 pub fn selectable_text_with_id_props(
3515 &mut self,
3516 f: impl FnOnce(&mut Self, GlobalElementId) -> SelectableTextProps,
3517 ) -> AnyElement {
3518 self.scope(|cx| {
3519 let id = cx.root_id();
3520 cx.selectable_text_clear_on_activate_span();
3521 let props = f(cx, id);
3522 cx.new_any_element(id, ElementKind::SelectableText(props), Vec::new())
3523 })
3524 }
3525
3526 #[track_caller]
3527 pub fn selectable_text_props(&mut self, props: SelectableTextProps) -> AnyElement {
3528 self.scope(|cx| {
3529 let id = cx.root_id();
3530 cx.selectable_text_clear_on_activate_span();
3531 cx.new_any_element(id, ElementKind::SelectableText(props), Vec::new())
3532 })
3533 }
3534
3535 #[track_caller]
3536 pub fn text_input(&mut self, props: TextInputProps) -> AnyElement {
3537 self.scope(|cx| {
3538 let id = cx.root_id();
3539 cx.new_any_element(id, ElementKind::TextInput(props), Vec::new())
3540 })
3541 }
3542
3543 #[track_caller]
3544 pub fn text_input_with_id_props(
3545 &mut self,
3546 f: impl FnOnce(&mut Self, GlobalElementId) -> TextInputProps,
3547 ) -> AnyElement {
3548 self.scope(|cx| {
3549 let id = cx.root_id();
3550 let props = f(cx, id);
3551 cx.new_any_element(id, ElementKind::TextInput(props), Vec::new())
3552 })
3553 }
3554
3555 #[track_caller]
3556 pub fn text_area(&mut self, props: TextAreaProps) -> AnyElement {
3557 self.scope(|cx| {
3558 let id = cx.root_id();
3559 cx.new_any_element(id, ElementKind::TextArea(props), Vec::new())
3560 })
3561 }
3562
3563 #[track_caller]
3564 pub fn text_area_with_id_props(
3565 &mut self,
3566 f: impl FnOnce(&mut Self, GlobalElementId) -> TextAreaProps,
3567 ) -> AnyElement {
3568 self.scope(|cx| {
3569 let id = cx.root_id();
3570 let props = f(cx, id);
3571 cx.new_any_element(id, ElementKind::TextArea(props), Vec::new())
3572 })
3573 }
3574
3575 #[track_caller]
3576 pub fn resizable_panel_group<I>(
3577 &mut self,
3578 props: ResizablePanelGroupProps,
3579 f: impl FnOnce(&mut Self) -> I,
3580 ) -> AnyElement
3581 where
3582 I: IntoIterator<Item = AnyElement>,
3583 {
3584 self.scope(|cx| {
3585 let id = cx.root_id();
3586 let built = f(cx);
3587 let children = cx.collect_children(built);
3588 cx.new_any_element(id, ElementKind::ResizablePanelGroup(props), children)
3589 })
3590 }
3591
3592 #[track_caller]
3593 pub fn image(&mut self, image: fret_core::ImageId) -> AnyElement {
3594 self.scope(|cx| {
3595 let id = cx.root_id();
3596 cx.new_any_element(id, ElementKind::Image(ImageProps::new(image)), Vec::new())
3597 })
3598 }
3599
3600 #[track_caller]
3601 pub fn image_props(&mut self, props: ImageProps) -> AnyElement {
3602 self.scope(|cx| {
3603 let id = cx.root_id();
3604 cx.new_any_element(id, ElementKind::Image(props), Vec::new())
3605 })
3606 }
3607
3608 #[track_caller]
3609 pub fn canvas(
3610 &mut self,
3611 props: CanvasProps,
3612 paint: impl for<'p> Fn(&mut CanvasPainter<'p>) + 'static,
3613 ) -> AnyElement {
3614 let on_paint: OnCanvasPaint = Arc::new(paint);
3615 self.scope(|cx| {
3616 let id = cx.root_id();
3617 cx.state_for(id, CanvasPaintHooks::default, |hooks| {
3618 hooks.on_paint = Some(on_paint.clone());
3619 });
3620 cx.new_any_element(id, ElementKind::Canvas(props), Vec::new())
3621 })
3622 }
3623
3624 #[cfg(feature = "unstable-retained-bridge")]
3625 #[track_caller]
3626 pub fn retained_subtree(
3627 &mut self,
3628 props: crate::retained_bridge::RetainedSubtreeProps,
3629 ) -> AnyElement {
3630 self.scope(|cx| {
3631 let id = cx.root_id();
3632 cx.new_any_element(id, ElementKind::RetainedSubtree(props), Vec::new())
3633 })
3634 }
3635
3636 #[track_caller]
3637 pub fn viewport_surface(&mut self, target: fret_core::RenderTargetId) -> AnyElement {
3638 self.viewport_surface_props(ViewportSurfaceProps::new(target))
3639 }
3640
3641 #[track_caller]
3642 pub fn viewport_surface_mapped(
3643 &mut self,
3644 target: fret_core::RenderTargetId,
3645 target_px_size: (u32, u32),
3646 fit: fret_core::ViewportFit,
3647 ) -> AnyElement {
3648 self.viewport_surface_props(ViewportSurfaceProps {
3649 target_px_size,
3650 fit,
3651 ..ViewportSurfaceProps::new(target)
3652 })
3653 }
3654
3655 #[track_caller]
3656 pub fn viewport_surface_props(&mut self, props: ViewportSurfaceProps) -> AnyElement {
3657 self.scope(|cx| {
3658 let id = cx.root_id();
3659 cx.new_any_element(id, ElementKind::ViewportSurface(props), Vec::new())
3660 })
3661 }
3662
3663 #[track_caller]
3664 pub fn svg_icon(&mut self, svg: SvgSource) -> AnyElement {
3665 self.svg_icon_props(SvgIconProps::new(svg))
3666 }
3667
3668 #[track_caller]
3669 pub fn svg_icon_props(&mut self, props: SvgIconProps) -> AnyElement {
3670 self.scope(|cx| {
3671 let id = cx.root_id();
3672 cx.new_any_element(id, ElementKind::SvgIcon(props), Vec::new())
3673 })
3674 }
3675
3676 #[track_caller]
3677 pub fn spinner(&mut self) -> AnyElement {
3678 self.spinner_props(SpinnerProps::default())
3679 }
3680
3681 #[track_caller]
3682 pub fn spinner_props(&mut self, props: SpinnerProps) -> AnyElement {
3683 self.scope(|cx| {
3684 let id = cx.root_id();
3685 cx.new_any_element(id, ElementKind::Spinner(props), Vec::new())
3686 })
3687 }
3688
3689 #[track_caller]
3690 pub fn hover_region<I>(
3691 &mut self,
3692 props: HoverRegionProps,
3693 f: impl FnOnce(&mut Self, bool) -> I,
3694 ) -> AnyElement
3695 where
3696 I: IntoIterator<Item = AnyElement>,
3697 {
3698 self.scope(|cx| {
3699 let id = cx.root_id();
3700 let hovered = cx.window_state.hovered_hover_region == Some(id);
3701 let built = f(cx, hovered);
3702 let children = cx.collect_children(built);
3703 cx.new_any_element(id, ElementKind::HoverRegion(props), children)
3704 })
3705 }
3706
3707 #[track_caller]
3708 pub fn wheel_region<I>(
3709 &mut self,
3710 props: crate::element::WheelRegionProps,
3711 f: impl FnOnce(&mut Self) -> I,
3712 ) -> AnyElement
3713 where
3714 I: IntoIterator<Item = AnyElement>,
3715 {
3716 self.scope(|cx| {
3717 let id = cx.root_id();
3718 let built = f(cx);
3719 let children = cx.collect_children(built);
3720 cx.new_any_element(id, ElementKind::WheelRegion(props), children)
3721 })
3722 }
3723
3724 #[track_caller]
3725 pub fn scroll<I>(&mut self, props: ScrollProps, f: impl FnOnce(&mut Self) -> I) -> AnyElement
3726 where
3727 I: IntoIterator<Item = AnyElement>,
3728 {
3729 self.scope(|cx| {
3730 let id = cx.root_id();
3731 let built = f(cx);
3732 let children = cx.collect_children(built);
3733 cx.new_any_element(id, ElementKind::Scroll(props), children)
3734 })
3735 }
3736
3737 #[track_caller]
3738 pub fn scrollbar(&mut self, props: ScrollbarProps) -> AnyElement {
3739 self.scope(|cx| {
3740 let id = cx.root_id();
3741 cx.new_any_element(id, ElementKind::Scrollbar(props), Vec::new())
3742 })
3743 }
3744
3745 #[track_caller]
3746 pub fn virtual_list<F, I>(
3747 &mut self,
3748 len: usize,
3749 options: VirtualListOptions,
3750 scroll_handle: &crate::scroll::VirtualListScrollHandle,
3751 f: F,
3752 ) -> AnyElement
3753 where
3754 F: FnOnce(&mut Self, &[crate::virtual_list::VirtualItem]) -> I,
3755 I: IntoIterator<Item = AnyElement>,
3756 {
3757 self.virtual_list_with_layout(LayoutStyle::default(), len, options, scroll_handle, f)
3758 }
3759
3760 #[track_caller]
3761 pub fn virtual_list_with_range_extractor<F, I>(
3762 &mut self,
3763 len: usize,
3764 options: VirtualListOptions,
3765 scroll_handle: &crate::scroll::VirtualListScrollHandle,
3766 range_extractor: impl FnOnce(crate::virtual_list::VirtualRange) -> Vec<usize>,
3767 f: F,
3768 ) -> AnyElement
3769 where
3770 F: FnOnce(&mut Self, &[crate::virtual_list::VirtualItem]) -> I,
3771 I: IntoIterator<Item = AnyElement>,
3772 {
3773 self.virtual_list_with_layout_and_range_extractor(
3774 LayoutStyle::default(),
3775 len,
3776 options,
3777 scroll_handle,
3778 range_extractor,
3779 f,
3780 )
3781 }
3782
3783 #[track_caller]
3784 pub fn virtual_list_with_layout<F, I>(
3785 &mut self,
3786 layout: LayoutStyle,
3787 len: usize,
3788 options: VirtualListOptions,
3789 scroll_handle: &crate::scroll::VirtualListScrollHandle,
3790 f: F,
3791 ) -> AnyElement
3792 where
3793 F: FnOnce(&mut Self, &[crate::virtual_list::VirtualItem]) -> I,
3794 I: IntoIterator<Item = AnyElement>,
3795 {
3796 self.virtual_list_with_layout_and_range_extractor(
3797 layout,
3798 len,
3799 options,
3800 scroll_handle,
3801 crate::virtual_list::default_range_extractor,
3802 f,
3803 )
3804 }
3805
3806 #[track_caller]
3807 pub fn virtual_list_with_layout_and_range_extractor<F, I>(
3808 &mut self,
3809 layout: LayoutStyle,
3810 len: usize,
3811 options: VirtualListOptions,
3812 scroll_handle: &crate::scroll::VirtualListScrollHandle,
3813 range_extractor: impl FnOnce(crate::virtual_list::VirtualRange) -> Vec<usize>,
3814 f: F,
3815 ) -> AnyElement
3816 where
3817 F: FnOnce(&mut Self, &[crate::virtual_list::VirtualItem]) -> I,
3818 I: IntoIterator<Item = AnyElement>,
3819 {
3820 self.virtual_list_with_layout_and_keys(
3821 layout,
3822 len,
3823 options,
3824 scroll_handle,
3825 |i| i as crate::ItemKey,
3826 range_extractor,
3827 f,
3828 )
3829 }
3830
3831 #[allow(clippy::too_many_arguments)]
3832 fn virtual_list_with_layout_and_keys<F, I>(
3833 &mut self,
3834 layout: LayoutStyle,
3835 len: usize,
3836 options: VirtualListOptions,
3837 scroll_handle: &crate::scroll::VirtualListScrollHandle,
3838 mut item_key_at: impl FnMut(usize) -> crate::ItemKey,
3839 range_extractor: impl FnOnce(crate::virtual_list::VirtualRange) -> Vec<usize>,
3840 f: F,
3841 ) -> AnyElement
3842 where
3843 F: FnOnce(&mut Self, &[crate::virtual_list::VirtualItem]) -> I,
3844 I: IntoIterator<Item = AnyElement>,
3845 {
3846 self.scope(|cx| {
3847 let id = cx.root_id();
3848
3849 let scroll_handle = scroll_handle.clone();
3850 scroll_handle.set_items_count(len);
3851
3852 let key_cache = match options.measure_mode {
3853 crate::element::VirtualListMeasureMode::Measured => {
3854 crate::element::VirtualListKeyCacheMode::AllKeys
3855 }
3856 crate::element::VirtualListMeasureMode::Fixed => options.key_cache,
3857 crate::element::VirtualListMeasureMode::Known => options.key_cache,
3858 };
3859
3860 let range = cx.root_state(VirtualListState::default, |state| {
3861 let axis = options.axis;
3862 let (viewport, offset) = match axis {
3863 fret_core::Axis::Vertical => (state.viewport_h, state.offset_y),
3864 fret_core::Axis::Horizontal => (state.viewport_w, state.offset_x),
3865 };
3866
3867 let mut overscan_for_range = if scroll_handle.deferred_scroll_to_item().is_some() {
3873 0
3874 } else {
3875 options.overscan
3876 };
3877
3878 let prev_anchor = if viewport.0 > 0.0 && len > 0 {
3879 state.metrics.visible_range(offset, viewport, 0).map(|r| {
3880 let idx = r.start_index;
3881 let key = if idx >= len {
3882 idx as crate::ItemKey
3883 } else {
3884 match key_cache {
3885 crate::element::VirtualListKeyCacheMode::AllKeys => state
3886 .keys
3887 .get(idx)
3888 .copied()
3889 .unwrap_or_else(|| item_key_at(idx)),
3890 crate::element::VirtualListKeyCacheMode::VisibleOnly => {
3891 item_key_at(idx)
3892 }
3893 }
3894 };
3895 let start = state.metrics.offset_for_index(idx);
3896 let offset_in_viewport = Px((offset.0 - start.0).max(0.0));
3897 (key, offset_in_viewport)
3898 })
3899 } else {
3900 None
3901 };
3902
3903 let prev_cfg = (
3904 state.metrics.estimate(),
3905 state.metrics.gap(),
3906 state.metrics.scroll_margin(),
3907 );
3908 let cfg = (
3909 options.estimate_row_height,
3910 options.gap,
3911 options.scroll_margin,
3912 );
3913
3914 state.metrics.ensure_with_mode(
3915 options.measure_mode,
3916 len,
3917 options.estimate_row_height,
3918 options.gap,
3919 options.scroll_margin,
3920 );
3921
3922 let needs_rebuild = state.items_revision != options.items_revision
3923 || state.items_len != len
3924 || state.key_cache != key_cache
3925 || prev_cfg != cfg;
3926
3927 if needs_rebuild {
3928 state.items_revision = options.items_revision;
3929 state.items_len = len;
3930 state.key_cache = key_cache;
3931
3932 match key_cache {
3933 crate::element::VirtualListKeyCacheMode::AllKeys => {
3934 state.keys.clear();
3935 state.keys.reserve(len);
3936
3937 for i in 0..len {
3938 let key = item_key_at(i);
3939 state.keys.push(key);
3940 }
3941 }
3942 crate::element::VirtualListKeyCacheMode::VisibleOnly => {
3943 state.keys.clear();
3944 }
3945 }
3946
3947 state.metrics.sync_keys(&state.keys, options.items_revision);
3948
3949 if options.measure_mode == crate::element::VirtualListMeasureMode::Known
3950 && let Some(height_at) = options.known_row_height_at.as_ref()
3951 {
3952 let heights = (0..len).map(|i| height_at(i)).collect::<Vec<_>>();
3953 state.metrics.rebuild_from_known_heights(
3954 heights,
3955 options.estimate_row_height,
3956 options.gap,
3957 options.scroll_margin,
3958 );
3959 }
3960
3961 if key_cache == crate::element::VirtualListKeyCacheMode::AllKeys {
3962 let has_deferred_scroll = scroll_handle.deferred_scroll_to_item().is_some();
3963 if !has_deferred_scroll
3964 && let Some((key, offset_in_viewport)) = prev_anchor
3965 && let Some(index) = state.keys.iter().position(|&k| k == key)
3966 {
3967 let start = state.metrics.offset_for_index(index);
3968 let desired = Px(start.0 + offset_in_viewport.0);
3969 let prev = scroll_handle.offset();
3970 let clamped = state.metrics.clamp_offset(desired, viewport);
3971 match axis {
3972 fret_core::Axis::Vertical => {
3973 scroll_handle
3974 .set_offset(fret_core::Point::new(prev.x, clamped));
3975 state.offset_y = clamped;
3976 }
3977 fret_core::Axis::Horizontal => {
3978 scroll_handle
3979 .set_offset(fret_core::Point::new(clamped, prev.y));
3980 state.offset_x = clamped;
3981 }
3982 }
3983 }
3984 }
3985 }
3986
3987 let viewport = Px(viewport.0.max(0.0));
3988 let offset = state.metrics.clamp_offset(offset, viewport);
3989
3990 state.deferred_scroll_offset_hint = None;
3991
3992 let mut range = state.render_window_range.filter(|r| {
3993 r.count == len && r.overscan == options.overscan && r.start_index <= r.end_index
3994 });
3995 if range.is_none() {
3996 range = state.window_range.filter(|r| {
3997 r.count == len
3998 && r.overscan == options.overscan
3999 && r.start_index <= r.end_index
4000 });
4001 }
4002
4003 let mut preview_offset = offset;
4011 if state.has_final_viewport && viewport.0 > 0.0 && len > 0 {
4012 let handle_offset = scroll_handle.offset();
4013 let handle_axis = match axis {
4014 fret_core::Axis::Vertical => handle_offset.y,
4015 fret_core::Axis::Horizontal => handle_offset.x,
4016 };
4017 let handle_axis = state.metrics.clamp_offset(handle_axis, viewport);
4018 if (handle_axis.0 - offset.0).abs() > 0.01 {
4019 if overscan_for_range > 0 {
4023 let prev_visible = state.metrics.visible_range(offset, viewport, 0);
4024 let next_visible =
4025 state.metrics.visible_range(handle_axis, viewport, 0);
4026 let large_jump = match (prev_visible, next_visible) {
4027 (Some(prev), Some(next)) => {
4028 let prev_len = prev
4029 .end_index
4030 .saturating_sub(prev.start_index)
4031 .saturating_add(1);
4032 let threshold = prev_len
4033 .saturating_mul(4)
4034 .max(options.overscan.saturating_mul(8));
4035 next.start_index.abs_diff(prev.start_index) > threshold
4036 }
4037 _ => {
4038 let delta_px = (handle_axis.0 - offset.0).abs();
4039 delta_px > (viewport.0 * 3.0)
4040 }
4041 };
4042
4043 if large_jump {
4044 overscan_for_range = 0;
4045 range = None;
4046 }
4047 }
4048 preview_offset = handle_axis;
4049 }
4050 }
4051
4052 if state.has_final_viewport
4056 && viewport.0 > 0.0
4057 && len > 0
4058 && let Some((index, strategy)) = scroll_handle.deferred_scroll_to_item()
4059 {
4060 let desired = state
4061 .metrics
4062 .scroll_offset_for_item(index, viewport, offset, strategy);
4063 let desired = state.metrics.clamp_offset(desired, viewport);
4064 preview_offset = desired;
4065 state.deferred_scroll_offset_hint = Some(desired);
4066 range = state
4067 .metrics
4068 .visible_range(desired, viewport, overscan_for_range);
4069 }
4070
4071 if state.has_final_viewport && viewport.0 > 0.0 && len > 0 {
4072 let visible = state.metrics.visible_range(preview_offset, viewport, 0);
4073 if let (Some(prev), Some(visible)) = (range, visible) {
4074 let prev_visible_len = prev
4075 .end_index
4076 .saturating_sub(prev.start_index)
4077 .saturating_add(1);
4078 let visible_len = visible
4079 .end_index
4080 .saturating_sub(visible.start_index)
4081 .saturating_add(1);
4082
4083 let win_start = prev.start_index.saturating_sub(prev.overscan);
4084 let win_end =
4085 (prev.end_index + prev.overscan).min(prev.count.saturating_sub(1));
4086 let out_of_window =
4087 visible.start_index < win_start || visible.end_index > win_end;
4088
4089 if visible_len > prev_visible_len || out_of_window {
4094 range = state.metrics.visible_range(
4095 preview_offset,
4096 viewport,
4097 overscan_for_range,
4098 );
4099 }
4100 } else if range.is_none() {
4101 range = state.metrics.visible_range(
4102 preview_offset,
4103 viewport,
4104 overscan_for_range,
4105 );
4106 }
4107 } else if range.is_none() {
4108 range = state
4109 .metrics
4110 .visible_range(offset, viewport, overscan_for_range);
4111 }
4112
4113 state.render_window_range = range;
4114 range
4115 });
4116
4117 let mut indices = range
4118 .map(range_extractor)
4119 .unwrap_or_default()
4120 .into_iter()
4121 .filter(|&idx| idx < len)
4122 .collect::<Vec<_>>();
4123 indices.sort_unstable();
4124 indices.dedup();
4125
4126 let visible_items = cx.root_state(VirtualListState::default, |state| {
4127 indices
4128 .iter()
4129 .map(|&idx| {
4130 let key = if idx >= len {
4131 idx as crate::ItemKey
4132 } else {
4133 match key_cache {
4134 crate::element::VirtualListKeyCacheMode::AllKeys => state
4135 .keys
4136 .get(idx)
4137 .copied()
4138 .unwrap_or_else(|| item_key_at(idx)),
4139 crate::element::VirtualListKeyCacheMode::VisibleOnly => {
4140 item_key_at(idx)
4141 }
4142 }
4143 };
4144 state.metrics.virtual_item(idx, key)
4145 })
4146 .collect::<Vec<_>>()
4147 });
4148
4149 let built = f(cx, &visible_items);
4150 let children = cx.collect_children(built);
4151 cx.new_any_element(
4152 id,
4153 ElementKind::VirtualList(VirtualListProps {
4154 layout,
4155 axis: options.axis,
4156 len,
4157 items_revision: options.items_revision,
4158 estimate_row_height: options.estimate_row_height,
4159 measure_mode: options.measure_mode,
4160 key_cache,
4161 overscan: options.overscan,
4162 keep_alive: options.keep_alive,
4163 scroll_margin: options.scroll_margin,
4164 gap: options.gap,
4165 scroll_handle,
4166 visible_items,
4167 }),
4168 children,
4169 )
4170 })
4171 }
4172
4173 #[track_caller]
4174 pub fn flex<I>(&mut self, props: FlexProps, f: impl FnOnce(&mut Self) -> I) -> AnyElement
4175 where
4176 I: IntoIterator<Item = AnyElement>,
4177 {
4178 self.scope(|cx| {
4179 let id = cx.root_id();
4180 let built = f(cx);
4181 let children = cx.collect_children(built);
4182 cx.new_any_element(id, ElementKind::Flex(props), children)
4183 })
4184 }
4185
4186 #[track_caller]
4187 pub fn roving_flex<I>(
4188 &mut self,
4189 props: crate::element::RovingFlexProps,
4190 f: impl FnOnce(&mut Self) -> I,
4191 ) -> AnyElement
4192 where
4193 I: IntoIterator<Item = AnyElement>,
4194 {
4195 self.scope(|cx| {
4196 let id = cx.root_id();
4197 cx.roving_clear_on_active_change();
4198 cx.roving_clear_on_typeahead();
4199 cx.roving_clear_on_key_down();
4200 cx.roving_clear_on_navigate();
4201 let built = f(cx);
4202 let children = cx.collect_children(built);
4203 cx.new_any_element(id, ElementKind::RovingFlex(props), children)
4204 })
4205 }
4206
4207 #[track_caller]
4208 pub fn grid<I>(&mut self, props: GridProps, f: impl FnOnce(&mut Self) -> I) -> AnyElement
4209 where
4210 I: IntoIterator<Item = AnyElement>,
4211 {
4212 self.scope(|cx| {
4213 let id = cx.root_id();
4214 let built = f(cx);
4215 let children = cx.collect_children(built);
4216 cx.new_any_element(id, ElementKind::Grid(props), children)
4217 })
4218 }
4219
4220 #[track_caller]
4226 pub fn virtual_list_keyed(
4227 &mut self,
4228 len: usize,
4229 options: VirtualListOptions,
4230 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4231 key_at: impl FnMut(usize) -> crate::ItemKey,
4232 row: impl FnMut(&mut Self, usize) -> AnyElement,
4233 ) -> AnyElement {
4234 self.virtual_list_keyed_with_layout(
4235 LayoutStyle::default(),
4236 len,
4237 options,
4238 scroll_handle,
4239 key_at,
4240 row,
4241 )
4242 }
4243
4244 #[track_caller]
4249 pub fn virtual_list_keyed_retained(
4250 &mut self,
4251 len: usize,
4252 options: VirtualListOptions,
4253 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4254 key_at: crate::windowed_surface_host::RetainedVirtualListKeyAtFn,
4255 row: crate::windowed_surface_host::RetainedVirtualListRowFn<H>,
4256 ) -> AnyElement
4257 where
4258 H: 'static,
4259 {
4260 self.virtual_list_keyed_retained_with_layout(
4261 LayoutStyle::default(),
4262 len,
4263 options,
4264 scroll_handle,
4265 key_at,
4266 row,
4267 )
4268 }
4269
4270 #[track_caller]
4271 pub fn virtual_list_keyed_retained_fn(
4272 &mut self,
4273 len: usize,
4274 options: VirtualListOptions,
4275 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4276 key_at: impl Fn(usize) -> crate::ItemKey + 'static,
4277 row: impl for<'b> Fn(&mut ElementContext<'b, H>, usize) -> AnyElement + 'static,
4278 ) -> AnyElement
4279 where
4280 H: 'static,
4281 {
4282 self.virtual_list_keyed_retained_with_layout_fn(
4283 LayoutStyle::default(),
4284 len,
4285 options,
4286 scroll_handle,
4287 key_at,
4288 row,
4289 )
4290 }
4291
4292 #[track_caller]
4293 pub fn virtual_list_keyed_retained_with_layout(
4294 &mut self,
4295 layout: LayoutStyle,
4296 len: usize,
4297 options: VirtualListOptions,
4298 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4299 key_at: crate::windowed_surface_host::RetainedVirtualListKeyAtFn,
4300 row: crate::windowed_surface_host::RetainedVirtualListRowFn<H>,
4301 ) -> AnyElement
4302 where
4303 H: 'static,
4304 {
4305 self.virtual_list_keyed_retained_with_layout_and_range_extractor(
4306 layout,
4307 len,
4308 options,
4309 scroll_handle,
4310 key_at,
4311 crate::virtual_list::default_range_extractor,
4312 row,
4313 )
4314 }
4315
4316 #[track_caller]
4317 pub fn virtual_list_keyed_retained_with_layout_fn(
4318 &mut self,
4319 layout: LayoutStyle,
4320 len: usize,
4321 options: VirtualListOptions,
4322 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4323 key_at: impl Fn(usize) -> crate::ItemKey + 'static,
4324 row: impl for<'b> Fn(&mut ElementContext<'b, H>, usize) -> AnyElement + 'static,
4325 ) -> AnyElement
4326 where
4327 H: 'static,
4328 {
4329 let key_at: crate::windowed_surface_host::RetainedVirtualListKeyAtFn = Arc::new(key_at);
4330 let row: crate::windowed_surface_host::RetainedVirtualListRowFn<H> = Arc::new(row);
4331 self.virtual_list_keyed_retained_with_layout(
4332 layout,
4333 len,
4334 options,
4335 scroll_handle,
4336 key_at,
4337 row,
4338 )
4339 }
4340
4341 #[track_caller]
4342 #[allow(clippy::too_many_arguments)]
4343 pub fn virtual_list_keyed_retained_with_layout_and_range_extractor(
4344 &mut self,
4345 layout: LayoutStyle,
4346 len: usize,
4347 options: VirtualListOptions,
4348 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4349 key_at: crate::windowed_surface_host::RetainedVirtualListKeyAtFn,
4350 range_extractor: crate::windowed_surface_host::RetainedVirtualListRangeExtractor,
4351 row: crate::windowed_surface_host::RetainedVirtualListRowFn<H>,
4352 ) -> AnyElement
4353 where
4354 H: 'static,
4355 {
4356 let key_at_for_keys = Arc::clone(&key_at);
4357 self.virtual_list_with_layout_and_keys(
4358 layout,
4359 len,
4360 options,
4361 scroll_handle,
4362 move |i| (key_at_for_keys)(i),
4363 range_extractor,
4364 move |cx, items| {
4365 cx.root_state(
4366 crate::windowed_surface_host::RetainedVirtualListHostMarker::default,
4367 |_| {},
4368 );
4369 cx.root_state(
4373 crate::windowed_surface_host::RetainedVirtualListKeepAliveState::default,
4374 |_| {},
4375 );
4376 cx.root_state(
4377 || crate::windowed_surface_host::RetainedVirtualListHostCallbacks::<H> {
4378 key_at: Arc::clone(&key_at),
4379 row: Arc::clone(&row),
4380 range_extractor,
4381 },
4382 |st| {
4383 st.key_at = Arc::clone(&key_at);
4384 st.row = Arc::clone(&row);
4385 st.range_extractor = range_extractor;
4386 },
4387 );
4388
4389 items
4390 .iter()
4391 .copied()
4392 .map(|item| {
4393 cx.retained_virtual_list_row_any_element(item.key, item.index, &row)
4394 })
4395 .collect::<Vec<_>>()
4396 },
4397 )
4398 }
4399
4400 #[track_caller]
4401 #[allow(clippy::too_many_arguments)]
4402 pub fn virtual_list_keyed_retained_with_layout_and_range_extractor_fn(
4403 &mut self,
4404 layout: LayoutStyle,
4405 len: usize,
4406 options: VirtualListOptions,
4407 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4408 key_at: impl Fn(usize) -> crate::ItemKey + 'static,
4409 range_extractor: crate::windowed_surface_host::RetainedVirtualListRangeExtractor,
4410 row: impl for<'b> Fn(&mut ElementContext<'b, H>, usize) -> AnyElement + 'static,
4411 ) -> AnyElement
4412 where
4413 H: 'static,
4414 {
4415 let key_at: crate::windowed_surface_host::RetainedVirtualListKeyAtFn = Arc::new(key_at);
4416 let row: crate::windowed_surface_host::RetainedVirtualListRowFn<H> = Arc::new(row);
4417 self.virtual_list_keyed_retained_with_layout_and_range_extractor(
4418 layout,
4419 len,
4420 options,
4421 scroll_handle,
4422 key_at,
4423 range_extractor,
4424 row,
4425 )
4426 }
4427
4428 #[track_caller]
4429 pub fn virtual_list_keyed_with_range_extractor(
4430 &mut self,
4431 len: usize,
4432 options: VirtualListOptions,
4433 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4434 key_at: impl FnMut(usize) -> crate::ItemKey,
4435 range_extractor: impl FnOnce(crate::virtual_list::VirtualRange) -> Vec<usize>,
4436 row: impl FnMut(&mut Self, usize) -> AnyElement,
4437 ) -> AnyElement {
4438 self.virtual_list_keyed_with_layout_and_range_extractor(
4439 LayoutStyle::default(),
4440 len,
4441 options,
4442 scroll_handle,
4443 key_at,
4444 range_extractor,
4445 row,
4446 )
4447 }
4448
4449 #[track_caller]
4450 pub fn virtual_list_keyed_with_layout(
4451 &mut self,
4452 layout: LayoutStyle,
4453 len: usize,
4454 options: VirtualListOptions,
4455 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4456 key_at: impl FnMut(usize) -> crate::ItemKey,
4457 row: impl FnMut(&mut Self, usize) -> AnyElement,
4458 ) -> AnyElement {
4459 self.virtual_list_keyed_with_layout_and_range_extractor(
4460 layout,
4461 len,
4462 options,
4463 scroll_handle,
4464 key_at,
4465 crate::virtual_list::default_range_extractor,
4466 row,
4467 )
4468 }
4469
4470 #[track_caller]
4471 #[allow(clippy::too_many_arguments)]
4472 pub fn virtual_list_keyed_with_layout_and_range_extractor(
4473 &mut self,
4474 layout: LayoutStyle,
4475 len: usize,
4476 options: VirtualListOptions,
4477 scroll_handle: &crate::scroll::VirtualListScrollHandle,
4478 key_at: impl FnMut(usize) -> crate::ItemKey,
4479 range_extractor: impl FnOnce(crate::virtual_list::VirtualRange) -> Vec<usize>,
4480 mut row: impl FnMut(&mut Self, usize) -> AnyElement,
4481 ) -> AnyElement {
4482 let loc = Location::caller();
4483 self.virtual_list_with_layout_and_keys(
4484 layout,
4485 len,
4486 options,
4487 scroll_handle,
4488 key_at,
4489 range_extractor,
4490 |cx, items| {
4491 if cfg!(debug_assertions) && items.len() > 1 {
4492 let mut first_dup: Option<(crate::ItemKey, usize, usize)> = None;
4493 let mut seen: HashMap<crate::ItemKey, usize> = HashMap::new();
4494 for (pos, item) in items.iter().enumerate() {
4495 if first_dup.is_none()
4496 && let Some(prev) = seen.insert(item.key, pos)
4497 {
4498 first_dup = Some((item.key, prev, pos));
4499 }
4500 }
4501
4502 if let Some((key, a, b)) = first_dup {
4503 let element_path: Option<String> = {
4504 #[cfg(feature = "diagnostics")]
4505 {
4506 cx.window_state.debug_path_for_element(cx.root_id())
4507 }
4508 #[cfg(not(feature = "diagnostics"))]
4509 {
4510 None
4511 }
4512 };
4513
4514 tracing::warn!(
4515 file = loc.file(),
4516 line = loc.line(),
4517 column = loc.column(),
4518 key = format_args!("{key:#x}"),
4519 first_visible_pos = a,
4520 second_visible_pos = b,
4521 element_path = element_path.as_deref().unwrap_or("<unknown>"),
4522 "duplicate virtual_list item key; element identity may collide"
4523 );
4524 }
4525 }
4526
4527 items
4528 .iter()
4529 .copied()
4530 .map(|item| cx.keyed(item.key, |cx| row(cx, item.index)))
4531 .collect::<Vec<_>>()
4532 },
4533 )
4534 }
4535}