@@ -41,7 +41,6 @@ impl Instance {
4141 match self . ty {
4242 InstanceType :: Gate ( g) => {
4343 let target = g. pos + move_vec;
44- // Gates are clamped with half size margins
4544 let clamped_x = target
4645 . x
4746 . clamp ( rect. left ( ) + half_extent. x , rect. right ( ) - half_extent. x ) ;
@@ -50,20 +49,27 @@ impl Instance {
5049 . clamp ( rect. top ( ) + half_extent. y , rect. bottom ( ) - half_extent. y ) ;
5150 vec2 ( clamped_x - g. pos . x , clamped_y - g. pos . y )
5251 }
52+ InstanceType :: Power ( p) => {
53+ let target = p. pos + move_vec;
54+ let clamped_x = target
55+ . x
56+ . clamp ( rect. left ( ) + half_extent. x , rect. right ( ) - half_extent. x ) ;
57+ let clamped_y = target
58+ . y
59+ . clamp ( rect. top ( ) + half_extent. y , rect. bottom ( ) - half_extent. y ) ;
60+ vec2 ( clamped_x - p. pos . x , clamped_y - p. pos . y )
61+ }
5362 InstanceType :: Wire ( w) => {
54- // Wires: both endpoints must remain inside the rect
5563 let ts = w. start + move_vec;
5664 let te = w. end + move_vec;
5765 let sx = ts. x . clamp ( rect. left ( ) , rect. right ( ) ) ;
5866 let sy = ts. y . clamp ( rect. top ( ) , rect. bottom ( ) ) ;
5967 let ex = te. x . clamp ( rect. left ( ) , rect. right ( ) ) ;
6068 let ey = te. y . clamp ( rect. top ( ) , rect. bottom ( ) ) ;
61- // Compute back the maximal safe delta that achieves those clamped targets
6269 let safe_dx_start = sx - w. start . x ;
6370 let safe_dy_start = sy - w. start . y ;
6471 let safe_dx_end = ex - w. end . x ;
6572 let safe_dy_end = ey - w. end . y ;
66- // We must respect both endpoints; take the limiting deltas
6773 let safe_dx = if move_vec. x . is_sign_positive ( ) {
6874 safe_dx_start. min ( safe_dx_end)
6975 } else {
@@ -109,6 +115,16 @@ impl Instance {
109115 } ) ;
110116 }
111117 }
118+ InstanceType :: Power ( power_instance) => {
119+ for ( i, pin) in power_instance. graphics ( ) . pins . iter ( ) . enumerate ( ) {
120+ let pin_pos = power_instance. pos + pin. offset ;
121+ pins. push ( Pin {
122+ pos : pin_pos,
123+ ins : self . id ,
124+ index : i as u32 ,
125+ } ) ;
126+ }
127+ }
112128 InstanceType :: Wire ( wire_instance) => {
113129 pins. push ( Pin {
114130 pos : wire_instance. start ,
@@ -135,6 +151,9 @@ impl Instance {
135151 InstanceType :: Gate ( gate) => {
136152 gate. pos += move_vec;
137153 }
154+ InstanceType :: Power ( power) => {
155+ power. pos += move_vec;
156+ }
138157 }
139158 }
140159
@@ -152,6 +171,10 @@ impl Instance {
152171 let move_vec = new_pos - pin. pos ;
153172 gate. pos += move_vec;
154173 }
174+ InstanceType :: Power ( power) => {
175+ let move_vec = new_pos - pin. pos ;
176+ power. pos += move_vec;
177+ }
155178 }
156179 }
157180}
@@ -160,6 +183,7 @@ impl Instance {
160183pub enum InstanceType {
161184 Gate ( GateInstance ) ,
162185 Wire ( WireInstance ) ,
186+ Power ( PowerInstance ) ,
163187}
164188
165189impl InstanceType {
@@ -173,6 +197,9 @@ impl InstanceType {
173197 fn new_gate ( kind : GateKind , pos : Pos2 ) -> Self {
174198 Self :: Gate ( GateInstance { kind, pos } )
175199 }
200+ fn new_power ( pos : Pos2 , on : bool ) -> Self {
201+ Self :: Power ( PowerInstance { pos, on } )
202+ }
176203}
177204
178205#[ derive( serde:: Deserialize , serde:: Serialize , Copy , Debug , Clone ) ]
@@ -197,6 +224,23 @@ impl GateKind {
197224 }
198225}
199226
227+ #[ derive( serde:: Deserialize , serde:: Serialize , Copy , Debug , Clone ) ]
228+ pub struct PowerInstance {
229+ // Center position
230+ pos : Pos2 ,
231+ on : bool ,
232+ }
233+
234+ impl PowerInstance {
235+ fn graphics ( & self ) -> & assets:: InstanceGraphics {
236+ if self . on {
237+ & assets:: POWER_ON_GRAPHICS
238+ } else {
239+ & assets:: POWER_OFF_GRAPHICS
240+ }
241+ }
242+ }
243+
200244#[ derive( serde:: Deserialize , serde:: Serialize , Copy , Debug , Clone ) ]
201245pub struct WireInstance {
202246 pub start : Pos2 ,
@@ -408,6 +452,16 @@ impl TemplateApp {
408452
409453 ui. add_space ( 8.0 ) ;
410454
455+ let pwr_image = egui:: Image :: new ( assets:: POWER_ON_GRAPHICS . svg . clone ( ) ) . max_height ( 70.0 ) ;
456+ let pwr_resp = ui. add ( egui:: ImageButton :: new ( pwr_image) . sense ( Sense :: click_and_drag ( ) ) ) ;
457+ if pwr_resp. dragged ( )
458+ && let Some ( pos) = ui. ctx ( ) . pointer_interact_pos ( )
459+ {
460+ self . panel_drag = Some ( PanelDrag :: new ( InstanceType :: new_power ( pos, true ) ) ) ;
461+ }
462+
463+ ui. add_space ( 8.0 ) ;
464+
411465 let wire_resp = ui. add (
412466 Button :: new ( "Wire" )
413467 . sense ( Sense :: click_and_drag ( ) )
@@ -450,14 +504,22 @@ impl TemplateApp {
450504 self . canvas_config . base_gate_size . x * 0.5 ,
451505 self . canvas_config . base_gate_size . y * 0.5 ,
452506 ) ;
453- // compute move from current preview pos to mouse, then clamp via temporary instance view
454507 let desired = mouse - g. pos ;
455508 let tmp = Instance :: new ( InstanceId ( 0 ) , InstanceType :: Gate ( * g) ) ;
456509 let delta = tmp. clamp_move ( desired, canvas_rect, half_extent) ;
457510 g. pos += delta;
458511 }
512+ InstanceType :: Power ( p) => {
513+ let half_extent = vec2 (
514+ self . canvas_config . base_gate_size . x * 0.5 ,
515+ self . canvas_config . base_gate_size . y * 0.5 ,
516+ ) ;
517+ let desired = mouse - p. pos ;
518+ let tmp = Instance :: new ( InstanceId ( 0 ) , InstanceType :: Power ( * p) ) ;
519+ let delta = tmp. clamp_move ( desired, canvas_rect, half_extent) ;
520+ p. pos += delta;
521+ }
459522 InstanceType :: Wire ( w) => {
460- // Move so that start follows mouse, but clamp as a wire move
461523 let desired = mouse - w. start ;
462524 let tmp = Instance :: new ( InstanceId ( 0 ) , InstanceType :: Wire ( * w) ) ;
463525 let delta = tmp. clamp_move ( desired, canvas_rect, vec2 ( 0.0 , 0.0 ) ) ;
@@ -469,6 +531,7 @@ impl TemplateApp {
469531 if inside_rect ( & canvas_rect, & pd. ty ) {
470532 match pd. ty {
471533 InstanceType :: Gate ( gate) => self . draw_gate ( ui, & gate) ,
534+ InstanceType :: Power ( power) => self . draw_power ( ui, & power) ,
472535 InstanceType :: Wire ( wire) => Self :: draw_wire ( ui, & wire) ,
473536 }
474537 }
@@ -487,6 +550,21 @@ impl TemplateApp {
487550 }
488551 let pointer_pos = ui. input ( |i| i. pointer . interact_pos ( ) ) ;
489552 let pointer_pressed = ui. input ( |i| i. pointer . primary_down ( ) ) ;
553+ let right_clicked = ui. input ( |i| i. pointer . secondary_clicked ( ) ) ;
554+
555+ if right_clicked
556+ && let Some ( mouse_pos) = pointer_pos
557+ && self . panel_drag . is_none ( )
558+ && self . canvas_drag . is_none ( )
559+ && self . resize . is_none ( )
560+ && let Some ( instance) = self . interacted_instance ( mouse_pos)
561+ && let InstanceType :: Power ( _) = instance. ty
562+ {
563+ let id = instance. id ;
564+ if let InstanceType :: Power ( pi) = & mut self . get_instance_mut ( id) . ty {
565+ pi. on = !pi. on ;
566+ }
567+ }
490568
491569 if pointer_pressed
492570 && let Some ( mouse_pos) = pointer_pos
@@ -496,14 +574,19 @@ impl TemplateApp {
496574 {
497575 let i = self . interacted_instance ( mouse_pos) ;
498576 if let Some ( instance) = i {
499- log:: debug!( "canvas drag on {instance:?}" ) ;
500577 match instance. ty {
501578 InstanceType :: Gate ( gate) => {
502579 self . canvas_drag = Some ( CanvasDrag :: new (
503580 instance. id ,
504581 gate. pos . to_vec2 ( ) - mouse_pos. to_vec2 ( ) ,
505582 ) ) ;
506583 }
584+ InstanceType :: Power ( power) => {
585+ self . canvas_drag = Some ( CanvasDrag :: new (
586+ instance. id ,
587+ power. pos . to_vec2 ( ) - mouse_pos. to_vec2 ( ) ,
588+ ) ) ;
589+ }
507590 InstanceType :: Wire ( wire) => {
508591 if mouse_pos. distance ( wire. end ) < 10.0 {
509592 self . resize = Some ( Resize {
@@ -538,6 +621,10 @@ impl TemplateApp {
538621 let desired = ( mouse_pos + offset) - gate. pos ;
539622 self . mov_component_with_connected ( id, desired, canvas_rect) ;
540623 }
624+ InstanceType :: Power ( power) => {
625+ let desired = ( mouse_pos + offset) - power. pos ;
626+ self . mov_component_with_connected ( id, desired, canvas_rect) ;
627+ }
541628 InstanceType :: Wire ( wire) => {
542629 let desired = ( mouse_pos + offset) - wire. end ;
543630 self . mov_component_with_connected ( id, desired, canvas_rect) ;
@@ -664,11 +751,15 @@ impl TemplateApp {
664751 InstanceType :: Gate ( gate) => {
665752 self . draw_gate ( ui, & gate) ;
666753 }
754+ InstanceType :: Power ( power) => {
755+ self . draw_power ( ui, & power) ;
756+ }
667757 InstanceType :: Wire ( wire) => {
668758 Self :: draw_wire ( ui, & wire) ;
669759 }
670760 }
671761 }
762+
672763 if mouse_up {
673764 self . resize = None ;
674765 self . canvas_drag = None ;
@@ -696,22 +787,22 @@ impl TemplateApp {
696787 } ;
697788 ui. painter ( )
698789 . circle_filled ( pin_pos, self . canvas_config . base_pin_size , color) ;
699- // paint connected pins
700- let mut conns : Vec < _ > = self . connections . iter ( ) . collect ( ) ;
701- conns . sort_by_key ( |c| {
702- (
703- c . pin1 . pos . x . to_bits ( ) ,
704- c . pin1 . pos . y . to_bits ( ) ,
705- c . pin2 . pos . x . to_bits ( ) ,
706- c . pin2 . pos . y . to_bits ( ) ,
707- )
708- } ) ;
709- for conn in conns {
710- if conn . pin1 . pos == pin_pos || conn . pin2 . pos == pin_pos {
711- // ui.painter()
712- // .circle_filled(pin_pos, 10.0, Color32::LIGHT_YELLOW) ;
713- }
714- }
790+ }
791+ }
792+
793+ fn draw_power ( & self , ui : & mut Ui , power : & PowerInstance ) {
794+ let rect = Rect :: from_center_size ( power . pos , self . canvas_config . base_gate_size ) ;
795+ let image = Image :: new ( power . graphics ( ) . svg . clone ( ) ) . fit_to_exact_size ( rect . size ( ) ) ;
796+ ui . put ( rect , image ) ;
797+
798+ for pin in power . graphics ( ) . pins {
799+ let pin_pos = power . pos + pin . offset ;
800+ let color = match pin . kind {
801+ assets :: PinKind :: Input => self . canvas_config . base_input_pin_color ,
802+ assets :: PinKind :: Output => self . canvas_config . base_output_pin_color ,
803+ } ;
804+ ui . painter ( )
805+ . circle_filled ( pin_pos , self . canvas_config . base_pin_size , color ) ;
715806 }
716807 }
717808
@@ -727,6 +818,14 @@ impl TemplateApp {
727818 break ;
728819 }
729820 }
821+ InstanceType :: Power ( power) => {
822+ let size = self . canvas_config . base_gate_size ;
823+ let rect = egui:: Rect :: from_center_size ( power. pos , size) ;
824+ if rect. contains ( mouse_pos) {
825+ i = Some ( instance) ;
826+ break ;
827+ }
828+ }
730829 InstanceType :: Wire ( wire) => {
731830 let dist = distance_point_to_segment ( mouse_pos, wire. start , wire. end ) ;
732831 if dist < 10.0 {
@@ -743,6 +842,7 @@ impl TemplateApp {
743842fn inside_rect ( canvas_rect : & Rect , ty : & InstanceType ) -> bool {
744843 match ty {
745844 InstanceType :: Gate ( gate_instance) => canvas_rect. contains ( gate_instance. pos ) ,
845+ InstanceType :: Power ( power_instance) => canvas_rect. contains ( power_instance. pos ) ,
746846 InstanceType :: Wire ( wire_instance) => {
747847 canvas_rect. contains ( wire_instance. start ) && canvas_rect. contains ( wire_instance. end )
748848 }
@@ -752,8 +852,8 @@ fn inside_rect(canvas_rect: &Rect, ty: &InstanceType) -> bool {
752852impl TemplateApp {
753853 fn get_wire_mut ( & mut self , id : InstanceId ) -> & mut WireInstance {
754854 match & mut self . get_instance_mut ( id) . ty {
755- InstanceType :: Gate ( _) => panic ! ( "Should not happen" ) ,
756855 InstanceType :: Wire ( wire_instance) => wire_instance,
856+ InstanceType :: Gate ( _) | InstanceType :: Power ( _) => panic ! ( "Should not happen" ) ,
757857 }
758858 }
759859
@@ -825,6 +925,17 @@ impl TemplateApp {
825925 dy_min = dy_min. max ( top - q. y ) ;
826926 dy_max = dy_max. min ( bottom - q. y ) ;
827927 }
928+ InstanceType :: Power ( p) => {
929+ let q = p. pos ;
930+ let left = rect. left ( ) + half_w;
931+ let right = rect. right ( ) - half_w;
932+ let top = rect. top ( ) + half_h;
933+ let bottom = rect. bottom ( ) - half_h;
934+ dx_min = dx_min. max ( left - q. x ) ;
935+ dx_max = dx_max. min ( right - q. x ) ;
936+ dy_min = dy_min. max ( top - q. y ) ;
937+ dy_max = dy_max. min ( bottom - q. y ) ;
938+ }
828939 InstanceType :: Wire ( w) => {
829940 for q in [ w. start , w. end ] {
830941 let left = rect. left ( ) ;
0 commit comments