From 0291a6e9417542158e269e4b146a245c3f4da294 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Mon, 9 May 2022 22:11:14 -0500 Subject: [PATCH] save dialog, n=tabs y=spaces --- board-builder-impl-egui/src/main.rs | 176 ++++++++++++++-------------- board.zip | Bin 511998 -> 511999 bytes src/lib.rs | 106 ++++++++--------- 3 files changed, 142 insertions(+), 140 deletions(-) diff --git a/board-builder-impl-egui/src/main.rs b/board-builder-impl-egui/src/main.rs index c928a1c..7225d64 100644 --- a/board-builder-impl-egui/src/main.rs +++ b/board-builder-impl-egui/src/main.rs @@ -5,7 +5,7 @@ use image::DynamicImage; use rfd::FileDialog; -use board_builder::{ Board, CoordTransformer, read_board_from_file }; +use board_builder::{ Board, CoordTransformer, read_board_from_file, write_board_to_file }; use std::path::Path; @@ -23,104 +23,106 @@ struct BoardBuilderApp { impl eframe::App for BoardBuilderApp { fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { - TopBottomPanel::top("menubar").show(ctx, |ui| { - menu::bar(ui, |ui| { - fn choose_file() { - FileDialog::new().pick_file(); - } - ui.menu_button("File", |ui| { - ui.button("New"); - if ui.button("Open...").clicked() { - if let Some(board_file) = FileDialog::new().pick_file() { - match read_board_from_file(&board_file) { - Ok((board, image)) => { - self.board = board; - match image { - None => { self.image = None; self.texture = None } - Some(image) => self.load_image(ctx, image), - } - } - Err(_) => panic!("Could not open file!"), - } - } - } - if ui.button("Save As...").clicked() { - choose_file(); - } - if ui.button("Open Image...").clicked() { - let image_file = FileDialog::new() - .add_filter("Image", &["png", "jpg", "jpeg", "gif", "webp", "bmp", "tiff"]) - .pick_file(); - if let Some(image_file) = image_file { - self.load_image_file(ctx, &image_file); - } - } - }); - ui.menu_button("Edit", |ui| { - ui.button("Edit Nodes"); - ui.button("Edit Edges"); - ui.button("Edit Labels..."); - }) - }); - }); - CentralPanel::default().show(ctx, |ui| { - if let Some(texture) = self.texture.as_ref() { - let size = ui.available_size(); - let (response, painter) = ui.allocate_painter(size, Sense::click()); - let image = widgets::Image::new(texture, size); - image.paint_at(ui, response.rect); - let view = View(response.rect); - self.draw_board(&painter, view); - } - }); + TopBottomPanel::top("menubar").show(ctx, |ui| { + menu::bar(ui, |ui| { + fn choose_file() { + FileDialog::new().pick_file(); + } + ui.menu_button("File", |ui| { + ui.button("New"); + if ui.button("Open...").clicked() { + if let Some(board_file) = FileDialog::new().pick_file() { + match read_board_from_file(&board_file) { + Ok((board, image)) => { + self.board = board; + match image { + None => { self.image = None; self.texture = None } + Some(image) => self.load_image(ctx, image), + } + } + Err(_) => panic!("Could not open file!"), + } + } + } + if ui.button("Save As...").clicked() { + if let Some(board_file) = FileDialog::new().save_file() { + write_board_to_file(&self.board, self.image.as_ref(), &board_file); + } + } + if ui.button("Open Image...").clicked() { + let image_file = FileDialog::new() + .add_filter("Image", &["png", "jpg", "jpeg", "gif", "webp", "bmp", "tiff"]) + .pick_file(); + if let Some(image_file) = image_file { + self.load_image_file(ctx, &image_file); + } + } + }); + ui.menu_button("Edit", |ui| { + ui.button("Edit Nodes"); + ui.button("Edit Edges"); + ui.button("Edit Labels..."); + }) + }); + }); + CentralPanel::default().show(ctx, |ui| { + if let Some(texture) = self.texture.as_ref() { + let size = ui.available_size(); + let (response, painter) = ui.allocate_painter(size, Sense::click()); + let image = widgets::Image::new(texture, size); + image.paint_at(ui, response.rect); + let view = View(response.rect); + self.draw_board(&painter, view); + } + }); } } impl BoardBuilderApp { fn new(cc: &eframe::CreationContext<'_>) -> Self { - let mut style = (*cc.egui_ctx.style()).clone(); - let mut button = style::TextStyle::Button.resolve(&style); - button.size = 20.0; - style.text_styles.insert(style::TextStyle::Button, button); - cc.egui_ctx.set_style(style); - - - BoardBuilderApp::default() + let mut style = (*cc.egui_ctx.style()).clone(); + let mut button = style::TextStyle::Button.resolve(&style); + button.size = 20.0; + style.text_styles.insert(style::TextStyle::Button, button); + cc.egui_ctx.set_style(style); + + + BoardBuilderApp::default() } fn load_image_file(&mut self, ctx: &Context, image_file: &Path) -> Result<(), image::ImageError> { - let image = image::io::Reader::open(image_file)?.decode()?; - self.load_image(ctx, image); - Ok(()) + let image = image::io::Reader::open(image_file)?.decode()?; + self.load_image(ctx, image); + Ok(()) } - + fn load_image(&mut self, ctx: &Context, image: DynamicImage) { - let egui_image = egui::ColorImage::from_rgba_unmultiplied( - [image.width() as _, image.height() as _], - image.to_rgba8().as_flat_samples().as_slice(), - ); - - self.image = Some(image); - self.texture = Some(ctx.load_texture("board-image", egui_image)); + let egui_image = egui::ColorImage::from_rgba_unmultiplied( + [image.width() as _, image.height() as _], + image.to_rgba8().as_flat_samples().as_slice(), + ); + + self.image = Some(image); + self.texture = Some(ctx.load_texture("board-image", egui_image)); } fn draw_board(&self, painter: &Painter, view: View) { - for node in self.board.nodes.values() { - painter.text( - view.from_coords(node.x, node.y), - Align2::CENTER_CENTER, - &node.name, - FontId::proportional(16.0), - Color32::BLACK, - ); - let stroke = Stroke { width: 1.0, color: Color32::BLACK }; - for edge in &node.edges { - let other_node = &self.board.nodes[edge]; - painter.line_segment( - [view.from_coords(node.x, node.y), view.from_coords(other_node.x, other_node.y)], - stroke, - ); - } - } + for node in self.board.nodes.values() { + painter.text( + view.from_coords(node.x, node.y), + Align2::CENTER_CENTER, + &node.name, + FontId::proportional(16.0), + Color32::BLACK, + ); + let stroke = Stroke { width: 1.0, color: Color32::BLACK }; + for edge in &node.edges { + let other_node = &self.board.nodes[edge]; + painter.line_segment( + [view.from_coords(node.x, node.y), view.from_coords(other_node.x, other_node.y)], + stroke, + ); + } + } } } diff --git a/board.zip b/board.zip index e42c4e2ba1e77f32bb209954e511cbcc0d022f97..0e7ee8a84828f58e56ec82d3f6c3595bb456d2c0 100644 GIT binary patch delta 536 zcmex2U;h7m`T78FW)=|!1_lm>TN0~6e5d>sn#9P!pv1z!zy%adFG?)P(90^$&#S$3 z+V8c20NaD`m3#X7Y`*=t7R&GS#^I5YSVybkG8Y#2qTU@V-}eOv-CokPtZRzKPow{5 zY9`&gx3kW9+WaSX*6uzy`6;iZtW!Cd0M(&*@nMQkd5Vv}P$ zd1qREzSx$xLg!+F@^d){HphjIS!(>Om*;GHBWo$&{C4$$sn+4Cj;dO13%-Re5}1$| z()m87!?gXZV}=HA3fIz<`Y8W-mu3V_*9uRZ`|3>%?>W;zgFCWG@-yFc2}fFQoBg6G zKIW(1uChYGT%V-SS98*4y6GKwVx+2}I8|fg@~4$EwoW?lIM?xAR%#S5=g z3C;Pu_iOIam50NUOlQ7NX4?6{!SWPO-0uB{<#|?43Y9W6uRL9D|JC?U_9Jnx>3S`C zd=K~PRq@R>(qF6LTRlJg-jZcfHZ!hI{JL$cy_BMqZF%L(T&X>t-Mi+8Wqtl}{@wos z`(6L8zq$QZ93}Fak1@6%V+3I)AZ7+)79eH?Vz%wa7}@uq<%GxZ^uF`#`piJ?^aJPF Tr5SfkzjK~lhOO#6J21)tu#xpr delta 535 zcmexAU;f{G`T78FW)=|!1_lm>14~zi*l|}kOk`wWP-0=ha@0 z_C9PN!v0~s(We-d>635YTh@`!75BmM+k~4I-LYJeF3)e2o9o6-TDzf?hw1hD=YP(> zl-rt?dRuqa`-_WX&F4CQHZQsV^Mhq{&YJvtysIt*e~+Cry}h1m=eli&eRur-=~`UV zIyGp4OKaKRP7bFXM|A#O&C!{)*fo1wylvX+()!oZkzqd{wr6~D36#*Yi)ye`-(=r+ zZS76A*LU9>H9dH3^YR2I6=UA#Th5qFjSyy3_GO*yG*QKVM?%eI(P=9xOg}1AZan`` z%J!J#K^_;T__t4k&Zh>Rs8`Sws9Yn`Ca{2`B(+vUxHW6iN-vqkQzp)MQfTL*vDV|< zmvhmtqaMFvni4!A)xgj7xRiT<%kKYbA8yUwzijUXEybPToKhR?&dm-!YT$dRxAfrb zZ4oE#7}|$tIyDw9nrd~;T}6D;iu{;Q{l=4gPwA*BJ!Y8Ur)^jBWaSTGcDriNZTHL< ze%@_#hI7t+SuID7Sy@xL9)&$)5UZ0_&X}`v!m@KSCP^H(_19jPd|yf}|9o%ZGBfqZ z&!$?H^0%YLUGs6q_T!8o%ml>DK+FQftU%1R{Wv50{ Self { - let nodes = HashMap::new(); - let labels = HashMap::new(); - Board { nodes, labels } + let nodes = HashMap::new(); + let labels = HashMap::new(); + Board { nodes, labels } } pub fn add_node(&mut self, x: f32, y: f32, name: String) { - self.nodes.insert(self.next_id(), Node { - x, - y, - name, - edges: HashSet::new(), - labels: HashMap::new(), - }); + self.nodes.insert(self.next_id(), Node { + x, + y, + name, + edges: HashSet::new(), + labels: HashMap::new(), + }); } pub fn remove_node(&mut self, id: usize) { - // We remove this node from the graph, then drop it from each - // other nodes edge. - self.nodes.remove(&id); - for node in self.nodes.values_mut() { - node.edges.remove(&id); - } + // We remove this node from the graph, then drop it from each + // other nodes edge. + self.nodes.remove(&id); + for node in self.nodes.values_mut() { + node.edges.remove(&id); + } } pub fn nearest_node(&self, x: f32, y: f32) -> Option { - let f = |n: &Node| dist_sq((n.x, n.y), (x, y)); - let mut iter = self.nodes.iter(); - if let Some((id, node)) = iter.next() { - let mut min = *id; - let mut min_val = f(node); - for (id, node) in iter { - let val = f(node); - if val < min_val { - min = *id; - min_val = val; - } - } - Some(min) - } else { - None - } + let f = |n: &Node| dist_sq((n.x, n.y), (x, y)); + let mut iter = self.nodes.iter(); + if let Some((id, node)) = iter.next() { + let mut min = *id; + let mut min_val = f(node); + for (id, node) in iter { + let val = f(node); + if val < min_val { + min = *id; + min_val = val; + } + } + Some(min) + } else { + None + } } fn next_id(&self) -> usize { - for i in 0 .. { - if !self.nodes.contains_key(&i) { - return i; - } - } - unreachable!(); + for i in 0 .. { + if !self.nodes.contains_key(&i) { + return i; + } + } + unreachable!(); } } @@ -92,10 +92,10 @@ pub fn write_board_to_file(board: &Board, image: Option<&DynamicImage>, path: &P ar.start_file("graph.json", options)?; ar.write_all(&serde_json::to_vec(board)?)?; if let Some(image) = image { - ar.start_file("image.png", options)?; - let data = encode_png(image); - ar.write_all(&data)?; - ar.flush()?; + ar.start_file("image.png", options)?; + let data = encode_png(image); + ar.write_all(&data)?; + ar.flush()?; } ar.finish()?; Ok(()) @@ -109,7 +109,7 @@ pub fn read_board_from_file(path: &Path) -> io::Result<(Board, Option + From<(f32, f32)>> { fn origin(&self) -> I; fn extremes(&self) -> I; fn to_coords(&self, pos: I) -> (f32, f32) { - let (sx, sy) = self.origin().into(); - let (ex, ey) = self.extremes().into(); - let (x, y) = pos.into(); - ( - inv_lerp(sx, ex, x), - inv_lerp(sy, ey, y), - ) + let (sx, sy) = self.origin().into(); + let (ex, ey) = self.extremes().into(); + let (x, y) = pos.into(); + ( + inv_lerp(sx, ex, x), + inv_lerp(sy, ey, y), + ) } fn from_coords(&self, x: f32, y: f32) -> I { - let (sx, sy) = self.origin().into(); - let (ex, ey) = self.extremes().into(); - (lerp(sx, ex, x), lerp(sy, ey, y)).into() + let (sx, sy) = self.origin().into(); + let (ex, ey) = self.extremes().into(); + (lerp(sx, ex, x), lerp(sy, ey, y)).into() } }