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