ferroui_base/rendering/composition/server/server_composition_visual/
act.rs1use super::ServerCompositionVisual;
9use crate::Matrix;
10use std::cell::{Cell, RefCell};
11use std::rc::{Rc, Weak};
12
13#[derive(Clone)]
16pub(super) enum ActSubscriber {
17 CombinedTransformChanged(Weak<ServerCompositionVisual>),
20 AdornedVisualWorldTransformChanged(Weak<ServerCompositionVisual>),
23}
24
25impl ActSubscriber {
26 fn same(&self, other: &ActSubscriber) -> bool {
27 match (self, other) {
28 (ActSubscriber::CombinedTransformChanged(a), ActSubscriber::CombinedTransformChanged(b)) => {
29 Weak::ptr_eq(a, b)
30 }
31 (
32 ActSubscriber::AdornedVisualWorldTransformChanged(a),
33 ActSubscriber::AdornedVisualWorldTransformChanged(b),
34 ) => Weak::ptr_eq(a, b),
35 _ => false,
36 }
37 }
38
39 fn invoke(&self) {
40 match self {
41 ActSubscriber::CombinedTransformChanged(visual) => {
42 if let Some(visual) = visual.upgrade() {
43 visual.att_helper_combined_transform_changed();
44 }
45 }
46 ActSubscriber::AdornedVisualWorldTransformChanged(visual) => {
47 if let Some(visual) = visual.upgrade() {
48 visual.adorner_helper_enqueue_for_adorner_update();
49 }
50 }
51 }
52 }
53}
54
55#[derive(Default)]
56pub(super) struct AttHelper {
57 pub(super) ancestor_chain_transform_subscribers: RefCell<Vec<ActSubscriber>>,
58 pub(super) enqueued_for_adorner_update: Cell<bool>,
60}
61
62impl ServerCompositionVisual {
63 fn parent_act_subscription_action(&self) -> ActSubscriber {
64 ActSubscriber::CombinedTransformChanged(self.this.clone())
65 }
66
67 pub(super) fn adorned_visual_act_subscription_action(&self) -> ActSubscriber {
68 ActSubscriber::AdornedVisualWorldTransformChanged(self.this.clone())
69 }
70
71 pub fn ancestor_transform_subscriber_count(&self) -> usize {
76 self.att_helper.ancestor_chain_transform_subscribers.borrow().len()
77 }
78
79 pub(super) fn att_helper_combined_transform_changed(&self) {
80 if self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
81 return;
82 }
83 let subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow().clone();
84 for subscriber in subscribers {
85 subscriber.invoke();
86 }
87 }
88
89 pub(super) fn att_helper_parent_changing(&self) {
90 if let Some(parent) = self.parent() {
91 if !self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
92 parent.att_helper_unsubscribe_from_act_notification(&self.parent_act_subscription_action());
93 }
94 }
95 }
96
97 pub(super) fn att_helper_parent_changed(&self) {
98 let parent = self.parent();
99 if let Some(parent) = &parent {
100 if !self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
101 parent.att_helper_subscribe_to_act_notification(self.parent_act_subscription_action());
102 }
103 }
104 if parent.is_some() && self.adorned_visual().is_some() {
105 self.adorner_helper_enqueue_for_adorner_update();
106 }
107 }
108
109 pub(super) fn att_helper_subscribe_to_act_notification(&self, cb: ActSubscriber) {
110 let count = {
111 let mut subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow_mut();
112 if !subscribers.iter().any(|s| s.same(&cb)) {
113 subscribers.push(cb);
114 }
115 subscribers.len()
116 };
117 if count == 1 {
118 if let Some(parent) = self.parent() {
119 parent.att_helper_subscribe_to_act_notification(self.parent_act_subscription_action());
120 }
121 }
122 }
123
124 pub(super) fn att_helper_unsubscribe_from_act_notification(&self, cb: &ActSubscriber) {
125 let count = {
126 let mut subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow_mut();
127 subscribers.retain(|s| !s.same(cb));
128 subscribers.len()
129 };
130 if count == 0 {
131 if let Some(parent) = self.parent() {
132 parent.att_helper_unsubscribe_from_act_notification(&self.parent_act_subscription_action());
133 }
134 }
135 }
136
137 pub(super) fn compute_transform_from_ancestor(
140 visual: &Rc<ServerCompositionVisual>,
141 ancestor: &Rc<ServerCompositionVisual>,
142 ) -> Option<Matrix> {
143 let mut transform = visual.own_transform.get().unwrap_or(Matrix::IDENTITY);
144 let mut visual = visual.clone();
145 while let Some(parent) = visual.parent() {
146 visual = parent;
147 if Rc::ptr_eq(&visual, ancestor) {
148 return Some(transform);
150 }
151 if let Some(own_transform) = visual.own_transform.get() {
152 transform = transform * own_transform;
153 }
154 }
155 None
157 }
158}