From d703d5c3e37974142e5803da359cacb82043782a Mon Sep 17 00:00:00 2001 From: Alain Emilia Anna Zscheile Date: Wed, 1 Jan 2025 22:53:13 +0100 Subject: [PATCH] feat(viewport,overlay): drag to select bbox --- crates/topola-egui/src/overlay.rs | 18 ++++++++++++++++-- crates/topola-egui/src/viewport.rs | 16 ++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/crates/topola-egui/src/overlay.rs b/crates/topola-egui/src/overlay.rs index 51eea85..269392b 100644 --- a/crates/topola-egui/src/overlay.rs +++ b/crates/topola-egui/src/overlay.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use geo::Point; -use rstar::AABB; +use rstar::{Point as _, AABB}; use spade::InsertionError; use topola::{ @@ -59,10 +59,24 @@ impl Overlay { self.reselect_bbox = Some(None); } + pub fn drag_start(&mut self, board: &Board, at: Point) { + if let None | Some(None) = self.reselect_bbox { + // handle bounding box selection + self.reselect_bbox = Some(Some(at)); + } + } + + pub fn drag_stop(&mut self, board: &Board, at: Point) { + if let Some(aabb) = self.get_bbox_reselect(at) { + // handle bounding box selection + self.selected_bbox = aabb; + self.reselect_bbox = None; + } + } + pub fn click(&mut self, board: &Board, at: Point) { if let Some(rsbb) = self.reselect_bbox.take() { // handle bounding box selection (takes precendence over other interactions) - use rstar::Point; self.reselect_bbox = match rsbb { None => Some(Some(at)), Some(pt) => { diff --git a/crates/topola-egui/src/viewport.rs b/crates/topola-egui/src/viewport.rs index d5d9daa..17b1e70 100644 --- a/crates/topola-egui/src/viewport.rs +++ b/crates/topola-egui/src/viewport.rs @@ -51,11 +51,13 @@ impl Viewport { ui.ctx().request_repaint(); let (id, viewport_rect) = ui.allocate_space(ui.available_size()); - let response = ui.interact(viewport_rect, id, egui::Sense::click()); + let response = ui.interact(viewport_rect, id, egui::Sense::click_and_drag()); // NOTE: we use `interact_pos` instead of `latest_pos` to handle "pointer gone" // events more graceful let latest_pos = self.transform.inverse() - * (ctx.input(|i| i.pointer.interact_pos().unwrap_or_default())); + * (response.interact_pointer_pos().unwrap_or_else(|| { + ctx.input(|i| i.pointer.interact_pos().unwrap_or_default()) + })); let old_scaling = self.transform.scaling; self.transform.scaling *= ctx.input(|i| i.zoom_delta()); @@ -70,6 +72,7 @@ impl Viewport { let layers = &mut workspace.appearance_panel; let overlay = &mut workspace.overlay; let latest_point = point! {x: latest_pos.x as f64, y: -latest_pos.y as f64}; + let board = workspace.interactor.invoker().autorouter().board(); if response.clicked() { if menu_bar.is_placing_via { @@ -87,11 +90,12 @@ impl Viewport { maybe_net: Some(1234), })); } else { - overlay.click( - workspace.interactor.invoker().autorouter().board(), - latest_point, - ); + overlay.click(board, latest_point); } + } else if response.drag_started() { + overlay.drag_start(board, latest_point); + } else if response.drag_stopped() { + overlay.drag_stop(board, latest_point); } else if let Some(cur_bbox) = overlay.get_bbox_reselect(latest_point) { painter.paint_bbox_with_color(cur_bbox, egui::Color32::RED); }