11use std:: { collections:: HashSet , hash:: Hash } ;
22
33use 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
88use 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