From 1bac3dedab4101ac7977dd376afda34d0e3153f4 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Tue, 3 Dec 2024 20:34:13 -0500 Subject: [PATCH] Implement color picker --- src/window/game.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/window/game.rs b/src/window/game.rs index c3a7437..b7e737a 100644 --- a/src/window/game.rs +++ b/src/window/game.rs @@ -3,8 +3,9 @@ use crate::{ emulator::{EmulatorClient, EmulatorCommand, SimId}, }; use egui::{ - menu, Button, CentralPanel, Color32, Context, Frame, Response, Sense, TopBottomPanel, Ui, Vec2, - ViewportBuilder, ViewportCommand, ViewportId, WidgetText, + ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Frame, Layout, + Response, Sense, TopBottomPanel, Ui, Vec2, ViewportBuilder, ViewportCommand, ViewportId, + WidgetText, Window, }; use winit::event_loop::EventLoopProxy; @@ -35,6 +36,7 @@ pub struct GameWindow { display_mode: DisplayMode, colors: [Color32; 2], screen: Option, + color_picker: Option, } impl GameWindow { @@ -46,6 +48,7 @@ impl GameWindow { display_mode: DisplayMode::Anaglyph, colors: COLOR_PRESETS[0], screen: None, + color_picker: None, } } @@ -148,8 +151,26 @@ impl GameWindow { for preset in COLOR_PRESETS { if ui.color_pair_button(preset[0], preset[1]).clicked() { self.colors = preset; + ui.close_menu(); } } + ui.with_layout(ui.layout().with_cross_align(egui::Align::Center), |ui| { + if ui.button("Custom").clicked() { + let color_str = |color: Color32| { + format!("{:02x}{:02x}{:02x}", color.r(), color.g(), color.b()) + }; + let is_running = self.client.is_running(self.sim_id); + if is_running { + self.client.send_command(EmulatorCommand::Pause); + } + self.color_picker = Some(ColorPickerState { + color_codes: [color_str(self.colors[0]), color_str(self.colors[1])], + just_opened: true, + unpause_on_close: is_running, + }); + ui.close_menu(); + } + }); }); }); ui.menu_button("Audio", |ui| { @@ -195,6 +216,29 @@ impl GameWindow { } }); } + + fn show_color_picker(&mut self, ui: &mut Ui) { + let Some(state) = self.color_picker.as_mut() else { + return; + }; + let open = ui + .horizontal(|ui| { + let left_color = ui.color_picker(&mut self.colors[0], &mut state.color_codes[0]); + if state.just_opened { + left_color.request_focus(); + state.just_opened = false; + } + let right_color = ui.color_picker(&mut self.colors[1], &mut state.color_codes[1]); + left_color.has_focus() || right_color.has_focus() + }) + .inner; + if !open { + if state.unpause_on_close { + self.client.send_command(EmulatorCommand::Resume); + } + self.color_picker = None; + } + } } impl AppWindow for GameWindow { @@ -220,6 +264,15 @@ impl AppWindow for GameWindow { self.show_menu(ctx, ui); }); }); + if self.color_picker.is_some() { + Window::new("Color Picker") + .title_bar(false) + .resizable(false) + .anchor(Align2::CENTER_CENTER, Vec2::ZERO) + .show(ctx, |ui| { + self.show_color_picker(ui); + }); + } let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK); CentralPanel::default().frame(frame).show(ctx, |ui| { if let Some(screen) = self.screen.as_mut() { @@ -259,6 +312,8 @@ trait UiExt { } fn color_pair_button(&mut self, left: Color32, right: Color32) -> Response; + + fn color_picker(&mut self, color: &mut Color32, hex: &mut String) -> Response; } impl UiExt for Ui { @@ -283,4 +338,29 @@ impl UiExt for Ui { self.painter().rect_stroke(rect, 0.0, style.fg_stroke); response } + + fn color_picker(&mut self, color: &mut Color32, hex: &mut String) -> Response { + self.allocate_ui_with_layout( + Vec2::new(100.0, 130.0), + Layout::top_down_justified(egui::Align::Center), + |ui| { + let (rect, _) = ui.allocate_at_least(Vec2::new(100.0, 100.0), Sense::hover()); + ui.painter().rect_filled(rect, 0.0, *color); + let resp = ui.text_edit_singleline(hex); + if resp.changed() { + if let Ok(new_color) = HexColor::from_str_without_hash(hex) { + *color = new_color.color(); + } + } + resp + }, + ) + .inner + } +} + +struct ColorPickerState { + color_codes: [String; 2], + just_opened: bool, + unpause_on_close: bool, }