From 2422e65b2b7b5dbe80f07b26ad0b3668d3503da9 Mon Sep 17 00:00:00 2001 From: luxick Date: Thu, 10 Sep 2026 09:51:23 +0200 Subject: [PATCH] Replace grid BG with dots --- src/app.rs | 2 -- src/view.rs | 58 +++++++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/app.rs b/src/app.rs index 7861802..c4254e6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -635,7 +635,6 @@ impl App { self.view.zoom_to_selection(&self.doc.canvas); } ui.separator(); - ui.checkbox(&mut self.view.show_grid, "Show grid"); ui.checkbox(&mut self.view.snap_to_grid, "Snap to grid"); ui.checkbox(&mut self.show_inspector, "Inspector"); ui.checkbox(&mut self.dark_mode, "Dark mode"); @@ -715,7 +714,6 @@ impl App { ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.toggle_value(&mut self.show_inspector, "Inspector"); ui.toggle_value(&mut self.view.snap_to_grid, "Snap"); - ui.toggle_value(&mut self.view.show_grid, "Grid"); let icon = if self.dark_mode { "Light theme" } else { "Dark theme" }; if ui.button(icon).on_hover_text("Switch theme").clicked() { self.dark_mode = !self.dark_mode; diff --git a/src/view.rs b/src/view.rs index ed758e2..03f55f2 100644 --- a/src/view.rs +++ b/src/view.rs @@ -26,6 +26,12 @@ const MIN_ZOOM: f32 = 0.05; const MAX_ZOOM: f32 = 3.0; /// Spacing of the background grid, in canvas units. const GRID: f32 = 20.0; +/// Every this many dots the background gets a heavier one. +const MAJOR: f32 = 5.0; +/// Radius of a background dot, in screen pixels. +const DOT_RADIUS: f32 = 0.9; +/// Radius of a heavier background dot, in screen pixels. +const DOT_RADIUS_MAJOR: f32 = 1.5; /// How close the pointer has to be to an edge to hit it, in screen pixels. const EDGE_HIT_RADIUS: f32 = 8.0; /// Size of the resize/connect handles, in screen pixels. @@ -239,7 +245,6 @@ pub struct CanvasView { hovered_node: Option, /// Node whose connect handles are on screen, held still during a drag. connect_target: Option, - pub show_grid: bool, pub snap_to_grid: bool, pub previews: PreviewCache, /// How far each node's contents are scrolled, and how far they can go. @@ -287,7 +292,6 @@ impl CanvasView { hovered_edge: None, hovered_node: None, connect_target: None, - show_grid: true, snap_to_grid: false, previews: PreviewCache::default(), body_scroll: HashMap::new(), @@ -615,9 +619,7 @@ impl CanvasView { ui.ctx().set_transform_layer(layer, self.to_global); - if self.show_grid { - self.paint_grid(&scene, visible, palette); - } + self.paint_grid(&scene, visible, palette); // Groups are painted first so they cannot cover the edges, which in // turn run underneath the nodes they connect. let mut interactions = @@ -710,33 +712,37 @@ impl CanvasView { // -- painting --------------------------------------------------------- fn paint_grid(&self, ui: &egui::Ui, visible: Rect, palette: &Palette) { - // Below this the grid turns into noise, so it is skipped. - if self.to_global.scaling < 0.35 { + // Zoomed out far enough the dots crowd into noise, so only every fifth + // one is kept; below that they are dropped altogether. + let scale = self.to_global.scaling; + let step = if GRID * scale < 10.0 { GRID * MAJOR } else { GRID }; + if step * scale < 6.0 { return; } let painter = ui.painter(); - let thin = Stroke::new(1.0 / self.to_global.scaling, palette.grid); - let thick = Stroke::new(1.0 / self.to_global.scaling, palette.grid_strong); + // The dots keep the same size on screen whatever the zoom is. + let radius = DOT_RADIUS / scale; + let radius_major = DOT_RADIUS_MAJOR / scale; + // A dot lands on a multiple of this wherever the paper is emphasised. + let major = GRID * MAJOR; + let on_major = |v: f32| (v / major).fract().abs() < 1e-3; - let first_x = (visible.left() / GRID).floor() * GRID; + let first_x = (visible.left() / step).floor() * step; + let first_y = (visible.top() / step).floor() * step; let mut x = first_x; while x <= visible.right() { - let stroke = if (x / (GRID * 5.0)).fract().abs() < 1e-3 { thick } else { thin }; - painter.line_segment( - [pos2(x, visible.top()), pos2(x, visible.bottom())], - stroke, - ); - x += GRID; - } - let first_y = (visible.top() / GRID).floor() * GRID; - let mut y = first_y; - while y <= visible.bottom() { - let stroke = if (y / (GRID * 5.0)).fract().abs() < 1e-3 { thick } else { thin }; - painter.line_segment( - [pos2(visible.left(), y), pos2(visible.right(), y)], - stroke, - ); - y += GRID; + let major_x = on_major(x); + let mut y = first_y; + while y <= visible.bottom() { + let (radius, color) = if major_x && on_major(y) { + (radius_major, palette.grid_strong) + } else { + (radius, palette.grid) + }; + painter.circle_filled(pos2(x, y), radius, color); + y += step; + } + x += step; } }