gled-ui 2.30.1

gled's egui interface, shared by the desktop app and the browser
Documentation
//! The lamp layout as an interface sees it: read from the project's SVG on the
//! client, the same way the engine reads it, so effects and the preview can
//! be drawn without asking the server.

use std::{collections::BTreeSet, sync::Arc};

use gled_gpu::{layout::LampLayout, render_to_output::positions::Positions};
use gled_model::asset::{group::Group, svg::Svg};
use gled_svg::{ParsedSvg, measurement_point::MeasurementPoints};

#[derive(Debug, Default)]
pub(crate) struct ClientLayout {
    /// The SVG the layout was read from.
    svg: Option<Arc<str>>,
    points: Arc<MeasurementPoints>,
    /// Changes whenever the layout was read again.
    generation: u64,
    groups: Arc<Vec<Group>>,
    universes: Arc<BTreeSet<u16>>,
}

impl ClientLayout {
    /// Reads the layout again if the project's SVG changed. Returns whether
    /// it did.
    pub(crate) fn update(&mut self, svg: Option<&Svg>) -> bool {
        let contents = svg.map(|svg| svg.contents().clone());
        let unchanged = match (&self.svg, &contents) {
            (Some(old), Some(new)) => Arc::ptr_eq(old, new) || old == new,
            (None, None) => true,
            _ => false,
        };
        if unchanged {
            return false;
        }
        self.svg = contents;
        self.generation += 1;
        self.points = Arc::default();
        self.groups = Arc::default();
        self.universes = Arc::default();
        // The engine reports an SVG it cannot read.
        if let Some(svg) = self
            .svg
            .as_deref()
            .and_then(|contents| ParsedSvg::parse(contents).ok())
        {
            let points = MeasurementPoints::from(&svg);
            self.groups = Arc::new(points.groups());
            self.universes = Arc::new(points.universes());
            self.points = Arc::new(points);
        }
        true
    }

    pub(crate) fn generation(&self) -> u64 {
        self.generation
    }

    /// The lamp groups of the SVG.
    pub(crate) fn groups(&self) -> &Arc<Vec<Group>> {
        &self.groups
    }

    /// The output universes the SVG's lamps use.
    pub(crate) fn universes(&self) -> &Arc<BTreeSet<u16>> {
        &self.universes
    }
}

impl LampLayout for ClientLayout {
    fn positions(&self, group: &Group) -> Positions {
        self.points.positions(group)
    }

    fn preview_positions(&self) -> Positions {
        self.points.preview_positions()
    }
}