gled-ui 2.30.1

gled's egui interface, shared by the desktop app and the browser
Documentation
//! Group colors and the group picker.

use egui::{Button, Color32, RichText, Stroke, Ui, UiKind};

use crate::ui::{ChangeButton, OverwriteChangeButton};
use gled_model::asset::group::{Group, Groups};

/// The color a group is shown in, by its position in the SVG.
pub(crate) trait GroupColor {
    fn color(&self) -> Color32;
}

impl GroupColor for Group {
    fn color(&self) -> Color32 {
        let index = crate::ui::frame_requests::layout_groups()
            .iter()
            .position(|group| group == self)
            .unwrap_or_default();
        static COLORS: &[Color32] = &[
            Color32::from_rgb(175, 213, 129),
            Color32::from_rgb(177, 152, 221),
            Color32::from_rgb(140, 181, 255),
            Color32::from_rgb(217, 176, 140),
            Color32::from_rgb(217, 148, 140),
            Color32::from_rgb(113, 208, 132),
            Color32::from_rgb(213, 129, 192),
            Color32::from_rgb(163, 218, 224),
            Color32::from_rgb(222, 233, 190),
            Color32::from_rgb(255, 255, 255),
        ];
        COLORS[index % COLORS.len()]
    }
}

impl OverwriteChangeButton for Groups {
    const NAME: &'static str = "Groups";
}

impl ChangeButton for Groups {
    fn change_button(&mut self, ui: &mut egui::Ui) -> bool {
        if crate::ui::frame_requests::layout_groups().is_empty() {
            ui.label("No groups available");
            return false;
        }

        let mut changed = false;
        let mut next_index = 0;
        while self.contains_index(next_index) {
            next_index += 1;
        }
        let mut insert = None;
        let mut remove = None;

        fn menu_button(
            ui: &mut Ui,
            index: usize,
            group: &Group,
            changed: &mut bool,
            remove: &mut Option<usize>,
            insert: &mut Option<(usize, Group)>,
        ) {
            ui.menu_button(format!("{index} {}", group.0), |ui| {
                ui.set_min_width(200.0);
                if ui
                    .add(Button::new("🗑 Remove").fill(Color32::DARK_RED))
                    .clicked()
                {
                    ui.close_kind(UiKind::Menu);
                    *remove = Some(index);
                    *changed = true;
                }
                let mut group = Some(group.to_owned());
                if group_buttons(ui, &mut group) {
                    ui.close_kind(UiKind::Menu);
                    if let Some(group) = group {
                        *insert = Some((index, group));
                    } else {
                        *remove = Some(index);
                    }
                    *changed = true;
                }
            });
        }

        let mut new_group = None;
        ui.menu_button(format!("+ Add Group {next_index}"), |ui| {
            ui.set_min_width(200.0);
            if group_buttons(ui, &mut new_group) {
                ui.close_kind(UiKind::Menu);
                if let Some(group) = new_group {
                    insert = Some((next_index, group));
                    changed = true;
                }
            }
        });

        for (index, group) in self.iter() {
            ui.scope(|ui| {
                {
                    let widgets = &mut ui.visuals_mut().widgets;
                    widgets.inactive.fg_stroke.color = Color32::from_black_alpha(200);
                    widgets.inactive.weak_bg_fill = group.color();
                    widgets.hovered.fg_stroke.color = Color32::from_black_alpha(200);
                    widgets.hovered.weak_bg_fill = group.color();
                }

                if ui.layout().main_dir().is_vertical() {
                    ui.vertical_centered_justified(|ui| {
                        menu_button(ui, *index, group, &mut changed, &mut remove, &mut insert);
                    });
                } else {
                    menu_button(ui, *index, group, &mut changed, &mut remove, &mut insert);
                }
            });
        }

        if let Some((index, group)) = insert {
            self.insert(index, group);
        }
        if let Some(index) = remove {
            self.remove(index);
        }

        changed
    }
}

fn group_buttons(ui: &mut Ui, selected: &mut Option<Group>) -> bool {
    let mut changed = false;
    for group in crate::ui::frame_requests::layout_groups().iter().cloned() {
        if ui
            .add(group_button(&group, selected.as_ref() == Some(&group)))
            .clicked()
        {
            *selected = Some(group);
            changed = true;
        }
    }
    changed
}

pub(crate) fn group_button(group: &'_ Group, selected: bool) -> Button<'_> {
    let button =
        Button::new(RichText::new(group).color(Color32::from_black_alpha(200))).fill(group.color());

    if selected {
        button.stroke(Stroke::new(3.0, Color32::RED))
    } else {
        button
    }
}