use super::ServerCompositionVisual;
use crate::Matrix;
use std::cell::{Cell, RefCell};
use std::rc::{Rc, Weak};
#[derive(Clone)]
pub(super) enum ActSubscriber {
CombinedTransformChanged(Weak<ServerCompositionVisual>),
AdornedVisualWorldTransformChanged(Weak<ServerCompositionVisual>),
}
impl ActSubscriber {
fn same(&self, other: &ActSubscriber) -> bool {
match (self, other) {
(ActSubscriber::CombinedTransformChanged(a), ActSubscriber::CombinedTransformChanged(b)) => {
Weak::ptr_eq(a, b)
}
(
ActSubscriber::AdornedVisualWorldTransformChanged(a),
ActSubscriber::AdornedVisualWorldTransformChanged(b),
) => Weak::ptr_eq(a, b),
_ => false,
}
}
fn invoke(&self) {
match self {
ActSubscriber::CombinedTransformChanged(visual) => {
if let Some(visual) = visual.upgrade() {
visual.att_helper_combined_transform_changed();
}
}
ActSubscriber::AdornedVisualWorldTransformChanged(visual) => {
if let Some(visual) = visual.upgrade() {
visual.adorner_helper_enqueue_for_adorner_update();
}
}
}
}
}
#[derive(Default)]
pub(super) struct AttHelper {
pub(super) ancestor_chain_transform_subscribers: RefCell<Vec<ActSubscriber>>,
pub(super) enqueued_for_adorner_update: Cell<bool>,
}
impl ServerCompositionVisual {
fn parent_act_subscription_action(&self) -> ActSubscriber {
ActSubscriber::CombinedTransformChanged(self.this.clone())
}
pub(super) fn adorned_visual_act_subscription_action(&self) -> ActSubscriber {
ActSubscriber::AdornedVisualWorldTransformChanged(self.this.clone())
}
pub fn ancestor_transform_subscriber_count(&self) -> usize {
self.att_helper.ancestor_chain_transform_subscribers.borrow().len()
}
pub(super) fn att_helper_combined_transform_changed(&self) {
if self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
return;
}
let subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow().clone();
for subscriber in subscribers {
subscriber.invoke();
}
}
pub(super) fn att_helper_parent_changing(&self) {
if let Some(parent) = self.parent() {
if !self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
parent.att_helper_unsubscribe_from_act_notification(&self.parent_act_subscription_action());
}
}
}
pub(super) fn att_helper_parent_changed(&self) {
let parent = self.parent();
if let Some(parent) = &parent {
if !self.att_helper.ancestor_chain_transform_subscribers.borrow().is_empty() {
parent.att_helper_subscribe_to_act_notification(self.parent_act_subscription_action());
}
}
if parent.is_some() && self.adorned_visual().is_some() {
self.adorner_helper_enqueue_for_adorner_update();
}
}
pub(super) fn att_helper_subscribe_to_act_notification(&self, cb: ActSubscriber) {
let count = {
let mut subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow_mut();
if !subscribers.iter().any(|s| s.same(&cb)) {
subscribers.push(cb);
}
subscribers.len()
};
if count == 1 {
if let Some(parent) = self.parent() {
parent.att_helper_subscribe_to_act_notification(self.parent_act_subscription_action());
}
}
}
pub(super) fn att_helper_unsubscribe_from_act_notification(&self, cb: &ActSubscriber) {
let count = {
let mut subscribers = self.att_helper.ancestor_chain_transform_subscribers.borrow_mut();
subscribers.retain(|s| !s.same(cb));
subscribers.len()
};
if count == 0 {
if let Some(parent) = self.parent() {
parent.att_helper_unsubscribe_from_act_notification(&self.parent_act_subscription_action());
}
}
}
pub(super) fn compute_transform_from_ancestor(
visual: &Rc<ServerCompositionVisual>,
ancestor: &Rc<ServerCompositionVisual>,
) -> Option<Matrix> {
let mut transform = visual.own_transform.get().unwrap_or(Matrix::IDENTITY);
let mut visual = visual.clone();
while let Some(parent) = visual.parent() {
visual = parent;
if Rc::ptr_eq(&visual, ancestor) {
return Some(transform);
}
if let Some(own_transform) = visual.own_transform.get() {
transform = transform * own_transform;
}
}
None
}
}