///|
fn ElementNode::dispatch_keyboard(
self : ElementNode,
target : ElementId,
event : KeyboardEvent,
environment? : Environment = Environment::neutral(),
style? : ViewStyle = ViewStyle::empty(),
text_system? : TextSystem = TextSystem::fallback(),
) -> ElementEventResult {
if self.id == target {
self.dispatch_view_event(
self.view_node,
Keyboard(event),
RenderNode::empty(),
text_system,
environment~,
style~,
focused=true,
)
} else {
let child_environment = self.view_node.child_environment(environment)
let child_style = self.view_node.child_style(style)
let mut changed = false
let mut activated = false
let deliveries : Array[() -> Unit] = []
for child in self.children {
let result = child.dispatch_keyboard(
target,
event,
environment=child_environment,
style=child_style,
text_system~,
)
changed = changed || result.changed
activated = activated || result.activated
deliveries.append(result.deliveries)
}
if changed {
self.dirty.mark_paint_descendant()
self.render_cache.invalidate_composition()
}
{
changed,
activated,
captured: false,
capture_target: None,
focused: None,
deliveries,
}
}
}
///|
fn ElementNode::dispatch_keyboard_shortcut(
self : ElementNode,
event : KeyboardEvent,
environment? : Environment = Environment::neutral(),
style? : ViewStyle = ViewStyle::empty(),
text_system? : TextSystem = TextSystem::fallback(),
) -> ElementEventResult {
// Keyboard policy is typed (ADR 0033): overlay hosts own top-most-first
// dismissal, keyboard-shortcut modifier scopes handle their own shortcuts.
let owns_dismissal = self.view_node.keyboard_policy() is TopMostDismissal
let is_shortcut_scope = self.view_node.keyboard_policy() is ShortcutScope
let own = if owns_dismissal {
// Give the host the first chance to consume Escape so a focused base
// control cannot observe the event before the top-most presentation
// dismisses. (The runtime layer stack runs hosts top-most-first before
// this tree dispatch; this pass stays for unconsumed fall-through.)
self.dispatch_view_event(
self.view_node,
Keyboard(event),
RenderNode::empty(),
text_system,
environment~,
style~,
)
} else {
{
changed: false,
activated: false,
captured: false,
capture_target: None,
focused: None,
deliveries: [],
}
}
if owns_dismissal && own.changed {
own
} else {
let child_result = self.dispatch_keyboard_shortcut_to_children(
event,
environment~,
style~,
text_system~,
)
if child_result.activated {
child_result
} else if is_shortcut_scope || owns_dismissal {
if owns_dismissal {
child_result
} else {
// Give the modifier node itself a chance to handle the keyboard event
// (so its `handle_keyboard_shortcut` runs). Only if the node reports a
// change (meaning the shortcut matched) do we activate the first child.
let scope_own = self.dispatch_view_event(
self.view_node,
Keyboard(event),
RenderNode::empty(),
text_system,
environment~,
style~,
)
if scope_own.changed {
self.activate_first_child(environment~, style~, text_system~)
} else if child_result.changed {
child_result
} else {
{
changed: false,
activated: false,
captured: false,
capture_target: None,
focused: None,
deliveries: [],
}
}
}
} else {
child_result
}
}
}
///|
fn ElementNode::dispatch_keyboard_shortcut_to_children(
self : ElementNode,
event : KeyboardEvent,
environment? : Environment = Environment::neutral(),
style? : ViewStyle = ViewStyle::empty(),
text_system? : TextSystem = TextSystem::fallback(),
) -> ElementEventResult {
let mut changed = false
let mut activated = false
let deliveries : Array[() -> Unit] = []
let child_environment = self.view_node.child_environment(environment)
let child_style = self.view_node.child_style(style)
for child in self.children {
let result = child.dispatch_keyboard_shortcut(
event,
environment=child_environment,
style=child_style,
text_system~,
)
changed = changed || result.changed
activated = activated || result.activated
deliveries.append(result.deliveries)
if result.activated {
break
}
}
if changed {
self.dirty.mark_paint_descendant()
self.render_cache.invalidate_composition()
}
{
changed,
activated,
captured: false,
capture_target: None,
focused: None,
deliveries,
}
}
///|
fn ElementNode::activate_primary(
self : ElementNode,
environment? : Environment = Environment::neutral(),
style? : ViewStyle = ViewStyle::empty(),
text_system? : TextSystem = TextSystem::fallback(),
) -> ElementEventResult {
let child_result = self.activate_first_child(
environment~,
style~,
text_system~,
)
if child_result.activated {
child_result
} else {
self.dispatch_view_event(
self.view_node,
Keyboard(KeyboardEvent::new(key="Enter")),
RenderNode::empty(),
text_system,
environment~,
style~,
)
}
}
///|
fn ElementNode::activate_first_child(
self : ElementNode,
environment? : Environment = Environment::neutral(),
style? : ViewStyle = ViewStyle::empty(),
text_system? : TextSystem = TextSystem::fallback(),
) -> ElementEventResult {
let child_environment = self.view_node.child_environment(environment)
let child_style = self.view_node.child_style(style)
for child in self.children {
let result = child.activate_primary(
environment=child_environment,
style=child_style,
text_system~,
)
if result.activated || result.changed {
return result
}
}
{
changed: false,
activated: false,
captured: false,
capture_target: None,
focused: None,
deliveries: [],
}
}