fission_core/input/
mod.rs1use crate::env::{
2 Clipboard, ContextMenuState, InteractionStateMap, ScrollStateMap, SelectableTextStateMap,
3 TextEditStateMap,
4};
5use crate::event::InputEvent;
6use crate::{ActionEnvelope, ActionInput};
7use fission_ir::{CoreIR, Op, WidgetId};
8use fission_layout::{LayoutSnapshot, TextMeasurer};
9use std::sync::Arc;
10
11pub mod gesture;
12pub mod hover;
13pub mod selectable_text;
14pub mod slider;
15pub mod text;
16
17pub struct ControllerContext<'a> {
18 pub ir: &'a CoreIR,
19 pub layout: &'a LayoutSnapshot,
20 pub text_edit: &'a mut TextEditStateMap,
21 pub selectable_text: &'a mut SelectableTextStateMap,
22 pub context_menu: &'a mut ContextMenuState,
23 pub interaction: &'a mut InteractionStateMap,
24 pub scroll: &'a mut ScrollStateMap,
25 pub gesture: &'a mut crate::env::GestureState,
26 pub clipboard: Option<&'a Arc<dyn Clipboard>>,
27 pub measurer: Option<&'a Arc<dyn TextMeasurer>>,
28 pub dispatched_actions: Vec<(WidgetId, ActionEnvelope, ActionInput)>,
30}
31
32pub trait InputController {
33 fn handle_event(&mut self, ctx: &mut ControllerContext, event: &InputEvent) -> bool;
34}
35
36pub(crate) fn action_scope_for_node(ir: &CoreIR, node_id: WidgetId) -> Option<u128> {
37 let mut current_id = Some(node_id);
38 while let Some(id) = current_id {
39 let Some(node) = ir.nodes.get(&id) else {
40 break;
41 };
42 if let Op::Semantics(semantics) = &node.op {
43 if let Some(scope_id) = semantics.action_scope_id {
44 return Some(scope_id);
45 }
46 }
47 current_id = node.parent;
48 }
49 None
50}
51
52pub(crate) fn scoped_action_input(
53 ir: &CoreIR,
54 target: WidgetId,
55 input: ActionInput,
56) -> ActionInput {
57 if let Some(scope_id) = action_scope_for_node(ir, target) {
58 ActionInput::scoped_raw(scope_id, target, input)
59 } else {
60 input
61 }
62}