gled-ui 2.32.1

gled's egui interface, shared by the desktop app and the browser
Documentation
use crate::ui::{
    asset::CollectionsChangeButton,
    window_common::{gled_window_frame, raise, tool_window_builder},
    windows::channel_overwrites,
};
use egui::{
    Color32, ComboBox, Context, Id, RichText, Vec2, ViewportId,
    scroll_area::ScrollBarVisibility::AlwaysVisible,
};
pub(crate) use gled_model::asset::project::io::ChannelIdentifier;
use gled_model::{
    asset::{Asset, output_device::OutputDevice, project::Project},
    asset_id::AssetId,
    collection::Collections,
};

#[derive(Debug)]
pub(crate) struct ChannelOverwritesWindow {
    open: bool,
    /// Set while the window still has to be brought forward.
    raise: bool,
    device: Option<AssetId<OutputDevice>>,
    universe: Option<u16>,
    channel: u16,
    value: u8,
}

impl Default for ChannelOverwritesWindow {
    fn default() -> Self {
        Self {
            open: false,
            raise: false,
            device: Default::default(),
            universe: Default::default(),
            channel: 1,
            value: Default::default(),
        }
    }
}

impl ChannelOverwritesWindow {
    #[cfg_attr(feature = "profiling", profiling::function)]
    pub(crate) fn update(
        &mut self,
        ctx: &Context,
        project: &mut Option<Project>,
        collections: &mut Collections,
    ) {
        if !self.open {
            return;
        }

        ctx.show_viewport_immediate(
            ViewportId(Id::new("channel overwrites window")),
            tool_window_builder("Channel Overwrites")
                .with_inner_size(Vec2::new(600.0, 500.0))
                .with_min_inner_size(Vec2::new(600.0, 500.0)),
            |ctx, _viewport_class| {
                raise(ctx, &mut self.raise);
                ctx.input(|input| {
                    if input.viewport().close_requested()
                        || crate::ui::window_common::embedded_close_clicked("Channel Overwrites") {
                        self.close();
                    }
                });

                gled_window_frame(ctx, "Channel Overwrites", |ui| {
                    // The overwrites are part of the project; the engine
                    // applies every change to the output right away.
                    let Some(project) = project.as_mut() else {
                        ui.label("No project is open.");
                        return;
                    };
                    let mut channel_overwrites = project.channel_overwrites.clone();

                    ui.horizontal(|ui| {
                        if self.device.collections_change_button(ui, collections) {
                            self.universe.take();
                        }

                        if let Some(device) = self.device.and_then(|id|Asset::get(id, collections)) {
                            let device_universes = device.data.universes();
                            if !device_universes.is_empty() {
                                ComboBox::new("channel_overwrites_universe", "")
                                    .selected_text(match self.universe {
                                        None => "No universe selected".to_string(),
                                        Some(universe) => format!("Universe {universe}"),
                                    })
                                    .width(150.0)
                                    .show_ui(ui, |ui| {
                                        for device_universe in device_universes {
                                            let res = ui.selectable_value(
                                                &mut self.universe,
                                                Some(*device_universe),
                                                format!("Universe {device_universe}"),
                                            );

                                            if res.changed() {
                                                self.universe = Some(*device_universe);
                                            }
                                        }
                                    });
                                }

                                ui.add(egui::DragValue::new(&mut self.channel).range(1..=512).prefix("Channel: "));
                                ui.add_enabled(device_universes.is_empty() || self.universe.is_some(), egui::DragValue::new(&mut self.value).range(0..=256).prefix("Value: "));
                                    if ui.button("Add/Update").on_hover_text(
                                        "Add or update the channel overwrite for the selected device, universe and channel",
                                    ).clicked() {
                                        channel_overwrites.0.insert(
                                            channel_overwrites::ChannelIdentifier {
                                                device: device.id,
                                                universe: self.universe,
                                                channel: self.channel,
                                            },
                                            self.value,
                                        );
                                        project.channel_overwrites = channel_overwrites.clone();
                                    }

                        }
                    });
                    ui.separator();

                    egui::ScrollArea::vertical()
                        .scroll_bar_visibility(AlwaysVisible)
                        .id_salt("channel_overwrites_scroll")
                        .show(ui, |ui| {
                            ui.set_min_width(ui.available_width());
                            for (channel_identifier, value) in channel_overwrites.0.iter() {
                                ui.horizontal(|ui| {
                                    let device_name = Asset::get(channel_identifier.device, collections)
                                        .map(|d| d.name().to_owned())
                                        .unwrap_or_else(|| {
                                            format!(
                                                "Unknown Device ({})",
                                                channel_identifier.device
                                            )
                                        });
                                    if ui.label(if let Some(universe) = channel_identifier.universe { format!(
                                        "{device_name} - Universe {universe} - Channel {}:",
                                        channel_identifier.channel
                                    )} else {
                                        format!("{device_name} - Channel {}:", channel_identifier.channel)
                                    }).clicked() {
                                        self.device = Some(channel_identifier.device);
                                        self.universe = channel_identifier.universe;
                                        self.channel = channel_identifier.channel;
                                        self.value = *value;
                                    };
                                    ui.label(RichText::new(value.to_string()).color(Color32::YELLOW));
                                    if ui.button("❌").on_hover_text("Remove this channel overwrite").clicked() {
                                        let mut channel_overwrites = channel_overwrites.clone();
                                        channel_overwrites.0.remove(channel_identifier);
                                        project.channel_overwrites = channel_overwrites;
                                    }
                                });
                            }
                        });
                });
            },
        );
    }

    pub(crate) fn open(&mut self) {
        self.open = true;
        self.raise = true;
    }

    pub(crate) fn close(&mut self) {
        self.open = false;
    }
}