Skip to main content

fission_core/input/
slider.rs

1use super::{ControllerContext, InputController};
2use crate::event::{InputEvent, PointerEvent};
3use crate::{ActionEnvelope, ActionId};
4use fission_ir::{op::Op, semantics::Role, NodeId};
5use serde_json;
6
7pub struct SliderController;
8
9impl InputController for SliderController {
10    fn handle_event(&mut self, ctx: &mut ControllerContext, event: &InputEvent) -> bool {
11        match event {
12            InputEvent::Pointer(PointerEvent::Down { point, .. }) => {
13                if let Some(hit_id) =
14                    crate::hit_test::hit_test_with_scroll(ctx.ir, ctx.layout, ctx.scroll, *point)
15                {
16                    let mut current_id = Some(hit_id);
17                    while let Some(node_id) = current_id {
18                        if let Some(node) = ctx.ir.nodes.get(&node_id) {
19                            if let Op::Semantics(sem) = &node.op {
20                                if sem.role == Role::Slider {
21                                    ctx.interaction.set_focused(Some(node_id));
22                                    ctx.interaction.set_pressed(node_id, true);
23
24                                    self.update_value(ctx, node_id, point.x);
25                                    return true;
26                                }
27                            }
28                            current_id = node.parent;
29                        } else {
30                            break;
31                        }
32                    }
33                }
34            }
35            InputEvent::Pointer(PointerEvent::Move { point, .. }) => {
36                if let Some(focused_id) = ctx.interaction.focused {
37                    if ctx.interaction.is_pressed(focused_id) {
38                        if let Some(node) = ctx.ir.nodes.get(&focused_id) {
39                            if let Op::Semantics(sem) = &node.op {
40                                if sem.role == Role::Slider {
41                                    self.update_value(ctx, focused_id, point.x);
42                                    return true;
43                                }
44                            }
45                        }
46                    }
47                }
48            }
49            _ => {}
50        }
51        false
52    }
53}
54
55impl SliderController {
56    fn update_value(&self, ctx: &mut ControllerContext, node_id: NodeId, point_x: f32) {
57        if let Some(geom) = ctx.layout.get_node_geometry(node_id) {
58            if let Some(node) = ctx.ir.nodes.get(&node_id) {
59                if let Op::Semantics(sem) = &node.op {
60                    let min = sem.min_value.unwrap_or(0.0);
61                    let max = sem.max_value.unwrap_or(1.0);
62
63                    // Note: Slider semantics nodes often wrap the layout node directly.
64                    // Layout traversal records geometry for all nodes, including semantics
65                    // wrappers, so the semantics geometry should match its child.
66
67                    let width = geom.rect.width();
68                    if width > 0.0 {
69                        let local_x = point_x - geom.rect.x();
70                        let t = (local_x / width).clamp(0.0, 1.0);
71                        let new_val = min + t * (max - min);
72
73                        if let Some(entry) = sem.actions.entries.first() {
74                            let payload = serde_json::to_vec(&new_val).unwrap();
75                            let envelope = ActionEnvelope {
76                                id: ActionId::from_u128(entry.action_id),
77                                payload,
78                            };
79                            let input = crate::input::scoped_action_input(
80                                ctx.ir,
81                                node_id,
82                                crate::ActionInput::None,
83                            );
84                            ctx.dispatched_actions.push((node_id, envelope, input));
85                        }
86                    }
87                }
88            }
89        }
90    }
91}