#![allow(deprecated)] //! Visual test GUI for the decoupled `hcie-draw` library using `egui`. //! Compiles only when running `cargo run --example draw_tester`. use eframe::egui; use hcie_draw::{draw_line, draw_filled_rect, draw_filled_circle, flood_fill}; use hcie_protocol::Layer; fn main() -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default() .with_inner_size([700.0, 500.0]) .with_title("HCIE Draw Engine Visual Tester"), ..Default::default() }; eframe::run_native( "HCIE Draw Visual Tester", options, Box::new(|cc| Ok(Box::new(DrawTesterApp::new(cc)))), ) } struct DrawTesterApp { layer: Layer, current_color: [u8; 4], thickness: f32, selected_tool: &'static str, last_drag_pos: Option, texture: Option, } impl DrawTesterApp { fn new(_cc: &eframe::CreationContext<'_>) -> Self { let width = 256; let height = 256; let len = (width * height * 4) as usize; let mut pixels = vec![255u8; len]; for y in 0..height { for x in 0..width { let i = ((y * width + x) * 4) as usize; let is_gray = ((x / 16) + (y / 16)) % 2 == 0; let c = if is_gray { 220 } else { 255 }; pixels[i] = c; pixels[i + 1] = c; pixels[i + 2] = c; pixels[i + 3] = 255; } } let layer = Layer::from_rgba("canvas", width, height, pixels); Self { layer, current_color: [255, 0, 0, 255], thickness: 5.0, selected_tool: "Line", last_drag_pos: None, texture: None, } } fn clear_canvas(&mut self) { let w = self.layer.width; let h = self.layer.height; for y in 0..h { for x in 0..w { let i = ((y * w + x) * 4) as usize; let is_gray = ((x / 16) + (y / 16)) % 2 == 0; let c = if is_gray { 220 } else { 255 }; self.layer.pixels[i] = c; self.layer.pixels[i + 1] = c; self.layer.pixels[i + 2] = c; self.layer.pixels[i + 3] = 255; } } self.texture = None; } } impl eframe::App for DrawTesterApp { fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { let ctx = ui.ctx().clone(); if self.texture.is_none() { let color_image = egui::ColorImage::from_rgba_unmultiplied( [self.layer.width as usize, self.layer.height as usize], &self.layer.pixels, ); self.texture = Some(ctx.load_texture("canvas_preview", color_image, Default::default())); } let texture = self.texture.as_ref().unwrap().clone(); egui::CentralPanel::default().show(&ctx, |ui| { ui.heading("HCIE Draw Engine Visual Tester"); ui.add_space(10.0); ui.horizontal(|ui| { ui.vertical(|ui| { ui.label("Click & drag to draw on this canvas:"); ui.add_space(5.0); let image_widget = egui::Image::new((texture.id(), texture.size_vec2())).sense(egui::Sense::click_and_drag()); let resp = ui.add(image_widget); if resp.dragged() || resp.clicked() { if let Some(hover_pos) = resp.hover_pos() { let rect = resp.rect; let px = ((hover_pos.x - rect.min.x) / rect.width() * self.layer.width as f32).clamp(0.0, self.layer.width as f32 - 1.0); let py = ((hover_pos.y - rect.min.y) / rect.height() * self.layer.height as f32).clamp(0.0, self.layer.height as f32 - 1.0); match self.selected_tool { "Line" => { if let Some(last_pos) = self.last_drag_pos { draw_line( &mut self.layer, last_pos.x, last_pos.y, px, py, self.current_color, self.thickness, None, ); self.texture = None; } self.last_drag_pos = Some(egui::pos2(px, py)); } "Circle" => { if resp.drag_started() || resp.clicked() { draw_filled_circle( &mut self.layer, px, py, self.thickness * 2.0, self.current_color, None, ); self.texture = None; } } "Rect" => { if resp.drag_started() || resp.clicked() { let size = self.thickness * 3.0; draw_filled_rect( &mut self.layer, px - size, py - size, px + size, py + size, self.current_color, None, ); self.texture = None; } } "Flood Fill" => { if resp.clicked() { flood_fill( &mut self.layer, px as u32, py as u32, self.current_color, 20, None, ); self.texture = None; } } _ => {} } } } else { self.last_drag_pos = None; } }); ui.add_space(20.0); ui.vertical(|ui| { ui.label("Toolbar Tools:"); ui.add_space(5.0); ui.selectable_value(&mut self.selected_tool, "Line", "Brush/Line"); ui.selectable_value(&mut self.selected_tool, "Circle", "Filled Circle"); ui.selectable_value(&mut self.selected_tool, "Rect", "Filled Rectangle"); ui.selectable_value(&mut self.selected_tool, "Flood Fill", "Flood Fill"); ui.add_space(15.0); ui.separator(); ui.add_space(15.0); ui.label(format!("Size / Radius: {:.1}", self.thickness)); ui.add(egui::Slider::new(&mut self.thickness, 1.0..=50.0)); ui.add_space(15.0); ui.label("Brush Color:"); let mut color_f32 = [ self.current_color[0] as f32 / 255.0, self.current_color[1] as f32 / 255.0, self.current_color[2] as f32 / 255.0, self.current_color[3] as f32 / 255.0, ]; if ui.color_edit_button_rgba_unmultiplied(&mut color_f32).changed() { self.current_color = [ (color_f32[0] * 255.0).round() as u8, (color_f32[1] * 255.0).round() as u8, (color_f32[2] * 255.0).round() as u8, (color_f32[3] * 255.0).round() as u8, ]; } ui.add_space(25.0); if ui.button("Clear Canvas").clicked() { self.clear_canvas(); } ui.add_space(35.0); ui.colored_label(egui::Color32::LIGHT_GREEN, "Layer-based drawing API"); ui.colored_label(egui::Color32::LIGHT_GREEN, "Decoupled from hcie-protocol"); ui.colored_label(egui::Color32::LIGHT_GREEN, "Operating with 100% GUI neutrality"); }); }); }); } }