spitfire_gui/
interactions.rs

1use raui_core::prelude::*;
2use spitfire_input::{ArrayInputCombinator, InputActionRef, InputCharactersRef};
3
4const ZERO_THRESHOLD: f32 = 1.0e-6;
5
6#[derive(Default)]
7pub struct GuiInteractionsInputs {
8    pub trigger: InputActionRef,
9    pub context: InputActionRef,
10    pub cancel: InputActionRef,
11    pub left: InputActionRef,
12    pub right: InputActionRef,
13    pub up: InputActionRef,
14    pub down: InputActionRef,
15    pub prev: InputActionRef,
16    pub next: InputActionRef,
17    pub text: InputCharactersRef,
18    pub text_start: InputActionRef,
19    pub text_end: InputActionRef,
20    pub text_delete_left: InputActionRef,
21    pub text_delete_right: InputActionRef,
22    pub pointer_position: ArrayInputCombinator<2>,
23    pub pointer_trigger: InputActionRef,
24    pub pointer_context: InputActionRef,
25    pub scroll: ArrayInputCombinator<2>,
26}
27
28#[derive(Default)]
29pub struct GuiInteractionsEngine {
30    pub inputs: GuiInteractionsInputs,
31    pub engine: DefaultInteractionsEngine,
32    cached_pointer_position: Vec2,
33}
34
35impl GuiInteractionsEngine {
36    pub fn maintain(&mut self, mapping: &CoordsMapping) {
37        if self.engine.focused_text_input().is_some() {
38            if let Some(mut text) = self.inputs.text.write() {
39                for character in text.take().chars() {
40                    self.engine
41                        .interact(Interaction::Navigate(NavSignal::TextChange(
42                            NavTextChange::InsertCharacter(character),
43                        )));
44                }
45            }
46            if self.inputs.left.get().is_pressed() {
47                self.engine
48                    .interact(Interaction::Navigate(NavSignal::TextChange(
49                        NavTextChange::MoveCursorLeft,
50                    )));
51            }
52            if self.inputs.right.get().is_pressed() {
53                self.engine
54                    .interact(Interaction::Navigate(NavSignal::TextChange(
55                        NavTextChange::MoveCursorRight,
56                    )));
57            }
58            if self.inputs.text_start.get().is_pressed() {
59                self.engine
60                    .interact(Interaction::Navigate(NavSignal::TextChange(
61                        NavTextChange::MoveCursorStart,
62                    )));
63            }
64            if self.inputs.text_end.get().is_pressed() {
65                self.engine
66                    .interact(Interaction::Navigate(NavSignal::TextChange(
67                        NavTextChange::MoveCursorEnd,
68                    )));
69            }
70            if self.inputs.text_delete_left.get().is_pressed() {
71                self.engine
72                    .interact(Interaction::Navigate(NavSignal::TextChange(
73                        NavTextChange::DeleteLeft,
74                    )));
75            }
76            if self.inputs.text_delete_right.get().is_pressed() {
77                self.engine
78                    .interact(Interaction::Navigate(NavSignal::TextChange(
79                        NavTextChange::DeleteRight,
80                    )));
81            }
82            if self.inputs.trigger.get().is_pressed() {
83                self.engine
84                    .interact(Interaction::Navigate(NavSignal::TextChange(
85                        NavTextChange::NewLine,
86                    )));
87            }
88        } else {
89            if self.inputs.up.get().is_pressed() {
90                self.engine.interact(Interaction::Navigate(NavSignal::Up));
91            }
92            if self.inputs.down.get().is_pressed() {
93                self.engine.interact(Interaction::Navigate(NavSignal::Down));
94            }
95            if self.inputs.left.get().is_pressed() {
96                self.engine.interact(Interaction::Navigate(NavSignal::Left));
97            }
98            if self.inputs.right.get().is_pressed() {
99                self.engine
100                    .interact(Interaction::Navigate(NavSignal::Right));
101            }
102            if self.inputs.prev.get().is_pressed() {
103                self.engine.interact(Interaction::Navigate(NavSignal::Prev));
104            }
105            if self.inputs.next.get().is_pressed() {
106                self.engine.interact(Interaction::Navigate(NavSignal::Next));
107            }
108            if self.inputs.trigger.get().is_pressed() {
109                self.engine
110                    .interact(Interaction::Navigate(NavSignal::Accept(true)));
111            }
112            if self.inputs.context.get().is_pressed() {
113                self.engine
114                    .interact(Interaction::Navigate(NavSignal::Context(true)));
115            }
116            if self.inputs.cancel.get().is_pressed() {
117                self.engine
118                    .interact(Interaction::Navigate(NavSignal::Cancel(true)));
119            }
120        }
121        let pointer_position = {
122            let [x, y] = self.inputs.pointer_position.get();
123            let position = mapping.real_to_virtual_vec2(Vec2 { x, y }, false);
124            if (position.x - self.cached_pointer_position.x).abs() > ZERO_THRESHOLD
125                || (position.y - self.cached_pointer_position.y).abs() > ZERO_THRESHOLD
126            {
127                self.cached_pointer_position = position;
128                self.engine.interact(Interaction::PointerMove(position));
129            }
130            position
131        };
132        let pointer_trigger = self.inputs.pointer_trigger.get();
133        let pointer_context = self.inputs.pointer_context.get();
134        if pointer_trigger.is_pressed() {
135            self.engine.interact(Interaction::PointerDown(
136                PointerButton::Trigger,
137                pointer_position,
138            ));
139        }
140        if pointer_trigger.is_released() {
141            self.engine.interact(Interaction::PointerUp(
142                PointerButton::Trigger,
143                pointer_position,
144            ));
145        }
146        if pointer_context.is_pressed() {
147            self.engine.interact(Interaction::PointerDown(
148                PointerButton::Context,
149                pointer_position,
150            ));
151        }
152        if pointer_context.is_released() {
153            self.engine.interact(Interaction::PointerUp(
154                PointerButton::Context,
155                pointer_position,
156            ));
157        }
158        {
159            let [x, y] = self.inputs.scroll.get();
160            if x.abs() > ZERO_THRESHOLD || y.abs() > ZERO_THRESHOLD {
161                self.engine
162                    .interact(Interaction::Navigate(NavSignal::Jump(NavJump::Scroll(
163                        NavScroll::Units(Vec2 { x: -x, y: -y }, true),
164                    ))));
165            }
166        }
167    }
168}
169
170impl InteractionsEngine<DefaultInteractionsEngineResult, ()> for GuiInteractionsEngine {
171    fn perform_interactions(
172        &mut self,
173        app: &mut Application,
174    ) -> Result<DefaultInteractionsEngineResult, ()> {
175        self.engine.perform_interactions(app)
176    }
177}