spitfire-gui 0.36.14

GUI module for Spitfire toolset
Documentation
use raui_core::{
    application::Application,
    interactive::{
        InteractionsEngine,
        default_interactions_engine::{
            DefaultInteractionsEngine, DefaultInteractionsEngineResult, Interaction, PointerButton,
        },
    },
    layout::CoordsMapping,
    widget::{
        component::interactive::navigation::{NavJump, NavScroll, NavSignal, NavTextChange},
        utils::Vec2,
    },
};
use spitfire_input::{ArrayInputCombinator, InputActionRef, InputCharactersRef};

const ZERO_THRESHOLD: f32 = 1.0e-6;

#[derive(Default)]
pub struct GuiInteractionsInputs {
    pub trigger: InputActionRef,
    pub context: InputActionRef,
    pub cancel: InputActionRef,
    pub left: InputActionRef,
    pub right: InputActionRef,
    pub up: InputActionRef,
    pub down: InputActionRef,
    pub prev: InputActionRef,
    pub next: InputActionRef,
    pub text: InputCharactersRef,
    pub text_start: InputActionRef,
    pub text_end: InputActionRef,
    pub text_delete_left: InputActionRef,
    pub text_delete_right: InputActionRef,
    pub pointer_position: ArrayInputCombinator<2>,
    pub pointer_trigger: InputActionRef,
    pub pointer_context: InputActionRef,
    pub scroll: ArrayInputCombinator<2>,
}

#[derive(Default)]
pub struct GuiInteractionsEngine {
    pub inputs: GuiInteractionsInputs,
    pub engine: DefaultInteractionsEngine,
    cached_pointer_position: Vec2,
}

impl GuiInteractionsEngine {
    pub fn maintain(&mut self, mapping: &CoordsMapping) {
        if self.engine.focused_text_input().is_some() {
            if let Some(mut text) = self.inputs.text.write() {
                for character in text.take().chars() {
                    self.engine
                        .interact(Interaction::Navigate(NavSignal::TextChange(
                            NavTextChange::InsertCharacter(character),
                        )));
                }
            }
            if self.inputs.left.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::MoveCursorLeft,
                    )));
            }
            if self.inputs.right.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::MoveCursorRight,
                    )));
            }
            if self.inputs.text_start.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::MoveCursorStart,
                    )));
            }
            if self.inputs.text_end.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::MoveCursorEnd,
                    )));
            }
            if self.inputs.text_delete_left.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::DeleteLeft,
                    )));
            }
            if self.inputs.text_delete_right.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::DeleteRight,
                    )));
            }
            if self.inputs.trigger.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::TextChange(
                        NavTextChange::NewLine,
                    )));
            }
        } else {
            if self.inputs.up.get().is_pressed() {
                self.engine.interact(Interaction::Navigate(NavSignal::Up));
            }
            if self.inputs.down.get().is_pressed() {
                self.engine.interact(Interaction::Navigate(NavSignal::Down));
            }
            if self.inputs.left.get().is_pressed() {
                self.engine.interact(Interaction::Navigate(NavSignal::Left));
            }
            if self.inputs.right.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::Right));
            }
            if self.inputs.prev.get().is_pressed() {
                self.engine.interact(Interaction::Navigate(NavSignal::Prev));
            }
            if self.inputs.next.get().is_pressed() {
                self.engine.interact(Interaction::Navigate(NavSignal::Next));
            }
            if self.inputs.trigger.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::Accept(true)));
            }
            if self.inputs.context.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::Context(true)));
            }
            if self.inputs.cancel.get().is_pressed() {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::Cancel(true)));
            }
        }
        let pointer_position = {
            let [x, y] = self.inputs.pointer_position.get();
            let position = mapping.real_to_virtual_vec2(Vec2 { x, y }, false);
            if (position.x - self.cached_pointer_position.x).abs() > ZERO_THRESHOLD
                || (position.y - self.cached_pointer_position.y).abs() > ZERO_THRESHOLD
            {
                self.cached_pointer_position = position;
                self.engine.interact(Interaction::PointerMove(position));
            }
            position
        };
        let pointer_trigger = self.inputs.pointer_trigger.get();
        let pointer_context = self.inputs.pointer_context.get();
        if pointer_trigger.is_pressed() {
            self.engine.interact(Interaction::PointerDown(
                PointerButton::Trigger,
                pointer_position,
            ));
        }
        if pointer_trigger.is_released() {
            self.engine.interact(Interaction::PointerUp(
                PointerButton::Trigger,
                pointer_position,
            ));
        }
        if pointer_context.is_pressed() {
            self.engine.interact(Interaction::PointerDown(
                PointerButton::Context,
                pointer_position,
            ));
        }
        if pointer_context.is_released() {
            self.engine.interact(Interaction::PointerUp(
                PointerButton::Context,
                pointer_position,
            ));
        }
        {
            let [x, y] = self.inputs.scroll.get();
            if x.abs() > ZERO_THRESHOLD || y.abs() > ZERO_THRESHOLD {
                self.engine
                    .interact(Interaction::Navigate(NavSignal::Jump(NavJump::Scroll(
                        NavScroll::Units(Vec2 { x: -x, y: -y }, true),
                    ))));
            }
        }
    }
}

impl InteractionsEngine<DefaultInteractionsEngineResult, ()> for GuiInteractionsEngine {
    fn perform_interactions(
        &mut self,
        app: &mut Application,
    ) -> Result<DefaultInteractionsEngineResult, ()> {
        self.engine.perform_interactions(app)
    }
}