diff --git a/Cargo.lock b/Cargo.lock index c8a5785..ef25d7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,7 +146,7 @@ dependencies = [ [[package]] name = "board-builder-gui" -version = "1.0.0" +version = "1.1.0" dependencies = [ "board-builder", "eframe", diff --git a/board-builder-gui/Cargo.toml b/board-builder-gui/Cargo.toml index 7b4cab9..c49b81b 100644 --- a/board-builder-gui/Cargo.toml +++ b/board-builder-gui/Cargo.toml @@ -3,10 +3,9 @@ name = "board-builder-gui" version = "1.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] board-builder = { path = "../" } eframe = "0.18.0" rfd = "0.8.2" -image = "0.24.2" \ No newline at end of file +image = "0.24.2" + diff --git a/board-builder-gui/src/main.rs b/board-builder-gui/src/main.rs index 07b7aee..fbbae6e 100644 --- a/board-builder-gui/src/main.rs +++ b/board-builder-gui/src/main.rs @@ -7,7 +7,7 @@ use image::DynamicImage; use rfd::FileDialog; -use board_builder::{ Board, Node, CoordTransformer, read_board_from_file, write_board_to_file }; +use board_builder::{ Board, Node, CoordTransformer, read_board_from_file, write_board_to_file, should_wrap_horizontal }; use std::path::Path; use std::collections::HashSet; @@ -29,6 +29,7 @@ struct BoardBuilderApp { create_node_dialog: CreateNodeDialog, edit_node_dialog: EditNodeDialog, edit_labels_dialog: EditLabelsDialog, + edit_settings_dialog: EditSettingsDialog, } #[derive(Clone, Copy)] @@ -93,7 +94,10 @@ impl eframe::App for BoardBuilderApp { if ui.button("Edit Labels...").clicked() { self.edit_labels_dialog.show(Rc::clone(&self.board)); } - }) + }); + if ui.button("Settings...").clicked() { + self.edit_settings_dialog.show(Rc::clone(&self.board)); + }; }); }); CentralPanel::default().show(ctx, |ui| { @@ -121,6 +125,7 @@ impl eframe::App for BoardBuilderApp { self.create_node_dialog.ui(ctx); self.edit_node_dialog.ui(ctx); self.edit_labels_dialog.ui(ctx); + self.edit_settings_dialog.ui(ctx); } } @@ -169,10 +174,25 @@ impl BoardBuilderApp { let stroke = Stroke { width: 1.0, color: Color32::BLACK }; for edge in &node.edges { let other_node = &board.nodes[edge]; - painter.line_segment( - [view.inv_xform(node.x, node.y), view.inv_xform(other_node.x, other_node.y)], - stroke, - ); + if board.config.horizontal_wrapping && should_wrap_horizontal(node, other_node) { + let mut nodes = [node, other_node]; + nodes.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap()); + let [left_node, right_node] = nodes; + let y_mid = (left_node.y + right_node.y) / 2.0; + painter.line_segment( + [view.inv_xform(0.0, y_mid), view.inv_xform(left_node.x, left_node.y)], + stroke + ); + painter.line_segment( + [view.inv_xform(right_node.x, right_node.y), view.inv_xform(1.0, y_mid)], + stroke + ); + } else { + painter.line_segment( + [view.inv_xform(node.x, node.y), view.inv_xform(other_node.x, other_node.y)], + stroke, + ); + } } } } @@ -364,7 +384,6 @@ impl EditLabelsDialog { } } - #[derive(Default)] struct StringDialog { string: String, @@ -422,3 +441,26 @@ fn node_common_ui(ui: &mut Ui, node: &mut Node, board: &Board) { }); } } + +#[derive(Default)] +struct EditSettingsDialog { + open: bool, + board: Rc> +} + +impl EditSettingsDialog { + fn show(&mut self, board: Rc>) { + self.board = board; + self.open = true; + } + + fn ui(&mut self, ctx: &Context) { + Window::new("Settings") + .collapsible(false) + .open(&mut self.open) + .show(ctx, |ui| { + let mut board = self.board.borrow_mut(); + ui.checkbox(&mut board.config.horizontal_wrapping, "Horizontal Wrapping"); + }); + } +} diff --git a/samples/risk.board b/samples/risk.board index b3adf8f..3832c09 100644 Binary files a/samples/risk.board and b/samples/risk.board differ diff --git a/src/lib.rs b/src/lib.rs index 9442bcf..cc314e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,18 @@ use serde::{ Serialize, Deserialize }; use std::collections::{ HashMap, HashSet }; +#[derive(Serialize, Deserialize, Debug)] +#[serde(default)] +pub struct Config { + pub horizontal_wrapping: bool, +} +impl Default for Config { + fn default() -> Self { + Config { + horizontal_wrapping: false, + } + } +} #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[serde(default)] pub struct Node { @@ -16,14 +28,9 @@ pub struct Node { pub struct Board { pub labels: HashMap>, pub nodes: HashMap, + pub config: Config, } impl Board { - pub fn new() -> Self { - 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, @@ -60,8 +67,8 @@ impl Board { } pub fn add_edge(&mut self, from: usize, to: usize) { - let node = self.nodes.get_mut(&from).expect("Could not find node"); - node.edges.insert(to); + let node = self.nodes.get_mut(&from).expect("Could not find node"); + node.edges.insert(to); } pub fn nearest_node(&self, x: f32, y: f32) -> Option { @@ -97,6 +104,12 @@ fn dist_sq((x0, y0): (f32, f32), (x1, y1): (f32, f32)) -> f32 { (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0) } +pub fn should_wrap_horizontal(node1: &Node, node2: &Node) -> bool { + let mut xs = [node1.x, node2.x]; + xs.sort_by(|a, b| a.partial_cmp(b).unwrap()); + xs[0] + (1.0 - xs[1]) < xs[1] - xs[0] +} + use std::io; use std::io::{ Write, Read, Cursor }; use std::fs::File;