gled-core 2.30.2

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
//! Evaluating input events (keys, gamepad, Art-Net) against the current input
//! state, for the project's trigger events and the scene instances' inputs.

use crate::{
    input::{Input, event::InputEvent},
    storage::asset::{
        curve::multiplied_curve::MultipliedCurve, project::Project, scene::instance::SceneInstance,
    },
};

/// The state of an input event right now.
pub(crate) trait InputEventState {
    /// Started this tick.
    fn is_new(&self) -> bool;
    /// Held down, or above zero for a fader.
    fn is_live(&self) -> bool;
    /// The event as a dimmer value in 0..=1.
    fn dimmer(&self) -> f32;
}

impl InputEventState for InputEvent {
    fn is_new(&self) -> bool {
        Input::is_event_new(self)
    }

    fn is_live(&self) -> bool {
        Input::event_live_value(self).is_some()
    }

    fn dimmer(&self) -> f32 {
        Input::event_live_value(self)
            .map(|value| f32::from(value) / 255.0)
            .unwrap_or(0.0)
    }
}

/// Applies the activation, flash and dimmer inputs of a scene instance.
pub(crate) trait SceneInstanceInputs {
    fn update_input_state(&mut self, beat_progression: f32);
}

impl SceneInstanceInputs for SceneInstance {
    /// Apply activation, flash and dimmer input events. Runs on the UI thread,
    /// once per `Input::tick`, so one-tick "new" events are seen exactly once.
    fn update_input_state(&mut self, beat_progression: f32) {
        if let Some(event) = self.activation_input.as_ref()
            && event.is_new()
        {
            self.active = !self.active;
        }

        if let Some(event) = self.flash_input.as_ref() {
            let flash_active = event.is_live();
            if !self.flash && flash_active && self.set_offset_on_flash {
                self.beat_progression_offset =
                    MultipliedCurve::new_multiplier(4.0 - beat_progression % 4.0);
            }
            self.flash = flash_active;
        }

        if let Some(event) = self.dimmer_input.as_ref() {
            self.input_dimmer = event.dimmer()
        }
    }
}

/// The project's trigger inputs and its scene instances' inputs.
pub(crate) trait ProjectInputs {
    fn update_input_state(&mut self, beat_progression: f32);
    fn tap_input_is_new(&self) -> bool;
    fn blackout_input_is_new(&self) -> bool;
    fn blackout_hold_input_is_live(&self) -> bool;
    fn half_input_is_new(&self) -> bool;
    fn double_input_is_new(&self) -> bool;
}

impl ProjectInputs for Project {
    /// Apply scene activation, flash and dimmer input events for every scene instance.
    fn update_input_state(&mut self, beat_progression: f32) {
        self.scenes_instances_grid
            .values_mut()
            .for_each(|scene_instance| scene_instance.update_input_state(beat_progression));
    }

    fn tap_input_is_new(&self) -> bool {
        self.tap_input_events.iter().any(|event| event.is_new())
    }

    fn blackout_input_is_new(&self) -> bool {
        self.blackout_input_events
            .iter()
            .any(|event| event.is_new())
    }

    fn blackout_hold_input_is_live(&self) -> bool {
        self.blackout_hold_input_events
            .iter()
            .any(|event| event.is_live())
    }

    fn half_input_is_new(&self) -> bool {
        self.half_input_events.iter().any(|event| event.is_new())
    }

    fn double_input_is_new(&self) -> bool {
        self.double_input_events.iter().any(|event| event.is_new())
    }
}