use std::any::{Any, TypeId};
use smallvec::SmallVec;
use crate::{
Applier, Command, Composer, DirtyBubble, NodeError, NodeId, composer_context,
with_current_composer,
};
pub fn with_node_mut<N: Node + 'static, R>(
id: NodeId,
f: impl FnOnce(&mut N) -> R,
) -> Result<R, NodeError> {
with_current_composer(|composer| composer.with_node_mut(id, f))
}
pub fn push_parent(id: NodeId) {
with_current_composer(|composer| composer.push_parent(id));
}
pub fn pop_parent() {
with_current_composer(Composer::pop_parent);
}
pub trait Node: Any {
fn mount(&mut self) {}
fn unmount(&mut self) {}
fn insert_child(&mut self, _child: NodeId) -> bool {
false
}
fn remove_child(&mut self, _child: NodeId) -> bool {
false
}
fn move_child(&mut self, _from: usize, _to: usize) {}
fn update_children(&mut self, _children: &[NodeId]) {}
fn keeps_own_children(&self) -> bool {
false
}
fn collect_children_into(&self, out: &mut SmallVec<[NodeId; 8]>) {
out.clear();
}
fn for_each_child(&self, f: &mut dyn FnMut(NodeId)) {
let mut children = SmallVec::<[NodeId; 8]>::new();
self.collect_children_into(&mut children);
for child in children {
f(child);
}
}
fn collect_owned_children_into(&self, out: &mut SmallVec<[NodeId; 8]>) {
self.collect_children_into(out);
}
fn owned_child_index(&self, child: NodeId) -> Option<usize> {
let mut children = SmallVec::<[NodeId; 8]>::new();
self.collect_owned_children_into(&mut children);
children.iter().position(|&id| id == child)
}
fn set_node_id(&mut self, _id: NodeId) {}
fn on_attached_to_parent(&mut self, _parent: NodeId) {}
fn on_removed_from_parent(&mut self) {}
fn parent(&self) -> Option<NodeId> {
None
}
fn mark_needs_layout(&self) {}
fn needs_layout(&self) -> bool {
false
}
fn mark_needs_measure(&self) {}
fn needs_measure(&self) -> bool {
false
}
fn mark_descendant_needs_layout(&self, measure: bool) {
if measure {
self.mark_needs_measure();
} else {
self.mark_needs_layout();
}
}
fn descendant_needs_layout(&self) -> bool {
false
}
fn descendant_needs_measure(&self) -> bool {
false
}
fn layout_dirty(&self) -> bool {
self.needs_measure() || self.needs_layout() || self.descendant_needs_layout()
}
fn is_virtual(&self) -> bool {
false
}
fn mark_needs_semantics(&self) {}
fn mark_descendant_needs_semantics(&self) {
self.mark_needs_semantics();
}
fn needs_semantics(&self) -> bool {
false
}
fn set_parent_for_bubbling(&mut self, parent: NodeId) {
if self.parent().is_none() {
self.on_attached_to_parent(parent);
}
}
fn recycle_key(&self) -> Option<TypeId> {
None
}
fn recycle_pool_limit(&self) -> Option<usize> {
None
}
fn prepare_for_recycle(&mut self) {}
fn rehouse_for_recycle(&self) -> Option<Box<dyn Node>> {
None
}
fn rehouse_for_live_compaction(&mut self) -> Option<Box<dyn Node>> {
None
}
fn debug_heap_bytes(&self) -> usize {
0
}
}
pub fn bubble_layout_dirty(applier: &mut dyn Applier, node_id: NodeId) {
DirtyBubble::LAYOUT.apply(applier, node_id);
}
pub fn bubble_measure_dirty(applier: &mut dyn Applier, node_id: NodeId) {
DirtyBubble::MEASURE.apply(applier, node_id);
}
pub fn bubble_semantics_dirty(applier: &mut dyn Applier, node_id: NodeId) {
DirtyBubble::SEMANTICS.apply(applier, node_id);
}
pub fn queue_semantics_invalidation(node_id: NodeId) {
let _ = composer_context::try_with_composer(|composer| {
composer.enqueue_semantics_invalidation(node_id);
});
}
pub fn bubble_layout_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
bubble_layout_dirty_composer::<N>(node_id);
}
pub fn bubble_measure_dirty_in_composer(node_id: NodeId) {
with_current_composer(|composer| {
composer.commands_mut().push(Command::BubbleDirty {
node_id,
bubble: DirtyBubble {
layout: false,
measure: true,
semantics: false,
},
});
});
}
pub fn bubble_semantics_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
bubble_semantics_dirty_composer::<N>(node_id);
}
fn bubble_layout_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
let _ = with_node_mut(node_id, |node: &mut N| {
node.mark_needs_layout();
});
with_current_composer(|composer| composer.borrow_applier().note_layout_dirt(node_id));
while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
let parent_id = pid;
let advanced = with_node_mut(parent_id, |node: &mut N| {
node.mark_descendant_needs_layout(false);
true
})
.unwrap_or(false);
if advanced {
node_id = parent_id;
} else {
break;
}
}
}
fn bubble_semantics_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
let _ = with_node_mut(node_id, |node: &mut N| {
node.mark_needs_semantics();
});
while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
let parent_id = pid;
let advanced = with_node_mut(parent_id, |node: &mut N| {
if !node.needs_semantics() {
node.mark_descendant_needs_semantics();
}
true
})
.unwrap_or(false);
if advanced {
node_id = parent_id;
} else {
break;
}
}
}
impl dyn Node {
pub fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}