tarsila 0.1.1

GUI image editor for pixel art
use crate::{Effect, UiEvent, UiState};
use lapix::{Position, Size, Tool};
use macroquad::prelude::*;

mod layers;
mod menu;
mod palette;
mod preview;
mod status;
mod toolbar;

use layers::LayersPanel;
use menu::MenuBar;
use palette::Palette;
use preview::Preview;
use status::StatusBar;
use toolbar::Toolbar;

#[derive(Debug, Clone)]
pub struct GuiSyncParams {
    pub main_color: [u8; 4],
    pub num_layers: usize,
    pub active_layer: usize,
    pub layers_vis: Vec<bool>,
    pub layers_alpha: Vec<u8>,
    pub palette: Vec<[u8; 4]>,
    pub mouse_canvas: Position<i32>,
    pub is_on_canvas: bool,
    pub selected_tool: Tool,
    pub visible_pixel_on_mouse: Option<[u8; 4]>,
    pub canvas_size: Size<i32>,
    pub spritesheet: Size<u8>,
    pub zoom: f32,
    pub fps: f32,
}

pub struct Gui {
    toolbar: Toolbar,
    layers_panel: LayersPanel,
    preview: Preview,
    palette: Palette,
    status_bar: StatusBar,
    menu: MenuBar,
    mouse_on_canvas: bool,
    selected_tool: Tool,
}

impl Gui {
    pub fn new() -> Self {
        Self {
            toolbar: Toolbar::new(),
            layers_panel: LayersPanel::new(),
            preview: Preview::new(),
            palette: Palette::new(),
            status_bar: StatusBar::new(),
            menu: MenuBar::new(),
            mouse_on_canvas: false,
            selected_tool: Tool::Brush,
        }
    }

    pub fn sync(&mut self, params: GuiSyncParams) {
        self.mouse_on_canvas = params.is_on_canvas;

        self.toolbar.sync(params.main_color);
        self.selected_tool = params.selected_tool;
        self.layers_panel.sync(
            params.num_layers,
            params.active_layer,
            params.layers_vis.clone(),
            params.layers_alpha.clone(),
        );
        self.preview.sync(
            params.spritesheet,
            params.canvas_size,
            params.layers_vis.clone(),
            params.layers_alpha.clone(),
        );
        self.palette.sync(params.palette.clone());
        self.menu.sync(params.canvas_size, params.spritesheet);
        self.status_bar.sync(params);
    }

    pub fn update(&mut self) -> Vec<Effect> {
        let mut events = Vec::new();

        let widget_color = egui::Color32::from_rgb(150, 150, 150);
        let widget_weak_color = egui::Color32::from_rgb(150, 150, 150);
        let bg_color = egui::Color32::from_rgb(175, 175, 175);
        let bg_strong_color = egui::Color32::from_rgb(230, 230, 230);
        let bg_weak_color = egui::Color32::from_rgb(150, 150, 150);
        let text_color = Some(egui::Color32::from_rgb(0, 0, 0));

        egui_macroquad::ui(|egui_ctx| {
            let mut visuals = egui_ctx.style().visuals.clone();
            visuals.dark_mode = false;
            visuals.menu_rounding = 2.0.into();
            visuals.window_rounding = 2.0.into();
            visuals.widgets.noninteractive.bg_fill = bg_color;
            visuals.widgets.noninteractive.weak_bg_fill = bg_weak_color;
            visuals.widgets.active.bg_fill = widget_color;
            visuals.widgets.active.weak_bg_fill = widget_weak_color;
            visuals.widgets.inactive.bg_fill = widget_color;
            visuals.widgets.inactive.weak_bg_fill = widget_weak_color;
            visuals.widgets.hovered.bg_fill = widget_color;
            visuals.widgets.hovered.weak_bg_fill = widget_weak_color;
            visuals.faint_bg_color = bg_weak_color;
            visuals.extreme_bg_color = bg_strong_color;
            visuals.panel_fill = bg_color;
            visuals.window_fill = bg_color;
            visuals.override_text_color = text_color;
            egui_ctx.set_visuals(visuals);

            let mut palette_events = self.palette.update(egui_ctx);
            events.append(&mut palette_events);

            let mut toolbar_events = self.toolbar.update(egui_ctx, self.selected_tool);
            events.append(&mut toolbar_events);

            let mut layers_events = self.layers_panel.update(egui_ctx);
            events.append(&mut layers_events);

            let mut menu_events = self.menu.update(egui_ctx);
            events.append(&mut menu_events);

            self.preview.update(egui_ctx);
            self.status_bar.update(egui_ctx);

            let mut canvas_panel_events = self.update_canvas_panel(egui_ctx);
            events.append(&mut canvas_panel_events);

            if self.mouse_on_canvas {
                egui_ctx.output_mut(|o| o.cursor_icon = egui::CursorIcon::None);
            }
        });

        events
    }

    pub fn draw_preview(&self, state: &UiState) {
        self.preview.draw(state);
    }

    fn update_canvas_panel(&mut self, egui_ctx: &egui::Context) -> Vec<Effect> {
        let mut events = Vec::new();

        if egui_ctx.is_pointer_over_area() {
            events.push(Effect::UiEvent(UiEvent::MouseOverGui));
        }

        events
    }
}