///|
priv struct ElementEventResult {
changed : Bool
activated : Bool
captured : Bool
capture_target : ElementId?
focused : ElementId?
deliveries : Array[() -> Unit]
}
///|
fn ElementNode::has_dirty_layout(self : ElementNode) -> Bool {
self.dirty.has_layout()
}
///|
fn ElementNode::has_dirty_paint(self : ElementNode) -> Bool {
self.dirty.has_paint()
}
///|
fn ElementNode::has_dirty_platform(self : ElementNode) -> Bool {
self.dirty.has_platform()
}
///|
fn ElementNode::has_dirty_semantics(self : ElementNode) -> Bool {
self.dirty.has_semantics()
}
///|
fn ElementNode::refresh_descendant_dirty_flags(self : ElementNode) -> Unit {
self.dirty.descendant_build = self.children.any(child => {
child.dirty.has_build()
})
self.dirty.descendant_layout = self.children.any(child => {
child.dirty.has_layout()
})
self.dirty.descendant_paint = self.children.any(child => {
child.dirty.has_paint()
})
self.dirty.descendant_semantics = self.children.any(child => {
child.dirty.has_semantics()
})
self.dirty.descendant_platform = self.children.any(child => {
child.dirty.has_platform()
})
}
///|
fn ElementNode::view_tree_inspector_snapshot(
self : ElementNode,
) -> ViewTreeInspectorSnapshot {
let nodes : Array[ViewInspectorSummary] = []
self.collect_view_summaries(nodes, depth=0)
{
root_kind: runtime_view_node_inspector_kind_label(self.view_node),
node_count: nodes.length(),
control_count: self.inspector_control_count(),
modified_count: self.inspector_modified_count(),
dirty_build_count: nodes.filter(node => node.needs_build).length(),
dirty_layout_count: nodes.filter(node => node.needs_layout).length(),
dirty_paint_count: nodes.filter(node => node.needs_paint).length(),
nodes,
}
}
///|
fn ElementNode::inspector_layout_cache_hits(self : ElementNode) -> Int {
let mut total = self.layout_cache.hit_count
for child in self.children {
total = total + child.inspector_layout_cache_hits()
}
total
}
///|
fn ElementNode::inspector_layout_cache_misses(self : ElementNode) -> Int {
let mut total = self.layout_cache.miss_count
for child in self.children {
total = total + child.inspector_layout_cache_misses()
}
total
}
///|
fn ElementNode::inspector_render_cache_hits(self : ElementNode) -> Int {
let mut total = self.render_cache.hit_count
for child in self.children {
total = total + child.inspector_render_cache_hits()
}
total
}
///|
fn ElementNode::inspector_render_cache_misses(self : ElementNode) -> Int {
let mut total = self.render_cache.miss_count
for child in self.children {
total = total + child.inspector_render_cache_misses()
}
total
}
///|
fn ElementNode::inspector_hit_path(
self : ElementNode,
point : @core.Point,
render : RenderNode,
) -> Array[Int] {
let path = [self.id.value()]
let mut index = self.children.length() - 1
while index >= 0 {
if index < render.children.length() &&
render.children[index].hit_bounds().contains(point) {
path.append(
self.children[index].inspector_hit_path(point, render.children[index]),
)
return path
}
index = index - 1
}
path
}
///|
fn ElementNode::collect_view_summaries(
self : ElementNode,
nodes : Array[ViewInspectorSummary],
depth~ : Int,
) -> Unit {
nodes.push({
element_id: self.id.value(),
kind: runtime_view_node_inspector_kind_label(self.view_node),
key: match self.key {
Some(key) => key.value()
None => ""
},
depth,
child_count: self.children.length(),
needs_build: self.dirty.needs_build,
needs_layout: self.dirty.needs_layout,
needs_paint: self.dirty.needs_paint,
})
for child in self.children {
child.collect_view_summaries(nodes, depth=depth + 1)
}
}
///|
fn ElementNode::inspector_control_count(self : ElementNode) -> Int {
let mut count = if runtime_view_node_inspector_is_control(self.view_node) {
1
} else {
0
}
for child in self.children {
count = count + child.inspector_control_count()
}
count
}
///|
fn ElementNode::inspector_modified_count(self : ElementNode) -> Int {
let mut count = if self.view_node.identity().kind.has_prefix("Modified<") {
1
} else {
0
}
for child in self.children {
count = count + child.inspector_modified_count()
}
count
}
///|
fn ElementNode::mark_paint_dirty_by_id(
self : ElementNode,
id : ElementId,
) -> Bool {
if self.id == id {
self.dirty.mark_paint()
self.render_cache.clear()
true
} else {
for child in self.children {
if child.mark_paint_dirty_by_id(id) {
self.dirty.mark_paint_descendant()
self.render_cache.invalidate_composition()
return true
}
}
false
}
}
///|
fn ElementNode::mark_semantics_dirty_by_id(
self : ElementNode,
id : ElementId,
) -> Bool {
if self.id == id {
self.dirty.mark_semantics()
true
} else {
for child in self.children {
if child.mark_semantics_dirty_by_id(id) {
self.dirty.mark_semantics_descendant()
return true
}
}
false
}
}
///|
fn ElementNode::invalidate_uncommitted_semantics(self : ElementNode) -> Unit {
// Nodes omitted from the committed tree stay invalidated. That lets hidden
// and merged descendants rebuild their contribution when an ancestor needs
// it again without retaining an unreachable duplicate subtree.
self.dirty.needs_semantics = true
self.semantics_cache.clear()
for child in self.children {
child.invalidate_uncommitted_semantics()
}
}
///|
fn ElementNode::mark_platform_dirty_by_id(
self : ElementNode,
id : ElementId,
) -> Bool {
if self.id == id {
self.dirty.mark_platform()
true
} else {
for child in self.children {
if child.mark_platform_dirty_by_id(id) {
self.dirty.mark_platform_descendant()
return true
}
}
false
}
}
///|
fn ElementNode::collect_dirty_element_ids_by_kind(
self : ElementNode,
all_ids : DirtyIdSet,
build_ids : DirtyIdSet,
layout_ids : DirtyIdSet,
paint_ids : DirtyIdSet,
semantics_ids : DirtyIdSet,
platform_ids : DirtyIdSet,
) -> Unit {
if self.dirty.needs_build ||
self.dirty.needs_layout ||
self.dirty.needs_paint ||
self.dirty.needs_semantics ||
self.dirty.needs_platform {
all_ids.push(self.id)
}
if self.dirty.needs_build {
build_ids.push(self.id)
}
if self.dirty.needs_layout {
layout_ids.push(self.id)
}
if self.dirty.needs_paint {
paint_ids.push(self.id)
}
if self.dirty.needs_semantics {
semantics_ids.push(self.id)
}
if self.dirty.needs_platform {
platform_ids.push(self.id)
}
for child in self.children {
child.collect_dirty_element_ids_by_kind(
all_ids, build_ids, layout_ids, paint_ids, semantics_ids, platform_ids,
)
}
}
///|
fn ElementNode::mark_subtree_layout_dirty(self : ElementNode) -> Unit {
self.dirty.mark_layout()
self.clear_cached_layout_and_paint()
for child in self.children {
child.mark_subtree_layout_dirty()
}
}
///|
fn ElementNode::clear_cached_layout_and_paint(self : ElementNode) -> Unit {
self.layout_cache.clear()
self.render_cache.clear()
}