Skip to content

Commit fe53395

Browse files
author
Tom
committed
Refactor hover datatype to work for constraints too
1 parent b5c79e1 commit fe53395

File tree

4 files changed

+148
-50
lines changed

4 files changed

+148
-50
lines changed

drawing/src/constraints.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ impl Constraint {
4040
}
4141
}
4242

43+
pub fn screen_dist_sq(
44+
&self,
45+
drawing: &crate::Data,
46+
hp: egui::Pos2,
47+
vp: &crate::Viewport,
48+
) -> Option<f32> {
49+
None
50+
}
51+
4352
pub fn paint(
4453
&self,
4554
drawing: &crate::Data,

drawing/src/data/mod.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{Feature, FeatureKey};
33
use slotmap::HopSlotMap;
44
use std::collections::HashMap;
55

6-
const MAX_HOVER_DISTANCE: f32 = 160.0;
6+
const MAX_HOVER_DISTANCE: f32 = 120.0;
77

88
mod viewport;
99
pub use viewport::Viewport;
@@ -14,6 +14,19 @@ pub use constraint_data::ConstraintData;
1414
mod terms;
1515
pub use terms::{TermAllocator, TermRef};
1616

17+
#[derive(Clone, Debug)]
18+
pub enum Hover {
19+
None,
20+
Feature {
21+
k: FeatureKey,
22+
feature: Feature,
23+
},
24+
Constraint {
25+
k: ConstraintKey,
26+
constraint: Constraint,
27+
},
28+
}
29+
1730
/// Data stores state about the drawing and what it is composed of.
1831
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
1932
pub struct Data {
@@ -114,8 +127,19 @@ impl Data {
114127
None
115128
}
116129

130+
/// Returns the 'thing' the screen coordinates are hovering over, if any.
131+
pub fn find_screen_hover(&self, hp: egui::Pos2) -> Hover {
132+
match self.find_screen_feature(hp) {
133+
Some((k, feature)) => Hover::Feature { k, feature },
134+
None => match self.find_screen_constraint(hp) {
135+
Some((k, constraint)) => Hover::Constraint { k, constraint },
136+
None => Hover::None,
137+
},
138+
}
139+
}
140+
117141
/// Returns the feature the screen coordinates are hovering over, if any.
118-
pub fn find_screen_feature(&self, hp: egui::Pos2) -> Option<(FeatureKey, Feature)> {
142+
fn find_screen_feature(&self, hp: egui::Pos2) -> Option<(FeatureKey, Feature)> {
119143
let mut closest: Option<(FeatureKey, f32, bool)> = None;
120144
for (k, v) in self.features.iter() {
121145
let is_point = v.is_point();
@@ -144,6 +168,30 @@ impl Data {
144168
}
145169
}
146170

171+
/// Returns the constraint the screen coordinates are hovering over, if any.
172+
fn find_screen_constraint(&self, hp: egui::Pos2) -> Option<(ConstraintKey, Constraint)> {
173+
let mut closest: Option<(ConstraintKey, f32)> = None;
174+
for (k, c) in self.constraints_iter() {
175+
let dist = match c.screen_dist_sq(self, hp, &self.vp) {
176+
Some(dist) => dist,
177+
None => continue,
178+
};
179+
180+
if dist < MAX_HOVER_DISTANCE {
181+
closest = Some(
182+
closest
183+
.map(|c| if dist < c.1 { (k, dist) } else { c })
184+
.unwrap_or((k, dist)),
185+
);
186+
}
187+
}
188+
189+
match closest {
190+
Some((k, _dist)) => Some((k, self.constraints.get(k).unwrap().clone())),
191+
None => None,
192+
}
193+
}
194+
147195
/// Moves the given feature to the given coordinates, and solving to update based on
148196
/// any side-effects of the move.
149197
pub fn move_feature(&mut self, k: FeatureKey, pos: egui::Pos2) {

drawing/src/lib.rs

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pub mod l;
44

55
mod data;
6-
pub use data::{Data, Viewport};
6+
pub use data::{Data, Hover, Viewport};
77
mod feature;
88
pub use feature::{Feature, FeatureKey, FeatureMeta};
99
mod constraints;
@@ -71,7 +71,7 @@ impl<'a> Widget<'a> {
7171
&mut self,
7272
ui: &mut egui::Ui,
7373
hp: Option<egui::Pos2>,
74-
hf: &Option<(FeatureKey, Feature)>,
74+
hover: &Hover,
7575
response: &egui::Response,
7676
) -> Option<Input> {
7777
// Handle: zooming
@@ -111,22 +111,30 @@ impl<'a> Widget<'a> {
111111
let current_input = if let Some(hp) = hp {
112112
let select_id = ui.make_persistent_id("select_box_start");
113113
let drag_state = if response.drag_started_by(egui::PointerButton::Primary) {
114-
match hf {
114+
match hover {
115115
// dragging a box to select
116-
None => {
116+
Hover::None => {
117117
let state = DragState::SelectBox(self.drawing.vp.screen_to_point(hp));
118118
ui.memory_mut(|mem| mem.data.insert_temp(select_id, state));
119119
Some(state)
120120
}
121121
// Dragging a point
122-
Some((fk, Feature::Point(_, px, py))) => {
122+
Hover::Feature {
123+
k,
124+
feature: Feature::Point(_, px, py),
125+
} => {
123126
let offset =
124127
self.drawing.vp.screen_to_point(hp) - egui::Pos2::new(*px, *py);
125-
let state = DragState::Feature(*fk, offset);
128+
let state = DragState::Feature(*k, offset);
126129
ui.memory_mut(|mem| mem.data.insert_temp(select_id, state));
127130
Some(state)
128131
}
129-
Some(_) => None,
132+
// TODO: dragging a line
133+
Hover::Feature {
134+
k: _,
135+
feature: Feature::LineSegment(..),
136+
} => None,
137+
Hover::Constraint { .. } => None,
130138
}
131139
} else {
132140
ui.memory(|mem| mem.data.get_temp(select_id))
@@ -177,7 +185,7 @@ impl<'a> Widget<'a> {
177185
let shift_held = ui.input(|i| i.modifiers.shift);
178186

179187
// feature clicked: add-to or replace selection
180-
if let Some((k, _)) = hf {
188+
if let Hover::Feature { k, .. } = hover {
181189
if !shift_held {
182190
self.drawing.selection_clear();
183191
}
@@ -218,7 +226,7 @@ impl<'a> Widget<'a> {
218226
ui: &egui::Ui,
219227
painter: &egui::Painter,
220228
hp: Option<egui::Pos2>,
221-
hf: Option<(FeatureKey, Feature)>,
229+
hover: Hover,
222230
response: &egui::Response,
223231
current_input: Option<Input>,
224232
base_params: &PaintParams,
@@ -230,17 +238,20 @@ impl<'a> Widget<'a> {
230238
continue;
231239
}
232240

233-
let hovered = hf.as_ref().map(|(hk, _dist)| hk == &k).unwrap_or(false)
234-
|| current_input
235-
.as_ref()
236-
.map(|dr| {
237-
if let Input::Selection(b) = dr {
238-
b.contains_rect(v.bb(self.drawing))
239-
} else {
240-
false
241-
}
242-
})
243-
.unwrap_or(false);
241+
let hovered = match hover {
242+
Hover::Feature { k: hk, .. } => hk == k,
243+
_ => false,
244+
} || current_input
245+
.as_ref()
246+
.map(|dr| {
247+
if let Input::Selection(b) = dr {
248+
b.contains_rect(v.bb(self.drawing))
249+
} else {
250+
false
251+
}
252+
})
253+
.unwrap_or(false);
254+
244255
let selected = self.drawing.selected_map.get(&k).is_some();
245256

246257
let pp = PaintParams {
@@ -339,16 +350,16 @@ impl<'a> Widget<'a> {
339350

340351
// Find hover feature, if any
341352
let hp = response.hover_pos();
342-
let hf = hp
343-
.map(|hp| self.drawing.find_screen_feature(hp))
344-
.unwrap_or(None);
353+
let hover = hp
354+
.map(|hp| self.drawing.find_screen_hover(hp))
355+
.unwrap_or(Hover::None);
345356

346357
// Handle input
347-
let current_input = if let Some(c) = self.tools.handle_input(ui, hp, &hf, &response) {
358+
let current_input = if let Some(c) = self.tools.handle_input(ui, hp, &hover, &response) {
348359
self.handler.handle(self.drawing, self.tools, c);
349360
None
350361
} else {
351-
self.handle_input(ui, hp, &hf, &response)
362+
self.handle_input(ui, hp, &hover, &response)
352363
};
353364

354365
let base_params = PaintParams {
@@ -372,7 +383,15 @@ impl<'a> Widget<'a> {
372383
};
373384
let painter = ui.painter();
374385

375-
self.draw(ui, painter, hp, hf, &response, current_input, &base_params);
386+
self.draw(
387+
ui,
388+
painter,
389+
hp,
390+
hover,
391+
&response,
392+
current_input,
393+
&base_params,
394+
);
376395
DrawResponse {}
377396
}
378397
}

drawing/src/tools.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::PaintParams;
2+
use crate::data::Hover;
23
use crate::handler::ToolResponse;
34

45
const TOOL_ICON_SIZE: egui::Vec2 = egui::Vec2 { x: 32.0, y: 32.0 };
@@ -155,50 +156,69 @@ impl Tool {
155156
&mut self,
156157
_ui: &mut egui::Ui,
157158
hp: egui::Pos2,
158-
hf: &Option<(crate::FeatureKey, crate::Feature)>,
159+
hover: &Hover,
159160
response: &egui::Response,
160161
) -> Option<ToolResponse> {
161162
match self {
162163
Tool::Point => {
163164
match (
164-
hf,
165+
hover,
165166
response.clicked(),
166167
response.drag_started_by(egui::PointerButton::Primary)
167168
|| response.drag_released_by(egui::PointerButton::Primary),
168169
) {
169-
(None, true, _) => Some(ToolResponse::NewPoint(hp)),
170-
(Some(_), true, _) => None,
170+
(Hover::None, true, _) => Some(ToolResponse::NewPoint(hp)),
171+
(Hover::Feature { .. } | Hover::Constraint { .. }, true, _) => None,
171172
(_, _, true) => Some(ToolResponse::Handled), // catch drag events
172173

173174
(_, false, false) => None,
174175
}
175176
}
176177

177178
Tool::Line(p1) => {
178-
let c = match (hf, &p1, response.clicked()) {
179+
let c = match (hover, &p1, response.clicked()) {
179180
// No first point, clicked on a point
180-
(Some((_, crate::Feature::Point(_, x, y))), None, true) => {
181+
(
182+
Hover::Feature {
183+
k: _,
184+
feature: crate::Feature::Point(_, x, y),
185+
},
186+
None,
187+
true,
188+
) => {
181189
*p1 = Some(egui::Pos2 { x: *x, y: *y });
182190
Some(ToolResponse::Handled)
183191
}
184192
// Has first point, clicked on a point
185-
(Some((_, crate::Feature::Point(_, x2, y2))), Some(starting_point), true) => {
193+
(
194+
Hover::Feature {
195+
k: _,
196+
feature: crate::Feature::Point(_, x2, y2),
197+
},
198+
Some(starting_point),
199+
true,
200+
) => {
186201
let starting_point = starting_point.clone();
187202
*p1 = Some(egui::Pos2 { x: *x2, y: *y2 });
188203
Some(ToolResponse::NewLineSegment(
189204
starting_point,
190205
egui::Pos2 { x: *x2, y: *y2 },
191206
))
192207
}
193-
(None, Some(_), true) => {
208+
(Hover::None, Some(_), true) => {
194209
*p1 = None;
195210
Some(ToolResponse::Handled)
196211
}
197212
// No first point, clicked empty space or line
198-
(None, None, true)
199-
| (Some((_, crate::Feature::LineSegment(_, _, _))), None, true) => {
200-
Some(ToolResponse::SwitchToPointer)
201-
}
213+
(Hover::None, None, true)
214+
| (
215+
Hover::Feature {
216+
feature: crate::Feature::LineSegment(..),
217+
..
218+
},
219+
None,
220+
true,
221+
) => Some(ToolResponse::SwitchToPointer),
202222

203223
_ => None,
204224
};
@@ -218,10 +238,11 @@ impl Tool {
218238

219239
Tool::Fixed => {
220240
if response.clicked() {
221-
return match hf {
222-
Some((k, crate::Feature::Point(_, _, _))) => {
223-
Some(ToolResponse::NewFixedConstraint(k.clone()))
224-
}
241+
return match hover {
242+
Hover::Feature {
243+
k,
244+
feature: crate::Feature::Point(..),
245+
} => Some(ToolResponse::NewFixedConstraint(k.clone())),
225246
_ => Some(ToolResponse::SwitchToPointer),
226247
};
227248
}
@@ -237,10 +258,11 @@ impl Tool {
237258

238259
Tool::Dimension => {
239260
if response.clicked() {
240-
return match hf {
241-
Some((k, crate::Feature::LineSegment(_, _, _))) => {
242-
Some(ToolResponse::NewLineLengthConstraint(k.clone()))
243-
}
261+
return match hover {
262+
Hover::Feature {
263+
k,
264+
feature: crate::Feature::LineSegment(..),
265+
} => Some(ToolResponse::NewLineLengthConstraint(k.clone())),
244266
_ => Some(ToolResponse::SwitchToPointer),
245267
};
246268
}
@@ -356,7 +378,7 @@ impl Toolbar {
356378
&mut self,
357379
ui: &mut egui::Ui,
358380
hp: Option<egui::Pos2>,
359-
hf: &Option<(crate::FeatureKey, crate::Feature)>,
381+
hover: &Hover,
360382
response: &egui::Response,
361383
) -> Option<ToolResponse> {
362384
// Escape to exit use of a tool
@@ -414,7 +436,7 @@ impl Toolbar {
414436
}
415437

416438
if let Some(current) = self.current.as_mut() {
417-
return current.handle_input(ui, hp, hf, response);
439+
return current.handle_input(ui, hp, hover, response);
418440
}
419441
}
420442
None

0 commit comments

Comments
 (0)