use egui::*; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct Painting { /// in 0-1 normalized coordinates lines: Vec>, stroke: Stroke, } impl Default for Painting { fn default() -> Self { Self { lines: Default::default(), stroke: Stroke::new(1.0, Color32::LIGHT_BLUE), } } } impl Painting { pub fn ui_control(&mut self, ui: &mut egui::Ui) -> egui::Response { ui.horizontal(|ui| { egui::stroke_ui(ui, &mut self.stroke, "Stroke"); ui.separator(); if ui.button("Clear Painting").clicked() { self.lines.clear(); } }) .response } pub fn ui_content(&mut self, ui: &mut Ui) -> egui::Response { let (mut response, painter) = ui.allocate_painter(ui.available_size_before_wrap(), Sense::drag()); let to_screen = emath::RectTransform::from_to( Rect::from_min_size(Pos2::ZERO, response.rect.square_proportions()), response.rect, ); let from_screen = to_screen.inverse(); if self.lines.is_empty() { self.lines.push(vec![]); } let current_line = self.lines.last_mut().unwrap(); if let Some(pointer_pos) = response.interact_pointer_pos() { let canvas_pos = from_screen * pointer_pos; if current_line.last() != Some(&canvas_pos) { current_line.push(canvas_pos); response.mark_changed(); } } else if !current_line.is_empty() { self.lines.push(vec![]); response.mark_changed(); } let mut shapes = vec![]; for line in &self.lines { if line.len() >= 2 { let points: Vec = line.iter().map(|p| to_screen * *p).collect(); shapes.push(egui::Shape::line(points, self.stroke)); } } painter.extend(shapes); response } } impl super::Demo for Painting { fn name(&self) -> &'static str { "🖊 Painting" } fn show(&mut self, ctx: &Context, open: &mut bool) { use super::View as _; Window::new(self.name()) .open(open) .default_size(vec2(512.0, 512.0)) .vscroll(false) .show(ctx, |ui| self.ui(ui)); } } impl super::View for Painting { fn ui(&mut self, ui: &mut Ui) { ui.vertical_centered(|ui| { ui.add(crate::__egui_github_link_file!()); }); self.ui_control(ui); ui.label("Paint with your mouse/touch!"); Frame::dark_canvas(ui.style()).show(ui, |ui| { self.ui_content(ui); }); } }