ferroui_controls/primitives/
adorner_layer.rs1use super::{AdornerHelper, OverlayLayer, VisualLayerManager};
2use crate::templates::ITemplateOf;
3use crate::{Canvas, CanvasImpl, Control, ControlImpl, PanelImpl, TopLevel};
4use ferroui_base::collections::{NotifyCollectionChangedAction, NotifyCollectionChangedEventArgs};
5use ferroui_base::data::core::ValueTypes;
6use ferroui_base::input::text_input::TransformTrackingHelper;
7use ferroui_base::ElementRef;
8use ferroui_base::input::InputElementImpl;
9use ferroui_base::interactivity::InteractiveImpl;
10use ferroui_base::layout::LayoutableImpl;
11use ferroui_base::media::{ITransform, MatrixTransform};
12use ferroui_base::reactive::IDisposable;
13use ferroui_base::{
14 ferro_class, ferro_impl_classes, ferro_property, instantiate, AttachedProperty, FerroObjectImpl,
15 FerroObjectImplExt, FerroProperty, FerroPropertyChangedEventArgs, Matrix, Nullable, Point, Rect, Ref,
16 RelativePoint, RelativeUnit, Size, StyledElement, StyledElementImpl, StyledProperty, Visual, VisualImpl, WeakRef,
17};
18use std::cell::RefCell;
19use std::rc::Rc;
20
21#[repr(C)]
25pub struct AdornerLayer {
26 base: Canvas,
27 tracking_helper: Rc<TransformTrackingHelper>,
28}
29
30ferro_class!(AdornerLayer: Canvas);
31ferro_impl_classes!(AdornerLayer: StyledElementImpl, VisualImpl, InteractiveImpl, InputElementImpl, ControlImpl, PanelImpl, CanvasImpl);
32
33impl FerroObjectImpl for AdornerLayer {
34 fn constructed(this: &Self) {
35 Self::parent_constructed(this);
36
37 let weak = this.to_ref().downgrade();
38 this.children().add_collection_changed(Rc::new(
39 move |e: &NotifyCollectionChangedEventArgs<'_, Ref<Control>>| {
40 if let Some(this) = weak.upgrade() {
41 this.children_collection_changed(e);
42 }
43 },
44 ));
45
46 this.tracking_helper.set_visual(Some(&this.to_ref().upcast()));
47 let weak = this.to_ref().downgrade();
48 this.tracking_helper.matrix_changed(move || {
49 if let Some(this) = weak.upgrade() {
50 this.invalidate_measure();
51 }
52 });
53 }
54}
55
56impl LayoutableImpl for AdornerLayer {
57 fn measure_override(this: &Self, available_size: Size) -> Size {
58 for child in this.children().snapshot().iter() {
59 let info = child.get_value(Self::adorned_element_info_property());
60
61 match info.and_then(|info| info.0.adorned_element()) {
62 Some(adorned_element) => child.measure(adorned_element.bounds().size()),
63 None => child.measure(available_size),
64 }
65 }
66
67 Size::default()
68 }
69
70 fn arrange_override(this: &Self, final_size: Size) -> Size {
71 for child in this.children().snapshot().iter() {
72 let info = child.get_value(Self::adorned_element_info_property());
73 let is_clip_enabled = child.get_value(Self::is_clip_enabled_property());
74
75 let adorned = info.and_then(|info| info.0.adorned_element());
76
77 if let Some(adorned) = adorned {
78 child.arrange(Rect::from_size(adorned.bounds().size()));
79 let mut transform = adorned.transform_to_visual(this);
80 let position = child.bounds().position();
83 if let Some(value) = transform {
84 if position != Point::default() {
85 transform = Some(
86 Matrix::create_translation(position.x, position.y)
87 * value
88 * Matrix::create_translation(-position.x, -position.y),
89 );
90 }
91 }
92 let render_transform: Rc<dyn ITransform> =
93 MatrixTransform::with_matrix(transform.unwrap_or(ZERO_MATRIX)).into();
94 child.set_render_transform(Some(render_transform));
95 child.set_render_transform_origin(RelativePoint::new(0.0, 0.0, RelativeUnit::Absolute));
96 this.update_clip(child, &adorned, is_clip_enabled);
97 } else {
98 this.arrange_child(child, final_size);
99 }
100 }
101
102 final_size
103 }
104}
105
106const ZERO_MATRIX: Matrix = Matrix::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
109
110ferroui_base::ferro_properties! { impl AdornerLayer {
111 ferro_property!(
112 pub fn adorned_element_property() -> AttachedProperty<Option<ElementRef<Visual>>> {
114 ValueTypes::register_element_ref::<Visual>();
115 let property = FerroProperty::register_attached::<AdornerLayer, Visual, _>("AdornedElement", None);
116 property.changed().subscribe(Self::adorned_element_changed);
117 property
118 }
119 );
120
121 ferro_property!(
122 pub fn is_clip_enabled_property() -> AttachedProperty<bool> {
124 let property = FerroProperty::register_attached::<AdornerLayer, Visual, _>("IsClipEnabled", true);
125 property.changed().subscribe(Self::adorner_is_clip_enabled_changed);
126 property
127 }
128 );
129
130 ferro_property!(
131 pub fn adorner_property() -> AttachedProperty<Option<Ref<Control>>> {
133 let property = FerroProperty::register_attached::<AdornerLayer, Visual, _>("Adorner", None);
134 property.changed().subscribe(Self::adorner_changed);
135 property
136 }
137 );
138
139 ferro_property!(
140 pub fn default_focus_adorner_property() -> StyledProperty<Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>>> {
142 FerroProperty::register::<AdornerLayer, _>("DefaultFocusAdorner", None)
143 }
144 );
145
146 ferro_property!(
147 fn adorned_element_info_property() -> AttachedProperty<Option<AdornedElementInfoHandle>> {
148 FerroProperty::register_attached::<AdornerLayer, Visual, _>("AdornedElementInfo", None)
149 }
150 );
151
152 ferro_property!(
153 fn saved_adorner_layer_property() -> AttachedProperty<Option<SavedAdornerLayer>> {
154 FerroProperty::register_attached::<Visual, Visual, _>("SavedAdornerLayer", None)
155 }
156 );
157
158 ferro_property!(
159 fn adorner_attachment_subscriptions_property() -> AttachedProperty<Option<AttachmentSubscriptions>> {
162 FerroProperty::register_attached::<AdornerLayer, Visual, _>("AdornerAttachmentSubscriptions", None)
163 }
164 );
165} }
166
167impl AdornerLayer {
168 pub(crate) fn new() -> Ref<Self> {
171 instantiate(Self { base: Canvas::construct(), tracking_helper: TransformTrackingHelper::new(false) })
172 }
173
174 pub fn get_adorned_element(adorner: &Visual) -> Option<Ref<Visual>> {
175 ElementRef::resolve(&adorner.get_value(Self::adorned_element_property()))
176 }
177
178 pub fn set_adorned_element(adorner: &Visual, adorned: impl Into<Nullable<Visual>>) {
179 adorner.set_value(Self::adorned_element_property(), ElementRef::from_nullable(adorned.into().0))
180 }
181
182 pub fn get_adorner_layer(visual: &Visual) -> Option<Ref<AdornerLayer>> {
186 for ancestor in visual.get_self_and_visual_ancestors() {
188 if let Some(adorner_layer) = Self::get_direct_adorner_layer(&ancestor) {
189 return Some(adorner_layer);
190 }
191 }
192
193 if let Some(top_level) = TopLevel::get_top_level(Some(visual)) {
194 for descendant in top_level.get_visual_descendants() {
195 if let Some(adorner_layer) = Self::get_direct_adorner_layer(&descendant) {
196 return Some(adorner_layer);
197 }
198 }
199 }
200
201 None
202 }
203
204 fn get_direct_adorner_layer(visual: &Ref<Visual>) -> Option<Ref<AdornerLayer>> {
205 if let Some(adorner_layer) = visual.cast::<OverlayLayer>().and_then(|overlay| overlay.adorner_layer()) {
206 return Some(adorner_layer);
207 }
208 if let Some(vlm) = visual.cast::<VisualLayerManager>() {
209 return vlm.adorner_layer();
210 }
211 None
212 }
213
214 pub fn get_is_clip_enabled(adorner: &Visual) -> bool {
215 adorner.get_value(Self::is_clip_enabled_property())
216 }
217
218 pub fn set_is_clip_enabled(adorner: &Visual, is_clip_enabled: bool) {
219 adorner.set_value(Self::is_clip_enabled_property(), is_clip_enabled)
220 }
221
222 pub fn get_adorner(visual: &Visual) -> Option<Ref<Control>> {
223 visual.get_value(Self::adorner_property())
224 }
225
226 pub fn set_adorner(visual: &Visual, adorner: impl Into<Nullable<Control>>) {
227 visual.set_value(Self::adorner_property(), adorner.into().0)
228 }
229
230 pub fn default_focus_adorner(&self) -> Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>> {
232 self.get_value(Self::default_focus_adorner_property())
233 }
234
235 pub fn set_default_focus_adorner(&self, value: Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>>) {
236 self.set_value(Self::default_focus_adorner_property(), value)
237 }
238
239 fn adorner_changed(e: &FerroPropertyChangedEventArgs<'_>) {
240 let Some(visual) = e.sender().downcast_ref::<Visual>() else { return };
241 let (old_adorner, new_adorner) = e.get_old_and_new_value::<Option<Ref<Control>>>();
242
243 if old_adorner == new_adorner {
244 return;
245 }
246
247 if let Some(old_adorner) = old_adorner {
248 if let Some(subscriptions) = visual.get_value(Self::adorner_attachment_subscriptions_property()) {
249 for subscription in subscriptions.0.iter() {
250 subscription.dispose();
251 }
252 }
253 visual.clear_value(Self::adorner_attachment_subscriptions_property());
254 Self::detach(visual, &old_adorner);
255 }
256
257 if let Some(new_adorner) = new_adorner {
258 let weak = visual.to_ref().downgrade();
259 let attached = visual.attached_to_visual_tree(move |_| {
260 if let Some(visual) = weak.upgrade() {
261 Self::visual_on_attached_to_visual_tree(&visual);
262 }
263 });
264 let weak = visual.to_ref().downgrade();
265 let detached = visual.detached_from_visual_tree(move |_| {
266 if let Some(visual) = weak.upgrade() {
267 Self::visual_on_detached_from_visual_tree(&visual);
268 }
269 });
270 visual.set_value(
271 Self::adorner_attachment_subscriptions_property(),
272 Some(AttachmentSubscriptions(Rc::new([attached, detached]))),
273 );
274 Self::attach(visual, &new_adorner);
275 }
276 }
277
278 fn visual_on_attached_to_visual_tree(visual: &Visual) {
279 if let Some(adorner) = Self::get_adorner(visual) {
280 Self::attach(visual, &adorner);
281 }
282 }
283
284 fn visual_on_detached_from_visual_tree(visual: &Visual) {
285 if let Some(adorner) = Self::get_adorner(visual) {
286 Self::detach(visual, &adorner);
287 }
288 }
289
290 fn attach(visual: &Visual, adorner: &Ref<Control>) {
291 let layer = AdornerLayer::get_adorner_layer(visual);
292 Self::add_visual_adorner(visual, adorner, layer.as_ref());
293 visual.set_value(
294 Self::saved_adorner_layer_property(),
295 layer.map(|layer| SavedAdornerLayer(layer.downgrade())),
296 );
297 }
298
299 fn detach(visual: &Visual, adorner: &Ref<Control>) {
300 let layer = visual.get_value(Self::saved_adorner_layer_property()).and_then(|layer| layer.0.upgrade());
301 Self::remove_visual_adorner(adorner, layer.as_ref());
302 visual.clear_value(Self::saved_adorner_layer_property());
303 }
304
305 fn add_visual_adorner(visual: &Visual, adorner: &Ref<Control>, layer: Option<&Ref<AdornerLayer>>) {
306 let Some(layer) = layer else { return };
307 if layer.children().contains(adorner) {
308 return;
309 }
310
311 Self::set_adorned_element(adorner, visual.to_ref());
312
313 adorner.set_parent(visual.to_ref().upcast::<StyledElement>());
314 layer.children().add(adorner.clone());
315 }
316
317 fn remove_visual_adorner(adorner: &Ref<Control>, layer: Option<&Ref<AdornerLayer>>) {
318 let Some(layer) = layer else { return };
319 if !layer.children().contains(adorner) {
320 return;
321 }
322
323 layer.children().remove(adorner.clone());
324 adorner.set_parent(None);
325 }
326
327 fn adorned_element_changed(e: &FerroPropertyChangedEventArgs<'_>) {
328 let Some(adorner) = e.sender().downcast_ref::<Visual>() else { return };
329 let adorned = Self::get_adorned_element(adorner);
330 if let Some(layer) = adorner.get_visual_parent_of_type::<AdornerLayer>() {
331 layer.update_adorned_element(adorner, adorned);
332 }
333 }
334
335 fn adorner_is_clip_enabled_changed(e: &FerroPropertyChangedEventArgs<'_>) {
336 let Some(adorner) = e.sender().downcast_ref::<Visual>() else { return };
337 if let Some(info) = adorner.get_value(Self::adorned_element_info_property()) {
338 info.0.update_subscription();
339 if let Some(layer) = info.0.layer() {
340 layer.invalidate_measure();
341 }
342 }
343 }
344
345 fn update_clip(&self, control: &Control, adorned: &Visual, is_enabled: bool) {
346 if !is_enabled {
347 control.set_clip(None);
348 return;
349 }
350
351 control.set_clip(AdornerHelper::calculate_adorner_clip(adorned));
352 }
353
354 fn children_collection_changed(&self, e: &NotifyCollectionChangedEventArgs<'_, Ref<Control>>) {
355 if e.action == NotifyCollectionChangedAction::Add {
356 for i in e.new_items.iter() {
357 self.update_adorned_element(i, Self::get_adorned_element(i));
358 }
359 } else {
360 for i in e.old_items.iter() {
366 if let Some(info) = i.get_value(Self::adorned_element_info_property()) {
367 if let Some(subscription) = info.0.subscription.borrow_mut().take() {
368 subscription.dispose();
369 }
370 }
371 }
372 }
373
374 self.invalidate_arrange();
375 }
376
377 fn update_adorned_element(&self, adorner: &Visual, adorned: Option<Ref<Visual>>) {
378 if let Some(composition_visual) = adorner.composition_visual() {
379 let adorned_visual = adorned.as_ref().and_then(|adorned| adorned.composition_visual());
380 composition_visual.set_adorned_visual(adorned_visual.map(|visual| (*visual).clone()));
381 composition_visual.set_adorner_is_clipped(Self::get_is_clip_enabled(adorner));
382 }
383
384 let mut info = adorner.get_value(Self::adorned_element_info_property());
385
386 if let Some(existing) = &info {
387 if let Some(subscription) = existing.0.subscription.borrow().clone() {
388 subscription.dispose();
389 }
390
391 if adorned.is_none() {
392 adorner.clear_value(Self::adorned_element_info_property());
393 }
394 }
395
396 if let Some(adorned) = adorned {
397 let info = match info.take() {
398 Some(info) => info,
399 None => {
400 let info = AdornedElementInfoHandle(Rc::new(AdornedElementInfo {
401 adorner: adorner.to_ref().downgrade(),
402 layer: RefCell::new(None),
403 subscription: RefCell::new(None),
404 adorned_element: RefCell::new(None),
405 }));
406 adorner.set_value(Self::adorned_element_info_property(), Some(info.clone()));
407 info
408 }
409 };
410
411 *info.0.layer.borrow_mut() = Some(self.to_ref().downgrade());
412 *info.0.adorned_element.borrow_mut() = Some(adorned.downgrade());
413 info.0.update_subscription();
414 }
415 }
416}
417
418struct AdornedElementInfo {
421 adorner: WeakRef<Visual>,
422 layer: RefCell<Option<WeakRef<AdornerLayer>>>,
423 subscription: RefCell<Option<Rc<dyn IDisposable>>>,
424 adorned_element: RefCell<Option<WeakRef<Visual>>>,
425}
426
427impl AdornedElementInfo {
428 fn layer(&self) -> Option<Ref<AdornerLayer>> {
429 self.layer.borrow().as_ref().and_then(WeakRef::upgrade)
430 }
431
432 fn adorned_element(&self) -> Option<Ref<Visual>> {
433 self.adorned_element.borrow().as_ref().and_then(WeakRef::upgrade)
434 }
435
436 fn update_subscription(self: &Rc<Self>) {
437 let subscription = self.subscription.borrow_mut().take();
438 if let Some(subscription) = subscription {
439 subscription.dispose();
440 }
441
442 if let Some(adorned_element) = self.adorned_element() {
443 let include_clip =
444 self.adorner.upgrade().map(|adorner| AdornerLayer::get_is_clip_enabled(&adorner)).unwrap_or(true);
445 let weak = Rc::downgrade(self);
446 let subscription =
447 AdornerHelper::subscribe_to_ancestor_property_changes(&adorned_element, include_clip, move || {
448 if let Some(layer) = weak.upgrade().and_then(|info| info.layer()) {
449 layer.invalidate_measure();
450 }
451 });
452 *self.subscription.borrow_mut() = Some(subscription);
453 }
454 }
455}
456
457#[derive(Clone)]
458struct AdornedElementInfoHandle(Rc<AdornedElementInfo>);
459
460impl PartialEq for AdornedElementInfoHandle {
461 fn eq(&self, other: &Self) -> bool {
462 Rc::ptr_eq(&self.0, &other.0)
463 }
464}
465
466#[derive(Clone)]
467struct SavedAdornerLayer(WeakRef<AdornerLayer>);
468
469impl PartialEq for SavedAdornerLayer {
470 fn eq(&self, other: &Self) -> bool {
471 self.0.upgrade() == other.0.upgrade()
472 }
473}
474
475#[derive(Clone)]
476struct AttachmentSubscriptions(Rc<[Rc<dyn IDisposable>; 2]>);
477
478impl PartialEq for AttachmentSubscriptions {
479 fn eq(&self, other: &Self) -> bool {
480 Rc::ptr_eq(&self.0, &other.0)
481 }
482}