jackdaw_feathers 0.4.1

Internal crate for the jackdaw editor
Documentation
use bevy::prelude::*;

use super::color_math::hsv_to_rgb;
use super::materials::{AlphaSliderMaterial, CheckerboardMaterial, HsvRectMaterial};
use super::{
    AlphaHandle, AlphaHandleMaterial, AlphaMaterialNode, AlphaSlider, ColorPickerState,
    HANDLE_SIZE, HsvRectHandle, HsvRectMaterialNode, HsvRectangle, HueHandle, HueSlider,
    PreviewSwatchMaterial, TriggerLabel, TriggerSwatchMaterial,
};

pub(super) fn update_color_picker_visuals(
    changed_pickers: Query<Entity, Changed<ColorPickerState>>,
    all_pickers: Query<&ColorPickerState>,
    mut hsv_rect_handles: Query<
        (&HsvRectHandle, &mut Node, &mut BackgroundColor),
        (Without<HueHandle>, Without<AlphaHandle>),
    >,
    mut hue_handles: Query<
        (&HueHandle, &mut Node, &mut BackgroundColor),
        (Without<HsvRectHandle>, Without<AlphaHandle>),
    >,
    mut alpha_handles: Query<
        (&AlphaHandle, &mut Node),
        (Without<HsvRectHandle>, Without<HueHandle>),
    >,
    alpha_handle_material_nodes: Query<(&AlphaHandleMaterial, &MaterialNode<CheckerboardMaterial>)>,
    hsv_rect_material_nodes: Query<(&HsvRectMaterialNode, &MaterialNode<HsvRectMaterial>)>,
    alpha_material_nodes: Query<(&AlphaMaterialNode, &MaterialNode<AlphaSliderMaterial>)>,
    preview_swatch_nodes: Query<(&PreviewSwatchMaterial, &MaterialNode<CheckerboardMaterial>)>,
    hsv_rects: Query<(&HsvRectangle, &ComputedNode), Changed<ComputedNode>>,
    all_hsv_rects: Query<(&HsvRectangle, &ComputedNode)>,
    hue_sliders: Query<(&HueSlider, &ComputedNode)>,
    alpha_sliders: Query<(&AlphaSlider, &ComputedNode)>,
    mut hsv_rect_materials: ResMut<Assets<HsvRectMaterial>>,
    mut alpha_materials: ResMut<Assets<AlphaSliderMaterial>>,
    mut checkerboard_materials: ResMut<Assets<CheckerboardMaterial>>,
) {
    let mut needs_update = Vec::new();
    for entity in &changed_pickers {
        if let Ok(state) = all_pickers.get(entity) {
            needs_update.push((entity, state));
        }
    }
    for (rect, _) in &hsv_rects {
        if !needs_update.iter().any(|(e, _)| *e == rect.0)
            && let Ok(state) = all_pickers.get(rect.0)
        {
            needs_update.push((rect.0, state));
        }
    }

    for (picker_entity, state) in needs_update {
        let clamped_rgba = state.to_rgba().map(|c| c.clamp(0.0, 1.0));
        let current_color = Srgba::new(
            clamped_rgba[0],
            clamped_rgba[1],
            clamped_rgba[2],
            clamped_rgba[3],
        );

        let hsv_size = all_hsv_rects
            .iter()
            .find(|(r, _)| r.0 == picker_entity)
            .map(|(_, c)| c.size() * c.inverse_scale_factor());
        let hue_size = hue_sliders
            .iter()
            .find(|(s, _)| s.0 == picker_entity)
            .map(|(_, c)| c.size() * c.inverse_scale_factor());
        let alpha_size = alpha_sliders
            .iter()
            .find(|(s, _)| s.0 == picker_entity)
            .map(|(_, c)| c.size() * c.inverse_scale_factor());

        for (hsv_rect_handle, mut node, mut bg) in &mut hsv_rect_handles {
            if hsv_rect_handle.0 != picker_entity {
                continue;
            }
            if let Some(size) = hsv_size
                && size.x > 0.0
                && size.y > 0.0
            {
                node.left = px(state.saturation * size.x - HANDLE_SIZE / 2.0);
                node.top = px((1.0 - state.brightness.min(1.0)) * size.y - HANDLE_SIZE / 2.0);
            }
            bg.0 = current_color.with_alpha(1.0).into();
        }

        for (hue_handle, mut node, mut bg) in &mut hue_handles {
            if hue_handle.0 != picker_entity {
                continue;
            }
            if let Some(size) = hue_size
                && size.x > 0.0
            {
                node.left = px((state.hue / 360.0) * size.x - HANDLE_SIZE / 2.0);
            }
            let hue_color = hsv_to_rgb(state.hue, 1.0, 1.0);
            bg.0 = Srgba::new(hue_color.0, hue_color.1, hue_color.2, 1.0).into();
        }

        for (alpha_handle, mut node) in &mut alpha_handles {
            if alpha_handle.0 != picker_entity {
                continue;
            }
            if let Some(size) = alpha_size
                && size.x > 0.0
            {
                node.left = px(state.alpha * size.x - HANDLE_SIZE / 2.0);
            }
        }

        for (alpha_handle_mat, material_node) in &alpha_handle_material_nodes {
            if alpha_handle_mat.0 != picker_entity {
                continue;
            }
            if let Some(material) = checkerboard_materials.get_mut(&material_node.0) {
                material.color = Vec4::new(
                    current_color.red,
                    current_color.green,
                    current_color.blue,
                    current_color.alpha,
                );
            }
        }

        for (preview_mat, material_node) in &preview_swatch_nodes {
            if preview_mat.0 != picker_entity {
                continue;
            }
            if let Some(material) = checkerboard_materials.get_mut(&material_node.0) {
                material.color = Vec4::new(
                    current_color.red,
                    current_color.green,
                    current_color.blue,
                    current_color.alpha,
                );
            }
        }

        for (hsv_rect_mat_node, material_node) in &hsv_rect_material_nodes {
            if hsv_rect_mat_node.0 != picker_entity {
                continue;
            }
            if let Some(material) = hsv_rect_materials.get_mut(&material_node.0) {
                material.hue = state.hue;
            }
        }

        for (alpha_mat_node, material_node) in &alpha_material_nodes {
            if alpha_mat_node.0 != picker_entity {
                continue;
            }
            if let Some(material) = alpha_materials.get_mut(&material_node.0) {
                let (r, g, b) = hsv_to_rgb(state.hue, state.saturation, state.brightness.min(1.0));
                material.color = Vec4::new(r, g, b, 1.0);
            }
        }
    }
}

pub(super) fn update_trigger_display(
    pickers: Query<(Entity, &ColorPickerState), Changed<ColorPickerState>>,
    trigger_swatch_materials: Query<(&TriggerSwatchMaterial, &MaterialNode<CheckerboardMaterial>)>,
    mut trigger_labels: Query<(&TriggerLabel, &mut Text)>,
    mut checkerboard_materials: ResMut<Assets<CheckerboardMaterial>>,
) {
    for (picker_entity, state) in &pickers {
        let srgba = state.to_srgba();
        let hex = state.to_hex();

        for (swatch_mat, material_node) in &trigger_swatch_materials {
            if swatch_mat.0 != picker_entity {
                continue;
            }
            if let Some(material) = checkerboard_materials.get_mut(&material_node.0) {
                material.color = Vec4::new(srgba.red, srgba.green, srgba.blue, srgba.alpha);
            }
        }

        for (label, mut text) in &mut trigger_labels {
            if label.0 != picker_entity {
                continue;
            }
            **text = hex.clone();
        }
    }
}