From 96c3dde25007276d4e14833e3cdc9988ba8ac247 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 2 Jan 2025 12:32:35 +0530 Subject: [PATCH 01/59] [Feature enhancement]: Pressing the 'w'-key now sets the schematic editor to wire-drawing mode, instead of immediately placing down the wire. Press LMB in this state to start drawing the wire. --- src/callback.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index 53af0107..2ffefcc7 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2577,10 +2577,12 @@ int rstate; /* (reduced state, without ShiftMask) */ { int prev_state = xctx->ui_state; if(xctx->semaphore >= 2) break; - start_wire(xctx->mousex_snap, xctx->mousey_snap); if(prev_state == STARTWIRE) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); tcleval("set constr_mv 0" ); xctx->constr_mv=0; + } else{ + tcleval("xschem wire"); } break; } From 76e106563ba626bb8ec98846dea583b02b870cbe Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 2 Jan 2025 18:46:46 +0530 Subject: [PATCH 02/59] [UI/UX Enhancement]: When the 'w'-key is pressed to enter wire-drawing mode, until drawing begins with an LMB-click - a new bottom status-bar entry will appear in deep blue color along with the text {WIRE READY TO DRAW! } - indicating the current editor mode. Either pressing 'Esc'-key, or starting the wire-drawing process with an LMB-click will cause this new status-bar entry to disappear. --- src/callback.c | 5 +++++ src/xschem.tcl | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index 2ffefcc7..9a1f64d5 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2070,6 +2070,11 @@ int rstate; /* (reduced state, without ShiftMask) */ } #endif + if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) { + tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {WIRE READY TO DRAW! }", NULL); + } else { + tclvareval(xctx->top_path, ".statusbar.10 configure -state normal -text { }", NULL); + } tclvareval(xctx->top_path, ".statusbar.7 configure -text $netlist_type", NULL); tclvareval(xctx->top_path, ".statusbar.3 delete 0 end;", xctx->top_path, ".statusbar.3 insert 0 $cadsnap", diff --git a/src/xschem.tcl b/src/xschem.tcl index 1732f10e..867e5b9d 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7731,6 +7731,7 @@ proc pack_widgets { { topwin {} } } { pack $topwin.statusbar.6 -side left pack $topwin.statusbar.7 -side left pack $topwin.statusbar.10 -side left + pack $topwin.statusbar.11 -side left pack $topwin.statusbar.9 -side left pack $topwin.statusbar.8 -side left pack $topwin.statusbar.1 -side left -fill x @@ -8471,7 +8472,8 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get entry_replace_selection $topwin.statusbar.5 label $topwin.statusbar.6 -text "MODE:" label $topwin.statusbar.7 -width 7 - label $topwin.statusbar.10 -text {Stretch:} + label $topwin.statusbar.11 -text {Stretch:} + label $topwin.statusbar.10 -activebackground blue -text {} label $topwin.statusbar.9 -textvariable enable_stretch label $topwin.statusbar.8 -activebackground red -text {} add_toolbuttons $topwin From 052d7e87933872ccaf07ee9510a8296685fa9c05 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 2 Jan 2025 20:03:42 +0530 Subject: [PATCH 03/59] [Added New Feature]: New menu option 'Enable infix wire' is now accessible through the 'Options' menu. This option is turned-off by default and can be enabled anytime through the menu or the 'xschemrc' file to make xschem-editor revert back to it's old behavior, prior to commit 96c3dde25007276d4e14833e3cdc9988ba8ac247 --- src/callback.c | 12 ++++++++---- src/xschem.tcl | 7 +++++-- src/xschemrc | 5 +++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/callback.c b/src/callback.c index 6c1a6f5a..7a1202c3 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2611,13 +2611,17 @@ int rstate; /* (reduced state, without ShiftMask) */ { int prev_state = xctx->ui_state; if(xctx->semaphore >= 2) break; - if(prev_state == STARTWIRE) { + if(tclgetboolvar("infix_wire")) { start_wire(xctx->mousex_snap, xctx->mousey_snap); - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } else{ + } else if(prev_state == STARTWIRE) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + } else { tcleval("xschem wire"); } + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0"); + xctx->constr_mv = 0; + } break; } if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ diff --git a/src/xschem.tcl b/src/xschem.tcl index f4adc72c..10002cd6 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7478,7 +7478,7 @@ set tctx::global_list { PDK_ROOT PDK SKYWATER_MODELS SKYWATER_STDCELLS INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow - autotrim_wires bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers + autotrim_wires infix_wire bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names @@ -7899,7 +7899,7 @@ proc build_widgets { {topwin {} } } { global netlist_show flat_netlist split_files compare_sch intuitive_interface global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type - global disable_unique_names persistent_command autotrim_wires en_hilight_conn_inst + global disable_unique_names persistent_command autotrim_wires infix_wire en_hilight_conn_inst global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry if { $dark_gui_colorscheme} { set selectcolor white @@ -8022,6 +8022,8 @@ proc build_widgets { {topwin {} } } { -onvalue disk -offvalue memory -command {switch_undo} $topwin.menubar.option add checkbutton -label "Enable stretch" -variable enable_stretch \ -selectcolor $selectcolor -accelerator Y + $topwin.menubar.option add checkbutton -label "Enable infix-wire" -variable infix_wire \ + -selectcolor $selectcolor $topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \ -selectcolor $selectcolor -variable unselect_partial_sel_wires @@ -8938,6 +8940,7 @@ set_ne draw_grid_axes 1 set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne autotrim_wires 0 +set_ne infix_wire 0 set_ne compare_sch 0 set_ne disable_unique_names 0 set_ne sym_txt 1 diff --git a/src/xschemrc b/src/xschemrc index a31096bd..fa6f7363 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -221,6 +221,11 @@ #### if not set show selected items at end of drag. Default: enabled (1) # set incremental_select 0 +#### if set to 1, pressing 'w' will immediately place a wire at current cursor +#### position without waiting for Button1 (LMB) click. Can be disabled via menu +#### default: 0 +# set infix_wire 1 + #### if set to 1 automatically join/trim wires while editing #### this may slow down on rally big designs. Can be disabled via menu #### default: 0 From b1e4d14a805abf3d8c146c6354c03c488d47e811 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 3 Jan 2025 18:08:33 +0530 Subject: [PATCH 04/59] [Changed behavior of a workflow action]: While the 'persistent-wire-draw' checkbox is ticked in the 'Options'-menu, pressing 'Esc' will immediately eject the user from wire-drawing-mode and end any multi-segment wire being drawn. Double click behavior remains the same as before. --- src/callback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/callback.c b/src/callback.c index 7a1202c3..96791a6c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2635,6 +2635,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* stuff that can be done reentrantly ... */ tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)) { + xctx->last_command &= ~STARTWIRE; + } break; } if(key=='z' && rstate == 0) /* zoom box */ From 8981b47ed3461be615373b47e4f47db48e47e3b4 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 3 Jan 2025 18:35:15 +0530 Subject: [PATCH 05/59] [Fixed an issue]: The bottom-statusbar now correctly indicates if the schematic editor is currently in wire-drawing-mode or not. The color of the indicator has been changed to a more visible and non-alerting green, and the text has been shortened to only display 'DRAW WIRE! ' instead of the previous message. --- src/callback.c | 4 ++-- src/xschem.tcl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index 96791a6c..f95fdaea 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2099,8 +2099,8 @@ int rstate; /* (reduced state, without ShiftMask) */ } #endif - if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) { - tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {WIRE READY TO DRAW! }", NULL); + if((xctx->ui_state & STARTWIRE) || (xctx->ui_state2 & MENUSTARTWIRE) || (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE))) { + tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {DRAW WIRE! }", NULL); } else { tclvareval(xctx->top_path, ".statusbar.10 configure -state normal -text { }", NULL); } diff --git a/src/xschem.tcl b/src/xschem.tcl index 158fa05c..25e6b615 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -8565,7 +8565,7 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get label $topwin.statusbar.6 -text "MODE:" label $topwin.statusbar.7 -width 7 label $topwin.statusbar.11 -text {Stretch:} - label $topwin.statusbar.10 -activebackground blue -text {} + label $topwin.statusbar.10 -activebackground green -text {} label $topwin.statusbar.9 -textvariable enable_stretch label $topwin.statusbar.8 -activebackground red -text {} add_toolbuttons $topwin From 3b5541070903a75239ba61198890e1c187ef506c Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 5 Jan 2025 13:20:52 +0530 Subject: [PATCH 06/59] [Added New Feature]: New menu option 'Enable orthogonal wiring' is now accessible through the 'Options' menu. This option is kept ON-BY-DEFAULT and can be disabled through the menu, 'Shift+L'-keyboard-shortcut, or by editing the 'xschemrc' file to make xschem-editor revert back to it's old behavior - which was drawing wires in free-form mode (Unconstrained move). The functionality of the 'h' and 'v' keys are preserved, and they can still be used to force the editor to only draw horizontal or vertical wires respectively. --- src/callback.c | 19 ++++++++++++++++++- src/xschem.tcl | 7 +++++-- src/xschemrc | 6 ++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index f95fdaea..dce70d83 100644 --- a/src/callback.c +++ b/src/callback.c @@ -87,7 +87,14 @@ void redraw_w_a_l_r_p_rubbers(void) if(xctx->ui_state & STARTWIRE) { if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + if(tclgetboolvar("orthogonal_wiring")) { + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + int tmp_x2 = xctx->nl_x2 - xctx->nl_x1, tmp_y2 = xctx->nl_y2 - xctx->nl_y1; + if(tmp_x2*tmp_x2 > tmp_y2*tmp_y2) xctx->manhattan_lines = 1; + else xctx->manhattan_lines = 2; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + else new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); } if(xctx->ui_state & STARTARC) { if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; @@ -3323,6 +3330,16 @@ int rstate; /* (reduced state, without ShiftMask) */ place_net_label(0); break; } + if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ + if(tclgetboolvar("orthogonal_wiring")){ + tclsetboolvar("orthogonal_wiring", 0); + } else { + tclsetboolvar("orthogonal_wiring", 1); + } + xctx->manhattan_lines = 0; + redraw_w_a_l_r_p_rubbers(); + break; + } if(key=='F' && rstate == 0) /* flip */ { if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); diff --git a/src/xschem.tcl b/src/xschem.tcl index 8d0b32e5..1e40e473 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7521,7 +7521,7 @@ set tctx::global_list { PDK_ROOT PDK SKYWATER_MODELS SKYWATER_STDCELLS INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow - autotrim_wires infix_wire bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers + autotrim_wires infix_wire orthogonal_wiring bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names @@ -7942,7 +7942,7 @@ proc build_widgets { {topwin {} } } { global netlist_show flat_netlist split_files compare_sch intuitive_interface global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type - global disable_unique_names persistent_command autotrim_wires infix_wire en_hilight_conn_inst + global disable_unique_names persistent_command autotrim_wires infix_wire orthogonal_wiring en_hilight_conn_inst global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry if { $dark_gui_colorscheme} { set selectcolor white @@ -8067,6 +8067,8 @@ proc build_widgets { {topwin {} } } { -selectcolor $selectcolor -accelerator Y $topwin.menubar.option add checkbutton -label "Enable infix-wire" -variable infix_wire \ -selectcolor $selectcolor + $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring mode" -variable orthogonal_wiring \ + -selectcolor $selectcolor -accelerator Shift+L $topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \ -selectcolor $selectcolor -variable unselect_partial_sel_wires @@ -8998,6 +9000,7 @@ set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne autotrim_wires 0 set_ne infix_wire 0 +set_ne orthogonal_wiring 1 set_ne compare_sch 0 set_ne disable_unique_names 0 set_ne sym_txt 1 diff --git a/src/xschemrc b/src/xschemrc index fa6f7363..fc15f538 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -226,6 +226,12 @@ #### default: 0 # set infix_wire 1 +#### wires are drawn in free-form mode with this mode enabled (default). +#### if set to 0, wires drawn on the schematic will no longer strictly +#### follow orthogonal routes to connect two distinct points toegther. +#### default: 1 +# set orthogonal_wiring 0 + #### if set to 1 automatically join/trim wires while editing #### this may slow down on rally big designs. Can be disabled via menu #### default: 0 From f020e45364bc292780b1ea4dc2c1b714e998feb4 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Mon, 6 Jan 2025 15:57:37 +0530 Subject: [PATCH 07/59] [Experimental Feature Update (orthogonal_wiring)]: Modified the last added orthogonal wiring mode to only draw either a horizontal, or a vertical component when a user-click event is detected. To get the best experience with this feature, 'persistent_commands' should also be enabled from the 'Options' menu. --- src/callback.c | 19 ++++++++++++------- src/xschem.tcl | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/callback.c b/src/callback.c index dce70d83..45c645f0 100644 --- a/src/callback.c +++ b/src/callback.c @@ -85,16 +85,20 @@ static int waves_selected(int event, KeySym key, int state, int button) void redraw_w_a_l_r_p_rubbers(void) { if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; if(tclgetboolvar("orthogonal_wiring")) { new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); int tmp_x2 = xctx->nl_x2 - xctx->nl_x1, tmp_y2 = xctx->nl_y2 - xctx->nl_y1; - if(tmp_x2*tmp_x2 > tmp_y2*tmp_y2) xctx->manhattan_lines = 1; - else xctx->manhattan_lines = 2; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + if(tmp_x2*tmp_x2 > tmp_y2*tmp_y2){ + tcleval("set constr_mv 1"); + xctx->constr_mv = 1; + } else { + tcleval("set constr_mv 2"); + xctx->constr_mv = 2; + } } - else new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); } if(xctx->ui_state & STARTARC) { if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; @@ -3333,10 +3337,11 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ if(tclgetboolvar("orthogonal_wiring")){ tclsetboolvar("orthogonal_wiring", 0); + tcleval("set constr_mv 0"); + xctx->constr_mv = 0; } else { tclsetboolvar("orthogonal_wiring", 1); } - xctx->manhattan_lines = 0; redraw_w_a_l_r_p_rubbers(); break; } diff --git a/src/xschem.tcl b/src/xschem.tcl index 1e40e473..f7ed1411 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -8067,7 +8067,7 @@ proc build_widgets { {topwin {} } } { -selectcolor $selectcolor -accelerator Y $topwin.menubar.option add checkbutton -label "Enable infix-wire" -variable infix_wire \ -selectcolor $selectcolor - $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring mode" -variable orthogonal_wiring \ + $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \ -selectcolor $selectcolor -accelerator Shift+L $topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \ -selectcolor $selectcolor -variable unselect_partial_sel_wires From 21d4abcfc038666fe2a33c0d6a1c67874fe6f5ff Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 9 Jan 2025 15:56:29 +0530 Subject: [PATCH 08/59] [Experimental Feature Update (orthogonal_wiring)]: Modified the last added orthogonal wiring mode to only FINALIZE either a horizontal, or a vertical component when a user-click event is detected. HOWEVER, the full orthogonal wire is drawn on the canvas anyways. A double-click using LMB causes both the horizontal and vertical components to get finalized, and the wire-drawing mode is simultaneously terminated. To get the best experience with this feature, 'persistent_commands' should also be enabled from the 'Options' menu. --- src/callback.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/callback.c b/src/callback.c index 45c645f0..a967ce3f 100644 --- a/src/callback.c +++ b/src/callback.c @@ -85,19 +85,17 @@ static int waves_selected(int event, KeySym key, int state, int button) void redraw_w_a_l_r_p_rubbers(void) { if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; if(tclgetboolvar("orthogonal_wiring")) { new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); int tmp_x2 = xctx->nl_x2 - xctx->nl_x1, tmp_y2 = xctx->nl_y2 - xctx->nl_y1; if(tmp_x2*tmp_x2 > tmp_y2*tmp_y2){ - tcleval("set constr_mv 1"); - xctx->constr_mv = 1; + xctx->manhattan_lines = 1; } else { - tcleval("set constr_mv 2"); - xctx->constr_mv = 2; + xctx->manhattan_lines = 2; } } - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); } if(xctx->ui_state & STARTARC) { @@ -201,10 +199,14 @@ static void start_line(double mx, double my) static void start_wire(double mx, double my) { - dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n", - xctx->ui_state, xctx->ui_state2, xctx->last_command); + dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n", xctx->ui_state, xctx->ui_state2, xctx->last_command); xctx->last_command = STARTWIRE; if(xctx->ui_state & STARTWIRE) { + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = xctx->manhattan_lines; + new_wire(CLEAR, mx, my); + redraw_w_a_l_r_p_rubbers(); + } if(xctx->constr_mv != 2) { xctx->mx_double_save = mx; } @@ -218,6 +220,9 @@ static void start_wire(double mx, double my) xctx->my_double_save=my; } new_wire(PLACE,mx, my); + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = 0; + } } static double interpolate_yval(int idx, int p, double x, int sweep_idx, int point_not_last) @@ -3337,8 +3342,7 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ if(tclgetboolvar("orthogonal_wiring")){ tclsetboolvar("orthogonal_wiring", 0); - tcleval("set constr_mv 0"); - xctx->constr_mv = 0; + xctx->manhattan_lines = 0; } else { tclsetboolvar("orthogonal_wiring", 1); } @@ -4045,6 +4049,8 @@ int rstate; /* (reduced state, without ShiftMask) */ edit_property(0); } else { if(xctx->ui_state & STARTWIRE) { + redraw_w_a_l_r_p_rubbers(); + start_wire(mx, my); xctx->ui_state &= ~STARTWIRE; } if(xctx->ui_state & STARTLINE) { From 24bfb5b3637b8b7a1d969981e9238d633bc9f4cd Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 17 Jan 2025 11:42:59 +0530 Subject: [PATCH 09/59] [Bugfix]: Fixed an issue where the bottom statusbar showed the green zsh: command not found: Draw indicatior when the user enters and exits wire-drawing mode without actually drawing a wire. --- src/callback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/callback.c b/src/callback.c index c0e65b64..606f95bb 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2772,6 +2772,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* stuff that can be done reentrantly ... */ tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(xctx->ui_state2 & MENUSTARTWIRE) { + xctx->ui_state2 &= ~MENUSTARTWIRE; + } if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)) { xctx->last_command &= ~STARTWIRE; } From 8ce32b73b7ab7abb0e84e2ff5fa6aafd6307b71d Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 18 Jan 2025 14:05:29 +0530 Subject: [PATCH 10/59] [Code Refactoring]: Modified the source code for compatibility with the upstream repo (due to 'infix_wire' feature integration with new name 'infix_interface') --- src/callback.c | 85 +++++++++++++++++++++++++++++++++----------------- src/xschem.tcl | 8 ++--- 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/callback.c b/src/callback.c index 606f95bb..dc85ca6e 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2202,6 +2202,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, XKeyboardState kbdstate; #endif int draw_xhair = tclgetboolvar("draw_crosshair"); +int infix_interface = tclgetboolvar("infix_interface"); int rstate; /* (reduced state, without ShiftMask) */ /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease @@ -2748,16 +2749,17 @@ int rstate; /* (reduced state, without ShiftMask) */ { int prev_state = xctx->ui_state; if(xctx->semaphore >= 2) break; - if(tclgetboolvar("infix_wire")) { - start_wire(xctx->mousex_snap, xctx->mousey_snap); - } else if(prev_state == STARTWIRE) { + + if(infix_interface) { start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0"); + xctx->constr_mv = 0; + } } else { - tcleval("xschem wire"); - } - if(prev_state == STARTWIRE) { - tcleval("set constr_mv 0"); - xctx->constr_mv = 0; + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTWIRE; } break; } @@ -2805,10 +2807,15 @@ int rstate; /* (reduced state, without ShiftMask) */ { if(xctx->semaphore >= 2) break; dbg(1, "callback(): start polygon\n"); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + if(infix_interface) { + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTPOLYGON; + } break; } if(key=='P' && rstate == 0) /* pan, other way to. */ @@ -2957,10 +2964,15 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ { dbg(1, "callback(): start rect\n"); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + } else{ + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTRECT; + } break; } if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ @@ -3130,19 +3142,29 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ { if(xctx->semaphore >= 2) break; - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTARC; + } break; } if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ { if(xctx->semaphore >= 2) break; - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCIRCLE; + } break; } if(key=='O' && rstate == ControlMask ) /* load most recent tile */ @@ -3452,10 +3474,17 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ { int prev_state = xctx->ui_state; - start_line(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTLINE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; + if(xctx->semaphore>=2) break; + if(infix_interface) { + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTLINE; } break; } diff --git a/src/xschem.tcl b/src/xschem.tcl index 24b5da01..e615f1ea 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7589,7 +7589,7 @@ set tctx::global_list { PDK_ROOT PDK SKYWATER_MODELS SKYWATER_STDCELLS INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow - autotrim_wires infix_wire orthogonal_wiring bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers + autotrim_wires infix_interface orthogonal_wiring bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names @@ -8010,7 +8010,7 @@ proc build_widgets { {topwin {} } } { global netlist_show flat_netlist split_files compare_sch intuitive_interface global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type - global disable_unique_names persistent_command autotrim_wires infix_wire orthogonal_wiring en_hilight_conn_inst + global disable_unique_names persistent_command autotrim_wires infix_interface orthogonal_wiring en_hilight_conn_inst global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry if { $dark_gui_colorscheme} { set selectcolor white @@ -8133,7 +8133,7 @@ proc build_widgets { {topwin {} } } { -onvalue disk -offvalue memory -command {switch_undo} $topwin.menubar.option add checkbutton -label "Enable stretch" -variable enable_stretch \ -selectcolor $selectcolor -accelerator Y - $topwin.menubar.option add checkbutton -label "Enable infix-wire" -variable infix_wire \ + $topwin.menubar.option add checkbutton -label "Enable infix-interface" -variable infix_interface \ -selectcolor $selectcolor $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \ -selectcolor $selectcolor -accelerator Shift+L @@ -9067,7 +9067,7 @@ set_ne draw_grid_axes 1 set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne autotrim_wires 0 -set_ne infix_wire 0 +set_ne infix_interface 0 set_ne orthogonal_wiring 1 set_ne compare_sch 0 set_ne disable_unique_names 0 From 7fe267842a89f2136658a1d770f4cb5405f686d1 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 18 Jan 2025 14:08:44 +0530 Subject: [PATCH 11/59] [Code Refactoring]: Modified the source code for compatibility with the upstream repo (due to 'infix_wire' feature integration with new name 'infix_interface') --- src/xschemrc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/xschemrc b/src/xschemrc index fc15f538..2dd5ca90 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -221,10 +221,11 @@ #### if not set show selected items at end of drag. Default: enabled (1) # set incremental_select 0 -#### if set to 1, pressing 'w' will immediately place a wire at current cursor -#### position without waiting for Button1 (LMB) click. Can be disabled via menu +#### if set to 1, pressing 'w', 'l', 'r', 'C', or 'Ctrl+C' will immediately place the +#### corresponding component at current cursor position without waiting for Button1 (LMB) click. +#### This setting can be disabled via the Options menu #### default: 0 -# set infix_wire 1 +# set infix_interface 1 #### wires are drawn in free-form mode with this mode enabled (default). #### if set to 0, wires drawn on the schematic will no longer strictly From 26df8d7d21c68ba0944b0164dcb00fcaf4b38326 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 18 Jan 2025 15:50:36 +0530 Subject: [PATCH 12/59] [Code Refactoring]: Modified the source code for compatibility with the upstream repo (due to 'infix_wire' feature integration with new name 'infix_interface') --- src/callback.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/callback.c b/src/callback.c index d061ffb2..7a21213c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2749,23 +2749,12 @@ int rstate; /* (reduced state, without ShiftMask) */ { int prev_state = xctx->ui_state; if(xctx->semaphore >= 2) break; -<<<<<<< HEAD - - if(infix_interface) { - start_wire(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTWIRE) { - tcleval("set constr_mv 0"); - xctx->constr_mv = 0; - } -======= - if(infix_interface) { start_wire(xctx->mousex_snap, xctx->mousey_snap); if(prev_state == STARTWIRE) { tcleval("set constr_mv 0" ); xctx->constr_mv=0; } ->>>>>>> 025823f14c8ca1f9562a1c452fffe267c7120905 } else { xctx->last_command = 0; xctx->ui_state |= MENUSTART; @@ -2818,13 +2807,8 @@ int rstate; /* (reduced state, without ShiftMask) */ if(xctx->semaphore >= 2) break; dbg(1, "callback(): start polygon\n"); if(infix_interface) { -<<<<<<< HEAD - xctx->mx_double_save = xctx->mousex_snap; - xctx->my_double_save = xctx->mousey_snap; -======= xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; ->>>>>>> 025823f14c8ca1f9562a1c452fffe267c7120905 xctx->last_command = 0; new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); } else { @@ -2979,20 +2963,13 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ { dbg(1, "callback(): start rect\n"); -<<<<<<< HEAD -======= if(xctx->semaphore >= 2) break; ->>>>>>> 025823f14c8ca1f9562a1c452fffe267c7120905 if(infix_interface) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; xctx->last_command = 0; new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); -<<<<<<< HEAD - } else{ -======= } else { ->>>>>>> 025823f14c8ca1f9562a1c452fffe267c7120905 xctx->ui_state |= MENUSTART; xctx->ui_state2 = MENUSTARTRECT; } @@ -3497,11 +3474,7 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ { int prev_state = xctx->ui_state; -<<<<<<< HEAD - if(xctx->semaphore>=2) break; -======= if(xctx->semaphore >= 2) break; ->>>>>>> 025823f14c8ca1f9562a1c452fffe267c7120905 if(infix_interface) { start_line(xctx->mousex_snap, xctx->mousey_snap); if(prev_state == STARTLINE) { From 92428e44094f1c0a8b4a572c8ea602a24e4c10fe Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 18 Jan 2025 15:52:17 +0530 Subject: [PATCH 13/59] [Code Refactoring]: Modified the source code for compatibility with the upstream repo (due to 'infix_wire' feature integration with new name 'infix_interface') --- src/xschem.tcl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xschem.tcl b/src/xschem.tcl index f12371c8..c350c7bd 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -9066,7 +9066,6 @@ set_ne big_grid_points 0 set_ne draw_grid_axes 1 set_ne persistent_command 0 set_ne intuitive_interface 1 -set_ne infix_interface 1 set_ne autotrim_wires 0 set_ne infix_interface 0 set_ne orthogonal_wiring 1 From ed1a471f5dd9f413ef7511a7e0704587455147f2 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Mon, 20 Jan 2025 14:12:33 +0530 Subject: [PATCH 14/59] [Fixed Upstream Bug]: While the schematic editor is in intuitive-interface mode, drawing a wire would immediately terminate the endpoint of it when the LMB button is released (i.e. user click drew a point - when persistent_command was disabled). This behavior is now corrected, but a non-essential feature introduced in the last set of upstream commits had to be broken (end wire creation when dragging in intuitive interface mode). The broken feature will be fixed in a future commit. --- src/callback.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index d52d6727..37888f88 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4207,9 +4207,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - else if(xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { - if(end_place_move_copy_zoom()) break; - } + /*else if(xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ + /* if(end_place_move_copy_zoom()) break;*/ + /*}*/ /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From 320b8efc4b3c7860a114bb9b1fd8a8c5f9c4ca34 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Mon, 20 Jan 2025 23:20:53 +0530 Subject: [PATCH 15/59] [Snap Cursor (WIP)]: Experimental feature 'snap_cursor' is now available to be selected from the Options menu (disabled by default). This is a work in progress and needs a lot more polishing to be properly usable. Currently only supports snapping to nearest component-endpoint. --- src/callback.c | 51 ++++++++++++++++++++++++++ src/draw.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/xschem.tcl | 7 ++-- 3 files changed, 154 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 37888f88..3276ba95 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1393,6 +1393,51 @@ void draw_crosshair(int what) xctx->draw_pixmap = sdp; } +/* cursor_type == 0 : only erase drawn cursor + * cursor_type == 1 : erase and draw a normal grid-snapping cursor + * cursor_type == 2 : erase and draw a diamond-shaped cursor that snaps to a component endpoint */ +void draw_snap_cursor(int cursor_type) +{ + int sdw, sdp; + dbg(1, "draw_snap_cursor(): cursor_type=%d\n", cursor_type); + sdw = xctx->draw_window; + sdp = xctx->draw_pixmap; + + if(!xctx->mouse_inside) return; + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + if(fix_broken_tiled_fill || !_unix) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw), + xctx->xrect[0].width, 4 * INT_WIDTH(xctx->lw), + 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw)); + + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0, + 4 * INT_WIDTH(xctx->lw), xctx->xrect[0].height, + (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0); + } else { + drawtemparc(xctx->gctiled, NOW, xctx->prev_crossx, xctx->prev_crossy, 1, 0, 360); + } + if(cursor_type != 1) { + /*drawline(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap, xctx->mousey_snap, 0, NULL);*/ + double x, y; + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + drawarc(xctx->crosshair_layer, NOW, x, y, 1, 1, 360, 1, 0); + draw_selection(xctx->gc[SELLAYER], 0); + xctx->prev_crossx = x; + xctx->prev_crossy = y; + } else { + drawarc(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, 1, 1, 360, 1, 0); + draw_selection(xctx->gc[SELLAYER], 0); + xctx->prev_crossx = xctx->mousex_snap; + xctx->prev_crossy = xctx->mousey_snap; + } + + xctx->draw_window = sdw; + xctx->draw_pixmap = sdp; +} + /* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ static int end_place_move_copy_zoom() { @@ -2218,6 +2263,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, #endif int draw_xhair = tclgetboolvar("draw_crosshair"); int infix_interface = tclgetboolvar("infix_interface"); +int snap_cursor = tclgetboolvar("snap_cursor"); int rstate; /* (reduced state, without ShiftMask) */ /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease @@ -2335,6 +2381,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case LeaveNotify: if(draw_xhair) draw_crosshair(1); + if(snap_cursor) draw_snap_cursor(0); tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); xctx->mouse_inside = 0; break; @@ -2403,11 +2450,13 @@ int rstate; /* (reduced state, without ShiftMask) */ if(draw_xhair) { draw_crosshair(1); } + if(snap_cursor) draw_snap_cursor(0); if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); if(xctx->semaphore >= 2) { if(draw_xhair) { draw_crosshair(2); } + if(snap_cursor) draw_snap_cursor(2); break; } dbg(1, "ui_state=%d deltax=%g\n", xctx->ui_state, xctx->deltax); @@ -2502,6 +2551,7 @@ int rstate; /* (reduced state, without ShiftMask) */ if(draw_xhair) { draw_crosshair(2); } + if(snap_cursor) draw_snap_cursor(2); break; case KeyRelease: @@ -4259,6 +4309,7 @@ int rstate; /* (reduced state, without ShiftMask) */ statusmsg(str,1); } if(draw_xhair) draw_crosshair(0); + if(snap_cursor) draw_snap_cursor(2); break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { diff --git a/src/draw.c b/src/draw.c index 6c7bf8b7..dcf409ac 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1601,6 +1601,104 @@ void drawarc(int c, int what, double x, double y, double r, double a, double b, } } +void draw_snap_point(int c, int what, double x, double y, double r, double a, double b, int arc_fill, int dash) +{ + static int i=0; + static XArc xarc[CADDRAWBUFFERSIZE]; + double x1, y1, x2, y2; /* arc bbox */ + double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */ + GC gc; + + if(arc_fill || dash) what = NOW; + + if(!has_x) return; + if(what & ADD) + { + if(i>=CADDRAWBUFFERSIZE) + { + if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i); + if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i); + i=0; + } + xx1=X_TO_SCREEN(x-r); + yy1=Y_TO_SCREEN(y-r); + xx2=X_TO_SCREEN(x+r); + yy2=Y_TO_SCREEN(y+r); + arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); + x1=X_TO_SCREEN(x1); + y1=Y_TO_SCREEN(y1); + x2=X_TO_SCREEN(x2); + y2=Y_TO_SCREEN(y2); + if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) + { + xarc[i].x=(short)xx1; + xarc[i].y=(short)yy1; + xarc[i].width =(unsigned short)(xx2 - xx1); + xarc[i].height=(unsigned short)(yy2 - yy1); + xarc[i].angle1 = (short)(a*64); + xarc[i].angle2 = (short)(b*64); + ++i; + } + } + else if(what & NOW) + { + xx1=X_TO_SCREEN(x-r); + yy1=Y_TO_SCREEN(y-r); + xx2=X_TO_SCREEN(x+r); + yy2=Y_TO_SCREEN(y+r); + if(arc_fill) + arc_bbox(x, y, r, 0, 360, &x1,&y1,&x2,&y2); + else + arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); + x1=X_TO_SCREEN(x1); + y1=Y_TO_SCREEN(y1); + x2=X_TO_SCREEN(x2); + y2=Y_TO_SCREEN(y2); + if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) + { + if(dash) { + char dash_arr[2]; + dash_arr[0] = dash_arr[1] = (char)dash; + XSetDashes(display, xctx->gc[c], 0, dash_arr, 1); + XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw), xDashType, xCap, xJoin); + } + + if(xctx->draw_window) { + XDrawArc(display, xctx->window, xctx->gc[c], (int)xx1, (int)yy1, + (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); + } + if(xctx->draw_pixmap) { + XDrawArc(display, xctx->save_pixmap, xctx->gc[c], (int)xx1, (int)yy1, + (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); + } + + if(xctx->fill_pattern && (xctx->fill_type[c] || arc_fill == 3) ){ + + if(arc_fill & 2) gc = xctx->gc[c]; + else gc = xctx->gcstipple[c]; + if(arc_fill) { + if(xctx->draw_window) + XFillArc(display, xctx->window, gc, (int)xx1, (int)yy1, + (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); + if(xctx->draw_pixmap) + XFillArc(display, xctx->save_pixmap, gc, (int)xx1, (int)yy1, + (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); + } + } + if(dash) { + XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw) ,LineSolid, LINECAP , LINEJOIN); + } + } + } + else if((what & END) && i) + { + if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i); + if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i); + i=0; + } +} + + void filledrect(int c, int what, double rectx1,double recty1,double rectx2,double recty2, int fill, int e_a, int e_b) { diff --git a/src/xschem.tcl b/src/xschem.tcl index 99f2c4fc..b02bb3ef 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7622,7 +7622,7 @@ set tctx::global_list { PDK_ROOT PDK SKYWATER_MODELS SKYWATER_STDCELLS INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow - autotrim_wires infix_interface orthogonal_wiring bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers + autotrim_wires orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names @@ -8042,7 +8042,7 @@ proc build_widgets { {topwin {} } } { global recentfile color_ps transparent_svg menu_debug_var enable_stretch global netlist_show flat_netlist split_files compare_sch intuitive_interface global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width - global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type + global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type snap_cursor global disable_unique_names persistent_command autotrim_wires infix_interface orthogonal_wiring en_hilight_conn_inst global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry if { $dark_gui_colorscheme} { @@ -8168,6 +8168,8 @@ proc build_widgets { {topwin {} } } { -selectcolor $selectcolor -accelerator Y $topwin.menubar.option add checkbutton -label "Enable infix-interface" -variable infix_interface \ -selectcolor $selectcolor + $topwin.menubar.option add checkbutton -label "Enable snap cursor" -variable snap_cursor \ + -selectcolor $selectcolor $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \ -selectcolor $selectcolor -accelerator Shift+L $topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \ @@ -9101,6 +9103,7 @@ set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne autotrim_wires 0 set_ne infix_interface 0 +set_ne snap_cursor 0 set_ne orthogonal_wiring 1 set_ne compare_sch 0 set_ne disable_unique_names 0 From 7f613294f4897e178b99490231f41085f2f87fdb Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Tue, 21 Jan 2025 15:49:52 +0530 Subject: [PATCH 16/59] [Snap Cursor (WIP)]: Experimental feature 'snap_cursor' is updated. It can be selected from the Options menu (disabled by default) and will take effect when the wire-drawing mode is active. This is a work in progress and needs a lot more polishing to be properly usable. Currently only supports snapping to nearest component-endpoint. Cursor to snap to nearest grid point is pending. --- src/callback.c | 58 ++++++++++++++---------------- src/draw.c | 98 -------------------------------------------------- 2 files changed, 27 insertions(+), 129 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3276ba95..c1406a3f 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,6 +21,7 @@ */ #include "xschem.h" +#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) @@ -1393,9 +1394,9 @@ void draw_crosshair(int what) xctx->draw_pixmap = sdp; } -/* cursor_type == 0 : only erase drawn cursor - * cursor_type == 1 : erase and draw a normal grid-snapping cursor - * cursor_type == 2 : erase and draw a diamond-shaped cursor that snaps to a component endpoint */ +/* cursor_type == 0 : erase and draw a new cursor + * cursor_type == 1 : erase the cursor + * cursor_type == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ void draw_snap_cursor(int cursor_type) { int sdw, sdp; @@ -1406,33 +1407,27 @@ void draw_snap_cursor(int cursor_type) if(!xctx->mouse_inside) return; xctx->draw_pixmap = 0; xctx->draw_window = 1; - if(fix_broken_tiled_fill || !_unix) { - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw), - xctx->xrect[0].width, 4 * INT_WIDTH(xctx->lw), - 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw)); - - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0, - 4 * INT_WIDTH(xctx->lw), xctx->xrect[0].height, - (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0); - } else { - drawtemparc(xctx->gctiled, NOW, xctx->prev_crossx, xctx->prev_crossy, 1, 0, 360); + if(cursor_type != 2) { + if(fix_broken_tiled_fill || !_unix) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); + } else { + double prev_x = xctx->prev_crossx; + double prev_y = xctx->prev_crossy; + double points_x[5] = {prev_x, prev_x+3, prev_x, prev_x-3, prev_x}; + double points_y[5] = {prev_y-3, prev_y, prev_y+3, prev_y, prev_y-3}; + drawtemppolygon(xctx->gctiled, NOW, points_x, points_y, 5, 0); + } } if(cursor_type != 1) { - /*drawline(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap, xctx->mousey_snap, 0, NULL);*/ double x, y; find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - drawarc(xctx->crosshair_layer, NOW, x, y, 1, 1, 360, 1, 0); - draw_selection(xctx->gc[SELLAYER], 0); + double points_x[5] = {x, x+3, x, x-3, x}; + double points_y[5] = {y-3, y, y+3, y, y-3}; + drawpolygon(8, NOW, points_x, points_y, 5, 0, 0, 0); xctx->prev_crossx = x; xctx->prev_crossy = y; - } else { - drawarc(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, 1, 1, 360, 1, 0); - draw_selection(xctx->gc[SELLAYER], 0); - xctx->prev_crossx = xctx->mousex_snap; - xctx->prev_crossy = xctx->mousey_snap; } + draw_selection(xctx->gc[SELLAYER], 0); xctx->draw_window = sdw; xctx->draw_pixmap = sdp; @@ -2264,6 +2259,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, int draw_xhair = tclgetboolvar("draw_crosshair"); int infix_interface = tclgetboolvar("infix_interface"); int snap_cursor = tclgetboolvar("snap_cursor"); +int wire_draw_active = (xctx->ui_state & STARTWIRE) || (xctx->ui_state2 & MENUSTARTWIRE) || (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); int rstate; /* (reduced state, without ShiftMask) */ /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease @@ -2298,7 +2294,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } #endif - if((xctx->ui_state & STARTWIRE) || (xctx->ui_state2 & MENUSTARTWIRE) || (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE))) { + if(wire_draw_active) { tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {DRAW WIRE! }", NULL); } else { tclvareval(xctx->top_path, ".statusbar.10 configure -state normal -text { }", NULL); @@ -2381,7 +2377,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case LeaveNotify: if(draw_xhair) draw_crosshair(1); - if(snap_cursor) draw_snap_cursor(0); + if(snap_cursor && wire_draw_active) draw_snap_cursor(1); tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); xctx->mouse_inside = 0; break; @@ -2450,13 +2446,13 @@ int rstate; /* (reduced state, without ShiftMask) */ if(draw_xhair) { draw_crosshair(1); } - if(snap_cursor) draw_snap_cursor(0); + if(snap_cursor && wire_draw_active) draw_snap_cursor(1); if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); if(xctx->semaphore >= 2) { if(draw_xhair) { draw_crosshair(2); } - if(snap_cursor) draw_snap_cursor(2); + if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; } dbg(1, "ui_state=%d deltax=%g\n", xctx->ui_state, xctx->deltax); @@ -2551,7 +2547,7 @@ int rstate; /* (reduced state, without ShiftMask) */ if(draw_xhair) { draw_crosshair(2); } - if(snap_cursor) draw_snap_cursor(2); + if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; case KeyRelease: @@ -2792,7 +2788,7 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; snapped_wire(c_snap); break; @@ -3034,7 +3030,7 @@ int rstate; /* (reduced state, without ShiftMask) */ draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ break; } - if(key=='s' && rstate == 0 ) /* simulate */ + if(key=='r' && rstate == ControlMask ) /* simulate */ { if(xctx->semaphore >= 2) break; if(waves_selected(event, key, state, button)) { @@ -4309,7 +4305,7 @@ int rstate; /* (reduced state, without ShiftMask) */ statusmsg(str,1); } if(draw_xhair) draw_crosshair(0); - if(snap_cursor) draw_snap_cursor(2); + if(snap_cursor && wire_draw_active) draw_snap_cursor(0); break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { diff --git a/src/draw.c b/src/draw.c index dcf409ac..6c7bf8b7 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1601,104 +1601,6 @@ void drawarc(int c, int what, double x, double y, double r, double a, double b, } } -void draw_snap_point(int c, int what, double x, double y, double r, double a, double b, int arc_fill, int dash) -{ - static int i=0; - static XArc xarc[CADDRAWBUFFERSIZE]; - double x1, y1, x2, y2; /* arc bbox */ - double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */ - GC gc; - - if(arc_fill || dash) what = NOW; - - if(!has_x) return; - if(what & ADD) - { - if(i>=CADDRAWBUFFERSIZE) - { - if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i); - if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i); - i=0; - } - xx1=X_TO_SCREEN(x-r); - yy1=Y_TO_SCREEN(y-r); - xx2=X_TO_SCREEN(x+r); - yy2=Y_TO_SCREEN(y+r); - arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); - x1=X_TO_SCREEN(x1); - y1=Y_TO_SCREEN(y1); - x2=X_TO_SCREEN(x2); - y2=Y_TO_SCREEN(y2); - if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) - { - xarc[i].x=(short)xx1; - xarc[i].y=(short)yy1; - xarc[i].width =(unsigned short)(xx2 - xx1); - xarc[i].height=(unsigned short)(yy2 - yy1); - xarc[i].angle1 = (short)(a*64); - xarc[i].angle2 = (short)(b*64); - ++i; - } - } - else if(what & NOW) - { - xx1=X_TO_SCREEN(x-r); - yy1=Y_TO_SCREEN(y-r); - xx2=X_TO_SCREEN(x+r); - yy2=Y_TO_SCREEN(y+r); - if(arc_fill) - arc_bbox(x, y, r, 0, 360, &x1,&y1,&x2,&y2); - else - arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); - x1=X_TO_SCREEN(x1); - y1=Y_TO_SCREEN(y1); - x2=X_TO_SCREEN(x2); - y2=Y_TO_SCREEN(y2); - if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) - { - if(dash) { - char dash_arr[2]; - dash_arr[0] = dash_arr[1] = (char)dash; - XSetDashes(display, xctx->gc[c], 0, dash_arr, 1); - XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw), xDashType, xCap, xJoin); - } - - if(xctx->draw_window) { - XDrawArc(display, xctx->window, xctx->gc[c], (int)xx1, (int)yy1, - (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); - } - if(xctx->draw_pixmap) { - XDrawArc(display, xctx->save_pixmap, xctx->gc[c], (int)xx1, (int)yy1, - (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); - } - - if(xctx->fill_pattern && (xctx->fill_type[c] || arc_fill == 3) ){ - - if(arc_fill & 2) gc = xctx->gc[c]; - else gc = xctx->gcstipple[c]; - if(arc_fill) { - if(xctx->draw_window) - XFillArc(display, xctx->window, gc, (int)xx1, (int)yy1, - (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); - if(xctx->draw_pixmap) - XFillArc(display, xctx->save_pixmap, gc, (int)xx1, (int)yy1, - (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64)); - } - } - if(dash) { - XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw) ,LineSolid, LINECAP , LINEJOIN); - } - } - } - else if((what & END) && i) - { - if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i); - if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i); - i=0; - } -} - - void filledrect(int c, int what, double rectx1,double recty1,double rectx2,double recty2, int fill, int e_a, int e_b) { From 1a7c9e11d1943582d693c89f376f9e0dac1b626a Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Tue, 21 Jan 2025 16:37:26 +0530 Subject: [PATCH 17/59] [Snap Cursor (WIP)]: Experimental feature 'snap_cursor' is updated. Yellow cursor that snaps to the nearest grid point is now available (always active, unless user activates crosshair using ALT+X). --- src/callback.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index c1406a3f..94470b2a 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1433,6 +1433,33 @@ void draw_snap_cursor(int cursor_type) xctx->draw_pixmap = sdp; } +/* what == 0 : erase and draw a new cursor + * what == 1 : erase the cursor + * what == 2 : draw a dot-cursor that snaps to a nearest grid-point */ +void draw_grid_cursor(int what) +{ + int sdw, sdp; + dbg(1, "draw_grid_cursor(): what=%d\n", what); + sdw = xctx->draw_window; + sdp = xctx->draw_pixmap; + + if(!xctx->mouse_inside) return; + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + if(what != 2) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); + } + if(what != 1) { + filledrect(8, NOW, xctx->prev_crossx-1, xctx->prev_crossy-1, xctx->prev_crossx+1, xctx->prev_crossy+1, 3, -1, -1); + } + draw_selection(xctx->gc[SELLAYER], 0); + xctx->prev_crossx = xctx->mousex_snap; + xctx->prev_crossy = xctx->mousey_snap; + + xctx->draw_window = sdw; + xctx->draw_pixmap = sdp; +} + /* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ static int end_place_move_copy_zoom() { @@ -2377,6 +2404,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case LeaveNotify: if(draw_xhair) draw_crosshair(1); + else draw_grid_cursor(1); if(snap_cursor && wire_draw_active) draw_snap_cursor(1); tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); xctx->mouse_inside = 0; @@ -2445,13 +2473,13 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) { draw_crosshair(1); - } + } else draw_grid_cursor(1); if(snap_cursor && wire_draw_active) draw_snap_cursor(1); if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); if(xctx->semaphore >= 2) { if(draw_xhair) { draw_crosshair(2); - } + } else draw_grid_cursor(2); if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; } @@ -2546,7 +2574,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) { draw_crosshair(2); - } + } else draw_grid_cursor(2); if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; @@ -4305,6 +4333,7 @@ int rstate; /* (reduced state, without ShiftMask) */ statusmsg(str,1); } if(draw_xhair) draw_crosshair(0); + else draw_grid_cursor(0); if(snap_cursor && wire_draw_active) draw_snap_cursor(0); break; case -3: /* double click : edit prop */ From ea7341742a654469c0ae033bdf360a314aa827a1 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Tue, 21 Jan 2025 21:37:04 +0530 Subject: [PATCH 18/59] [Undo Temporary Bugfix]: Discarded the temporary bugfix for commit ed1a471 --- src/callback.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index 94470b2a..7022a157 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4281,9 +4281,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - /*else if(xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ - /* if(end_place_move_copy_zoom()) break;*/ - /*}*/ + else if(xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { + if(end_place_move_copy_zoom()) break; + } /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From 634213d3c9b72fd50fe93fb159a1185bb9ed7ac4 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Tue, 21 Jan 2025 22:18:19 +0530 Subject: [PATCH 19/59] [Integrated Upstream + Temporary Bugfix]: Integrated the upstream changes for adding a custom rectangular grid-snap cursor, and re-implemented the temporary bugfix from commit ed1a471 --- src/callback.c | 41 ++++++----------------------------------- src/xschemrc | 6 +++--- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/src/callback.c b/src/callback.c index 8dfd2761..752d7751 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1502,33 +1502,6 @@ void draw_snap_cursor(int cursor_type) xctx->draw_pixmap = sdp; } -/* what == 0 : erase and draw a new cursor - * what == 1 : erase the cursor - * what == 2 : draw a dot-cursor that snaps to a nearest grid-point */ -void draw_grid_cursor(int what) -{ - int sdw, sdp; - dbg(1, "draw_grid_cursor(): what=%d\n", what); - sdw = xctx->draw_window; - sdp = xctx->draw_pixmap; - - if(!xctx->mouse_inside) return; - xctx->draw_pixmap = 0; - xctx->draw_window = 1; - if(what != 2) { - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); - } - if(what != 1) { - filledrect(8, NOW, xctx->prev_crossx-1, xctx->prev_crossy-1, xctx->prev_crossx+1, xctx->prev_crossy+1, 3, -1, -1); - } - draw_selection(xctx->gc[SELLAYER], 0); - xctx->prev_crossx = xctx->mousex_snap; - xctx->prev_crossy = xctx->mousey_snap; - - xctx->draw_window = sdw; - xctx->draw_pixmap = sdp; -} - /* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ static int end_place_move_copy_zoom() { @@ -2473,7 +2446,6 @@ int rstate; /* (reduced state, without ShiftMask) */ case LeaveNotify: if(draw_xhair) draw_crosshair(1); - else draw_grid_cursor(1); if(snap_cursor && wire_draw_active) draw_snap_cursor(1); tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); xctx->mouse_inside = 0; @@ -2544,13 +2516,13 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) { draw_crosshair(1); - } else draw_grid_cursor(1); + } if(snap_cursor && wire_draw_active) draw_snap_cursor(1); if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); if(xctx->semaphore >= 2) { if(draw_xhair) { draw_crosshair(2); - } else draw_grid_cursor(2); + } if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; } @@ -2645,7 +2617,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) { draw_crosshair(2); - } else draw_grid_cursor(2); + } if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; @@ -4352,9 +4324,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { - if(end_place_move_copy_zoom()) break; - } + /*else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ + /* if(end_place_move_copy_zoom()) break;*/ + /*}*/ /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { @@ -4404,7 +4376,6 @@ int rstate; /* (reduced state, without ShiftMask) */ statusmsg(str,1); } if(draw_xhair) draw_crosshair(0); - else draw_grid_cursor(0); if(snap_cursor && wire_draw_active) draw_snap_cursor(0); break; case -3: /* double click : edit prop */ diff --git a/src/xschemrc b/src/xschemrc index a8bccedf..bda256b9 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -277,13 +277,13 @@ # set enable_stretch 0 #### enable drawing crosshairs at mouse coordinates. Default: disabled (0) -# set draw_crosshair 1 +set draw_crosshair 1 #### set crosshair layer; Default 3 (TEXTLAYER) -# set crosshair_layer 3 +set crosshair_layer 8 #### set crosshair size; Default: 0 (full screen spanning crosshair) -# set crosshair_size 5 +set crosshair_size 4 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 2a97ca5716acbc72d25a1fdefb31c4ad367f7f91 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 14:58:59 +0530 Subject: [PATCH 20/59] [Prepare For Upstream Integration]: Changes made to integrate upstream adoption of default yellow-colored grid-snapping cursor. --- src/xschemrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xschemrc b/src/xschemrc index bda256b9..a8bccedf 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -277,13 +277,13 @@ # set enable_stretch 0 #### enable drawing crosshairs at mouse coordinates. Default: disabled (0) -set draw_crosshair 1 +# set draw_crosshair 1 #### set crosshair layer; Default 3 (TEXTLAYER) -set crosshair_layer 8 +# set crosshair_layer 3 #### set crosshair size; Default: 0 (full screen spanning crosshair) -set crosshair_size 4 +# set crosshair_size 5 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 196e0d737b90131cab2f14a9e133c6a3183de959 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 15:11:17 +0530 Subject: [PATCH 21/59] [After-Merge Modifications]: Changed default behavior for grid-snapping cursor, returning it to pre-merge state. Can be undone by the user if necessary from the 'src/xschemrc' file --- src/xschemrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xschemrc b/src/xschemrc index e3dfb181..d6ff0abe 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -283,7 +283,7 @@ # set crosshair_layer 8 #### set crosshair size; Default: 0 (full screen spanning crosshair) -# set crosshair_size 5 +set crosshair_size 2 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 49442797002e44b0ea9cfb8b664788acb8e63ca0 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 15:58:28 +0530 Subject: [PATCH 22/59] Some refactoring and cleanup to standardize the previously added code --- src/callback.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/callback.c b/src/callback.c index b59d7b3f..379e7993 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,7 +21,6 @@ */ #include "xschem.h" -#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) @@ -1463,20 +1462,20 @@ void draw_crosshair(int what) xctx->draw_pixmap = sdp; } -/* cursor_type == 0 : erase and draw a new cursor - * cursor_type == 1 : erase the cursor - * cursor_type == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ -void draw_snap_cursor(int cursor_type) +/* what == 0 : erase and draw a new cursor + * what == 1 : erase the cursor + * what == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ +void draw_snap_cursor(int what) { int sdw, sdp; - dbg(1, "draw_snap_cursor(): cursor_type=%d\n", cursor_type); + dbg(1, "draw_snap_cursor(): what=%d\n", what); sdw = xctx->draw_window; sdp = xctx->draw_pixmap; if(!xctx->mouse_inside) return; xctx->draw_pixmap = 0; xctx->draw_window = 1; - if(cursor_type != 2) { + if(what != 2) { if(fix_broken_tiled_fill || !_unix) { MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); } else { @@ -1487,7 +1486,7 @@ void draw_snap_cursor(int cursor_type) drawtemppolygon(xctx->gctiled, NOW, points_x, points_y, 5, 0); } } - if(cursor_type != 1) { + if(what != 1) { double x, y; find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); double points_x[5] = {x, x+3, x, x-3, x}; From dc544f81fd67ebd1069b6d96315c9da22afbd5c5 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 17:02:04 +0530 Subject: [PATCH 23/59] [Grid-Snap Cursor Update (WIP)]: The grid snap cursor is now drawn with constant-pixel-size, regardless of the schematic editor's zoom level. This behavior will be interchangeble with the upstream version's behavior via a menu-option or a custom tcl-command in the future. --- src/callback.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++---- src/xinit.c | 1 + src/xschem.h | 1 + 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/callback.c b/src/callback.c index 379e7993..09febe6b 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1353,7 +1353,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* what == 0 : delete and draw * what == 1 : delete * what == 2 : draw */ -void draw_crosshair(int what) +void draw_crosshair_old(int what) { int sdw, sdp; int xhair_size = tclgetintvar("crosshair_size"); @@ -1462,6 +1462,70 @@ void draw_crosshair(int what) xctx->draw_pixmap = sdp; } +/* what == 0 : delete and draw + * what == 1 : delete + * what == 2 : draw */ +void draw_crosshair(int what) /* For drawing the grid-snapping cursor with constant pixel-size */ +{ + int sdw, sdp; + int xhair_size = tclgetintvar("crosshair_size"); + dbg(1, "draw_crosshair_constpixel(): what=%d\n", what); + sdw = xctx->draw_window; + sdp = xctx->draw_pixmap; + + if(!xctx->mouse_inside) return; + + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + if(what != 2) { /* delete previous */ + if(fix_broken_tiled_fill || !_unix) { + if(xhair_size) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); + } else { /* full screen span xhair */ + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw), + xctx->xrect[0].width, 4 * INT_WIDTH(xctx->lw), + 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw)); + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0, + 4 * INT_WIDTH(xctx->lw), xctx->xrect[0].height, + (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0); + } + } else { + if(xhair_size) { + drawtemprect(xctx->gctiled, NOW, + xctx->prev_crossx - xhair_size, xctx->prev_crossy - xhair_size, + xctx->prev_crossx + xhair_size, xctx->prev_crossy + xhair_size); + } else { /* full screen span xhair */ + drawtempline(xctx->gctiled, NOW, X_TO_XSCHEM(xctx->areax1), + xctx->prev_crossy, X_TO_XSCHEM(xctx->areax2), xctx->prev_crossy); + drawtempline(xctx->gctiled, NOW, xctx->prev_crossx, Y_TO_XSCHEM(xctx->areay1), + xctx->prev_crossx, Y_TO_XSCHEM(xctx->areay2)); + } + } + } + if(what != 1) { /* draw new */ + if(xhair_size) { + drawrect(xctx->crosshair_layer, NOW, xctx->prev_crossx - xhair_size, xctx->prev_crossy - xhair_size, + xctx->prev_crossx + xhair_size, xctx->prev_crossy + xhair_size, + 0, -1, -1); + } else { /* full screen span xhair */ + draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size, + xctx->areax1, Y_TO_SCREEN(xctx->mousey_snap), + xctx->areax2, Y_TO_SCREEN(xctx->mousey_snap)); + draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size, + X_TO_SCREEN(xctx->mousex_snap), xctx->areay1, + X_TO_SCREEN(xctx->mousex_snap), xctx->areay2); + } + } + draw_selection(xctx->gc[SELLAYER], 0); + xctx->prev_crossx = xctx->mousex_snap; + xctx->prev_crossy = xctx->mousey_snap; + + xctx->draw_window = sdw; + xctx->draw_pixmap = sdp; +} + /* what == 0 : erase and draw a new cursor * what == 1 : erase the cursor * what == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ @@ -1479,8 +1543,8 @@ void draw_snap_cursor(int what) if(fix_broken_tiled_fill || !_unix) { MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); } else { - double prev_x = xctx->prev_crossx; - double prev_y = xctx->prev_crossy; + double prev_x = xctx->prev_snapx; + double prev_y = xctx->prev_snapy; double points_x[5] = {prev_x, prev_x+3, prev_x, prev_x-3, prev_x}; double points_y[5] = {prev_y-3, prev_y, prev_y+3, prev_y, prev_y-3}; drawtemppolygon(xctx->gctiled, NOW, points_x, points_y, 5, 0); @@ -1492,8 +1556,8 @@ void draw_snap_cursor(int what) double points_x[5] = {x, x+3, x, x-3, x}; double points_y[5] = {y-3, y, y+3, y, y-3}; drawpolygon(8, NOW, points_x, points_y, 5, 0, 0, 0); - xctx->prev_crossx = x; - xctx->prev_crossy = y; + xctx->prev_snapx = x; + xctx->prev_snapy = y; } draw_selection(xctx->gc[SELLAYER], 0); diff --git a/src/xinit.c b/src/xinit.c index 82edc3a3..25d2f9f6 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -646,6 +646,7 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->enable_drill = 0; xctx->prev_set_modify = -1; xctx->prev_crossx = xctx->prev_crossy = 0.0; + xctx->prev_snapx = xctx->prev_snapy = 0.0; xctx->mouse_inside = 0; xctx->pending_fullzoom = 0; my_strncpy(xctx->hiersep, ".", S(xctx->hiersep)); diff --git a/src/xschem.h b/src/xschem.h index 0fcae282..04f80698 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1049,6 +1049,7 @@ typedef struct { double p_xx1,p_xx2,p_yy1,p_yy2; /* draw_crosshair */ double prev_crossx, prev_crossy; + double prev_snapx, prev_snapy; int mouse_inside; /* set_modify */ int prev_set_modify; From 4c5421fddafd45f0af4b14453a96381f1e47b741 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 17:08:16 +0530 Subject: [PATCH 24/59] [Bugfix]: Fixed a bug where the non-persistent wire-draw mode didn't put down a new anchor-point when 'w'-key was pressed by user. This bug was introduced in the upstream-merge (commit 8ce32b7) after incorrectly adopting the upstream way of handling 'infix_interface' mode. --- src/callback.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/callback.c b/src/callback.c index 09febe6b..99fb8c27 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2953,6 +2953,7 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->last_command = 0; xctx->ui_state |= MENUSTART; xctx->ui_state2 = MENUSTARTWIRE; + if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); } break; } From 248596f81ce2b0138c870259778062b9161a757f Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 17:30:14 +0530 Subject: [PATCH 25/59] [Refactoring]: Renamed variables and added inline code-comments for better code readability. --- src/callback.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 99fb8c27..3df27b46 100644 --- a/src/callback.c +++ b/src/callback.c @@ -102,8 +102,10 @@ void redraw_w_a_l_r_p_rubbers(void) if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; if(tclgetboolvar("orthogonal_wiring")) { new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - int tmp_x2 = xctx->nl_x2 - xctx->nl_x1, tmp_y2 = xctx->nl_y2 - xctx->nl_y1; - if(tmp_x2*tmp_x2 > tmp_y2*tmp_y2){ + /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ + int origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1, origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; + /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ + if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2){ xctx->manhattan_lines = 1; } else { xctx->manhattan_lines = 2; From 4b8a3c653b19b8bd53311d773bb8f52c33d10772 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 22 Jan 2025 19:01:48 +0530 Subject: [PATCH 26/59] [New Experimental Functionality]: Added the functionality of terminating the wire-draw mode when the user clicks a component endpoint. This feature is currently on by default (if the user has the 'Display snap cursor' option enabled. --- src/callback.c | 9 ++++++++- src/xschem.tcl | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3df27b46..f1a36095 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4272,7 +4272,14 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->drag_elements = 0; if(tclgetboolvar("persistent_command") && xctx->last_command) { if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); - if(xctx->last_command == STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(xctx->last_command == STARTWIRE){ + if(tclgetboolvar("snap_cursor") && (xctx->prev_snapx == xctx->mousex_snap && xctx->prev_snapy == xctx->mousey_snap)){ + new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + xctx->last_command &= ~STARTWIRE; + } + else + start_wire(xctx->mousex_snap, xctx->mousey_snap); + } break; } /* handle all object insertions started from Tools/Edit menu */ diff --git a/src/xschem.tcl b/src/xschem.tcl index 6d5493ce..34696455 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -8200,7 +8200,7 @@ proc build_widgets { {topwin {} } } { -selectcolor $selectcolor -accelerator Y $topwin.menubar.option add checkbutton -label "Enable infix-interface" -variable infix_interface \ -selectcolor $selectcolor - $topwin.menubar.option add checkbutton -label "Enable snap cursor" -variable snap_cursor \ + $topwin.menubar.option add checkbutton -label "Display snap cursor" -variable snap_cursor \ -selectcolor $selectcolor $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \ -selectcolor $selectcolor -accelerator Shift+L From 710f8577650e746fc2685758ab9d57110f4f25a0 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 17:45:49 +0530 Subject: [PATCH 27/59] [Snap Cursor Update (WIP)]: Added keybind to activate snap_cursor + new tcl-command to adjust 'snap_cursor_size'. Added grid-coordinate checks for better performance using the 'find_closest_net_or_symbol_pin()' function (by only running the search when the grid-snap position changes). Fixed xctx->prev_crossx and xctx->prev_crossy conflict between draw_crosshair() and draw_snap_cursor() by using the new globally accesible variables 'xctx->prev_gridx' and 'xctx->prev_gridy' in draw_snap_cursor(). --- src/callback.c | 97 ++++++++++++++------------------------------------ src/xinit.c | 1 + src/xschem.h | 1 + src/xschem.tcl | 9 ++--- src/xschemrc | 3 ++ 5 files changed, 36 insertions(+), 75 deletions(-) diff --git a/src/callback.c b/src/callback.c index 30a2516e..3d7000e2 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1355,7 +1355,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* what == 0 : delete and draw * what == 1 : delete * what == 2 : draw */ -void draw_crosshair_old(int what) +void draw_crosshair(int what) { int sdw, sdp; int xhair_size = tclgetintvar("crosshair_size"); @@ -1464,76 +1464,14 @@ void draw_crosshair_old(int what) xctx->draw_pixmap = sdp; } -/* what == 0 : delete and draw - * what == 1 : delete - * what == 2 : draw */ -void draw_crosshair(int what) /* For drawing the grid-snapping cursor with constant pixel-size */ -{ - int sdw, sdp; - int xhair_size = tclgetintvar("crosshair_size"); - dbg(1, "draw_crosshair_constpixel(): what=%d\n", what); - sdw = xctx->draw_window; - sdp = xctx->draw_pixmap; - - if(!xctx->mouse_inside) return; - - xctx->draw_pixmap = 0; - xctx->draw_window = 1; - if(what != 2) { /* delete previous */ - if(fix_broken_tiled_fill || !_unix) { - if(xhair_size) { - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); - } else { /* full screen span xhair */ - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw), - xctx->xrect[0].width, 4 * INT_WIDTH(xctx->lw), - 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw)); - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0, - 4 * INT_WIDTH(xctx->lw), xctx->xrect[0].height, - (int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0); - } - } else { - if(xhair_size) { - drawtemprect(xctx->gctiled, NOW, - xctx->prev_crossx - xhair_size, xctx->prev_crossy - xhair_size, - xctx->prev_crossx + xhair_size, xctx->prev_crossy + xhair_size); - } else { /* full screen span xhair */ - drawtempline(xctx->gctiled, NOW, X_TO_XSCHEM(xctx->areax1), - xctx->prev_crossy, X_TO_XSCHEM(xctx->areax2), xctx->prev_crossy); - drawtempline(xctx->gctiled, NOW, xctx->prev_crossx, Y_TO_XSCHEM(xctx->areay1), - xctx->prev_crossx, Y_TO_XSCHEM(xctx->areay2)); - } - } - } - if(what != 1) { /* draw new */ - if(xhair_size) { - drawrect(xctx->crosshair_layer, NOW, xctx->prev_crossx - xhair_size, xctx->prev_crossy - xhair_size, - xctx->prev_crossx + xhair_size, xctx->prev_crossy + xhair_size, - 0, -1, -1); - } else { /* full screen span xhair */ - draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size, - xctx->areax1, Y_TO_SCREEN(xctx->mousey_snap), - xctx->areax2, Y_TO_SCREEN(xctx->mousey_snap)); - draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size, - X_TO_SCREEN(xctx->mousex_snap), xctx->areay1, - X_TO_SCREEN(xctx->mousex_snap), xctx->areay2); - } - } - draw_selection(xctx->gc[SELLAYER], 0); - xctx->prev_crossx = xctx->mousex_snap; - xctx->prev_crossy = xctx->mousey_snap; - - xctx->draw_window = sdw; - xctx->draw_pixmap = sdp; -} - /* what == 0 : erase and draw a new cursor * what == 1 : erase the cursor * what == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ void draw_snap_cursor(int what) { int sdw, sdp; + int snapcursor_size = tclgetintvar("snap_cursor_size"); + int pos_changed = (xctx->mousex_snap - xctx->prev_gridx) || (xctx->mousey_snap - xctx->prev_gridy); dbg(1, "draw_snap_cursor(): what=%d\n", what); sdw = xctx->draw_window; sdp = xctx->draw_pixmap; @@ -1547,17 +1485,24 @@ void draw_snap_cursor(int what) } else { double prev_x = xctx->prev_snapx; double prev_y = xctx->prev_snapy; - double points_x[5] = {prev_x, prev_x+3, prev_x, prev_x-3, prev_x}; - double points_y[5] = {prev_y-3, prev_y, prev_y+3, prev_y, prev_y-3}; + double points_x[5] = {prev_x, prev_x+snapcursor_size, prev_x, prev_x-snapcursor_size, prev_x}; + double points_y[5] = {prev_y-snapcursor_size, prev_y, prev_y+snapcursor_size, prev_y, prev_y-snapcursor_size}; drawtemppolygon(xctx->gctiled, NOW, points_x, points_y, 5, 0); } } if(what != 1) { double x, y; - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - double points_x[5] = {x, x+3, x, x-3, x}; - double points_y[5] = {y-3, y, y+3, y, y-3}; - drawpolygon(8, NOW, points_x, points_y, 5, 0, 0, 0); + if(!pos_changed) { + x = xctx->prev_snapx; + y = xctx->prev_snapy; + } else { /* Only search for nearest pin if the grid-snap-point has changed */ + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + } + double points_x[5] = {x, x+snapcursor_size, x, x-snapcursor_size, x}; + double points_y[5] = {y-snapcursor_size, y, y+snapcursor_size, y, y-snapcursor_size}; + drawpolygon(xctx->crosshair_layer, NOW, points_x, points_y, 5, 0, 0, 0); + xctx->prev_gridx = xctx->mousex_snap; + xctx->prev_gridy = xctx->mousey_snap; xctx->prev_snapx = x; xctx->prev_snapy = y; } @@ -2988,6 +2933,16 @@ int rstate; /* (reduced state, without ShiftMask) */ { view_zoom(0.0); break; } + if(key=='z' && EQUAL_MODMASK) /* toggle snap-cursor option */ + { + if(tclgetboolvar("snap_cursor")) { + tclsetvar("snap_cursor", "0"); + draw_snap_cursor(1); + } else { + tclsetvar("snap_cursor", "1"); + if(wire_draw_active) draw_snap_cursor(0); + } + } if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ { xctx->push_undo(); diff --git a/src/xinit.c b/src/xinit.c index 25d2f9f6..acb456ef 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -646,6 +646,7 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->enable_drill = 0; xctx->prev_set_modify = -1; xctx->prev_crossx = xctx->prev_crossy = 0.0; + xctx->prev_gridx = xctx->prev_gridy = 0.0; xctx->prev_snapx = xctx->prev_snapy = 0.0; xctx->mouse_inside = 0; xctx->pending_fullzoom = 0; diff --git a/src/xschem.h b/src/xschem.h index 04f80698..23d9d254 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1049,6 +1049,7 @@ typedef struct { double p_xx1,p_xx2,p_yy1,p_yy2; /* draw_crosshair */ double prev_crossx, prev_crossy; + double prev_gridx, prev_gridy; double prev_snapx, prev_snapy; int mouse_inside; /* set_modify */ diff --git a/src/xschem.tcl b/src/xschem.tcl index 34696455..fda04474 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7656,7 +7656,7 @@ set tctx::global_list { add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow autotrim_wires orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv - copy_cell crosshair_layer crosshair_size custom_label_prefix custom_token dark_colors dark_colorscheme + copy_cell crosshair_layer crosshair_size snap_cursor_size custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names do_all_inst draw_crosshair draw_grid draw_grid_axes draw_window edit_prop_pos edit_prop_size @@ -8200,10 +8200,8 @@ proc build_widgets { {topwin {} } } { -selectcolor $selectcolor -accelerator Y $topwin.menubar.option add checkbutton -label "Enable infix-interface" -variable infix_interface \ -selectcolor $selectcolor - $topwin.menubar.option add checkbutton -label "Display snap cursor" -variable snap_cursor \ - -selectcolor $selectcolor $topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \ - -selectcolor $selectcolor -accelerator Shift+L + -selectcolor $selectcolor -accelerator Shift-L $topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \ -selectcolor $selectcolor -variable unselect_partial_sel_wires @@ -8222,6 +8220,8 @@ proc build_widgets { {topwin {} } } { $topwin.menubar.option add checkbutton -label "Draw crosshair" \ -variable draw_crosshair -selectcolor $selectcolor -accelerator {Alt-X} + $topwin.menubar.option add checkbutton -label "Draw persistent snap cursor" -variable snap_cursor \ + -selectcolor $selectcolor -accelerator {Alt-Z} $topwin.menubar.option add command -label "Replace \[ and \] for buses in SPICE netlist" \ -command { @@ -9106,6 +9106,7 @@ set_ne ps_page_title 1 ;# add a title in the top left page corner set_ne draw_crosshair 0 set_ne crosshair_layer 8 ;# Yellow set_ne crosshair_size 0 +set_ne snap_cursor_size 3 set_ne ps_paper_size {a4 842 595} set_ne transparent_svg 0 set_ne only_probes 0 ; # 20110112 diff --git a/src/xschemrc b/src/xschemrc index d6ff0abe..f7d7253e 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -285,6 +285,9 @@ #### set crosshair size; Default: 0 (full screen spanning crosshair) set crosshair_size 2 +#### set snap_cursor size; Default: 3 (Diamond-shaped cursor that snaps to nearest circuit endpoint) +# set snap_cursor size 3 + #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 783bccf8cf45d86a4ee401033effe2823488ba57 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 19:14:58 +0530 Subject: [PATCH 28/59] Added changes to resolve merge conflicts --- src/callback.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3d7000e2..b97cf9e9 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2882,7 +2882,7 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; snapped_wire(c_snap); break; @@ -4366,9 +4366,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - /*else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ - /* if(end_place_move_copy_zoom()) break;*/ - /*}*/ + else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { + if(end_place_move_copy_zoom()) break; + } /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From ffcbeaec66e0d097fb799c7591f36277f0f6504e Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 19:46:16 +0530 Subject: [PATCH 29/59] [After merge-changes]: Re-introduced temporary bugfix and altered snap-cursor keybind to match pre-merge state of this fork. --- src/callback.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/callback.c b/src/callback.c index df00821a..d32a1ba1 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2864,7 +2864,7 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; if(infix_interface) { snapped_wire(c_snap); @@ -4352,10 +4352,10 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && - (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { - if(end_place_move_copy_zoom()) break; - } + /*else if(state == Button1Mask && xctx->intuitive_interface &&*/ + /* (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) {*/ + /* if(end_place_move_copy_zoom()) break;*/ + /*}*/ /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From 8c1bfc93f67d5e65f9d794d31955498384bbd35e Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 20:00:59 +0530 Subject: [PATCH 30/59] [Revert changes] --- src/callback.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/callback.c b/src/callback.c index d32a1ba1..df00821a 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2864,7 +2864,7 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; if(infix_interface) { snapped_wire(c_snap); @@ -4352,10 +4352,10 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ - /*else if(state == Button1Mask && xctx->intuitive_interface &&*/ - /* (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) {*/ - /* if(end_place_move_copy_zoom()) break;*/ - /*}*/ + else if(state == Button1Mask && xctx->intuitive_interface && + (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { + if(end_place_move_copy_zoom()) break; + } /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From 3556f3599c034c4bb875c210e9e868efb59a7c42 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 20:03:12 +0530 Subject: [PATCH 31/59] [Revert changes] --- src/actions.c | 24 ++++++-------- src/callback.c | 86 +++++++++++++++++++++++++++----------------------- src/xschem.h | 1 - 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/actions.c b/src/actions.c index 60ee1174..4c07a46f 100644 --- a/src/actions.c +++ b/src/actions.c @@ -3019,7 +3019,7 @@ void new_wire(int what, double mx_snap, double my_snap) if( (what & PLACE) ) { if( (xctx->ui_state & STARTWIRE) && (xctx->nl_x1!=xctx->nl_x2 || xctx->nl_y1!=xctx->nl_y2) ) { xctx->push_undo(); - if(xctx->manhattan_lines & 1) { + if(xctx->manhattan_lines==1) { if(xctx->nl_xx2!=xctx->nl_xx1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3038,7 +3038,7 @@ void new_wire(int what, double mx_snap, double my_snap) hash_wire(XINSERT, xctx->wires-1, 1); drawline(WIRELAYER,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); } - } else if(xctx->manhattan_lines & 2) { + } else if(xctx->manhattan_lines==2) { if(xctx->nl_yy2!=xctx->nl_yy1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3076,8 +3076,6 @@ void new_wire(int what, double mx_snap, double my_snap) draw(); /* draw_hilight_net(1);*/ /* for updating connection bubbles on hilight nets */ } - -#if 0 if(! (what &END)) { xctx->nl_x1=mx_snap; xctx->nl_y1=my_snap; @@ -3087,7 +3085,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->nl_yy1=xctx->nl_y1; xctx->nl_xx2=xctx->mousex_snap; xctx->nl_yy2=xctx->mousey_snap; - if(xctx->manhattan_lines & 1) { + if(xctx->manhattan_lines==1) { xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3097,7 +3095,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - } else if(xctx->manhattan_lines & 2) { + } else if(xctx->manhattan_lines==2) { xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3115,8 +3113,6 @@ void new_wire(int what, double mx_snap, double my_snap) drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } } -#endif - xctx->nl_x1 = xctx->nl_x2=mx_snap; xctx->nl_y1 = xctx->nl_y2=my_snap; xctx->ui_state |= STARTWIRE; if(modified) set_modify(1); } @@ -3124,7 +3120,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->ui_state &= ~STARTWIRE; } if( (what & RUBBER) ) { - if(xctx->manhattan_lines & 1) { + if(xctx->manhattan_lines==1) { xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1; xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); @@ -3145,7 +3141,7 @@ void new_wire(int what, double mx_snap, double my_snap) ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } - } else if(xctx->manhattan_lines & 2) { + } else if(xctx->manhattan_lines==2) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); @@ -3315,7 +3311,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) if( (xctx->nl_x1!=xctx->nl_x2 || xctx->nl_y1!=xctx->nl_y2) && (xctx->ui_state & STARTLINE) ) { xctx->push_undo(); - if(xctx->manhattan_lines & 1) { + if(xctx->manhattan_lines==1) { if(xctx->nl_xx2!=xctx->nl_xx1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3332,7 +3328,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) modified = 1; drawline(xctx->rectcolor,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); } - } else if(xctx->manhattan_lines & 2) { + } else if(xctx->manhattan_lines==2) { if(xctx->nl_yy2!=xctx->nl_yy1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3369,7 +3365,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) if(what & RUBBER) { - if(xctx->manhattan_lines & 1) { + if(xctx->manhattan_lines==1) { xctx->nl_xx1 = xctx->nl_x1;xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2;xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); @@ -3390,7 +3386,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[xctx->rectcolor], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } - } else if(xctx->manhattan_lines & 2) { + } else if(xctx->manhattan_lines==2) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); diff --git a/src/callback.c b/src/callback.c index df00821a..b97cf9e9 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1593,25 +1593,6 @@ static int end_place_move_copy_zoom() return 0; } -void snapped_wire(double c_snap) -{ - double x, y; - if(!(xctx->ui_state & STARTWIRE)){ - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - xctx->mx_double_save = my_round(x / c_snap) * c_snap; - xctx->my_double_save = my_round(y / c_snap) * c_snap; - new_wire(PLACE, x, y); - new_wire(RUBBER, xctx->mousex_snap,xctx->mousey_snap); - } - else { - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - new_wire(RUBBER, x, y); - new_wire(PLACE|END, x, y); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - } -} - static int check_menu_start_commands(double c_snap) { dbg(1, "check_menu_start_commands(): ui_state=%x, ui_state2=%x last_command=%d\n", @@ -1619,10 +1600,12 @@ static int check_menu_start_commands(double c_snap) if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT)) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT2)) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTMOVE)) { @@ -1631,12 +1614,14 @@ static int check_menu_start_commands(double c_snap) /* stretch nets that land on selected instance pins if connect_by_kissing == 2 */ /* select_attached_nets(); */ move_objects(START,0,0,0); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCOPY)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; copy_objects(START); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) { @@ -1647,6 +1632,8 @@ static int check_menu_start_commands(double c_snap) tcleval("set constr_mv 0" ); xctx->constr_mv=0; } + xctx->ui_state &=~MENUSTART; + xctx->ui_state2 = 0; /* * xctx->mx_double_save=xctx->mousex_snap; @@ -1657,7 +1644,13 @@ static int check_menu_start_commands(double c_snap) return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTSNAPWIRE)) { - snapped_wire(c_snap); + double x, y; + + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + xctx->mx_double_save = my_round(x / c_snap) * c_snap; + xctx->my_double_save = my_round(y / c_snap) * c_snap; + new_wire(PLACE, x, y); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTLINE)) { @@ -1668,6 +1661,8 @@ static int check_menu_start_commands(double c_snap) tcleval("set constr_mv 0" ); xctx->constr_mv=0; } + xctx->ui_state &=~MENUSTART; + xctx->ui_state2 = 0; /* * xctx->mx_double_save=xctx->mousex_snap; @@ -1681,28 +1676,33 @@ static int check_menu_start_commands(double c_snap) xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTPOLYGON)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTARC)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCIRCLE)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTZOOM)) { zoom_rectangle(START); + xctx->ui_state &=~MENUSTART; return 1; } return 0; @@ -2300,6 +2300,25 @@ static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key } #endif +static void snapped_wire(double c_snap) +{ + double x, y; + if(!(xctx->ui_state & STARTWIRE)){ + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + xctx->mx_double_save = my_round(x / c_snap) * c_snap; + xctx->my_double_save = my_round(y / c_snap) * c_snap; + new_wire(PLACE, x, y); + new_wire(RUBBER, xctx->mousex_snap,xctx->mousey_snap); + } + else { + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + new_wire(RUBBER, x, y); + new_wire(PLACE|END, x, y); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + } +} + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* winpath: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -2608,8 +2627,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* snap crosshair to closest pin or net endpoint */ if(draw_xhair) { - if( ( (xctx->ui_state & (MENUSTART | STARTWIRE) ) || xctx->ui_state == 0 ) && - (state == ShiftMask) ) { + if( ( (xctx->ui_state & STARTWIRE) || xctx->ui_state == 0 ) && (state & ShiftMask) ) { double x, y, sx, sy; sx = xctx->mousex_snap; sy = xctx->mousey_snap; @@ -2637,7 +2655,7 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->manhattan_lines %=3; new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } else if(xctx->ui_state & STARTLINE) { + } else if(xctx->ui_state==STARTLINE) { new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); xctx->manhattan_lines++; xctx->manhattan_lines %=3; @@ -2866,12 +2884,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; - if(infix_interface) { - snapped_wire(c_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTSNAPWIRE; - } + snapped_wire(c_snap); break; } if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ @@ -4178,6 +4191,7 @@ int rstate; /* (reduced state, without ShiftMask) */ /* terminate wire placement in snap mode */ else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { snapped_wire(c_snap); + here(1111); } /* Alt - Button1 click to unselect */ else if(button==Button1 && (SET_MODMASK) ) { @@ -4351,12 +4365,11 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->semaphore = savesem; } - /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && - (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { + /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ + else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { if(end_place_move_copy_zoom()) break; } - + /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { copy_objects(END); @@ -4404,13 +4417,6 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); statusmsg(str,1); } - - /* clear start from menu flag or infix_interface=0 start commands */ - if(xctx->ui_state & MENUSTART) { - xctx->ui_state &= ~MENUSTART; - break; - } - if(draw_xhair) draw_crosshair(0); if(snap_cursor && wire_draw_active) draw_snap_cursor(0); break; diff --git a/src/xschem.h b/src/xschem.h index 1fe3d3bd..23d9d254 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1393,7 +1393,6 @@ extern int Tcl_AppInit(Tcl_Interp *interp); extern void abort_operation(void); extern void draw_crosshair(int what); extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr); -/* extern void snapped_wire(double c_snap); */ extern int callback(const char *winpath, int event, int mx, int my, KeySym key, int button, int aux, int state); extern void resetwin(int create_pixmap, int clear_pixmap, int force, int w, int h); From 935696ef81905b70c7c7be40a2c3678a6104e55b Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 20:04:27 +0530 Subject: [PATCH 32/59] [Revert changes] --- src/callback.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/callback.c b/src/callback.c index b97cf9e9..3d7000e2 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2882,7 +2882,7 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) break; snapped_wire(c_snap); break; @@ -4366,9 +4366,9 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) { - if(end_place_move_copy_zoom()) break; - } + /*else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ + /* if(end_place_move_copy_zoom()) break;*/ + /*}*/ /* end intuitive_interface copy or move */ if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { From 0a0ef228fe1eefdf0a492b3dccd8e59d8903ed9d Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 20:26:20 +0530 Subject: [PATCH 33/59] [Bugfix]: Fixed a bug where drawing a wire in an empty canvas caused the snap-cursor to detect it's own endpoint as a snap-point and incorrectly terminate wire-drawing mode --- src/callback.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3d7000e2..3d00c1ba 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4230,9 +4230,10 @@ int rstate; /* (reduced state, without ShiftMask) */ if(tclgetboolvar("persistent_command") && xctx->last_command) { if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); if(xctx->last_command == STARTWIRE){ - if(tclgetboolvar("snap_cursor") && (xctx->prev_snapx == xctx->mousex_snap && xctx->prev_snapy == xctx->mousey_snap)){ + if(tclgetboolvar("snap_cursor") && (xctx->prev_snapx == xctx->mousex_snap && xctx->prev_snapy == xctx->mousey_snap) + && (xctx->ui_state & STARTWIRE)){ new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); - xctx->last_command &= ~STARTWIRE; + xctx->ui_state &= ~STARTWIRE; } else start_wire(xctx->mousex_snap, xctx->mousey_snap); From ea7d0d94c51a0e0c18252742498cfc284f810e82 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 23 Jan 2025 22:58:35 +0530 Subject: [PATCH 34/59] [Snap Cursor Update (WIP)]: Added dynamically scaling snap cursor. --- src/callback.c | 26 +++++++++++++++++++++++--- src/xschem.tcl | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3d00c1ba..6a2b3339 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1498,9 +1498,29 @@ void draw_snap_cursor(int what) } else { /* Only search for nearest pin if the grid-snap-point has changed */ find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); } - double points_x[5] = {x, x+snapcursor_size, x, x-snapcursor_size, x}; - double points_y[5] = {y-snapcursor_size, y, y+snapcursor_size, y, y-snapcursor_size}; - drawpolygon(xctx->crosshair_layer, NOW, points_x, points_y, 5, 0, 0, 0); + /*double points_x[5] = {x, x+snapcursor_size, x, x-snapcursor_size, x};*/ + /*double points_y[5] = {y-snapcursor_size, y, y+snapcursor_size, y, y-snapcursor_size};*/ + /*drawpolygon(xctx->crosshair_layer, NOW, points_x, points_y, 5, 0, 0, 0);*/ + draw_xhair_line(xctx->gc[xctx->crosshair_layer], snapcursor_size, + X_TO_SCREEN(x), + Y_TO_SCREEN(y) - snapcursor_size, + X_TO_SCREEN(x) + snapcursor_size, + Y_TO_SCREEN(y)); + draw_xhair_line(xctx->gc[xctx->crosshair_layer], snapcursor_size, + X_TO_SCREEN(x) + snapcursor_size, + Y_TO_SCREEN(y), + X_TO_SCREEN(x), + Y_TO_SCREEN(y) + snapcursor_size); + draw_xhair_line(xctx->gc[xctx->crosshair_layer], snapcursor_size, + X_TO_SCREEN(x), + Y_TO_SCREEN(y) + snapcursor_size, + X_TO_SCREEN(x) - snapcursor_size, + Y_TO_SCREEN(y)); + draw_xhair_line(xctx->gc[xctx->crosshair_layer], snapcursor_size, + X_TO_SCREEN(x) - snapcursor_size, + Y_TO_SCREEN(y), + X_TO_SCREEN(x), + Y_TO_SCREEN(y) - snapcursor_size); xctx->prev_gridx = xctx->mousex_snap; xctx->prev_gridy = xctx->mousey_snap; xctx->prev_snapx = x; diff --git a/src/xschem.tcl b/src/xschem.tcl index fda04474..81739137 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -9106,7 +9106,7 @@ set_ne ps_page_title 1 ;# add a title in the top left page corner set_ne draw_crosshair 0 set_ne crosshair_layer 8 ;# Yellow set_ne crosshair_size 0 -set_ne snap_cursor_size 3 +set_ne snap_cursor_size 6 set_ne ps_paper_size {a4 842 595} set_ne transparent_svg 0 set_ne only_probes 0 ; # 20110112 From fefbd922d50f08a87b885e46b9e9c08d04ec7429 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 24 Jan 2025 14:40:29 +0530 Subject: [PATCH 35/59] [Bugfix - Snap Cursor]: Fully removed the bug from commit 0a0ef22. Solved by introducing breaking change in 'find_closest_net_or_symbol_pin()' function defined in 'src/xschem.h' and implemented in 'src/findnet.c'. The function now returns a boolean value indicating if the search yielded any valid results, instead of returning nothing (void). --- src/callback.c | 57 ++++++++++++++++++++++++++++++++++++++------------ src/findnet.c | 7 ++++++- src/xinit.c | 1 + src/xschem.h | 4 +++- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/callback.c b/src/callback.c index 6a2b3339..f3a64f41 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1479,15 +1479,46 @@ void draw_snap_cursor(int what) if(!xctx->mouse_inside) return; xctx->draw_pixmap = 0; xctx->draw_window = 1; + double prev_x = xctx->prev_snapx; + double prev_y = xctx->prev_snapy; if(what != 2) { if(fix_broken_tiled_fill || !_unix) { - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0); - } else { - double prev_x = xctx->prev_snapx; - double prev_y = xctx->prev_snapy; - double points_x[5] = {prev_x, prev_x+snapcursor_size, prev_x, prev_x-snapcursor_size, prev_x}; - double points_y[5] = {prev_y-snapcursor_size, prev_y, prev_y+snapcursor_size, prev_y, prev_y-snapcursor_size}; - drawtemppolygon(xctx->gctiled, NOW, points_x, points_y, 5, 0); + /*MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0);*/ + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, + 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, + (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size); + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, + 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, + (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size); + } else { + draw_xhair_line(xctx->gctiled, snapcursor_size, + X_TO_SCREEN(prev_x), + Y_TO_SCREEN(prev_y) - snapcursor_size, + X_TO_SCREEN(prev_x) + snapcursor_size, + Y_TO_SCREEN(prev_y)); + draw_xhair_line(xctx->gctiled, snapcursor_size, + X_TO_SCREEN(prev_x) + snapcursor_size, + Y_TO_SCREEN(prev_y), + X_TO_SCREEN(prev_x), + Y_TO_SCREEN(prev_y) + snapcursor_size); + draw_xhair_line(xctx->gctiled, snapcursor_size, + X_TO_SCREEN(prev_x), + Y_TO_SCREEN(prev_y) + snapcursor_size, + X_TO_SCREEN(prev_x) - snapcursor_size, + Y_TO_SCREEN(prev_y)); + draw_xhair_line(xctx->gctiled, snapcursor_size, + X_TO_SCREEN(prev_x) - snapcursor_size, + Y_TO_SCREEN(prev_y), + X_TO_SCREEN(prev_x), + Y_TO_SCREEN(prev_y) - snapcursor_size); } } if(what != 1) { @@ -1496,11 +1527,8 @@ void draw_snap_cursor(int what) x = xctx->prev_snapx; y = xctx->prev_snapy; } else { /* Only search for nearest pin if the grid-snap-point has changed */ - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + xctx->closest_pin_found = find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); } - /*double points_x[5] = {x, x+snapcursor_size, x, x-snapcursor_size, x};*/ - /*double points_y[5] = {y-snapcursor_size, y, y+snapcursor_size, y, y-snapcursor_size};*/ - /*drawpolygon(xctx->crosshair_layer, NOW, points_x, points_y, 5, 0, 0, 0);*/ draw_xhair_line(xctx->gc[xctx->crosshair_layer], snapcursor_size, X_TO_SCREEN(x), Y_TO_SCREEN(y) - snapcursor_size, @@ -4250,8 +4278,11 @@ int rstate; /* (reduced state, without ShiftMask) */ if(tclgetboolvar("persistent_command") && xctx->last_command) { if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); if(xctx->last_command == STARTWIRE){ - if(tclgetboolvar("snap_cursor") && (xctx->prev_snapx == xctx->mousex_snap && xctx->prev_snapy == xctx->mousey_snap) - && (xctx->ui_state & STARTWIRE)){ + if(tclgetboolvar("snap_cursor") + && (xctx->prev_snapx == xctx->mousex_snap + && xctx->prev_snapy == xctx->mousey_snap) + && (xctx->ui_state & STARTWIRE) + && xctx->closest_pin_found){ new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); xctx->ui_state &= ~STARTWIRE; } diff --git a/src/findnet.c b/src/findnet.c index 852e72bb..cc9801e1 100644 --- a/src/findnet.c +++ b/src/findnet.c @@ -185,7 +185,7 @@ static void find_closest_line(double mx, double my) /* snap wire to closest pin or net endpoint (if it is inside the current screen viewport) */ /* use spatial hash table iterators to avoid O(N) */ -void find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) +int find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) { double x1, y1, x2, y2; Iterator_ctx ctx; @@ -193,6 +193,7 @@ void find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) Wireentry *wireptr; double curr_dist = DBL_MAX; double xx, yy, dist, min_dist_x = xctx->mousex_snap, min_dist_y = xctx->mousey_snap; + int found_net_or_pin = 0; x1 = X_TO_XSCHEM(xctx->areax1); y1 = Y_TO_XSCHEM(xctx->areay1); @@ -218,6 +219,7 @@ void find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) curr_dist = dist; min_dist_x = xx; min_dist_y = yy; + found_net_or_pin = 1; } } } @@ -236,6 +238,7 @@ void find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) curr_dist = dist; min_dist_x = xx; min_dist_y = yy; + found_net_or_pin = 1; } xx = wire[i].x2; yy = wire[i].y2; @@ -245,11 +248,13 @@ void find_closest_net_or_symbol_pin(double mx, double my, double *x, double *y) curr_dist = dist; min_dist_x = xx; min_dist_y = yy; + found_net_or_pin = 1; } } *x = min_dist_x; *y = min_dist_y; + return found_net_or_pin; } #if 0 diff --git a/src/xinit.c b/src/xinit.c index acb456ef..2fcb25f7 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -648,6 +648,7 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->prev_crossx = xctx->prev_crossy = 0.0; xctx->prev_gridx = xctx->prev_gridy = 0.0; xctx->prev_snapx = xctx->prev_snapy = 0.0; + xctx->closest_pin_found = 0; xctx->mouse_inside = 0; xctx->pending_fullzoom = 0; my_strncpy(xctx->hiersep, ".", S(xctx->hiersep)); diff --git a/src/xschem.h b/src/xschem.h index 23d9d254..de5b5f2a 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1051,6 +1051,7 @@ typedef struct { double prev_crossx, prev_crossy; double prev_gridx, prev_gridy; double prev_snapx, prev_snapy; + int closest_pin_found; int mouse_inside; /* set_modify */ int prev_set_modify; @@ -1397,7 +1398,8 @@ extern int callback(const char *winpath, int event, int mx, int my, KeySym key, int button, int aux, int state); extern void resetwin(int create_pixmap, int clear_pixmap, int force, int w, int h); extern Selected find_closest_obj(double mx,double my, int override_lock); -extern void find_closest_net_or_symbol_pin(double mx,double my, double *x, double *y); +/*extern void find_closest_net_or_symbol_pin(double mx,double my, double *x, double *y);*/ +extern int find_closest_net_or_symbol_pin(double mx,double my, double *x, double *y); extern void drawline(int c, int what, double x1,double y1,double x2,double y2, int dash, void *ct); extern void draw_xhair_line(GC gc, int size, double linex1, double liney1, double linex2, double liney2); From 7e9132ff3be3ce11e22026b2d5162ada4acddc6f Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 24 Jan 2025 16:48:42 +0530 Subject: [PATCH 36/59] [Manual Upstream Merge]: Manually reintroduced the changes from commit a361505 without breaking functionalities. This fork is now effectively up-to-date with upstream. --- src/actions.c | 24 ++++++++------- src/callback.c | 80 +++++++++++++++++++++++--------------------------- src/xschem.h | 1 + 3 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/actions.c b/src/actions.c index 4c07a46f..60ee1174 100644 --- a/src/actions.c +++ b/src/actions.c @@ -3019,7 +3019,7 @@ void new_wire(int what, double mx_snap, double my_snap) if( (what & PLACE) ) { if( (xctx->ui_state & STARTWIRE) && (xctx->nl_x1!=xctx->nl_x2 || xctx->nl_y1!=xctx->nl_y2) ) { xctx->push_undo(); - if(xctx->manhattan_lines==1) { + if(xctx->manhattan_lines & 1) { if(xctx->nl_xx2!=xctx->nl_xx1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3038,7 +3038,7 @@ void new_wire(int what, double mx_snap, double my_snap) hash_wire(XINSERT, xctx->wires-1, 1); drawline(WIRELAYER,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); } - } else if(xctx->manhattan_lines==2) { + } else if(xctx->manhattan_lines & 2) { if(xctx->nl_yy2!=xctx->nl_yy1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3076,6 +3076,8 @@ void new_wire(int what, double mx_snap, double my_snap) draw(); /* draw_hilight_net(1);*/ /* for updating connection bubbles on hilight nets */ } + +#if 0 if(! (what &END)) { xctx->nl_x1=mx_snap; xctx->nl_y1=my_snap; @@ -3085,7 +3087,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->nl_yy1=xctx->nl_y1; xctx->nl_xx2=xctx->mousex_snap; xctx->nl_yy2=xctx->mousey_snap; - if(xctx->manhattan_lines==1) { + if(xctx->manhattan_lines & 1) { xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3095,7 +3097,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - } else if(xctx->manhattan_lines==2) { + } else if(xctx->manhattan_lines & 2) { xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3113,6 +3115,8 @@ void new_wire(int what, double mx_snap, double my_snap) drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } } +#endif + xctx->nl_x1 = xctx->nl_x2=mx_snap; xctx->nl_y1 = xctx->nl_y2=my_snap; xctx->ui_state |= STARTWIRE; if(modified) set_modify(1); } @@ -3120,7 +3124,7 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->ui_state &= ~STARTWIRE; } if( (what & RUBBER) ) { - if(xctx->manhattan_lines==1) { + if(xctx->manhattan_lines & 1) { xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1; xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); @@ -3141,7 +3145,7 @@ void new_wire(int what, double mx_snap, double my_snap) ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } - } else if(xctx->manhattan_lines==2) { + } else if(xctx->manhattan_lines & 2) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); @@ -3311,7 +3315,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) if( (xctx->nl_x1!=xctx->nl_x2 || xctx->nl_y1!=xctx->nl_y2) && (xctx->ui_state & STARTLINE) ) { xctx->push_undo(); - if(xctx->manhattan_lines==1) { + if(xctx->manhattan_lines & 1) { if(xctx->nl_xx2!=xctx->nl_xx1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3328,7 +3332,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) modified = 1; drawline(xctx->rectcolor,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); } - } else if(xctx->manhattan_lines==2) { + } else if(xctx->manhattan_lines & 2) { if(xctx->nl_yy2!=xctx->nl_yy1) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; @@ -3365,7 +3369,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) if(what & RUBBER) { - if(xctx->manhattan_lines==1) { + if(xctx->manhattan_lines & 1) { xctx->nl_xx1 = xctx->nl_x1;xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2;xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); @@ -3386,7 +3390,7 @@ void new_line(int what, double mousex_snap, double mousey_snap) ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtempline(xctx->gc[xctx->rectcolor], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); } - } else if(xctx->manhattan_lines==2) { + } else if(xctx->manhattan_lines & 2) { xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); diff --git a/src/callback.c b/src/callback.c index f3a64f41..b4f4f4e1 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1641,6 +1641,26 @@ static int end_place_move_copy_zoom() return 0; } +void snapped_wire(double c_snap) +{ + double x, y; + if(!(xctx->ui_state & STARTWIRE)){ + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + xctx->mx_double_save = my_round(x / c_snap) * c_snap; + xctx->my_double_save = my_round(y / c_snap) * c_snap; + new_wire(PLACE, x, y); + new_wire(RUBBER, xctx->mousex_snap,xctx->mousey_snap); + } + else { + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + new_wire(RUBBER, x, y); + new_wire(PLACE|END, x, y); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + if((xctx->ui_state & MENUSTART) && !tclgetboolvar("persistent_command") ) xctx->ui_state &= ~MENUSTART; + } +} + static int check_menu_start_commands(double c_snap) { dbg(1, "check_menu_start_commands(): ui_state=%x, ui_state2=%x last_command=%d\n", @@ -1648,12 +1668,10 @@ static int check_menu_start_commands(double c_snap) if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT)) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT2)) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTMOVE)) { @@ -1662,14 +1680,12 @@ static int check_menu_start_commands(double c_snap) /* stretch nets that land on selected instance pins if connect_by_kissing == 2 */ /* select_attached_nets(); */ move_objects(START,0,0,0); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCOPY)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; copy_objects(START); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) { @@ -1680,8 +1696,6 @@ static int check_menu_start_commands(double c_snap) tcleval("set constr_mv 0" ); xctx->constr_mv=0; } - xctx->ui_state &=~MENUSTART; - xctx->ui_state2 = 0; /* * xctx->mx_double_save=xctx->mousex_snap; @@ -1692,13 +1706,7 @@ static int check_menu_start_commands(double c_snap) return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTSNAPWIRE)) { - double x, y; - - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - xctx->mx_double_save = my_round(x / c_snap) * c_snap; - xctx->my_double_save = my_round(y / c_snap) * c_snap; - new_wire(PLACE, x, y); - xctx->ui_state &=~MENUSTART; + snapped_wire(c_snap); return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTLINE)) { @@ -1709,8 +1717,6 @@ static int check_menu_start_commands(double c_snap) tcleval("set constr_mv 0" ); xctx->constr_mv=0; } - xctx->ui_state &=~MENUSTART; - xctx->ui_state2 = 0; /* * xctx->mx_double_save=xctx->mousex_snap; @@ -1724,33 +1730,28 @@ static int check_menu_start_commands(double c_snap) xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTPOLYGON)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTARC)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCIRCLE)) { xctx->mx_double_save=xctx->mousex_snap; xctx->my_double_save=xctx->mousey_snap; new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); - xctx->ui_state &=~MENUSTART; return 1; } else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTZOOM)) { zoom_rectangle(START); - xctx->ui_state &=~MENUSTART; return 1; } return 0; @@ -2348,25 +2349,6 @@ static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key } #endif -static void snapped_wire(double c_snap) -{ - double x, y; - if(!(xctx->ui_state & STARTWIRE)){ - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - xctx->mx_double_save = my_round(x / c_snap) * c_snap; - xctx->my_double_save = my_round(y / c_snap) * c_snap; - new_wire(PLACE, x, y); - new_wire(RUBBER, xctx->mousex_snap,xctx->mousey_snap); - } - else { - find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); - new_wire(RUBBER, x, y); - new_wire(PLACE|END, x, y); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - } -} - /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* winpath: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -2386,7 +2368,9 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, int draw_xhair = tclgetboolvar("draw_crosshair"); int infix_interface = tclgetboolvar("infix_interface"); int snap_cursor = tclgetboolvar("snap_cursor"); -int wire_draw_active = (xctx->ui_state & STARTWIRE) || (xctx->ui_state2 & MENUSTARTWIRE) || (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); +int wire_draw_active = (xctx->ui_state & STARTWIRE) || + ((xctx->ui_state2 & MENUSTARTWIRE) && (xctx->ui_state & MENUSTART)) || + (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); int rstate; /* (reduced state, without ShiftMask) */ /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease @@ -2675,7 +2659,8 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* snap crosshair to closest pin or net endpoint */ if(draw_xhair) { - if( ( (xctx->ui_state & STARTWIRE) || xctx->ui_state == 0 ) && (state & ShiftMask) ) { + if( ( (xctx->ui_state & (MENUSTART | STARTWIRE)) || xctx->ui_state == 0 ) && + (state & ShiftMask) ) { double x, y, sx, sy; sx = xctx->mousex_snap; sy = xctx->mousey_snap; @@ -2703,7 +2688,7 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->manhattan_lines %=3; new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } else if(xctx->ui_state==STARTLINE) { + } else if(xctx->ui_state & STARTLINE) { new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); xctx->manhattan_lines++; xctx->manhattan_lines %=3; @@ -4239,7 +4224,6 @@ int rstate; /* (reduced state, without ShiftMask) */ /* terminate wire placement in snap mode */ else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { snapped_wire(c_snap); - here(1111); } /* Alt - Button1 click to unselect */ else if(button==Button1 && (SET_MODMASK) ) { @@ -4418,7 +4402,8 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - /*else if(state == Button1Mask && xctx->intuitive_interface && (xctx->ui_state & STARTWIRE)) {*/ + /*else if(state == Button1Mask && xctx->intuitive_interface + * && (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) {*/ /* if(end_place_move_copy_zoom()) break;*/ /*}*/ @@ -4469,6 +4454,13 @@ int rstate; /* (reduced state, without ShiftMask) */ xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); statusmsg(str,1); } + + /* clear start from menu flag or infix_interface=0 start commands */ + if(xctx->ui_state & MENUSTART) { + xctx->ui_state &= ~MENUSTART; + break; + } + if(draw_xhair) draw_crosshair(0); if(snap_cursor && wire_draw_active) draw_snap_cursor(0); break; diff --git a/src/xschem.h b/src/xschem.h index 7d79d48b..50a7ff42 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1394,6 +1394,7 @@ extern int Tcl_AppInit(Tcl_Interp *interp); extern void abort_operation(void); extern void draw_crosshair(int what); extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr); +/* extern void snapped_wire(double c_snap); */ extern int callback(const char *winpath, int event, int mx, int my, KeySym key, int button, int aux, int state); extern void resetwin(int create_pixmap, int clear_pixmap, int force, int w, int h); From 2137fa0aeff529ddde8128a45352d068180daa5a Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 25 Jan 2025 12:26:52 +0530 Subject: [PATCH 37/59] [Graphical Bugfix]: Fixed a small graphical bug that occurred when drawing multi-segment wires in persistent_command mode and suddenly exiting using 'Esc'-key while the snap-cursor is active. --- src/callback.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/callback.c b/src/callback.c index e792181d..fb605967 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2955,6 +2955,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)) { xctx->last_command &= ~STARTWIRE; + if(snap_cursor) draw_snap_cursor(1); } break; } From 260beffe717163602fb6023399d18d8f9440eda8 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 25 Jan 2025 12:47:23 +0530 Subject: [PATCH 38/59] [Selection Using Crosshair]: Added new functionality of using the crosshair to select objects in the schematic, instead of the default mouse-pointer based selection. This functionality will only take effect if the crosshair feature is enabled by the user. --- src/callback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index fb605967..2601ab0b 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4301,7 +4301,8 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); - sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); + if(draw_xhair) sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); + else sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); switch(sel.type) { case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; From 9056da92a6a49890c10871102ead91bfe939b45a Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 26 Jan 2025 11:39:04 +0530 Subject: [PATCH 39/59] [After merge-changes]: Changes made to match pre-merge state of 'snap-cursor select' in this fork. --- src/callback.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index 1f9d4d4a..6e67c7de 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4333,12 +4333,10 @@ int rstate; /* (reduced state, without ShiftMask) */ * first unselect everything... * For intuitive interface unselection see below... */ if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); - if(draw_xhair) sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); - else sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); /* find closest object. Use snap coordinates if full crosshair is enabled * since the mouse pointer is obscured and crosshair is snapped to grid points */ - if(draw_xhair && crosshair_size == 0) { + if(draw_xhair) { sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); } else { sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); From 999503a26a6ef45dbcefc17454b7813574d9c888 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 26 Jan 2025 12:17:29 +0530 Subject: [PATCH 40/59] [Fixed Typo]: Fixed a small typo that would create a bug in TCL. --- src/xschemrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xschemrc b/src/xschemrc index 3fd4bce6..bce0f8cf 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -285,8 +285,8 @@ #### set crosshair size; Default: 0 (full screen spanning crosshair) set crosshair_size 2 -#### set snap_cursor size; Default: 3 (Diamond-shaped cursor that snaps to nearest circuit endpoint) -# set snap_cursor size 3 +#### set snap_cursor_size; Default: 3 (Diamond-shaped cursor that snaps to nearest circuit endpoint) +# set snap_cursor_size 3 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 18fb977c68ec25dccaa63ced9bed5c9193f87e95 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 26 Jan 2025 12:33:21 +0530 Subject: [PATCH 41/59] [Refactor + Minor Changes]: Refactored to fix a small code-readablity issue from last upstream merge. Added the snap_cursor option to be enabled from 'src/xschemrc' config file. --- src/callback.c | 2 +- src/xschemrc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index 6e67c7de..ad46f9b3 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2569,8 +2569,8 @@ int rstate; /* (reduced state, without ShiftMask) */ if(draw_xhair) { draw_crosshair(1); /* when moving mouse: first action is delete crosshair, will be drawn later */ } - /* pan schematic */ if(snap_cursor && wire_draw_active) draw_snap_cursor(1); + /* pan schematic */ if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); if(xctx->semaphore >= 2) { diff --git a/src/xschemrc b/src/xschemrc index bce0f8cf..db52c144 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -285,6 +285,9 @@ #### set crosshair size; Default: 0 (full screen spanning crosshair) set crosshair_size 2 +#### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) +# set snap_cursor 1 + #### set snap_cursor_size; Default: 3 (Diamond-shaped cursor that snaps to nearest circuit endpoint) # set snap_cursor_size 3 From 15fc4b9bb4d6d9bce199045e522f525ad9001748 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 26 Jan 2025 13:31:33 +0530 Subject: [PATCH 42/59] [Refactor + Minor Changes]: Refactored to fix a small code-readablity issue. --- src/callback.c | 13 ++++++------- src/xschem.h | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/callback.c b/src/callback.c index ad46f9b3..0742d4c7 100644 --- a/src/callback.c +++ b/src/callback.c @@ -319,7 +319,7 @@ void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr) cnt = 0; } if(xx >= start && xx <= end) { - if((dataset == sweepvar_wrap)) { + if(dataset == sweepvar_wrap) { dbg(1, "xx=%g cursor2=%g first=%d last=%d start=%g end=%g p=%d wrap=%d sweepvar_wrap=%d ofs=%d\n", xx, cursor2, first, last, start, end, p, wrap, sweepvar_wrap, ofs); if(first == -1) first = p; @@ -1465,7 +1465,7 @@ void draw_crosshair(int what) xctx->draw_pixmap = sdp; } -/* what == 0 : erase and draw a new cursor +/* what == 3 : erase and draw a new cursor * what == 1 : erase the cursor * what == 2 : draw a diamond-shaped cursor that snaps to a component endpoint */ void draw_snap_cursor(int what) @@ -1482,9 +1482,8 @@ void draw_snap_cursor(int what) xctx->draw_window = 1; double prev_x = xctx->prev_snapx; double prev_y = xctx->prev_snapy; - if(what != 2) { + if(what & 1) { if(fix_broken_tiled_fill || !_unix) { - /*MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], 0, 0, xctx->xrect[0].width, xctx->xrect[0].height, 0, 0);*/ MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, @@ -1522,7 +1521,7 @@ void draw_snap_cursor(int what) Y_TO_SCREEN(prev_y) - snapcursor_size); } } - if(what != 1) { + if(what & 1) { double x, y; if(!pos_changed) { x = xctx->prev_snapx; @@ -2996,7 +2995,7 @@ int rstate; /* (reduced state, without ShiftMask) */ draw_snap_cursor(1); } else { tclsetvar("snap_cursor", "1"); - if(wire_draw_active) draw_snap_cursor(0); + if(wire_draw_active) draw_snap_cursor(3); } } if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ @@ -4525,7 +4524,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) draw_crosshair(3); /* restore crosshair when selecting / unselecting */ - if(snap_cursor && wire_draw_active) draw_snap_cursor(0); + if(snap_cursor && wire_draw_active) draw_snap_cursor(3); break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { diff --git a/src/xschem.h b/src/xschem.h index a10139bf..4bd05ae4 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1393,6 +1393,7 @@ extern void tclmainloop(void); extern int Tcl_AppInit(Tcl_Interp *interp); extern void abort_operation(void); extern void draw_crosshair(int what); +extern void draw_snap_cursor(int what); extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr); /* extern void snapped_wire(double c_snap); */ extern int callback(const char *winpath, int event, int mx, int my, KeySym key, From 4022d0ec10aaacc28b9cadc88f0d597d8b6ca773 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sun, 26 Jan 2025 14:39:48 +0530 Subject: [PATCH 43/59] [Graphical Bugfix]: Fixed a small graphical bug that occurred when drawing a wire while simutaneously zooming in/out in the schematic editor. --- src/callback.c | 2 +- src/xschemrc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callback.c b/src/callback.c index 0742d4c7..8ce7412c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4524,7 +4524,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(draw_xhair) draw_crosshair(3); /* restore crosshair when selecting / unselecting */ - if(snap_cursor && wire_draw_active) draw_snap_cursor(3); + if(snap_cursor && wire_draw_active) draw_snap_cursor(2); break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { diff --git a/src/xschemrc b/src/xschemrc index db52c144..305c308b 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -288,8 +288,8 @@ set crosshair_size 2 #### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) # set snap_cursor 1 -#### set snap_cursor_size; Default: 3 (Diamond-shaped cursor that snaps to nearest circuit endpoint) -# set snap_cursor_size 3 +#### set snap_cursor_size; Default: 6 (Diamond-shaped cursor that snaps to nearest circuit endpoint) +# set snap_cursor_size 6 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 6f20174c42d89db9a631f7bc059e371183553687 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Mon, 27 Jan 2025 12:52:20 +0530 Subject: [PATCH 44/59] [Compatibility + Graphical Bugfix]: Fixed compatibility issue resulting from a breaking change in the function 'redraw_w_a_l_p_z_rubber(int force)', and also fixed (partially) a graphical bug resulting from this change. The bug shouldn't affect user workflow at the current version. --- src/callback.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/callback.c b/src/callback.c index 0dd703c6..5023ac7e 100644 --- a/src/callback.c +++ b/src/callback.c @@ -230,7 +230,7 @@ static void start_wire(double mx, double my) if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ xctx->constr_mv = xctx->manhattan_lines; new_wire(CLEAR, mx, my); - redraw_w_a_l_r_p_rubbers(); + redraw_w_a_l_r_p_z_rubbers(1); } if(xctx->constr_mv != 2) { xctx->mx_double_save = mx; @@ -1504,19 +1504,19 @@ void draw_snap_cursor(int what) if(what & 1) { if(fix_broken_tiled_fill || !_unix) { MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, - 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, - (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size); + (int)X_TO_SCREEN(prev_x) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + (int)X_TO_SCREEN(prev_x) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size); MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], - (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, - 4 * INT_WIDTH(xctx->lw) + 4 * snapcursor_size, - (int)X_TO_SCREEN(prev_x) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size, - (int)Y_TO_SCREEN(prev_y) - 2 * INT_WIDTH(xctx->lw) - snapcursor_size); + (int)X_TO_SCREEN(prev_x) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + (int)X_TO_SCREEN(prev_x) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - 1 * INT_WIDTH(xctx->lw) - snapcursor_size); } else { draw_xhair_line(xctx->gctiled, snapcursor_size, X_TO_SCREEN(prev_x), @@ -3708,7 +3708,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } else { tclsetboolvar("orthogonal_wiring", 1); } - redraw_w_a_l_r_p_rubbers(); + redraw_w_a_l_r_p_z_rubbers(1); break; } if(key=='F' && rstate == 0) /* flip */ @@ -4526,7 +4526,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; } if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ - if(snap_cursor && wire_draw_active) draw_snap_cursor(2); + if(snap_cursor && wire_draw_active) draw_snap_cursor(3); break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { @@ -4550,7 +4550,7 @@ int rstate; /* (reduced state, without ShiftMask) */ edit_property(0); } else { if(xctx->ui_state & STARTWIRE) { - redraw_w_a_l_r_p_rubbers(); + redraw_w_a_l_r_p_z_rubbers(1); start_wire(mx, my); xctx->ui_state &= ~STARTWIRE; } From 753f5d24bca8cc08ace1b5ba6571f8dab31b8186 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 29 Jan 2025 11:54:25 +0530 Subject: [PATCH 45/59] Changes made to reduce git diff with upstream repo --- src/xschem.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xschem.tcl b/src/xschem.tcl index b02051d4..fa294625 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7664,7 +7664,7 @@ set tctx::global_list { autotrim_wires orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer crosshair_size cursor_2_hook snap_cursor_size custom_label_prefix custom_token - dark_colors dark_colorscheme dark_gui_colorscheme delay_flag + dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names do_all_inst draw_crosshair draw_grid draw_grid_axes draw_window edit_prop_pos edit_prop_size edit_symbol_prop_new_sel editprop_sympath en_hilight_conn_inst enable_dim_bg enable_stretch From 808f89c4c60fb2908ef5c41e3389e94b3bfd53df Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 29 Jan 2025 13:44:24 +0530 Subject: [PATCH 46/59] Fix typo --- src/xschemrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xschemrc b/src/xschemrc index 305c308b..007933c8 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -234,7 +234,7 @@ #### wires are drawn in free-form mode with this mode enabled (default). #### if set to 0, wires drawn on the schematic will no longer strictly -#### follow orthogonal routes to connect two distinct points toegther. +#### follow orthogonal routes to connect two distinct points together. #### default: 1 # set orthogonal_wiring 0 From d4b388186d33e584b164d9e48e6b5236722c1ed7 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 1 Feb 2025 16:22:03 +0530 Subject: [PATCH 47/59] [Upstream Compatibily Fixes]: Added a new TCL-variable 'cadence_compat', which can be enabled from either the TCL-command execution prompt inside xschem, or by uncommenting the corresponding option in 'src/xschemrc' - used for enabling Cadence-friendly keybinds (simulate and snap-wire). Additionally, reset the default behavior of xschem to the upstream-version's behavior. All the disabled options can be re-enabled by uncommenting the correct options in 'src/xschemrc'. Added ANSI-C compatibility fixes suggested by @StefanSchippers in issue #292 in upstream repo. --- src/callback.c | 36 +++++++++++++++++++++++++++++++----- src/xschem.tcl | 9 +++++---- src/xschemrc | 9 ++++++--- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/callback.c b/src/callback.c index 9c962dc6..c5b2309e 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,6 +21,7 @@ */ #include "xschem.h" +#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) @@ -102,6 +103,7 @@ void redraw_w_a_l_r_p_z_rubbers(int force) { double mx = xctx->mousex_snap; double my = xctx->mousey_snap; + double origin_shifted_x2, origin_shifted_y2; if(!force && xctx->mousex_snap == xctx->prev_rubberx && xctx->mousey_snap == xctx->prev_rubbery) return; @@ -112,7 +114,8 @@ void redraw_w_a_l_r_p_z_rubbers(int force) if(tclgetboolvar("orthogonal_wiring")) { new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ - int origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1, origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; + origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1; + origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2){ xctx->manhattan_lines = 1; @@ -1516,6 +1519,8 @@ void draw_snap_cursor(int what) int sdw, sdp; int snapcursor_size = tclgetintvar("snap_cursor_size"); int pos_changed = (xctx->mousex_snap - xctx->prev_gridx) || (xctx->mousey_snap - xctx->prev_gridy); + double prev_x = xctx->prev_snapx; + double prev_y = xctx->prev_snapy; dbg(1, "draw_snap_cursor(): what=%d\n", what); sdw = xctx->draw_window; sdp = xctx->draw_pixmap; @@ -1523,8 +1528,6 @@ void draw_snap_cursor(int what) if(!xctx->mouse_inside) return; xctx->draw_pixmap = 0; xctx->draw_window = 1; - double prev_x = xctx->prev_snapx; - double prev_y = xctx->prev_snapy; if(what & 1) { if(fix_broken_tiled_fill || !_unix) { MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], @@ -2418,6 +2421,7 @@ int draw_xhair = tclgetboolvar("draw_crosshair"); int crosshair_size = tclgetintvar("crosshair_size"); int infix_interface = tclgetboolvar("infix_interface"); int snap_cursor = tclgetboolvar("snap_cursor"); +int cadence_compat = tclgetboolvar("cadence_compat"); int wire_draw_active = (xctx->ui_state & STARTWIRE) || ((xctx->ui_state2 & MENUSTARTWIRE) && (xctx->ui_state & MENUSTART)) || (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); @@ -2958,7 +2962,12 @@ int rstate; /* (reduced state, without ShiftMask) */ hilight_net_pin_mismatches(); break; } - if(key== 's' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */ + if(xctx->semaphore >= 2) break; + snapped_wire(c_snap); + break; + } + if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ if(xctx->semaphore >= 2) break; snapped_wire(c_snap); break; @@ -3016,6 +3025,9 @@ int rstate; /* (reduced state, without ShiftMask) */ if(tclgetboolvar("snap_cursor")) { tclsetvar("snap_cursor", "0"); draw_snap_cursor(1); + xctx->closest_pin_found = 0; + xctx->prev_snapx = 0.0; + xctx->prev_snapy = 0.0; } else { tclsetvar("snap_cursor", "1"); if(wire_draw_active) draw_snap_cursor(3); @@ -3213,7 +3225,21 @@ int rstate; /* (reduced state, without ShiftMask) */ draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ break; } - if(key=='r' && rstate == ControlMask ) /* simulate */ + if((key=='s' && rstate == 0) && !cadence_compat) /* simulate (original keybind) */ + { + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + break; + } + if((key=='r' && rstate == ControlMask) && cadence_compat) /* simulate (for cadence users) */ { if(xctx->semaphore >= 2) break; if(waves_selected(event, key, state, button)) { diff --git a/src/xschem.tcl b/src/xschem.tcl index 5c21b990..5c12cffb 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7702,7 +7702,7 @@ set tctx::global_list { INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow autotrim_wires orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers - cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv + cadsnap cadence_compat cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv copy_cell crosshair_layer crosshair_size cursor_2_hook snap_cursor_size custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names do_all_inst draw_crosshair @@ -8120,7 +8120,7 @@ proc build_widgets { {topwin {} } } { global dark_gui_colorscheme draw_crosshair global recentfile color_ps transparent_svg menu_debug_var enable_stretch global netlist_show flat_netlist split_files compare_sch intuitive_interface - global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width + global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width cadence_compat global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type snap_cursor global disable_unique_names persistent_command autotrim_wires infix_interface orthogonal_wiring en_hilight_conn_inst global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry @@ -9184,9 +9184,10 @@ set_ne draw_grid_axes 1 set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne autotrim_wires 0 -set_ne infix_interface 0 +set_ne cadence_compat 0 +set_ne infix_interface 1 set_ne snap_cursor 0 -set_ne orthogonal_wiring 1 +set_ne orthogonal_wiring 0 set_ne compare_sch 0 set_ne disable_unique_names 0 set_ne sym_txt 1 diff --git a/src/xschemrc b/src/xschemrc index 007933c8..dfec3dfc 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -235,8 +235,8 @@ #### wires are drawn in free-form mode with this mode enabled (default). #### if set to 0, wires drawn on the schematic will no longer strictly #### follow orthogonal routes to connect two distinct points together. -#### default: 1 -# set orthogonal_wiring 0 +#### default: 0 +# set orthogonal_wiring 1 #### if set to 1 automatically join/trim wires while editing #### this may slow down on rally big designs. Can be disabled via menu @@ -283,7 +283,7 @@ # set crosshair_layer 8 #### set crosshair size; Default: 0 (full screen spanning crosshair) -set crosshair_size 2 +# set crosshair_size 2 #### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) # set snap_cursor 1 @@ -291,6 +291,9 @@ set crosshair_size 2 #### set snap_cursor_size; Default: 6 (Diamond-shaped cursor that snaps to nearest circuit endpoint) # set snap_cursor_size 6 +#### set cadence_compat; Default: 0 (Cadence-style keybinds are not used by default) +# set cadence_compat 1 + #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From aa1c038f5c95274f25bd72eabbf34437356da090 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Sat, 1 Feb 2025 16:23:56 +0530 Subject: [PATCH 48/59] Small correction --- src/callback.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index c5b2309e..8d612530 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,7 +21,6 @@ */ #include "xschem.h" -#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) From 5487575d819bd345454fa1f10d3963467c88592b Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Mon, 3 Feb 2025 13:01:11 +0530 Subject: [PATCH 49/59] Lock old behavior of 'Esc'-keypress during persistent_command is active, behind the newly added TCL-option 'cadence_compat'. Wire drawing mode will now take two 'Esc' keypresses to clear, but if 'cadence_compat' is enabled, it will only take one. --- src/callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index 8d612530..056e3062 100644 --- a/src/callback.c +++ b/src/callback.c @@ -3003,7 +3003,7 @@ int rstate; /* (reduced state, without ShiftMask) */ if(xctx->ui_state2 & MENUSTARTWIRE) { xctx->ui_state2 &= ~MENUSTARTWIRE; } - if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)) { + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { xctx->last_command &= ~STARTWIRE; if(snap_cursor) draw_snap_cursor(1); } From 2bb0c10bd97ec33e957874ad809561eadacf1b4c Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Wed, 19 Feb 2025 16:58:07 +0530 Subject: [PATCH 50/59] [Refactor]: Manually added the refactoring changes introduced into upstream repository. --- .gitignore | 3 +- src/callback.c | 4075 ++++++++++++++++++++++++------------------------ 2 files changed, 2064 insertions(+), 2014 deletions(-) diff --git a/.gitignore b/.gitignore index 0fe49d81..9d85221b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # bison output src/expandlabel.c src/expandlabel.h +src/eval_expr.c # flex output src/parselabel.c src/parselabel.h @@ -39,4 +40,4 @@ scconfig/config.cache doc/manpages/xschem.1 Makefile.conf config.h -*.Identifier \ No newline at end of file +*.Identifier diff --git a/src/callback.c b/src/callback.c index 45e95cec..c1deffe4 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2429,6 +2429,2051 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke } #endif +static void handle_enter_notify(int draw_xhair, int crosshair_size) +{ + struct stat buf; + dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); + xctx->mouse_inside = 1; + if(draw_xhair) { + if(crosshair_size == 0) { + tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); + } + } else + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + /* xschem window *sending* selected objects + when the pointer comes back in abort copy operation since it has been done + in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ + if(stat(sel_file, &buf) && (xctx->ui_state & STARTCOPY) ) + { + copy_objects(ABORT); + unselect_all(1); + } + /* xschem window *receiving* selected objects selection cleared --> abort */ + else if(xctx->paste_from == 1 && stat(sel_file, &buf) && (xctx->ui_state & STARTMERGE)) { + abort_operation(); + } + /*xschem window *receiving* selected objects + * no selected objects and selection file exists --> start merge */ + else if(xctx->lastsel == 0 && !stat(sel_file, &buf)) { + xctx->mousex_snap = 490; + xctx->mousey_snap = -340; + merge_file(1, ".sch"); + } + return; +} + +static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, + int mx, int my, int aux, int draw_xhair, int enable_stretch, int snap_cursor, int wire_draw_active, char *str) +{ + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(draw_xhair) { + draw_crosshair(1, state); /* when moving mouse: first action is delete crosshair, will be drawn later */ + } + if(snap_cursor && wire_draw_active) draw_snap_cursor(1); + /* pan schematic */ + if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); + + if(xctx->semaphore >= 2) { + if(draw_xhair) { + draw_crosshair(2, state); /* locked UI: draw new crosshair and break out */ + } + if(snap_cursor && wire_draw_active) draw_snap_cursor(2); + return; + } + + /* update status bar messages */ + if(xctx->ui_state) { + if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", + xctx->mousex_snap, xctx->mousey_snap, + xctx->lastsel , + xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save + ); + statusmsg(str,1); + } + } + + /* determine direction of a rectangle selection (or unselection with ALT key) */ + if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { + /* Unselect by area : determine direction */ + if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,0); + /* select by area : determine direction */ + } else if(state & Button1Mask) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,1); + } + } + /* draw objects being moved */ + if(xctx->ui_state & STARTMOVE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + move_objects(RUBBER,0,0,0); + } + + /* draw objects being copied */ + if(xctx->ui_state & STARTCOPY) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + copy_objects(RUBBER); + } + + /* draw moving objects being inserted, wires, arcs, lines, rectangles, polygons or zoom box */ + redraw_w_a_l_r_p_z_rubbers(0); + + /* start of a mouse area select. Button1 pressed. No shift pressed + * Do not start an area select if user is dragging a polygon/bezier point */ + if(!(xctx->ui_state & STARTPOLYGON) && (state&Button1Mask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & STARTPAN) && !(SET_MODMASK) && !xctx->shape_point_selected && + !(state & ShiftMask) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) + { + if(mx != xctx->mx_save || my != xctx->my_save) { + xctx->mouse_moved = 1; + if(!xctx->drag_elements) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + xctx->onetime=1; + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(xctx->onetime) { + unselect_all(1); /* 20171026 avoid multiple calls of unselect_all() */ + xctx->onetime=0; + } + xctx->ui_state|=STARTSELECT; /* set it again cause unselect_all(1) clears it... */ + } + } + } + } + /* Unselect by area */ + if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && + !(state & ShiftMask) && + !(xctx->ui_state & STARTPAN) && + !xctx->shape_point_selected && + !(xctx->ui_state & STARTSELECT) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ + select_rect(enable_stretch, START,0); + } + /* Select by area. Shift pressed */ + else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !xctx->shape_point_selected && + !xctx->drag_elements && !(xctx->ui_state & STARTPAN) ) { + if(mx != xctx->mx_save || my != xctx->my_save) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(!xctx->already_selected) { + select_object(X_TO_XSCHEM(xctx->mx_save), + Y_TO_XSCHEM(xctx->my_save), 0, 0, NULL); /* remove near obj if dragging */ + } + rebuild_selected_array(); + } + } + } + if(draw_xhair) { + draw_crosshair(2, state); /* what = 2(draw) */ + } + if(snap_cursor && wire_draw_active) draw_snap_cursor(2); + return; +} + +static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, + int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, + int cadence_compat, int wire_draw_active, int snap_cursor, char *str) +{ + if(key==' ') { + if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + + } else if(xctx->ui_state & STARTLINE) { + new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } else { + if(xctx->semaphore<2) { + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ + } + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + return; + } + if(key == '_' ) /* toggle change line width */ + { + if(!tclgetboolvar("change_lw")) { + tcleval("alert_ { enabling change line width} {}"); + tclsetvar("change_lw","1"); + } + else { + tcleval("alert_ { disabling change line width} {}"); + tclsetvar("change_lw","0"); + } + return; + } + if(key == 'b' && rstate==ControlMask) /* toggle show text in symbol */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->sym_txt =!xctx->sym_txt; + if(xctx->sym_txt) { + /* tcleval("alert_ { enabling text in symbol} {}"); */ + tclsetvar("sym_txt","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling text in symbol} {}"); */ + tclsetvar("sym_txt","0"); + draw(); + } + return; + } + if(key == '%' ) /* toggle draw grid */ + { + int dr_gr; + dr_gr = tclgetboolvar("draw_grid"); + dr_gr =!dr_gr; + if(dr_gr) { + /* tcleval("alert_ { enabling draw grid} {}"); */ + tclsetvar("draw_grid","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling draw grid} {}"); */ + tclsetvar("draw_grid","0"); + draw(); + } + return; + } + if(key == 'j' && rstate==0 ) /* print list of highlight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(1); + return; + } + if(key == 'j' && rstate==ControlMask) /* create ipins from highlight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(0); + return; + } + if(key == 'j' && EQUAL_MODMASK) /* create labels without i prefix from hilight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(4); + return; + } + if(key == 'J' && SET_MODMASK ) /* create labels with i prefix from hilight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(2); + return; + } + if(key == 'h' && rstate==ControlMask ) /* go to http link */ + { + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); + xctx->semaphore = savesem; + return; + } + if(key == 'h' && EQUAL_MODMASK) /* create symbol pins from schematic pins 20171208 */ + { + tcleval("schpins_to_sympins"); + return; + } + if(key == 'h' && rstate == 0) { + /* horizontally constrained drag 20171023 */ + if ( xctx->constr_mv == 1 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 1" ); + xctx->constr_mv = 1; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + if(key=='H' && rstate == 0) { /* attach labels to selected instances */ + attach_labels_to_inst(1); + return; + } + if (key == 'H' && rstate == ControlMask) { /* create schematic and symbol from selected components */ + make_schematic_symbol_from_sel(); + return; + } + if(key == 'v' && rstate==0) { + /* vertically constrained drag 20171023 */ + if ( xctx->constr_mv == 2 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 2" ); + xctx->constr_mv = 2; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + if(key == 'j' && SET_MODMASK && (state & ControlMask) ) /* print list of highlight net with label expansion */ + { + print_hilight_net(3); + return; + } + if(key == 'J' && rstate == 0) { + create_plot_cmd(); + return; + } + if(key == '$' && rstate == 0 ) /* toggle pixmap saving */ + { + xctx->draw_pixmap =!xctx->draw_pixmap; + if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); + else tcleval("alert_ { disabling draw pixmap} {}"); + return; + } + if(key == '$' && (state &ControlMask) ) /* toggle window drawing */ + { + xctx->draw_window =!xctx->draw_window; + if(xctx->draw_window) { + tcleval("alert_ { enabling draw window} {}"); + tclsetvar("draw_window","1"); + } else { + tcleval("alert_ { disabling draw window} {}"); + tclsetvar("draw_window","0"); + } + return; + } + if(key == '=' && (state &ControlMask)) /* toggle fill rectangles */ + { + int x; + xctx->fill_pattern++; + if(xctx->fill_pattern==3) xctx->fill_pattern=0; + + if(xctx->fill_pattern==1) { + tcleval("alert_ { Stippled pattern fill} {}"); + for(x=0;xfill_type[x]==1) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); + else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); + } + } + else if(xctx->fill_pattern==2) { + tcleval("alert_ { solid pattern fill} {}"); + for(x=0;xgcstipple[x],FillSolid); + } + else { + tcleval("alert_ { No pattern fill} {}"); + for(x=0;xgcstipple[x],FillStippled); + } + + draw(); + return; + } + if(key == '+' && state & ControlMask) /* change line width */ + { + xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + return; + } + + if(key == '-' && state & ControlMask) /* change line width */ + { + xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); + if(xctx->lw < 0.0) xctx->lw = 0.0; + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + return; + } + if(key == 'X' && rstate == 0) /* highlight discrepanciens between selected instance pin and net names */ + { + hilight_net_pin_mismatches(); + return; + } + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */ + if(xctx->semaphore >= 2) return; + snapped_wire(c_snap); + return; + } + if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ + if(xctx->semaphore >= 2) return; + snapped_wire(c_snap); + return; + } + if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ + { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return; + if(infix_interface) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTWIRE; + if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ + new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); + return; + } + if(key == XK_Escape) /* abort & redraw */ + { + if(xctx->semaphore < 2) { + abort_operation(); + } + /* stuff that can be done reentrantly ... */ + tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(xctx->ui_state2 & MENUSTARTWIRE) { + xctx->ui_state2 &= ~MENUSTARTWIRE; + } + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { + xctx->last_command &= ~STARTWIRE; + if(snap_cursor) draw_snap_cursor(1); + } + return; + } + if(key=='z' && rstate == 0 && + !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) /* zoom box */ + { + dbg(1, "callback(): zoom_rectangle call\n"); + zoom_rectangle(START);return; + } + if(key=='Z' && rstate == 0) /* zoom in */ + { + view_zoom(0.0); return; + } + if(key=='z' && EQUAL_MODMASK) /* toggle snap-cursor option */ + { + if(tclgetboolvar("snap_cursor")) { + tclsetvar("snap_cursor", "0"); + draw_snap_cursor(1); + xctx->closest_pin_found = 0; + xctx->prev_snapx = 0.0; + xctx->prev_snapy = 0.0; + } else { + tclsetvar("snap_cursor", "1"); + if(wire_draw_active) draw_snap_cursor(3); + } + } + if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ + { + xctx->push_undo(); + unselect_all(1); + storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, + xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); + xctx->need_reb_sel_arr=1; + rebuild_selected_array(); + move_objects(START,0,0,0); + xctx->ui_state |= START_SYMPIN; + return; + } + if(key=='p' && !(xctx->ui_state & STARTPOLYGON) && rstate==0) /* start polygon */ + { + if(xctx->semaphore >= 2) return; + dbg(1, "callback(): start polygon\n"); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTPOLYGON; + } + return; + } + if(key=='P' && rstate == 0) /* pan, other way to. */ + { + xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; + xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key=='5' && rstate == 0) { /* 20110112 display only probes */ + xctx->only_probes = !xctx->only_probes; + tclsetboolvar("only_probes", xctx->only_probes); + toggle_only_probes(); + return; + } /* /20110112 */ + if(key<='9' && key >='0' && state==ControlMask) /* choose layer */ + { + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); + + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); + return; + } + if(key==XK_Delete && (xctx->ui_state & SELECTION) ) /* delete selection */ + { + if(xctx->semaphore >= 2) return; + delete(1/* to_push_undo */);return; + } + if(key==XK_Right && state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->semaphore = 0; + tcleval("next_tab"); + xctx->semaphore = save; + return; + } + if(key==XK_Left && state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->semaphore = 0; + tcleval("prev_tab"); + xctx->semaphore = save; + return; + } + if(key==XK_Right && !(state & ControlMask)) /* left */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->xorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Left && !(state & ControlMask)) /* right */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->xorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Down) /* down */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->yorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Up) /* up */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->yorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key=='w' && rstate == ControlMask) /* close current schematic */ + { + int save_sem; + if(xctx->semaphore >= 2) return; + save_sem = xctx->semaphore; + tcleval("xschem exit"); + xctx->semaphore = save_sem; + return; + } + /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ + if(key == 'T' && rstate == 0) { + toggle_ignore(); + } + if(key=='t' && rstate == 0) /* place text */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->last_command = 0; + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_TEXT; + } + return; + } + if(key=='t' && (rstate & ControlMask)) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ + { + dbg(1, "callback(): start rect\n"); + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTRECT; + } + return; + } + if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ + { + xctx->netlist_type++; if(xctx->netlist_type==6) xctx->netlist_type=1; + set_tcl_netlist_type(); + draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ + return; + } + if((key=='s' && rstate == 0) && !cadence_compat) /* simulate (original keybind) */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + return; + } + if((key=='r' && rstate == ControlMask) && cadence_compat) /* simulate (for cadence users) */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + return; + } + if(key=='s' && rstate == ControlMask ) /* save 20121201 */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + /* check if unnamed schematic, use saveas in this case */ + if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { + saveas(NULL, SCHEMATIC); + } else { + save(1, 0); + } + return; + } + if(key=='s' && SET_MODMASK && (state & ControlMask) ) /* save as symbol */ + { + if(xctx->semaphore >= 2) return; + saveas(NULL, SYMBOL); + return; + } + if(key=='S' && rstate == ControlMask) /* save as schematic */ + { + if(xctx->semaphore >= 2) return; + saveas(NULL, SCHEMATIC); + return; + } + if(key=='e' && rstate == 0) /* descend to schematic */ + { + if(xctx->semaphore >= 2) return; + descend_schematic(0, 1, 1, 1);return; + } + if(key=='e' && EQUAL_MODMASK) /* edit schematic in new window */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + /* schematic_in_new_window(0, 1, 0); */ + tcleval("open_sub_schematic"); + xctx->semaphore = save; + return; + } + + if(key=='E' && EQUAL_MODMASK) /* edit schematic in new window - new xschem process */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + schematic_in_new_window(1, 1, 0); + xctx->semaphore = save; + return; + } + + if(key=='i' && EQUAL_MODMASK) /* edit symbol in new window */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(0); + xctx->semaphore = save; + return; + } + + if(key=='I' && EQUAL_MODMASK) /* edit symbol in new window - new xschem process */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(1); + xctx->semaphore = save; + return; + } + + + if( (key=='e' && rstate == ControlMask) || (key==XK_BackSpace)) /* back */ + { + if(xctx->semaphore >= 2) return; + go_back(1);return; + } + + if(key=='a' && rstate == 0) /* make symbol */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {do you want to make symbol view ?}"); + if(strcmp(tclresult(),"ok")==0) + { + save_schematic(xctx->sch[xctx->currsch], 0); + make_symbol(); + } + return; + } + if(key=='a' && rstate == ControlMask) /* select all */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + select_all(); + return; + } + if(key=='y' && rstate == 0) /* toggle stretching */ + { + enable_stretch = !enable_stretch; + tclsetboolvar("enable_stretch", enable_stretch); + return; + } + if(key=='x' && EQUAL_MODMASK) /* toggle draw crosshair at mouse pos */ + { + if(tclgetboolvar("draw_crosshair")) { + tclsetvar("draw_crosshair", "0"); + } else { + tclsetvar("draw_crosshair", "1"); + } + draw(); + } + if(key=='x' && rstate == ControlMask) /* cut selection into clipboard */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + delete(1/* to_push_undo */); + } + return; + } + if(key=='c' && rstate == ControlMask) /* copy selection into clipboard */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + } + return; + } + if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTARC; + } + return; + } + if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCIRCLE; + } + return; + } + if(key=='O' && rstate == ControlMask ) /* load most recent tile */ + { + tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); + return; + } + if(key=='O' && rstate == 0) /* toggle light/dark colorscheme 20171113 */ + { + int d_c; + d_c = tclgetboolvar("dark_colorscheme"); + d_c = !d_c; + tclsetboolvar("dark_colorscheme", d_c); + tclsetdoublevar("dim_value", 0.0); + tclsetdoublevar("dim_bg", 0.0); + build_colors(0.0, 0.0); + draw(); + return; + } + if(key=='v' && rstate == ControlMask) /* paste from clipboard */ + { + if(xctx->semaphore >= 2) return; + merge_file(2,".sch"); + return; + } + if(key=='Q' && rstate == ControlMask ) /* view attributes */ + { + edit_property(2);return; + } + if(key=='q' && rstate==ControlMask) /* quit xschem */ + { + if(xctx->semaphore >= 2) return; + /* must be set to zero, otherwise switch_tab/switch_win does not proceed + * and these are necessary when closing tabs/windows */ + xctx->semaphore = 0; + tcleval("quit_xschem"); + return; + } + if(key=='q' && rstate==0) /* edit attributes */ + { + if(xctx->semaphore >= 2) return; + edit_property(0); + return; + } + if(key=='q' && EQUAL_MODMASK) /* edit .sch file (DANGER!!) */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel==0 ) { + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + tcleval(str); + } + else if(xctx->sel_array[0].type==ELEMENT) { + my_snprintf(str, S(str), "edit_file {%s}", + abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); + tcleval(str); + + } + return; + } + #if defined(__unix__) && HAS_CAIRO==1 + if(key == XK_Print) { + xctx->ui_state |= GRABSCREEN; + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); + return; + } + #endif + if(key=='Q' && rstate == 0) /* edit attributes in editor */ + { + if(xctx->semaphore >= 2) return; + edit_property(1);return; + } + if(key=='i' && rstate==0) /* descend to symbol */ + { + if(xctx->semaphore >= 2) return; + descend_symbol();return; + } + if((key==XK_Insert && state == ShiftMask) || (key == 'i' && rstate == ControlMask)) /* insert sym */ + { + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + return; + } + if((key==XK_Insert) || (key == 'I' && rstate == 0) ) /* insert sym */ + { + if(xctx->semaphore >= 2) return; + start_place_symbol(); + + return; + } + if(key=='s' && SET_MODMASK) /* reload */ + { + if(xctx->semaphore >= 2) return; + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Are you sure you want to reload from disk?}"); + if(strcmp(tclresult(),"ok")==0) { + char filename[PATH_MAX]; + unselect_all(1); + remove_symbols(); + my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); + load_schematic(1, filename, 1, 1); + draw(); + } + return; + } + if(key=='o' && rstate == ControlMask) /* load */ + { + if(xctx->semaphore >= 2) return; + ask_new_file(); + return; + } + if(key=='S' && rstate == 0) /* change element order */ + { + if(xctx->semaphore >= 2) return; + change_elem_order(-1); + return; + } + if(key=='k' && EQUAL_MODMASK) /* select whole net (all attached wires/labels/pins) */ + { + select_hilight_net(); + return; + } + if(key=='k' && rstate==ControlMask) /* unhilight net */ + { + if(xctx->semaphore >= 2) return; + unhilight_net(); + return; + } + if(key=='K' && rstate == ControlMask) /* hilight net drilling thru elements */ + /* with 'propag=' prop set on pins */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=1; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + return; + } + if(key=='k' && rstate==0) /* hilight net */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=0; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + return; + } + if(key=='K' && rstate == 0) /* delete hilighted nets */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=0; + clear_all_hilights(); + /* undraw_hilight_net(1); */ + draw(); + return; + } + if(key=='g' && EQUAL_MODMASK) { /* highlight net and send to viewer */ + int tool = 0; + int exists = 0; + char *tool_name = NULL; + char str[200]; + + if(xctx->semaphore >= 2) return; + tcleval("winfo exists .graphdialog"); + if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; + else if(xctx->graph_lastsel >=0 && + xctx->rects[GRIDLAYER] > xctx->graph_lastsel && + xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { + tool = XSCHEM_GRAPH; + } + tcleval("info exists sim"); + if(tclresult()[0] == '1') exists = 1; + xctx->enable_drill = 0; + if(exists) { + if(!tool) { + tool = tclgetintvar("sim(spicewave,default)"); + my_snprintf(str, S(str), "sim(spicewave,%d,name)", tool); + my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); + dbg(1,"callback(): tool_name=%s\n", tool_name); + if(strstr(tool_name, "Gaw")) tool=GAW; + else if(strstr(tool_name, "Bespice")) tool=BESPICE; + my_free(_ALLOC_ID_, &tool_name); + } + } + if(tool) { + hilight_net(tool); + redraw_hilights(0); + } + Tcl_ResetResult(interp); + return; + } + if(key=='g' && rstate==0) /* half snap factor */ + { + set_snap(c_snap / 2.0); + change_linewidth(-1.); + draw(); + return; + } + if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ + { + my_snprintf(str, S(str), + "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", + CADSNAP, c_snap, c_snap); + tcleval(str); + return; + } + if(key=='G' && rstate == 0) /* double snap factor */ + { + set_snap(c_snap * 2.0); + change_linewidth(-1.); + draw(); + return; + } + if(key=='*' && EQUAL_MODMASK) /* svg print , 20121108 */ + { + if(xctx->semaphore >= 2) return; + svg_draw(); + return; + } + if(key=='*' && rstate == 0 ) /* postscript print */ + { + if(xctx->semaphore >= 2) return; + ps_draw(7, 0, 0); + return; + } + if(key=='*' && rstate == ControlMask) /* xpm print */ + { + if(xctx->semaphore >= 2) return; + print_image(); + return; + } + if(key=='u' && EQUAL_MODMASK) /* align to grid */ + { + if(xctx->semaphore >= 2) return; + xctx->push_undo(); + round_schematic_to_grid(c_snap); + set_modify(1); + if(tclgetboolvar("autotrim_wires")) trim_wires(); + xctx->prep_hash_inst=0; + xctx->prep_hash_wires=0; + xctx->prep_net_structs=0; + xctx->prep_hi_structs=0; + + draw(); + return; + } + if(0 && (key=='u') && rstate==ControlMask) /* testmode */ + { + static int x = 0; + + if(x == 0) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } else if(x == 1) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } + x++; + x %= 2; + return; + } + if(key=='u' && rstate==0) /* undo */ + { + if(xctx->semaphore >= 2) return; + xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ + draw(); + return; + } + if(key=='U' && rstate == 0) /* redo */ + { + if(xctx->semaphore >= 2) return; + xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ + draw(); + return; + } + if(key=='&') /* check wire connectivity */ + { + if(xctx->semaphore >= 2) return; + xctx->push_undo(); + trim_wires(); + draw(); + return; + } + if(key=='l' && rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ + if(xctx->semaphore >= 2) return; + create_sch_from_sym(); + return; + } + if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ + { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return; + if(infix_interface) { + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTLINE; + } + return; + } + if(key=='l' && EQUAL_MODMASK) { /* add pin label*/ + place_net_label(1); + return; + } + if(key >= '0' && key <= '4' && state == 0) { /* toggle pin logic level */ + if(xctx->semaphore >= 2) return; + if(key == '4') logic_set(-1, 1, NULL); + else logic_set((int)key - '0', 1, NULL); + return; + } + if(key=='L' && EQUAL_MODMASK ) { /* add pin label*/ + place_net_label(0); + return; + } + if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ + if(tclgetboolvar("orthogonal_wiring")){ + tclsetboolvar("orthogonal_wiring", 0); + xctx->manhattan_lines = 0; + } else { + tclsetboolvar("orthogonal_wiring", 1); + } + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key=='F' && rstate == 0) /* flip */ + { + if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='V' && rstate == 0) /* vertical flip */ + { + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE); + copy_objects(ROTATE); + copy_objects(FLIP); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='v' && EQUAL_MODMASK) /* vertical flip objects around their anchor points */ + { + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(FLIP|ROTATELOCAL); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + + if(key=='\\' && state==0) /* fullscreen */ + { + + dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); + toggle_fullscreen(win_path); + return; + } + if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ + { + if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='R' && rstate == 0) /* rotate */ + { + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(END,0,0,0); + } + + return; + } + if(key=='r' && EQUAL_MODMASK) /* rotate objects around their anchor points 20171208 */ + { + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + /* Move selection */ + if(key=='m' && rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + /* Move selection adding wires to moved pins */ + if(((key == 'M' && rstate == 0) || (key == 'm' && EQUAL_MODMASK)) && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + /* move selection stretching attached nets */ + if(key=='m' && rstate == ControlMask && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + + /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ + if(key=='M' && rstate == ControlMask && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + + if(key=='c' && EQUAL_MODMASK && /* duplicate selection */ + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(xctx->semaphore >= 2) return; + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + return; + } + + if(key=='c' && rstate==0 && /* duplicate selection */ + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + return; + } + if(key=='n' && rstate == ControlMask) /* clear schematic */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem clear SCHEMATIC"); + return; + } + if(key=='N' && rstate == ControlMask ) /* clear symbol */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem clear SYMBOL"); + return; + } + if(key=='n' && rstate==0) /* hierarchical netlist */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem netlist -erc"); + return; + } + if(key=='N' && rstate == 0) /* current level only netlist */ + { + int err = 0; + yyparse_error = 0; + if(xctx->semaphore >= 2) return; + unselect_all(1); + if( set_netlist_dir(0, NULL) ) { + dbg(1, "callback(): -------------\n"); + if(xctx->netlist_type == CAD_SPICE_NETLIST) + err = global_spice_netlist(0, 1); + else if(xctx->netlist_type == CAD_VHDL_NETLIST) + err = global_vhdl_netlist(0, 1); + else if(xctx->netlist_type == CAD_VERILOG_NETLIST) + err = global_verilog_netlist(0, 1); + else if(xctx->netlist_type == CAD_TEDAX_NETLIST) + err = global_tedax_netlist(0, 1); + else + tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " + "-message {Please Set netlisting mode (Options menu)}"); + dbg(1, "callback(): -------------\n"); + } + else { + if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); + else dbg(0, "Can not write into the netlist directory. Please check"); + err = 1; + } + if(err) { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); + } + } else { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); + } + } + + return; + } + if(key=='A' && rstate == ControlMask) /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='A' && rstate == 0) /* toggle show netlist */ + { + int net_s; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + net_s = tclgetboolvar("netlist_show"); + net_s = !net_s; + if(net_s) { + tcleval("alert_ { enabling show netlist window} {}"); + tclsetvar("netlist_show","1"); + } + else { + tcleval("alert_ { disabling show netlist window } {}"); + tclsetvar("netlist_show","0"); + } + return; + } + if(key=='>') { + if(xctx->semaphore >= 2) return; + if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; + draw(); + return; + } + if(key=='<') { + if(xctx->semaphore >= 2) return; + if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; + draw(); + return; + } + if(key==':') /* toggle flat netlist (only spice) */ + { + if(!tclgetboolvar("flat_netlist")) { + tcleval("alert_ { enabling flat netlist} {}"); + tclsetvar("flat_netlist","1"); + } + else { + tcleval("alert_ { set hierarchical netlist } {}"); + tclsetvar("flat_netlist","0"); + } + return; + } + if(key=='B' && rstate == ControlMask) /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='B' && rstate == 0) /* edit schematic header/license */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("update_schematic_header"); + } + if(key=='b' && rstate==0) /* merge schematic */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ + return; + } + if(key=='b' && EQUAL_MODMASK) /* hide/show instance details */ + { + if(xctx->semaphore >= 2) return; + xctx->hide_symbols++; + if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; + tclsetintvar("hide_symbols", xctx->hide_symbols); + draw(); + return; + } + if(key=='d' && rstate == 0) /* unselect object under the mouse */ + { + if(infix_interface) { + unselect_at_mouse_pos(mx, my); + } else { + xctx->ui_state |= (MENUSTART | DESEL_CLICK); + xctx->ui_state2 = MENUSTARTDESEL; + } + return; + } + if(key=='D' && rstate == 0) /* unselect by area */ + { + if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { + if(infix_interface) { + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTDESEL; + } + } + return; + } + if(key=='d' && rstate == ControlMask) /* delete files */ + { + if(xctx->semaphore >= 2) return; + delete_files(); + return; + } + if(key=='x' && rstate == 0 ) /* new cad session */ + { + new_xschem_process(NULL ,0); + return; + } + if((key=='#') && !(state & ControlMask) ) + { + check_unique_names(0); + return; + } + if((key=='#') && (state & ControlMask) ) + { + check_unique_names(1); + return; + } + if( 0 && (key==';') && (state & ControlMask) ) /* testmode */ + { + return; + } + if(0 && key=='~' && (state & ControlMask)) { /* testmode */ + return; + } + if(0 && key=='|' && !(state & ControlMask)) { /* testmode */ + return; + } + if(0 && key=='|' && (state & ControlMask)) /* testmode */ + { + return; + } + + if(key=='f' && rstate == ControlMask) /* search */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("property_search"); + return; + } + if(key=='F' && rstate == ControlMask ) /* full zoom selection */ + { + if(xctx->ui_state == SELECTION) { + zoom_full(1, 1, 3, 0.97); + } + return; + } + if(key=='f' && rstate == 0 ) /* full zoom */ + { + int flags = 1; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(tclgetboolvar("zoom_full_center")) flags |= 2; + zoom_full(1, 0, flags, 0.97); + return; + } + if((key=='z' && rstate==ControlMask)) /* zoom out */ + { + view_unzoom(0.0); + return; + } + if(key=='!' && !(state & ControlMask)) + { + if(xctx->semaphore >= 2) return; + break_wires_at_pins(0); + return; + } + if(key=='!' && (state & ControlMask)) + { + if(xctx->semaphore >= 2) return; + break_wires_at_pins(1); + return; + } + return; +} + +static void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, + double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux) +{ + dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + /* terminate a schematic pan action */ + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + return; + } + + /* select instance and connected nets stopping at wire junctions */ + if(button == Button3 && state == ControlMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(1); + } + + /* break wire at mouse coordinates, move break point to nearest grid point */ + else if(button == Button3 && EQUAL_MODMASK && !(state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); + } + /* break wire at mouse coordinates */ + else if(button == Button3 && EQUAL_MODMASK && (state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); + } + /* select instance and connected nets NOT stopping at wire junctions */ + else if(button == Button3 && state == ShiftMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(0); + } + /* moved to Button3 release */ + /* + * else if(button == Button3 && state == 0 && xctx->semaphore <2) { + * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + * } + */ + + /* zoom rectangle by right clicking and drag */ + else if(button == Button3 && state == 0 && xctx->semaphore < 2) { + zoom_rectangle(START);return; + } + + /* Mouse wheel events */ + else if(handle_mouse_wheel(event, mx, my, key, button, aux, state)) return; + + /* terminate wire placement in snap mode */ + else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { + snapped_wire(c_snap); + } + /* Alt - Button1 click to unselect */ + else if(button==Button1 && (SET_MODMASK) ) { + unselect_at_mouse_pos(mx, my); + } + + /* Middle button press (Button2) will pan the schematic. */ + else if(button==Button2 && (state == 0)) { + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + + /* button1 click to select another instance while edit prop dialog open */ + else if(button==Button1 && xctx->semaphore >= 2) { + if(tcleval("winfo exists .dialog.textinput")[0] == '1') { /* proc text_line */ + tcleval(".dialog.f1.b1 invoke"); + return; + } else if(tcleval("winfo exists .dialog.txt")[0] == '1') { /* proc enter_text */ + tcleval(".dialog.buttons.ok invoke"); + return; + } else if(state==0 && tclgetvar("edit_symbol_prop_new_sel")[0]) { + tcleval("set edit_symbol_prop_new_sel 1; .dialog.f1.b1 invoke"); /* invoke 'OK' of edit prop dialog */ + } else if((state & ShiftMask) && tclgetvar("edit_symbol_prop_new_sel")[0]) { + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + tclsetvar("preserve_unchanged_attrs", "1"); + rebuild_selected_array(); + } + } + + /* Handle the remaining Button1Press events */ + else if(button==Button1) /* MOD button is not pressed here. Processed above */ + { + xctx->onetime = 0; + xctx->mouse_moved = 0; + xctx->drag_elements = 0; + + /* start another wire or line in persistent mode */ + if(tclgetboolvar("persistent_command") && xctx->last_command) { + if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); + if(xctx->last_command == STARTWIRE){ + if(tclgetboolvar("snap_cursor") + && (xctx->prev_snapx == xctx->mousex_snap + && xctx->prev_snapy == xctx->mousey_snap) + && (xctx->ui_state & STARTWIRE) + && xctx->closest_pin_found){ + new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &= ~STARTWIRE; + } + else + start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + /* handle all object insertions started from Tools/Edit menu */ + if(check_menu_start_commands(c_snap, mx, my)) return; + + /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ + if(end_place_move_copy_zoom()) return; + + /* Button1Press to select objects */ + if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { + Selected sel; + int already_selected = 0; + int prev_last_sel = xctx->lastsel; + int no_shift_no_ctrl = !(state & (ShiftMask | ControlMask)); + + xctx->shape_point_selected = 0; + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + + #if 0 /* disabled */ + /* Clicking and dragging from a **selected** instance pin will start a new wire + * if no other elements are selected */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) { + if(add_wire_from_wire(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + if(add_wire_from_inst(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + } + #endif + + /* In *NON* intuitive interface a button1 press with no modifiers will + * first unselect everything... + * For intuitive interface unselection see below... */ + if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); + + /* find closest object. Use snap coordinates if full crosshair is enabled + * since the mouse pointer is obscured and crosshair is snapped to grid points */ + if(draw_xhair) { + sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); + } else { + sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); + } + dbg(1, "sel.type=%d\n", sel.type); + /* determine if closest object was already selected when button1 was pressed */ + switch(sel.type) { + case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; + case xTEXT: if(xctx->text[sel.n].sel) already_selected = 1; break; + case LINE: if(xctx->line[sel.col][sel.n].sel) already_selected = 1; break; + case POLYGON: if(xctx->poly[sel.col][sel.n].sel) already_selected = 1; break; + case xRECT: if(xctx->rect[sel.col][sel.n].sel) already_selected = 1; break; + case ARC: if(xctx->arc[sel.col][sel.n].sel) already_selected = 1; break; + case ELEMENT: if(xctx->inst[sel.n].sel) already_selected = 1; break; + default: break; + } /*end switch */ + + /* Clicking and drag on an instance pin -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_inst(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* Clicking and drag on a wire end -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_wire(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* In intuitive interface a button1 press with no modifiers will + * unselect everything... we do it here */ + if(xctx->intuitive_interface && !already_selected && no_shift_no_ctrl ) unselect_all(1); + + /* select the object under the mouse and rebuild the selected array */ + if(!already_selected) select_object(xctx->mousex, xctx->mousey, SELECTED, 0, &sel); + rebuild_selected_array(); + dbg(1, "Button1Press to select objects, lastsel = %d\n", xctx->lastsel); + + /* if clicking on some object endpoints or vertices set shape_point_selected + * this information will be used in Motion events to draw the stretched vertices */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { + if(edit_polygon_point(state)) return; /* sets xctx->shape_point_selected */ + } + if(xctx->lastsel == 1 && xctx->intuitive_interface) { + int cond = already_selected; + + if(cond && xctx->sel_array[0].type==xRECT) { + if(edit_rect_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==LINE) { + if(edit_line_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==WIRE) { + if(edit_wire_point(state)) return; /* sets xctx->shape_point_selected */ + } + } + dbg(1, "shape_point_selected=%d, lastsel=%d\n", xctx->shape_point_selected, xctx->lastsel); + + /* intuitive interface: directly drag elements */ + if(sel.type && xctx->intuitive_interface && xctx->lastsel >= 1 && + !xctx->shape_point_selected) { + /* enable_stretch (from TCL variable) reverses command if enabled: + * - move --> stretch move + * - stretch move (with ctrl key) --> move + */ + int stretch = (state & ControlMask ? 1 : 0) ^ enable_stretch; + xctx->drag_elements = 1; + /* select attached nets depending on ControlMask and enable_stretch */ + if(stretch) { + select_attached_nets(); /* stretch nets that land on selected instance pins */ + } + /* if dragging instances with stretch enabled and Shift down add wires to pins + * attached to something */ + if((state & ShiftMask) && stretch) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + move_objects(START,0,0,0); + } + /* dragging away an object with Shift pressed is a copy (duplicate object) */ + else if(state & ShiftMask) copy_objects(START); + /* else it is a normal move */ + else move_objects(START,0,0,0); + } + + if(tclgetboolvar("auto_hilight") && !xctx->shape_point_selected) { + if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { + if(!prev_last_sel) { + redraw_hilights(1); /* 1: clear all hilights, then draw */ + } + } + hilight_net(0); + if(xctx->lastsel) { + redraw_hilights(0); + } + } + return; + } + } /* button==Button1 */ + return; +} + +static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, + int aux, double c_snap, int enable_stretch, int draw_xhair, int snap_cursor, int wire_draw_active, char *str) +{ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->ui_state &= ~DESEL_CLICK; + dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); + /* bring up context menu if no pending operation */ + if(state == Button3Mask && xctx->semaphore <2) { + if(!end_place_move_copy_zoom()) { + context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + } + } + + /* launcher, no intuitive interface */ + if(!xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* launcher, intuitive_interface, only if no movement has been done */ + else if(xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && (xctx->ui_state & STARTMOVE) && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + move_objects(ABORT, 0, 0.0, 0.0); + unselect_all(1); + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + rebuild_selected_array(); + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ + /*else if(state == Button1Mask && xctx->intuitive_interface + * && (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) {*/ + /* if(end_place_move_copy_zoom()) break;*/ + /*}*/ + + /* end intuitive_interface copy or move */ + if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { + copy_objects(END); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + else if(xctx->ui_state & STARTMOVE && xctx->drag_elements) { + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + + /* if a polygon/bezier/rectangle control point was clicked, end point move operation + * and set polygon state back to SELECTED from SELECTED1 */ + else if((xctx->ui_state & (STARTMOVE | SELECTION)) && xctx->shape_point_selected) { + end_shape_point_edit(c_snap); + } + + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + /* xctx->mx_save = mx; xctx->my_save = my; */ + /* xctx->mx_double_save=xctx->mousex_snap; */ + /* xctx->my_double_save=xctx->mousey_snap; */ + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + dbg(1, "callback(): ButtonRelease ui_state=%d state=%d\n",xctx->ui_state,state); + if(xctx->semaphore >= 2) return; + if(xctx->ui_state & STARTSELECT) { + if(state & ControlMask) { + select_rect(!enable_stretch, END,-1); + } else { + /* Button1 release: end of rectangle select */ + if(!(state & (Button4Mask|Button5Mask) ) ) { + select_rect(enable_stretch, END,-1); + } + } + xctx->ui_state &= ~DESEL_AREA; + rebuild_selected_array(); + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", + xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); + statusmsg(str,1); + } + + /* clear start from menu flag or infix_interface=0 start commands */ + if(xctx->ui_state & MENUSTART) { + xctx->ui_state &= ~MENUSTART; + return; + } + if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ + if(snap_cursor && wire_draw_active) draw_snap_cursor(3); + return; +} + +static void handle_double_click(int event, int state, KeySym key, int button, + int mx, int my, int aux, int cadence_compat) +{ + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } else { + if(xctx->semaphore >= 2) return; + dbg(1, "callback(): DoubleClick ui_state=%d state=%d\n",xctx->ui_state,state); + if(button==Button1) { + Selected sel; + if(!xctx->lastsel && xctx->ui_state == 0) { + /* Following 5 lines do again a selection overriding lock, + * so locked instance attrs can be edited */ + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 1, NULL); + if(sel.type) { + xctx->ui_state = SELECTION; + rebuild_selected_array(); + } + } + if(xctx->ui_state == 0 || xctx->ui_state == SELECTION) { + edit_property(0); + } else { + if(xctx->ui_state & STARTWIRE) { + redraw_w_a_l_r_p_z_rubbers(1); + start_wire(mx, my); + xctx->ui_state &= ~STARTWIRE; + } + if(xctx->ui_state & STARTLINE) { + xctx->ui_state &= ~STARTLINE; + } + if( (xctx->ui_state & STARTPOLYGON) && (state ==0 ) ) { + new_polygon(SET, xctx->mousex_snap, xctx->mousey_snap); + } + } + } + } +} + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -2436,7 +4481,6 @@ int callback(const char *win_path, int event, int mx, int my, KeySym key, int button, int aux, int state) { char str[PATH_MAX + 100]; - struct stat buf; int redraw_only; double c_snap; #ifndef __unix__ @@ -2577,33 +4621,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case EnterNotify: - dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); - xctx->mouse_inside = 1; - if(draw_xhair) { - if(crosshair_size == 0) { - tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); - } - } else - tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); - /* xschem window *sending* selected objects - when the pointer comes back in abort copy operation since it has been done - in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ - if(stat(sel_file, &buf) && (xctx->ui_state & STARTCOPY) ) - { - copy_objects(ABORT); - unselect_all(1); - } - /* xschem window *receiving* selected objects selection cleared --> abort */ - else if(xctx->paste_from == 1 && stat(sel_file, &buf) && (xctx->ui_state & STARTMERGE)) { - abort_operation(); - } - /*xschem window *receiving* selected objects - * no selected objects and selection file exists --> start merge */ - else if(xctx->lastsel == 0 && !stat(sel_file, &buf)) { - xctx->mousex_snap = 490; - xctx->mousey_snap = -340; - merge_file(1, ".sch"); - } + handle_enter_notify(draw_xhair, crosshair_size); break; case Expose: @@ -2635,2003 +4653,34 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case MotionNotify: - if( waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(draw_xhair) { - draw_crosshair(1, state); /* when moving mouse: first action is delete crosshair, will be drawn later */ - } - if(snap_cursor && wire_draw_active) draw_snap_cursor(1); - /* pan schematic */ - if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); - - if(xctx->semaphore >= 2) { - if(draw_xhair) { - draw_crosshair(2, state); /* locked UI: draw new crosshair and break out */ - } - if(snap_cursor && wire_draw_active) draw_snap_cursor(2); - break; - } - - /* update status bar messages */ - if(xctx->ui_state) { - if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", - xctx->mousex_snap, xctx->mousey_snap, - xctx->lastsel , - xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save - ); - statusmsg(str,1); - } - } - - /* determine direction of a rectangle selection (or unselection with ALT key) */ - if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { - /* Unselect by area : determine direction */ - if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { - if(mx >= xctx->mx_save) xctx->nl_dir = 0; - else xctx->nl_dir = 1; - select_rect(enable_stretch, RUBBER,0); - /* select by area : determine direction */ - } else if(state & Button1Mask) { - if(mx >= xctx->mx_save) xctx->nl_dir = 0; - else xctx->nl_dir = 1; - select_rect(enable_stretch, RUBBER,1); - } - } - /* draw objects being moved */ - if(xctx->ui_state & STARTMOVE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - move_objects(RUBBER,0,0,0); - } - - /* draw objects being copied */ - if(xctx->ui_state & STARTCOPY) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - copy_objects(RUBBER); - } - - /* draw moving objects being inserted, wires, arcs, lines, rectangles, polygons or zoom box */ - redraw_w_a_l_r_p_z_rubbers(0); - - /* start of a mouse area select. Button1 pressed. No shift pressed - * Do not start an area select if user is dragging a polygon/bezier point */ - if(!(xctx->ui_state & STARTPOLYGON) && (state&Button1Mask) && !(xctx->ui_state & STARTWIRE) && - !(xctx->ui_state & STARTPAN) && !(SET_MODMASK) && !xctx->shape_point_selected && - !(state & ShiftMask) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) - { - if(mx != xctx->mx_save || my != xctx->my_save) { - xctx->mouse_moved = 1; - if(!xctx->drag_elements) { - if( !(xctx->ui_state & STARTSELECT)) { - select_rect(enable_stretch, START,1); - xctx->onetime=1; - } - if(abs(mx-xctx->mx_save) > 8 || - abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ - if(xctx->onetime) { - unselect_all(1); /* 20171026 avoid multiple calls of unselect_all() */ - xctx->onetime=0; - } - xctx->ui_state|=STARTSELECT; /* set it again cause unselect_all(1) clears it... */ - } - } - } - } - /* Unselect by area */ - if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && - !(state & ShiftMask) && - !(xctx->ui_state & STARTPAN) && - !xctx->shape_point_selected && - !(xctx->ui_state & STARTSELECT) && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ - select_rect(enable_stretch, START,0); - } - /* Select by area. Shift pressed */ - else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !xctx->shape_point_selected && - !xctx->drag_elements && !(xctx->ui_state & STARTPAN) ) { - if(mx != xctx->mx_save || my != xctx->my_save) { - if( !(xctx->ui_state & STARTSELECT)) { - select_rect(enable_stretch, START,1); - } - if(abs(mx-xctx->mx_save) > 8 || - abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ - if(!xctx->already_selected) { - select_object(X_TO_XSCHEM(xctx->mx_save), - Y_TO_XSCHEM(xctx->my_save), 0, 0, NULL); /* remove near obj if dragging */ - } - rebuild_selected_array(); - } - } - } - if(draw_xhair) { - draw_crosshair(2, state); /* what = 2(draw) */ - } - if(snap_cursor && wire_draw_active) draw_snap_cursor(2); + handle_motion_notify(event, key, state, rstate, button, mx, my, + aux, draw_xhair, enable_stretch, + snap_cursor, wire_draw_active, str); break; case KeyRelease: break; case KeyPress: - if(key==' ') { - if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ - new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - - } else if(xctx->ui_state & STARTLINE) { - new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } else { - if(xctx->semaphore<2) { - rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ - } - pan(START, mx, my); - xctx->ui_state |= STARTPAN; - } - break; - } - if(key == '_' ) /* toggle change line width */ - { - if(!tclgetboolvar("change_lw")) { - tcleval("alert_ { enabling change line width} {}"); - tclsetvar("change_lw","1"); - } - else { - tcleval("alert_ { disabling change line width} {}"); - tclsetvar("change_lw","0"); - } + handle_key_press(event, key, state, rstate, mx, my, button, aux, + infix_interface, enable_stretch, win_path, c_snap, + cadence_compat, wire_draw_active, snap_cursor, str); break; - } - if(key == 'b' && rstate==ControlMask) /* toggle show text in symbol */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->sym_txt =!xctx->sym_txt; - if(xctx->sym_txt) { - /* tcleval("alert_ { enabling text in symbol} {}"); */ - tclsetvar("sym_txt","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling text in symbol} {}"); */ - tclsetvar("sym_txt","0"); - draw(); - } - break; - } - if(key == '%' ) /* toggle draw grid */ - { - int dr_gr; - dr_gr = tclgetboolvar("draw_grid"); - dr_gr =!dr_gr; - if(dr_gr) { - /* tcleval("alert_ { enabling draw grid} {}"); */ - tclsetvar("draw_grid","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling draw grid} {}"); */ - tclsetvar("draw_grid","0"); - draw(); - } - break; - } - if(key == 'j' && rstate==0 ) /* print list of highlight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(1); - break; - } - if(key == 'j' && rstate==ControlMask) /* create ipins from highlight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(0); - break; - } - if(key == 'j' && EQUAL_MODMASK) /* create labels without i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(4); - break; - } - if(key == 'J' && SET_MODMASK ) /* create labels with i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(2); - break; - } - if(key == 'h' && rstate==ControlMask ) /* go to http link */ - { - int savesem = xctx->semaphore; - xctx->semaphore = 0; - launcher(); - xctx->semaphore = savesem; - break; - } - if(key == 'h' && EQUAL_MODMASK) /* create symbol pins from schematic pins 20171208 */ - { - tcleval("schpins_to_sympins"); - break; - } - if(key == 'h' && rstate == 0) { - /* horizontally constrained drag 20171023 */ - if ( xctx->constr_mv == 1 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 1" ); - xctx->constr_mv = 1; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - if(key=='H' && rstate == 0) { /* attach labels to selected instances */ - attach_labels_to_inst(1); - break; - } - if (key == 'H' && rstate == ControlMask) { /* create schematic and symbol from selected components */ - make_schematic_symbol_from_sel(); - break; - } - if(key == 'v' && rstate==0) { - /* vertically constrained drag 20171023 */ - if ( xctx->constr_mv == 2 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 2" ); - xctx->constr_mv = 2; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - if(key == 'j' && SET_MODMASK && (state & ControlMask) ) /* print list of highlight net with label expansion */ - { - print_hilight_net(3); - break; - } - if(key == 'J' && rstate == 0) { - create_plot_cmd(); - break; - } - if(key == '$' && rstate == 0 ) /* toggle pixmap saving */ - { - xctx->draw_pixmap =!xctx->draw_pixmap; - if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); - else tcleval("alert_ { disabling draw pixmap} {}"); - break; - } - if(key == '$' && (state &ControlMask) ) /* toggle window drawing */ - { - xctx->draw_window =!xctx->draw_window; - if(xctx->draw_window) { - tcleval("alert_ { enabling draw window} {}"); - tclsetvar("draw_window","1"); - } else { - tcleval("alert_ { disabling draw window} {}"); - tclsetvar("draw_window","0"); - } - break; - } - if(key == '=' && (state &ControlMask)) /* toggle fill rectangles */ - { - int x; - xctx->fill_pattern++; - if(xctx->fill_pattern==3) xctx->fill_pattern=0; - - if(xctx->fill_pattern==1) { - tcleval("alert_ { Stippled pattern fill} {}"); - for(x=0;xfill_type[x]==1) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); - else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); - } - } - else if(xctx->fill_pattern==2) { - tcleval("alert_ { solid pattern fill} {}"); - for(x=0;xgcstipple[x],FillSolid); - } - else { - tcleval("alert_ { No pattern fill} {}"); - for(x=0;xgcstipple[x],FillStippled); - } - - draw(); - break; - } - if(key == '+' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - break; - } - - if(key == '-' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); - if(xctx->lw < 0.0) xctx->lw = 0.0; - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - break; - } - if(key == 'X' && rstate == 0) /* highlight discrepanciens between selected instance pin and net names */ - { - hilight_net_pin_mismatches(); - break; - } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */ - if(xctx->semaphore >= 2) break; - snapped_wire(c_snap); - break; - } - if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ - if(xctx->semaphore >= 2) break; - snapped_wire(c_snap); - break; - } - if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) break; - if(infix_interface) { - start_wire(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTWIRE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTWIRE; - if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ - new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); - break; - } - if(key == XK_Escape) /* abort & redraw */ - { - if(xctx->semaphore < 2) { - abort_operation(); - } - /* stuff that can be done reentrantly ... */ - tclsetvar("tclstop", "1"); /* stop simulation if any running */ - if(xctx->ui_state2 & MENUSTARTWIRE) { - xctx->ui_state2 &= ~MENUSTARTWIRE; - } - if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { - xctx->last_command &= ~STARTWIRE; - if(snap_cursor) draw_snap_cursor(1); - } - break; - } - if(key=='z' && rstate == 0 && - !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) /* zoom box */ - { - dbg(1, "callback(): zoom_rectangle call\n"); - zoom_rectangle(START);break; - } - if(key=='Z' && rstate == 0) /* zoom in */ - { - view_zoom(0.0); break; - } - if(key=='z' && EQUAL_MODMASK) /* toggle snap-cursor option */ - { - if(tclgetboolvar("snap_cursor")) { - tclsetvar("snap_cursor", "0"); - draw_snap_cursor(1); - xctx->closest_pin_found = 0; - xctx->prev_snapx = 0.0; - xctx->prev_snapy = 0.0; - } else { - tclsetvar("snap_cursor", "1"); - if(wire_draw_active) draw_snap_cursor(3); - } - } - if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ - { - xctx->push_undo(); - unselect_all(1); - storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, - xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); - xctx->need_reb_sel_arr=1; - rebuild_selected_array(); - move_objects(START,0,0,0); - xctx->ui_state |= START_SYMPIN; - break; - } - if(key=='p' && !(xctx->ui_state & STARTPOLYGON) && rstate==0) /* start polygon */ - { - if(xctx->semaphore >= 2) break; - dbg(1, "callback(): start polygon\n"); - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTPOLYGON; - } - break; - } - if(key=='P' && rstate == 0) /* pan, other way to. */ - { - xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; - xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key=='5' && rstate == 0) { /* 20110112 display only probes */ - xctx->only_probes = !xctx->only_probes; - tclsetboolvar("only_probes", xctx->only_probes); - toggle_only_probes(); - break; - } /* /20110112 */ - if(key<='9' && key >='0' && state==ControlMask) /* choose layer */ - { - char n[30]; - xctx->rectcolor = (int)key - '0'+4; - my_snprintf(n, S(n), "%d", xctx->rectcolor); - tclvareval("xschem set rectcolor ", n, NULL); - - if(has_x) { - if(!strcmp(win_path, ".drw")) { - tclvareval("reconfigure_layers_button {}", NULL); - } else { - tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); - } - } - dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); - break; - } - if(key==XK_Delete && (xctx->ui_state & SELECTION) ) /* delete selection */ - { - if(xctx->semaphore >= 2) break; - delete(1/* to_push_undo */);break; - } - if(key==XK_Right && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->semaphore = 0; - tcleval("next_tab"); - xctx->semaphore = save; - break; - } - if(key==XK_Left && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->semaphore = 0; - tcleval("prev_tab"); - xctx->semaphore = save; - break; - } - if(key==XK_Right && !(state & ControlMask)) /* left */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->xorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Left && !(state & ControlMask)) /* right */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->xorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Down) /* down */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->yorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Up) /* up */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->yorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key=='w' && rstate == ControlMask) /* close current schematic */ - { - int save_sem; - if(xctx->semaphore >= 2) break; - save_sem = xctx->semaphore; - tcleval("xschem exit"); - xctx->semaphore = save_sem; - break; - } - /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ - if(key == 'T' && rstate == 0) { - toggle_ignore(); - } - if(key=='t' && rstate == 0) /* place text */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->last_command = 0; - xctx->mx_double_save = xctx->mousex_snap; - xctx->my_double_save = xctx->mousey_snap; - if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ - xctx->mousey_snap = xctx->my_double_save; - xctx->mousex_snap = xctx->mx_double_save; - move_objects(START,0,0,0); - xctx->ui_state |= PLACE_TEXT; - } - break; - } - if(key=='t' && (rstate & ControlMask)) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ - { - dbg(1, "callback(): start rect\n"); - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTRECT; - } - break; - } - if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ - { - xctx->netlist_type++; if(xctx->netlist_type==6) xctx->netlist_type=1; - set_tcl_netlist_type(); - draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ - break; - } - if((key=='s' && rstate == 0) && !cadence_compat) /* simulate (original keybind) */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Run circuit simulation?}"); - if(strcmp(tclresult(),"ok")==0) { - tcleval("[xschem get top_path].menubar invoke Simulate"); - } - break; - } - if((key=='r' && rstate == ControlMask) && cadence_compat) /* simulate (for cadence users) */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Run circuit simulation?}"); - if(strcmp(tclresult(),"ok")==0) { - tcleval("[xschem get top_path].menubar invoke Simulate"); - } - break; - } - if(key=='s' && rstate == ControlMask ) /* save 20121201 */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - /* check if unnamed schematic, use saveas in this case */ - if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { - saveas(NULL, SCHEMATIC); - } else { - save(1, 0); - } - break; - } - if(key=='s' && SET_MODMASK && (state & ControlMask) ) /* save as symbol */ - { - if(xctx->semaphore >= 2) break; - saveas(NULL, SYMBOL); - break; - } - if(key=='S' && rstate == ControlMask) /* save as schematic */ - { - if(xctx->semaphore >= 2) break; - saveas(NULL, SCHEMATIC); - break; - } - if(key=='e' && rstate == 0) /* descend to schematic */ - { - if(xctx->semaphore >= 2) break; - descend_schematic(0, 1, 1, 1);break; - } - if(key=='e' && EQUAL_MODMASK) /* edit schematic in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - /* schematic_in_new_window(0, 1, 0); */ - tcleval("open_sub_schematic"); - xctx->semaphore = save; - break; - } - - if(key=='E' && EQUAL_MODMASK) /* edit schematic in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - schematic_in_new_window(1, 1, 0); - xctx->semaphore = save; - break; - } - - if(key=='i' && EQUAL_MODMASK) /* edit symbol in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(0); - xctx->semaphore = save; - break; - } - - if(key=='I' && EQUAL_MODMASK) /* edit symbol in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(1); - xctx->semaphore = save; - break; - } - - - if( (key=='e' && rstate == ControlMask) || (key==XK_BackSpace)) /* back */ - { - if(xctx->semaphore >= 2) break; - go_back(1);break; - } - - if(key=='a' && rstate == 0) /* make symbol */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {do you want to make symbol view ?}"); - if(strcmp(tclresult(),"ok")==0) - { - save_schematic(xctx->sch[xctx->currsch], 0); - make_symbol(); - } - break; - } - if(key=='a' && rstate == ControlMask) /* select all */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - select_all(); - break; - } - if(key=='y' && rstate == 0) /* toggle stretching */ - { - enable_stretch = !enable_stretch; - tclsetboolvar("enable_stretch", enable_stretch); - break; - } - if(key=='x' && EQUAL_MODMASK) /* toggle draw crosshair at mouse pos */ - { - if(tclgetboolvar("draw_crosshair")) { - tclsetvar("draw_crosshair", "0"); - } else { - tclsetvar("draw_crosshair", "1"); - } - draw(); - } - if(key=='x' && rstate == ControlMask) /* cut selection into clipboard */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - delete(1/* to_push_undo */); - } - break; - } - if(key=='c' && rstate == ControlMask) /* copy selection into clipboard */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - } - break; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTARC; - } - break; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCIRCLE; - } - break; - } - if(key=='O' && rstate == ControlMask ) /* load most recent tile */ - { - tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); - break; - } - if(key=='O' && rstate == 0) /* toggle light/dark colorscheme 20171113 */ - { - int d_c; - d_c = tclgetboolvar("dark_colorscheme"); - d_c = !d_c; - tclsetboolvar("dark_colorscheme", d_c); - tclsetdoublevar("dim_value", 0.0); - tclsetdoublevar("dim_bg", 0.0); - build_colors(0.0, 0.0); - draw(); - break; - } - if(key=='v' && rstate == ControlMask) /* paste from clipboard */ - { - if(xctx->semaphore >= 2) break; - merge_file(2,".sch"); - break; - } - if(key=='Q' && rstate == ControlMask ) /* view attributes */ - { - edit_property(2);break; - } - if(key=='q' && rstate==ControlMask) /* quit xschem */ - { - if(xctx->semaphore >= 2) break; - /* must be set to zero, otherwise switch_tab/switch_win does not proceed - * and these are necessary when closing tabs/windows */ - xctx->semaphore = 0; - tcleval("quit_xschem"); - break; - } - if(key=='q' && rstate==0) /* edit attributes */ - { - if(xctx->semaphore >= 2) break; - edit_property(0); - break; - } - if(key=='q' && EQUAL_MODMASK) /* edit .sch file (DANGER!!) */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel==0 ) { - my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); - tcleval(str); - } - else if(xctx->sel_array[0].type==ELEMENT) { - my_snprintf(str, S(str), "edit_file {%s}", - abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); - tcleval(str); - - } - break; - } - #if defined(__unix__) && HAS_CAIRO==1 - if(key == XK_Print) { - xctx->ui_state |= GRABSCREEN; - tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); - tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); - break; - } - #endif - if(key=='Q' && rstate == 0) /* edit attributes in editor */ - { - if(xctx->semaphore >= 2) break; - edit_property(1);break; - } - if(key=='i' && rstate==0) /* descend to symbol */ - { - if(xctx->semaphore >= 2) break; - descend_symbol();break; - } - if((key==XK_Insert && state == ShiftMask) || (key == 'i' && rstate == ControlMask)) /* insert sym */ - { - tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); - break; - } - if((key==XK_Insert) || (key == 'I' && rstate == 0) ) /* insert sym */ - { - if(xctx->semaphore >= 2) break; - start_place_symbol(); - - break; - } - if(key=='s' && SET_MODMASK) /* reload */ - { - if(xctx->semaphore >= 2) break; - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Are you sure you want to reload from disk?}"); - if(strcmp(tclresult(),"ok")==0) { - char filename[PATH_MAX]; - unselect_all(1); - remove_symbols(); - my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); - load_schematic(1, filename, 1, 1); - draw(); - } - break; - } - if(key=='o' && rstate == ControlMask) /* load */ - { - if(xctx->semaphore >= 2) break; - ask_new_file(); - break; - } - if(key=='S' && rstate == 0) /* change element order */ - { - if(xctx->semaphore >= 2) break; - change_elem_order(-1); - break; - } - if(key=='k' && EQUAL_MODMASK) /* select whole net (all attached wires/labels/pins) */ - { - select_hilight_net(); - break; - } - if(key=='k' && rstate==ControlMask) /* unhilight net */ - { - if(xctx->semaphore >= 2) break; - unhilight_net(); - break; - } - if(key=='K' && rstate == ControlMask) /* hilight net drilling thru elements */ - /* with 'propag=' prop set on pins */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=1; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - break; - } - if(key=='k' && rstate==0) /* hilight net */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=0; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - break; - } - if(key=='K' && rstate == 0) /* delete hilighted nets */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=0; - clear_all_hilights(); - /* undraw_hilight_net(1); */ - draw(); - break; - } - if(key=='g' && EQUAL_MODMASK) { /* highlight net and send to viewer */ - int tool = 0; - int exists = 0; - char *tool_name = NULL; - char str[200]; - - if(xctx->semaphore >= 2) break; - tcleval("winfo exists .graphdialog"); - if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; - else if(xctx->graph_lastsel >=0 && - xctx->rects[GRIDLAYER] > xctx->graph_lastsel && - xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { - tool = XSCHEM_GRAPH; - } - tcleval("info exists sim"); - if(tclresult()[0] == '1') exists = 1; - xctx->enable_drill = 0; - if(exists) { - if(!tool) { - tool = tclgetintvar("sim(spicewave,default)"); - my_snprintf(str, S(str), "sim(spicewave,%d,name)", tool); - my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); - dbg(1,"callback(): tool_name=%s\n", tool_name); - if(strstr(tool_name, "Gaw")) tool=GAW; - else if(strstr(tool_name, "Bespice")) tool=BESPICE; - my_free(_ALLOC_ID_, &tool_name); - } - } - if(tool) { - hilight_net(tool); - redraw_hilights(0); - } - Tcl_ResetResult(interp); - break; - } - if(key=='g' && rstate==0) /* half snap factor */ - { - set_snap(c_snap / 2.0); - change_linewidth(-1.); - draw(); - break; - } - if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ - { - my_snprintf(str, S(str), - "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", - CADSNAP, c_snap, c_snap); - tcleval(str); - break; - } - if(key=='G' && rstate == 0) /* double snap factor */ - { - set_snap(c_snap * 2.0); - change_linewidth(-1.); - draw(); - break; - } - if(key=='*' && EQUAL_MODMASK) /* svg print , 20121108 */ - { - if(xctx->semaphore >= 2) break; - svg_draw(); - break; - } - if(key=='*' && rstate == 0 ) /* postscript print */ - { - if(xctx->semaphore >= 2) break; - ps_draw(7, 0, 0); - break; - } - if(key=='*' && rstate == ControlMask) /* xpm print */ - { - if(xctx->semaphore >= 2) break; - print_image(); - break; - } - if(key=='u' && EQUAL_MODMASK) /* align to grid */ - { - if(xctx->semaphore >= 2) break; - xctx->push_undo(); - round_schematic_to_grid(c_snap); - set_modify(1); - if(tclgetboolvar("autotrim_wires")) trim_wires(); - xctx->prep_hash_inst=0; - xctx->prep_hash_wires=0; - xctx->prep_net_structs=0; - xctx->prep_hi_structs=0; - - draw(); - break; - } - if(0 && (key=='u') && rstate==ControlMask) /* testmode */ - { - static int x = 0; - - if(x == 0) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); - } - } else if(x == 1) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); - } - } - x++; - x %= 2; - break; - } - if(key=='u' && rstate==0) /* undo */ - { - if(xctx->semaphore >= 2) break; - xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ - draw(); - break; - } - if(key=='U' && rstate == 0) /* redo */ - { - if(xctx->semaphore >= 2) break; - xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ - draw(); - break; - } - if(key=='&') /* check wire connectivity */ - { - if(xctx->semaphore >= 2) break; - xctx->push_undo(); - trim_wires(); - draw(); - break; - } - if(key=='l' && rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ - if(xctx->semaphore >= 2) break; - create_sch_from_sym(); - break; - } - if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) break; - if(infix_interface) { - start_line(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTLINE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTLINE; - } - break; - } - if(key=='l' && EQUAL_MODMASK) { /* add pin label*/ - place_net_label(1); - break; - } - if(key >= '0' && key <= '4' && state == 0) { /* toggle pin logic level */ - if(xctx->semaphore >= 2) break; - if(key == '4') logic_set(-1, 1, NULL); - else logic_set((int)key - '0', 1, NULL); - break; - } - if(key=='L' && EQUAL_MODMASK ) { /* add pin label*/ - place_net_label(0); - break; - } - if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ - if(tclgetboolvar("orthogonal_wiring")){ - tclsetboolvar("orthogonal_wiring", 0); - xctx->manhattan_lines = 0; - } else { - tclsetboolvar("orthogonal_wiring", 1); - } - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key=='F' && rstate == 0) /* flip */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='V' && rstate == 0) /* vertical flip */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE); - copy_objects(ROTATE); - copy_objects(FLIP); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='v' && EQUAL_MODMASK) /* vertical flip objects around their anchor points */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(FLIP|ROTATELOCAL); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - - if(key=='\\' && state==0) /* fullscreen */ - { - - dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); - toggle_fullscreen(win_path); - break; - } - if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='R' && rstate == 0) /* rotate */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(END,0,0,0); - } - - break; - } - if(key=='r' && EQUAL_MODMASK) /* rotate objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - /* Move selection */ - if(key=='m' && rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - /* Move selection adding wires to moved pins */ - if(((key == 'M' && rstate == 0) || (key == 'm' && EQUAL_MODMASK)) && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - /* move selection stretching attached nets */ - if(key=='m' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - - /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ - if(key=='M' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - - if(key=='c' && EQUAL_MODMASK && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) break; - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - break; - } - - if(key=='c' && rstate==0 && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - break; - } - if(key=='n' && rstate == ControlMask) /* clear schematic */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem clear SCHEMATIC"); - break; - } - if(key=='N' && rstate == ControlMask ) /* clear symbol */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem clear SYMBOL"); - break; - } - if(key=='n' && rstate==0) /* hierarchical netlist */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem netlist -erc"); - break; - } - if(key=='N' && rstate == 0) /* current level only netlist */ - { - int err = 0; - yyparse_error = 0; - if(xctx->semaphore >= 2) break; - unselect_all(1); - if( set_netlist_dir(0, NULL) ) { - dbg(1, "callback(): -------------\n"); - if(xctx->netlist_type == CAD_SPICE_NETLIST) - err = global_spice_netlist(0, 1); - else if(xctx->netlist_type == CAD_VHDL_NETLIST) - err = global_vhdl_netlist(0, 1); - else if(xctx->netlist_type == CAD_VERILOG_NETLIST) - err = global_verilog_netlist(0, 1); - else if(xctx->netlist_type == CAD_TEDAX_NETLIST) - err = global_tedax_netlist(0, 1); - else - tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " - "-message {Please Set netlisting mode (Options menu)}"); - dbg(1, "callback(): -------------\n"); - } - else { - if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); - else dbg(0, "Can not write into the netlist directory. Please check"); - err = 1; - } - if(err) { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); - } - } else { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); - } - } - - break; - } - if(key=='A' && rstate == ControlMask) /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='A' && rstate == 0) /* toggle show netlist */ - { - int net_s; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - net_s = tclgetboolvar("netlist_show"); - net_s = !net_s; - if(net_s) { - tcleval("alert_ { enabling show netlist window} {}"); - tclsetvar("netlist_show","1"); - } - else { - tcleval("alert_ { disabling show netlist window } {}"); - tclsetvar("netlist_show","0"); - } - break; - } - if(key=='>') { - if(xctx->semaphore >= 2) break; - if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; - draw(); - break; - } - if(key=='<') { - if(xctx->semaphore >= 2) break; - if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; - draw(); - break; - } - if(key==':') /* toggle flat netlist (only spice) */ - { - if(!tclgetboolvar("flat_netlist")) { - tcleval("alert_ { enabling flat netlist} {}"); - tclsetvar("flat_netlist","1"); - } - else { - tcleval("alert_ { set hierarchical netlist } {}"); - tclsetvar("flat_netlist","0"); - } - break; - } - if(key=='B' && rstate == ControlMask) /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='B' && rstate == 0) /* edit schematic header/license */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("update_schematic_header"); - } - if(key=='b' && rstate==0) /* merge schematic */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ - break; - } - if(key=='b' && EQUAL_MODMASK) /* hide/show instance details */ - { - if(xctx->semaphore >= 2) break; - xctx->hide_symbols++; - if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; - tclsetintvar("hide_symbols", xctx->hide_symbols); - draw(); - break; - } - if(key=='d' && rstate == 0) /* unselect object under the mouse */ - { - if(infix_interface) { - unselect_at_mouse_pos(mx, my); - } else { - xctx->ui_state |= (MENUSTART | DESEL_CLICK); - xctx->ui_state2 = MENUSTARTDESEL; - } - break; - } - if(key=='D' && rstate == 0) /* unselect by area */ - { - if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { - if(infix_interface) { - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex; - xctx->my_double_save=xctx->mousey; - xctx->ui_state |= DESEL_AREA; - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTDESEL; - } - } - break; - } - if(key=='d' && rstate == ControlMask) /* delete files */ - { - if(xctx->semaphore >= 2) break; - delete_files(); - break; - } - if(key=='x' && rstate == 0 ) /* new cad session */ - { - new_xschem_process(NULL ,0); - break; - } - if((key=='#') && !(state & ControlMask) ) - { - check_unique_names(0); - break; - } - if((key=='#') && (state & ControlMask) ) - { - check_unique_names(1); - break; - } - if( 0 && (key==';') && (state & ControlMask) ) /* testmode */ - { - break; - } - if(0 && key=='~' && (state & ControlMask)) { /* testmode */ - break; - } - if(0 && key=='|' && !(state & ControlMask)) { /* testmode */ - break; - } - if(0 && key=='|' && (state & ControlMask)) /* testmode */ - { - break; - } - - if(key=='f' && rstate == ControlMask) /* search */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("property_search"); - break; - } - if(key=='F' && rstate == ControlMask ) /* full zoom selection */ - { - if(xctx->ui_state == SELECTION) { - zoom_full(1, 1, 3, 0.97); - } - break; - } - if(key=='f' && rstate == 0 ) /* full zoom */ - { - int flags = 1; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(tclgetboolvar("zoom_full_center")) flags |= 2; - zoom_full(1, 0, flags, 0.97); - break; - } - if((key=='z' && rstate==ControlMask)) /* zoom out */ - { - view_unzoom(0.0); - break; - } - if(key=='!' && !(state & ControlMask)) - { - if(xctx->semaphore >= 2) break; - break_wires_at_pins(0); - break; - } - if(key=='!' && (state & ControlMask)) - { - if(xctx->semaphore >= 2) break; - break_wires_at_pins(1); - break; - } - break; case ButtonPress: - dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - /* terminate a schematic pan action */ - if(xctx->ui_state & STARTPAN) { - xctx->ui_state &=~STARTPAN; - break; - } - - /* select instance and connected nets stopping at wire junctions */ - if(button == Button3 && state == ControlMask && xctx->semaphore <2) - { - Selected sel; - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - if(sel.type) select_connected_nets(1); - } - - /* break wire at mouse coordinates, move break point to nearest grid point */ - else if(button == Button3 && EQUAL_MODMASK && !(state & ShiftMask) && xctx->semaphore <2) - { - break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); - } - /* break wire at mouse coordinates */ - else if(button == Button3 && EQUAL_MODMASK && (state & ShiftMask) && xctx->semaphore <2) - { - break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); - } - /* select instance and connected nets NOT stopping at wire junctions */ - else if(button == Button3 && state == ShiftMask && xctx->semaphore <2) - { - Selected sel; - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - if(sel.type) select_connected_nets(0); - } - /* moved to Button3 release */ - /* - * else if(button == Button3 && state == 0 && xctx->semaphore <2) { - * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); - * } - */ - - /* zoom rectangle by right clicking and drag */ - else if(button == Button3 && state == 0 && xctx->semaphore < 2) { - zoom_rectangle(START);break; - } - - /* Mouse wheel events */ - else if(handle_mouse_wheel(event, mx, my, key, button, aux, state)) break; - - /* terminate wire placement in snap mode */ - else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { - snapped_wire(c_snap); - } - /* Alt - Button1 click to unselect */ - else if(button==Button1 && (SET_MODMASK) ) { - unselect_at_mouse_pos(mx, my); - } - - /* Middle button press (Button2) will pan the schematic. */ - else if(button==Button2 && (state == 0)) { - pan(START, mx, my); - xctx->ui_state |= STARTPAN; - } - - /* button1 click to select another instance while edit prop dialog open */ - else if(button==Button1 && xctx->semaphore >= 2) { - if(tcleval("winfo exists .dialog.textinput")[0] == '1') { /* proc text_line */ - tcleval(".dialog.f1.b1 invoke"); - break; - } else if(tcleval("winfo exists .dialog.txt")[0] == '1') { /* proc enter_text */ - tcleval(".dialog.buttons.ok invoke"); - break; - } else if(state==0 && tclgetvar("edit_symbol_prop_new_sel")[0]) { - tcleval("set edit_symbol_prop_new_sel 1; .dialog.f1.b1 invoke"); /* invoke 'OK' of edit prop dialog */ - } else if((state & ShiftMask) && tclgetvar("edit_symbol_prop_new_sel")[0]) { - select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - tclsetvar("preserve_unchanged_attrs", "1"); - rebuild_selected_array(); - } - } - - /* Handle the remaining Button1Press events */ - else if(button==Button1) /* MOD button is not pressed here. Processed above */ - { - xctx->onetime = 0; - xctx->mouse_moved = 0; - xctx->drag_elements = 0; - - /* start another wire or line in persistent mode */ - if(tclgetboolvar("persistent_command") && xctx->last_command) { - if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); - if(xctx->last_command == STARTWIRE){ - if(tclgetboolvar("snap_cursor") - && (xctx->prev_snapx == xctx->mousex_snap - && xctx->prev_snapy == xctx->mousey_snap) - && (xctx->ui_state & STARTWIRE) - && xctx->closest_pin_found){ - new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); - xctx->ui_state &= ~STARTWIRE; - } - else - start_wire(xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - /* handle all object insertions started from Tools/Edit menu */ - if(check_menu_start_commands(c_snap, mx, my)) break; - - /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ - if(end_place_move_copy_zoom()) break; - - /* Button1Press to select objects */ - if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { - Selected sel; - int already_selected = 0; - int prev_last_sel = xctx->lastsel; - int no_shift_no_ctrl = !(state & (ShiftMask | ControlMask)); - - xctx->shape_point_selected = 0; - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex; - xctx->my_double_save=xctx->mousey; - - #if 0 /* disabled */ - /* Clicking and dragging from a **selected** instance pin will start a new wire - * if no other elements are selected */ - if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) { - if(add_wire_from_wire(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) break; - if(add_wire_from_inst(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) break; - } - #endif - - /* In *NON* intuitive interface a button1 press with no modifiers will - * first unselect everything... - * For intuitive interface unselection see below... */ - if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); - - /* find closest object. Use snap coordinates if full crosshair is enabled - * since the mouse pointer is obscured and crosshair is snapped to grid points */ - if(draw_xhair) { - sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); - } else { - sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); - } - dbg(1, "sel.type=%d\n", sel.type); - /* determine if closest object was already selected when button1 was pressed */ - switch(sel.type) { - case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; - case xTEXT: if(xctx->text[sel.n].sel) already_selected = 1; break; - case LINE: if(xctx->line[sel.col][sel.n].sel) already_selected = 1; break; - case POLYGON: if(xctx->poly[sel.col][sel.n].sel) already_selected = 1; break; - case xRECT: if(xctx->rect[sel.col][sel.n].sel) already_selected = 1; break; - case ARC: if(xctx->arc[sel.col][sel.n].sel) already_selected = 1; break; - case ELEMENT: if(xctx->inst[sel.n].sel) already_selected = 1; break; - default: break; - } /*end switch */ - - /* Clicking and drag on an instance pin -> drag a new wire */ - if(xctx->intuitive_interface && !already_selected) { - if(add_wire_from_inst(&sel, xctx->mousex_snap, xctx->mousey_snap)) break; - } - - /* Clicking and drag on a wire end -> drag a new wire */ - if(xctx->intuitive_interface && !already_selected) { - if(add_wire_from_wire(&sel, xctx->mousex_snap, xctx->mousey_snap)) break; - } - - /* In intuitive interface a button1 press with no modifiers will - * unselect everything... we do it here */ - if(xctx->intuitive_interface && !already_selected && no_shift_no_ctrl ) unselect_all(1); - - /* select the object under the mouse and rebuild the selected array */ - if(!already_selected) select_object(xctx->mousex, xctx->mousey, SELECTED, 0, &sel); - rebuild_selected_array(); - dbg(1, "Button1Press to select objects, lastsel = %d\n", xctx->lastsel); - - /* if clicking on some object endpoints or vertices set shape_point_selected - * this information will be used in Motion events to draw the stretched vertices */ - if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { - if(edit_polygon_point(state)) break; /* sets xctx->shape_point_selected */ - } - if(xctx->lastsel == 1 && xctx->intuitive_interface) { - int cond = already_selected; - - if(cond && xctx->sel_array[0].type==xRECT) { - if(edit_rect_point(state)) break; /* sets xctx->shape_point_selected */ - } - - if(cond && xctx->sel_array[0].type==LINE) { - if(edit_line_point(state)) break; /* sets xctx->shape_point_selected */ - } - - if(cond && xctx->sel_array[0].type==WIRE) { - if(edit_wire_point(state)) break; /* sets xctx->shape_point_selected */ - } - } - dbg(1, "shape_point_selected=%d, lastsel=%d\n", xctx->shape_point_selected, xctx->lastsel); - - /* intuitive interface: directly drag elements */ - if(sel.type && xctx->intuitive_interface && xctx->lastsel >= 1 && - !xctx->shape_point_selected) { - /* enable_stretch (from TCL variable) reverses command if enabled: - * - move --> stretch move - * - stretch move (with ctrl key) --> move - */ - int stretch = (state & ControlMask ? 1 : 0) ^ enable_stretch; - xctx->drag_elements = 1; - /* select attached nets depending on ControlMask and enable_stretch */ - if(stretch) { - select_attached_nets(); /* stretch nets that land on selected instance pins */ - } - /* if dragging instances with stretch enabled and Shift down add wires to pins - * attached to something */ - if((state & ShiftMask) && stretch) { - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - move_objects(START,0,0,0); - } - /* dragging away an object with Shift pressed is a copy (duplicate object) */ - else if(state & ShiftMask) copy_objects(START); - /* else it is a normal move */ - else move_objects(START,0,0,0); - } - - if(tclgetboolvar("auto_hilight") && !xctx->shape_point_selected) { - if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { - if(!prev_last_sel) { - redraw_hilights(1); /* 1: clear all hilights, then draw */ - } - } - hilight_net(0); - if(xctx->lastsel) { - redraw_hilights(0); - } - } - break; - } - } /* button==Button1 */ - break; + handle_button_press(event, state, rstate, key, button, mx, my, + c_snap, draw_xhair, crosshair_size, enable_stretch, aux); + break; case ButtonRelease: - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->ui_state &= ~DESEL_CLICK; - dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); - /* bring up context menu if no pending operation */ - if(state == Button3Mask && xctx->semaphore <2) { - if(!end_place_move_copy_zoom()) { - context_menu_action(xctx->mousex_snap, xctx->mousey_snap); - } - } - - /* launcher, no intuitive interface */ - if(!xctx->intuitive_interface && state == (Button1Mask | ControlMask) && - !xctx->shape_point_selected && xctx->mouse_moved == 0) { - int savesem = xctx->semaphore; - xctx->semaphore = 0; - launcher(); /* works only if lastsel == 1 */ - xctx->semaphore = savesem; - } - - /* launcher, intuitive_interface, only if no movement has been done */ - else if(xctx->intuitive_interface && state == (Button1Mask | ControlMask) && - !xctx->shape_point_selected && (xctx->ui_state & STARTMOVE) && xctx->mouse_moved == 0) { - int savesem = xctx->semaphore; - move_objects(ABORT, 0, 0.0, 0.0); - unselect_all(1); - select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - rebuild_selected_array(); - xctx->semaphore = 0; - launcher(); /* works only if lastsel == 1 */ - xctx->semaphore = savesem; - } - - /* end wire creation when dragging in intuitive interface from an inst pin ow wire endpoint */ - /*else if(state == Button1Mask && xctx->intuitive_interface - * && (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) {*/ - /* if(end_place_move_copy_zoom()) break;*/ - /*}*/ - - /* end intuitive_interface copy or move */ - if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { - copy_objects(END); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - xctx->drag_elements = 0; - } - else if(xctx->ui_state & STARTMOVE && xctx->drag_elements) { - move_objects(END,0,0,0); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - xctx->drag_elements = 0; - } - - /* if a polygon/bezier/rectangle control point was clicked, end point move operation - * and set polygon state back to SELECTED from SELECTED1 */ - else if((xctx->ui_state & (STARTMOVE | SELECTION)) && xctx->shape_point_selected) { - end_shape_point_edit(c_snap); - } - - if(xctx->ui_state & STARTPAN) { - xctx->ui_state &=~STARTPAN; - /* xctx->mx_save = mx; xctx->my_save = my; */ - /* xctx->mx_double_save=xctx->mousex_snap; */ - /* xctx->my_double_save=xctx->mousey_snap; */ - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - dbg(1, "callback(): ButtonRelease ui_state=%d state=%d\n",xctx->ui_state,state); - if(xctx->semaphore >= 2) break; - if(xctx->ui_state & STARTSELECT) { - if(state & ControlMask) { - select_rect(!enable_stretch, END,-1); - } else { - /* Button1 release: end of rectangle select */ - if(!(state & (Button4Mask|Button5Mask) ) ) { - select_rect(enable_stretch, END,-1); - } - } - xctx->ui_state &= ~DESEL_AREA; - rebuild_selected_array(); - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", - xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); - statusmsg(str,1); - } + handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, + draw_xhair, snap_cursor, wire_draw_active, str); + break; - /* clear start from menu flag or infix_interface=0 start commands */ - if(xctx->ui_state & MENUSTART) { - xctx->ui_state &= ~MENUSTART; - break; - } - if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ - if(snap_cursor && wire_draw_active) draw_snap_cursor(3); - break; case -3: /* double click : edit prop */ - if( waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } else { - if(xctx->semaphore >= 2) break; - dbg(1, "callback(): DoubleClick ui_state=%d state=%d\n",xctx->ui_state,state); - if(button==Button1) { - Selected sel; - if(!xctx->lastsel && xctx->ui_state == 0) { - /* Following 5 lines do again a selection overriding lock, - * so locked instance attrs can be edited */ - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 1, NULL); - if(sel.type) { - xctx->ui_state = SELECTION; - rebuild_selected_array(); - } - } - if(xctx->ui_state == 0 || xctx->ui_state == SELECTION) { - edit_property(0); - } else { - if(xctx->ui_state & STARTWIRE) { - redraw_w_a_l_r_p_z_rubbers(1); - start_wire(mx, my); - xctx->ui_state &= ~STARTWIRE; - } - if(xctx->ui_state & STARTLINE) { - xctx->ui_state &= ~STARTLINE; - } - if( (xctx->ui_state & STARTPOLYGON) && (state ==0 ) ) { - new_polygon(SET, xctx->mousex_snap, xctx->mousey_snap); - } - } - } - } - break; + handle_double_click(event, state, key, button, mx, my, aux, cadence_compat); + break; + default: dbg(1, "callback(): Event:%d\n",event); break; @@ -4648,6 +4697,6 @@ int rstate; /* (reduced state, without ShiftMask) */ if(old_win_path[0]) dbg(1, "callback(): reset old_win_path: %s <- %s\n", old_win_path, win_path); my_strncpy(old_win_path, win_path, S(old_win_path)); } - return 0; + return 0; } From 2462ec04b9e135f20c9894d69929d187cd862866 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 20 Feb 2025 13:50:05 +0530 Subject: [PATCH 51/59] [After Merge Modification]: Removed references to the 'str' variable from all handle_* functions - as per upstream requirements. Removed redundant LOCs from 'src/xschemrc'. --- src/callback.c | 15 +++++++++------ src/xschemrc | 15 --------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/callback.c b/src/callback.c index bbd75c0f..aac70f13 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2468,8 +2468,9 @@ static void handle_enter_notify(int draw_xhair, int crosshair_size) } static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, - int mx, int my, int aux, int draw_xhair, int enable_stretch, int snap_cursor, int wire_draw_active, char *str) + int mx, int my, int aux, int draw_xhair, int enable_stretch, int snap_cursor, int wire_draw_active) { + char str[PATH_MAX + 100]; if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); return; @@ -2594,8 +2595,9 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, - int cadence_compat, int wire_draw_active, int snap_cursor, char *str) + int cadence_compat, int wire_draw_active, int snap_cursor) { + char str[PATH_MAX + 100]; if(key==' ') { if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); @@ -4349,8 +4351,9 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, - int aux, double c_snap, int enable_stretch, int draw_xhair, int snap_cursor, int wire_draw_active, char *str) + int aux, double c_snap, int enable_stretch, int draw_xhair, int snap_cursor, int wire_draw_active) { + char str[PATH_MAX + 100]; if(waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); return; @@ -4671,7 +4674,7 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) || case MotionNotify: handle_motion_notify(event, key, state, rstate, button, mx, my, aux, draw_xhair, enable_stretch, - snap_cursor, wire_draw_active, str); + snap_cursor, wire_draw_active); break; case KeyRelease: @@ -4680,7 +4683,7 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) || case KeyPress: handle_key_press(event, key, state, rstate, mx, my, button, aux, infix_interface, enable_stretch, win_path, c_snap, - cadence_compat, wire_draw_active, snap_cursor, str); + cadence_compat, wire_draw_active, snap_cursor); break; case ButtonPress: @@ -4690,7 +4693,7 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) || case ButtonRelease: handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, - draw_xhair, snap_cursor, wire_draw_active, str); + draw_xhair, snap_cursor, wire_draw_active); break; case -3: /* double click : edit prop */ diff --git a/src/xschemrc b/src/xschemrc index fd5feedc..da44c178 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -226,12 +226,6 @@ #### if not set show selected items at end of drag. Default: enabled (1) # set incremental_select 0 -#### if set to 1, pressing 'w', 'l', 'r', 'C', or 'Ctrl+C' will immediately place the -#### corresponding component at current cursor position without waiting for Button1 (LMB) click. -#### This setting can be disabled via the Options menu -#### default: 0 -# set infix_interface 1 - #### wires are drawn in free-form mode with this mode enabled (default). #### if set to 0, wires drawn on the schematic will no longer strictly #### follow orthogonal routes to connect two distinct points together. @@ -294,15 +288,6 @@ #### set cadence_compat; Default: 0 (Cadence-style keybinds are not used by default) # set cadence_compat 1 -#### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) -# set snap_cursor 1 - -#### set snap_cursor_size; Default: 6 (Diamond-shaped cursor that snaps to nearest circuit endpoint) -# set snap_cursor_size 6 - -#### set cadence_compat; Default: 0 (Cadence-style keybinds are not used by default) -# set cadence_compat 1 - #### if set, then, when cursor (regardless of style) is on an object, and user clicks (though mouse pointer is not on the object), #### the object is selected. Default: 0 # set use_cursor_for_selection 1 From 18884d69602d0963ea264f39a1abeff70db58995 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 20 Feb 2025 13:59:46 +0530 Subject: [PATCH 52/59] [After Merge Modification]: Fixed description for 'orthogonal_wiring' option in 'src/xschemrc'. --- src/xschemrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xschemrc b/src/xschemrc index da44c178..1ccaffd0 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -226,9 +226,9 @@ #### if not set show selected items at end of drag. Default: enabled (1) # set incremental_select 0 -#### wires are drawn in free-form mode with this mode enabled (default). -#### if set to 0, wires drawn on the schematic will no longer strictly -#### follow orthogonal routes to connect two distinct points together. +#### wires are drawn in free-form mode with this mode disabled (default). +#### if set to 1, wires drawn on the schematic will strictly follow +#### orthogonal routes to connect two distinct points together. #### default: 0 # set orthogonal_wiring 1 From 57a9348cf1cb5d265e29160ad817554c10ca9a2b Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Tue, 11 Mar 2025 11:51:17 +0530 Subject: [PATCH 53/59] [Major Refactor]: The 'handle_key_press()' function responsible for processing keyboard inputs has been refactored to use switch-case statements intead of an excessively long chain of if-else statements. Due to huge number of possible inputs, this approach should improve performance (jump-tables) of the application, while increasing readability and maintainability of the codebase in the future. Custom keybinds can also be easily worked on and implemented in the near future thanks to this approach. --- src/callback.c | 2970 ++++++++++++++++++++++++------------------------ 1 file changed, 1483 insertions(+), 1487 deletions(-) diff --git a/src/callback.c b/src/callback.c index 504a19eb..44ab24cb 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2605,1502 +2605,1498 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, int cadence_compat, int wire_draw_active, int snap_cursor) { - char str[PATH_MAX + 100]; - if(key==' ') { - if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ - new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - - } else if(xctx->ui_state & STARTLINE) { - new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } else { - if(xctx->semaphore<2) { - rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ - } - pan(START, mx, my); - xctx->ui_state |= STARTPAN; - } - return; - } - if(key == '_' ) /* toggle change line width */ - { - if(!tclgetboolvar("change_lw")) { - tcleval("alert_ { enabling change line width} {}"); - tclsetvar("change_lw","1"); - } - else { - tcleval("alert_ { disabling change line width} {}"); - tclsetvar("change_lw","0"); - } - return; - } - if(key == 'b' && rstate==ControlMask) /* toggle show text in symbol */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - xctx->sym_txt =!xctx->sym_txt; - if(xctx->sym_txt) { - /* tcleval("alert_ { enabling text in symbol} {}"); */ - tclsetvar("sym_txt","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling text in symbol} {}"); */ - tclsetvar("sym_txt","0"); - draw(); - } - return; - } - if(key == '%' ) /* toggle draw grid */ - { - int dr_gr; - dr_gr = tclgetboolvar("draw_grid"); - dr_gr =!dr_gr; - if(dr_gr) { - /* tcleval("alert_ { enabling draw grid} {}"); */ - tclsetvar("draw_grid","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling draw grid} {}"); */ - tclsetvar("draw_grid","0"); - draw(); - } - return; - } - if(key == 'j' && rstate==0 ) /* print list of highlight nets */ - { - if(xctx->semaphore >= 2) return; - print_hilight_net(1); - return; - } - if(key == 'j' && rstate==ControlMask) /* create ipins from highlight nets */ - { - if(xctx->semaphore >= 2) return; - print_hilight_net(0); - return; - } - if(key == 'j' && EQUAL_MODMASK) /* create labels without i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) return; - print_hilight_net(4); - return; - } - if(key == 'J' && SET_MODMASK ) /* create labels with i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) return; - print_hilight_net(2); - return; - } - if(key == 'h' && rstate==ControlMask ) /* go to http link */ - { - int savesem = xctx->semaphore; - xctx->semaphore = 0; - launcher(); - xctx->semaphore = savesem; - return; - } - if(key == 'h' && EQUAL_MODMASK) /* create symbol pins from schematic pins 20171208 */ - { - tcleval("schpins_to_sympins"); - return; - } - if(key == 'h' && rstate == 0) { - /* horizontally constrained drag 20171023 */ - if ( xctx->constr_mv == 1 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 1" ); - xctx->constr_mv = 1; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - return; - } - if(key=='H' && rstate == 0) { /* attach labels to selected instances */ - attach_labels_to_inst(1); - return; - } - if (key == 'H' && rstate == ControlMask) { /* create schematic and symbol from selected components */ - make_schematic_symbol_from_sel(); - return; - } - if(key == 'v' && rstate==0) { - /* vertically constrained drag 20171023 */ - if ( xctx->constr_mv == 2 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 2" ); - xctx->constr_mv = 2; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - return; - } - if(key == 'j' && SET_MODMASK && (state & ControlMask) ) /* print list of highlight net with label expansion */ - { - print_hilight_net(3); - return; - } - if(key == 'J' && rstate == 0) { - create_plot_cmd(); - return; - } - if(key == '$' && rstate == 0 ) /* toggle pixmap saving */ - { - xctx->draw_pixmap =!xctx->draw_pixmap; - if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); - else tcleval("alert_ { disabling draw pixmap} {}"); - return; - } - if(key == '$' && (state &ControlMask) ) /* toggle window drawing */ - { - xctx->draw_window =!xctx->draw_window; - if(xctx->draw_window) { - tcleval("alert_ { enabling draw window} {}"); - tclsetvar("draw_window","1"); - } else { - tcleval("alert_ { disabling draw window} {}"); - tclsetvar("draw_window","0"); - } - return; - } - if(key == '=' && (state &ControlMask)) /* toggle fill rectangles */ - { - int x; - xctx->fill_pattern++; - if(xctx->fill_pattern==2) xctx->fill_pattern=0; - - if(xctx->fill_pattern==1) { - tcleval("alert_ { Stippled pattern fill} {}"); - for(x=0;xfill_type[x]==2) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); - else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); - } - } - else if(xctx->fill_pattern==2) { - tcleval("alert_ { solid pattern fill} {}"); - for(x=0;xgcstipple[x],FillSolid); - } - else { - tcleval("alert_ { No pattern fill} {}"); - for(x=0;xgcstipple[x],FillStippled); - } - - draw(); - return; - } - if(key == '+' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - return; - } - - if(key == '-' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); - if(xctx->lw < 0.0) xctx->lw = 0.0; - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - return; - } - /* highlight discrepanciens between selected instance pin and net names */ - if(key == 'X' && rstate == 0) - { - hilight_net_pin_mismatches(); - return; - } - /* create wire snapping to closest instance pin */ - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { - if(xctx->semaphore >= 2) return; - snapped_wire(c_snap); - return; - } - /* create wire snapping to closest instance pin (cadence keybind) */ - if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { - if(xctx->semaphore >= 2) return; - snapped_wire(c_snap); - return; - } - if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) return; - - if(infix_interface) { - start_wire(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTWIRE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTWIRE; - if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); - } - return; - } - if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ - new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); - return; - } - if(key == XK_Escape) /* abort & redraw */ - { - if(xctx->semaphore < 2) { - abort_operation(); - } - /* stuff that can be done reentrantly ... */ - tclsetvar("tclstop", "1"); /* stop simulation if any running */ - if(xctx->ui_state2 & MENUSTARTWIRE) { - xctx->ui_state2 &= ~MENUSTARTWIRE; - } - if(snap_cursor) draw_snap_cursor(1); /* erase */ - if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { - xctx->last_command &= ~STARTWIRE; - } - return; - } - if(key=='z' && rstate == 0 && - !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) /* zoom box */ - { - dbg(1, "callback(): zoom_rectangle call\n"); - zoom_rectangle(START);return; - } - if(key=='Z' && rstate == 0) /* zoom in */ - { - view_zoom(0.0); return; - } - if(key=='z' && EQUAL_MODMASK && cadence_compat) /* toggle snap-cursor option */ - { - if(tclgetboolvar("snap_cursor")) { - tclsetvar("snap_cursor", "0"); - draw_snap_cursor(1); - xctx->closest_pin_found = 0; - xctx->prev_snapx = 0.0; - xctx->prev_snapy = 0.0; - } else { - tclsetvar("snap_cursor", "1"); - if(wire_draw_active) draw_snap_cursor(3); - } - } - if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ - { - xctx->push_undo(); - unselect_all(1); - storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, - xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); - xctx->need_reb_sel_arr=1; - rebuild_selected_array(); - move_objects(START,0,0,0); - xctx->ui_state |= START_SYMPIN; - return; - } - if(key=='p' && !(xctx->ui_state & STARTPOLYGON) && rstate==0) /* start polygon */ - { - if(xctx->semaphore >= 2) return; - dbg(1, "callback(): start polygon\n"); - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTPOLYGON; - } - return; - } - if(key=='P' && rstate == 0) /* pan, other way to. */ - { - xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; - xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key=='5' && rstate == 0) { /* 20110112 display only probes */ - xctx->only_probes = !xctx->only_probes; - tclsetboolvar("only_probes", xctx->only_probes); - toggle_only_probes(); - return; - } /* /20110112 */ - if(key<='9' && key >='0' && state==ControlMask) /* choose layer */ - { - char n[30]; - xctx->rectcolor = (int)key - '0'+4; - my_snprintf(n, S(n), "%d", xctx->rectcolor); - tclvareval("xschem set rectcolor ", n, NULL); - - if(has_x) { - if(!strcmp(win_path, ".drw")) { - tclvareval("reconfigure_layers_button {}", NULL); - } else { - tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + char str[PATH_MAX + 100]; + switch (key) { + case '0' ... '4': + if(state == 0) { /* toggle pin logic level */ + if(xctx->semaphore >= 2) break; + if(key == '4') logic_set(-1, 1, NULL); + else logic_set((int)key - '0', 1, NULL); } - } - dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); - return; - } - if(key==XK_Delete && (xctx->ui_state & SELECTION) ) /* delete selection */ - { - if(xctx->semaphore >= 2) return; - delete(1/* to_push_undo */);return; - } - if(key==XK_Right && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(xctx->semaphore >= 2) return; - xctx->semaphore = 0; - tcleval("next_tab"); - xctx->semaphore = save; - return; - } - if(key==XK_Left && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(xctx->semaphore >= 2) return; - xctx->semaphore = 0; - tcleval("prev_tab"); - xctx->semaphore = save; - return; - } - if(key==XK_Right && !(state & ControlMask)) /* left */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - xctx->xorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key==XK_Left && !(state & ControlMask)) /* right */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - xctx->xorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key==XK_Down) /* down */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - xctx->yorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key==XK_Up) /* up */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - xctx->yorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key=='w' && rstate == ControlMask) /* close current schematic */ - { - int save_sem; - if(xctx->semaphore >= 2) return; - save_sem = xctx->semaphore; - tcleval("xschem exit"); - xctx->semaphore = save_sem; - return; - } - /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ - if(key == 'T' && rstate == 0) { - toggle_ignore(); - } - if(key=='t' && rstate == 0) /* place text */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(xctx->semaphore >= 2) return; - xctx->last_command = 0; - xctx->mx_double_save = xctx->mousex_snap; - xctx->my_double_save = xctx->mousey_snap; - if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ - xctx->mousey_snap = xctx->my_double_save; - xctx->mousex_snap = xctx->mx_double_save; - move_objects(START,0,0,0); - xctx->ui_state |= PLACE_TEXT; - } - return; - } - if(key=='t' && (rstate & ControlMask)) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - return; - } - if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ - { - dbg(1, "callback(): start rect\n"); - if(xctx->semaphore >= 2) return; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTRECT; - } - return; - } - if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ - { - xctx->netlist_type++; if(xctx->netlist_type==6) xctx->netlist_type=1; - set_tcl_netlist_type(); - draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ - return; - } - if((key=='s' && rstate == 0) && !cadence_compat) /* simulate (original keybind) */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Run circuit simulation?}"); - if(strcmp(tclresult(),"ok")==0) { - tcleval("[xschem get top_path].menubar invoke Simulate"); - } - return; - } - if((key=='r' && rstate == ControlMask) && cadence_compat) /* simulate (for cadence users) */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Run circuit simulation?}"); - if(strcmp(tclresult(),"ok")==0) { - tcleval("[xschem get top_path].menubar invoke Simulate"); - } - return; - } - if(key=='s' && rstate == ControlMask ) /* save 20121201 */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - /* check if unnamed schematic, use saveas in this case */ - if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { - saveas(NULL, SCHEMATIC); - } else { - save(1, 0); - } - return; - } - if(key=='s' && SET_MODMASK && (state & ControlMask) ) /* save as symbol */ - { - if(xctx->semaphore >= 2) return; - saveas(NULL, SYMBOL); - return; - } - if(key=='S' && rstate == ControlMask) /* save as schematic */ - { - if(xctx->semaphore >= 2) return; - saveas(NULL, SCHEMATIC); - return; - } - if(key=='e' && rstate == 0) /* descend to schematic */ - { - if(xctx->semaphore >= 2) return; - descend_schematic(0, 1, 1, 1);return; - } - if(key=='e' && EQUAL_MODMASK) /* edit schematic in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - /* schematic_in_new_window(0, 1, 0); */ - tcleval("open_sub_schematic"); - xctx->semaphore = save; - return; - } + else if(state==ControlMask) { /* choose layer */ + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); - if(key=='E' && EQUAL_MODMASK) /* edit schematic in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - schematic_in_new_window(1, 1, 0); - xctx->semaphore = save; - return; - } - - if(key=='i' && EQUAL_MODMASK) /* edit symbol in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(0); - xctx->semaphore = save; - return; - } - - if(key=='I' && EQUAL_MODMASK) /* edit symbol in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(1); - xctx->semaphore = save; - return; - } - - - if( (key=='e' && rstate == ControlMask) || (key==XK_BackSpace)) /* back */ - { - if(xctx->semaphore >= 2) return; - go_back(1);return; - } - - if(key=='a' && rstate == 0) /* make symbol */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {do you want to make symbol view ?}"); - if(strcmp(tclresult(),"ok")==0) - { - save_schematic(xctx->sch[xctx->currsch], 0); - make_symbol(); - } - return; - } - if(key=='a' && rstate == ControlMask) /* select all */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - select_all(); - return; - } - if(key=='y' && rstate == 0) /* toggle stretching */ - { - enable_stretch = !enable_stretch; - tclsetboolvar("enable_stretch", enable_stretch); - return; - } - if(key=='x' && EQUAL_MODMASK) /* toggle draw crosshair at mouse pos */ - { - if(tclgetboolvar("draw_crosshair")) { - tclsetvar("draw_crosshair", "0"); - } else { - tclsetvar("draw_crosshair", "1"); - } - draw(); - } - if(key=='x' && rstate == ControlMask) /* cut selection into clipboard */ - { - if(xctx->semaphore >= 2) return; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - delete(1/* to_push_undo */); - } - return; - } - if(key=='c' && rstate == ControlMask) /* copy selection into clipboard */ - { - if(xctx->semaphore >= 2) return; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - } - return; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ - { - if(xctx->semaphore >= 2) return; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTARC; - } - return; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ - { - if(xctx->semaphore >= 2) return; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCIRCLE; - } - return; - } - if(key=='O' && rstate == ControlMask ) /* load most recent tile */ - { - tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); - return; - } - if(key=='O' && rstate == 0) /* toggle light/dark colorscheme 20171113 */ - { - int d_c; - d_c = tclgetboolvar("dark_colorscheme"); - d_c = !d_c; - tclsetboolvar("dark_colorscheme", d_c); - tclsetdoublevar("dim_value", 0.0); - tclsetdoublevar("dim_bg", 0.0); - build_colors(0.0, 0.0); - draw(); - return; - } - if(key=='v' && rstate == ControlMask) /* paste from clipboard */ - { - if(xctx->semaphore >= 2) return; - merge_file(2,".sch"); - return; - } - if(key=='Q' && rstate == ControlMask ) /* view attributes */ - { - edit_property(2);return; - } - if(key=='q' && rstate==ControlMask) /* quit xschem */ - { - if(xctx->semaphore >= 2) return; - /* must be set to zero, otherwise switch_tab/switch_win does not proceed - * and these are necessary when closing tabs/windows */ - xctx->semaphore = 0; - tcleval("quit_xschem"); - return; - } - if(key=='q' && rstate==0) /* edit attributes */ - { - if(xctx->semaphore >= 2) return; - edit_property(0); - return; - } - if(key=='q' && EQUAL_MODMASK) /* edit .sch file (DANGER!!) */ - { - if(xctx->semaphore >= 2) return; - rebuild_selected_array(); - if(xctx->lastsel==0 ) { - my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); - tcleval(str); - } - else if(xctx->sel_array[0].type==ELEMENT) { - my_snprintf(str, S(str), "edit_file {%s}", - abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); - tcleval(str); - - } - return; - } - #if defined(__unix__) && HAS_CAIRO==1 - if(key == XK_Print) { - xctx->ui_state |= GRABSCREEN; - tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); - tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); - return; - } - #endif - if(key=='Q' && rstate == 0) /* edit attributes in editor */ - { - if(xctx->semaphore >= 2) return; - edit_property(1);return; - } - if(key=='i' && rstate==0) /* descend to symbol */ - { - if(xctx->semaphore >= 2) return; - descend_symbol();return; - } - if((key==XK_Insert && state == ShiftMask) || (key == 'i' && rstate == ControlMask)) /* insert sym */ - { - tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); - return; - } - if((key==XK_Insert) || (key == 'I' && rstate == 0) ) /* insert sym */ - { - if(xctx->semaphore >= 2) return; - start_place_symbol(); - - return; - } - if(key=='s' && SET_MODMASK) /* reload */ - { - if(xctx->semaphore >= 2) return; - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Are you sure you want to reload from disk?}"); - if(strcmp(tclresult(),"ok")==0) { - char filename[PATH_MAX]; - unselect_all(1); - remove_symbols(); - my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); - load_schematic(1, filename, 1, 1); - draw(); - } - return; - } - if(key=='o' && rstate == ControlMask) /* load */ - { - if(xctx->semaphore >= 2) return; - ask_new_file(); - xctx->semaphore--; - tcleval("load_additional_files"); - xctx->semaphore++; - return; - } - if(key=='S' && rstate == 0) /* change element order */ - { - if(xctx->semaphore >= 2) return; - change_elem_order(-1); - return; - } - if(key=='k' && EQUAL_MODMASK) /* select whole net (all attached wires/labels/pins) */ - { - select_hilight_net(); - return; - } - if(key=='k' && rstate==ControlMask) /* unhilight net */ - { - if(xctx->semaphore >= 2) return; - unhilight_net(); - return; - } - if(key=='K' && rstate == ControlMask) /* hilight net drilling thru elements */ - /* with 'propag=' prop set on pins */ - { - if(xctx->semaphore >= 2) return; - xctx->enable_drill=1; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - return; - } - if(key=='k' && rstate==0) /* hilight net */ - { - if(xctx->semaphore >= 2) return; - xctx->enable_drill=0; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - return; - } - if(key=='K' && rstate == 0) /* delete hilighted nets */ - { - if(xctx->semaphore >= 2) return; - xctx->enable_drill=0; - clear_all_hilights(); - /* undraw_hilight_net(1); */ - draw(); - return; - } - if(key=='g' && EQUAL_MODMASK) { /* highlight net and send to viewer */ - int tool = 0; - int exists = 0; - char *tool_name = NULL; - - if(xctx->semaphore >= 2) return; - tcleval("winfo exists .graphdialog"); - if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; - else if(xctx->graph_lastsel >=0 && - xctx->rects[GRIDLAYER] > xctx->graph_lastsel && - xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { - tool = XSCHEM_GRAPH; - } - tcleval("info exists sim"); - if(tclresult()[0] == '1') exists = 1; - xctx->enable_drill = 0; - if(exists) { - if(!tool) { - tool = tclgetintvar("sim(spicewave,default)"); - my_snprintf(str, PATH_MAX + 100, "sim(spicewave,%d,name)", tool); - my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); - dbg(1,"callback(): tool_name=%s\n", tool_name); - if(strstr(tool_name, "Gaw")) tool=GAW; - else if(strstr(tool_name, "Bespice")) tool=BESPICE; - my_free(_ALLOC_ID_, &tool_name); - } - } - if(tool) { - hilight_net(tool); - redraw_hilights(0); - } - Tcl_ResetResult(interp); - return; - } - if(key=='g' && rstate==0) /* half snap factor */ - { - set_snap(c_snap / 2.0); - change_linewidth(-1.); - draw(); - return; - } - if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ - { - my_snprintf(str, S(str), - "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", - CADSNAP, c_snap, c_snap); - tcleval(str); - return; - } - if(key=='G' && rstate == 0) /* double snap factor */ - { - set_snap(c_snap * 2.0); - change_linewidth(-1.); - draw(); - return; - } - if(key=='*' && EQUAL_MODMASK) /* svg print , 20121108 */ - { - if(xctx->semaphore >= 2) return; - svg_draw(); - return; - } - if(key=='*' && rstate == 0 ) /* postscript print */ - { - if(xctx->semaphore >= 2) return; - ps_draw(7, 0, 0); - return; - } - if(key=='*' && rstate == ControlMask) /* xpm print */ - { - if(xctx->semaphore >= 2) return; - print_image(); - return; - } - if(key=='u' && EQUAL_MODMASK) /* align to grid */ - { - if(xctx->semaphore >= 2) return; - xctx->push_undo(); - round_schematic_to_grid(c_snap); - set_modify(1); - if(tclgetboolvar("autotrim_wires")) trim_wires(); - xctx->prep_hash_inst=0; - xctx->prep_hash_wires=0; - xctx->prep_net_structs=0; - xctx->prep_hi_structs=0; - - draw(); - return; - } - if(key=='u' && rstate==ControlMask) /* unselect attached floater elements */ - { - unselect_attached_floaters(); - } - if(0 && (key=='|') && rstate==ControlMask) /* testmode */ - { - static int x = 0; - - if(x == 0) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); } - } else if(x == 1) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); - } - } - x++; - x %= 2; - return; - } - if(key=='u' && rstate==0) /* undo */ - { - if(xctx->semaphore >= 2) return; - xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ - draw(); - return; - } - if(key=='U' && rstate == 0) /* redo */ - { - if(xctx->semaphore >= 2) return; - xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ - draw(); - return; - } - if(key=='&') /* check wire connectivity */ - { - if(xctx->semaphore >= 2) return; - xctx->push_undo(); - trim_wires(); - draw(); - return; - } - if(key=='l' && rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ - if(xctx->semaphore >= 2) return; - create_sch_from_sym(); - return; - } - if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) return; - if(infix_interface) { - start_line(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTLINE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTLINE; - } - return; - } - if(key=='l' && EQUAL_MODMASK) { /* add pin label*/ - place_net_label(1); - return; - } - if(key >= '0' && key <= '4' && state == 0) { /* toggle pin logic level */ - if(xctx->semaphore >= 2) return; - if(key == '4') logic_set(-1, 1, NULL); - else logic_set((int)key - '0', 1, NULL); - return; - } - if(key=='L' && EQUAL_MODMASK ) { /* add pin label*/ - place_net_label(0); - return; - } - if(key=='L' && rstate == 0) { /* toggle orthogonal routing */ - if(tclgetboolvar("orthogonal_wiring")){ - tclsetboolvar("orthogonal_wiring", 0); - xctx->manhattan_lines = 0; - } else { - tclsetboolvar("orthogonal_wiring", 1); - } - redraw_w_a_l_r_p_z_rubbers(1); - return; - } - if(key=='F' && rstate == 0) /* flip */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - return; - } - if(key=='V' && rstate == 0) /* vertical flip */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE); - copy_objects(ROTATE); - copy_objects(FLIP); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - return; - } - if(key=='v' && EQUAL_MODMASK) /* vertical flip objects around their anchor points */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(FLIP|ROTATELOCAL); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - return; - } + break; - if(key=='\\' && state==0) /* fullscreen */ - { + case '5': + if(rstate == 0) { /* 20110112 display only probes */ + xctx->only_probes = !xctx->only_probes; + tclsetboolvar("only_probes", xctx->only_probes); + toggle_only_probes(); + } /* /20110112 */ + break; + + case '6' ... '9': + if(state==ControlMask) { /* choose layer */ + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); + + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); + } + break; - dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); - toggle_fullscreen(win_path); - return; - } - if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - return; - } - if(key=='R' && rstate == 0) /* rotate */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(END,0,0,0); - } - - return; - } - if(key=='r' && EQUAL_MODMASK) /* rotate objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - return; - } - /* Move selection */ - if(key=='m' && rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - return; - } - /* Move selection adding wires to moved pins */ - if(((key == 'M' && rstate == 0) || (key == 'm' && EQUAL_MODMASK)) && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - return; - } - /* move selection stretching attached nets */ - if(key=='m' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - return; - } - - /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ - if(key=='M' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - return; - } - - if(key=='c' && EQUAL_MODMASK && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) return; - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - return; - } - - if(key=='c' && rstate==0 && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) return; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - return; - } - if(key=='n' && rstate == ControlMask) /* clear schematic */ - { - if(xctx->semaphore >= 2) return; - tcleval("xschem clear SCHEMATIC"); - return; - } - if(key=='N' && rstate == ControlMask ) /* clear symbol */ - { - if(xctx->semaphore >= 2) return; - tcleval("xschem clear SYMBOL"); - return; - } - if(key=='n' && rstate==0) /* hierarchical netlist */ - { - if(xctx->semaphore >= 2) return; - tcleval("xschem netlist -erc"); - return; - } - if(key=='N' && rstate == 0) /* current level only netlist */ - { - int err = 0; - yyparse_error = 0; - if(xctx->semaphore >= 2) return; - unselect_all(1); - if( set_netlist_dir(0, NULL) ) { - dbg(1, "callback(): -------------\n"); - if(xctx->netlist_type == CAD_SPICE_NETLIST) - err = global_spice_netlist(0, 1); - else if(xctx->netlist_type == CAD_VHDL_NETLIST) - err = global_vhdl_netlist(0, 1); - else if(xctx->netlist_type == CAD_VERILOG_NETLIST) - err = global_verilog_netlist(0, 1); - else if(xctx->netlist_type == CAD_TEDAX_NETLIST) - err = global_tedax_netlist(0, 1); - else - tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " - "-message {Please Set netlisting mode (Options menu)}"); - dbg(1, "callback(): -------------\n"); - } - else { - if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); - else dbg(0, "Can not write into the netlist directory. Please check"); - err = 1; - } - if(err) { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); + case 'a': + if(rstate == 0) { /* make symbol */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {do you want to make symbol view ?}"); + if(strcmp(tclresult(),"ok")==0) + { + save_schematic(xctx->sch[xctx->currsch], 0); + make_symbol(); + } } - } else { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); + else if(rstate == ControlMask) { /* select all */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + select_all(); } - } + break; - return; - } - if(key=='A' && rstate == ControlMask) /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - return; - } - if(key=='A' && rstate == 0) /* toggle show netlist */ - { - int net_s; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - net_s = tclgetboolvar("netlist_show"); - net_s = !net_s; - if(net_s) { - tcleval("alert_ { enabling show netlist window} {}"); - tclsetvar("netlist_show","1"); - } - else { - tcleval("alert_ { disabling show netlist window } {}"); - tclsetvar("netlist_show","0"); - } - return; - } - if(key=='>') { - if(xctx->semaphore >= 2) return; - if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; - draw(); - return; - } - if(key=='<') { - if(xctx->semaphore >= 2) return; - if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; - draw(); - return; - } - if(key==':') /* toggle flat netlist (only spice) */ - { - if(!tclgetboolvar("flat_netlist")) { - tcleval("alert_ { enabling flat netlist} {}"); - tclsetvar("flat_netlist","1"); - } - else { - tcleval("alert_ { set hierarchical netlist } {}"); - tclsetvar("flat_netlist","0"); - } - return; - } - if(key=='B' && rstate == ControlMask) /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - return; - } - if(key=='B' && rstate == 0) /* edit schematic header/license */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - tcleval("update_schematic_header"); - } - if(key=='b' && rstate==0) /* merge schematic */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ - return; - } - if(key=='b' && EQUAL_MODMASK) /* hide/show instance details */ - { - if(xctx->semaphore >= 2) return; - xctx->hide_symbols++; - if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; - tclsetintvar("hide_symbols", xctx->hide_symbols); - draw(); - return; - } - if(key=='d' && rstate == 0) /* unselect object under the mouse */ - { - if(infix_interface) { - unselect_at_mouse_pos(mx, my); - } else { - xctx->ui_state |= (MENUSTART | DESEL_CLICK); - xctx->ui_state2 = MENUSTARTDESEL; - } - return; - } - if(key=='D' && rstate == 0) /* unselect by area */ - { - if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { - if(infix_interface) { - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex; - xctx->my_double_save=xctx->mousey; - xctx->ui_state |= DESEL_AREA; - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTDESEL; + case 'A': + if(rstate == 0) { /* toggle show netlist */ + int net_s; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + net_s = tclgetboolvar("netlist_show"); + net_s = !net_s; + if(net_s) { + tcleval("alert_ { enabling show netlist window} {}"); + tclsetvar("netlist_show","1"); + } + else { + tcleval("alert_ { disabling show netlist window } {}"); + tclsetvar("netlist_show","0"); + } + } + else if(rstate == ControlMask) { /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'b': + if(rstate==0) { /* merge schematic */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ + } + else if(rstate==ControlMask) { /* toggle show text in symbol */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->sym_txt =!xctx->sym_txt; + if(xctx->sym_txt) { + /* tcleval("alert_ { enabling text in symbol} {}"); */ + tclsetvar("sym_txt","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling text in symbol} {}"); */ + tclsetvar("sym_txt","0"); + draw(); + } + } + else if(EQUAL_MODMASK) { /* hide/show instance details */ + if(xctx->semaphore >= 2) break; + xctx->hide_symbols++; + if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; + tclsetintvar("hide_symbols", xctx->hide_symbols); + draw(); + } + break; + + case 'B': + if(rstate == 0) { /* edit schematic header/license */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("update_schematic_header"); + } + else if(rstate == ControlMask) { /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'c': + /* duplicate selection */ + if(rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + } + /* copy selection into clipboard */ + else if(rstate == ControlMask) { + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + } + } + /* duplicate selection */ + else if(EQUAL_MODMASK && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(xctx->semaphore >= 2) break; + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + } + break; + + case 'C': + if(/* !xctx->ui_state && */ rstate == 0) { /* place arc */ + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTARC; + } + } + else if(/* !xctx->ui_state && */ rstate == ControlMask) { /* place circle */ + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCIRCLE; + } + } + break; + + case 'd': + if(rstate == 0) { /* unselect object under the mouse */ + if(infix_interface) { + unselect_at_mouse_pos(mx, my); + } else { + xctx->ui_state |= (MENUSTART | DESEL_CLICK); + xctx->ui_state2 = MENUSTARTDESEL; + } + } + else if(rstate == ControlMask) { /* delete files */ + if(xctx->semaphore >= 2) break; + delete_files(); + } + break; + + case 'D': + if(rstate == 0) { /* unselect by area */ + if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { + if(infix_interface) { + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTDESEL; + } + } + } + break; + + case 'e': + if(rstate == 0) { /* descend to schematic */ + if(xctx->semaphore >= 2) break; + descend_schematic(0, 1, 1, 1); + } + else if(rstate == ControlMask) { + if(xctx->semaphore >= 2) break; + go_back(1); + } + else if(EQUAL_MODMASK) { /* edit schematic in new window */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + /* schematic_in_new_window(0, 1, 0); */ + tcleval("open_sub_schematic"); + xctx->semaphore = save; + } + break; + + case 'E': + if(EQUAL_MODMASK) { /* edit schematic in new window - new xschem process */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + schematic_in_new_window(1, 1, 0); + xctx->semaphore = save; + } + break; + + case 'f': + if(rstate == 0) { /* full zoom */ + int flags = 1; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(tclgetboolvar("zoom_full_center")) flags |= 2; + zoom_full(1, 0, flags, 0.97); + } + else if(rstate == ControlMask) { /* search */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("property_search"); + } + else if(EQUAL_MODMASK) { /* flip objects around their anchor points 20171208 */ + if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'F': + if(rstate == 0) { /* flip */ + if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + } + else if(rstate == ControlMask ) { /* full zoom selection */ + if(xctx->ui_state == SELECTION) { + zoom_full(1, 1, 3, 0.97); + } + } + break; + + case 'g': + if(rstate==0) { /* half snap factor */ + set_snap(c_snap / 2.0); + change_linewidth(-1.); + draw(); + } + else if(rstate==ControlMask) { /* set snap factor 20161212 */ + my_snprintf(str, S(str), + "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", + CADSNAP, c_snap, c_snap); + tcleval(str); + } + else if(EQUAL_MODMASK) { /* highlight net and send to viewer */ + int tool = 0; + int exists = 0; + char *tool_name = NULL; + + if(xctx->semaphore >= 2) break; + tcleval("winfo exists .graphdialog"); + if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; + else if(xctx->graph_lastsel >=0 && + xctx->rects[GRIDLAYER] > xctx->graph_lastsel && + xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { + tool = XSCHEM_GRAPH; + } + tcleval("info exists sim"); + if(tclresult()[0] == '1') exists = 1; + xctx->enable_drill = 0; + if(exists) { + if(!tool) { + tool = tclgetintvar("sim(spicewave,default)"); + my_snprintf(str, PATH_MAX + 100, "sim(spicewave,%d,name)", tool); + my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); + dbg(1,"callback(): tool_name=%s\n", tool_name); + if(strstr(tool_name, "Gaw")) tool=GAW; + else if(strstr(tool_name, "Bespice")) tool=BESPICE; + my_free(_ALLOC_ID_, &tool_name); + } + } + if(tool) { + hilight_net(tool); + redraw_hilights(0); + } + Tcl_ResetResult(interp); + } + break; + + case 'G': + if(rstate == 0) { /* double snap factor */ + set_snap(c_snap * 2.0); + change_linewidth(-1.); + draw(); + } + break; + + case 'h': + if(rstate==ControlMask ) { /* go to http link */ + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); + xctx->semaphore = savesem; + } + else if (rstate == 0) { /* horizontally constrained drag 20171023 */ + if ( xctx->constr_mv == 1 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 1" ); + xctx->constr_mv = 1; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + } + else if (EQUAL_MODMASK) { + tcleval("schpins_to_sympins"); + } + break; + + case 'H': + if(rstate == 0) { /* attach labels to selected instances */ + attach_labels_to_inst(1); + } + else if (rstate == ControlMask) { /* create schematic and symbol from selected components */ + make_schematic_symbol_from_sel(); + } + break; + + case 'i': + if(rstate==0) { /* descend to symbol */ + if(xctx->semaphore >= 2) break; + descend_symbol(); + } + else if(rstate == ControlMask) { /* insert sym */ + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } + else if(EQUAL_MODMASK) { /* edit symbol in new window */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(0); + xctx->semaphore = save; + } + break; + + case 'I': + if(rstate == 0) { /* insert sym */ + if(xctx->semaphore >= 2) break; + start_place_symbol(); + } + else if(EQUAL_MODMASK) { /* edit symbol in new window - new xschem process */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(1); + xctx->semaphore = save; + } + break; + + case 'j': + if(rstate==0 ) { /* print list of highlight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(1); + } + else if(rstate==ControlMask) { /* create ipins from highlight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(0); + } + else if(EQUAL_MODMASK) { /* create labels without i prefix from hilight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(4); + } + else if( SET_MODMASK && (state & ControlMask) ) { /* print list of highlight net with label expansion */ + print_hilight_net(3); + } + break; + + case 'J': + if(rstate == 0) { + create_plot_cmd(); + } + else if(SET_MODMASK ) { /* create labels with i prefix from hilight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(2); + } + break; + + case 'k': + if(rstate==0) { /* hilight net */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=0; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + } + else if(EQUAL_MODMASK) { /* select whole net (all attached wires/labels/pins) */ + select_hilight_net(); + } + else if(rstate==ControlMask) { /* unhilight net */ + if(xctx->semaphore >= 2) break; + unhilight_net(); + } + break; + + case 'K': + if(rstate == 0) { /* delete hilighted nets */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=0; + clear_all_hilights(); + /* undraw_hilight_net(1); */ + draw(); + } + else if(rstate == ControlMask) { /* hilight net drilling thru elements with 'propag=' prop set on pins */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=1; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + } + break; + + case 'l': + if(/* !xctx->ui_state && */ rstate == 0) { /* start line */ + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) break; + if(infix_interface) { + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTLINE; + } + } + else if(rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ + if(xctx->semaphore >= 2) break; + create_sch_from_sym(); + } + else if(EQUAL_MODMASK) { /* add pin label*/ + place_net_label(1); + } + break; + + case 'L': + if(rstate == 0) { /* toggle orthogonal routing */ + if(tclgetboolvar("orthogonal_wiring")){ + tclsetboolvar("orthogonal_wiring", 0); + xctx->manhattan_lines = 0; + } else { + tclsetboolvar("orthogonal_wiring", 1); + } + redraw_w_a_l_r_p_z_rubbers(1); + } + else if(EQUAL_MODMASK ) { /* add pin label*/ + place_net_label(0); + } + break; + + case 'm': + /* Move selection */ + if(rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* move selection stretching attached nets */ + else if(rstate == ControlMask && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* Move selection adding wires to moved pins */ + else if(EQUAL_MODMASK && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + break; + + case 'M': + /* Move selection adding wires to moved pins */ + if((rstate == 0) && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ + else if(rstate == ControlMask && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + break; + + case 'n': + if(rstate==0) { /* hierarchical netlist */ + if(xctx->semaphore >= 2) break; + tcleval("xschem netlist -erc"); + } + else if(rstate == ControlMask) { /* clear schematic */ + if(xctx->semaphore >= 2) break; + tcleval("xschem clear SCHEMATIC"); + } + break; + + case 'N': + if(rstate == 0) { /* current level only netlist */ + int err = 0; + yyparse_error = 0; + if(xctx->semaphore >= 2) break; + unselect_all(1); + if( set_netlist_dir(0, NULL) ) { + dbg(1, "callback(): -------------\n"); + if(xctx->netlist_type == CAD_SPICE_NETLIST) + err = global_spice_netlist(0, 1); + else if(xctx->netlist_type == CAD_VHDL_NETLIST) + err = global_vhdl_netlist(0, 1); + else if(xctx->netlist_type == CAD_VERILOG_NETLIST) + err = global_verilog_netlist(0, 1); + else if(xctx->netlist_type == CAD_TEDAX_NETLIST) + err = global_tedax_netlist(0, 1); + else + tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " + "-message {Please Set netlisting mode (Options menu)}"); + dbg(1, "callback(): -------------\n"); + } + else { + if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); + else dbg(0, "Can not write into the netlist directory. Please check"); + err = 1; + } + if(err) { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); + } + } else { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); + } + } + + } + else if(rstate == ControlMask ) { /* clear symbol */ + if(xctx->semaphore >= 2) break; + tcleval("xschem clear SYMBOL"); + } + break; + + case 'o': + if(rstate == ControlMask) { /* load */ + if(xctx->semaphore >= 2) break; + ask_new_file(); + xctx->semaphore--; + tcleval("load_additional_files"); + xctx->semaphore++; + } + break; + + case 'O': + if(rstate == ControlMask ) { /* load most recent tile */ + tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); + } + else if(rstate == 0) { /* toggle light/dark colorscheme 20171113 */ + int d_c; + d_c = tclgetboolvar("dark_colorscheme"); + d_c = !d_c; + tclsetboolvar("dark_colorscheme", d_c); + tclsetdoublevar("dim_value", 0.0); + tclsetdoublevar("dim_bg", 0.0); + build_colors(0.0, 0.0); + draw(); + } + break; + + case 'p': + if(EQUAL_MODMASK) { /* add symbol pin */ + xctx->push_undo(); + unselect_all(1); + storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, + xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); + xctx->need_reb_sel_arr=1; + rebuild_selected_array(); + move_objects(START,0,0,0); + xctx->ui_state |= START_SYMPIN; + } + else if( !(xctx->ui_state & STARTPOLYGON) && rstate==0) { /* start polygon */ + if(xctx->semaphore >= 2) break; + dbg(1, "callback(): start polygon\n"); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTPOLYGON; + } + } + break; + + case 'P': + if(rstate == 0) { /* pan, other way to. */ + xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; + xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case 'q': + if(rstate==ControlMask) { /* quit xschem */ + if(xctx->semaphore >= 2) break; + /* must be set to zero, otherwise switch_tab/switch_win does not proceed + * and these are necessary when closing tabs/windows */ + xctx->semaphore = 0; + tcleval("quit_xschem"); + } + else if(rstate==0) { /* edit attributes */ + if(xctx->semaphore >= 2) break; + edit_property(0); + } + else if(EQUAL_MODMASK) { /* edit .sch file (DANGER!!) */ + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel==0 ) { + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + tcleval(str); + } + else if(xctx->sel_array[0].type==ELEMENT) { + my_snprintf(str, S(str), "edit_file {%s}", + abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); + tcleval(str); + + } + } + break; + + case 'Q': + if(rstate == 0) { /* edit attributes in editor */ + if(xctx->semaphore >= 2) break; + edit_property(1); + } + else if(rstate == ControlMask) { /* view attributes */ + edit_property(2); + } + break; + + case 'r': + if(/* !xctx->ui_state && */ rstate==0) { /* start rect */ + dbg(1, "callback(): start rect\n"); + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTRECT; + } + } + else if((rstate == ControlMask) && cadence_compat) { /* simulate (for cadence users) */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + } + else if(SET_MODMASK) { /* reload */ + if(xctx->semaphore >= 2) break; + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Are you sure you want to reload from disk?}"); + if(strcmp(tclresult(),"ok")==0) { + char filename[PATH_MAX]; + unselect_all(1); + remove_symbols(); + my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); + load_schematic(1, filename, 1, 1); + draw(); + } + } + else if(EQUAL_MODMASK) { /* rotate objects around their anchor points 20171208 */ + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'R': + if(rstate == 0) { /* rotate */ + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(END,0,0,0); + } + + } + break; + + case 's': + if((rstate == 0) && !cadence_compat) { /* simulate (original keybind) */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + } + else if(/* !xctx->ui_state && */ (rstate == 0) && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ + if(xctx->semaphore >= 2) break; + snapped_wire(c_snap); + } + else if(rstate == ControlMask ){ /* save 20121201 */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + /* check if unnamed schematic, use saveas in this case */ + if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { + saveas(NULL, SCHEMATIC); + } else { + save(1, 0); + } + } + else if(SET_MODMASK && (state & ControlMask) ) { /* save as symbol */ + if(xctx->semaphore >= 2) break; + saveas(NULL, SYMBOL); + } + break; + + case 'S': + if(rstate == 0) { /* change element order */ + if(xctx->semaphore >= 2) break; + change_elem_order(-1); + } + else if(rstate == ControlMask) { /* save as schematic */ + if(xctx->semaphore >= 2) break; + saveas(NULL, SCHEMATIC); + } + break; + + case 't': + if(rstate == 0) { /* place text */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->last_command = 0; + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_TEXT; + } + } + else if(rstate & ControlMask) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'T': + if(rstate == 0) { /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ + toggle_ignore(); + } + break; + + case 'u': + if(rstate==0) { /* undo */ + if(xctx->semaphore >= 2) break; + xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ + draw(); + } + else if(EQUAL_MODMASK) { /* align to grid */ + if(xctx->semaphore >= 2) break; + xctx->push_undo(); + round_schematic_to_grid(c_snap); + set_modify(1); + if(tclgetboolvar("autotrim_wires")) trim_wires(); + xctx->prep_hash_inst=0; + xctx->prep_hash_wires=0; + xctx->prep_net_structs=0; + xctx->prep_hi_structs=0; + + draw(); + } + else if(rstate==ControlMask) { /* testmode */ + unselect_attached_floaters(); + } + + break; + + case 'U': + if(rstate == 0) { /* redo */ + if(xctx->semaphore >= 2) break; + xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ + draw(); + } + break; + + case 'v': + if(rstate==0) { /* vertically constrained drag 20171023 */ + if ( xctx->constr_mv == 2 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 2" ); + xctx->constr_mv = 2; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + } + else if(rstate == ControlMask) { /* paste from clipboard */ + if(xctx->semaphore >= 2) break; + merge_file(2,".sch"); + } + else if(EQUAL_MODMASK) { /* vertical flip objects around their anchor points */ + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(FLIP|ROTATELOCAL); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'V': + if(rstate == 0) { /* vertical flip */ + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE); + copy_objects(ROTATE); + copy_objects(FLIP); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + } + else if(rstate == ControlMask) { /* toggle spice/vhdl netlist */ + xctx->netlist_type++; + if(xctx->netlist_type==6) xctx->netlist_type=1; + set_tcl_netlist_type(); + draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ + } + break; + + case 'w': + if(/* !xctx->ui_state && */ rstate==0) { /* place wire. */ + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) break; + + if(infix_interface) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTWIRE; + if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + } + else if(rstate == ControlMask) { /* close current schematic */ + int save_sem; + if(xctx->semaphore >= 2) break; + save_sem = xctx->semaphore; + tcleval("xschem exit"); + xctx->semaphore = save_sem; + } + break; + + case 'W': + if(/* !xctx->ui_state && */ (rstate == 0) && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */ + if(xctx->semaphore >= 2) break; + snapped_wire(c_snap); + } + break; + + case 'x': + if(rstate == 0) { /* new cad session */ + new_xschem_process(NULL ,0); + } + else if(EQUAL_MODMASK) { /* toggle draw crosshair at mouse pos */ + if(tclgetboolvar("draw_crosshair")) { + tclsetvar("draw_crosshair", "0"); + } else { + tclsetvar("draw_crosshair", "1"); + } + draw(); + } + else if(rstate == ControlMask) { /* cut selection into clipboard */ + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + delete(1/* to_push_undo */); + } + } + break; + + case 'X': + if(rstate == 0) { /* highlight discrepanciens between selected instance pin and net names */ + hilight_net_pin_mismatches(); + } + break; + + case 'y': + if(rstate == 0) { /* toggle stretching */ + enable_stretch = !enable_stretch; + tclsetboolvar("enable_stretch", enable_stretch); + } + break; + + case 'z': + if(rstate == 0 && !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) { /* zoom box */ + dbg(1, "callback(): zoom_rectangle call\n"); + zoom_rectangle(START); + } + else if(rstate==ControlMask) { /* zoom out */ + view_unzoom(0.0); + } + else if(EQUAL_MODMASK && cadence_compat) { /* toggle snap-cursor option */ + if(tclgetboolvar("snap_cursor")) { + tclsetvar("snap_cursor", "0"); + draw_snap_cursor(1); + xctx->closest_pin_found = 0; + xctx->prev_snapx = 0.0; + xctx->prev_snapy = 0.0; + } else { + tclsetvar("snap_cursor", "1"); + if(wire_draw_active) draw_snap_cursor(3); + } + } + break; + + case 'Z': + if(rstate == 0) { /* zoom in */ + view_zoom(0.0); + } + break; + + case ' ': + if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + + } else if(xctx->ui_state & STARTLINE) { + new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } else { + if(xctx->semaphore<2) { + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ + } + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + break; + + case '_': /* toggle change line width */ + if(!tclgetboolvar("change_lw")) { + tcleval("alert_ { enabling change line width} {}"); + tclsetvar("change_lw","1"); + } + else { + tcleval("alert_ { disabling change line width} {}"); + tclsetvar("change_lw","0"); + } + break; + + case '%': /* toggle draw grid */ + int dr_gr; + dr_gr = tclgetboolvar("draw_grid"); + dr_gr =!dr_gr; + if(dr_gr) { + /* tcleval("alert_ { enabling draw grid} {}"); */ + tclsetvar("draw_grid","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling draw grid} {}"); */ + tclsetvar("draw_grid","0"); + draw(); + } + break; + + case '$': + if( rstate == 0 ) { /* toggle pixmap saving */ + xctx->draw_pixmap =!xctx->draw_pixmap; + if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); + else tcleval("alert_ { disabling draw pixmap} {}"); + } + else if(state & ControlMask) { /* toggle window drawing */ + xctx->draw_window =!xctx->draw_window; + if(xctx->draw_window) { + tcleval("alert_ { enabling draw window} {}"); + tclsetvar("draw_window","1"); + } else { + tcleval("alert_ { disabling draw window} {}"); + tclsetvar("draw_window","0"); + } + } + break; + + case '=': + if(state & ControlMask) { /* toggle fill rectangles */ + int x; + xctx->fill_pattern++; + if(xctx->fill_pattern==2) xctx->fill_pattern=0; + + if(xctx->fill_pattern==1) { + tcleval("alert_ { Stippled pattern fill} {}"); + for(x=0;xfill_type[x]==2) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); + else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); } - } - return; - } - if(key=='d' && rstate == ControlMask) /* delete files */ - { - if(xctx->semaphore >= 2) return; - delete_files(); - return; - } - if(key=='x' && rstate == 0 ) /* new cad session */ - { - new_xschem_process(NULL ,0); - return; - } - if((key=='#') && !(state & ControlMask) ) - { - check_unique_names(0); - return; - } - if((key=='#') && (state & ControlMask) ) - { - check_unique_names(1); - return; - } - if(key=='f' && rstate == ControlMask) /* search */ - { - if(xctx->semaphore >= 2) return; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - tcleval("property_search"); - return; - } - if(key=='F' && rstate == ControlMask ) /* full zoom selection */ - { - if(xctx->ui_state == SELECTION) { - zoom_full(1, 1, 3, 0.97); - } - return; - } - if(key=='f' && rstate == 0 ) /* full zoom */ - { - int flags = 1; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - return; - } - if(tclgetboolvar("zoom_full_center")) flags |= 2; - zoom_full(1, 0, flags, 0.97); - return; - } - if((key=='z' && rstate==ControlMask)) /* zoom out */ - { - view_unzoom(0.0); - return; - } - if(key=='!' && !(state & ControlMask)) - { - if(xctx->semaphore >= 2) return; - break_wires_at_pins(0); - return; - } - if(key=='!' && (state & ControlMask)) - { - if(xctx->semaphore >= 2) return; - break_wires_at_pins(1); - return; - } - - return; + } + else if(xctx->fill_pattern==2) { + tcleval("alert_ { solid pattern fill} {}"); + for(x=0;xgcstipple[x],FillSolid); + } + else { + tcleval("alert_ { No pattern fill} {}"); + for(x=0;xgcstipple[x],FillStippled); + } + + draw(); + } + break; + + case '+': + if(state & ControlMask) { /* change line width */ + xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + } + break; + + case '-': + if(state & ControlMask) { /* change line width */ + xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); + if(xctx->lw < 0.0) xctx->lw = 0.0; + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + } + break; + + case XK_Return: + if((state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ + new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); + } + break; + + case XK_Escape: /* abort & redraw */ + if(xctx->semaphore < 2) { + abort_operation(); + } + /* stuff that can be done reentrantly ... */ + tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(xctx->ui_state2 & MENUSTARTWIRE) { + xctx->ui_state2 &= ~MENUSTARTWIRE; + } + if(snap_cursor) draw_snap_cursor(1); /* erase */ + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { + xctx->last_command &= ~STARTWIRE; + } + break; + + case XK_Delete: + if(xctx->ui_state & SELECTION) { /* delete selection */ + if(xctx->semaphore >= 2) break; + delete(1/* to_push_undo */); + } + break; + + case XK_Right: + if(state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->semaphore = 0; + tcleval("next_tab"); + xctx->semaphore = save; + } + else { /* left */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->xorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case XK_Left: + if(state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->semaphore = 0; + tcleval("prev_tab"); + xctx->semaphore = save; + } + else { /* right */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->xorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case XK_Down: /* down */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->yorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + break; + + case XK_Up: /* up */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->yorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + break; + + case XK_BackSpace: /* back */ + if(xctx->semaphore >= 2) break; + go_back(1); + break; + +#if defined(__unix__) && HAS_CAIRO==1 + case XK_Print: + xctx->ui_state |= GRABSCREEN; + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); + break; +#endif + + case XK_Insert: + if(state == ShiftMask) { /* insert sym */ + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } + else { + if(xctx->semaphore >= 2) break; + start_place_symbol(); + } + break; + + case '*': + if(rstate == 0 ) { /* postscript print */ + if(xctx->semaphore >= 2) break; + ps_draw(7, 0, 0); + } + else if(rstate == ControlMask) {/* xpm print */ + if(xctx->semaphore >= 2) break; + print_image(); + } + else if(EQUAL_MODMASK) { /* svg print , 20121108 */ + if(xctx->semaphore >= 2) break; + svg_draw(); + } + break; + + case '&': /* check wire connectivity */ + if(xctx->semaphore >= 2) break; + xctx->push_undo(); + trim_wires(); + draw(); + break; + + case '\\': + if(state==0) { /* fullscreen */ + dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); + toggle_fullscreen(win_path); + } + break; + + case '>': + if(xctx->semaphore >= 2) break; + if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; + draw(); + break; + + case '<': + if(xctx->semaphore >= 2) break; + if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; + draw(); + break; + + /* toggle flat netlist (only spice) */ + case ':': + if(!tclgetboolvar("flat_netlist")) { + tcleval("alert_ { enabling flat netlist} {}"); + tclsetvar("flat_netlist","1"); + } + else { + tcleval("alert_ { set hierarchical netlist } {}"); + tclsetvar("flat_netlist","0"); + } + break; + + case '#': + if((state & ControlMask)) { + check_unique_names(1); + } + else { + check_unique_names(0); + } + break; + + case ';': + if(0 && (state & ControlMask)) { /* testmode */ + } + break; + + case '~': + if(0 && (state & ControlMask)) { /* testmode */ + } + break; + + case '|': + if(0 && (state & ControlMask)) { /* testmode */ + static int x = 0; + + if(x == 0) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } else if(x == 1) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } + x++; + x %= 2; + } + break; + + case '!': + if((state & ControlMask)) { + if(xctx->semaphore >= 2) break; + break_wires_at_pins(1); + } + else { + if(xctx->semaphore >= 2) break; + break_wires_at_pins(0); + } + break; + + default: + break; + } + + return; } static void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, From 9808dd14ccbe49c8956a6c1c3b23490cdb7f41a8 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 13 Mar 2025 12:54:56 +0530 Subject: [PATCH 54/59] [Minor Addition to .gitignore]: Added an entry to ignore locally used config file for auto-formatting C-code. This helps reduce confusion when reading existing code and makes future contributions easier for newcomer developers. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9d85221b..01c9e727 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,9 @@ src/eval_expr.c src/parselabel.c src/parselabel.h +# Config file for C/C++ code formatter (clang-format) +.clang-format + # Executables *.exe src/rawtovcd From 3a9b478a8db3ac74c5291ff47e2ff72f5a1ecb4b Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 13 Mar 2025 13:08:49 +0530 Subject: [PATCH 55/59] [Resolve Merge Conflicts - 2]: Second stage of changes. --- src/callback.c | 4722 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4722 insertions(+) create mode 100644 src/callback.c diff --git a/src/callback.c b/src/callback.c new file mode 100644 index 00000000..4dd7d3bf --- /dev/null +++ b/src/callback.c @@ -0,0 +1,4722 @@ +/* File: callback.c + * + * This file is part of XSCHEM, + * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit + * simulation. + * Copyright (C) 1998-2024 Stefan Frederik Schippers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "xschem.h" + +/* allow to use the Windows keys as alternate for Alt */ +#define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) +#define EQUAL_MODMASK ( (rstate == Mod1Mask) || (rstate == Mod4Mask) ) + +static int waves_selected(int event, KeySym key, int state, int button) +{ + int rstate; /* state without ShiftMask */ + int i, check; + int graph_use_ctrl_key = tclgetboolvar("graph_use_ctrl_key"); + int is_inside = 0, skip = 0; + static unsigned int excl = STARTZOOM | STARTRECT | STARTLINE | STARTWIRE | + STARTPAN | STARTSELECT | STARTMOVE | STARTCOPY; + int draw_xhair = tclgetboolvar("draw_crosshair"); + rstate = state; /* rstate does not have ShiftMask bit, so easier to test for KeyPress events */ + rstate &= ~ShiftMask; /* don't use ShiftMask, identifying characters is sufficient */ + if(xctx->ui_state & excl) skip = 1; + /* else if(event != -3 && sch_waves_loaded() < 0 ) skip = 1; */ + /* allow to work on graphs even if ctrl released while in GRAPHPAN mode + * This is useful on touchpads with TappingDragLock enabled */ + else if(graph_use_ctrl_key && !(state & ControlMask) && !(xctx->ui_state & GRAPHPAN)) skip = 1; + else if(SET_MODMASK) skip = 1; + else if(event == MotionNotify && (state & Button2Mask)) skip = 1; + else if(event == MotionNotify && (state & Button1Mask) && (state & ShiftMask)) skip = 1; + else if(event == ButtonPress && button == Button2) skip = 1; + else if(event == ButtonPress && button == Button1 && (state & ShiftMask) ) skip = 1; + else if(event == ButtonRelease && button == Button2) skip = 1; + /* else if(event == KeyPress && (state & ShiftMask)) skip = 1; */ + else if(!skip) for(i=0; i< xctx->rects[GRIDLAYER]; ++i) { + double lmargin; + xRect *r; + r = &xctx->rect[GRIDLAYER][i]; + lmargin = (r->x2 - r->x1) / 20.; + lmargin = lmargin < 3. ? 3. : lmargin; + lmargin = lmargin > 20. ? 20. : lmargin; + if(!(r->flags & 1) ) continue; + if( !graph_use_ctrl_key && !(state & ControlMask) && + !strboolcmp(get_tok_value(xctx->rect[GRIDLAYER][i].prop_ptr, "lock", 0), "true")) continue; + + check = + (xctx->ui_state & GRAPHPAN) || + (event != -3 && + ( + POINTINSIDE(xctx->mousex, xctx->mousey, r->x1 + lmargin, r->y1 + 8, r->x2 - 20, r->y2 - 8) || + POINTINSIDE(xctx->mousex, xctx->mousey, r->x1, r->y1, r->x1 + 20, r->y1 + 8) || + POINTINSIDE(xctx->mousex, xctx->mousey, r->x2 - 20, r->y2 - 8, r->x2, r->y2) + ) + ) || + ( event == -3 && + (POINTINSIDE(xctx->mousex, xctx->mousey, r->x1, r->y1, r->x2 - 40, r->y1 + 20) || + POINTINSIDE(xctx->mousex, xctx->mousey, r->x1 + 20, r->y1, r->x2 - 30, r->y2 - 10)) + ); + + if(check) { + is_inside = 1; + if(! (xctx->ui_state & GRAPHPAN) ) { + xctx->graph_master = i; + } + if(draw_xhair) draw_crosshair(1, 0); /* remove crosshair, re-enable mouse cursor */ + tclvareval(xctx->top_path, ".drw configure -cursor tcross" , NULL); + break; + } + } + if(!is_inside) { + xctx->graph_master = -1; + xctx->ui_state &= ~GRAPHPAN; /* terminate ongoing GRAPHPAN to avoid deadlocks */ + if(draw_xhair) { + if(tclgetintvar("crosshair_size") == 0) { + tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); + } else { + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + } + } else + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + if(xctx->graph_flags & 64) { + tcleval("graph_show_measure stop"); + } + } + return is_inside; +} + +/* do nothing if coordinates not changed unless force is given */ +void redraw_w_a_l_r_p_z_rubbers(int force) +{ + double mx = xctx->mousex_snap; + double my = xctx->mousey_snap; + double origin_shifted_x2, origin_shifted_y2; + + if(!force && xctx->mousex_snap == xctx->prev_rubberx && xctx->mousey_snap == xctx->prev_rubbery) return; + + if(xctx->ui_state & STARTZOOM) zoom_rectangle(RUBBER); + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + if(tclgetboolvar("orthogonal_wiring")) { + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ + origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1; + origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; + /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ + if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2){ + xctx->manhattan_lines = 1; + } else { + xctx->manhattan_lines = 2; + } + } + new_wire(RUBBER, mx, my); + } + if(xctx->ui_state & STARTARC) { + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + new_arc(RUBBER, 0, mx, my); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + new_line(RUBBER, mx, my); + } + if(xctx->ui_state & STARTRECT) new_rect(RUBBER,mx, my); + if(xctx->ui_state & STARTPOLYGON) { + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + new_polygon(RUBBER, mx, my); + } + xctx->prev_rubberx = xctx->mousex_snap; + xctx->prev_rubbery = xctx->mousey_snap; +} + +/* resets UI state, unselect all and abort any pending operation */ +void abort_operation(void) +{ + xctx->no_draw = 0; + tcleval("set constr_mv 0" ); + dbg(1, "abort_operation(): Escape: ui_state=%d, last_command=%d\n", xctx->ui_state, xctx->last_command); + xctx->constr_mv=0; + + if(xctx->ui_state & STARTPOLYGON) new_polygon(END, xctx->mousex_snap, xctx->mousey_snap); + if(xctx->last_command && xctx->ui_state & (STARTWIRE | STARTLINE)) { + if(xctx->ui_state & STARTWIRE) new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + if(xctx->ui_state & STARTLINE) new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + if(tclgetboolvar("draw_crosshair")) draw_crosshair(2, 0); + xctx->ui_state = 0; + return; + } + xctx->last_command=0; + xctx->manhattan_lines = 0; + if(xctx->ui_state & STARTMOVE) + { + move_objects(ABORT,0,0,0); + if(xctx->ui_state & (START_SYMPIN | PLACE_SYMBOL | PLACE_TEXT)) { + int save; + save = xctx->modified; + delete(1/* to_push_undo */); + set_modify(save); /* aborted placement: no change, so reset modify flag set by delete() */ + xctx->ui_state &= ~START_SYMPIN; + xctx->ui_state &= ~PLACE_SYMBOL; + xctx->ui_state &= ~PLACE_TEXT; + } + return; + } + if(xctx->ui_state & STARTCOPY) + { + copy_objects(ABORT); + return; + } + if(xctx->ui_state & STARTMERGE) { + delete(1/* to_push_undo */); + set_modify(0); /* aborted merge: no change, so reset modify flag set by delete() */ + } + xctx->ui_state = 0; + unselect_all(1); + draw(); +} + +static void start_place_symbol(void) +{ + xctx->last_command = 0; + rebuild_selected_array(); + if(xctx->lastsel && xctx->sel_array[0].type==ELEMENT) { + tclvareval("set INITIALINSTDIR [file dirname {", + abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), ""), "}]", NULL); + } + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + if(place_symbol(-1,NULL,xctx->mousex_snap, xctx->mousey_snap, 0, 0, NULL, 4, 1, 1/* to_push_undo */) ) { + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_SYMBOL; + } +} + +void start_line(double mx, double my) +{ + xctx->last_command = STARTLINE; + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv != 2) { + xctx->mx_double_save=mx; + } + if(xctx->constr_mv != 1) { + xctx->my_double_save=my; + } + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + } else { + xctx->manhattan_lines = 0; + xctx->mx_double_save=mx; + xctx->my_double_save=my; + } + new_line(PLACE, mx, my); +} + +void start_wire(double mx, double my) +{ + dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n", + xctx->ui_state, xctx->ui_state2, xctx->last_command); + xctx->last_command = STARTWIRE; + if(xctx->ui_state & STARTWIRE) { + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = xctx->manhattan_lines; + new_wire(CLEAR, mx, my); + redraw_w_a_l_r_p_z_rubbers(1); + } + if(xctx->constr_mv != 2) { + xctx->mx_double_save = mx; + } + if(xctx->constr_mv != 1) { + xctx->my_double_save = my; + } + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + } else { + xctx->mx_double_save=mx; + xctx->my_double_save=my; + } + new_wire(PLACE,mx, my); + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = 0; + } +} + +static double interpolate_yval(int idx, int p, double x, int sweep_idx, int point_not_last) +{ + double val = xctx->raw->values[idx][p]; + /* not operating point, annotate from 'b' cursor */ + if(point_not_last && (xctx->raw->allpoints > 1) && sweep_idx >= 0) { + Raw *raw = xctx->raw; + SPICE_DATA *sweep_gv = raw->values[sweep_idx]; + SPICE_DATA *gv = raw->values[idx]; + double dx = sweep_gv[p + 1] - sweep_gv[p]; + double dy = gv[p + 1] - gv[p]; + double offset = x - sweep_gv[p]; + double interp = dx != 0.0 ? offset * dy / dx : 0.0; + val += interp; + } + return val; +} + +void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr) +{ + tcleval("catch {eval $cursor_2_hook}"); + if(sch_waves_loaded() >= 0) { + int dset, first = -1, last, dataset = gr->dataset, i, p, ofs = 0, ofs_end; + double start, end; + int sweepvar_wrap = 0, sweep_idx; + double xx, cursor2; /* xx is the p-th sweep variable value, cursor2 is cursor 'b' x position */ + Raw *raw = xctx->raw; + int save_datasets = -1, save_npoints = -1; + /* transform multiple OP points into a dc sweep */ + if(raw->sim_type && !strcmp(raw->sim_type, "op") && raw->datasets > 1 && raw->npoints[0] == 1) { + save_datasets = raw->datasets; + raw->datasets = 1; + save_npoints = raw->npoints[0]; + raw->npoints[0] = raw->allpoints; + } + sweep_idx = get_raw_index(find_nth(get_tok_value(r->prop_ptr, "sweep", 0), ", ", "\"", 0, 1), NULL); + if(sweep_idx < 0) sweep_idx = 0; + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0); + if(s[0]) { + cursor2 = atof_spice(s); + } else { + cursor2 = xctx->graph_cursor2_x; + } + } else { + cursor2 = xctx->graph_cursor2_x; + } + start = (gr->gx1 <= gr->gx2) ? gr->gx1 : gr->gx2; + end = (gr->gx1 <= gr->gx2) ? gr->gx2 : gr->gx1; + dbg(1, "start=%g, end=%g\n", start, end); + if(gr->logx) { + start = pow(10, start); + end = pow(10, end); + } + dbg(1, "cursor b pos: %g dataset=%d\n", cursor2, gr->dataset); + if(dataset < 0) dataset = 0; /* if all datasets are plotted use first for backannotation */ + dbg(1, "dataset=%d\n", dataset); + ofs = 0; + for(dset = 0 ; dset < raw->datasets; dset++) { + double prev_x, prev_prev_x; + int cnt=0, wrap; + register SPICE_DATA *gv = raw->values[sweep_idx]; + int s=0; + ofs_end = ofs + raw->npoints[dset]; + first = -1; + prev_prev_x = prev_x = 0; + last = ofs; + + /* optimization: skip unwanted datasets, if no dc no need to detect sweep variable wraps */ + if(dataset >= 0 && strcmp(xctx->raw->sim_type, "dc") && dataset != sweepvar_wrap) goto done; + + for(p = ofs ; p < ofs_end; p++) { + xx = gv[p]; + wrap = ( cnt > 1 && XSIGN(xx - prev_x) != XSIGN(prev_x - prev_prev_x)); + if(wrap) { + sweepvar_wrap++; + cnt = 0; + } + if(xx >= start && xx <= end) { + if(dataset == sweepvar_wrap) { + dbg(1, "xx=%g cursor2=%g first=%d last=%d start=%g end=%g p=%d wrap=%d sweepvar_wrap=%d ofs=%d\n", + xx, cursor2, first, last, start, end, p, wrap, sweepvar_wrap, ofs); + if(first == -1) first = p; + if(p == first) { + if(xx == cursor2) {goto found;} + s = XSIGN0(xx - cursor2); + dbg(1, "s=%d\n", s); + } else { + int ss = XSIGN0(xx - cursor2); + dbg(1, "s=%d, ss=%d\n", s, ss); + if(ss != s) {goto found;} + } + last = p; + } + ++cnt; + } /* if(xx >= start && xx <= end) */ + prev_prev_x = prev_x; + prev_x = xx; + } /* for(p = ofs ; p < ofs + raw->npoints[dset]; p++) */ + /* offset pointing to next dataset */ + + done: + + ofs = ofs_end; + sweepvar_wrap++; + } /* for(dset...) */ + found: + if(first != -1) { + if(p > last) { + double sweep0, sweep1; + p = last; + sweep0 = raw->values[sweep_idx][first]; + sweep1 = raw->values[sweep_idx][p]; + if(fabs(sweep0 - cursor2) < fabs(sweep1 - cursor2)) { + p = first; + } + } + dbg(1, "xx=%g, p=%d\n", xx, p); + Tcl_UnsetVar(interp, "ngspice::ngspice_data", TCL_GLOBAL_ONLY); + raw->annot_p = p; + raw->annot_x = cursor2; + raw->annot_sweep_idx = sweep_idx; + for(i = 0; i < raw->nvars; ++i) { + char s[100]; + raw->cursor_b_val[i] = interpolate_yval(i, p, cursor2, sweep_idx, (p < ofs_end)); + my_snprintf(s, S(s), "%.5g", raw->cursor_b_val[i]); + /* tclvareval("array set ngspice::ngspice_data [list {", raw->names[i], "} ", s, "]", NULL); */ + Tcl_SetVar2(interp, "ngspice::ngspice_data", raw->names[i], s, TCL_GLOBAL_ONLY); + } + Tcl_SetVar2(interp, "ngspice::ngspice_data", "n\\ vars", my_itoa( raw->nvars), TCL_GLOBAL_ONLY); + Tcl_SetVar2(interp, "ngspice::ngspice_data", "n\\ points", "1", TCL_GLOBAL_ONLY); + } + if(save_npoints != -1) { /* restore multiple OP points from artificial dc sweep */ + raw->datasets = save_datasets; + raw->npoints[0] = save_npoints; + } + } +} + +/* process user input (arrow keys for now) when only graphs are selected */ + +/* xctx->graph_flags: + * 1: dnu, reserved, used in draw_graphs() + * 2: draw x-cursor1 + * 4: draw x-cursor2 + * 8: dnu, reserved, used in draw_graphs() + * 16: move x-cursor1 + * 32: move x-cursor2 + * 64: show measurement tooltip + * 128: draw y-cursor1 (hcursor) + * 256: draw y-cursor2 (hcursor) + * 512: move y-cursor1 + * 1024: move y-cursor2 + */ +static int waves_callback(int event, int mx, int my, KeySym key, int button, int aux, int state) +{ + Graph_ctx *gr; + int rstate; /* reduced state wit ShiftMask bit filtered out */ + int graph_use_ctrl_key = tclgetboolvar("graph_use_ctrl_key"); + int i, dataset = 0; + int need_fullredraw = 0, need_all_redraw = 0, need_redraw = 0, need_redraw_master = 0; + double xx1 = 0.0, xx2 = 0.0, yy1, yy2; + double delta_threshold = 0.25; + double zoom_m = 0.5; + int save_mouse_at_end = 0, clear_graphpan_at_end = 0; + int track_dset = -2; /* used to find dataset of closest wave to mouse if 't' is pressed */ + xRect *r = NULL; + int access_cond = !graph_use_ctrl_key || (state & ControlMask); + + dbg(1, "uistate=%d, graph_flags=%d\n", xctx->ui_state, xctx->graph_flags); + /* if(event != -3 && !xctx->raw) return 0; */ + rstate = state; /* rstate does not have ShiftMask bit, so easier to test for KeyPress events */ + rstate &= ~ShiftMask; /* don't use ShiftMask, identifying characters is sufficient */ + #if HAS_CAIRO==1 + cairo_save(xctx->cairo_ctx); + cairo_save(xctx->cairo_save_ctx); + xctx->cairo_font = + cairo_toy_font_face_create("Sans-Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_face(xctx->cairo_ctx, xctx->cairo_font); + cairo_set_font_face(xctx->cairo_save_ctx, xctx->cairo_font); + cairo_font_face_destroy(xctx->cairo_font); + #endif + gr = &xctx->graph_struct; + if((i = xctx->graph_master) >= 0 && ((r = &xctx->rect[GRIDLAYER][i])->flags & 1)) { + /* check if this is the master graph (the one containing the mouse pointer) */ + /* determine if mouse pointer is below xaxis or left of yaxis in some graph */ + setup_graph_data(i, 0, gr); + + /* check if user clicked on a wave label -> draw wave in bold */ + if(event == ButtonPress && button == Button3 && + edit_wave_attributes(2, i, gr)) { + draw_graph(i, 1 + 8 + (xctx->graph_flags & (2 | 4 | 128 | 256)), gr, NULL); /* draw data in graph box */ + return 0; + } + + /* destroy / show measurement widget */ + if(xctx->graph_flags & 64) { + char sx[100], sy[100]; + double xval, yval; + if(gr->digital) { + double deltag = gr->gy2 - gr->gy1; + double s1 = DIG_NWAVES; /* 1/DIG_NWAVES waveforms fit in graph if unscaled vertically */ + double s2 = DIG_SPACE; /* (DIG_NWAVES - DIG_SPACE) spacing between traces */ + double c = s1 * deltag; + deltag = deltag * s1 / s2; + yval=(DG_Y(xctx->mousey) - c) / s2; + yval=fmod(yval, deltag ) + gr->gy1; + if(yval > gr->gy2 + deltag * (s1 + s2) * 0.5) yval -= deltag; + } else { + yval = G_Y(xctx->mousey); + } + + xval = G_X(xctx->mousex); + if(gr->logx) xval = pow(10, xval); + if(gr->logy) yval = pow(10, yval); + if(gr->unitx != 1.0) + my_snprintf(sx, S(sx), "%.5g%c", gr->unitx * xval, gr->unitx_suffix); + else + my_strncpy(sx, dtoa_eng(xval), S(sx)); + + if(gr->unitx != 1.0) + my_snprintf(sy, S(sy), "%.4g%c", gr->unity * yval, gr->unity_suffix); + else + my_strncpy(sy, dtoa_eng(yval), S(sy)); + + tclvareval("set measure_text \"y=", sy, "\nx=", sx, "\"", NULL); + tcleval("graph_show_measure"); + } /* if(xctx->graph_flags & 64) */ + + gr->master_gx1 = gr->gx1; + gr->master_gx2 = gr->gx2; + gr->master_gw = gr->gw; + gr->master_cx = gr->cx; + /* move hcursor1 */ + if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 512 )) { + double c; + + c = G_Y(xctx->mousey); + if(gr->logy) c = pow(10, c); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", dtoa(c))); + need_redraw_master = 1; + } + + /* move hcursor2 */ + else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 1024 )) { + double c; + + c = G_Y(xctx->mousey); + if(gr->logy) c = pow(10, c); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", dtoa(c))); + need_redraw_master = 1; + } + + /* move cursor1 */ + /* set cursor position from master graph x-axis */ + else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 16 )) { + double c; + + c = G_X(xctx->mousex); + if(gr->logx) c = pow(10, c); + if(r->flags & 4) { /* private_cursor */ + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(c))); + } else { + xctx->graph_cursor1_x = c; + } + need_all_redraw = 1; + } + /* move cursor2 */ + /* set cursor position from master graph x-axis */ + else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 32 )) { + double c; + int floaters = there_are_floaters(); + + c = G_X(xctx->mousex); + if(gr->logx) c = pow(10, c); + if(r->flags & 4) { /* private_cursor */ + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(c))); + } else { + xctx->graph_cursor2_x = c; + } + if(tclgetboolvar("live_cursor2_backannotate")) { + backannotate_at_cursor_b_pos(r, gr); + if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */ + need_fullredraw = 1; + } else { + need_all_redraw = 1; + } + } + + if(xctx->ui_state & GRAPHPAN) goto finish; /* After GRAPHPAN only need to check Motion events for cursors */ + if(xctx->mousey_snap < W_Y(gr->gy2)) { + xctx->graph_top = 1; + } else { + xctx->graph_top = 0; + } + if(xctx->mousex_snap < W_X(gr->gx1)) { + xctx->graph_left = 1; + } else { + xctx->graph_left = 0; + } + if(xctx->mousey_snap > W_Y(gr->gy1)) { + xctx->graph_bottom = 1; + } else { + xctx->graph_bottom = 0; + } + zoom_m = (xctx->mousex - gr->x1) / gr->w; + if(event == ButtonPress && button == Button1) { + /* dragging cursors when mouse is very close */ + if(xctx->graph_flags & 128) { /* hcursor1 */ + double cursor; + cursor = gr->hcursor1_y; + if(gr->logy ) { + cursor = mylog10(cursor); + } + if(fabs(xctx->mousey - W_Y(cursor)) < 10) { + xctx->graph_flags |= 512; /* Start move hcursor1 */ + } + } + if(xctx->graph_flags & 256) { /* hcursor2 */ + double cursor; + cursor = gr->hcursor2_y; + if(gr->logy ) { + cursor = mylog10(cursor); + } + if(fabs(xctx->mousey - W_Y(cursor)) < 10) { + xctx->graph_flags |= 1024; /* Start move hcursor2 */ + } + } + if(xctx->graph_flags & 2) { /* cursor1 */ + double cursor1; + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0); + if(s[0]) { + cursor1 = atof_eng(s); + } else { + cursor1 = xctx->graph_cursor1_x; + } + } else { + cursor1 = xctx->graph_cursor1_x; + } + if(gr->logx ) { + cursor1 = mylog10(cursor1); + } + if(fabs(xctx->mousex - W_X(cursor1)) < 10) { + xctx->graph_flags |= 16; /* Start move cursor1 */ + } + } + if(xctx->graph_flags & 4) { /* cursor2 */ + double cursor2; + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0); + if(s[0]) { + cursor2 = atof_eng(s); + } else { + cursor2 = xctx->graph_cursor2_x; + } + } else { + cursor2 = xctx->graph_cursor2_x; + } + if(gr->logx) { + cursor2 = mylog10(cursor2); + } + if(fabs(xctx->mousex - W_X(cursor2)) < 10) { + xctx->graph_flags |= 32; /* Start move cursor2 */ + } + } + } + else if(event == ButtonPress && button == Button3) { + /* Numerically set cursor position */ + if(xctx->graph_flags & 2) { + double logcursor, cursor; + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0); + if(s[0]) { + cursor = atof_spice(s); + } else { + cursor = xctx->graph_cursor1_x; + } + } else { + cursor = xctx->graph_cursor1_x; + } + logcursor = cursor; + if(gr->logx ) { + logcursor = mylog10(cursor); + } + if(fabs(xctx->mousex - W_X(logcursor)) < 10) { + tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL); + cursor = atof_eng(tclresult()); + if(r->flags & 4) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(cursor))); + } else { + xctx->graph_cursor1_x = cursor; + } + event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */ + } + need_all_redraw = 1; + } + /* Numerically set cursor position *** DO NOT PUT AN `else if` BELOW *** */ + if(xctx->graph_flags & 4) { + double logcursor, cursor; + int floaters = there_are_floaters(); + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0); + if(s[0]) { + cursor = atof_spice(s); + } else { + cursor = xctx->graph_cursor2_x; + } + } else { + cursor = xctx->graph_cursor2_x; + } + logcursor = cursor; + if(gr->logx) { + logcursor = mylog10(cursor); + } + if(fabs(xctx->mousex - W_X(logcursor)) < 10) { + tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL); + cursor = atof_eng(tclresult()); + if(r->flags & 4) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(cursor))); + } else { + xctx->graph_cursor2_x = cursor; + } + event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */ + } + if(tclgetboolvar("live_cursor2_backannotate")) { + backannotate_at_cursor_b_pos(r, gr); + if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */ + need_fullredraw = 1; + } else { + need_all_redraw = 1; + } + } + /* Numerically set hcursor position *** DO NOT PUT AN `else if` BELOW *** */ + if(xctx->graph_flags & 128) { + double logcursor, cursor; + logcursor = cursor = gr->hcursor1_y; + if(gr->logy ) { + logcursor = mylog10(cursor); + } + if(fabs(xctx->mousey - W_Y(logcursor)) < 10) { + tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL); + cursor = atof_eng(tclresult()); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", dtoa(cursor))); + event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */ + } + need_redraw_master = 1; + } + /* Numerically set hcursor position *** DO NOT PUT AN `else if` BELOW *** */ + if(xctx->graph_flags & 256) { + double logcursor, cursor; + logcursor = cursor = gr->hcursor2_y; + if(gr->logy ) { + logcursor = mylog10(cursor); + } + if(fabs(xctx->mousey - W_Y(logcursor)) < 10) { + tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL); + cursor = atof_eng(tclresult()); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", dtoa(cursor))); + event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */ + } + need_redraw_master = 1; + } + } + else if(event == -3 && button == Button1) { + if(!edit_wave_attributes(1, i, gr)) { + tclvareval("graph_edit_properties ", my_itoa(i), NULL); + } + } + /* x cursor1 toggle */ + else if(key == 'a' && access_cond) { + xctx->graph_flags ^= 2; + need_all_redraw = 1; + if(xctx->graph_flags & 2) { + double c = G_X(xctx->mousex); + + if(gr->logx) c = pow(10, c); + if(r->flags & 4) { + if(!get_tok_value(r->prop_ptr, "cursor1_x", 0)[0]) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(c))); + } + } else { + xctx->graph_cursor1_x = c; + } + } + } + /* x cursor2 toggle */ + else if(key == 'b' && access_cond) { + int floaters = there_are_floaters(); + + xctx->graph_flags ^= 4; + if(xctx->graph_flags & 4) { + double c = G_X(xctx->mousex); + + if(gr->logx) c = pow(10, c); + if(r->flags & 4) { + if(!get_tok_value(r->prop_ptr, "cursor2_x", 0)[0]) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(c))); + } + } else { + xctx->graph_cursor2_x = c; + } + if(tclgetboolvar("live_cursor2_backannotate")) { + backannotate_at_cursor_b_pos(r, gr); + if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */ + need_fullredraw = 1; + } else { + need_all_redraw = 1; + } + } else if(xctx->raw) { + xctx->raw->annot_p = -1; + xctx->raw->annot_sweep_idx = -1; + /* need_all_redraw = 1; */ + need_fullredraw = 1; + } + } + /* swap cursors */ + else if((key == 's' && access_cond) ) { + double tmp, cursor1, cursor2; + int floaters = there_are_floaters(); + + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0); + if(s[0]) { + cursor1 = atof_spice(s); + } else { + cursor1 = xctx->graph_cursor1_x; + } + } else { + cursor1 = xctx->graph_cursor1_x; + } + + if(r->flags & 4) { /* private_cursor */ + const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0); + if(s[0]) { + cursor2 = atof_spice(s); + } else { + cursor2 = xctx->graph_cursor2_x; + } + } else { + cursor2 = xctx->graph_cursor2_x; + } + + tmp = cursor2; + cursor2 = cursor1; + cursor1 = tmp; + + if(r->flags & 4) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(cursor1))); + } else { + xctx->graph_cursor1_x = cursor1; + } + if(r->flags & 4) { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(cursor2))); + } else { + xctx->graph_cursor2_x = cursor2; + } + if(tclgetboolvar("live_cursor2_backannotate")) { + backannotate_at_cursor_b_pos(r, gr); + if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */ + need_fullredraw = 1; + } + else need_all_redraw = 1; + } + /* measurement tooltip */ + else if((key == 'm') && access_cond) { + xctx->graph_flags ^= 64; + if(!(xctx->graph_flags & 64)) { + tcleval("graph_show_measure stop"); + } + } + else if(key == 't' && access_cond) { + if(!gr->digital) { + const char *d = get_tok_value(r->prop_ptr, "dataset", 0); + if(d[0]) { + track_dset = atoi(d); + } else { + track_dset = -1; /* all datasets */ + } + if(track_dset < 0) { + track_dset = find_closest_wave(i, gr); + } else { + track_dset = -1; /* all datasets */ + } + } + } /* key == 't' */ + } /* if((i = xctx->graph_master) >= 0 && ((r = &xctx->rect[GRIDLAYER][i])->flags & 1)) */ + + /* save mouse position when doing pan operations */ + if( + ( event == ButtonPress && (button == Button1 || button == Button3)) && + !(xctx->ui_state & GRAPHPAN) && + !xctx->graph_top /* && !xctx->graph_bottom */ + ) { + xctx->ui_state |= GRAPHPAN; + if(!xctx->graph_left) xctx->mx_double_save = xctx->mousex_snap; + if(xctx->graph_left) xctx->my_double_save = xctx->mousey_snap; + } + dbg(1, "graph_master=%d\n", xctx->graph_master); + + finish: + + /* parameters for absolute positioning by mouse drag in bottom graph area */ + if( xctx->raw && event == MotionNotify && (state & Button1Mask) && xctx->graph_bottom ) { + int idx; + int dset; + double wwx1, wwx2, pp, delta, ccx, ddx; + + char *rawfile = NULL; + char *sim_type = NULL; + int switched = 0; + + my_strdup2(_ALLOC_ID_, &rawfile, get_tok_value(r->prop_ptr, "rawfile", 0)); + my_strdup2(_ALLOC_ID_, &sim_type, get_tok_value(r->prop_ptr, "sim_type", 0)); + if(rawfile[0] && sim_type[0]) switched = extra_rawfile(2, rawfile, sim_type, -1.0, -1.0); + my_free(_ALLOC_ID_, &rawfile); + my_free(_ALLOC_ID_, &sim_type); + + idx = get_raw_index(find_nth(get_tok_value(r->prop_ptr, "sweep", 0), ", ", "\"", 0, 1), NULL); + dset = dataset == -1 ? 0 : dataset; + + if(idx < 0 ) idx = 0; + delta = gr->gw; + wwx1 = get_raw_value(dset, idx, 0); + wwx2 = get_raw_value(dset, idx, xctx->raw->npoints[dset] - 1); + if(wwx1 == wwx2) wwx2 += 1e-6; + if(gr->logx) { + wwx1 = mylog10(wwx1); + wwx2 = mylog10(wwx2); + } + ccx = (gr->x2 - gr->x1) / (wwx2 - wwx1); + ddx = gr->x1 - wwx1 * ccx; + pp = (xctx->mousex_snap - ddx) / ccx; + xx1 = pp - delta / 2.0; + xx2 = pp + delta / 2.0; + if(switched) extra_rawfile(5, NULL, NULL, -1.0, -1.0); /* switch back to previous raw file */ + } + else if(button == Button3 && (xctx->ui_state & GRAPHPAN) && !xctx->graph_left && !xctx->graph_top) { + /* parameters for zoom area by mouse drag */ + xx1 = G_X(xctx->mx_double_save); + xx2 = G_X(xctx->mousex_snap); + if(state & ShiftMask) { + if(xx1 < xx2) { double tmp; tmp = xx1; xx1 = xx2; xx2 = tmp; } + } else { + if(xx2 < xx1) { double tmp; tmp = xx1; xx1 = xx2; xx2 = tmp; } + } + + if(xx1 == xx2) xx2 += 1e-6; + } + /* loop: after having operated on the master graph do the others */ + for(i=0; i< xctx->rects[GRIDLAYER]; ++i) { + int same_sim_type = 0; + char *curr_sim_type = NULL; + r = &xctx->rect[GRIDLAYER][i]; + my_strdup2(_ALLOC_ID_, &curr_sim_type, get_tok_value(r->prop_ptr, "sim_type", 0)); + need_redraw = 0; + if( !(r->flags & 1) ) continue; /* 1: graph; 3: graph_unlocked */ + gr->gx1 = gr->master_gx1; + gr->gx2 = gr->master_gx2; + gr->gw = gr->master_gw; + setup_graph_data(i, 1, gr); /* skip flag set, no reload x1 and x2 fields */ + if(gr->dataset >= 0 /* && gr->dataset < xctx->raw->datasets */) dataset =gr->dataset; + else dataset = -1; + + /* if master graph has unlocked X axis do not zoom/pan any other graphs: same_sim_type = 0 */ + if(!(xctx->rect[GRIDLAYER][xctx->graph_master].flags & 2) && + !strcmp(curr_sim_type, + get_tok_value(xctx->rect[GRIDLAYER][xctx->graph_master].prop_ptr, "sim_type", 0))) { + same_sim_type = 1; + } + my_free(_ALLOC_ID_, &curr_sim_type); + + if(event == MotionNotify && (state & Button1Mask) && !xctx->graph_bottom && + !(xctx->graph_flags & (16 | 32 | 512 | 1024))) { + double delta; + /* vertical move of waveforms */ + if(xctx->graph_left) { + if(i == xctx->graph_master) { + if(gr->digital) { + delta = gr->posh; + delta_threshold = 0.01; + if(fabs(xctx->my_double_save - xctx->mousey_snap) > fabs(gr->dcy * delta) * delta_threshold) { + yy1 = gr->ypos1 + (xctx->my_double_save - xctx->mousey_snap) / gr->dcy; + yy2 = gr->ypos2 + (xctx->my_double_save - xctx->mousey_snap) / gr->dcy; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + xctx->my_double_save = xctx->mousey_snap; + need_redraw = 1; + } + } else { + delta = gr->gh / gr->divy; + delta_threshold = 0.01; + if(fabs(xctx->my_double_save - xctx->mousey_snap) > fabs(gr->cy * delta) * delta_threshold) { + yy1 = gr->gy1 + (xctx->my_double_save - xctx->mousey_snap) / gr->cy; + yy2 = gr->gy2 + (xctx->my_double_save - xctx->mousey_snap) / gr->cy; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + xctx->my_double_save = xctx->mousey_snap; + need_redraw = 1; + } + } + } + } + /* horizontal move of waveforms */ + else { + save_mouse_at_end = 1; + delta = gr->gw; + delta_threshold = 0.01; + /* selected or locked or master */ + if( r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + dbg(1, "moving waves: %d\n", i); + if(fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->cx * delta) * delta_threshold) { + xx1 = gr->gx1 + (xctx->mx_double_save - xctx->mousex_snap) / gr->cx; + xx2 = gr->gx2 + (xctx->mx_double_save - xctx->mousex_snap) / gr->cx; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + } + + else if(event == ButtonPress && button == Button5 && !(state & ShiftMask)) { + double delta; + /* vertical move of waveforms with mouse wheel */ + if(xctx->graph_left) { + if(i == xctx->graph_master) { + if(gr->digital) { + delta = gr->posh * 0.05; + yy1 = gr->ypos1 + delta; + yy2 = gr->ypos2 + delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + need_redraw = 1; + } else { + delta = gr->gh/ gr->divy; + delta_threshold = 1.0; + yy1 = gr->gy1 + delta * delta_threshold; + yy2 = gr->gy2 + delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } + } + /* horizontal move of waveforms with mouse wheel */ + else { + /* selected or locked or master */ + if( r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 - delta * delta_threshold; + xx2 =gr->gx2 - delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == ButtonPress && button == Button4 && !(state & ShiftMask)) { + double delta; + /* vertical move of waveforms with mouse wheel */ + if(xctx->graph_left) { + if(i == xctx->graph_master) { + if(gr->digital) { + delta = gr->posh * 0.05; + yy1 = gr->ypos1 - delta; + yy2 = gr->ypos2 - delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + need_redraw = 1; + } else { + delta = gr->gh / gr->divy; + delta_threshold = 1.0; + yy1 = gr->gy1 - delta * delta_threshold; + yy2 = gr->gy2 - delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } + } + /* horizontal move of waveforms with mouse wheel */ + else { + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 + delta * delta_threshold; + xx2 = gr->gx2 + delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == ButtonPress && button == Button5 && (state & ShiftMask)) { + if(xctx->graph_left) { + if(i == xctx->graph_master) { + if(gr->digital) { + double m = DG_Y(xctx->mousey); + double a = m - gr->ypos1; + double b = gr->ypos2 -m; + double delta = gr->posh; + double var = delta * 0.05; + yy2 = gr->ypos2 + var * b / delta; + yy1 = gr->ypos1 - var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + need_redraw = 1; + + } else { + double m = G_Y(xctx->mousey); + double a = m - gr->gy1; + double b = gr->gy2 -m; + double delta = (gr->gy2 - gr->gy1); + double var = delta * 0.2; + yy2 = gr->gy2 + var * b / delta; + yy1 = gr->gy1 - var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } + } else { + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + double var = 0.2 * gr->gw; + xx2 = gr->gx2 + var * (1 - zoom_m); + xx1 = gr->gx1 - var * zoom_m; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == ButtonPress && button == Button4 && (state & ShiftMask)) { + if(xctx->graph_left) { + if(i == xctx->graph_master) { + if(gr->digital) { + double m = DG_Y(xctx->mousey); + double a = m - gr->ypos1; + double b = gr->ypos2 -m; + double delta = (gr->ypos2 - gr->ypos1); + double var = delta * 0.05; + yy2 = gr->ypos2 - var * b / delta; + yy1 = gr->ypos1 + var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + need_redraw = 1; + } else { + double m = G_Y(xctx->mousey); + double a = m - gr->gy1; + double b = gr->gy2 -m; + double delta = (gr->gy2 - gr->gy1); + double var = delta * 0.2; + yy2 = gr->gy2 - var * b / delta; + yy1 = gr->gy1 + var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } + } else { + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + double var = 0.2 * gr->gw; + xx2 = gr->gx2 - var * (1 - zoom_m); + xx1 = gr->gx1 + var * zoom_m; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + /* y hcursor1 toggle */ + else if(event == KeyPress && key == 'A' && access_cond && i == xctx->graph_master) { + xctx->graph_flags ^= 128; + need_redraw = 1; + if(xctx->graph_flags & 128) { + double c = G_Y(xctx->mousey); + if(gr->logy) c = pow(10, c); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", dtoa(c))); + } else { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", NULL)); + } + } + /* y hcursor2 toggle */ + else if(event == KeyPress && key == 'B' && access_cond && i == xctx->graph_master) { + xctx->graph_flags ^= 256; + need_redraw = 1; + if(xctx->graph_flags & 256) { + double c = G_Y(xctx->mousey); + if(gr->logy) c = pow(10, c); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", dtoa(c))); + } else { + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", NULL)); + } + } + else if(event == KeyPress && key == 't' && access_cond ) { + if(track_dset != -2) { /* -2 means no dataset selection ('t' key) was started */ + /* + const char *unlocked = strstr(get_tok_value(r->prop_ptr, "flags", 0), "unlocked"); + */ + int unlocked = r->flags & 2; + int floaters = there_are_floaters(); + if(i == xctx->graph_master || !unlocked) { + gr->dataset = track_dset; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "dataset", my_itoa(track_dset))); + + } + /* do this here to update texts printing current dataset in graph + * tcleval([xschem getprop rect 2 n dataset]) */ + if(i == xctx->graph_master && floaters) { + set_modify(-2); /* update floater caches to reflect actual backannotation */ + need_fullredraw = 1; + } + if((xctx->graph_flags & 4) && tclgetboolvar("live_cursor2_backannotate")) { + if(i == xctx->graph_master) { + backannotate_at_cursor_b_pos(r, gr); + } + need_fullredraw = 1; + } else { + if(!need_fullredraw) need_redraw = 1; + } + + } + } /* key == 't' */ + else if(event == KeyPress && key == XK_Left) { + double delta; + if(xctx->graph_left) { + if(!gr->digital && i == xctx->graph_master) { + double m = G_Y(xctx->mousey); + double a = m - gr->gy1; + double b = gr->gy2 -m; + double delta = gr->gh; + double var = delta * 0.2; + yy2 = gr->gy2 + var * b / delta; + yy1 = gr->gy1 - var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } else { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 - delta * delta_threshold; + xx2 = gr->gx2 - delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == KeyPress && key == XK_Right) { + double delta; + if(xctx->graph_left) { + if(!gr->digital && i == xctx->graph_master) { + double m = G_Y(xctx->mousey); + double a = m - gr->gy1; + double b = gr->gy2 -m; + double delta = gr->gh; + double var = delta * 0.2; + yy2 = gr->gy2 - var * b / delta; + yy1 = gr->gy1 + var * a / delta; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + need_redraw = 1; + } + } else { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 + delta * delta_threshold; + xx2 = gr->gx2 + delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == KeyPress && key == XK_Down) { + if(!xctx->graph_left) { + /* selected or locked or master */ + if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + double var = 0.2 * gr->gw; + xx2 = gr->gx2 + var * (1 - zoom_m); + xx1 = gr->gx1 - var * zoom_m; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == KeyPress && key == XK_Up) { + if(!xctx->graph_left) { + /* selected or locked or master */ + if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + double var = 0.2 * gr->gw; + xx2 = gr->gx2 - var * (1 - zoom_m); + xx1 = gr->gx1 + var * zoom_m; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + else if(event == KeyPress && key == 'f' && access_cond) { + if(xctx->raw && xctx->raw->values) { + if(xctx->graph_left) { /* full Y zoom*/ + if(i == xctx->graph_master) { + need_redraw = graph_fullyzoom(r, gr, dataset); + } /* graph_master */ + } else { /* not graph_left, full X zoom*/ + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + need_redraw = graph_fullxzoom(i, gr, dataset); + } + } + } /* raw->values */ + } /* key == 'f' */ + /* absolute positioning by mouse drag in bottom graph area */ + else if(event == MotionNotify && (state & Button1Mask) && xctx->graph_bottom ) { + if(xctx->raw && xctx->raw->values) { + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + + /* xx1 and xx2 calculated for master graph above */ + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } + } + } + + + else if(event == ButtonRelease) { + if(button != Button3) { + xctx->ui_state &= ~GRAPHPAN; + xctx->graph_flags &= ~(16 | 32 | 512 | 1024); /* clear move cursor flags */ + } + /* zoom X area by mouse drag */ + else if(button == Button3 && (xctx->ui_state & GRAPHPAN) && + !xctx->graph_left && !xctx->graph_top) { + /* selected or locked or master */ + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + if(xctx->mx_double_save != xctx->mousex_snap) { + clear_graphpan_at_end = 1; + + /* xx1 and xx2 calculated for master graph above */ + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } else if(i == xctx->graph_master) { + clear_graphpan_at_end = 1; + } + } + } + /* zoom Y area by mouse drag */ + else if(button == Button3 && (xctx->ui_state & GRAPHPAN) && + xctx->graph_left && !xctx->graph_top) { + /* Only on master */ + if(i == xctx->graph_master) { + if(xctx->my_double_save != xctx->mousey_snap) { + double yy1, yy2; + clear_graphpan_at_end = 1; + if(!gr->digital) { + yy1 = G_Y(xctx->my_double_save); + yy2 = G_Y(xctx->mousey_snap); + if(state & ShiftMask) { + if(yy1 < yy2) { double tmp; tmp = yy1; yy1 = yy2; yy2 = tmp; } + } else { + if(yy2 < yy1) { double tmp; tmp = yy1; yy1 = yy2; yy2 = tmp; } + } + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "y2", dtoa(yy2))); + } else { + yy1 = DG_Y(xctx->my_double_save); + yy2 = DG_Y(xctx->mousey_snap); + if(state & ShiftMask) { + if(yy1 < yy2) { double tmp; tmp = yy1; yy1 = yy2; yy2 = tmp; } + } else { + if(yy2 < yy1) { double tmp; tmp = yy1; yy1 = yy2; yy2 = tmp; } + } + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos1", dtoa(yy1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "ypos2", dtoa(yy2))); + } + need_redraw = 1; + } else if(i == xctx->graph_master) { + clear_graphpan_at_end = 1; + } + } + } + } /* else if( event == ButtonRelease) */ + if(need_redraw || need_all_redraw || ( i == xctx->graph_master && need_redraw_master) ) { + setup_graph_data(i, 0, gr); + draw_graph(i, 1 + 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), gr, NULL); /* draw data in each graph box */ + } + } /* for(i=0; i< xctx->rects[GRIDLAYER]; i++ */ + + if(need_fullredraw ==1) { + draw(); + need_fullredraw = 0; + } + if(clear_graphpan_at_end) xctx->ui_state &= ~GRAPHPAN; + /* update saved mouse position after processing all graphs */ + if(save_mouse_at_end) { + if( fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->master_cx * gr->master_gw) * delta_threshold) { + dbg(1, "save mouse pos\n"); + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + } + } + + + draw_selection(xctx->gc[SELLAYER], 0); + #if HAS_CAIRO==1 + cairo_restore(xctx->cairo_ctx); + cairo_restore(xctx->cairo_save_ctx); + #endif + return 0; +} + +/* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ +static int end_place_move_copy_zoom() +{ + if(xctx->ui_state & STARTZOOM) { + zoom_rectangle(END); + if( xctx->nl_x1 == xctx->nl_x2 && xctx->nl_y1 == xctx->nl_y2) { + return 0; + } + return 1; + } + else if(xctx->ui_state & STARTWIRE) { + if(tclgetboolvar("persistent_command")) { + if(xctx->constr_mv != 2) { + xctx->mx_double_save=xctx->mousex_snap; + } + if(xctx->constr_mv != 1) { + xctx->my_double_save=xctx->mousey_snap; + } + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(PLACE, xctx->mousex_snap, xctx->mousey_snap); + + } else { + new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + } + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + return 0; + } + else if(xctx->ui_state & STARTARC) { + new_arc(SET, 0, xctx->mousex_snap, xctx->mousey_snap); + return 0; + } + else if(xctx->ui_state & STARTLINE) { + if(tclgetboolvar("persistent_command")) { + if(xctx->constr_mv != 2) { + xctx->mx_double_save=xctx->mousex_snap; + } + if(xctx->constr_mv == 1) { + xctx->my_double_save=xctx->mousey_snap; + } + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + new_line(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + } + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + return 0; + } + else if(xctx->ui_state & STARTRECT) { + new_rect(PLACE|END,xctx->mousex_snap, xctx->mousey_snap); + return 0; + } + else if(xctx->ui_state & STARTPOLYGON) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_polygon(ADD, xctx->mousex_snap, xctx->mousey_snap); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + return 0; + } + else if(xctx->ui_state & STARTMOVE) { + move_objects(END,0,0,0); + xctx->ui_state &=~START_SYMPIN; + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + return 1; + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(END); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + return 1; + } + return 0; +} + +static void draw_snap_cursor_shape(GC gc, double x, double y, int snapcursor_size) { + /* Convert coordinates to screen space */ + double screen_x = X_TO_SCREEN(x); + double screen_y = Y_TO_SCREEN(y); + double left = screen_x - snapcursor_size; + double right = screen_x + snapcursor_size; + double top = screen_y - snapcursor_size; + double bottom = screen_y + snapcursor_size; + int i; + /* Define crosshair lines */ + double lines[4][4]; + lines[0][0] = screen_x; lines[0][1] = top; lines[0][2] = right; lines[0][3] = screen_y; + lines[1][0] = right; lines[1][1] = screen_y; lines[1][2] = screen_x; lines[1][3] = bottom; + lines[2][0] = screen_x; lines[2][1] = bottom; lines[2][2] = left; lines[2][3] = screen_y; + lines[3][0] = left; lines[3][1] = screen_y; lines[3][2] = screen_x; lines[3][3] = top; + /* Draw crosshair lines */ + for (i = 0; i < 4; i++) { + draw_xhair_line(gc, snapcursor_size, lines[i][0], lines[i][1], lines[i][2], lines[i][3]); + } +} + +static void erase_snap_cursor(double prev_x, double prev_y, int snapcursor_size) { + if (fix_broken_tiled_fill || !_unix) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + (int)X_TO_SCREEN(prev_x) - INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - INT_WIDTH(xctx->lw) - snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + 2 * INT_WIDTH(xctx->lw) + 2 * snapcursor_size, + (int)X_TO_SCREEN(prev_x) - INT_WIDTH(xctx->lw) - snapcursor_size, + (int)Y_TO_SCREEN(prev_y) - INT_WIDTH(xctx->lw) - snapcursor_size); + } else { + draw_snap_cursor_shape(xctx->gctiled, prev_x, prev_y, snapcursor_size); + } +} + +static void find_snap_position(double *x, double *y, int pos_changed) { + if (!pos_changed) { + *x = xctx->prev_snapx; + *y = xctx->prev_snapy; + } else { + xctx->closest_pin_found = find_closest_net_or_symbol_pin( + xctx->mousex, xctx->mousey, x, y); + } +} + +/* action == 3 : delete and draw + * action == 1 : delete + * action == 2 : draw + * action == 5 : delete even if pos not changed + */ +static void draw_snap_cursor(int action) { + int snapcursor_size; + int pos_changed; + int prev_draw_window = xctx->draw_window; + int prev_draw_pixmap = xctx->draw_pixmap; + + if (!xctx->mouse_inside) return; /* Early exit if mouse is outside */ + snapcursor_size = tclgetintvar("snap_cursor_size"); + pos_changed = (xctx->mousex_snap != xctx->prev_gridx) || (xctx->mousey_snap != xctx->prev_gridy); + /* Save current drawing context */ + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + if(pos_changed || action == 5) { + /* Erase the cursor */ + if (action & 1) { + erase_snap_cursor(xctx->prev_snapx, xctx->prev_snapy, snapcursor_size); + draw_selection(xctx->gc[SELLAYER], 0); + } + /* Redraw the cursor */ + if (action & 2) { + double new_x, new_y; + find_snap_position(&new_x, &new_y, pos_changed); + draw_snap_cursor_shape(xctx->gc[xctx->crosshair_layer],new_x, new_y, snapcursor_size); + /* Update previous position tracking */ + xctx->prev_gridx = xctx->mousex_snap; + xctx->prev_gridy = xctx->mousey_snap; + xctx->prev_snapx = new_x; + xctx->prev_snapy = new_y; + } + } + /* Restore previous drawing context */ + xctx->draw_window = prev_draw_window; + xctx->draw_pixmap = prev_draw_pixmap; +} + +static void erase_crosshair(int size) { + + int prev_cr_x = (int)X_TO_SCREEN(xctx->prev_crossx); + int prev_cr_y = (int)Y_TO_SCREEN(xctx->prev_crossy); + int lw = INT_WIDTH(xctx->lw); + if(size) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + prev_cr_x - 1 * lw - size, prev_cr_y - 1 * lw - size, 2 * lw + 2 * size, 2 * lw + 2 * size, + prev_cr_x - 1 * lw - size, prev_cr_y - 1 * lw - size); + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + prev_cr_x - 1 * lw - size, prev_cr_y - 1 * lw - size, 2 * lw + 2 * size, 2 * lw + 2 * size, + prev_cr_x - 1 * lw - size, prev_cr_y - 1 * lw - size); + } else { /* full screen span xhair */ + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + 0, prev_cr_y - 1 * lw, xctx->xrect[0].width, 2 * lw, 0, prev_cr_y - 1 * lw); + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], + prev_cr_x - 1 * lw, 0, 2 * lw, xctx->xrect[0].height, prev_cr_x - 1 * lw, 0); + } +} + +static void draw_crosshair_shape(GC gc, double x, double y, int size) +{ + double screen_x = X_TO_SCREEN(x); + double screen_y = Y_TO_SCREEN(y); + if(size) { + draw_xhair_line(gc, size, screen_x - size, screen_y - size, screen_x + size, screen_y - size); + draw_xhair_line(gc, size, screen_x - size, screen_y + size, screen_x + size, screen_y + size); + draw_xhair_line(gc, size, screen_x - size, screen_y - size, screen_x - size, screen_y + size); + draw_xhair_line(gc, size, screen_x + size, screen_y - size, screen_x + size, screen_y + size); + } else { /* full screen span xhair */ + draw_xhair_line(gc, size, xctx->areax1, screen_y, xctx->areax2, screen_y); + draw_xhair_line(gc, size, screen_x, xctx->areay1, screen_x, xctx->areay2); + } +} + +/* what == 3 (+4) : delete and draw (force) + * what == 1 (+4) : delete (force) + * what == 2 (+4) : draw (force) + * what == 4 : force (re)clear and/or (re)draw even if on same point */ +void draw_crosshair(int what, int state) +{ + int sdw, sdp; + int xhair_size = tclgetintvar("crosshair_size"); + int snap_cursor = tclgetintvar("snap_cursor"); + double mx, my; + int changed = 0; + dbg(1, "draw_crosshair(): what=%d\n", what); + sdw = xctx->draw_window; + sdp = xctx->draw_pixmap; + + if(!xctx->mouse_inside) return; + mx = xctx->mousex_snap; + my = xctx->mousey_snap; + if( ( (xctx->ui_state & (MENUSTART | STARTWIRE) ) || xctx->ui_state == 0 ) && + (state == ShiftMask)) { + if(!snap_cursor) { + /* mouse not changed so closest net or symbol pin unchanged too */ + if(mx == xctx->prev_m_crossx && my == xctx->prev_m_crossy) { + mx = xctx->prev_crossx; /* get previous one */ + my = xctx->prev_crossy; + } else { + /* mouse position changed, so find new closest net or pin */ + find_closest_net_or_symbol_pin(xctx->mousex_snap, xctx->mousey_snap, &mx, &my); + changed = 1; /* we force a cursor redraw */ + dbg(1, "find\n"); + } + } else { + /* draw_snap_cursor(what); */ + } + } + + /* no changed closest pin/net, no force, mx,my is not changed. --> do nothing + | _____________| | + | | _____________________|____________________________ */ + if(!changed && !(what & 4) && mx == xctx->prev_crossx && my == xctx->prev_crossy) { + return; + } + dbg(1, "draw %d\n", what); + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + if(what & 1) { /* delete previous */ + if(fix_broken_tiled_fill || !_unix) { + erase_crosshair(xhair_size); + } else { + draw_crosshair_shape(xctx->gctiled, xctx->prev_crossx, xctx->prev_crossy, xhair_size); + } + } + if(what & 2) { /* draw new */ + draw_crosshair_shape(xctx->gc[xctx->crosshair_layer], mx, my, xhair_size); + } + if(what) draw_selection(xctx->gc[SELLAYER], 0); + + if(what & 2) { + /* previous closest pin or net position (if snap wire or Shift pressed) */ + xctx->prev_crossx = mx; + xctx->prev_crossy = my; + /* previous mouse_snap position */ + xctx->prev_m_crossx = xctx->mousex_snap; + xctx->prev_m_crossy = xctx->mousey_snap; + } + xctx->draw_window = sdw; + xctx->draw_pixmap = sdp; +} + +static void unselect_at_mouse_pos(int mx, int my) +{ + xctx->last_command = 0; + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + select_object(xctx->mousex, xctx->mousey, 0, 0, NULL); + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ +} + +static void snapped_wire(double c_snap) +{ + double x, y; + if(!(xctx->ui_state & STARTWIRE)){ + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + xctx->mx_double_save = my_round(x / c_snap) * c_snap; + xctx->my_double_save = my_round(y / c_snap) * c_snap; + xctx->manhattan_lines = 1; + new_wire(PLACE, x, y); + new_wire(RUBBER, xctx->mousex_snap,xctx->mousey_snap); + } + else { + find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y); + new_wire(RUBBER, x, y); + new_wire(PLACE|END, x, y); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + if((xctx->ui_state & MENUSTART) && !tclgetboolvar("persistent_command") ) xctx->ui_state &= ~MENUSTART; /*CD*/ + } +} + +static int check_menu_start_commands(int state, double c_snap, int mx, int my) +{ + dbg(1, "check_menu_start_commands(): ui_state=%x, ui_state2=%x last_command=%d\n", + xctx->ui_state, xctx->ui_state2, xctx->last_command); + + if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTDESEL) ) { + if(xctx->ui_state & DESEL_CLICK) { + unselect_at_mouse_pos(mx, my); + } else { /* unselect by area */ + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } + return 1; + } + if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT)) { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT2)) { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTMOVE)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* stretch nets that land on selected instance pins if connect_by_kissing == 2 */ + /* select_attached_nets(); */ + move_objects(START,0,0,0); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCOPY)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return 0; + if( state & ShiftMask) { + snapped_wire(c_snap); + } else { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } + + /* + * xctx->mx_double_save=xctx->mousex_snap; + * xctx->my_double_save=xctx->mousey_snap; + * new_wire(PLACE, xctx->mousex_snap, xctx->mousey_snap); + * xctx->ui_state &=~MENUSTART; + */ + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTSNAPWIRE)) { + snapped_wire(c_snap); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTLINE)) { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return 0; + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + + /* + * xctx->mx_double_save=xctx->mousex_snap; + * xctx->my_double_save=xctx->mousey_snap; + * new_line(PLACE, xctx->mousex_snap, xctx->mousey_snap); + * xctx->ui_state &=~MENUSTART; + */ + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTRECT)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTPOLYGON)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTARC)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTCIRCLE)) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + return 1; + } + else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTZOOM)) { + zoom_rectangle(START); + return 1; + } + return 0; +} + +static int add_wire_from_inst(Selected *sel, double mx, double my) +{ + int res = 0; + int prev_state = xctx->ui_state; + int i, type = sel->type; + double pinx0, piny0; + if(type == ELEMENT) { + int n = sel->n; + xSymbol *symbol = xctx->sym + xctx->inst[n].ptr; + int npin = symbol->rects[PINLAYER]; + for(i = 0; i < npin; ++i) { + get_inst_pin_coord(n, i, &pinx0, &piny0); + if(pinx0 == mx && piny0 == my) { + break; + } + } + if(i < npin) { + dbg(1, "pin: %g %g\n", pinx0, piny0); + unselect_all(1); + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + res = 1; + } + } + return res; +} + +static int add_wire_from_wire(Selected *sel, double mx, double my) +{ + int res = 0; + int prev_state = xctx->ui_state; + int type = sel->type; + if(type == WIRE) { + int n = sel->n; + double x1 = xctx->wire[n].x1; + double y1 = xctx->wire[n].y1; + double x2 = xctx->wire[n].x2; + double y2 = xctx->wire[n].y2; + if( (mx == x1 && my == y1) || (mx == x2 && my == y2) ) { + unselect_all(1); + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + res = 1; + } + } + return res; +} + +/* sets xctx->shape_point_selected */ +static int edit_line_point(int state) +{ + int line_n = -1, line_c = -1; + dbg(1, "1 Line selected\n"); + line_n = xctx->sel_array[0].n; + line_c = xctx->sel_array[0].col; + /* lineangle point: Check is user is clicking a control point of a lineangle */ + if(line_n >= 0) { + xLine *p = &xctx->line[line_c][line_n]; + + xctx->need_reb_sel_arr=1; + if(xctx->mousex_snap == p->x1 && xctx->mousey_snap == p->y1) { + xctx->shape_point_selected = 1; + p->sel = SELECTED1; + } + else if(xctx->mousex_snap == p->x2 && xctx->mousey_snap == p->y2) { + xctx->shape_point_selected = 1; + p->sel = SELECTED2; + } + if(xctx->shape_point_selected) { + /* move one line selected point */ + if(!(state & (ControlMask | ShiftMask))){ + /* xctx->push_undo(); */ + move_objects(START,0,0,0); + return 1; + } + } /* if(xctx->shape_point_selected) */ + } /* if(line_n >= 0) */ + return 0; +} + +/* sets xctx->shape_point_selected */ +static int edit_wire_point(int state) +{ + int wire_n = -1; + dbg(1, "edit_wire_point, ds = %g\n", xctx->cadhalfdotsize); + wire_n = xctx->sel_array[0].n; + /* wire point: Check is user is clicking a control point of a wire */ + if(wire_n >= 0) { + xWire *p = &xctx->wire[wire_n]; + + xctx->need_reb_sel_arr=1; + if(xctx->mousex_snap == p->x1 && xctx->mousey_snap == p->y1) { + xctx->shape_point_selected = 1; + p->sel = SELECTED1; + } + else if(xctx->mousex_snap == p->x2 && xctx->mousey_snap == p->y2) { + xctx->shape_point_selected = 1; + p->sel = SELECTED2; + } + if(xctx->shape_point_selected) { + /* move one wire selected point */ + if(!(state & (ControlMask | ShiftMask))){ + /* xctx->push_undo(); */ + move_objects(START,0,0,0); + return 1; + } + } /* if(xctx->shape_point_selected) */ + } /* if(wire_n >= 0) */ + return 0; +} + +/* sets xctx->shape_point_selected */ +static int edit_rect_point(int state) +{ + int rect_n = -1, rect_c = -1; + dbg(1, "1 Rectangle selected\n"); + rect_n = xctx->sel_array[0].n; + rect_c = xctx->sel_array[0].col; + /* rectangle point: Check is user is clicking a control point of a rectangle */ + if(rect_n >= 0) { + double ds = xctx->cadhalfdotsize * 2; + xRect *p = &xctx->rect[rect_c][rect_n]; + + xctx->need_reb_sel_arr=1; + if(POINTINSIDE(xctx->mousex, xctx->mousey, p->x1, p->y1, p->x1 + ds, p->y1 + ds)) { + xctx->shape_point_selected = 1; + p->sel = SELECTED1; + } + else if(POINTINSIDE(xctx->mousex, xctx->mousey, p->x2 - ds, p->y1, p->x2, p->y1 + ds)) { + xctx->shape_point_selected = 1; + p->sel = SELECTED2; + } + else if(POINTINSIDE(xctx->mousex, xctx->mousey, p->x1, p->y2 - ds, p->x1 + ds, p->y2)) { + xctx->shape_point_selected = 1; + p->sel = SELECTED3; + } + else if(POINTINSIDE(xctx->mousex, xctx->mousey, p->x2 - ds, p->y2 - ds, p->x2, p->y2)) { + xctx->shape_point_selected = 1; + p->sel = SELECTED4; + } + if(xctx->shape_point_selected) { + /* move one rectangle selected point */ + if(!(state & (ControlMask | ShiftMask))){ + /* xctx->push_undo(); */ + move_objects(START,0,0,0); + return 1; + } + } /* if(xctx->shape_point_selected) */ + } /* if(rect_n >= 0) */ + return 0; +} + +/* sets xctx->shape_point_selected */ +static int edit_polygon_point(int state) +{ + int poly_n = -1, poly_c = -1; + dbg(1, "1 Polygon selected\n"); + poly_n = xctx->sel_array[0].n; + poly_c = xctx->sel_array[0].col; + /* polygon point: Check is user is clicking a control point of a polygon */ + if(poly_n >= 0) { + int i; + double ds = xctx->cadhalfdotsize; + int c = poly_c; + int n = poly_n; + xPoly *p = &xctx->poly[c][n]; + + xctx->need_reb_sel_arr=1; + for(i = 0; i < p->points; i++) { + if( + POINTINSIDE(xctx->mousex, xctx->mousey, p->x[i] - ds, p->y[i] - ds, + p->x[i] + ds, p->y[i] + ds) + ) { + dbg(1, "selecting point %d\n", i); + p->selected_point[i] = 1; + xctx->shape_point_selected = 1; + break; + } + } + if(xctx->shape_point_selected) { + int j; + int points = p->points; + + /* add a new polygon/bezier point after selected one and start moving it*/ + if(state & ShiftMask) { + xctx->push_undo(); + points++; + my_realloc(_ALLOC_ID_, &p->x, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &p->y, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &p->selected_point, sizeof(unsigned short) * points); + p->selected_point[i] = 0; + for(j = points - 2; j > i; j--) { + p->x[j + 1] = p->x[j]; + p->y[j + 1] = p->y[j]; + p->selected_point[j + 1] = p->selected_point[j]; + } + p->selected_point[i + 1] = 1; + p->x[i + 1] = p->x[i]; + p->y[i + 1] = p->y[i]; + p->points = points; + p->sel = SELECTED1; + move_objects(START,0,0,0); + return 1; + } + /* delete polygon/bezier selected point */ + else if(points > 2 && state & ControlMask) { + xctx->push_undo(); + points--; + for(j = i ; j < points ; j++) { + p->x[j] = p->x[j + 1]; + p->y[j] = p->y[j + 1]; + p->selected_point[j] = p->selected_point[j + 1]; + } + my_realloc(_ALLOC_ID_, &p->x, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &p->y, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &p->selected_point, sizeof(unsigned short) * points); + p->points = points; + p->sel = SELECTED; + return 1; + /* move one polygon/bezier selected point */ + } else if(!(state & (ControlMask | ShiftMask))){ + /* xctx->push_undo(); */ + p->sel = SELECTED1; + move_objects(START,0,0,0); + return 1; + } + } /* if(xctx->shape_point_selected) */ + } /* if(poly_n >= 0) */ + return 0; +} + +static void context_menu_action(double mx, double my) +{ + int ret; + const char *status; + int prev_state; + xctx->semaphore++; + status = tcleval("context_menu"); + xctx->semaphore--; + if(!status) return; + ret = atoi(status); + switch(ret) { + case 1: + start_place_symbol(); + break; + case 2: + prev_state = xctx->ui_state; + start_wire(mx, my); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + break; + case 3: + prev_state = xctx->ui_state; + start_line(mx, my); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + break; + case 4: + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,mx, my); + break; + case 5: + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, mx, my); + break; + case 6: /* place text */ + xctx->last_command = 0; + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + if(place_text(0, mx, my)) { /* 1 = draw text */ + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_TEXT; + } + break; + case 7: /* cut selection into clipboard */ + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + delete(1/* to_push_undo */); + } + break; + case 8: /* paste from clipboard */ + merge_file(2,".sch"); + break; + case 9: /* load most recent file */ + tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); + break; + case 10: /* edit attributes */ + edit_property(0); + break; + case 11: /* edit attributes in editor */ + edit_property(1); + break; + case 12: + descend_schematic(0, 1, 1, 1); + break; + case 13: + descend_symbol(); + break; + case 14: + go_back(1); + break; + case 15: /* copy selection into clipboard */ + rebuild_selected_array(); + if(xctx->lastsel) { + save_selection(2); + } + break; + case 16: /* move selection */ + if(!(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } + break; + case 17: /* duplicate selection */ + if(!(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } + break; + case 18: /* delete selection */ + if(xctx->ui_state & SELECTION) delete(1/* to_push_undo */); + break; + case 19: /* place arc */ + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., mx, my); + break; + case 20: /* place circle */ + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., mx, my); + break; + case 21: /* abort & redraw */ + abort_operation(); + break; + default: + break; + } +} + +/* Mouse wheel events */ +static int handle_mouse_wheel(int event, int mx, int my, KeySym key, int button, int aux, int state) +{ + int graph_use_ctrl_key = tclgetboolvar("graph_use_ctrl_key"); + if(button==Button5 && state == 0 ) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return 1; + } + view_unzoom(CADZOOMSTEP); + return 0; + } + else if(button==Button4 && state == 0 ) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return 1; + } + view_zoom(CADZOOMSTEP); + return 0; + } + if(!graph_use_ctrl_key) { + if(button==Button4 && (state & ShiftMask) && !(state & Button2Mask)) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return 1; + } + xctx->xorigin+=-CADMOVESTEP*xctx->zoom/2.; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + else if(button==Button5 && (state & ShiftMask) && !(state & Button2Mask)) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return 1; + } + xctx->xorigin-=-CADMOVESTEP*xctx->zoom/2.; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + else if(button==Button4 && (state & ControlMask) && !(state & Button2Mask)) { + xctx->yorigin+=-CADMOVESTEP*xctx->zoom/2.; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + else if(button==Button5 && (state & ControlMask) && !(state & Button2Mask)) { + xctx->yorigin-=-CADMOVESTEP*xctx->zoom/2.; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + } + return 0; +} + +static void end_shape_point_edit(double c_snap) +{ + int save = xctx->modified; + double sx, sy; + dbg(1, "%g %g %g %g\n", + xctx->mx_double_save, xctx->my_double_save, xctx->mousex_snap, xctx->mousey_snap); + if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { + int k; + int n = xctx->sel_array[0].n; + int c = xctx->sel_array[0].col; + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->poly[c][n].sel = SELECTED; + xctx->shape_point_selected = 0; + for(k=0; kpoly[c][n].points; ++k) { + xctx->poly[c][n].selected_point[k] = 0; + } + xctx->need_reb_sel_arr=1; + } + else if(xctx->lastsel == 1 && xctx->sel_array[0].type==xRECT) { + int n = xctx->sel_array[0].n; + int c = xctx->sel_array[0].col; + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->rect[c][n].sel = SELECTED; + xctx->shape_point_selected = 0; + xctx->need_reb_sel_arr=1; + } + else if(xctx->lastsel == 1 && xctx->sel_array[0].type==LINE) { + int n = xctx->sel_array[0].n; + int c = xctx->sel_array[0].col; + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->line[c][n].sel = SELECTED; + xctx->shape_point_selected = 0; + xctx->need_reb_sel_arr=1; + } + else if(xctx->lastsel == 1 && xctx->sel_array[0].type==WIRE) { + int n = xctx->sel_array[0].n; + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->wire[n].sel = SELECTED; + xctx->shape_point_selected = 0; + xctx->need_reb_sel_arr=1; + } + sx = my_round(xctx->mx_double_save / c_snap) * c_snap; + sy = my_round(xctx->my_double_save / c_snap) * c_snap; + + if(sx == xctx->mousex_snap && sy == xctx->mousey_snap) { + set_modify(save); + } +} + +#if defined(__unix__) && HAS_CAIRO==1 +static int grabscreen(const char *win_path, int event, int mx, int my, KeySym key, + int button, int aux, int state) +{ + static int grab_state = 0; + static int x1, y1, x2, y2; + int rmx, rmy, wmx, wmy; + unsigned int msq; + Window rw, cw; + XSetWindowAttributes winattr; + XGCValues gcv; + static GC gc = NULL; + static Window clientwin = 0; + static int first_motion = 1; + static int displayh = 0, displayw = 0; + static unsigned long white = 0; + + if(grab_state == 0 && event == ButtonPress && button == Button1) { + unsigned long gcvm = GCFunction | GCForeground; + + white = WhitePixel(display, screen_number); + displayh = DisplayHeight(display, screen_number); + displayw = DisplayWidth(display, screen_number); + + XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq); + gcv.function = GXxor; + gcv.foreground = white; + gc = XCreateGC(display, rw, gcvm, &gcv); + + winattr.override_redirect = True; + clientwin = XCreateWindow(display, rw, 0, 0, displayw, displayh, 0, screendepth, + InputOutput, visual, CWOverrideRedirect, &winattr); + XMapRaised(display,clientwin); + + x1 = rmx; + y1 = rmy; + dbg(1, "grabscreen(): got point1: %d %d\n", x1, y1); + grab_state = 1; + } + + if(grab_state == 1 && event == MotionNotify) { + static int xx1, xx2, yy1, yy2; + xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2; + INT_RECTORDER(xx1, yy1, xx2, yy2); + dbg(1, "Motion: %d %d %d %d\n", xx1, yy1, xx2, yy2); + if(!first_motion) { + XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2); + } + first_motion = 0; + XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq); + x2 = xx2 = rmx; + y2 = yy2 = rmy; + xx1 = x1; yy1 = y1; + INT_RECTORDER(xx1, yy1, xx2, yy2); + XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2); + } + + if(grab_state == 1 && event == ButtonRelease) { + int grab_w = 0, grab_h = 0; + cairo_surface_t *sfc = NULL, *subsfc = NULL; + png_to_byte_closure_t closure; + char *encoded_data = NULL; + size_t olength; + char *prop = NULL; + + + grab_state = 0; + first_motion = 1; + xctx->ui_state &= ~GRABSCREEN; + XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq); + x2 = rmx; + y2 = rmy; + INT_RECTORDER(x1, y1, x2, y2); + tclvareval("grab release ", xctx->top_path, ".drw", NULL); + if(x2 - x1 > 10 && y2 -y1 > 10) { + xctx->push_undo(); + grab_w = (x2 - x1 + 1); + grab_h = (y2 - y1 + 1); + dbg(1, "grabscreen(): grab area: %d %d - %d %d\n", x1, y1, x2, y2); + dbg(1, "grabscreen(): root w=%d, h=%d\n", displayw, displayh); + sfc = cairo_xlib_surface_create(display, rw, visual, displayw, displayh); + if(!sfc || cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) { + dbg(0, "grabscreen(): failure creating sfc\n"); + XFreeGC(display, gc); + XDestroyWindow(display, clientwin); + return 0; + } + dbg(1, "sfc: w=%d, h=%d\n", + cairo_xlib_surface_get_width(sfc), + cairo_xlib_surface_get_height(sfc)); + subsfc = cairo_surface_create_for_rectangle(sfc, x1, y1, grab_w, grab_h); + if(!subsfc || cairo_surface_status(subsfc) != CAIRO_STATUS_SUCCESS) { + dbg(0, "grabscreen(): failure creating subsfc\n"); + cairo_surface_destroy(sfc); + XFreeGC(display, gc); + XDestroyWindow(display, clientwin); + return 0; + } + closure.buffer = NULL; + closure.size = 0; + closure.pos = 0; + cairo_surface_write_to_png_stream(subsfc, png_writer, &closure); + cairo_surface_destroy(subsfc); + cairo_surface_destroy(sfc); + closure.size = closure.pos; + dbg(1, "closure.size = %ld\n", closure.size); + encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0); + dbg(1, "olength = %ld\n", olength); + my_free(_ALLOC_ID_, &closure.buffer); + my_mstrcat(_ALLOC_ID_, &prop, "flags=image,unscaled\nalpha=0.8\nimage_data=", encoded_data, NULL); + my_free(_ALLOC_ID_, &encoded_data); + storeobject(-1, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap + grab_w, xctx->mousey_snap + grab_h, + xRECT, GRIDLAYER, SELECTED, prop); + my_free(_ALLOC_ID_, &prop); + xctx->need_reb_sel_arr=1; + rebuild_selected_array(); + move_objects(START,0,0,0); + xctx->ui_state |= START_SYMPIN; + } + XFreeGC(display, gc); + XDestroyWindow(display, clientwin); + } + return 1; +} +#endif + +void unselect_attached_floaters(void) +{ + int c, i, found = 0; + for(c = 0; c < cadlayers; c++) { + for(i = 0; i < xctx->rects[c]; i++) { + if(get_tok_value(xctx->rect[c][i].prop_ptr, "name", 0)[0]) { + found = 1; + select_box(c, i, 0, 1, 1); + } + } + for(i = 0; i < xctx->lines[c]; i++) { + if(get_tok_value(xctx->line[c][i].prop_ptr, "name", 0)[0]) { + found = 1; + select_line(c, i, 0, 1, 1); + } + } + + for(i = 0; i < xctx->polygons[c]; i++) { + if(get_tok_value(xctx->poly[c][i].prop_ptr, "name", 0)[0]) { + found = 1; + select_polygon(c, i, 0, 1, 1); + } + } + for(i = 0; i < xctx->arcs[c]; i++) { + if(get_tok_value(xctx->arc[c][i].prop_ptr, "name", 0)[0]) { + found = 1; + select_arc(c, i, 0, 1, 1); + } + } + } + for(i = 0; i < xctx->wires; i++) { + if(get_tok_value(xctx->wire[i].prop_ptr, "name", 0)[0]) { + found = 1; + select_wire(i, 0, 1, 1); + } + } + for(i = 0; i < xctx->texts; i++) { + if(get_tok_value(xctx->text[i].prop_ptr, "name", 0)[0]) { + found = 1; + select_text(i, 0, 1, 1); + } + } + if(found) { + rebuild_selected_array(); + draw_selection(xctx->gc[SELLAYER],0); + } +} + +static void handle_enter_notify(int draw_xhair, int crosshair_size) +{ + struct stat buf; + dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); + xctx->mouse_inside = 1; + if(draw_xhair) { + if(crosshair_size == 0) { + tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); + } + } else + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + /* xschem window *sending* selected objects + when the pointer comes back in abort copy operation since it has been done + in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ + if(stat(sel_file, &buf) && (xctx->ui_state & STARTCOPY) ) + { + copy_objects(ABORT); + unselect_all(1); + } + /* xschem window *receiving* selected objects selection cleared --> abort */ + else if(xctx->paste_from == 1 && stat(sel_file, &buf) && (xctx->ui_state & STARTMERGE)) { + abort_operation(); + } + /*xschem window *receiving* selected objects + * no selected objects and selection file exists --> start merge */ + else if(xctx->lastsel == 0 && !stat(sel_file, &buf)) { + xctx->mousex_snap = 490; + xctx->mousey_snap = -340; + merge_file(1, ".sch"); + } + + return; +} + +static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, + int mx, int my, int aux, int draw_xhair, int enable_stretch, int snap_cursor, int wire_draw_active) +{ + char str[PATH_MAX + 100]; + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(draw_xhair) { + draw_crosshair(1, state); /* when moving mouse: first action is delete crosshair, will be drawn later */ + } + if(snap_cursor) draw_snap_cursor(1); /* clear */ + /* pan schematic */ + if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); + + if(xctx->semaphore >= 2) { + if(draw_xhair) { + draw_crosshair(2, state); /* locked UI: draw new crosshair and break out */ + } + if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(2); /* redraw */ + return; + } + + /* update status bar messages */ + if(xctx->ui_state) { + if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", + xctx->mousex_snap, xctx->mousey_snap, + xctx->lastsel , + xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save + ); + statusmsg(str,1); + } + } + + /* determine direction of a rectangle selection (or unselection with ALT key) */ + if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { + /* Unselect by area : determine direction */ + if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,0); + /* select by area : determine direction */ + } else if(state & Button1Mask) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,1); + } + } + /* draw objects being moved */ + if(xctx->ui_state & STARTMOVE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + move_objects(RUBBER,0,0,0); + } + + /* draw objects being copied */ + if(xctx->ui_state & STARTCOPY) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + copy_objects(RUBBER); + } + + /* draw moving objects being inserted, wires, arcs, lines, rectangles, polygons or zoom box */ + redraw_w_a_l_r_p_z_rubbers(0); + + /* start of a mouse area select. Button1 pressed. No shift pressed + * Do not start an area select if user is dragging a polygon/bezier point */ + if(!(xctx->ui_state & STARTPOLYGON) && (state&Button1Mask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & STARTPAN) && !(SET_MODMASK) && !xctx->shape_point_selected && + !(state & ShiftMask) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) + { + if(mx != xctx->mx_save || my != xctx->my_save) { + xctx->mouse_moved = 1; + if(!xctx->drag_elements) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + xctx->onetime=1; + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(xctx->onetime) { + unselect_all(1); /* 20171026 avoid multiple calls of unselect_all() */ + xctx->onetime=0; + } + xctx->ui_state|=STARTSELECT; /* set it again cause unselect_all(1) clears it... */ + } + } + } + } + /* Unselect by area */ + if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && + !(state & ShiftMask) && + !(xctx->ui_state & STARTPAN) && + !xctx->shape_point_selected && + !(xctx->ui_state & STARTSELECT) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ + select_rect(enable_stretch, START,0); + } + /* Select by area. Shift pressed */ + else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !xctx->shape_point_selected && + !xctx->drag_elements && !(xctx->ui_state & STARTPAN) ) { + if(mx != xctx->mx_save || my != xctx->my_save) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(!xctx->already_selected) { + select_object(X_TO_XSCHEM(xctx->mx_save), + Y_TO_XSCHEM(xctx->my_save), 0, 0, NULL); /* remove near obj if dragging */ + } + rebuild_selected_array(); + } + } + } + if(draw_xhair) { + draw_crosshair(2, state); /* what = 2(draw) */ + } + if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(2); /* redraw */ + + return; +} + +static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, + int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, + int cadence_compat, int wire_draw_active, int snap_cursor) +{ + char str[PATH_MAX + 100]; + switch (key) { + case '0' ... '4': + if(state == 0) { /* toggle pin logic level */ + if(xctx->semaphore >= 2) break; + if(key == '4') logic_set(-1, 1, NULL); + else logic_set((int)key - '0', 1, NULL); + } + else if(state==ControlMask) { /* choose layer */ + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); + + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); + } + break; + + case '5': + if(rstate == 0) { /* 20110112 display only probes */ + xctx->only_probes = !xctx->only_probes; + tclsetboolvar("only_probes", xctx->only_probes); + toggle_only_probes(); + } /* /20110112 */ + break; + + case '6' ... '9': + if(state==ControlMask) { /* choose layer */ + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); + + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); + } + break; + + case 'a': + if(rstate == 0) { /* make symbol */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {do you want to make symbol view ?}"); + if(strcmp(tclresult(),"ok")==0) + { + save_schematic(xctx->sch[xctx->currsch], 0); + make_symbol(); + } + } + else if(rstate == ControlMask) { /* select all */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + select_all(); + } + break; + + case 'A': + if(rstate == 0) { /* toggle show netlist */ + int net_s; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + net_s = tclgetboolvar("netlist_show"); + net_s = !net_s; + if(net_s) { + tcleval("alert_ { enabling show netlist window} {}"); + tclsetvar("netlist_show","1"); + } + else { + tcleval("alert_ { disabling show netlist window } {}"); + tclsetvar("netlist_show","0"); + } + } + else if(rstate == ControlMask) { /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'b': + if(rstate==0) { /* merge schematic */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ + } + else if(rstate==ControlMask) { /* toggle show text in symbol */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->sym_txt =!xctx->sym_txt; + if(xctx->sym_txt) { + /* tcleval("alert_ { enabling text in symbol} {}"); */ + tclsetvar("sym_txt","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling text in symbol} {}"); */ + tclsetvar("sym_txt","0"); + draw(); + } + } + else if(EQUAL_MODMASK) { /* hide/show instance details */ + if(xctx->semaphore >= 2) break; + xctx->hide_symbols++; + if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; + tclsetintvar("hide_symbols", xctx->hide_symbols); + draw(); + } + break; + + case 'B': + if(rstate == 0) { /* edit schematic header/license */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("update_schematic_header"); + } + else if(rstate == ControlMask) { /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'c': + /* duplicate selection */ + if(rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + } + /* copy selection into clipboard */ + else if(rstate == ControlMask) { + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + } + } + /* duplicate selection */ + else if(EQUAL_MODMASK && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(xctx->semaphore >= 2) break; + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + } + break; + + case 'C': + if(/* !xctx->ui_state && */ rstate == 0) { /* place arc */ + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTARC; + } + } + else if(/* !xctx->ui_state && */ rstate == ControlMask) { /* place circle */ + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCIRCLE; + } + } + break; + + case 'd': + if(rstate == 0) { /* unselect object under the mouse */ + if(infix_interface) { + unselect_at_mouse_pos(mx, my); + } else { + xctx->ui_state |= (MENUSTART | DESEL_CLICK); + xctx->ui_state2 = MENUSTARTDESEL; + } + } + else if(rstate == ControlMask) { /* delete files */ + if(xctx->semaphore >= 2) break; + delete_files(); + } + break; + + case 'D': + if(rstate == 0) { /* unselect by area */ + if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { + if(infix_interface) { + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTDESEL; + } + } + } + break; + + case 'e': + if(rstate == 0) { /* descend to schematic */ + if(xctx->semaphore >= 2) break; + descend_schematic(0, 1, 1, 1); + } + else if(rstate == ControlMask) { + if(xctx->semaphore >= 2) break; + go_back(1); + } + else if(EQUAL_MODMASK) { /* edit schematic in new window */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + /* schematic_in_new_window(0, 1, 0); */ + tcleval("open_sub_schematic"); + xctx->semaphore = save; + } + break; + + case 'E': + if(EQUAL_MODMASK) { /* edit schematic in new window - new xschem process */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + schematic_in_new_window(1, 1, 0); + xctx->semaphore = save; + } + break; + + case 'f': + if(rstate == 0) { /* full zoom */ + int flags = 1; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(tclgetboolvar("zoom_full_center")) flags |= 2; + zoom_full(1, 0, flags, 0.97); + } + else if(rstate == ControlMask) { /* search */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("property_search"); + } + else if(EQUAL_MODMASK) { /* flip objects around their anchor points 20171208 */ + if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'F': + if(rstate == 0) { /* flip */ + if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + } + else if(rstate == ControlMask ) { /* full zoom selection */ + if(xctx->ui_state == SELECTION) { + zoom_full(1, 1, 3, 0.97); + } + } + break; + + case 'g': + if(rstate==0) { /* half snap factor */ + set_snap(c_snap / 2.0); + change_linewidth(-1.); + draw(); + } + else if(rstate==ControlMask) { /* set snap factor 20161212 */ + my_snprintf(str, S(str), + "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", + CADSNAP, c_snap, c_snap); + tcleval(str); + } + else if(EQUAL_MODMASK) { /* highlight net and send to viewer */ + int tool = 0; + int exists = 0; + char *tool_name = NULL; + + if(xctx->semaphore >= 2) break; + tcleval("winfo exists .graphdialog"); + if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; + else if(xctx->graph_lastsel >=0 && + xctx->rects[GRIDLAYER] > xctx->graph_lastsel && + xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { + tool = XSCHEM_GRAPH; + } + tcleval("info exists sim"); + if(tclresult()[0] == '1') exists = 1; + xctx->enable_drill = 0; + if(exists) { + if(!tool) { + tool = tclgetintvar("sim(spicewave,default)"); + my_snprintf(str, PATH_MAX + 100, "sim(spicewave,%d,name)", tool); + my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); + dbg(1,"callback(): tool_name=%s\n", tool_name); + if(strstr(tool_name, "Gaw")) tool=GAW; + else if(strstr(tool_name, "Bespice")) tool=BESPICE; + my_free(_ALLOC_ID_, &tool_name); + } + } + if(tool) { + hilight_net(tool); + redraw_hilights(0); + } + Tcl_ResetResult(interp); + } + break; + + case 'G': + if(rstate == 0) { /* double snap factor */ + set_snap(c_snap * 2.0); + change_linewidth(-1.); + draw(); + } + break; + + case 'h': + if(rstate==ControlMask ) { /* go to http link */ + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); + xctx->semaphore = savesem; + } + else if (rstate == 0) { /* horizontally constrained drag 20171023 */ + if ( xctx->constr_mv == 1 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 1" ); + xctx->constr_mv = 1; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + } + else if (EQUAL_MODMASK) { + tcleval("schpins_to_sympins"); + } + break; + + case 'H': + if(rstate == 0) { /* attach labels to selected instances */ + attach_labels_to_inst(1); + } + else if (rstate == ControlMask) { /* create schematic and symbol from selected components */ + make_schematic_symbol_from_sel(); + } + break; + + case 'i': + if(rstate==0) { /* descend to symbol */ + if(xctx->semaphore >= 2) break; + descend_symbol(); + } + else if(rstate == ControlMask) { /* insert sym */ + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } + else if(EQUAL_MODMASK) { /* edit symbol in new window */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(0); + xctx->semaphore = save; + } + break; + + case 'I': + if(rstate == 0) { /* insert sym */ + if(xctx->semaphore >= 2) break; + start_place_symbol(); + } + else if(EQUAL_MODMASK) { /* edit symbol in new window - new xschem process */ + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(1); + xctx->semaphore = save; + } + break; + + case 'j': + if(rstate==0 ) { /* print list of highlight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(1); + } + else if(rstate==ControlMask) { /* create ipins from highlight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(0); + } + else if(EQUAL_MODMASK) { /* create labels without i prefix from hilight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(4); + } + else if( SET_MODMASK && (state & ControlMask) ) { /* print list of highlight net with label expansion */ + print_hilight_net(3); + } + break; + + case 'J': + if(rstate == 0) { + create_plot_cmd(); + } + else if(SET_MODMASK ) { /* create labels with i prefix from hilight nets */ + if(xctx->semaphore >= 2) break; + print_hilight_net(2); + } + break; + + case 'k': + if(rstate==0) { /* hilight net */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=0; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + } + else if(EQUAL_MODMASK) { /* select whole net (all attached wires/labels/pins) */ + select_hilight_net(); + } + else if(rstate==ControlMask) { /* unhilight net */ + if(xctx->semaphore >= 2) break; + unhilight_net(); + } + break; + + case 'K': + if(rstate == 0) { /* delete hilighted nets */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=0; + clear_all_hilights(); + /* undraw_hilight_net(1); */ + draw(); + } + else if(rstate == ControlMask) { /* hilight net drilling thru elements with 'propag=' prop set on pins */ + if(xctx->semaphore >= 2) break; + xctx->enable_drill=1; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + } + break; + + case 'l': + if(/* !xctx->ui_state && */ rstate == 0) { /* start line */ + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) break; + if(infix_interface) { + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTLINE; + } + } + else if(rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ + if(xctx->semaphore >= 2) break; + create_sch_from_sym(); + } + else if(EQUAL_MODMASK) { /* add pin label*/ + place_net_label(1); + } + break; + + case 'L': + if(rstate == 0) { /* toggle orthogonal routing */ + if(tclgetboolvar("orthogonal_wiring")){ + tclsetboolvar("orthogonal_wiring", 0); + xctx->manhattan_lines = 0; + } else { + tclsetboolvar("orthogonal_wiring", 1); + } + redraw_w_a_l_r_p_z_rubbers(1); + } + else if(EQUAL_MODMASK ) { /* add pin label*/ + place_net_label(0); + } + break; + + case 'm': + /* Move selection */ + if(rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* move selection stretching attached nets */ + else if(rstate == ControlMask && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* Move selection adding wires to moved pins */ + else if(EQUAL_MODMASK && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + break; + + case 'M': + /* Move selection adding wires to moved pins */ + if((rstate == 0) && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ + else if(rstate == ControlMask && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) { + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + } + break; + + case 'n': + if(rstate==0) { /* hierarchical netlist */ + if(xctx->semaphore >= 2) break; + tcleval("xschem netlist -erc"); + } + else if(rstate == ControlMask) { /* clear schematic */ + if(xctx->semaphore >= 2) break; + tcleval("xschem clear SCHEMATIC"); + } + break; + + case 'N': + if(rstate == 0) { /* current level only netlist */ + int err = 0; + yyparse_error = 0; + if(xctx->semaphore >= 2) break; + unselect_all(1); + if( set_netlist_dir(0, NULL) ) { + dbg(1, "callback(): -------------\n"); + if(xctx->netlist_type == CAD_SPICE_NETLIST) + err = global_spice_netlist(0, 1); + else if(xctx->netlist_type == CAD_VHDL_NETLIST) + err = global_vhdl_netlist(0, 1); + else if(xctx->netlist_type == CAD_VERILOG_NETLIST) + err = global_verilog_netlist(0, 1); + else if(xctx->netlist_type == CAD_TEDAX_NETLIST) + err = global_tedax_netlist(0, 1); + else + tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " + "-message {Please Set netlisting mode (Options menu)}"); + dbg(1, "callback(): -------------\n"); + } + else { + if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); + else dbg(0, "Can not write into the netlist directory. Please check"); + err = 1; + } + if(err) { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); + } + } else { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); + } + } + + } + else if(rstate == ControlMask ) { /* clear symbol */ + if(xctx->semaphore >= 2) break; + tcleval("xschem clear SYMBOL"); + } + break; + + case 'o': + if(rstate == ControlMask) { /* load */ + if(xctx->semaphore >= 2) break; + ask_new_file(); + xctx->semaphore--; + tcleval("load_additional_files"); + xctx->semaphore++; + } + break; + + case 'O': + if(rstate == ControlMask ) { /* load most recent tile */ + tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); + } + else if(rstate == 0) { /* toggle light/dark colorscheme 20171113 */ + int d_c; + d_c = tclgetboolvar("dark_colorscheme"); + d_c = !d_c; + tclsetboolvar("dark_colorscheme", d_c); + tclsetdoublevar("dim_value", 0.0); + tclsetdoublevar("dim_bg", 0.0); + build_colors(0.0, 0.0); + draw(); + } + break; + + case 'p': + if(EQUAL_MODMASK) { /* add symbol pin */ + xctx->push_undo(); + unselect_all(1); + storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, + xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); + xctx->need_reb_sel_arr=1; + rebuild_selected_array(); + move_objects(START,0,0,0); + xctx->ui_state |= START_SYMPIN; + } + else if( !(xctx->ui_state & STARTPOLYGON) && rstate==0) { /* start polygon */ + if(xctx->semaphore >= 2) break; + dbg(1, "callback(): start polygon\n"); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTPOLYGON; + } + } + break; + + case 'P': + if(rstate == 0) { /* pan, other way to. */ + xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; + xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case 'q': + if(rstate==ControlMask) { /* quit xschem */ + if(xctx->semaphore >= 2) break; + /* must be set to zero, otherwise switch_tab/switch_win does not proceed + * and these are necessary when closing tabs/windows */ + xctx->semaphore = 0; + tcleval("quit_xschem"); + } + else if(rstate==0) { /* edit attributes */ + if(xctx->semaphore >= 2) break; + edit_property(0); + } + else if(EQUAL_MODMASK) { /* edit .sch file (DANGER!!) */ + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel==0 ) { + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + tcleval(str); + } + else if(xctx->sel_array[0].type==ELEMENT) { + my_snprintf(str, S(str), "edit_file {%s}", + abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); + tcleval(str); + + } + } + break; + + case 'Q': + if(rstate == 0) { /* edit attributes in editor */ + if(xctx->semaphore >= 2) break; + edit_property(1); + } + else if(rstate == ControlMask) { /* view attributes */ + edit_property(2); + } + break; + + case 'r': + if(/* !xctx->ui_state && */ rstate==0) { /* start rect */ + dbg(1, "callback(): start rect\n"); + if(xctx->semaphore >= 2) break; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTRECT; + } + } + else if((rstate == ControlMask) && cadence_compat) { /* simulate (for cadence users) */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + } + else if(SET_MODMASK) { /* reload */ + if(xctx->semaphore >= 2) break; + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Are you sure you want to reload from disk?}"); + if(strcmp(tclresult(),"ok")==0) { + char filename[PATH_MAX]; + unselect_all(1); + remove_symbols(); + my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); + load_schematic(1, filename, 1, 1); + draw(); + } + } + else if(EQUAL_MODMASK) { /* rotate objects around their anchor points 20171208 */ + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'R': + if(rstate == 0) { /* rotate */ + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(END,0,0,0); + } + + } + break; + + case 's': + if((rstate == 0) && !cadence_compat) { /* simulate (original keybind) */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + } + else if(/* !xctx->ui_state && */ (rstate == 0) && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ + if(xctx->semaphore >= 2) break; + snapped_wire(c_snap); + } + else if(rstate == ControlMask ){ /* save 20121201 */ + if(xctx->semaphore >= 2) break; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + /* check if unnamed schematic, use saveas in this case */ + if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { + saveas(NULL, SCHEMATIC); + } else { + save(1, 0); + } + } + else if(SET_MODMASK && (state & ControlMask) ) { /* save as symbol */ + if(xctx->semaphore >= 2) break; + saveas(NULL, SYMBOL); + } + break; + + case 'S': + if(rstate == 0) { /* change element order */ + if(xctx->semaphore >= 2) break; + change_elem_order(-1); + } + else if(rstate == ControlMask) { /* save as schematic */ + if(xctx->semaphore >= 2) break; + saveas(NULL, SCHEMATIC); + } + break; + + case 't': + if(rstate == 0) { /* place text */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->last_command = 0; + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_TEXT; + } + } + else if(rstate & ControlMask) { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + } + break; + + case 'T': + if(rstate == 0) { /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ + toggle_ignore(); + } + break; + + case 'u': + if(rstate==0) { /* undo */ + if(xctx->semaphore >= 2) break; + xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ + draw(); + } + else if(EQUAL_MODMASK) { /* align to grid */ + if(xctx->semaphore >= 2) break; + xctx->push_undo(); + round_schematic_to_grid(c_snap); + set_modify(1); + if(tclgetboolvar("autotrim_wires")) trim_wires(); + xctx->prep_hash_inst=0; + xctx->prep_hash_wires=0; + xctx->prep_net_structs=0; + xctx->prep_hi_structs=0; + + draw(); + } + else if(rstate==ControlMask) { /* testmode */ + unselect_attached_floaters(); + } + + break; + + case 'U': + if(rstate == 0) { /* redo */ + if(xctx->semaphore >= 2) break; + xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ + draw(); + } + break; + + case 'v': + if(rstate==0) { /* vertically constrained drag 20171023 */ + if ( xctx->constr_mv == 2 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 2" ); + xctx->constr_mv = 2; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + } + else if(rstate == ControlMask) { /* paste from clipboard */ + if(xctx->semaphore >= 2) break; + merge_file(2,".sch"); + } + else if(EQUAL_MODMASK) { /* vertical flip objects around their anchor points */ + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(FLIP|ROTATELOCAL); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + } + break; + + case 'V': + if(rstate == 0) { /* vertical flip */ + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE); + copy_objects(ROTATE); + copy_objects(FLIP); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + } + else if(rstate == ControlMask) { /* toggle spice/vhdl netlist */ + xctx->netlist_type++; + if(xctx->netlist_type==6) xctx->netlist_type=1; + set_tcl_netlist_type(); + draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ + } + break; + + case 'w': + if(/* !xctx->ui_state && */ rstate==0) { /* place wire. */ + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) break; + + if(infix_interface) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTWIRE; + if(prev_state & STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + } + else if(rstate == ControlMask) { /* close current schematic */ + int save_sem; + if(xctx->semaphore >= 2) break; + save_sem = xctx->semaphore; + tcleval("xschem exit"); + xctx->semaphore = save_sem; + } + break; + + case 'W': + if(/* !xctx->ui_state && */ (rstate == 0) && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */ + if(xctx->semaphore >= 2) break; + snapped_wire(c_snap); + } + break; + + case 'x': + if(rstate == 0) { /* new cad session */ + new_xschem_process(NULL ,0); + } + else if(EQUAL_MODMASK) { /* toggle draw crosshair at mouse pos */ + if(tclgetboolvar("draw_crosshair")) { + tclsetvar("draw_crosshair", "0"); + } else { + tclsetvar("draw_crosshair", "1"); + } + draw(); + } + else if(rstate == ControlMask) { /* cut selection into clipboard */ + if(xctx->semaphore >= 2) break; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + delete(1/* to_push_undo */); + } + } + break; + + case 'X': + if(rstate == 0) { /* highlight discrepanciens between selected instance pin and net names */ + hilight_net_pin_mismatches(); + } + break; + + case 'y': + if(rstate == 0) { /* toggle stretching */ + enable_stretch = !enable_stretch; + tclsetboolvar("enable_stretch", enable_stretch); + } + break; + + case 'z': + if(rstate == 0 && !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) { /* zoom box */ + dbg(1, "callback(): zoom_rectangle call\n"); + zoom_rectangle(START); + } + else if(rstate==ControlMask) { /* zoom out */ + view_unzoom(0.0); + } + else if(EQUAL_MODMASK && cadence_compat) { /* toggle snap-cursor option */ + if(tclgetboolvar("snap_cursor")) { + tclsetvar("snap_cursor", "0"); + draw_snap_cursor(1); + xctx->closest_pin_found = 0; + xctx->prev_snapx = 0.0; + xctx->prev_snapy = 0.0; + } else { + tclsetvar("snap_cursor", "1"); + if(wire_draw_active) draw_snap_cursor(3); + } + } + break; + + case 'Z': + if(rstate == 0) { /* zoom in */ + view_zoom(0.0); + } + break; + + case ' ': + if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + + } else if(xctx->ui_state & STARTLINE) { + new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } else { + if(xctx->semaphore<2) { + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ + } + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + break; + + case '_': /* toggle change line width */ + if(!tclgetboolvar("change_lw")) { + tcleval("alert_ { enabling change line width} {}"); + tclsetvar("change_lw","1"); + } + else { + tcleval("alert_ { disabling change line width} {}"); + tclsetvar("change_lw","0"); + } + break; + + case '%': /* toggle draw grid */ + int dr_gr; + dr_gr = tclgetboolvar("draw_grid"); + dr_gr =!dr_gr; + if(dr_gr) { + /* tcleval("alert_ { enabling draw grid} {}"); */ + tclsetvar("draw_grid","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling draw grid} {}"); */ + tclsetvar("draw_grid","0"); + draw(); + } + break; + + case '$': + if( rstate == 0 ) { /* toggle pixmap saving */ + xctx->draw_pixmap =!xctx->draw_pixmap; + if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); + else tcleval("alert_ { disabling draw pixmap} {}"); + } + else if(state & ControlMask) { /* toggle window drawing */ + xctx->draw_window =!xctx->draw_window; + if(xctx->draw_window) { + tcleval("alert_ { enabling draw window} {}"); + tclsetvar("draw_window","1"); + } else { + tcleval("alert_ { disabling draw window} {}"); + tclsetvar("draw_window","0"); + } + } + break; + + case '=': + if(state & ControlMask) { /* toggle fill rectangles */ + int x; + xctx->fill_pattern++; + if(xctx->fill_pattern==2) xctx->fill_pattern=0; + + if(xctx->fill_pattern==1) { + tcleval("alert_ { Stippled pattern fill} {}"); + for(x=0;xfill_type[x]==2) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); + else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); + } + } + else if(xctx->fill_pattern==2) { + tcleval("alert_ { solid pattern fill} {}"); + for(x=0;xgcstipple[x],FillSolid); + } + else { + tcleval("alert_ { No pattern fill} {}"); + for(x=0;xgcstipple[x],FillStippled); + } + + draw(); + } + break; + + case '+': + if(state & ControlMask) { /* change line width */ + xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + } + break; + + case '-': + if(state & ControlMask) { /* change line width */ + xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); + if(xctx->lw < 0.0) xctx->lw = 0.0; + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + } + break; + + case XK_Return: + if((state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ + new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); + } + break; + + case XK_Escape: /* abort & redraw */ + if(xctx->semaphore < 2) { + abort_operation(); + } + /* stuff that can be done reentrantly ... */ + tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(xctx->ui_state2 & MENUSTARTWIRE) { + xctx->ui_state2 &= ~MENUSTARTWIRE; + } + if(snap_cursor) draw_snap_cursor(1); /* erase */ + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { + xctx->last_command &= ~STARTWIRE; + } + break; + + case XK_Delete: + if(xctx->ui_state & SELECTION) { /* delete selection */ + if(xctx->semaphore >= 2) break; + delete(1/* to_push_undo */); + } + break; + + case XK_Right: + if(state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->semaphore = 0; + tcleval("next_tab"); + xctx->semaphore = save; + } + else { /* left */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->xorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case XK_Left: + if(state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + if(xctx->semaphore >= 2) break; + xctx->semaphore = 0; + tcleval("prev_tab"); + xctx->semaphore = save; + } + else { /* right */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->xorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + } + break; + + case XK_Down: /* down */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->yorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + break; + + case XK_Up: /* up */ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + break; + } + xctx->yorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + break; + + case XK_BackSpace: /* back */ + if(xctx->semaphore >= 2) break; + go_back(1); + break; + +#if defined(__unix__) && HAS_CAIRO==1 + case XK_Print: + xctx->ui_state |= GRABSCREEN; + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); + break; +#endif + + case XK_Insert: + if(state == ShiftMask) { /* insert sym */ + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } + else { + if(xctx->semaphore >= 2) break; + start_place_symbol(); + } + break; + + case '*': + if(rstate == 0 ) { /* postscript print */ + if(xctx->semaphore >= 2) break; + ps_draw(7, 0, 0); + } + else if(rstate == ControlMask) {/* xpm print */ + if(xctx->semaphore >= 2) break; + print_image(); + } + else if(EQUAL_MODMASK) { /* svg print , 20121108 */ + if(xctx->semaphore >= 2) break; + svg_draw(); + } + break; + + case '&': /* check wire connectivity */ + if(xctx->semaphore >= 2) break; + xctx->push_undo(); + trim_wires(); + draw(); + break; + + case '\\': + if(state==0) { /* fullscreen */ + dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); + toggle_fullscreen(win_path); + } + break; + + case '>': + if(xctx->semaphore >= 2) break; + if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; + draw(); + break; + + case '<': + if(xctx->semaphore >= 2) break; + if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; + draw(); + break; + + /* toggle flat netlist (only spice) */ + case ':': + if(!tclgetboolvar("flat_netlist")) { + tcleval("alert_ { enabling flat netlist} {}"); + tclsetvar("flat_netlist","1"); + } + else { + tcleval("alert_ { set hierarchical netlist } {}"); + tclsetvar("flat_netlist","0"); + } + break; + + case '#': + if((state & ControlMask)) { + check_unique_names(1); + } + else { + check_unique_names(0); + } + break; + + case ';': + if(0 && (state & ControlMask)) { /* testmode */ + } + break; + + case '~': + if(0 && (state & ControlMask)) { /* testmode */ + } + break; + + case '|': + if(0 && (state & ControlMask)) { /* testmode */ + static int x = 0; + + if(x == 0) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } else if(x == 1) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } + x++; + x %= 2; + } + break; + + case '!': + if((state & ControlMask)) { + if(xctx->semaphore >= 2) break; + break_wires_at_pins(1); + } + else { + if(xctx->semaphore >= 2) break; + break_wires_at_pins(0); + } + break; + + default: + break; + } + + return; +} + +static void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, + double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux) +{ + dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); + int use_cursor_for_sel = tclgetintvar("use_cursor_for_selection"); + int excl = xctx->ui_state & (STARTWIRE | STARTRECT | STARTLINE | STARTPOLYGON | STARTARC); + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + /* terminate a schematic pan action */ + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + return; + } + + /* select instance and connected nets stopping at wire junctions */ + if(!excl && button == Button3 && state == ControlMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(1); + } + + /* break wire at mouse coordinates, move break point to nearest grid point */ + else if(!excl && button == Button3 && EQUAL_MODMASK && + !(state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); + } + /* break wire at mouse coordinates */ + else if(!excl && button == Button3 && EQUAL_MODMASK && + (state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); + } + /* select instance and connected nets NOT stopping at wire junctions */ + else if(!excl && button == Button3 && state == ShiftMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(0); + } + /* moved to Button3 release */ + /* + * else if(button == Button3 && state == 0 && xctx->semaphore <2) { + * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + * } + */ + + /* zoom rectangle by right clicking and drag */ + else if(!excl && button == Button3 && state == 0 && xctx->semaphore < 2) { + zoom_rectangle(START);return; + } + + /* Mouse wheel events */ + else if(handle_mouse_wheel(event, mx, my, key, button, aux, state)) return; + + /* terminate wire placement in snap mode */ + else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { + snapped_wire(c_snap); + } + /* Alt - Button1 click to unselect */ + else if(button==Button1 && (SET_MODMASK) ) { + unselect_at_mouse_pos(mx, my); + } + + /* Middle button press (Button2) will pan the schematic. */ + else if(button==Button2 && (state == 0)) { + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + + /* button1 click to select another instance while edit prop dialog open */ + else if(button==Button1 && xctx->semaphore >= 2) { + if(tcleval("winfo exists .dialog.textinput")[0] == '1') { /* proc text_line */ + tcleval(".dialog.f1.b1 invoke"); + return; + } else if(tcleval("winfo exists .dialog.txt")[0] == '1') { /* proc enter_text */ + tcleval(".dialog.buttons.ok invoke"); + return; + } else if(state==0 && tclgetvar("edit_symbol_prop_new_sel")[0]) { + tcleval("set edit_symbol_prop_new_sel 1; .dialog.f1.b1 invoke"); /* invoke 'OK' of edit prop dialog */ + } else if((state & ShiftMask) && tclgetvar("edit_symbol_prop_new_sel")[0]) { + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + tclsetvar("preserve_unchanged_attrs", "1"); + rebuild_selected_array(); + } + } + + /* Handle the remaining Button1Press events */ + else if(button==Button1) /* MOD button is not pressed here. Processed above */ + { + xctx->onetime = 0; + xctx->mouse_moved = 0; + xctx->drag_elements = 0; + + /* start another wire or line in persistent mode */ + if(tclgetboolvar("persistent_command") && xctx->last_command) { + if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); + if(xctx->last_command == STARTWIRE){ + if(tclgetboolvar("snap_cursor") + && (xctx->prev_snapx == xctx->mousex_snap + && xctx->prev_snapy == xctx->mousey_snap) + && (xctx->ui_state & STARTWIRE) + && xctx->closest_pin_found){ + new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &= ~STARTWIRE; + } + else + start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + /* handle all object insertions started from Tools/Edit menu */ + if(check_menu_start_commands(state, c_snap, mx, my)) return; + + /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ + if(end_place_move_copy_zoom()) return; + + /* Button1Press to select objects */ + if(!excl) { + Selected sel; + int already_selected = 0; + int prev_last_sel = xctx->lastsel; + int no_shift_no_ctrl = !(state & (ShiftMask | ControlMask)); + + xctx->shape_point_selected = 0; + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + + #if 0 /* disabled */ + /* Clicking and dragging from a **selected** instance pin will start a new wire + * if no other elements are selected */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) { + if(add_wire_from_wire(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + if(add_wire_from_inst(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + } + #endif + + /* In *NON* intuitive interface a button1 press with no modifiers will + * first unselect everything... + * For intuitive interface unselection see below... */ + if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); + + /* find closest object. Use snap coordinates if full crosshair is enabled + * since the mouse pointer is obscured and crosshair is snapped to grid points */ + if(draw_xhair && (use_cursor_for_sel || crosshair_size == 0)) { + sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); + } else { + sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); + } + dbg(1, "sel.type=%d\n", sel.type); + /* determine if closest object was already selected when button1 was pressed */ + switch(sel.type) { + case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; + case xTEXT: if(xctx->text[sel.n].sel) already_selected = 1; break; + case LINE: if(xctx->line[sel.col][sel.n].sel) already_selected = 1; break; + case POLYGON: if(xctx->poly[sel.col][sel.n].sel) already_selected = 1; break; + case xRECT: if(xctx->rect[sel.col][sel.n].sel) already_selected = 1; break; + case ARC: if(xctx->arc[sel.col][sel.n].sel) already_selected = 1; break; + case ELEMENT: if(xctx->inst[sel.n].sel) already_selected = 1; break; + default: break; + } /*end switch */ + + /* Clicking and drag on an instance pin -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_inst(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* Clicking and drag on a wire end -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_wire(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* In intuitive interface a button1 press with no modifiers will + * unselect everything... we do it here */ + if(xctx->intuitive_interface && !already_selected && no_shift_no_ctrl ) unselect_all(1); + + /* select the object under the mouse and rebuild the selected array */ + if(!already_selected) select_object(xctx->mousex, xctx->mousey, SELECTED, 0, &sel); + rebuild_selected_array(); + dbg(1, "Button1Press to select objects, lastsel = %d\n", xctx->lastsel); + + /* if clicking on some object endpoints or vertices set shape_point_selected + * this information will be used in Motion events to draw the stretched vertices */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { + if(edit_polygon_point(state)) return; /* sets xctx->shape_point_selected */ + } + if(xctx->lastsel == 1 && xctx->intuitive_interface) { + int cond = already_selected; + + if(cond && xctx->sel_array[0].type==xRECT) { + if(edit_rect_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==LINE) { + if(edit_line_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==WIRE) { + if(edit_wire_point(state)) return; /* sets xctx->shape_point_selected */ + } + } + dbg(1, "shape_point_selected=%d, lastsel=%d\n", xctx->shape_point_selected, xctx->lastsel); + + /* intuitive interface: directly drag elements */ + if(sel.type && xctx->intuitive_interface && xctx->lastsel >= 1 && + !xctx->shape_point_selected) { + /* enable_stretch (from TCL variable) reverses command if enabled: + * - move --> stretch move + * - stretch move (with ctrl key) --> move + */ + int stretch = (state & ControlMask ? 1 : 0) ^ enable_stretch; + xctx->drag_elements = 1; + /* select attached nets depending on ControlMask and enable_stretch */ + if(stretch) { + select_attached_nets(); /* stretch nets that land on selected instance pins */ + } + /* if dragging instances with stretch enabled and Shift down add wires to pins + * attached to something */ + if((state & ShiftMask) && stretch) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + move_objects(START,0,0,0); + } + /* dragging away an object with Shift pressed is a copy (duplicate object) */ + else if(state & ShiftMask) copy_objects(START); + /* else it is a normal move */ + else move_objects(START,0,0,0); + } + + if(tclgetboolvar("auto_hilight") && !xctx->shape_point_selected) { + if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { + if(!prev_last_sel) { + redraw_hilights(1); /* 1: clear all hilights, then draw */ + } + } + hilight_net(0); + if(xctx->lastsel) { + redraw_hilights(0); + } + } + return; + } /* if(!excl) */ + } /* button==Button1 */ + + return; +} + +static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, + int aux, double c_snap, int enable_stretch, int draw_xhair, int snap_cursor, int wire_draw_active) +{ + char str[PATH_MAX + 100]; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->ui_state &= ~DESEL_CLICK; + dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); + /* bring up context menu if no pending operation */ + if(state == Button3Mask && xctx->semaphore <2) { + if(!end_place_move_copy_zoom()) { + context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + } + } + + /* launcher, no intuitive interface */ + if(!xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* launcher, intuitive_interface, only if no movement has been done */ + else if(xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && (xctx->ui_state & STARTMOVE) && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + move_objects(ABORT, 0, 0.0, 0.0); + unselect_all(1); + xctx->drag_elements = 0; /* after ctrl-Button1Press on a launcher need to clear this */ + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + rebuild_selected_array(); + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ + else if(state == Button1Mask && xctx->intuitive_interface && !tclgetboolvar("persistent_command") + && (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { + if(end_place_move_copy_zoom()) return; + } + + /* end intuitive_interface copy or move */ + if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { + copy_objects(END); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + else if(xctx->ui_state & STARTMOVE && xctx->drag_elements) { + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + + /* if a polygon/bezier/rectangle control point was clicked, end point move operation + * and set polygon state back to SELECTED from SELECTED1 */ + else if((xctx->ui_state & (STARTMOVE | SELECTION)) && xctx->shape_point_selected) { + end_shape_point_edit(c_snap); + } + + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + /* xctx->mx_save = mx; xctx->my_save = my; */ + /* xctx->mx_double_save=xctx->mousex_snap; */ + /* xctx->my_double_save=xctx->mousey_snap; */ + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + dbg(1, "callback(): ButtonRelease ui_state=%d state=%d\n",xctx->ui_state,state); + if(xctx->semaphore >= 2) return; + if(xctx->ui_state & STARTSELECT) { + if(state & ControlMask) { + select_rect(!enable_stretch, END,-1); + } else { + /* Button1 release: end of rectangle select */ + if(!(state & (Button4Mask|Button5Mask) ) ) { + select_rect(enable_stretch, END,-1); + } + } + xctx->ui_state &= ~DESEL_AREA; + rebuild_selected_array(); + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", + xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); + statusmsg(str,1); + } + + /* clear start from menu flag or infix_interface=0 start commands */ + if( state == Button1Mask && xctx->ui_state & MENUSTART) { + xctx->ui_state &= ~MENUSTART; + return; + } + if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ + if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(3); /* erase & redraw */ + return; +} + +static void handle_double_click(int event, int state, KeySym key, int button, + int mx, int my, int aux, int cadence_compat) +{ + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } else { + if(xctx->semaphore >= 2) return; + dbg(1, "callback(): DoubleClick ui_state=%d state=%d\n",xctx->ui_state,state); + if(button==Button1) { + Selected sel; + if(!xctx->lastsel && xctx->ui_state == 0) { + /* Following 5 lines do again a selection overriding lock, + * so locked instance attrs can be edited */ + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 1, NULL); + if(sel.type) { + xctx->ui_state = SELECTION; + rebuild_selected_array(); + } + } + if(xctx->ui_state == 0 || xctx->ui_state == SELECTION) { + edit_property(0); + } else { + if(xctx->ui_state & STARTWIRE) { + redraw_w_a_l_r_p_z_rubbers(1); + start_wire(mx, my); + xctx->ui_state &= ~STARTWIRE; + } + if(xctx->ui_state & STARTLINE) { + xctx->ui_state &= ~STARTLINE; + } + if( (xctx->ui_state & STARTPOLYGON) && (state ==0 ) ) { + new_polygon(SET, xctx->mousex_snap, xctx->mousey_snap); + } + } + } + } +} + + +/* main window callback */ +/* mx and my are set to the mouse coord. relative to window */ +/* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ +int callback(const char *win_path, int event, int mx, int my, KeySym key, + int button, int aux, int state) +{ + char str[PATH_MAX + 100]; + int redraw_only; + double c_snap; +#ifndef __unix__ + short cstate = GetKeyState(VK_CAPITAL); + short nstate = GetKeyState(VK_NUMLOCK); +#else + XKeyboardState kbdstate; +#endif +int enable_stretch = tclgetboolvar("enable_stretch"); +int draw_xhair = tclgetboolvar("draw_crosshair"); +int crosshair_size = tclgetintvar("crosshair_size"); +int infix_interface = tclgetboolvar("infix_interface"); +int rstate; /* (reduced state, without ShiftMask) */ +int snap_cursor = tclgetboolvar("snap_cursor"); +int cadence_compat = tclgetboolvar("cadence_compat"); +int wire_draw_active = (xctx->ui_state & STARTWIRE) || + ((xctx->ui_state2 & MENUSTARTWIRE) && (xctx->ui_state & MENUSTART)) || + (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); + + /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease + * events. Some remote connection softwares do not generate the correct coordinates + * on such events */ + if(fix_mouse_coord) { + if(event == KeyPress || event == KeyRelease) { + tclvareval("getmousex ", win_path, NULL); + mx = atoi(tclresult()); + tclvareval("getmousey ", win_path, NULL); + my = atoi(tclresult()); + dbg(1, "mx = %d my=%d\n", mx, my); + } + } + +#ifndef __unix__ + if(cstate & 0x0001) { /* caps lock */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state active -text {CAPS LOCK SET! }", NULL); + } else if (nstate & 0x0001) { /* num lock */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state active -text {NUM LOCK SET! }", NULL); + } else { /* normal state */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state normal -text {}", NULL); + } +#else + XGetKeyboardControl(display, &kbdstate); + if(kbdstate.led_mask & 1) { /* caps lock */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state active -text {CAPS LOCK SET! }", NULL); + } else if(kbdstate.led_mask & 2) { /* num lock */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state active -text {NUM LOCK SET! }", NULL); + } else { /* normal state */ + tclvareval(xctx->top_path, ".statusbar.8 configure -state normal -text {}", NULL); + } +#endif + + if(wire_draw_active) { + tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {DRAW WIRE! }", NULL); + } else { + tclvareval(xctx->top_path, ".statusbar.10 configure -state normal -text { }", NULL); + } + + tclvareval(xctx->top_path, ".statusbar.7 configure -text $netlist_type", NULL); + tclvareval(xctx->top_path, ".statusbar.3 delete 0 end;", + xctx->top_path, ".statusbar.3 insert 0 $cadsnap", + NULL); + tclvareval(xctx->top_path, ".statusbar.5 delete 0 end;", + xctx->top_path, ".statusbar.5 insert 0 $cadgrid", + NULL); + + #if 0 + /* exclude Motion and Expose events */ + if(event!=6 /* && event!=12 */) { + dbg(0, "callback(): state=%d event=%d, win_path=%s, old_win_path=%s, semaphore=%d\n", + state, event, win_path, old_win_path, xctx->semaphore+1); + } + #endif + + /* Schematic window context switch */ + redraw_only =0; + if(strcmp(old_win_path, win_path) ) { + if( xctx->semaphore >= 1 || event == Expose) { + dbg(1, "callback(): semaphore >=2 (or Expose) switching window context: %s --> %s\n", old_win_path, win_path); + redraw_only = 1; + new_schematic("switch_no_tcl_ctx", win_path, "", 1); + } else { + dbg(1, "callback(): switching window context: %s --> %s, semaphore=%d\n", old_win_path, win_path, xctx->semaphore); + new_schematic("switch", win_path, "", 1); + } + tclvareval("housekeeping_ctx", NULL); + } + /* artificially set semaphore to allow only redraw operations in switched schematic, + * so we don't need to switch tcl context which is costly performance-wise + */ + if(redraw_only) { + dbg(1, "callback(): incrementing semaphore for redraw_only\n"); + xctx->semaphore++; + } + + xctx->semaphore++; /* to recognize recursive callback() calls */ + + c_snap = tclgetdoublevar("cadsnap"); + #ifdef __unix__ + state &= (1 <<13) -1; /* filter out anything above bit 12 (4096) */ + #endif + state &= ~Mod2Mask; /* 20170511 filter out NumLock status */ + state &= ~LockMask; /* filter out Caps Lock */ + rstate = state; /* rstate does not have ShiftMask bit, so easier to test for KeyPress events */ + rstate &= ~ShiftMask; /* don't use ShiftMask, identifying characters is sufficient */ + rstate &= ~Button1Mask; /* ignore button-1 */ + if(xctx->semaphore >= 2) + { + if(debug_var>=2) + if(event != MotionNotify) + fprintf(errfp, "callback(): reentrant call of callback(), semaphore=%d, ev=%d, ui_state=%d\n", + xctx->semaphore, event, xctx->ui_state); + } + xctx->mousex=X_TO_XSCHEM(mx); + xctx->mousey=Y_TO_XSCHEM(my); + xctx->mousex_snap=my_round(xctx->mousex / c_snap) * c_snap; + xctx->mousey_snap=my_round(xctx->mousey / c_snap) * c_snap; + + if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", + xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); + statusmsg(str,1); + } + + dbg(1, "key=%d EQUAL_MODMASK=%d, SET_MODMASK=%d\n", key, SET_MODMASK, EQUAL_MODMASK); + + #if defined(__unix__) && HAS_CAIRO==1 + if(xctx->ui_state & GRABSCREEN) { + grabscreen(win_path, event, mx, my, key, button, aux, state); + } else + #endif + switch(event) + { + + case LeaveNotify: + if(draw_xhair) draw_crosshair(1, state); /* clear crosshair when exiting window */ + if(snap_cursor) draw_snap_cursor(1); /* erase */ + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + xctx->mouse_inside = 0; + break; + + case EnterNotify: + handle_enter_notify(draw_xhair, crosshair_size); + break; + + case Expose: + dbg(1, "callback: Expose, win_path=%s, %dx%d+%d+%d\n", win_path, button, aux, mx, my); + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], mx,my,button,aux,mx,my); + { + XRectangle xr[1]; + xr[0].x=(short)mx; + xr[0].y=(short)my; + xr[0].width=(unsigned short)button; + xr[0].height=(unsigned short)aux; + /* redraw selection on expose, needed if no backing store available on the server 20171112 */ + XSetClipRectangles(display, xctx->gc[SELLAYER], 0,0, xr, 1, Unsorted); + rebuild_selected_array(); + if(tclgetboolvar("compare_sch") /* && xctx->sch_to_compare[0] */){ + compare_schematics(""); + } else { + draw_selection(xctx->gc[SELLAYER],0); + } + XSetClipMask(display, xctx->gc[SELLAYER], None); + } + dbg(1, "callback(): Expose\n"); + break; + + case ConfigureNotify: + dbg(1,"callback(): ConfigureNotify event\n"); + resetwin(1, 1, 0, 0, 0); + draw(); + break; + + case MotionNotify: + handle_motion_notify(event, key, state, rstate, button, mx, my, + aux, draw_xhair, enable_stretch, + snap_cursor, wire_draw_active); + break; + + case KeyRelease: + /* force clear (even if mouse pos not changed) */ + /* if(snap_cursor && (key == XK_Shift_L || key == XK_Shift_R) ) draw_snap_cursor(5); */ + break; + + case KeyPress: + handle_key_press(event, key, state, rstate, mx, my, button, aux, + infix_interface, enable_stretch, win_path, c_snap, + cadence_compat, wire_draw_active, snap_cursor); + break; + + case ButtonPress: + handle_button_press(event, state, rstate, key, button, mx, my, + c_snap, draw_xhair, crosshair_size, enable_stretch, aux); + break; + + case ButtonRelease: + handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, + draw_xhair, snap_cursor, wire_draw_active); + break; + + case -3: /* double click : edit prop */ + handle_double_click(event, state, key, button, mx, my, aux, cadence_compat); + break; + + default: + dbg(1, "callback(): Event:%d\n",event); + break; + } /* switch(event) */ + + if(xctx->semaphore > 0) xctx->semaphore--; + if(redraw_only) { + xctx->semaphore--; /* decrement articially incremented semaphore (see above) */ + dbg(1, "callback(): semaphore >=2 restoring window context: %s <-- %s\n", old_win_path, win_path); + if(old_win_path[0]) new_schematic("switch_no_tcl_ctx", old_win_path, "", 1); + } + else + if(strcmp(old_win_path, win_path)) { + if(old_win_path[0]) dbg(1, "callback(): reset old_win_path: %s <- %s\n", old_win_path, win_path); + my_strncpy(old_win_path, win_path, S(old_win_path)); + } + return 0; +} + From afaa38e81d62e12bb000f30fae1020450cfcef60 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Thu, 13 Mar 2025 13:17:21 +0530 Subject: [PATCH 56/59] [Resolve Merge Conflicts - 3]: Third (Final) stage of changes. All upstream changes are now merged. --- src/callback.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/callback.c b/src/callback.c index 4dd7d3bf..a9158ee3 100644 --- a/src/callback.c +++ b/src/callback.c @@ -3032,7 +3032,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m descend_symbol(); } else if(rstate == ControlMask) { /* insert sym */ - tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + if(tclgetboolvar("new_symbol_browser")) { + tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + } else { + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } } else if(EQUAL_MODMASK) { /* edit symbol in new window */ int save = xctx->semaphore; @@ -3045,7 +3049,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m case 'I': if(rstate == 0) { /* insert sym */ if(xctx->semaphore >= 2) break; - start_place_symbol(); + if(tclgetboolvar("new_symbol_browser")) { + tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + } else { + start_place_symbol(); + } } else if(EQUAL_MODMASK) { /* edit symbol in new window - new xschem process */ int save = xctx->semaphore; @@ -3967,11 +3975,19 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m case XK_Insert: if(state == ShiftMask) { /* insert sym */ - tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + if(tclgetboolvar("new_symbol_browser")) { + tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + } else { + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + } } else { if(xctx->semaphore >= 2) break; - start_place_symbol(); + if(tclgetboolvar("new_symbol_browser")) { + tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + } else { + start_place_symbol(); + } } break; From 5c44fec50654dc750835f717ae653041ac9e6ef9 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 14 Mar 2025 14:00:36 +0530 Subject: [PATCH 57/59] [Experimental Feature Update]: Orthogonal wiring feature is now applicable to wires connected to objects, when those objects are moved to a different position by the user. This requires 'enable_stretching' to be enabled, which will stretch the connected wires orthogonally when the user drags/moves objects around in the canvas. --- src/actions.c | 60 ++++------------------------------------ src/draw.c | 39 ++++++++++++++++++++++++++ src/move.c | 76 ++++++++++++++++++++++++++++++++++++++++++++------- src/xschem.h | 1 + 4 files changed, 111 insertions(+), 65 deletions(-) diff --git a/src/actions.c b/src/actions.c index d56798ac..7a6f56e5 100644 --- a/src/actions.c +++ b/src/actions.c @@ -3183,61 +3183,11 @@ void new_wire(int what, double mx_snap, double my_snap) xctx->ui_state &= ~STARTWIRE; } if( (what & RUBBER) ) { - if(xctx->manhattan_lines & 1) { - xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1; - xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); - drawtempline(xctx->gctiled, NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); - xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1; - xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; - ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gctiled, NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); - xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; - if(!(what & CLEAR)) { - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); - drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - } - } else if(xctx->manhattan_lines & 2) { - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); - drawtempline(xctx->gctiled, NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gctiled, NOW, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); - restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); - xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; - if(!(what & CLEAR)) { - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); - drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); - } - } else { - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gctiled, NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); - xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; - if(!(what & CLEAR)) { - xctx->nl_xx1 = xctx->nl_x1; xctx->nl_yy1 = xctx->nl_y1; - xctx->nl_xx2 = xctx->nl_x2; xctx->nl_yy2 = xctx->nl_y2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - drawtempline(xctx->gc[WIRELAYER], NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - } + drawtemp_manhattanline(xctx->gctiled, NOW, xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); + restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); + xctx->nl_x2 = mx_snap; xctx->nl_y2 = my_snap; + if(!(what & CLEAR)) { + drawtemp_manhattanline(xctx->gc[WIRELAYER], NOW, xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); } } } diff --git a/src/draw.c b/src/draw.c index fb0c1ddc..c6bbeabe 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1375,6 +1375,45 @@ void drawtempline(GC gc, int what, double linex1,double liney1,double linex2,dou } } +void drawtemp_manhattanline(GC gc, int what, double x1, double y1, double x2, double y2) +{ + double origin_shifted_x2, origin_shifted_y2; + if(tclgetboolvar("orthogonal_wiring")) { + /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ + origin_shifted_x2 = x2 - x1; + origin_shifted_y2 = y2 - y1; + /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ + if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2) + xctx->manhattan_lines = 1; + else + xctx->manhattan_lines = 2; + } + if(xctx->manhattan_lines & 1) { + xctx->nl_xx1 = x1; xctx->nl_yy1 = y1; + xctx->nl_xx2 = x2; xctx->nl_yy2 = y2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); + drawtempline(gc, what, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); + xctx->nl_xx1 = x1; xctx->nl_yy1 = y1; + xctx->nl_xx2 = x2; xctx->nl_yy2 = y2; + ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + drawtempline(gc, what, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + } else if(xctx->manhattan_lines & 2) { + xctx->nl_xx1 = x1; xctx->nl_yy1 = y1; + xctx->nl_xx2 = x2; xctx->nl_yy2 = y2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); + drawtempline(gc, what, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); + xctx->nl_xx1 = x1; xctx->nl_yy1 = y1; + xctx->nl_xx2 = x2; xctx->nl_yy2 = y2; + ORDER(xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); + drawtempline(gc, what, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); + } else { + xctx->nl_xx1 = x1; xctx->nl_yy1 = y1; + xctx->nl_xx2 = x2; xctx->nl_yy2 = y2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + drawtempline(gc, what, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + } +} + void drawtemparc(GC gc, int what, double x, double y, double r, double a, double b) { static int i=0; diff --git a/src/move.c b/src/move.c index 6ec3ba09..37db4066 100644 --- a/src/move.c +++ b/src/move.c @@ -378,25 +378,25 @@ void draw_selection(GC g, int interruptable) if(xctx->wire[n].sel==SELECTED) { if(xctx->wire[n].bus) - drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, + drawtemp_manhattanline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); else - drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, + drawtemp_manhattanline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); } else if(xctx->wire[n].sel==SELECTED1) { if(xctx->wire[n].bus) - drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2); + drawtemp_manhattanline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2); else - drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2); + drawtemp_manhattanline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2); } else if(xctx->wire[n].sel==SELECTED2) { if(xctx->wire[n].bus) - drawtempline(g, THICK, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); + drawtemp_manhattanline(g, THICK, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); else - drawtempline(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); + drawtemp_manhattanline(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay); } break; case LINE: @@ -1135,10 +1135,66 @@ void move_objects(int what, int merge, double dx, double dy) if(wire[n].sel == SELECTED1) wire[n].sel = SELECTED2; else if(wire[n].sel == SELECTED2) wire[n].sel = SELECTED1; } - wire[n].x1=xctx->rx1; - wire[n].y1=xctx->ry1; - wire[n].x2=xctx->rx2; - wire[n].y2=xctx->ry2; + + if(wire[n].sel & (SELECTED|SELECTED1)) + { + if(xctx->manhattan_lines & 1) xctx->manhattan_lines=2; + else if(xctx->manhattan_lines & 2) xctx->manhattan_lines=1; + } + wire[n].sel = SELECTED; + delete_wires(SELECTED); + if(xctx->manhattan_lines & 1) { + if(xctx->nl_xx2!=xctx->nl_xx1) { + xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; + xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); + storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1, 0, NULL); + } + if(xctx->nl_yy2!=xctx->nl_yy1) { + xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; + xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; + ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + storeobject(-1, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); + } + } else if(xctx->manhattan_lines & 2) { + if(xctx->nl_yy2!=xctx->nl_yy1) { + xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; + xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); + storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2, 0, NULL); + } + if(xctx->nl_xx2!=xctx->nl_xx1) { + xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; + xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; + ORDER(xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); + storeobject(-1, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); + } + } else { + xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; + xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; + ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); + } + xctx->prep_hi_structs = 0; + if(tclgetboolvar("autotrim_wires")) trim_wires(); + prepare_netlist_structs(0); /* since xctx->prep_hi_structs==0, do a delete_netlist_structs() first, + * this clears both xctx->prep_hi_structs and xctx->prep_net_structs. */ + if(xctx->hilight_nets) { + propagate_hilights(1, 1, XINSERT_NOREPLACE); + } + draw(); + /* draw_hilight_net(1);*/ /* for updating connection bubbles on hilight nets */ + set_modify(1); } break; diff --git a/src/xschem.h b/src/xschem.h index 93c93b09..4d85fe43 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1428,6 +1428,7 @@ extern void filledrect(int c, int what, double rectx1,double recty1, extern void drawtempline(GC gc, int what, double x1,double y1,double x2,double y2); +extern void drawtemp_manhattanline(GC gc, int what, double x1,double y1,double x2,double y2); /* instead of doing a drawtemprect(xctx->gctiled, NOW, ....) do 4 * XCopy Area operations. Used if fix_broken_tiled_fill is set */ From a3eb1b0c17be1b7aa17a4835484a7dc49ef7a846 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 14 Mar 2025 16:16:29 +0530 Subject: [PATCH 58/59] [Experimental Feature Update]: Orthogonal wiring feature is now applicable to wires connected to objects, when those objects are moved to a different position by the user. This requires 'enable_stretching' to be enabled, which will stretch the connected wires orthogonally when the user drags/moves objects around in the canvas. --- src/move.c | 74 ++++++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 52 deletions(-) diff --git a/src/move.c b/src/move.c index 37db4066..59893122 100644 --- a/src/move.c +++ b/src/move.c @@ -1141,60 +1141,30 @@ void move_objects(int what, int merge, double dx, double dy) if(xctx->manhattan_lines & 1) xctx->manhattan_lines=2; else if(xctx->manhattan_lines & 2) xctx->manhattan_lines=1; } - wire[n].sel = SELECTED; - delete_wires(SELECTED); - if(xctx->manhattan_lines & 1) { - if(xctx->nl_xx2!=xctx->nl_xx1) { - xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; - xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1); - storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1,WIRE,0,0,NULL); - hash_wire(XINSERT, xctx->wires-1, 1); - drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy1, 0, NULL); - } - if(xctx->nl_yy2!=xctx->nl_yy1) { - xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; - xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; - ORDER(xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - storeobject(-1, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); - hash_wire(XINSERT, xctx->wires-1, 1); - drawline(WIRELAYER,NOW, xctx->nl_xx2,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); - } - } else if(xctx->manhattan_lines & 2) { - if(xctx->nl_yy2!=xctx->nl_yy1) { - xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; - xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2); - storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2,WIRE,0,0,NULL); - hash_wire(XINSERT, xctx->wires-1, 1); - drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx1,xctx->nl_yy2, 0, NULL); - } - if(xctx->nl_xx2!=xctx->nl_xx1) { - xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; - xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; - ORDER(xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2); - storeobject(-1, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); - hash_wire(XINSERT, xctx->wires-1, 1); - drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy2,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); - } - } else { - xctx->nl_xx1 = xctx->rx1; xctx->nl_yy1 = xctx->ry1; - xctx->nl_xx2 = xctx->rx2; xctx->nl_yy2 = xctx->ry2; - ORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); - storeobject(-1, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2,WIRE,0,0,NULL); - hash_wire(XINSERT, xctx->wires-1, 1); - drawline(WIRELAYER,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2, 0, NULL); + wire[n].x1 = xctx->rx1; + wire[n].y1 = xctx->ry1; + if(xctx->manhattan_lines&1) + { + wire[n].x2 = xctx->rx2; + wire[n].y2 = xctx->ry1; + storeobject(-1, xctx->rx2,xctx->ry1,xctx->rx2,xctx->ry2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,ADD, xctx->rx2,xctx->ry1,xctx->rx2,xctx->ry2, 0, NULL); } - xctx->prep_hi_structs = 0; - if(tclgetboolvar("autotrim_wires")) trim_wires(); - prepare_netlist_structs(0); /* since xctx->prep_hi_structs==0, do a delete_netlist_structs() first, - * this clears both xctx->prep_hi_structs and xctx->prep_net_structs. */ - if(xctx->hilight_nets) { - propagate_hilights(1, 1, XINSERT_NOREPLACE); + else if(xctx->manhattan_lines&2) + { + wire[n].x2 = xctx->rx1; + wire[n].y2 = xctx->ry2; + storeobject(-1, xctx->rx1,xctx->ry2,xctx->rx2,xctx->ry2,WIRE,0,0,NULL); + hash_wire(XINSERT, xctx->wires-1, 1); + drawline(WIRELAYER,ADD, xctx->rx1,xctx->ry2,xctx->rx2,xctx->ry2, 0, NULL); } - draw(); - /* draw_hilight_net(1);*/ /* for updating connection bubbles on hilight nets */ - set_modify(1); + else + { + wire[n].x2 = xctx->rx2; + wire[n].y2 = xctx->ry2; + } + } break; From 333dc91b48129531a6ff785ce2ae881ac8ca07d1 Mon Sep 17 00:00:00 2001 From: Chayan Deb Date: Fri, 14 Mar 2025 20:02:49 +0530 Subject: [PATCH 59/59] [ANSI-C Compatibilty Update + Remove Redundant TCL Menu Entries]: Made changes to conform to ANSI-C standard and removed some redundant code in 'src/xschem.tcl'. --- src/callback.c | 11 +++++++++-- src/xschem.tcl | 7 +------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/callback.c b/src/callback.c index a9158ee3..78b00491 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2607,7 +2607,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m { char str[PATH_MAX + 100]; switch (key) { - case '0' ... '4': + case '0': + case '1': + case '2': + case '3': + case '4': if(state == 0) { /* toggle pin logic level */ if(xctx->semaphore >= 2) break; if(key == '4') logic_set(-1, 1, NULL); @@ -2638,7 +2642,10 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m } /* /20110112 */ break; - case '6' ... '9': + case '6': + case '7': + case '8': + case '9': if(state==ControlMask) { /* choose layer */ char n[30]; xctx->rectcolor = (int)key - '0'+4; diff --git a/src/xschem.tcl b/src/xschem.tcl index 122a0d75..51c4575c 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -8736,17 +8736,12 @@ proc build_widgets { {topwin {} } } { -variable intuitive_interface -selectcolor $selectcolor \ -command {xschem set intuitive_interface $intuitive_interface} - $topwin.menubar.option add checkbutton -label "Draw crosshair" \ - -variable draw_crosshair -selectcolor $selectcolor -accelerator {Alt-X} - $topwin.menubar.option add checkbutton -label "Draw persistent snap cursor" -variable snap_cursor \ - -selectcolor $selectcolor -accelerator {Alt-Z} - $topwin.menubar.option add cascade -label "Crosshair" \ -menu $topwin.menubar.option.crosshair menu $topwin.menubar.option.crosshair -tearoff 0 $topwin.menubar.option.crosshair add checkbutton -label "Draw snap cursor" \ - -variable snap_cursor -selectcolor $selectcolor + -variable snap_cursor -selectcolor $selectcolor -accelerator {Alt-Z} $topwin.menubar.option.crosshair add checkbutton -label "Draw crosshair" \ -variable draw_crosshair -selectcolor $selectcolor -accelerator {Alt-X} $topwin.menubar.option.crosshair add command -label "Crosshair size" \