Skip to content

Commit f29ab7d

Browse files
committed
Draft selection
1 parent 66ebf54 commit f29ab7d

File tree

1 file changed

+106
-8
lines changed

1 file changed

+106
-8
lines changed

src/app.rs

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{collections::HashSet, hash::Hash};
22

33
use egui::{
4-
Align, Button, Color32, Image, Layout, Pos2, Rect, Sense, Stroke, Ui, Vec2, Widget as _, pos2,
5-
vec2,
4+
Align, Button, Color32, CornerRadius, Image, Layout, Pos2, Rect, Sense, Stroke, StrokeKind, Ui,
5+
Vec2, Widget as _, pos2, vec2,
66
};
77

88
use crate::{assets, config::CanvasConfig};
@@ -397,6 +397,11 @@ pub struct TemplateApp {
397397
/// Currently dragged gate id from canvas
398398
canvas_drag: Option<CanvasDrag>,
399399

400+
/// If the user started a selection
401+
selection: Option<Pos2>,
402+
403+
selected: HashSet<InstanceId>,
404+
400405
/// An item is being resized
401406
resize: Option<Resize>,
402407

@@ -414,6 +419,8 @@ impl Default for TemplateApp {
414419
panel_drag: None,
415420
canvas_drag: None,
416421
resize: None,
422+
selection: None,
423+
selected: Default::default(),
417424
canvas_config: CanvasConfig::default(),
418425
}
419426
}
@@ -443,8 +450,8 @@ impl TemplateApp {
443450
ui.add_sized(
444451
vec2(200.0, 50.0),
445452
egui::TextEdit::multiline(&mut format!(
446-
"world {:#?}\n conn: {:#?}\n current: {:#?}\n moving: {:#?}\n\n\n",
447-
self.instances, self.connections, sorted_current, self.canvas_drag
453+
"world {:#?}\n conn: {:#?}\n current: {:#?}\n moving: {:#?}\n selected: {:#?}\n\n\n",
454+
self.instances, self.connections, sorted_current, self.canvas_drag, self.selected
448455
)),
449456
)
450457
});
@@ -498,7 +505,7 @@ impl TemplateApp {
498505
let wire_resp = ui.add(
499506
Button::new("Wire")
500507
.sense(Sense::click_and_drag())
501-
.min_size(vec2(48.0, 30.0)),
508+
.min_size(vec2(78.0, 30.0)),
502509
);
503510
if wire_resp.dragged()
504511
&& let Some(pos) = ui.ctx().pointer_interact_pos()
@@ -566,7 +573,7 @@ impl TemplateApp {
566573
}
567574
if inside_rect(&canvas_rect, &pd.ty) {
568575
match pd.ty {
569-
InstanceType::Gate(gate) => self.draw_gate(ui, &gate),
576+
InstanceType::Gate(gate) => self.draw_gate(ui, InstanceId(u32::MAX), &gate),
570577
InstanceType::Power(power) => self.draw_power(ui, &power),
571578
InstanceType::Wire(wire) => self.draw_wire(ui, InstanceId(u32::MAX), &wire),
572579
}
@@ -608,6 +615,7 @@ impl TemplateApp {
608615
&& self.panel_drag.is_none()
609616
&& self.canvas_drag.is_none()
610617
&& self.resize.is_none()
618+
&& self.selection.is_none()
611619
{
612620
let i = self.interacted_instance(mouse_pos);
613621
if let Some(instance) = i {
@@ -669,6 +677,47 @@ impl TemplateApp {
669677
}
670678
}
671679

680+
// Make a selection
681+
if self.selection.is_none()
682+
&& self.panel_drag.is_none()
683+
&& self.canvas_drag.is_none()
684+
&& pointer_pressed
685+
&& let Some(mouse_pos) = pointer_pos
686+
&& canvas_rect.contains(mouse_pos)
687+
&& self.interacted_instance(mouse_pos).is_none()
688+
{
689+
self.selection = Some(mouse_pos);
690+
}
691+
if let Some(selection) = self.selection
692+
&& let Some(mouse_pos) = pointer_pos
693+
{
694+
let x = mouse_pos.x.clamp(canvas_rect.left(), canvas_rect.right());
695+
let y = mouse_pos.y.clamp(canvas_rect.top(), canvas_rect.bottom());
696+
let rect = Rect::from_two_pos(selection, pos2(x, y));
697+
ui.painter().rect_stroke(
698+
rect,
699+
CornerRadius::default(),
700+
Stroke::new(2.0, Color32::DARK_BLUE),
701+
StrokeKind::Middle,
702+
);
703+
}
704+
705+
// TODO: Does not work breaks selection
706+
// if let Some(mouse_pos) = pointer_pos
707+
// && self.selection.is_none()
708+
// {
709+
// if let Some(i) = {
710+
// let id_opt = self.interacted_instance(mouse_pos).map(|c| c.id);
711+
// id_opt
712+
// } {
713+
// self.selected.retain(|id| *id == i);
714+
// self.selected.insert(i);
715+
// } else {
716+
// self.selected.clear();
717+
// }
718+
// }
719+
720+
// Create connections
672721
if self.canvas_drag.is_some() || self.resize.is_some() {
673722
// TODO: Only need to check this on placement and moving.
674723
// Also use a better way than iterating on everything.
@@ -822,7 +871,7 @@ impl TemplateApp {
822871
for instance in &self.instances {
823872
match instance.ty {
824873
InstanceType::Gate(gate) => {
825-
self.draw_gate(ui, &gate);
874+
self.draw_gate(ui, instance.id, &gate);
826875
}
827876
InstanceType::Power(power) => {
828877
self.draw_power(ui, &power);
@@ -836,6 +885,18 @@ impl TemplateApp {
836885
if mouse_up {
837886
self.resize = None;
838887
self.canvas_drag = None;
888+
if let Some(selection) = self.selection
889+
&& let Some(mouse_pos) = pointer_pos
890+
{
891+
// TODO sync with other rect
892+
let rect = Rect::from_two_pos(selection, mouse_pos);
893+
let instances = self.selected_instances(rect);
894+
self.selected = instances;
895+
self.selection = None;
896+
} else {
897+
self.selected.clear();
898+
self.selection = None;
899+
}
839900
}
840901
}
841902

@@ -850,11 +911,24 @@ impl TemplateApp {
850911
.line_segment([wire.start, wire.end], Stroke::new(thickness, color));
851912
}
852913

853-
fn draw_gate(&self, ui: &mut Ui, gate: &GateInstance) {
914+
fn draw_gate(&self, ui: &mut Ui, instance_id: InstanceId, gate: &GateInstance) {
854915
let rect = Rect::from_center_size(gate.pos, self.canvas_config.base_gate_size);
855916
let image = Image::new(gate.kind.graphics().svg.clone()).fit_to_exact_size(rect.size());
856917
ui.put(rect, image);
857918

919+
if self.selected.contains(&instance_id) {
920+
let outer = Rect::from_center_size(
921+
gate.pos,
922+
self.canvas_config.base_gate_size + vec2(3.0, 3.0),
923+
);
924+
ui.painter().rect_stroke(
925+
outer,
926+
CornerRadius::default(),
927+
Stroke::new(2.0, Color32::DARK_BLUE),
928+
StrokeKind::Middle,
929+
);
930+
}
931+
858932
for pin in gate.kind.graphics().pins {
859933
let pin_pos = gate.pos + pin.offset;
860934
let color = match pin.kind {
@@ -882,6 +956,30 @@ impl TemplateApp {
882956
}
883957
}
884958

959+
fn selected_instances(&self, rect: Rect) -> HashSet<InstanceId> {
960+
let mut instances = HashSet::new();
961+
for instance in &self.instances {
962+
match instance.ty {
963+
InstanceType::Gate(gate) => {
964+
if rect.contains(gate.pos) {
965+
instances.insert(instance.id);
966+
}
967+
}
968+
InstanceType::Power(power) => {
969+
if rect.contains(power.pos) {
970+
instances.insert(instance.id);
971+
}
972+
}
973+
InstanceType::Wire(wire) => {
974+
if rect.contains(wire.start) && rect.contains(wire.end) {
975+
instances.insert(instance.id);
976+
}
977+
}
978+
}
979+
}
980+
instances
981+
}
982+
885983
fn interacted_instance(&self, mouse_pos: Pos2) -> Option<&Instance> {
886984
let mut i: Option<&Instance> = None;
887985
for instance in &self.instances {

0 commit comments

Comments
 (0)