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
diff --git a/doc/xschem_man/commands.html b/doc/xschem_man/commands.html
index 0a4f589e..02f5777a 100644
--- a/doc/xschem_man/commands.html
+++ b/doc/xschem_man/commands.html
@@ -229,6 +229,7 @@ ctrl+alt 's' Save-as symbol
- 't' Place text
shift 'T' Toggle *_ignore flag on selected instances
alt 'u' Align to current grid selected objects
+ctrl 'u' Unselect attached floater objects
shift 'U' Redo
- 'u' Undo
- 'v' Constrained vertical move/copy of objects
diff --git a/doc/xschem_man/component_property_syntax.html b/doc/xschem_man/component_property_syntax.html
index bf4148f1..75acf5a2 100644
--- a/doc/xschem_man/component_property_syntax.html
+++ b/doc/xschem_man/component_property_syntax.html
@@ -138,6 +138,11 @@ name="mchanged_name" model=\"nmos\" w="20u" l="3u" m="10"
text_layer_<n>
This attribute sets the layer of symbol text item number n. This allows
instance based symbol text color customization.
+ attach
+ An attribute attach="x1 g3 p4" will "attach" specified objects that have a matching name=...
+ attribute. These objects can be any xschem objects, like other elements, wires, rectangles, polygons, texts etc.
+ Attached objects will be selected when selecting the component with this attribute set.
+ This allows to create "object groups"
highlight
If set to true the symbol will be highlighted when one of the nets attached to its pins are highlighted.
net_name
diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html
index 0cc1b8b6..e5676ad7 100644
--- a/doc/xschem_man/developer_info.html
+++ b/doc/xschem_man/developer_info.html
@@ -551,7 +551,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
-
abort_operation
@@ -814,6 +813,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
textlayer layer number for texts
top_path get top hier path of current window (always "" for tabbed if)
topwindow same as top_path but main window returned as "."
+ ui_state return UI state
version return xschem version
wirelayer layer used for wires
wires number of wires
@@ -828,6 +828,15 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
return result of get_cell function
get_cell_w_ext cell n_dirs
return result of get_cell_w_ext function
+ get_fqdevice instname param modelparam
+ get the full pathname of "instname" device
+ modelparam:
+ 0: current, 1: modelparam, 2: modelvoltage
+ param: device parameter, like ib, gm, vth
+ set param to {} (empty str) for just branch current of 2 terminal device
+ for parameters like "vth" modelparam must be 2
+ for parameters like "ib" modelparam must be 0
+ for parameters like "gm" modelparam must be 1
getprop instance|instance_pin|symbol|text ref
getprop instance inst
@@ -981,13 +990,17 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
is_generator symbol
tell if 'symbol' is a generator (symbol(param1,param2,...)
line [x1 y1 x2 y2] [pos] [propstring] [draw]
+ line
+ line gui
if 'x1 y1 x2 y2'is given place line on current
layer (rectcolor) at indicated coordinates.
- if 'pos' is given insert at given position in rectangle array.
+ if 'pos' is given insert at given position in line array.
if 'pos' set to -1 append to last element in line array.
'propstring' is the attribute string. Set to empty if not given.
if 'draw' is set to 1 (default) draw the new object, else don't
- If no coordinates are given start a GUI operation of line placement
+ If no coordinates are given start a GUI operation of line placement
+ if `gui` argument is given start a line GUI placement with 1st point
+ set to current mouse coordinates
line_width n
set line width to floating point number 'n'
list_hierarchy
@@ -1153,8 +1166,10 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
If not given take from symbol template attribute.
place_text
Start a GUI placement of a text object
- polygon
- Start a GUI placement of a polygon
+ polygon [gui]
+ Start a GUI placement of a polygon
+ if `gui` argument is given start a polygon GUI placement with 1st point
+ set to current mouse coordinates
preview_window create|draw|destroy|close [win_path] [file]
destroy: will delete preview schematic data and destroy container window
close: same as destroy but leave the container window.
@@ -1192,8 +1207,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
push_undo
Push current state on undo stack
raw what ...
- what = add | clear | datasets | index | info | loaded | list | new | points | rawfile | del |
- read | set | sim_type | switch | switch_back | table_read | value | values | pos_at | vars |
+ what = add | clear | datasets | index | info | loaded | list |
+ new | points | rawfile | del | read | set | rename |
+ sim_type | switch | switch_back | table_read | value | values | pos_at | vars |
xschem raw read filename [type [sweep1 sweep2]]
if sweep1, sweep2 interval is given in 'read' subcommand load only the interval
@@ -1208,6 +1224,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
xschem raw del name
delete named vector from current raw file
+ xschem raw rename old_name new_name
+ rename a node in the loaded raw file.
+
xschem raw info
print information about loaded raw files and show the currently active one.
@@ -1284,7 +1303,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
new dataset do not start with a header row.
Lines beginning with '#' are comments and ignored
- time var_a var_b var_c
+ time var_a var_b var_cnode in the loaded raw file.
# this is a comment, ignored
0.0 0.0 1.8 0.3
<single empty line: ignored>
@@ -1325,14 +1344,19 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Rebuild selection list
record_global_node n node
call the record_global_node function (list of netlist global nodes)
- rect [x1 y1 x2 y2] [pos] [propstring] [draw]
- if 'x1 y1 x2 y2'is given place recangle on current
- layer (rectcolor) at indicated coordinates.
- if 'pos' is given insert at given position in rectangle array.
- if 'pos' set to -1 append rectangle to last element in rectangle array.
- 'propstring' is the attribute string. Set to empty if not given.
- if 'draw' is set to 1 (default) draw the new object, else don't
- If no coordinates are given start a GUI operation of rectangle placement
+ rect ...
+ rect [x1 y1 x2 y2] [pos] [propstring] [draw]
+ if 'x1 y1 x2 y2'is given place recangle on current
+ layer (rectcolor) at indicated coordinates.
+ if 'pos' is given insert at given position in rectangle array.
+ if 'pos' set to -1 append rectangle to last element in rectangle array.
+ 'propstring' is the attribute string. Set to empty if not given.
+ if 'draw' is set to 1 (default) draw the new object, else don't
+ rect
+ If no coordinates are given start a GUI operation of rectangle placement
+ rect gui
+ if `gui` argument is given start a GUI placement of a rectangle with 1st
+ point starting from current mouse coordinates
redo
Redo last undone action
redraw
@@ -1634,6 +1658,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Unhighlight selected nets/pins
unselect_all [draw]
Unselect everything. If draw is given and set to '0' no drawing is done
+ unselect_attached_floaters
+ Unselect objects (not symbol instances) attached to some instance with a
+ non empty name=... attribute
update_all_sym_bboxes
Update all symbol bounding boxes
update_op
@@ -1649,8 +1676,12 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
wire_coord n
return 4 coordinates of wire[n]
wire [x1 y1 x2 y2] [pos] [prop] [sel]
+ wire
+ wire gui
Place a new wire
- if no coordinates are given start a GUI wire placement
+ if no coordinates are given start a GUI wire placement
+ if `gui` argument is given start a GUI placement of a wire with 1st point
+ starting from current mouse coordinates
wire_cut [x y] [noalign]
start a wire cut operation. Point the mouse in the middle of a wire and
Alt-click right button.
@@ -1732,6 +1763,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
+
diff --git a/doc/xschem_man/symbol_property_syntax.html b/doc/xschem_man/symbol_property_syntax.html
index 9aa02448..5ff5abce 100644
--- a/doc/xschem_man/symbol_property_syntax.html
+++ b/doc/xschem_man/symbol_property_syntax.html
@@ -551,6 +551,19 @@ verilog_format="xnor #(@risedel , @falldel ) @name ( @@Z , @@A , @@B );"
PREDEFINED SYMBOL VALUES
+ - @name
+ This expands to the instance name of the symbol (like C1, R2, X3, ...)
+ It is replaced with the value of the name=... attribute given when placing an instance of the symbol
+ in a schematic.
+ - #pattern#@name
+ This is a variation of the above where pattern is prefixed to all substituted @name
+ patterns. The difference with pattern@name is that in case of vector instances (this means
+ a placement of an instance with name=R2[3:0], for example) the pattern string
+ is added to all single instances when expanding the name. see below examples.
+ pattern@name where name=R2[2:0] is given in the instance placement,
+ expands to patternR2[2],R2[1],R2[0]
+ #pattern#@name where name=R2[2:0] is given in the instance placement,
+ expands to patternR2[2],patternR2[1],patternR2[0]
- @symname
This expands to the name of the symbol
- @symref
diff --git a/src/actions.c b/src/actions.c
index ba5bac99..bb3f17be 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -1066,7 +1066,7 @@ void clear_partial_selected_wires(void)
rebuild_selected_array();
for(j=0; j < xctx->lastsel; ++j) if(xctx->sel_array[j].type == WIRE) {
int wire = xctx->sel_array[j].n;
- select_wire(wire, 0, 1);
+ select_wire(wire, 0, 1, 1);
}
xctx->need_reb_sel_arr = 1;
rebuild_selected_array();
@@ -1229,7 +1229,7 @@ int unselect_partial_sel_wires(void)
while(wptr) {
xWire *w = &xctx->wire[wptr->n];
if(touch(w->x1, w->y1, w->x2, w->y2, pinx0, piny0) && w->sel && w->sel != SELECTED) {
- select_wire(wptr->n, 0, 1);
+ select_wire(wptr->n, 0, 1, 1);
changed = 1;
}
wptr = wptr->next;
@@ -1258,7 +1258,7 @@ int unselect_partial_sel_wires(void)
}
if(touch(w->x1, w->y1, w->x2, w->y2, x0, y0) && w->sel && w->sel != SELECTED) {
xctx->wire[wptr->n].sel = 0;
- select_wire(wptr->n, 0, 1);
+ select_wire(wptr->n, 0, 1, 1);
changed = 1;
}
wptr = wptr->next;
@@ -1295,8 +1295,8 @@ void attach_labels_to_inst(int interactive) /* offloaded from callback.c 201710
int use_label_prefix;
int found=0;
- my_strdup(_ALLOC_ID_, &symname_pin, tcleval("rel_sym_path [find_file_first lab_pin.sym]"));
- my_strdup(_ALLOC_ID_, &symname_wire, tcleval("rel_sym_path [find_file_first lab_wire.sym]"));
+ my_strdup(_ALLOC_ID_, &symname_pin, tcleval("find_file_first lab_pin.sym"));
+ my_strdup(_ALLOC_ID_, &symname_wire, tcleval("find_file_first lab_wire.sym"));
if(symname_pin && symname_wire) {
rebuild_selected_array();
k = xctx->lastsel;
@@ -1450,12 +1450,11 @@ void delete_files(void)
void place_net_label(int type)
{
- unselect_all(1);
if(type == 1) {
- const char *lab = tcleval("rel_sym_path [find_file_first lab_pin.sym]");
+ const char *lab = tcleval("find_file_first lab_pin.sym");
place_symbol(-1, lab, xctx->mousex_snap, xctx->mousey_snap, 0, 0, NULL, 4, 1, 1/*to_push_undo*/);
} else {
- const char *lab = tcleval("rel_sym_path [find_file_first lab_wire.sym]");
+ const char *lab = tcleval("find_file_first lab_wire.sym");
place_symbol(-1, lab, xctx->mousex_snap, xctx->mousey_snap, 0, 0, NULL, 4, 1, 1/*to_push_undo*/);
}
move_objects(START,0,0,0);
@@ -1478,13 +1477,14 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot
char name[PATH_MAX];
char name1[PATH_MAX];
char tclev = 0;
+
if(symbol_name==NULL) {
tcleval("load_file_dialog {Choose symbol} *.\\{sym,tcl\\} INITIALINSTDIR");
my_strncpy(name1, tclresult(), S(name1));
} else {
- my_strncpy(name1, trim_chars(symbol_name, " \t\n"), S(name1));
+ my_strncpy(name1, abs_sym_path(trim_chars(symbol_name, " \t\n"), ""), S(name1));
}
-
+ if(!name1[0]) return 0;
dbg(1, "place_symbol(): 1: name1=%s first_call=%d\n",name1, first_call);
/* remove tcleval( given in file selector, if any ... */
if(strstr(name1, "tcleval(")) {
@@ -1562,7 +1562,11 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot
/* After having assigned prop_ptr to new instance translate symbol reference
* to resolve @params --> res.tcl(@value\) --> res.tcl(100) */
my_strncpy(name, translate(n, name), S(name));
- i = match_symbol(name);
+ /* parameters like res.tcl(@value\) have been resolved, so reload symbol removing previous */
+ if(strcmp(name, name1)) {
+ remove_symbol(i);
+ i = match_symbol(name);
+ }
xctx->inst[n].ptr = i;
set_inst_flags(&xctx->inst[n]);
hash_names(n, XINSERT);
@@ -1576,6 +1580,50 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot
if(xctx->prep_hash_inst) hash_inst(XINSERT, n); /* no need to rehash, add item */
/* xctx->prep_hash_inst=0; */
+ /* embed a (locked) graph object floater inside the symbol */
+ if(xctx->sym[i].type && !strcmp(xctx->sym[i].type, "scope")) {
+ char *prop = NULL;
+
+ my_strdup(_ALLOC_ID_, &xctx->inst[n].prop_ptr,
+ subst_token(xctx->inst[n].prop_ptr, "attach", xctx->inst[n].instname));
+ my_mstrcat(_ALLOC_ID_, &prop, "name=", xctx->inst[n].instname, "\n", NULL);
+ my_mstrcat(_ALLOC_ID_, &prop, "flags=graph,unlocked\n", NULL);
+ my_mstrcat(_ALLOC_ID_, &prop, "lock=1\n", NULL);
+ my_mstrcat(_ALLOC_ID_, &prop, "color=8\n", NULL);
+ if(xctx->sym[i].rects[PINLAYER] == 0) {
+ if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) {
+ my_mstrcat(_ALLOC_ID_, &prop, "node=\"tcleval([xschem get_fqdevice [xschem translate ",
+ xctx->inst[n].instname, " @device]])\"\n", NULL);
+ my_strdup(_ALLOC_ID_, &xctx->inst[n].prop_ptr,
+ subst_token(xctx->inst[n].prop_ptr, "device", xctx->inst[xctx->sel_array[0].n].instname));
+ } else {
+ const char msg[]="scope_ammeter is being inserted but no selected ammeter device/vsource to link to\n";
+ dbg(0, "%s", msg);
+ if(has_x) tclvareval("alert_ {", msg, "} {}", NULL);
+ if(xctx->inst[n].instname) my_free(_ALLOC_ID_, &xctx->inst[n].instname);
+ if(xctx->inst[n].name) my_free(_ALLOC_ID_, &xctx->inst[n].name);
+ if(xctx->inst[n].prop_ptr) my_free(_ALLOC_ID_, &xctx->inst[n].prop_ptr);
+ if(xctx->inst[n].lab) my_free(_ALLOC_ID_, &xctx->inst[n].lab);
+ if(prop) my_free(_ALLOC_ID_, &prop);
+ xctx->instances--;
+ return 0;
+ }
+ } else if(xctx->sym[i].rects[PINLAYER] == 1) {
+ my_mstrcat(_ALLOC_ID_, &prop,
+ "node=\"tcleval(",
+ "[xschem translate ", xctx->inst[n].instname, " @#0:net_name]",
+ ")\"\n", NULL);
+ } else {
+ my_mstrcat(_ALLOC_ID_, &prop,
+ "node=\"tcleval(",
+ "[xschem translate ", xctx->inst[n].instname, " @#0:net_name] ",
+ "[xschem translate ", xctx->inst[n].instname, " @#1:net_name] -",
+ ")\"\n", NULL);
+ }
+ storeobject(-1, x + 20, y-125, x + 130 , y - 25, xRECT, 2, SELECTED, prop);
+ my_free(_ALLOC_ID_, &prop);
+ }
+
if(draw_sym & 3) {
bbox(ADD, xctx->inst[n].x1, xctx->inst[n].y1, xctx->inst[n].x2, xctx->inst[n].y2);
}
@@ -1587,6 +1635,7 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot
/* hilight new element 24122002 */
if(draw_sym & 4 ) {
+ unselect_all(1);
select_element(n, SELECTED,0, 1);
drawtemparc(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0, 0.0);
drawtemprect(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0);
@@ -2214,7 +2263,7 @@ int change_sch_path(int instnumber, int dr)
char *ptr;
size_t pathlen;
int res = 0;
- if(level <= 0 ) return 0;
+ if(level < 0 ) return 0;
my_strdup2(_ALLOC_ID_, &instname, get_tok_value(xctx->hier_attr[level].prop_ptr, "name", 0));
my_strdup2(_ALLOC_ID_, &expanded_instname, expandlabel(instname, &inst_mult));
my_strdup2(_ALLOC_ID_, &path, xctx->sch_path[xctx->currsch]);
@@ -2261,6 +2310,7 @@ int descend_schematic(int instnumber, int fallback, int alert, int set_title)
int inst_mult, inst_number;
int save_ok = 0;
int i, n = 0;
+ int descend_ok = 1;
if(xctx->currsch + 1 >= CADMAXHIER) {
dbg(0, "descend_schematic(): max hierarchy depth reached: %d", CADMAXHIER);
@@ -2416,24 +2466,25 @@ int descend_schematic(int instnumber, int fallback, int alert, int set_title)
dbg(1, "descend_schematic(): filename=%s\n", filename);
/* we are descending from a parent schematic downloaded from the web */
if(!tclgetboolvar("keep_symbols")) remove_symbols();
- load_schematic(1, filename, (set_title & 1), alert);
- if(xctx->hilight_nets) {
- prepare_netlist_structs(0);
- propagate_hilights(1, 0, XINSERT_NOREPLACE);
- }
- dbg(1, "descend_schematic(): before zoom(): prep_hash_inst=%d\n", xctx->prep_hash_inst);
-
- if(xctx->rects[GRIDLAYER] > 0 && tcleval("info exists ngspice::ngspice_data")[0] == '0') {
- Graph_ctx *gr = &xctx->graph_struct;
- xRect *r = &xctx->rect[GRIDLAYER][0];
- if(r->flags & 1) {
- backannotate_at_cursor_b_pos(r, gr);
+ descend_ok = load_schematic(1, filename, (set_title & 1), alert);
+ if(descend_ok) {
+ if(xctx->hilight_nets) {
+ prepare_netlist_structs(0);
+ propagate_hilights(1, 0, XINSERT_NOREPLACE);
+ }
+ dbg(1, "descend_schematic(): before zoom(): prep_hash_inst=%d\n", xctx->prep_hash_inst);
+
+ if(xctx->rects[GRIDLAYER] > 0 && tcleval("info exists ngspice::ngspice_data")[0] == '0') {
+ Graph_ctx *gr = &xctx->graph_struct;
+ xRect *r = &xctx->rect[GRIDLAYER][0];
+ if(r->flags & 1) {
+ backannotate_at_cursor_b_pos(r, gr);
+ }
}
}
-
zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97);
}
- return 1;
+ return descend_ok;
}
/*
@@ -2449,7 +2500,7 @@ void go_back(int what)
char filename[PATH_MAX];
int prev_sch_type;
int confirm = what & 1;
- int set_title = !(confirm & 2);
+ int set_title = !(what & 2);
save_ok=1;
dbg(1,"go_back(): sch[xctx->currsch]=%s\n", xctx->sch[xctx->currsch]);
@@ -3132,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);
}
}
}
@@ -3830,7 +3831,7 @@ int place_text(int draw_text, double mx, double my)
dbg(1,"props=%s, txt=%s\n", props, txt);
create_text(draw_text, mx, my, 0, 0, txt, props, atof(hsize), atof(vsize));
- select_text(xctx->texts - 1, SELECTED, 0);
+ select_text(xctx->texts - 1, SELECTED, 0, 1);
rebuild_selected_array(); /* sets xctx->ui_state |= SELECTION */
drawtemprect(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0);
drawtempline(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0);
diff --git a/src/callback.c b/src/callback.c
index aac70f13..a9158ee3 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -50,16 +50,21 @@ static int waves_selected(int event, KeySym key, int state, int button)
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(!strboolcmp(get_tok_value(xctx->rect[GRIDLAYER][i].prop_ptr, "lock", 0), "true")) 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 + 20, r->y1 + 8, r->x2 - 20, r->y2 - 8) ||
+ 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)
)
@@ -198,7 +203,6 @@ static void start_place_symbol(void)
tclvareval("set INITIALINSTDIR [file dirname {",
abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), ""), "}]", NULL);
}
- unselect_all(1);
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 */) ) {
@@ -209,7 +213,7 @@ static void start_place_symbol(void)
}
}
-static void start_line(double mx, double my)
+void start_line(double mx, double my)
{
xctx->last_command = STARTLINE;
if(xctx->ui_state & STARTLINE) {
@@ -229,7 +233,7 @@ static void start_line(double mx, double my)
new_line(PLACE, mx, my);
}
-static void start_wire(double mx, double 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);
@@ -427,7 +431,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
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;
+ /* 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
@@ -921,7 +925,9 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
if(gr->dataset >= 0 /* && gr->dataset < xctx->raw->datasets */) dataset =gr->dataset;
else dataset = -1;
- if(!strcmp(curr_sim_type,
+ /* 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;
}
@@ -1379,245 +1385,6 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
return 0;
}
-/* 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");
- 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) ) {
- /* 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");
- }
- }
-
- /* 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) {
- if(xhair_size) {
- MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- 2 * INT_WIDTH(xctx->lw) + 2 * xhair_size,
- 2 * INT_WIDTH(xctx->lw) + 2 * xhair_size,
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw) - xhair_size);
- MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- 2 * INT_WIDTH(xctx->lw) + 2 * xhair_size,
- 2 * INT_WIDTH(xctx->lw) + 2 * xhair_size,
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw) - xhair_size,
- (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw) - xhair_size);
- } else { /* full screen span xhair */
- MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
- 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw),
- xctx->xrect[0].width, 2 * INT_WIDTH(xctx->lw),
- 0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 1 * INT_WIDTH(xctx->lw));
- MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw), 0,
- 2 * INT_WIDTH(xctx->lw), xctx->xrect[0].height,
- (int)X_TO_SCREEN(xctx->prev_crossx) - 1 * INT_WIDTH(xctx->lw), 0);
- }
-
- } else {
- if(xhair_size) {
- draw_xhair_line(xctx->gctiled, xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) - xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) - xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) + xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) - xhair_size);
- draw_xhair_line(xctx->gctiled, xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) - xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) + xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) + xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) + xhair_size);
- draw_xhair_line(xctx->gctiled, xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) - xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) - xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) - xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) + xhair_size);
- draw_xhair_line(xctx->gctiled, xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) + xhair_size,
- Y_TO_SCREEN(xctx->prev_crossy) - xhair_size,
- X_TO_SCREEN(xctx->prev_crossx) + xhair_size,
- Y_TO_SCREEN(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 & 2) { /* draw new */
- if(xhair_size) {
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- X_TO_SCREEN(mx) - xhair_size,
- Y_TO_SCREEN(my) - xhair_size,
- X_TO_SCREEN(mx) + xhair_size,
- Y_TO_SCREEN(my) - xhair_size);
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- X_TO_SCREEN(mx) - xhair_size,
- Y_TO_SCREEN(my) + xhair_size,
- X_TO_SCREEN(mx) + xhair_size,
- Y_TO_SCREEN(my) + xhair_size);
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- X_TO_SCREEN(mx) - xhair_size,
- Y_TO_SCREEN(my) - xhair_size,
- X_TO_SCREEN(mx) - xhair_size,
- Y_TO_SCREEN(my) + xhair_size);
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- X_TO_SCREEN(mx) + xhair_size,
- Y_TO_SCREEN(my) - xhair_size,
- X_TO_SCREEN(mx) + xhair_size,
- Y_TO_SCREEN(my) + xhair_size);
- } else { /* full screen span xhair */
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- xctx->areax1, Y_TO_SCREEN(my),
- xctx->areax2, Y_TO_SCREEN(my));
- draw_xhair_line(xctx->gc[xctx->crosshair_layer], xhair_size,
- X_TO_SCREEN(mx), xctx->areay1,
- X_TO_SCREEN(mx), xctx->areay2);
- }
- }
- 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;
-}
-
-/* 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)
-{
- 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;
-
- if(!xctx->mouse_inside) return;
- xctx->draw_pixmap = 0;
- xctx->draw_window = 1;
- 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) - 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) - 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),
- 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) {
- double x, y;
- if(!pos_changed) {
- x = xctx->prev_snapx;
- y = xctx->prev_snapy;
- } else { /* Only search for nearest pin if the grid-snap-point has changed */
- xctx->closest_pin_found = find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y);
- }
- 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;
- xctx->prev_snapy = y;
- }
- draw_selection(xctx->gc[SELLAYER], 0);
-
- xctx->draw_window = sdw;
- xctx->draw_pixmap = sdp;
-}
-
/* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */
static int end_place_move_copy_zoom()
{
@@ -1699,6 +1466,195 @@ static int end_place_move_copy_zoom()
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;
@@ -1709,13 +1665,14 @@ static void unselect_at_mouse_pos(int mx, int my)
rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */
}
-void snapped_wire(double c_snap)
+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);
}
@@ -1729,7 +1686,7 @@ void snapped_wire(double c_snap)
}
}
-static int check_menu_start_commands(double c_snap, int mx, int my)
+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);
@@ -1770,10 +1727,14 @@ static int check_menu_start_commands(double c_snap, int mx, int my)
else if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRE)) {
int prev_state = xctx->ui_state;
if(xctx->semaphore >= 2) return 0;
- start_wire(xctx->mousex_snap, xctx->mousey_snap);
- if(prev_state == STARTWIRE) {
- tcleval("set constr_mv 0" );
- xctx->constr_mv=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;
+ }
}
/*
@@ -2433,6 +2394,54 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke
}
#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;
@@ -2463,7 +2472,7 @@ static void handle_enter_notify(int draw_xhair, int crosshair_size)
xctx->mousey_snap = -340;
merge_file(1, ".sch");
}
-
+
return;
}
@@ -2477,9 +2486,8 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i
}
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);
}
- if(snap_cursor && wire_draw_active) draw_snap_cursor(1);
+ if(snap_cursor) draw_snap_cursor(1); /* clear */
/* pan schematic */
if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my);
@@ -2487,7 +2495,7 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i
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);
+ if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(2); /* redraw */
return;
}
@@ -2588,7 +2596,7 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i
if(draw_xhair) {
draw_crosshair(2, state); /* what = 2(draw) */
}
- if(snap_cursor && wire_draw_active) draw_snap_cursor(2);
+ if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(2); /* redraw */
return;
}
@@ -2597,1507 +2605,1514 @@ 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;
- }
- 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 && 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();
- 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(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);
+ 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 */
+ 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;
+ 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;
+ 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;
+ 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( 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;
- }
+ }
+ 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);
+ }
- 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;
+ 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 */
+ 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;
+ 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;
+
+ 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,
@@ -4215,7 +4230,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in
return;
}
/* handle all object insertions started from Tools/Edit menu */
- if(check_menu_start_commands(c_snap, mx, my)) return;
+ 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;
@@ -4382,6 +4397,7 @@ static void handle_button_release(int event, KeySym key, int state, int button,
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;
@@ -4442,13 +4458,12 @@ static void handle_button_release(int event, KeySym key, int state, int button,
}
/* clear start from menu flag or infix_interface=0 start commands */
- if(xctx->ui_state & MENUSTART) {
+ 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 && wire_draw_active) draw_snap_cursor(3);
-
+ if(snap_cursor && ((state == ShiftMask) || wire_draw_active)) draw_snap_cursor(3); /* erase & redraw */
return;
}
@@ -4634,7 +4649,7 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) ||
case LeaveNotify:
if(draw_xhair) draw_crosshair(1, state); /* clear crosshair when exiting window */
- if(snap_cursor && wire_draw_active) draw_snap_cursor(1);
+ if(snap_cursor) draw_snap_cursor(1); /* erase */
tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL);
xctx->mouse_inside = 0;
break;
@@ -4678,6 +4693,8 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) ||
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:
diff --git a/src/draw.c b/src/draw.c
index bee7b42b..c6bbeabe 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -930,10 +930,14 @@ static void drawgrid()
double mult;
#if DRAW_ALL_CAIRO==0
int i=0;
+ const char *psize_ptr;
int big_gr = tclgetboolvar("big_grid_points");
+ int grid_point_size = -1;
char dash_arr[2];
int axes = tclgetboolvar("draw_grid_axes");
+ psize_ptr = tclgetvar("grid_point_size");
+ if(psize_ptr[0]) grid_point_size = atoi(psize_ptr);
if(axes) {
dash_arr[0] = dash_arr[1] = (char) 3;
XSetDashes(display, xctx->gc[GRIDLAYER], 0, dash_arr, 1);
@@ -959,9 +963,8 @@ static void drawgrid()
delta = delta * pow(CADGRIDMULTIPLY, mult);
}
- /* while(delta < CADGRIDTHRESHOLD) delta *= CADGRIDMULTIPLY; */ /* <-- to be improved,but works */
-
+ /* ************************ Draw axes ****************** */
#if DRAW_ALL_CAIRO==1
xax =floor(xctx->xorigin*xctx->mooz) + 0.5; yax = floor(xctx->yorigin*xctx->mooz) + 0.5;
#else
@@ -1007,26 +1010,36 @@ static void drawgrid()
#endif
}
}
+ /* ************************ /Draw axes ****************** */
+
#if DRAW_ALL_CAIRO==0
- if(axes) {
+ if(grid_point_size != -1) {
+ XSetLineAttributes (display, xctx->gc[GRIDLAYER],
+ grid_point_size, LineSolid, CapProjecting, LINEJOIN);
+ } else if(!big_gr) {
+ XSetLineAttributes (display, xctx->gc[GRIDLAYER],
+ 0, LineSolid, LINECAP, LINEJOIN);
+ } else {
XSetLineAttributes (display, xctx->gc[GRIDLAYER],
XLINEWIDTH(xctx->lw), LineSolid, LINECAP, LINEJOIN);
}
#endif
+ if(grid_point_size >= 0) big_gr = 1;
+
tmp = floor((xctx->areay1+1)/delta)*delta-fmod(-xctx->yorigin*xctx->mooz, delta);
for(x=floor((xctx->areax1+1)/delta)*delta-fmod(-xctx->xorigin*xctx->mooz, delta); x < xctx->areax2; x += delta) {
xx = x;
#if DRAW_ALL_CAIRO==1
xx = floor(x) + 0.5;
#endif
- if((int)xx == (int)xax) continue;
+ if(axes && (int)xx == (int)xax) continue;
for(y=tmp; y < xctx->areay2; y += delta) {
yy = y;
#if DRAW_ALL_CAIRO==1
yy = floor(y) + 0.5;
#endif
- if((int)yy == (int)yax) continue;
+ if(axes && (int)yy == (int)yax) continue;
#if DRAW_ALL_CAIRO==1
if(xctx->draw_window) {
cairo_move_to(xctx->cairo_ctx, xx, yy) ;
@@ -1087,6 +1100,12 @@ static void drawgrid()
if(xctx->draw_pixmap) cairo_stroke(xctx->cairo_save_ctx);
if(xctx->draw_window) cairo_stroke(xctx->cairo_ctx);
#endif
+
+ #if DRAW_ALL_CAIRO==0
+ XSetLineAttributes (display, xctx->gc[GRIDLAYER],
+ XLINEWIDTH(xctx->lw), LineSolid, LINECAP, LINEJOIN);
+ #endif
+
}
#if !defined(__unix__) && HAS_CAIRO==1
@@ -1356,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;
@@ -2838,7 +2896,7 @@ static void draw_graph_grid(Graph_ctx *gr, void *ct)
/* background */
filledrect(0, NOW, gr->rx1, gr->ry1, gr->rx2, gr->ry2, 2, -1, -1);
/* graph bounding box */
- drawrect(GRIDLAYER, NOW, gr->rx1, gr->ry1, gr->rx2, gr->ry2, 0, -1, -1);
+ drawrect(GRIDLAYER, NOW, gr->rx1, gr->ry1, gr->rx2, gr->ry2, 2, -1, -1);
bbox(START, 0.0, 0.0, 0.0, 0.0);
bbox(ADD, gr->rx1, gr->ry1, gr->rx2, gr->ry2);
@@ -3055,10 +3113,9 @@ void setup_graph_data(int i, int skip, Graph_ctx *gr)
gr->gh = gr->gy2 - gr->gy1;
/* set margins */
tmp = gr->rw * 0.14;
- gr->marginx = tmp < 50 ? 50 : tmp;
+ gr->marginx = tmp;
tmp = gr->rh * 0.14;
- gr->marginy = tmp < 40 ? 40 : tmp;
-
+ gr->marginy = tmp;
/* calculate graph bounding box (container - margin)
* This is the box where plot is done */
gr->x1 = gr->rx1 + gr->marginx;
@@ -3083,14 +3140,15 @@ void setup_graph_data(int i, int skip, Graph_ctx *gr)
/* x axis, y axis text sizes */
gr->txtsizey = gr->h / gr->divy * 0.0095;
- tmp = gr->marginx * 0.003;
- if(tmp < gr->txtsizey) gr->txtsizey = tmp;
- tmp = gr->marginy * 0.02;
+ tmp = gr->marginx * 0.004;
if(tmp < gr->txtsizey) gr->txtsizey = tmp;
+ /* tmp = gr->marginy * 0.02;
+ * if(tmp < gr->txtsizey) gr->txtsizey = tmp;
+ */
gr->txtsizey *= gr->magy;
- gr->txtsizex = gr->w / gr->divx * 0.0033;
- tmp = gr->marginy * 0.0063;
+ gr->txtsizex = gr->w / gr->divx * 0.0070;
+ tmp = gr->marginy * 0.0065;
if(tmp < gr->txtsizex) gr->txtsizex = tmp;
gr->txtsizex *= gr->magx;
@@ -3258,7 +3316,7 @@ static void draw_graph_variables(int wcnt, int wave_color, int n_nodes, int swee
if(gr->unitx != 1.0) my_snprintf(tmpstr, S(tmpstr), "%s[%c]", stok ? stok : "" , gr->unitx_suffix);
else my_snprintf(tmpstr, S(tmpstr), "%s", stok ? stok : "");
draw_string(wave_color, NOW, tmpstr, 2, 1, 0, 0,
- gr->rx1 + 2 + gr->rw / n_nodes * wcnt, gr->ry2-5, gr->txtsizelab, gr->txtsizelab);
+ gr->rx1 + 2 + gr->rw / n_nodes * wcnt, gr->ry2-2, gr->txtsizelab, gr->txtsizelab);
}
if(gr->legend || gr->digital) {
@@ -3782,7 +3840,7 @@ int find_closest_wave(int i, Graph_ctx *gr)
* 8: all drawing, if not set do only XCopyArea / x-cursor if specified
* ct is a pointer used in windows for cairo
*/
-void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
+void draw_graph(int i, int flags, Graph_ctx *gr, void *ct)
{
int wc = 4, wave_color = 4;
char *node = NULL, *color = NULL, *sweep = NULL;
@@ -3804,7 +3862,6 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
int save_extra_idx = -1;
double cursor1, cursor2;
-
if(xctx->only_probes) return;
if(RECT_OUTSIDE( gr->sx1, gr->sy1, gr->sx2, gr->sy2,
xctx->areax1, xctx->areay1, xctx->areax2, xctx->areay2)) return;
@@ -4089,7 +4146,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
if((gr->mode == 2) || (xxfollowing >= start && xxprevious <= end)) {
if(first == -1) first = p;
/* Build poly x array. Translate from graph coordinates to screen coords */
- point[poly_npoints].x = (short)S_X(xx);
+ point[poly_npoints].x = (short)CLIP(S_X(xx), -30000, 30000);
if(dataset == -1 || dataset == sweepvar_wrap) {
/* cursor1: show measurements on nodes in graph */
if(flags & 2 && measure_p == -1 && cnt) {
@@ -4770,8 +4827,11 @@ static void draw_images_all(void)
#endif
}
-void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, double ry2)
+void svg_embedded_graph(FILE *fd, int i, double rx1, double ry1, double rx2, double ry2)
{
+ #ifndef __unix__
+ xRect *r = &xctx->rect[GRIDLAYER][i];
+ #endif
#if HAS_CAIRO==1
Zoom_info zi;
char *ptr = NULL;
@@ -4821,7 +4881,9 @@ void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2,
xctx->draw_pixmap=1;
save = xctx->do_copy_area;
xctx->do_copy_area=0;
- draw();
+ setup_graph_data(i, 0, &xctx->graph_struct);
+ draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, NULL);
+
#ifdef __unix__
png_sfc = cairo_xlib_surface_create(display, xctx->save_pixmap, visual,
xctx->xrect[0].width, xctx->xrect[0].height);
@@ -4834,12 +4896,9 @@ void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2,
cairo_set_source_surface(ct, xctx->cairo_save_sfc, 0, 0);
cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(ct);
- for(int i = 0; i < xctx->rects[GRIDLAYER]; ++i) {
- xRect *r = &xctx->rect[GRIDLAYER][i];
- if(r->flags & 1) {
- setup_graph_data(i, 0, &xctx->graph_struct);
- draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, (void *)ct);
- }
+ if(r->flags & 1) {
+ setup_graph_data(i, 0, &xctx->graph_struct);
+ draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, (void *)ct);
}
#endif
closure.buffer = NULL;
diff --git a/src/editprop.c b/src/editprop.c
index 3a7f9323..dbe65604 100644
--- a/src/editprop.c
+++ b/src/editprop.c
@@ -594,7 +594,11 @@ FILE *my_fopen(const char *f, const char *m)
st = stat(f, &buf);
if(st) return NULL; /* not existing or error */
+#ifdef __unix__
if(!S_ISREG(buf.st_mode)) return NULL; /* not a regular file/symlink to a regular file */
+#else
+ /* TBD */
+#endif
fd = fopen(f, m);
return fd;
}
@@ -1637,6 +1641,7 @@ static int update_symbol(const char *result, int x, int selected_inst)
/* preserve backslashes in name ---------0---------------------------------->. */
my_strdup(_ALLOC_ID_, &name, get_tok_value(xctx->inst[*ii].prop_ptr, "name", 1));
if(name && name[0] ) {
+ char *old_name = NULL;
dbg(1, "update_symbol(): prefix!='\\0', name=%s\n", name);
/* change prefix if changing symbol type; */
if(prefix && old_prefix && old_prefix != prefix) {
@@ -1650,10 +1655,13 @@ static int update_symbol(const char *result, int x, int selected_inst)
if(!k) hash_names(-1, XINSERT);
hash_names(*ii, XDELETE);
dbg(1, "update_symbol(): delete %s\n", xctx->inst[*ii].instname);
+ my_strdup2(_ALLOC_ID_, &old_name, xctx->inst[*ii].instname);
new_prop_string(*ii, ptr, /* sets also inst[].instname */
tclgetboolvar("disable_unique_names")); /* set new prop_ptr */
hash_names(*ii, XINSERT);
+ update_attached_floaters(old_name, *ii, 1);
dbg(1, "update_symbol(): insert %s\n", xctx->inst[*ii].instname);
+ my_free(_ALLOC_ID_, &old_name);
}
set_inst_flags(&xctx->inst[*ii]);
} /* end for(k=0;klastsel; ++k) */
diff --git a/src/eval_expr.y b/src/eval_expr.y
index 5198718f..80eb696f 100644
--- a/src/eval_expr.y
+++ b/src/eval_expr.y
@@ -274,10 +274,11 @@ static int kklex()
while (c != 0 && isalnum(c) && i < length);
str--;
symbuf[i] = '\0';
- s = getsym (symbuf);
+ s = getsym(symbuf);
kklval.tptr = s;
dbg(dbglev, "ylex: FNCT=%s\n", symbuf);
- return FNCT;
+ if(s) return FNCT;
+ return 0; /* error : undefined identifier */
}
/* Any other character is a token by itself. */
return c;
diff --git a/src/findnet.c b/src/findnet.c
index ba36fc71..41d2d489 100644
--- a/src/findnet.c
+++ b/src/findnet.c
@@ -25,7 +25,7 @@
static double distance; /* safe to keep even with multiple schematics */
static Selected sel; /* safe to keep even with multiple schematics */
-static void find_closest_wire(double mx, double my)
+static void find_closest_wire(double mx, double my, int override_lock)
/* returns the net that is closest to the mouse pointer */
/* if there are nets and distance < CADWIREMINDIST */
{
@@ -42,14 +42,15 @@ static void find_closest_wire(double mx, double my)
w = i; d = tmp;
}
}
- if( d <= threshold && w!=-1)
+ if( w != -1 && d <= threshold &&
+ (override_lock || strboolcmp(get_tok_value(xctx->wire[w].prop_ptr, "lock", 0), "true")) )
{
sel.n = w; sel.type = WIRE;
distance = d;
}
}
-static void find_closest_bezier(double mx, double my, int c, int i, int *l, int *col)
+static double find_closest_bezier(double mx, double my, double d, int c, int i, int *l, int *col)
{
const double bez_steps = 1.0/8.0; /* divide the t = [0,1] interval into 8 steps */
int b;
@@ -97,16 +98,17 @@ static void find_closest_bezier(double mx, double my, int c, int i, int *l, int
xp1 = (1 - t1) * (1 - t1) * x0 + 2 * (1 - t1) * t1 * x1 + t1 * t1 * x2;
yp1 = (1 - t1) * (1 - t1) * y0 + 2 * (1 - t1) * t1 * y1 + t1 * t1 * y2;
ORDER(xp, yp, xp1, yp1);
- if( (tmp = dist(xp, yp, xp1, yp1, mx, my)) < distance )
+ if( (tmp = dist(xp, yp, xp1, yp1, mx, my)) < d )
{
- *l = i; distance = tmp; *col = c;
- dbg(1, "find_closest_bezier(): distance=%.16g n=%d\n", distance, i);
+ *l = i; d = tmp; *col = c;
}
}
}
+ dbg(1, "find_closest_bezier(): d=%.16g n=%d\n", d, i);
+ return d;
}
-static void find_closest_polygon(double mx, double my)
+static void find_closest_polygon(double mx, double my, int override_lock)
/* returns the polygon that is closest to the mouse pointer */
/* if there are lines and distance < CADWIREMINDIST */
{
@@ -126,15 +128,7 @@ static void find_closest_polygon(double mx, double my)
bezier = bezier && (p->points > 2);
if(bezier) {
- double ds = xctx->cadhalfdotsize;
-
- find_closest_bezier(mx, my, c, i, &l, &col);
- for(j = 0; j < p->points; j++) {
- if( POINTINSIDE(mx, my, p->x[j] - ds, p->y[j] - ds, p->x[j] + ds, p->y[j] + ds)) {
- l = i; d = 0.0;col = c;
- break;
- }
- }
+ d = find_closest_bezier(mx, my, d, c, i, &l, &col);
} else {
for(j=0; jpoly[c][i].points-1; ++j) {
x1 = p->x[j];
@@ -145,13 +139,14 @@ static void find_closest_polygon(double mx, double my)
if( (tmp = dist(x1, y1, x2, y2, mx, my)) < d )
{
l = i; d = tmp;col = c;
- dbg(1, "find_closest_polygon(): d=%.16g n=%d\n", d, i);
}
}
+ dbg(1, "find_closest_polygon(): d=%.16g n=%d\n", d, i);
}
} /* end for i */
} /* end for c */
- if( d <= threshold && l!=-1)
+ if( d <= threshold && l!=-1 &&
+ (override_lock || strboolcmp(get_tok_value(xctx->poly[col][l].prop_ptr, "lock", 0), "true")))
{
sel.n = l; sel.type = POLYGON; sel.col = col;
distance = d;
@@ -159,7 +154,7 @@ static void find_closest_polygon(double mx, double my)
}
-static void find_closest_line(double mx, double my)
+static void find_closest_line(double mx, double my, int override_lock)
/* returns the line that is closest to the mouse pointer */
/* if there are lines and distance < CADWIREMINDIST */
{
@@ -181,7 +176,8 @@ static void find_closest_line(double mx, double my)
}
} /* end for i */
} /* end for c */
- if( d <= threshold && l!=-1)
+ if( d <= threshold && l!=-1 &&
+ (override_lock || strboolcmp(get_tok_value(xctx->line[col][l].prop_ptr, "lock", 0), "true")))
{
sel.n = l; sel.type = LINE; sel.col = col;
distance = d;
@@ -326,7 +322,7 @@ void xfind_closest_net_or_symbol_pin(double mx, double my, double *x, double *y)
}
#endif
-static void find_closest_arc(double mx, double my)
+static void find_closest_arc(double mx, double my, int override_lock)
{
double dist, angle, angle1, angle2;
int i, c, r=-1, col;
@@ -371,7 +367,8 @@ static void find_closest_arc(double mx, double my)
}
} /* end for i */
} /* end for c */
- if( r!=-1 && d <= threshold ) /* * pow(xctx->arc[col][r].r, 2)) */
+ if(r!=-1 && d <= threshold &&
+ strboolcmp(get_tok_value(xctx->arc[col][r].prop_ptr, "lock", 0), "true"))
{
sel.n = r; sel.type = ARC; sel.col = col;
distance = d;
@@ -439,7 +436,7 @@ static void find_closest_element(double mx, double my, int override_lock)
}
}
-static void find_closest_text(double mx, double my)
+static void find_closest_text(double mx, double my, int override_lock)
{
short rot, flip;
double xx1, xx2, yy1, yy2;
@@ -476,7 +473,9 @@ static void find_closest_text(double mx, double my)
dbg(2, "find_closest_text(): finding closest text, texts=%d, dist=%.16g\n", i, d);
}
} /* end for i */
- if( d <= threshold && r!=-1)
+
+ if( r != -1 && d <= threshold &&
+ (override_lock || strboolcmp(get_tok_value(xctx->text[r].prop_ptr, "lock", 0), "true")) )
{
sel.n = r; sel.type = xTEXT;
distance = d;
@@ -487,14 +486,14 @@ Selected find_closest_obj(double mx, double my, int override_lock)
{
sel.n = 0L; sel.col = 0; sel.type = 0;
distance = DBL_MAX;
- find_closest_line(mx, my);
- find_closest_polygon(mx, my);
+ find_closest_line(mx, my, override_lock);
+ find_closest_polygon(mx, my, override_lock);
/* dbg(1, "1 find_closest_obj(): sel.n=%d, sel.col=%d, sel.type=%d\n", sel.n, sel.col, sel.type); */
find_closest_box(mx, my, override_lock);
- find_closest_arc(mx, my);
+ find_closest_arc(mx, my, override_lock);
/* dbg(1, "2 find_closest_obj(): sel.n=%d, sel.col=%d, sel.type=%d\n", sel.n, sel.col, sel.type); */
- find_closest_text(mx, my);
- find_closest_wire(mx, my);
+ find_closest_text(mx, my, override_lock);
+ find_closest_wire(mx, my, override_lock);
find_closest_element(mx, my, override_lock);
return sel; /*sel.type = 0 if nothing found */
}
diff --git a/src/keys.help b/src/keys.help
index a73197bf..a473aa45 100644
--- a/src/keys.help
+++ b/src/keys.help
@@ -169,6 +169,7 @@ ctrl+alt 's' Save-as symbol
- 't' Place text
shift 'T' Toggle *_ignore flag on selected instances
alt 'u' Align to current grid selected objects
+ctrl 'u' Unselect attached floater objects
shift 'U' Redo
- 'u' Undo
- 'v' Constrained vertical move/copy of objects
diff --git a/src/move.c b/src/move.c
index c6fc2b55..59893122 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:
@@ -513,6 +513,82 @@ void draw_selection(GC g, int interruptable)
xctx->movelastsel = i;
}
+/* sel: if set to 1 change references only on selected items, like in a copy operation.
+ * If set to 0 operate on all objects with matching name=... attribute */
+void update_attached_floaters(const char *from_name, int inst, int sel)
+{
+ int i, c;
+ char *to_name = xctx->inst[inst].instname;
+ const char *attach = get_tok_value(xctx->inst[inst].prop_ptr, "attach", 0);
+ char *new_attach;
+
+ if(!from_name || !from_name[0]) return;
+ if(!to_name || !to_name[0]) return;
+ if(!attach[0]) return;
+
+ new_attach = str_replace(attach, from_name, to_name, 1, 1);
+ my_strdup(_ALLOC_ID_, &xctx->inst[inst].prop_ptr,
+ subst_token(xctx->inst[inst].prop_ptr, "attach", new_attach) );
+
+ for(c = 0; c < cadlayers; c++) {
+ for(i = 0; i < xctx->rects[c]; i++) {
+ if(!sel || xctx->rect[c][i].sel == SELECTED) {
+ if( !strcmp(from_name, get_tok_value(xctx->rect[c][i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->rect[c][i].prop_ptr,
+ subst_token(xctx->rect[c][i].prop_ptr, "name", to_name) );
+ }
+ if(c == GRIDLAYER) {
+ const char *node = get_tok_value(xctx->rect[c][i].prop_ptr, "node", 2);
+ if(node && node[0]) {
+ const char *new_node = str_replace(node, from_name, to_name, 1, -1);
+ my_strdup(_ALLOC_ID_, &xctx->rect[c][i].prop_ptr,
+ subst_token(xctx->rect[c][i].prop_ptr, "node", new_node));
+ }
+ }
+ }
+ }
+ for(i = 0; i < xctx->lines[c]; i++) {
+ if((!sel || xctx->line[c][i].sel == SELECTED) &&
+ !strcmp(from_name, get_tok_value(xctx->line[c][i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->line[c][i].prop_ptr,
+ subst_token(xctx->line[c][i].prop_ptr, "name", to_name) );
+ }
+ }
+
+ for(i = 0; i < xctx->polygons[c]; i++) {
+ if((!sel || xctx->poly[c][i].sel == SELECTED) &&
+ !strcmp(from_name, get_tok_value(xctx->poly[c][i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->poly[c][i].prop_ptr,
+ subst_token(xctx->poly[c][i].prop_ptr, "name", to_name) );
+
+ }
+ }
+ for(i = 0; i < xctx->arcs[c]; i++) {
+ if((!sel || xctx->arc[c][i].sel == SELECTED) &&
+ !strcmp(from_name, get_tok_value(xctx->arc[c][i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->arc[c][i].prop_ptr,
+ subst_token(xctx->arc[c][i].prop_ptr, "name", to_name) );
+ }
+ }
+ }
+ for(i = 0; i < xctx->wires; i++) {
+ if((!sel || xctx->wire[i].sel == SELECTED) &&
+ !strcmp(from_name, get_tok_value(xctx->wire[i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->wire[i].prop_ptr,
+ subst_token(xctx->wire[i].prop_ptr, "name", to_name) );
+ }
+ }
+ for(i = 0; i < xctx->texts; i++) {
+ if((!sel || xctx->text[i].sel == SELECTED) &&
+ !strcmp(from_name, get_tok_value(xctx->text[i].prop_ptr, "name", 0))) {
+ my_strdup(_ALLOC_ID_, &xctx->text[i].prop_ptr,
+ subst_token(xctx->text[i].prop_ptr, "name", to_name) );
+ set_text_flags(&xctx->text[i]);
+ }
+ }
+}
+
+
void copy_objects(int what)
{
int tmpi, c, i, n, k /*, tmp */ ;
@@ -881,6 +957,9 @@ void copy_objects(int what)
newpropcnt++;
new_prop_string(xctx->instances, xctx->inst[n].prop_ptr, /* sets also inst[].instname */
tclgetboolvar("disable_unique_names"));
+
+ update_attached_floaters(xctx->inst[n].instname, xctx->instances, 1);
+
hash_names(xctx->instances, XINSERT);
xctx->instances++; /* symbol_bbox calls translate and translate must have updated xctx->instances */
symbol_bbox(xctx->instances-1,
@@ -1056,10 +1135,36 @@ 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].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);
+ }
+ 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);
+ }
+ else
+ {
+ wire[n].x2 = xctx->rx2;
+ wire[n].y2 = xctx->ry2;
+ }
+
}
break;
diff --git a/src/netlist.c b/src/netlist.c
index afa7f5b0..407049a2 100644
--- a/src/netlist.c
+++ b/src/netlist.c
@@ -678,7 +678,7 @@ static void print_wires(void)
ptr=xctx->wire_spatial_table[0][1];
while(ptr)
{
- select_wire(ptr->n,SELECTED, 1);
+ select_wire(ptr->n,SELECTED, 1, 1);
rebuild_selected_array();
ptr=ptr->next;
}
diff --git a/src/paste.c b/src/paste.c
index 7ed3c536..4b784524 100644
--- a/src/paste.c
+++ b/src/paste.c
@@ -48,7 +48,7 @@ static void merge_text(FILE *fd)
xctx->text[i].sel=0;
load_ascii_string(&xctx->text[i].prop_ptr,fd);
set_text_flags(&xctx->text[i]);
- select_text(i,SELECTED, 1);
+ select_text(i,SELECTED, 1, 1);
xctx->texts++;
}
@@ -66,7 +66,7 @@ static void merge_wire(FILE *fd)
load_ascii_string( &ptr, fd);
storeobject(-1, x1,y1,x2,y2,WIRE,0,SELECTED,ptr);
my_free(_ALLOC_ID_, &ptr);
- select_wire(i, SELECTED, 1);
+ select_wire(i, SELECTED, 1, 1);
}
static void merge_box(FILE *fd)
@@ -172,7 +172,7 @@ static void merge_arc(FILE *fd)
ptr[i].dash = 0;
}
- select_arc(c,i, SELECTED, 1);
+ select_arc(c,i, SELECTED, 1, 1);
xctx->arcs[c]++;
}
@@ -232,7 +232,7 @@ static void merge_polygon(FILE *fd)
ptr[i].dash = 0;
}
- select_polygon(c,i, SELECTED, 1);
+ select_polygon(c,i, SELECTED, 1, 1);
xctx->polygons[c]++;
}
@@ -271,7 +271,7 @@ static void merge_line(FILE *fd)
ptr[i].bus = 1;
else
ptr[i].bus = 0;
- select_line(c,i, SELECTED, 1);
+ select_line(c,i, SELECTED, 1, 1);
xctx->lines[c]++;
}
diff --git a/src/psprint.c b/src/psprint.c
index 3332aeb8..def868ff 100644
--- a/src/psprint.c
+++ b/src/psprint.c
@@ -250,8 +250,9 @@ static int ps_embedded_image(xRect* r, double x1, double y1, double x2, double y
return 1;
}
-static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, double ry2)
+static int ps_embedded_graph(int i, double rx1, double ry1, double rx2, double ry2)
{
+ xRect *r = &xctx->rect[GRIDLAYER][i];
#if defined(HAS_LIBJPEG) && HAS_CAIRO==1
Zoom_info zi;
double rw, rh, scale;
@@ -269,7 +270,7 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl
int quality=40;
const char *quality_attr;
size_t oLength;
- int i;
+ int j;
double sx1, sy1, sx2, sy2;
/* screen position */
@@ -323,7 +324,9 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl
d_c = tclgetboolvar("dark_colorscheme");
tclsetboolvar("dark_colorscheme", 0);
build_colors(0, 0);
- draw();
+ setup_graph_data(i, 0, &xctx->graph_struct);
+ draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, NULL);
+
dbg(1, "width=%d, rwi=%d height=%d rhi=%d\n", xctx->xrect[0].width, rwi, xctx->xrect[0].height, rhi);
#ifdef __unix__
png_sfc = cairo_xlib_surface_create(display, xctx->save_pixmap, visual,
@@ -337,13 +340,8 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl
cairo_set_source_surface(ct, xctx->cairo_save_sfc, 0, 0);
cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(ct);
- for (i = 0; i < xctx->rects[GRIDLAYER]; ++i) {
- xRect* r2 = &xctx->rect[GRIDLAYER][i];
- if (r2->flags & 1) {
- setup_graph_data(i, 0, &xctx->graph_struct);
- draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, (void *)ct);
- }
- }
+ setup_graph_data(i, 0, &xctx->graph_struct);
+ draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, (void *)ct);
#endif
cairo_image_surface_write_to_jpeg_mem(png_sfc, &jpgData, &fileSize, quality);
@@ -382,10 +380,10 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl
fprintf(fd, "} exec\n");
#if 1 /* break lines */
- for (i = 0; i < oLength; ++i)
+ for (j = 0; j < oLength; ++j)
{
- fputc(ascii85EncodedJpeg[i],fd);
- if(i > 0 && (i % 64) == 0)
+ fputc(ascii85EncodedJpeg[j],fd);
+ if(j > 0 && (j % 64) == 0)
{
fputc('\n',fd);
/* if (ascii85Encode[i+1]=='%') idx=63; imageMagic does this for some reason?!
@@ -1449,8 +1447,8 @@ void create_ps(char **psfile, int what, int fullzoom, int eps)
continue;
}
if (c == GRIDLAYER && (xctx->rect[c][i].flags & 1)) { /* graph */
- xRect* r = &xctx->rect[c][i];
- ps_embedded_graph(r, r->x1, r->y1, r->x2, r->y2);
+ xRect *r = &xctx->rect[c][i];
+ ps_embedded_graph(i, r->x1, r->y1, r->x2, r->y2);
}
if(c != GRIDLAYER || !(xctx->rect[c][i].flags & 1) ) {
ps_filledrect(c, xctx->rect[c][i].x1, xctx->rect[c][i].y1,
diff --git a/src/save.c b/src/save.c
index cefd1a04..a3c039eb 100644
--- a/src/save.c
+++ b/src/save.c
@@ -1014,17 +1014,16 @@ int raw_read(const char *f, Raw **rawptr, const char *type, int no_warning, doub
return res;
}
dbg(1, "raw_read(): type=%s\n", type ? type : "");
- *rawptr = my_calloc(_ALLOC_ID_, 1, sizeof(Raw));
- raw = *rawptr;
- raw->level = -1;
- raw->annot_p = -1;
- raw->sweep1 = sweep1;
- raw->sweep2 = sweep2;
- raw->annot_sweep_idx = -1;
-
- int_hash_init(&raw->table, HASHSIZE);
fd = my_fopen(f, fopen_read_mode);
if(fd) {
+ *rawptr = my_calloc(_ALLOC_ID_, 1, sizeof(Raw));
+ raw = *rawptr;
+ raw->level = -1;
+ raw->annot_p = -1;
+ raw->sweep1 = sweep1;
+ raw->sweep2 = sweep2;
+ raw->annot_sweep_idx = -1;
+ int_hash_init(&raw->table, HASHSIZE);
if((res = read_dataset(fd, rawptr, type, no_warning)) == 1) {
int i;
set_modify(-2); /* clear text floater caches */
@@ -1044,12 +1043,13 @@ int raw_read(const char *f, Raw **rawptr, const char *type, int no_warning, doub
xRect *r;
r = &xctx->rect[GRIDLAYER][0];
if(r->flags & 1) {
- setup_graph_data(0, 0, &xctx->graph_struct);
- backannotate_at_cursor_b_pos(r, &xctx->graph_struct);
+ /* don't overwrite xctx->graph_struct, being used in draw_graph() which calls raw_read() */
+ Graph_ctx gr_ctx;
+ setup_graph_data(0, 0, &gr_ctx);
+ backannotate_at_cursor_b_pos(r, &gr_ctx);
}
}
}
-
} else {
/* free_rawfile(rawptr, 0, 0); */ /* do not free: already done in read_dataset()->extra_rawfile() */
if(!no_warning) {
@@ -1074,6 +1074,22 @@ int raw_read(const char *f, Raw **rawptr, const char *type, int no_warning, doub
return 0;
}
+int raw_renamevar(const char *old_name, const char *new_name)
+{
+ int n, ret = 0;
+ Raw *raw = xctx->raw;
+ Int_hashentry *entry;
+
+ n = get_raw_index(old_name, &entry);
+ if(n < 0) return ret;
+ dbg(1, "n=%d, %s \n", n, entry->token);
+ int_hash_lookup(&raw->table, entry->token, 0, XDELETE);
+ my_strdup2(_ALLOC_ID_, &raw->names[n], new_name);
+ int_hash_lookup(&raw->table, raw->names[n], n, XINSERT); /* update hash table */
+ ret = 1;
+ return ret;
+}
+
int raw_deletevar(const char *name)
{
int ret = 0;
@@ -1206,6 +1222,7 @@ int extra_rawfile(int what, const char *file, const char *type, double sweep1, d
if(what == 0) return 0;
/* if not already done insert base raw file (if there is one) into xctx->extra_raw_arr[0] */
if(xctx->raw && xctx->extra_raw_n == 0) {
+ dbg(1, "insert extra_raw_arr[0]\n");
xctx->extra_raw_arr[xctx->extra_raw_n] = xctx->raw;
xctx->extra_raw_n++;
}
@@ -1277,7 +1294,8 @@ int extra_rawfile(int what, const char *file, const char *type, double sweep1, d
if(!no_warning) {
dbg(0, "extra_rawfile() read: %s not found or no \"%s\" analysis\n", f, type ? type : "");
}
- if(xctx->extra_raw_n) { /* only restore if raw wiles were not deleted due to a failure in read_raw() */
+ if(xctx->extra_raw_n) { /* only restore if raw files were not deleted due to a failure in read_raw() */
+ dbg(1, "extra_rawfile(): read: restore previous, extra_idx=%d\n", xctx->extra_idx);
xctx->raw = save; /* restore */
xctx->extra_prev_idx = xctx->extra_idx;
}
@@ -2783,7 +2801,8 @@ static void load_inst(int k, FILE *fd)
if(name[0] == '/') my_strdup2(_ALLOC_ID_, &xctx->inst[i].name, rel_sym_path(name));
else my_strdup2(_ALLOC_ID_, &xctx->inst[i].name, name);
#else
- my_strdup2(_ALLOC_ID_, &xctx->inst[i].name, rel_sym_path(name));
+ if(isupper(name[0]) && name[1] == ':' && name[1] == '/') my_strdup2(_ALLOC_ID_, &xctx->inst[i].name, rel_sym_path(name));
+ else my_strdup2(_ALLOC_ID_, &xctx->inst[i].name, name);
#endif
my_free(_ALLOC_ID_, &tmp);
if(fscanf(fd, "%lf %lf %hd %hd", &xctx->inst[i].x0, &xctx->inst[i].y0,
diff --git a/src/scheduler.c b/src/scheduler.c
index 38e6866e..f25ead3d 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -1725,6 +1725,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_SetResult(interp, top_path,TCL_VOLATILE);
}
break;
+ case 'u':
+ if(!strcmp(argv[2], "ui_state")) { /* return UI state */
+ if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
+ Tcl_SetResult(interp, my_itoa(xctx->ui_state), TCL_VOLATILE);
+ }
+ break;
case 'v':
if(!strcmp(argv[2], "version")) { /* return xschem version */
Tcl_SetResult(interp, XSCHEM_VERSION, TCL_VOLATILE);
@@ -1798,8 +1804,34 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_SetResult(interp, (char *)get_cell_w_ext(argv[2], atoi(argv[3])), TCL_VOLATILE);
}
}
-
/************ end xschem get subcommands *************/
+
+
+ /* get_fqdevice instname param modelparam
+ * get the full pathname of "instname" device
+ * modelparam:
+ * 0: current, 1: modelparam, 2: modelvoltage
+ * param: device parameter, like ib, gm, vth
+ * set param to {} (empty str) for just branch current of 2 terminal device
+ * for parameters like "vth" modelparam must be 2
+ * for parameters like "ib" modelparam must be 0
+ * for parameters like "gm" modelparam must be 1
+ */
+ else if(!strcmp(argv[1], "get_fqdevice"))
+ {
+ char *fqdev;
+ if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
+ if(argc > 4) {
+ fqdev = get_fqdevice(argv[3], atoi(argv[4]), argv[2]);
+ Tcl_SetResult(interp, fqdev, TCL_VOLATILE);
+ my_free(_ALLOC_ID_, &fqdev);
+ } else if(argc > 2) {
+ fqdev = get_fqdevice("", 0, argv[2]);
+ Tcl_SetResult(interp, fqdev, TCL_VOLATILE);
+ my_free(_ALLOC_ID_, &fqdev);
+ }
+ }
+
/* getprop instance|instance_pin|symbol|text ref
*
* getprop instance inst
@@ -2103,6 +2135,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
my_snprintf(res, S(res), "semaphore=%d\n", xctx->semaphore); Tcl_AppendResult(interp, res, NULL);
my_snprintf(res, S(res), "ui_state=%d\n", xctx->ui_state); Tcl_AppendResult(interp, res, NULL);
my_snprintf(res, S(res), "ui_state2=%d\n", xctx->ui_state2); Tcl_AppendResult(interp, res, NULL);
+ my_snprintf(res, S(res), "drag_elements=%d\n", xctx->drag_elements); Tcl_AppendResult(interp, res, NULL);
my_snprintf(res, S(res), "last_command=%d\n", xctx->last_command); Tcl_AppendResult(interp, res, NULL);
my_snprintf(res, S(res), "prep_net_structs=%d\n", xctx->prep_net_structs); Tcl_AppendResult(interp, res, NULL);
my_snprintf(res, S(res), "prep_hi_structs=%d\n", xctx->prep_hi_structs); Tcl_AppendResult(interp, res, NULL);
@@ -2760,13 +2793,17 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
break;
case 'l': /*----------------------------------------------*/
/* line [x1 y1 x2 y2] [pos] [propstring] [draw]
+ * line
+ * line gui
* if 'x1 y1 x2 y2'is given place line on current
* layer (rectcolor) at indicated coordinates.
- * if 'pos' is given insert at given position in rectangle array.
+ * if 'pos' is given insert at given position in line array.
* if 'pos' set to -1 append to last element in line array.
* 'propstring' is the attribute string. Set to empty if not given.
* if 'draw' is set to 1 (default) draw the new object, else don't
- * If no coordinates are given start a GUI operation of line placement */
+ * If no coordinates are given start a GUI operation of line placement
+ * if `gui` argument is given start a line GUI placement with 1st point
+ * set to current mouse coordinates */
if(!strcmp(argv[1], "line"))
{
double x1,y1,x2,y2;
@@ -2792,6 +2829,21 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
set_modify(1);
}
+ else if(argc == 3 && !strcmp(argv[2], "gui")) {
+ int prev_state = xctx->ui_state;
+ int infix_interface = tclgetboolvar("infix_interface");
+ 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 {
xctx->last_command = 0;
xctx->ui_state |= MENUSTART;
@@ -2888,11 +2940,10 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
else if(!strcmp(argv[1], "load") )
{
int load_symbols = 1, force = 1, undo_reset = 1, nofullzoom = 0, nodraw = 0;
- int keep_symbols = 0;
- size_t i;
+ int keep_symbols = 0, first;
+ int i;
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
-
for(i = 2; i < argc; i++) {
if(argv[i][0] == '-') {
if(!strcmp(argv[i], "-nosymbols")) {
@@ -2912,8 +2963,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
break;
}
}
-
- if(argc>i) {
+ first = i;
+ if(argc==2) {
+ ask_new_file();
+ tcleval("load_additional_files");
+ } else
+ for(i = first; i < argc; i++) {
char f[PATH_MAX + 100];
my_snprintf(f, S(f),"regsub {^~/} {%s} {%s/}", argv[i], home_dir);
tcleval(f);
@@ -2940,34 +2995,41 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
unselect_all(1);
/* no implicit undo: if needed do it before loading */
/* if(!undo_reset) xctx->push_undo(); */
- if(undo_reset) xctx->currsch = 0;
- if(!keep_symbols) remove_symbols();
- if(!nofullzoom) {
- xctx->zoom=CADINITIALZOOM;
- xctx->mooz=1/CADINITIALZOOM;
- xctx->xorigin=CADINITIALX;
- xctx->yorigin=CADINITIALY;
+ if(i == first) {
+ if(undo_reset) xctx->currsch = 0;
+ if(!keep_symbols) remove_symbols();
+ if(!nofullzoom) {
+ xctx->zoom=CADINITIALZOOM;
+ xctx->mooz=1/CADINITIALZOOM;
+ xctx->xorigin=CADINITIALX;
+ xctx->yorigin=CADINITIALY;
+ }
}
dbg(1, "scheduler: undo_reset=%d\n", undo_reset);
- ret = load_schematic(load_symbols, f, undo_reset, !force);
- dbg(1, "xschem load: ret=%d\n", ret);
- if(undo_reset) {
- tclvareval("update_recent_file {", f, "}", NULL);
- my_strdup(_ALLOC_ID_, &xctx->sch_path[xctx->currsch], ".");
- if(xctx->portmap[xctx->currsch].table) str_hash_free(&xctx->portmap[xctx->currsch]);
- str_hash_init(&xctx->portmap[xctx->currsch], HASHSIZE);
- xctx->sch_path_hash[xctx->currsch] = 0;
- xctx->sch_inst_number[xctx->currsch] = 1;
+
+ if(i > first) {
+ ret = new_schematic("create", "noconfirm", f, 1);
+ if(undo_reset) {
+ tclvareval("update_recent_file {", f, "}", NULL);
+ }
+ } else {
+ ret = load_schematic(load_symbols, f, undo_reset, !force);
+ dbg(1, "xschem load: f=%s, ret=%d\n", f, ret);
+ if(undo_reset) {
+ tclvareval("update_recent_file {", f, "}", NULL);
+ my_strdup(_ALLOC_ID_, &xctx->sch_path[xctx->currsch], ".");
+ if(xctx->portmap[xctx->currsch].table) str_hash_free(&xctx->portmap[xctx->currsch]);
+ str_hash_init(&xctx->portmap[xctx->currsch], HASHSIZE);
+ xctx->sch_path_hash[xctx->currsch] = 0;
+ xctx->sch_inst_number[xctx->currsch] = 1;
+ }
+ if(nofullzoom) {
+ if(!nodraw) draw();
+ } else zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97);
}
- if(nofullzoom) {
- if(!nodraw) draw();
- } else zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97);
}
}
}
- else if(argc==2) {
- ask_new_file();
- }
Tcl_SetResult(interp, xctx->sch[xctx->currsch], TCL_STATIC);
}
@@ -2980,13 +3042,32 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int cancel = 0;
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
if(argc > 2) {
- if(!is_from_web(argv[2])) {
- my_snprintf(f, S(f),"regsub {^~/} {%s} {%s/}", argv[2], home_dir);
- tcleval(f);
- /* tclvareval("file normalize {", tclresult(), "}", NULL); */
- my_strncpy(f, abs_sym_path(tclresult(), ""), S(f));
- } else {
- my_strncpy(f, argv[2], S(f));
+ int i;
+ for(i = 2; i < argc; i++) {
+ if(!is_from_web(argv[i])) {
+ my_snprintf(f, S(f),"regsub {^~/} {%s} {%s/}", argv[i], home_dir);
+ tcleval(f);
+ /* tclvareval("file normalize {", tclresult(), "}", NULL); */
+ my_strncpy(f, abs_sym_path(tclresult(), ""), S(f));
+ } else {
+ my_strncpy(f, argv[i], S(f));
+ }
+ if(f[0]) {
+ char win_path[WINDOW_PATH_SIZE];
+ dbg(1, "f=%s\n", f);
+ if(check_loaded(f, win_path)) {
+ char msg[PATH_MAX + 100];
+ my_snprintf(msg, S(msg),
+ "tk_messageBox -type okcancel -icon warning -parent [xschem get topwindow] "
+ "-message {Warning: %s already open.}", f);
+ tcleval(msg);
+ if(strcmp(tclresult(), "ok")) continue;
+ }
+ new_schematic("create", "noconfirm", f, 1);
+ tclvareval("update_recent_file {", f, "}", NULL);
+ } else {
+ new_schematic("create", NULL, NULL, 1);
+ }
}
} else {
tcleval("load_file_dialog {Load file} *.\\{sch,sym,tcl\\} INITIALLOADDIR");
@@ -2995,14 +3076,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
} else {
cancel = 1;
}
- }
- if(!cancel) {
- if(f[0]) {
- dbg(1, "f=%s\n", f);
- new_schematic("create", "noconfirm", f, 1);
- tclvareval("update_recent_file {", f, "}", NULL);
- } else {
- new_schematic("create", NULL, NULL, 1);
+ if(!cancel) {
+ if(f[0]) {
+ dbg(1, "f=%s\n", f);
+ new_schematic("create", "noconfirm", f, 1);
+ tclvareval("update_recent_file {", f, "}", NULL);
+ } else {
+ new_schematic("create", NULL, NULL, 1);
+ }
}
}
Tcl_ResetResult(interp);
@@ -3604,7 +3685,6 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
tclvareval("set INITIALINSTDIR [file dirname {",
abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), ""), "}]", NULL);
}
- unselect_all(1);
xctx->mx_double_save = xctx->mousex_snap;
xctx->my_double_save = xctx->mousey_snap;
if(argc > 3) {
@@ -3646,13 +3726,28 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
- /* polygon
- * Start a GUI placement of a polygon */
+ /* polygon [gui]
+ * Start a GUI placement of a polygon
+ * if `gui` argument is given start a polygon GUI placement with 1st point
+ * set to current mouse coordinates */
else if(!strcmp(argv[1], "polygon"))
{
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
- xctx->ui_state |= MENUSTART;
- xctx->ui_state2 = MENUSTARTPOLYGON;
+ if(argc > 2 && !strcmp(argv[2], "gui")) {
+ int infix_interface = tclgetboolvar("infix_interface");
+ 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;
+ }
+ } else {
+ xctx->ui_state |= MENUSTART;
+ xctx->ui_state2 = MENUSTARTPOLYGON;
+ }
}
/* preview_window create|draw|destroy|close [win_path] [file]
@@ -3969,8 +4064,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
case 'r': /*----------------------------------------------*/
/* raw what ...
- * what = add | clear | datasets | index | info | loaded | list | new | points | rawfile | del |
- * read | set | sim_type | switch | switch_back | table_read | value | values | pos_at | vars |
+ * what = add | clear | datasets | index | info | loaded | list |
+ * new | points | rawfile | del | read | set | rename |
+ * sim_type | switch | switch_back | table_read | value | values | pos_at | vars |
*
* xschem raw read filename [type [sweep1 sweep2]]
* if sweep1, sweep2 interval is given in 'read' subcommand load only the interval
@@ -3985,6 +4081,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* xschem raw del name
* delete named vector from current raw file
*
+ * xschem raw rename old_name new_name
+ * rename a node in the loaded raw file.
+ *
* xschem raw info
* print information about loaded raw files and show the currently active one.
*
@@ -4061,7 +4160,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* new dataset do not start with a header row.
* Lines beginning with '#' are comments and ignored
*
- * time var_a var_b var_c
+ * time var_a var_b var_cnode in the loaded raw file.
* # this is a comment, ignored
* 0.0 0.0 1.8 0.3
*
@@ -4129,9 +4228,6 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
update_op();
}
Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
- } else if(argc > 3 && !strcmp(argv[2], "del")) {
- ret = raw_deletevar(argv[3]);
- Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
} else if(argc > 2 && !strcmp(argv[2], "clear")) {
if(argc > 4) {
ret = extra_rawfile(3, argv[3], argv[4], -1.0, -1.0);
@@ -4164,6 +4260,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_SetResult(interp, dtoa(val), TCL_VOLATILE);
}
}
+ } else if(argc > 3 && !strcmp(argv[2], "del")) {
+ ret = raw_deletevar(argv[3]);
+ Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
+ } else if(argc > 4 && !strcmp(argv[2], "rename")) {
+ ret = raw_renamevar(argv[3], argv[4]);
+ Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
} else if(argc > 3 && !strcmp(argv[2], "index")) {
/* xschem raw index v(ldcp) */
int idx;
@@ -4372,7 +4474,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
/* rebuild_connectivity
- Rebuild logical connectivity abstraction of schematic */
+ * Rebuild logical connectivity abstraction of schematic */
else if(!strcmp(argv[1], "rebuild_connectivity"))
{
int err = 0;
@@ -4411,14 +4513,19 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
}
- /* rect [x1 y1 x2 y2] [pos] [propstring] [draw]
- * if 'x1 y1 x2 y2'is given place recangle on current
- * layer (rectcolor) at indicated coordinates.
- * if 'pos' is given insert at given position in rectangle array.
- * if 'pos' set to -1 append rectangle to last element in rectangle array.
- * 'propstring' is the attribute string. Set to empty if not given.
- * if 'draw' is set to 1 (default) draw the new object, else don't
- * If no coordinates are given start a GUI operation of rectangle placement */
+ /* rect ...
+ * rect [x1 y1 x2 y2] [pos] [propstring] [draw]
+ * if 'x1 y1 x2 y2'is given place recangle on current
+ * layer (rectcolor) at indicated coordinates.
+ * if 'pos' is given insert at given position in rectangle array.
+ * if 'pos' set to -1 append rectangle to last element in rectangle array.
+ * 'propstring' is the attribute string. Set to empty if not given.
+ * if 'draw' is set to 1 (default) draw the new object, else don't
+ * rect
+ * If no coordinates are given start a GUI operation of rectangle placement
+ * rect gui
+ * if `gui` argument is given start a GUI placement of a rectangle with 1st
+ * point starting from current mouse coordinates */
else if(!strcmp(argv[1], "rect"))
{
double x1,y1,x2,y2;
@@ -4448,8 +4555,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
xctx->draw_window = save;
}
set_modify(1);
- }
- else {
+ } else if(argc > 2 && !strcmp(argv[2], "gui")) {
+ int infix_interface = tclgetboolvar("infix_interface");
+ 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 {
xctx->ui_state |= MENUSTART;
xctx->ui_state2 = MENUSTARTRECT;
}
@@ -4960,7 +5077,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int n=atoi(argv[3]);
int valid = n < xctx->wires && n >= 0;
if(valid) {
- select_wire(n, sel, fast);
+ select_wire(n, sel, fast, 1);
xctx->ui_state |= SELECTION;
}
Tcl_SetResult(interp, valid ? "1" : "0" , TCL_STATIC);
@@ -4970,7 +5087,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int n=atoi(argv[4]);
int valid = n < xctx->lines[c] && n >= 0 && c < cadlayers && c >= 0;
if(valid) {
- select_line(c, n, sel, fast);
+ select_line(c, n, sel, fast, 0);
xctx->ui_state |= SELECTION;
}
Tcl_SetResult(interp, valid ? "1" : "0" , TCL_STATIC);
@@ -4990,7 +5107,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int n=atoi(argv[4]);
int valid = n < xctx->arcs[c] && n >= 0 && c < cadlayers && c >= 0;
if(valid) {
- select_arc(c, n, sel, fast);
+ select_arc(c, n, sel, fast, 0);
xctx->ui_state |= SELECTION;
}
Tcl_SetResult(interp, valid ? "1" : "0" , TCL_STATIC);
@@ -5000,7 +5117,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int n=atoi(argv[4]);
int valid = n < xctx->polygons[c] && n >= 0 && c < cadlayers && c >= 0;
if(valid) {
- select_polygon(c, n, sel, fast);
+ select_polygon(c, n, sel, fast, 0);
xctx->ui_state |= SELECTION;
}
Tcl_SetResult(interp, valid ? "1" : "0" , TCL_STATIC);
@@ -5009,7 +5126,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int n=atoi(argv[3]);
int valid = n < xctx->texts && n >= 0;
if(valid) {
- select_text(n, sel, fast);
+ select_text(n, sel, fast, 0);
xctx->ui_state |= SELECTION;
}
Tcl_SetResult(interp, valid ? "1" : "0" , TCL_STATIC);
@@ -5461,7 +5578,8 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
} else {
char *translated_sym = NULL;
int sym_number = -1;
- char *subst = NULL;
+ char *subst = NULL, *old_name = NULL;;
+
if(!fast) {
symbol_bbox(inst, &xctx->inst[inst].x1, &xctx->inst[inst].y1, &xctx->inst[inst].x2, &xctx->inst[inst].y2);
xctx->push_undo();
@@ -5469,7 +5587,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
xctx->prep_hash_inst=0;
xctx->prep_net_structs=0;
xctx->prep_hi_structs=0;
- if(argc > 4 && !strcmp(argv[4], "name") && fast == 0) hash_names(-1, XINSERT);
+ if(argc > 4 && !strcmp(argv[4], "name")) {
+ if(fast == 0) {
+ hash_names(-1, XINSERT);
+ }
+ my_strdup2(_ALLOC_ID_, &old_name, xctx->inst[inst].instname);
+ }
if(argc > 5) {
if(!strcmp(argv[4], "allprops")) {
hash_names(-1, XINSERT);
@@ -5486,7 +5609,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
hash_names(inst, XDELETE);
new_prop_string(inst, subst, tclgetboolvar("disable_unique_names"));
-
+ if(old_name) {
+ update_attached_floaters(old_name, inst, 0);
+ }
my_strdup2(_ALLOC_ID_, &translated_sym, translate(inst, xctx->inst[inst].name));
sym_number=match_symbol(translated_sym);
@@ -5495,6 +5620,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
xctx->inst[inst].ptr=sym_number;
}
if(subst) my_free(_ALLOC_ID_, &subst);
+ if(old_name) my_free(_ALLOC_ID_, &old_name);
set_inst_flags(&xctx->inst[inst]);
hash_names(inst, XINSERT);
if(!fast) {
@@ -5927,22 +6053,22 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
select_element(n, SELECTED, 1, 1);
break;
case WIRE:
- select_wire(n, SELECTED, 1);
+ select_wire(n, SELECTED, 1, 1);
break;
case xTEXT:
- select_text(n, SELECTED, 1);
+ select_text(n, SELECTED, 1, 1);
break;
case xRECT:
- select_box(c, n, SELECTED, 1, 0);
+ select_box(c, n, SELECTED, 1, 1);
break;
case LINE:
- select_line(c, n, SELECTED, 1);
+ select_line(c, n, SELECTED, 1, 1);
break;
case POLYGON:
- select_polygon(c, n, SELECTED, 1);
+ select_polygon(c, n, SELECTED, 1, 1);
break;
case ARC:
- select_arc(c, n, SELECTED, 1);
+ select_arc(c, n, SELECTED, 1, 1);
break;
}
}
@@ -6215,6 +6341,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
+ /* unselect_attached_floaters
+ * Unselect objects (not symbol instances) attached to some instance with a
+ * non empty name=... attribute */
+ else if(!strcmp(argv[1], "unselect_attached_floaters"))
+ {
+ if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
+ unselect_attached_floaters();
+ }
/* update_all_sym_bboxes
* Update all symbol bounding boxes */
else if(!strcmp(argv[1], "update_all_sym_bboxes"))
@@ -6295,8 +6429,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
}
/* wire [x1 y1 x2 y2] [pos] [prop] [sel]
+ * wire
+ * wire gui
* Place a new wire
- * if no coordinates are given start a GUI wire placement */
+ * if no coordinates are given start a GUI wire placement
+ * if `gui` argument is given start a GUI placement of a wire with 1st point
+ * starting from current mouse coordinates */
else if(!strcmp(argv[1], "wire"))
{
double x1,y1,x2,y2;
@@ -6324,7 +6462,21 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
if(tclgetboolvar("autotrim_wires")) trim_wires();
set_modify(1);
}
- else {
+ else if(argc > 2 && !strcmp(argv[2], "gui")) {
+ int prev_state = xctx->ui_state;
+ int infix_interface = tclgetboolvar("infix_interface");
+ 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;
+ }
+ } else {
xctx->last_command = 0;
xctx->ui_state |= MENUSTART;
xctx->ui_state2 = MENUSTARTWIRE;
diff --git a/src/select.c b/src/select.c
index 620bac21..f815d0d5 100644
--- a/src/select.c
+++ b/src/select.c
@@ -735,7 +735,7 @@ void bbox(int what,double x1,double y1, double x2, double y2)
/* n = -1 : clear first selected info
* n = -2 : return first selected element if still selected, or get first from
- * selected list. Id no elements selected return first selected item (j = 0)
+ * selected list. If no elements selected return first selected item (j = 0)
* n >= 0 : store indicated element as first selected
*/
int set_first_sel(unsigned short type, int n, unsigned int col)
@@ -896,10 +896,12 @@ void unselect_all(int dr)
}
}
-void select_wire(int i,unsigned short select_mode, int fast)
+void select_wire(int i,unsigned short select_mode, int fast, int override_lock)
{
char str[1024]; /* overflow safe */
/*my_strncpy(s,xctx->wire[i].prop_ptr!=NULL?xctx->wire[i].prop_ptr:"",256); */
+ if(!strboolcmp(get_tok_value(xctx->wire[i].prop_ptr, "lock", 0), "true") &&
+ select_mode == SELECTED && !override_lock) return;
if( !fast )
{
my_snprintf(str, S(str), "Info: selected wire: n=%d end1=%d end2=%d\nnode=%s",i,
@@ -937,6 +939,68 @@ void select_wire(int i,unsigned short select_mode, int fast)
xctx->need_reb_sel_arr=1;
}
+
+static int select_attached_floaters(int inst, const char *name)
+{
+ int i, c;
+ int found = 0;
+ char *attach = NULL;
+ char *att_save, *att_ptr;
+ if(!name || !name[0]) return found;
+ my_strdup2(_ALLOC_ID_, &attach, name);
+ att_ptr = attach;
+ while( (name = my_strtok_r(att_ptr, " \n", "\"", 0, &att_save)) ) {
+ att_ptr = NULL;
+ for(c = 0; c < cadlayers; c++) {
+ for(i = 0; i < xctx->rects[c]; i++) {
+ if(!strcmp(name, get_tok_value(xctx->rect[c][i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_box(c, i, SELECTED, 1, 1);
+ }
+ }
+ for(i = 0; i < xctx->lines[c]; i++) {
+ if(!strcmp(name, get_tok_value(xctx->line[c][i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_line(c, i, SELECTED, 1, 1);
+ }
+ }
+
+ for(i = 0; i < xctx->polygons[c]; i++) {
+ if(!strcmp(name, get_tok_value(xctx->poly[c][i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_polygon(c, i, SELECTED, 1, 1);
+ }
+ }
+ for(i = 0; i < xctx->arcs[c]; i++) {
+ if(!strcmp(name, get_tok_value(xctx->arc[c][i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_arc(c, i, SELECTED, 1, 1);
+ }
+ }
+ }
+ for(i = 0; i < xctx->wires; i++) {
+ if(!strcmp(name, get_tok_value(xctx->wire[i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_wire(i, SELECTED, 1, 1);
+ }
+ }
+ for(i = 0; i < xctx->texts; i++) {
+ if(!strcmp(name, get_tok_value(xctx->text[i].prop_ptr, "name", 0))) {
+ found = 1;
+ select_text(i, SELECTED, 1, 1);
+ }
+ }
+ for(i = 0; i < xctx->instances; i++) {
+ if(i != inst && !strcmp(name, xctx->inst[i].instname)) {
+ found = 1;
+ select_element(i, SELECTED, 1, 0);
+ }
+ }
+ }
+ my_free(_ALLOC_ID_, &attach);
+ return found;
+}
+
/* fast == 1: do not update status line
* fast == 2: do not draw / undraw selected elements
* fast == 3: 1 + 2
@@ -991,16 +1055,21 @@ void select_element(int i,unsigned short select_mode, int fast, int override_loc
}
}
}
+ if(!fast && select_mode == SELECTED) {
+ select_attached_floaters(i, get_tok_value(xctx->inst[i].prop_ptr, "attach", 0));
+ }
xctx->need_reb_sel_arr=1;
}
-void select_text(int i,unsigned short select_mode, int fast)
+void select_text(int i, unsigned short select_mode, int fast, int override_lock)
{
char str[1024]; /* overflow safe */
char s[256]; /* overflow safe */
#if HAS_CAIRO==1
int customfont;
#endif
+ if(!strboolcmp(get_tok_value(xctx->text[i].prop_ptr, "lock", 0), "true") &&
+ select_mode == SELECTED && !override_lock) return;
if(!fast) {
my_strncpy(s,xctx->text[i].prop_ptr!=NULL?xctx->text[i].prop_ptr:"",S(s));
my_snprintf(str, S(str), "Info: selected text %d: properties: %s", i,s);
@@ -1075,7 +1144,7 @@ void select_box(int c, int i, unsigned short select_mode, int fast, int override
-void select_arc(int c, int i, unsigned short select_mode, int fast)
+void select_arc(int c, int i, unsigned short select_mode, int fast, int override_lock)
{
char str[1024]; /* overflow safe */
char s[256]; /* overflow safe */
@@ -1105,11 +1174,14 @@ void select_arc(int c, int i, unsigned short select_mode, int fast)
xctx->need_reb_sel_arr=1;
}
-void select_polygon(int c, int i, unsigned short select_mode, int fast )
+void select_polygon(int c, int i, unsigned short select_mode, int fast, int override_lock )
{
char str[1024]; /* overflow safe */
char s[256]; /* overflow safe */
int bezier;
+
+ if(!strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "lock", 0), "true") &&
+ select_mode == SELECTED && !override_lock) return;
if(!fast)
{
my_strncpy(s,xctx->poly[c][i].prop_ptr!=NULL?xctx->poly[c][i].prop_ptr:"",S(s));
@@ -1134,10 +1206,13 @@ void select_polygon(int c, int i, unsigned short select_mode, int fast )
xctx->need_reb_sel_arr=1;
}
-void select_line(int c, int i, unsigned short select_mode, int fast )
+void select_line(int c, int i, unsigned short select_mode, int fast, int override_lock )
{
char str[1024]; /* overflow safe */
char s[256]; /* overflow safe */
+
+ if(!strboolcmp(get_tok_value(xctx->line[c][i].prop_ptr, "lock", 0), "true") &&
+ select_mode == SELECTED && !override_lock) return;
if(!fast)
{
my_strncpy(s,xctx->line[c][i].prop_ptr!=NULL?xctx->line[c][i].prop_ptr:"",S(s));
@@ -1193,19 +1268,19 @@ Selected select_object(double mx,double my, unsigned short select_mode,
{
case WIRE:
if(xctx->wire[sel.n].sel) xctx->already_selected = 1;
- select_wire(sel.n, select_mode, 0);
+ select_wire(sel.n, select_mode, 0, override_lock);
break;
case xTEXT:
if(xctx->text[sel.n].sel) xctx->already_selected = 1;
- select_text(sel.n, select_mode, 0);
+ select_text(sel.n, select_mode, 0, override_lock);
break;
case LINE:
if(xctx->line[sel.col][sel.n].sel) xctx->already_selected = 1;
- select_line(sel.col, sel.n, select_mode,0);
+ select_line(sel.col, sel.n, select_mode,0, override_lock);
break;
case POLYGON:
if(xctx->poly[sel.col][sel.n].sel) xctx->already_selected = 1;
- select_polygon(sel.col, sel.n, select_mode,0);
+ select_polygon(sel.col, sel.n, select_mode,0, override_lock);
break;
case xRECT:
if(xctx->rect[sel.col][sel.n].sel) xctx->already_selected = 1;
@@ -1213,11 +1288,11 @@ Selected select_object(double mx,double my, unsigned short select_mode,
break;
case ARC:
if(xctx->arc[sel.col][sel.n].sel) xctx->already_selected = 1;
- select_arc(sel.col,sel.n, select_mode,0);
+ select_arc(sel.col,sel.n, select_mode,0, override_lock);
break;
case ELEMENT:
if(xctx->inst[sel.n].sel) xctx->already_selected = 1;
- select_element(sel.n,select_mode,0, override_lock);
+ select_element(sel.n, select_mode,0, override_lock);
break;
default:
break;
@@ -1260,10 +1335,10 @@ void select_attached_nets(void)
for(wptr=xctx->wire_spatial_table[sqx][sqy]; wptr; wptr=wptr->next) {
i = wptr->n;
if(xctx->wire[i].x1 == x0 && xctx->wire[i].y1 == y0) {
- select_wire(i,SELECTED1, 1);
+ select_wire(i,SELECTED1, 1, 0);
}
if(xctx->wire[i].x2 == x0 && xctx->wire[i].y2 == y0) {
- select_wire(i,SELECTED2, 1);
+ select_wire(i,SELECTED2, 1, 0);
}
}
}
@@ -1286,10 +1361,10 @@ void select_attached_nets(void)
i = wptr->n;
if(i == wire) continue;
if(xctx->wire[i].x1 == x0 && xctx->wire[i].y1 == y0) {
- select_wire(i,SELECTED1, 1);
+ select_wire(i,SELECTED1, 1, 0);
}
if(xctx->wire[i].x2 == x0 && xctx->wire[i].y2 == y0) {
- select_wire(i,SELECTED2, 1);
+ select_wire(i,SELECTED2, 1, 0);
}
}
}
@@ -1316,23 +1391,23 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
if(RECT_INSIDE(xctx->wire[i].x1,xctx->wire[i].y1,xctx->wire[i].x2,xctx->wire[i].y2, x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_wire(i, SELECTED, 1);
+ select_wire(i, SELECTED, 1, 0);
}
else if(stretch && POINTINSIDE(xctx->wire[i].x1,xctx->wire[i].y1, x1,y1,x2,y2) )
{
xctx->ui_state |= SELECTION;
- select_wire(i, SELECTED1, 1);
+ select_wire(i, SELECTED1, 1, 0);
}
else if(stretch && POINTINSIDE(xctx->wire[i].x2,xctx->wire[i].y2, x1,y1,x2,y2) )
{
xctx->ui_state |= SELECTION;
- select_wire(i, SELECTED2, 1);
+ select_wire(i, SELECTED2, 1, 0);
}
} else {
if(RECT_INSIDE(xctx->wire[i].x1,xctx->wire[i].y1,xctx->wire[i].x2,xctx->wire[i].y2, x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_wire(i, 0, 1);
+ select_wire(i, 0, 1, 0);
}
}
}
@@ -1358,7 +1433,7 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
if(RECT_INSIDE(xx1,yy1, xx2, yy2,x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- sel ? select_text(i, SELECTED, 1): select_text(i, 0, 1);
+ sel ? select_text(i, SELECTED, 1, 0): select_text(i, 0, 1, 0);
}
}
for(i=0;iinstances; ++i)
@@ -1367,9 +1442,7 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
if(sel) {
- if(strboolcmp(get_tok_value(xctx->inst[i].prop_ptr, "lock", 0), "true")) {
- select_element(i, SELECTED, 1, 1);
- }
+ select_element(i, SELECTED, 1, 0);
} else {
select_element(i, 0, 1, 0);
}
@@ -1403,14 +1476,14 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
}
if(flag) {
if(selected_points==0) {
- select_polygon(c, i, 0, 1);
+ select_polygon(c, i, 0, 1, 0);
}
if(selected_points==xctx->poly[c][i].points) {
xctx->ui_state |= SELECTION;
- select_polygon(c, i, SELECTED, 1);
+ select_polygon(c, i, SELECTED, 1, 0);
} else if(selected_points) {
/* for polygon, SELECTED1 means partial sel */
- if(sel && stretch) select_polygon(c, i, SELECTED1,1);
+ if(sel && stretch) select_polygon(c, i, SELECTED1, 1, 0);
}
}
@@ -1421,23 +1494,23 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
if(RECT_INSIDE(xctx->line[c][i].x1,xctx->line[c][i].y1,xctx->line[c][i].x2,xctx->line[c][i].y2, x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION;
- select_line(c,i,SELECTED,1);
+ select_line(c, i, SELECTED, 1, 0);
}
else if(stretch && POINTINSIDE(xctx->line[c][i].x1,xctx->line[c][i].y1, x1,y1,x2,y2) )
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_line(c, i,SELECTED1,1);
+ select_line(c, i, SELECTED1, 1, 0);
}
else if(stretch && POINTINSIDE(xctx->line[c][i].x2,xctx->line[c][i].y2, x1,y1,x2,y2) )
{
xctx->ui_state |= SELECTION;
- select_line(c, i,SELECTED2,1);
+ select_line(c, i, SELECTED2, 1, 0);
}
} else {
if(RECT_INSIDE(xctx->line[c][i].x1,xctx->line[c][i].y1,xctx->line[c][i].x2,xctx->line[c][i].y2, x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION;
- select_line(c,i,0,1);
+ select_line(c, i, 0, 1, 0);
}
}
}
@@ -1454,22 +1527,22 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
arc_bbox(x, y, r, a, b, &tmp.x1, &tmp.y1, &tmp.x2, &tmp.y2);
if(RECT_INSIDE(tmp.x1, tmp.y1, tmp.x2, tmp.y2, x1,y1,x2,y2)) {
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- sel? select_arc(c, i, SELECTED,1): select_arc(c, i, 0,1);
+ sel? select_arc(c, i, SELECTED,1, 0): select_arc(c, i, 0,1, 0);
}
else if( sel && stretch && POINTINSIDE(x, y, x1, y1, x2, y2) )
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_arc(c, i,SELECTED1,1);
+ select_arc(c, i,SELECTED1,1, 0);
}
else if( sel && stretch && POINTINSIDE(xb, yb, x1, y1, x2, y2) )
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_arc(c, i,SELECTED3,1);
+ select_arc(c, i,SELECTED3,1, 0);
}
else if( sel && stretch && POINTINSIDE(xa, ya, x1, y1, x2, y2) )
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- select_arc(c, i,SELECTED2,1);
+ select_arc(c, i,SELECTED2,1, 0);
}
}
for(i=0;irects[c]; ++i)
@@ -1480,9 +1553,7 @@ void select_inside(int stretch, double x1,double y1, double x2, double y2, int s
if(sel) {
- if(strboolcmp(get_tok_value(xctx->rect[c][i].prop_ptr, "lock", 0), "true")) {
- select_box(c,i, SELECTED, 1, 1);
- }
+ select_box(c,i, SELECTED, 1, 0);
} else {
select_box(c,i, 0, 1, 0);
}
@@ -1544,7 +1615,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
ly2 = xctx->wire[i].y2;
if(lineclip(&lx1, &ly1, &lx2, &ly2, x1,y1,x2,y2)) {
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- sel ? select_wire(i,SELECTED, 1): select_wire(i,0, 1);
+ sel ? select_wire(i,SELECTED, 1, 0): select_wire(i,0, 1, 0);
}
}
for(i=0;itexts; ++i)
@@ -1570,7 +1641,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
if(RECT_TOUCH(xx1, yy1, xx2, yy2,x1,y1,x2,y2))
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- sel ? select_text(i, SELECTED, 1): select_text(i, 0, 1);
+ sel ? select_text(i, SELECTED, 1, 0): select_text(i, 0, 1, 0);
}
}
for(i=0;iinstances; ++i)
@@ -1579,9 +1650,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
if(sel) {
- if(strboolcmp(get_tok_value(xctx->inst[i].prop_ptr, "lock", 0), "true")) {
- select_element(i, SELECTED, 1, 1);
- }
+ select_element(i, SELECTED, 1, 0);
} else {
select_element(i, 0, 1, 0);
}
@@ -1605,7 +1674,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
}
}
if(flag) {
- sel ? select_polygon(c, i, SELECTED, 1): select_polygon(c, i, 0, 1);
+ sel ? select_polygon(c, i, SELECTED, 1, 0): select_polygon(c, i, 0, 1, 0);
}
}
for(i=0;ilines[c]; ++i)
@@ -1617,7 +1686,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
ly2 = xctx->line[c][i].y2;
if(lineclip(&lx1, &ly1, &lx2, &ly2, x1,y1,x2,y2)) {
xctx->ui_state |= SELECTION;
- sel? select_line(c,i,SELECTED,1): select_line(c,i,0,1);
+ sel? select_line(c, i, SELECTED, 1, 0): select_line(c, i, 0, 1, 0);
}
}
for(i=0;iarcs[c]; ++i) {
@@ -1633,7 +1702,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
arc_bbox(x, y, r, a, b, &tmp.x1, &tmp.y1, &tmp.x2, &tmp.y2);
if(RECT_TOUCH(tmp.x1, tmp.y1, tmp.x2, tmp.y2, x1,y1,x2,y2)) {
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
- sel? select_arc(c, i, SELECTED,1): select_arc(c, i, 0,1);
+ sel? select_arc(c, i, SELECTED,1, 0): select_arc(c, i, 0,1, 0);
}
}
for(i=0;irects[c]; ++i)
@@ -1642,9 +1711,7 @@ void select_touch(double x1,double y1, double x2, double y2, int sel) /*added un
{
xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */
if(sel) {
- if(strboolcmp(get_tok_value(xctx->rect[c][i].prop_ptr, "lock", 0), "true")) {
- select_box(c,i, SELECTED, 1, 1);
- }
+ select_box(c,i, SELECTED, 1, 0);
} else {
select_box(c,i, 0, 1, 0);
}
@@ -1688,6 +1755,8 @@ int floaters_from_selected_inst()
}
my_strdup2(_ALLOC_ID_, &xctx->inst[i].prop_ptr,
subst_token(xctx->inst[i].prop_ptr, "hide_texts", "true"));
+ my_strdup2(_ALLOC_ID_, &xctx->inst[i].prop_ptr,
+ subst_token(xctx->inst[i].prop_ptr, "attach", xctx->inst[i].instname));
set_inst_flags(&xctx->inst[i]);
for(t = 0; t < sym->texts; t++) {
double txtx0, txty0;
@@ -1730,33 +1799,35 @@ void select_all(void)
for(i=0;iwires; ++i)
{
- select_wire(i,SELECTED, 1);
+ select_wire(i,SELECTED, 1, 0);
}
for(i=0;itexts; ++i)
{
- select_text(i, SELECTED, 1);
+ select_text(i, SELECTED, 1, 0);
}
for(i=0;iinstances; ++i)
{
- select_element(i,SELECTED,1, 0);
+ select_element(i, SELECTED, 1, 0);
+ /* following not done in select_element() due to fast=1 argument */
+ select_attached_floaters(i, get_tok_value(xctx->inst[i].prop_ptr, "attach", 0));
}
for(c=0;cpolygons[c]; ++i)
{
- select_polygon(c,i,SELECTED,1);
+ select_polygon(c, i, SELECTED, 1, 0);
}
for(i=0;ilines[c]; ++i)
{
- select_line(c,i,SELECTED,1);
+ select_line(c, i, SELECTED, 1, 0);
}
for(i=0;iarcs[c]; ++i)
{
- select_arc(c,i, SELECTED, 1);
+ select_arc(c, i, SELECTED, 1, 0);
}
for(i=0;irects[c]; ++i)
{
- select_box(c,i, SELECTED, 1, 0);
+ select_box(c, i, SELECTED, 1, 0);
}
} /* end for c */
drawtemparc(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0, 0.0);
diff --git a/src/spice.awk b/src/spice.awk
index 5dc7b170..07bb05e7 100755
--- a/src/spice.awk
+++ b/src/spice.awk
@@ -275,7 +275,7 @@ function process( i,j, iprefix, saveinstr, savetype, saveanalysis)
} else if( $1 ~ /^\*\.(ipin|opin|iopin)/ ) {
num=split($2,name,",")
for(i=1;i<=num;i++) print $1 " " name[i]
- } else if( $1 ~ /\.subckt/) {
+ } else if( tolower($1) ~ /\.subckt/) {
# remove m=.. from subcircuit definition since m= is a multiplier not a param
sub(/ m=[0-9]+/," ",$0)
gsub(","," ",$0)
diff --git a/src/spice_netlist.c b/src/spice_netlist.c
index 663a2a7d..359a0095 100644
--- a/src/spice_netlist.c
+++ b/src/spice_netlist.c
@@ -173,10 +173,9 @@ static int spice_netlist(FILE *fd, int spice_stop )
int err = 0;
int i, flag = 0;
const char *type;
- int top_sub;
+ int top_sub = tclgetboolvar("lvs_netlist") || tclgetboolvar("top_is_subckt");
int lvs_ignore = tclgetboolvar("lvs_ignore");
-
- top_sub = tclgetboolvar("lvs_netlist") || tclgetboolvar("top_is_subckt");
+
if(!spice_stop) {
dbg(1, "spice_netlist(): invoke prepare_netlist_structs for %s\n", xctx->current_name);
xctx->prep_net_structs = 0;
@@ -278,6 +277,7 @@ int global_spice_netlist(int global, int alert) /* netlister driver */
int found_top_symbol = 0;
int npins = 0; /* top schematic number of i/o ports */
Sch_pin_record *pinnumber_list = NULL; /* list of top sch i/o ports ordered wrt sim_pinnumber attr */
+ int uppercase_subckt = tclgetboolvar("uppercase_subckt");
exit_code = 0; /* reset exit code */
split_f = tclgetboolvar("split_files");
@@ -341,7 +341,10 @@ int global_spice_netlist(int global, int alert) /* netlister driver */
}
top_sub = tclgetboolvar("lvs_netlist") || tclgetboolvar("top_is_subckt");
if(!top_sub) fprintf(fd,"**");
- fprintf(fd,".subckt %s", get_cell(xctx->sch[xctx->currsch], 0));
+ if(uppercase_subckt)
+ fprintf(fd,".SUBCKT %s", get_cell(xctx->sch[xctx->currsch], 0));
+ else
+ fprintf(fd,".subckt %s", get_cell(xctx->sch[xctx->currsch], 0));
pinnumber_list = sort_schematic_pins(&npins); /* sort pins according to sim_pinnumber attr */
/* print top subckt ipin/opins */
@@ -405,7 +408,10 @@ int global_spice_netlist(int global, int alert) /* netlister driver */
/* /20100217 */
if(!top_sub) fprintf(fd,"**");
- fprintf(fd, ".ends\n");
+ if(uppercase_subckt)
+ fprintf(fd, ".ENDS\n");
+ else
+ fprintf(fd, ".ends\n");
if(split_f) {
@@ -572,7 +578,7 @@ int global_spice_netlist(int global, int alert) /* netlister driver */
/* 20150922 added split_files check */
- if(!split_f) fprintf(fd, ".end\n");
+ if( !top_sub && !split_f) fprintf(fd, ".end\n");
dbg(1, "global_spice_netlist(): starting awk on netlist!\n");
@@ -612,7 +618,8 @@ int spice_block_netlist(FILE *fd, int i, int alert)
char *sym_def = NULL;
char *name = NULL;
const char *default_schematic;
-
+ int uppercase_subckt = tclgetboolvar("uppercase_subckt");
+
split_f = tclgetboolvar("split_files");
if(!strboolcmp( get_tok_value(xctx->sym[i].prop_ptr,"spice_stop",0),"true") )
@@ -657,7 +664,10 @@ int spice_block_netlist(FILE *fd, int i, int alert)
} else {
const char *s = get_cell(sanitize(name), 0);
fprintf(fd, "** sch_path: %s\n", sanitized_abs_sym_path(filename, ""));
- fprintf(fd, ".subckt %s ", s);
+ if(uppercase_subckt)
+ fprintf(fd, ".SUBCKT %s ", s);
+ else
+ fprintf(fd, ".subckt %s ", s);
print_spice_subckt_nodes(fd, i);
my_strdup(_ALLOC_ID_, &extra, get_tok_value(xctx->sym[i].prop_ptr,"extra",0) );
@@ -680,7 +690,10 @@ int spice_block_netlist(FILE *fd, int i, int alert)
fprintf(fd, "%s\n", xctx->schprop);
fprintf(fd,"**** end user architecture code\n");
}
- fprintf(fd, ".ends\n\n");
+ if(uppercase_subckt)
+ fprintf(fd, ".ENDS\n\n");
+ else
+ fprintf(fd, ".ends\n\n");
}
if(split_f) {
int save;
diff --git a/src/svgdraw.c b/src/svgdraw.c
index 601de7da..e277e7c9 100644
--- a/src/svgdraw.c
+++ b/src/svgdraw.c
@@ -1035,7 +1035,7 @@ void svg_draw(void)
{
if(xctx->rect[c][i].flags & 1) { /* graph */
xRect *r = &xctx->rect[c][i];
- svg_embedded_graph(fd, r, r->x1, r->y1, r->x2, r->y2);
+ svg_embedded_graph(fd, i, r->x1, r->y1, r->x2, r->y2);
}
}
}
diff --git a/src/token.c b/src/token.c
index ee6a1a55..74a8bf9b 100644
--- a/src/token.c
+++ b/src/token.c
@@ -184,6 +184,7 @@ int match_symbol(const char *name) /* never returns -1, if symbol not found loa
int i,found;
found=0;
+ dbg(1, "match_symbol(): name=%s\n", name);
for(i=0;isymbols; ++i) {
/* dbg(1, "match_symbol(): name=%s, sym[i].name=%s\n",name, xctx->sym[i].name);*/
if(xctx->x_strcmp(name, xctx->sym[i].name) == 0)
@@ -1198,8 +1199,8 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200
}
}
my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */
- if(strstr(result, "expr(") ) {
- result = eval_expr(result);
+ if(strstr(result, "expr(")) {
+ my_strdup2(_ALLOC_ID_, &result, eval_expr(result));
}
dbg(1, "print_vhdl_primitive(): after translate3() result=%s\n", result);
}
@@ -2152,7 +2153,8 @@ int print_spice_element(FILE *fd, int inst)
const char *str_ptr=NULL;
register int c, state=TOK_BEGIN, space;
char *template=NULL,*format=NULL, *s, *name=NULL, *token=NULL;
- const char *lab, *value = NULL;
+ const char *lab;
+ const char *value = NULL;
/* char *translatedvalue = NULL; */
size_t sizetok=0;
size_t token_pos=0;
@@ -2462,8 +2464,8 @@ int print_spice_element(FILE *fd, int inst)
value = spiceprefixtag;
}
- if(strstr(value, "expr(") ) {
- value = eval_expr(value);
+ if(strstr(value, "expr(")) {
+ value = eval_expr(value);
}
/* token=%xxxx and xxxx is not defined in prop_ptr or template: return xxxx */
if(!token_exists && token[0] =='%') {
@@ -2517,8 +2519,8 @@ int print_spice_element(FILE *fd, int inst)
if(result) {
my_strdup(_ALLOC_ID_, &result, tcl_hook2(result));
}
- if(strstr(result, "expr(") ) {
- result = eval_expr(result);
+ if(strstr(result, "expr(")) {
+ my_strdup2(_ALLOC_ID_, &result, eval_expr(result));
}
if(result) fprintf(fd, "%s", result);
dbg(1, "print_spice_element(): returning |%s|\n", result);
@@ -3154,8 +3156,8 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level
}
}
my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */
- if(strstr(result, "expr(") ) {
- result = eval_expr(result);
+ if(strstr(result, "expr(")) {
+ my_strdup2(_ALLOC_ID_, &result, eval_expr(result));
}
dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result);
}
@@ -3779,6 +3781,99 @@ const char *spice_get_node(const char *token)
}
+
+
+/* caller must free returned value
+ * get the full pathname of "instname" device
+ * modelparam:
+ * 0: current, 1: modelparam, 2: modelvoltage
+ * param: device parameter, like "ib", "gm", "vth"
+ * set param to {} (empty str) for just branch current of 2 terminal device
+ * for parameters like "vth" modelparam must be 2
+ * for parameters like "ib" modelparam must be 0
+ * for parameters like "gm" modelparam must be 1
+ */
+char *get_fqdevice(const char *param, int modelparam, const char *instname)
+{
+ int start_level; /* hierarchy level where waves were loaded */
+ char *fqdev = NULL;
+ const char *path = xctx->sch_path[xctx->currsch] + 1;
+ char *dev = NULL;
+ size_t len;
+ int idx;
+ int sim_is_xyce = tcleval("sim_is_xyce")[0] == '1' ? 1 : 0;
+ int skip = 0;
+ char *iprefix = modelparam == 0 ? "i(" : modelparam == 1 ? "" : "v(";
+ char *ipostfix = modelparam == 1 ? "" : ")";
+ int prefix;
+
+ start_level = sch_waves_loaded();
+ /* skip path components that are above the level where raw file was loaded */
+ while(*path && skip < start_level) {
+ if(*path == '.') skip++;
+ ++path;
+ }
+ my_strdup2(_ALLOC_ID_, &dev, instname);
+ strtolower(dev);
+ prefix=dev[0];
+ len = strlen(path) + strlen(dev) + 40; /* some extra chars for i(..) wrapper */
+ fqdev = my_malloc(_ALLOC_ID_, len);
+ if(!sim_is_xyce) {
+ int vsource = (prefix == 'v') || (prefix == 'e');
+ if(path[0]) {
+ if(vsource) {
+ my_snprintf(fqdev, len, "i(%c.%s%s)", prefix, path, dev);
+ } else if(prefix=='q') {
+ my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s",
+ iprefix, prefix, path, dev, param ? param : "ic", ipostfix);
+ } else if(prefix=='d' || prefix == 'm') {
+ my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s",
+ iprefix, prefix, path, dev, param ? param : "id", ipostfix);
+ } else if(prefix=='i') {
+ my_snprintf(fqdev, len, "i(@%c.%s%s[current])", prefix, path, dev);
+ } else {
+ my_snprintf(fqdev, len, "i(@%c.%s%s[i])", prefix, path, dev);
+ }
+ } else {
+ if(vsource) {
+ my_snprintf(fqdev, len, "i(%s)", dev);
+ } else if(prefix == 'q') {
+ my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "ic", ipostfix);
+ } else if(prefix == 'd' || prefix == 'm') {
+ my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "id", ipostfix);
+ } else if(prefix == 'i') {
+ my_snprintf(fqdev, len, "i(@%s[current])", dev);
+ } else {
+ my_snprintf(fqdev, len, "i(@%s[i])", dev);
+ }
+ }
+ } else {
+ my_snprintf(fqdev, len, "i(%s%s)", path, dev);
+ }
+ dbg(1, "fqdev=%s\n", fqdev);
+ strtolower(fqdev);
+ idx = get_raw_index(fqdev, NULL);
+ /* special handling for resistors that are converted to b sources:
+ * i(@r.x4.r1[i]) --> i(@b.x4.br1[i])
+ */
+ if(idx < 0 && !strncmp(fqdev, "i(@r", 4)) {
+ if(path[0]) {
+ my_snprintf(fqdev, len, "i(@b.%sb%s[i])", path, dev);
+ } else {
+ my_snprintf(fqdev, len, "i(@b%s[i])", dev);
+ }
+ dbg(1, "fqdev=%s\n", fqdev);
+ }
+
+
+ my_free(_ALLOC_ID_, &dev);
+ return fqdev;
+
+}
+
+
+
+
/* substitute given tokens in a string with their corresponding values */
/* ex.: name=@name w=@w l=@l ---> name=m112 w=3e-6 l=0.8e-6 */
/* if s==NULL return emty string */
diff --git a/src/xinit.c b/src/xinit.c
index 288b4e8c..ff9e9835 100644
--- a/src/xinit.c
+++ b/src/xinit.c
@@ -1179,7 +1179,7 @@ static int source_tcl_file(char *s)
fprintf(errfp, "Tcl_AppInit() error: can not execute %s, please fix:\n", s);
fprintf(errfp, "%s", tclresult());
#if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6
- fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp));
+ fprintf(errfp, "\nLine No: %d\n", Tcl_GetErrorLine(interp));
#endif
fprintf(errfp, "\n");
#if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6
@@ -1666,6 +1666,7 @@ static void create_new_window(int *window_count, const char *noconfirm, const ch
tclvareval("set_bindings ", window_path[n], NULL);
tclvareval("set_replace_key_binding ", window_path[n], NULL);
tclvareval("save_ctx ", window_path[n], NULL);
+ tcleval("eval_user_startup_commands");
/* restore previous context,
* because the Expose event after new window creation does a context switch prev win -> new win
*
@@ -2060,6 +2061,7 @@ void change_linewidth(double w)
double cs = tclgetdoublevar("cadsnap");
if(tclgetboolvar("change_lw")) {
xctx->lw=xctx->mooz * 0.09 * cs;
+ if(xctx->lw > 100.) xctx->lw = 100.;
xctx->cadhalfdotsize = CADHALFDOTSIZE * (cs < 20. ? cs : 20.) / 10.;
}
/* explicitly set line width */
@@ -2891,6 +2893,7 @@ int Tcl_AppInit(Tcl_Interp *inter)
if(has_x) {
tclsetintvar("tctx::max_new_windows", MAX_NEW_WINDOWS);
tcleval("pack_widgets; set_bindings .drw");
+ tcleval("eval_user_startup_commands");
}
fs=tclgetintvar("fullscreen");
diff --git a/src/xschem.h b/src/xschem.h
index 27700e9f..4d85fe43 100644
--- a/src/xschem.h
+++ b/src/xschem.h
@@ -163,8 +163,8 @@ extern char win_temp_dir[PATH_MAX];
#define CADINITIALY -870
#define CADZOOMSTEP 1.2
#define CADMOVESTEP 200
-#define CADMAXZOOM 1000000.0
-#define CADMINZOOM 0.000001
+#define CADMAXZOOM 10000.0
+#define CADMINZOOM 0.005
#define CADHALFDOTSIZE 3.7
#define CADNULLNODE -1 /* no valid node number */
#define CADWIREMINDIST 8.0
@@ -375,7 +375,7 @@ extern char win_temp_dir[PATH_MAX];
* show_label also used on metal option type symbols (pass-through symbols)
* to optionally short two nets (using *_ignore=[true|false] attribute) */
#define IS_LABEL_SH_OR_PIN(type) (!(strcmp(type,"label") && strcmp(type,"ipin") && strcmp(type,"opin") && \
- strcmp(type,"show_label") && strcmp(type,"iopin") && strcmp(type,"bus_tap")))
+ strcmp(type,"scope") && strcmp(type,"show_label") && strcmp(type,"iopin") && strcmp(type,"bus_tap")))
#define IS_LABEL_OR_PIN(type) (!(strcmp(type,"label") && strcmp(type,"ipin") && \
strcmp(type,"opin") && strcmp(type,"iopin")))
#define IS_PIN(type) (!(strcmp(type,"ipin") && strcmp(type,"opin") && strcmp(type,"iopin")))
@@ -954,7 +954,7 @@ typedef struct {
int lastsel;
int maxsel;
Selected *sel_array;
- Selected first_sel; /* first selected instance (used as master when editing multile pbjects) */
+ Selected first_sel; /* first selected instance (used as master when editing multiple objects) */
int prep_net_structs;
int prep_hi_structs;
int prep_hash_inst;
@@ -1259,6 +1259,7 @@ extern int embed_rawfile(const char *rawfile);
extern int read_rawfile_from_attr(const char *b64s, size_t length, const char *type);
extern int raw_read_from_attr(Raw **rawptr, const char *type, double sweep1, double sweep2);
extern int raw_add_vector(const char *varname, const char *expr, int sweep_idx);
+extern int raw_renamevar(const char *old_name, const char *new_name);
extern int raw_deletevar(const char *name);
extern int new_rawfile(const char *name, const char *type, const char *sweepvar,
double start, double end, double step);
@@ -1329,7 +1330,7 @@ extern int process_options(int argc, char **argv);
extern void calc_drawing_bbox(xRect *boundbox, int selected);
extern int ps_draw(int what, int fullzoom, int eps);
extern void svg_draw(void);
-extern void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, double ry2);
+extern void svg_embedded_graph(FILE *fd, int i, double rx1, double ry1, double rx2, double ry2);
extern void set_viewport_size(int w, int h, double lw);
extern void print_image();
extern const char *get_trailing_path(const char *str, int no_of_dir, int skip_ext);
@@ -1400,9 +1401,11 @@ extern void tclmainloop(void);
extern int Tcl_AppInit(Tcl_Interp *interp);
extern void abort_operation(void);
extern void draw_crosshair(int what, int state);
-extern void draw_snap_cursor(int what);
+extern void start_line(double mx, double my);
+extern void start_wire(double mx, double my);
extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr);
/* extern void snapped_wire(double c_snap); */
+extern void unselect_attached_floaters(void);
extern int callback(const char *win_path, 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);
@@ -1425,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 */
@@ -1547,6 +1551,8 @@ extern void new_line(int what, double mx_snap, double my_snap);
extern void new_arc(int what, double sweep, double mousex_snap, double mousey_snap);
extern void arc_3_points(double x1, double y1, double x2, double y2, double x3, double y3,
double *x, double *y, double *r, double *a, double *b);
+/* sel: if set to 1 change references only on selected items, like in a copy operation */
+extern void update_attached_floaters(const char *from_name, int inst, int sel);
extern void move_objects(int what,int merge, double dx, double dy);
extern void check_collapsing_objects();
extern void redraw_w_a_l_r_p_z_rubbers(int force); /* redraw wire, arcs, line, polygon rubbers */
@@ -1611,6 +1617,7 @@ extern char *trim_chars(const char *str, const char *sep);
extern char *find_nth(const char *str, const char *sep, const char *quote, int keep_quote, int n);
extern int isonlydigit(const char *s);
extern const char *spice_get_node(const char *token);
+extern char *get_fqdevice(const char *param, int modelparam, const char *instname);
extern const char *translate(int inst, const char* s);
extern const char* translate2(Lcc *lcc, int level, char* s);
extern const char *translate3(const char* s, int eat_escapes, const char *s1,
@@ -1688,13 +1695,13 @@ extern const char *expandlabel(const char *s, int *m);
extern void parse(const char *s);
extern void clear_expandlabel_data(void);
extern void merge_file(int selection_load, const char ext[]);
-extern void select_wire(int i, unsigned short select_mode, int fast);
+extern void select_wire(int i, unsigned short select_mode, int fast, int override_lock);
extern void select_element(int i, unsigned short select_mode, int fast, int override_lock);
-extern void select_text(int i, unsigned short select_mode, int fast);
+extern void select_text(int i, unsigned short select_mode, int fast, int override_lock);
extern void select_box(int c, int i, unsigned short select_mode, int fast, int override_lock);
-extern void select_arc(int c, int i, unsigned short select_mode, int fast);
-extern void select_line(int c, int i, unsigned short select_mode, int fast);
-extern void select_polygon(int c, int i, unsigned short select_mode, int fast );
+extern void select_arc(int c, int i, unsigned short select_mode, int fast, int override_lock);
+extern void select_line(int c, int i, unsigned short select_mode, int fast, int override_lock);
+extern void select_polygon(int c, int i, unsigned short select_mode, int fast, int override_lock );
extern const char *net_name(int i, int j, int *mult, int hash_prefix_unnamed_net, int erc);
extern int record_global_node(int what, FILE *fp, const char *node);
extern int count_items(const char *s, const char *sep, const char *quote);
diff --git a/src/xschem.tcl b/src/xschem.tcl
index 8311eaab..122a0d75 100644
--- a/src/xschem.tcl
+++ b/src/xschem.tcl
@@ -628,6 +628,10 @@ proc from_eng {i} {
## convert number to engineering form
proc to_eng {args} {
set suffix {}
+
+ if {[ catch {uplevel #0 expr [join $args]} i]} {
+ return [join $args]
+ }
set i [uplevel #0 expr [join $args]]
set absi [expr {abs($i)}]
@@ -1836,6 +1840,7 @@ proc simconf_add {tool} {
############ cellview
# proc cellview prints symbol bindings (default binding or "schematic" attr in symbol)
# of all symbols used in current and sub schematics.
+# the derived_symbols parameter of cellview should be either empty or 'derived_symbols'
proc cellview_setlabels {w symbol derived_symbol} {
global dark_gui_colorscheme netlist_type
if {$dark_gui_colorscheme} {
@@ -1937,6 +1942,8 @@ proc cellview_edit_sym {w} {
xschem load_new_window $sym
}
+# derived_symbols: empty or 'derived_symbols'
+# upd: never set by caller (used iinternally to update)
proc cellview { {derived_symbols {}} {upd 0}} {
global keep_symbols nolist_libs dark_gui_colorscheme netlist_type
@@ -2095,10 +2102,9 @@ proc traversal_setlabels {w parent_sch instname inst_sch sym_sch default_sch
set save_netlist_type [xschem get netlist_type]
# puts "traversal_setlabels: $w parent: |$parent_sch| inst: $instname def: $sym_sch $inst_sch --> [$w get]"
# update schematic
- if {$parent_sch ne {}} {
+ if {$parent_sch ne {} && $sym_spice_sym_def eq {} && $inst_spice_sym_def eq {} } {
set current [xschem get current_name]
if { $inst_sch ne [$w get] } {
- puts "update attr"
xschem load -undoreset -nodraw $parent_sch
if { [$w get] eq $sym_sch} {
xschem setprop -fast instance $instname schematic ;# remove schematic attr on instance
@@ -2224,6 +2230,7 @@ proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} {
set instances [xschem get instances]
set current_level [xschem get currsch]
for {set i 0} { $i < $instances} { incr i} {
+ # puts "hier_traversal: i=$i, current_level=$current_level, parent_sch=$parent_sch"
set instname [xschem getprop instance $i name]
set symbol [xschem getprop instance $i cell::name]
set default_sch [add_ext $symbol .sch]
@@ -2301,8 +2308,10 @@ proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} {
if {$descended} {
incr level
set dp [hier_traversal $level $only_subckts 1]
- xschem go_back 1
+ xschem go_back 2
incr level -1
+ } else { ;# descended into a blank schematic. Go back.
+ xschem go_back 2
}
}
}
@@ -3973,6 +3982,7 @@ proc open_sub_schematic {{inst {}} {inst_number 0}} {
proc is_xschem_file {f} {
+ # puts "is_xschem_file $f"
regsub {\(.*} $f {} f ;# remove trailing generator args (gen.tcl(....)) if any
if { ![file exists $f] } { return 0
} elseif { [file isdirectory $f] } { return 0 }
@@ -3987,6 +3997,13 @@ proc is_xschem_file {f} {
} else {
fconfigure $fd -translation binary
while { [gets $fd line] >=0 } {
+
+ #### Can not use this. schematics may containg 8 bit extended characters
+ # if {[regexp {[^[:print:][:space:]]} $line]} { ;# line contains non ascii chars
+ # close $fd
+ # return 0
+ # }
+
# this is a script. not an xschem file
if { $nline == 0 && [regexp {^#!} $line] } {
#### too dangerous executing an arbitrary script...
@@ -4365,8 +4382,10 @@ proc file_dialog_display_preview {f} {
proc file_dialog_right_listboxselect {dirselect} {
global file_dialog_yview file_dialog_dir1 file_dialog_dir2 file_dialog_retval file_dialog_sel
global OS file_dialog_loadfile file_dialog_index1 file_dialog_files1 file_dialog_globfilter
+ global file_dialog_others
set file_dialog_yview [.load.l.paneright.f.list yview]
- set file_dialog_sel [.load.l.paneright.f.list curselection]
+ set file_dialog_sel [lindex [.load.l.paneright.f.list curselection] 0]
+
if { $file_dialog_sel ne {} } {
set curr_dir [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]]
set curr_item [.load.l.paneright.f.list get $file_dialog_sel]
@@ -4399,6 +4418,17 @@ proc file_dialog_right_listboxselect {dirselect} {
set file_dialog_dir1 $curr_dir
set file_dialog_dir2 $curr_item
+
+ set file_dialog_others {}
+ if {$file_dialog_loadfile == 1} {
+ foreach i [lrange [.load.l.paneright.f.list curselection] 1 end] {
+ set file_dialog_retval [.load.l.paneright.f.list get $i]
+ lappend file_dialog_others [file_dialog_getresult 1 0]
+ }
+ }
+ set file_dialog_retval {} ;# we used this variable above to communicate with file_dialog_getresult
+
+
if { [file isdirectory $file_dialog_d]} {
bind .load.l.paneright.draw {}
bind .load.l.paneright.draw {}
@@ -4421,6 +4451,16 @@ proc file_dialog_right_listboxselect {dirselect} {
}
}
+proc load_additional_files {} {
+ global file_dialog_others
+
+ if {$file_dialog_others ne {} } {
+ foreach i $file_dialog_others {
+ xschem load_new_window $i
+ }
+ }
+}
+
# global_initdir: name of global variable containing the initial directory
# loadfile: set to 0 if calling for saving instead of loading a file
# set to 2 for non blocking operation (symbol insertion)
@@ -4458,7 +4498,8 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
set_ne file_dialog_files2 {}
panedwindow .load.l -orient horizontal -height 8c
if { $loadfile == 2} {frame .load.l.recent -takefocus 0}
- frame .load.l.paneleft -takefocus 0 -highlightcolor red -highlightthickness 2 -bg {grey90}
+ frame .load.l.paneleft -takefocus 0 -highlightcolor red -highlightthickness 2 -bg {grey90} \
+ -highlightbackground [option get . background {}]
eval [subst {listbox .load.l.paneleft.list -listvariable file_dialog_names1 -width 40 -height 12 \
-fg black -background {grey90} -highlightthickness 0 -relief flat -borderwidth 0 \
-yscrollcommand ".load.l.paneleft.yscroll set" -selectmode browse \
@@ -4469,9 +4510,6 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
file_dialog_set_colors1
scrollbar .load.l.paneleft.yscroll -command ".load.l.paneleft.list yview" -takefocus 0
scrollbar .load.l.paneleft.xscroll -command ".load.l.paneleft.list xview" -orient horiz -takefocus 0
- pack .load.l.paneleft.yscroll -side right -fill y
- pack .load.l.paneleft.xscroll -side bottom -fill x
- pack .load.l.paneleft.list -fill both -expand true -padx 12
bind .load.l.paneleft.list <> {
set file_dialog_sel [.load.l.paneleft.list curselection]
if { $file_dialog_sel ne {} } {
@@ -4486,14 +4524,12 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
}
}
-
panedwindow .load.l.paneright -orient vertical
frame .load.l.paneright.f -takefocus 0
frame .load.l.paneright.draw -background white -height 3.8c -takefocus 0
.load.l.paneright add .load.l.paneright.f
.load.l.paneright add .load.l.paneright.draw -minsize 150
-
if { ![catch {.load.l.paneright panecget .load.l.paneright.f -stretch}]} {
set optnever {-stretch never}
set optalways {-stretch always}
@@ -4506,17 +4542,19 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
eval .load.l.paneright paneconfigure .load.l.paneright.f $optnever
eval .load.l.paneright paneconfigure .load.l.paneright.draw $optalways
-
+ if {$global_initdir eq {INITIALINSTDIR}} {
+ set selmode browse
+ } else {
+ set selmode extended
+ }
listbox .load.l.paneright.f.list -background {grey90} -listvariable file_dialog_files2 -width 20 -height 12\
-fg black -highlightcolor red -highlightthickness 2 \
- -yscrollcommand ".load.l.paneright.f.yscroll set" -selectmode browse \
+ -highlightbackground [option get . background {}] \
+ -yscrollcommand ".load.l.paneright.f.yscroll set" -selectmode $selmode \
-xscrollcommand ".load.l.paneright.f.xscroll set" -exportselection 0
scrollbar .load.l.paneright.f.yscroll -command ".load.l.paneright.f.list yview" -takefocus 0
scrollbar .load.l.paneright.f.xscroll -command ".load.l.paneright.f.list xview" -orient horiz -takefocus 0
- pack .load.l.paneright.f.yscroll -side right -fill y
- pack .load.l.paneright.f.xscroll -side bottom -fill x
- pack .load.l.paneright.f.list -side bottom -fill both -expand true
if { $loadfile == 2} {
.load.l add .load.l.recent
@@ -4560,10 +4598,12 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
.load.l.paneleft.list selection set $file_dialog_index1
}
label .load.buttons_bot.label -text { File:}
- entry .load.buttons_bot.entry -highlightcolor red -highlightthickness 2
+ entry .load.buttons_bot.entry -highlightcolor red -highlightthickness 2 \
+ -highlightbackground [option get . background {}] -takefocus 0
entry_replace_selection .load.buttons_bot.entry
label .load.buttons_bot.srclab -text { Search:}
- entry .load.buttons_bot.src -width 18 -highlightcolor red -highlightthickness 2
+ entry .load.buttons_bot.src -width 18 -highlightcolor red -highlightthickness 2 \
+ -highlightbackground [option get . background {}]
entry_replace_selection .load.buttons_bot.src
.load.buttons_bot.src delete 0 end
.load.buttons_bot.src insert 0 $file_dialog_globfilter
@@ -4591,28 +4631,6 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
set file_dialog_retval { }
}
- # radiobutton .load.buttons_bot.all -text All -variable file_dialog_globfilter -value {*} -takefocus 0 \
- # -command {
- # set file_dialog_ext $file_dialog_globfilter
- # setglob $file_dialog_dir1
- # .load.buttons_bot.src delete 0 end
- # .load.buttons_bot.src insert 0 $file_dialog_globfilter
- # }
- # radiobutton .load.buttons_bot.sym -text .sym -variable file_dialog_globfilter -value {*.sym} -takefocus 0 \
- # -command {
- # set file_dialog_ext $file_dialog_globfilter
- # setglob $file_dialog_dir1
- # .load.buttons_bot.src delete 0 end
- # .load.buttons_bot.src insert 0 $file_dialog_globfilter
- # }
- # radiobutton .load.buttons_bot.sch -text .sch -variable file_dialog_globfilter -value {*.sch} -takefocus 0 \
- # -command {
- # set file_dialog_ext $file_dialog_globfilter
- # setglob $file_dialog_dir1
- # .load.buttons_bot.src delete 0 end
- # .load.buttons_bot.src insert 0 $file_dialog_globfilter
- # }
-
button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up $file_dialog_dir1} -takefocus 0
label .load.buttons.mkdirlab -text { New dir: }
entry .load.buttons.newdir -width 16 -takefocus 0
@@ -4635,19 +4653,28 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
file_dialog_set_colors1
.load.l.paneleft.list xview moveto 1
}
+
+ pack .load.l -expand true -fill both
+ pack .load.l.paneleft.yscroll -side right -fill y
+ pack .load.l.paneleft.xscroll -side bottom -fill x
+ pack .load.l.paneleft.list -fill both -expand true -padx 12
+
pack .load.buttons.home .load.buttons.up .load.buttons.pwd .load.buttons.path -side left
pack .load.buttons.mkdirlab -side left
pack .load.buttons.newdir -expand true -fill x -side left
pack .load.buttons.rmdir .load.buttons.mkdir -side right
- # pack .load.buttons_bot.all .load.buttons_bot.sym .load.buttons_bot.sch -side left
pack .load.buttons_bot.srclab -side left
pack .load.buttons_bot.src -side left
pack .load.buttons_bot.label -side left
pack .load.buttons_bot.entry -side left -fill x -expand true
+
+ pack .load.l.paneright.f.yscroll -side right -fill y
+ pack .load.l.paneright.f.xscroll -side bottom -fill x
+ pack .load.l.paneright.f.list -side bottom -fill both -expand true
+
pack .load.buttons_bot.cancel .load.buttons_bot.ok -side left
pack .load.buttons_bot -side bottom -fill x
pack .load.buttons -side bottom -fill x
- pack .load.l -expand true -fill both
if { [info exists file_dialog_default_geometry]} {
wm geometry .load "${file_dialog_default_geometry}"
}
@@ -4681,7 +4708,8 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
destroy .load
set $global_initdir \"\$file_dialog_dir1\"
"
-
+ bind .load {.load.buttons.home invoke }
+ bind .load {.load.buttons.up invoke }
### update
if { [info exists file_dialog_v_sp0] } {
@@ -4770,6 +4798,253 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
return [file_dialog_getresult $loadfile $confirm_overwrt]
}
+
+
+#######################################################################
+##### new alternate insert_symbol browser
+#######################################################################
+
+#### Display preview of selected symbol
+proc insert_symbol_focusin {{paths {}} {maxdepth -1}} {
+ global insert_symbol new_symbol_browser_ext
+ xschem abort_operation
+ set insert_symbol(ext) $new_symbol_browser_ext
+ insert_symbol_filelist $paths $maxdepth
+}
+
+proc insert_symbol_preview {{paths {}}} {
+ # puts insert_symbol_preview
+ global insert_symbol
+ xschem preview_window close .ins.center.right {}
+ .ins.center.right configure -bg white
+ bind .ins.center.right {}
+ bind .ins.center.right {}
+ set sel [.ins.center.left.l curselection]
+ if {$sel eq {}} {
+ set sel [.ins.center.left.l index active]
+ .ins.center.left.l selection set active
+ }
+ if {$sel ne {}} {
+ set f [lindex $insert_symbol(fullpathlist) $sel 0]
+ if {$f ne {}} {
+ set type [is_xschem_file $f]
+ if {$type ne {0}} {
+ set dir [rel_sym_path $f $paths]
+ .ins.top.dir_e configure -state normal
+ .ins.top.dir_e delete 0 end
+ .ins.top.dir_e insert 0 $dir
+ .ins.top.dir_e configure -state readonly
+
+
+ .ins.top2.dir_e configure -state normal
+ .ins.top2.dir_e delete 0 end
+ .ins.top2.dir_e insert 0 $f
+ .ins.top2.dir_e configure -state readonly
+ .ins.center.right configure -bg {}
+ xschem preview_window create .ins.center.right {}
+ xschem preview_window draw .ins.center.right [list $f]
+ bind .ins.center.right "xschem preview_window draw .ins.center.right [list $f]"
+ bind .ins.center.right "xschem preview_window draw .ins.center.right [list $f]"
+ }
+ insert_symbol_place
+ }
+ }
+}
+
+proc get_list_of_dirs_with_symbols {{paths {}} {levels -1} {level -1}} {
+ global pathlist
+ if {$level == -1} { set level 0}
+ if {$paths eq {}} {set paths $pathlist}
+
+ foreach i $paths {
+ set filelist [glob -nocomplain -directory $i -type f *]
+ set there_are_symbols 0
+ foreach f $filelist {
+ if {[regexp {\.(sch|sym|tcl)$} $f]} {
+ # if {[is_xschem_file $f] ne {0}} { }
+ set there_are_symbols 1
+ break
+ }
+ }
+ if {$there_are_symbols} {
+ puts $i
+ }
+
+ set dirlist [glob -nocomplain -directory $i -type d *]
+ if {$levels >=0 && $level + 1 > $levels} {return}
+ foreach d $dirlist {
+ get_list_of_dirs_with_symbols $d $levels [expr {$level + 1} ]
+ }
+ }
+}
+
+#### fill list of files matching pattern
+proc insert_symbol_filelist {paths {maxdepth -1}} {
+ # puts "insert_symbol_filelist: paths=$paths"
+ global insert_symbol
+ set insert_symbol(regex) [.ins.top.pat_e get]
+
+ #check if regex is valid
+ set err [catch {regexp $insert_symbol(regex) {12345}} res]
+ if {$err} {return}
+
+ set f [match_file $insert_symbol(regex) $paths $maxdepth]
+ set filelist {}
+ set insert_symbol(fullpathlist) {}
+ set sel [.ins.center.left.l curselection]
+ if {$sel eq {}} { set sel 0}
+ .ins.center.left.l activate $sel
+ foreach i $f {
+
+ set err [catch {regexp $insert_symbol(ext) $i} type]
+ if {!$err && $type} {
+ set fname [rel_sym_path $i $paths]
+ lappend filelist $fname
+ lappend insert_symbol(fullpathlist) $i
+ }
+ }
+ # sort lists using filelist as key
+ set files {}
+ foreach f $filelist ff $insert_symbol(fullpathlist) {
+ lappend files [list $f $ff]
+ }
+ set files [lsort -dictionary -index 0 $files]
+ set filelist {}
+ set insert_symbol(fullpathlist) {}
+
+ foreach f $files {
+ lassign $f ff fff
+ lappend filelist $ff
+ lappend insert_symbol(fullpathlist) $fff
+ }
+
+ # assign listbox variable all at the end, it is faster...
+ set insert_symbol(list) $filelist
+ set insert_symbol(nitems) [llength $filelist]
+ # .ins.center.left.l selection clear 0 end
+ # .ins.center.left.l selection set 0
+}
+
+proc insert_symbol_place {} {
+ # puts insert_symbol_place
+ global insert_symbol
+ set sel [.ins.center.left.l curselection]
+ if {$sel eq {}} {
+ set sel [.ins.center.left.l index active]
+ .ins.center.left.l selection set active
+ }
+ if {$sel ne {}} {
+ set f [lindex $insert_symbol(fullpathlist) $sel 0]
+ if {$f ne {}} {
+ set type [is_xschem_file $f]
+ if {$type ne {0}} {
+ xschem abort_operation
+ xschem place_symbol $f
+ }
+ }
+ }
+}
+
+#### paths: list of paths to use for listing symbols
+#### maxdepth: how many levels to descend for each $paths directory (-1: no limit)
+proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}}} {
+ global insert_symbol
+ set paths [cleanup_paths $paths] ;# remove ~ and other strange path combinations
+ # xschem set semaphore [expr {[xschem get semaphore] +1}]
+ set insert_symbol(ext) $ext
+ if {[winfo exists .ins]} {
+ raise .ins
+ return
+ }
+ toplevel .ins
+ frame .ins.top -takefocus 0
+ frame .ins.top2 -takefocus 0
+ panedwindow .ins.center -orient horizontal -height 8c
+ frame .ins.center.leftdir -takefocus 0
+ frame .ins.center.left -takefocus 0
+ frame .ins.center.right -width 250 -height 250 -bg white -takefocus 0
+ .ins.center add .ins.center.leftdir
+ .ins.center add .ins.center.left
+ .ins.center add .ins.center.right
+ frame .ins.bottom -takefocus 0
+ pack .ins.top -side top -fill x
+ pack .ins.top2 -side top -fill x
+ pack .ins.center -side top -expand 1 -fill both
+ pack .ins.bottom -side top -fill x
+
+ listbox .ins.center.leftdir.l -listvariable insert_symbol(dirs) -width 20 -height 20 \
+ -yscrollcommand ".ins.center.leftdir.s set" -highlightcolor red -highlightthickness 2 \
+ -activestyle underline -highlightbackground [option get . background {}] \
+ -exportselection 0
+
+ listbox .ins.center.left.l -listvariable insert_symbol(list) -width 40 -height 20 \
+ -yscrollcommand ".ins.center.left.s set" -highlightcolor red -highlightthickness 2 \
+ -activestyle underline -highlightbackground [option get . background {}] \
+ -exportselection 0
+
+ scrollbar .ins.center.leftdir.s -command ".ins.center.leftdir.l yview" -takefocus 0
+ scrollbar .ins.center.left.s -command ".ins.center.left.l yview" -takefocus 0
+
+ pack .ins.center.left.l -expand 1 -fill both -side left
+ pack .ins.center.left.s -fill y -side left
+
+ pack .ins.center.leftdir.l -expand 1 -fill both -side left
+ pack .ins.center.leftdir.s -fill y -side left
+
+ label .ins.top2.dir_l -text {Full path:}
+ entry .ins.top2.dir_e -width 60 -state readonly \
+ -readonlybackground [option get . background {}] -takefocus 0
+ label .ins.top.pat_l -text Pattern:
+ entry .ins.top.pat_e -width 20 -highlightcolor red -highlightthickness 2 \
+ -highlightbackground [option get . background {}]
+ label .ins.top.dir_l -text { Symbol ref: }
+ entry .ins.top.dir_e -width 40 -state readonly \
+ -readonlybackground [option get . background {}] -takefocus 0
+ label .ins.top.ext_l -text Ext:
+ entry .ins.top.ext_e -width 15 -takefocus 0 -state normal -textvariable new_symbol_browser_ext
+ if {[info exists insert_symbol(regex)]} {
+ .ins.top.pat_e insert 0 $insert_symbol(regex)
+ }
+
+ bind .ins {.ins.bottom.dismiss invoke}
+ bind .ins "
+ if {{%K} eq {Tab} && {%W} eq {.ins.center.left.l}} {
+ insert_symbol_filelist [list $paths] [list $maxdepth]
+ insert_symbol_preview [list $paths]
+ }
+ "
+ bind .ins.center.left.l <> "insert_symbol_preview [list $paths]"
+ bind .ins.center.left.l "insert_symbol_focusin [list $paths] [list $maxdepth]"
+ label .ins.bottom.n -text { N. of items:}
+ label .ins.bottom.nitems -textvariable insert_symbol(nitems)
+ button .ins.bottom.dismiss -takefocus 0 -text Dismiss -command {
+ if { [xschem get ui_state] & 8192 } {
+ xschem abort_operation
+ } else {
+ xschem preview_window close .ins.center.right {}
+ destroy .ins
+ }
+ }
+ pack .ins.bottom.dismiss -side left
+ pack .ins.bottom.n -side left
+ pack .ins.bottom.nitems -side left
+ pack .ins.top2.dir_l -side left
+ pack .ins.top2.dir_e -side left -fill x -expand 1
+ pack .ins.top.pat_l -side left
+ pack .ins.top.pat_e -side left
+ pack .ins.top.dir_l -side left
+ pack .ins.top.dir_e -side left
+ pack .ins.top.ext_l -side left
+ pack .ins.top.ext_e -side left
+ insert_symbol_filelist $paths $maxdepth
+ # tkwait window .ins
+ # xschem set semaphore [expr {[xschem get semaphore] -1}]
+ return {}
+}
+#######################################################################
+##### /new alternate insert_symbol browser
+#######################################################################
+
# get last n path components: example , n=1 --> /aaa/bbb/ccc/ddd.sch -> ccc/ddd.sch
proc get_cell {s n } {
set slist [file split $s]
@@ -6447,12 +6722,17 @@ proc editdata {{data {}} {title {Edit data}} } {
# wm transient $window [xschem get topwindow]
frame $window.buttons
pack $window.buttons -side bottom -fill x -pady 2m
+ button $window.buttons.copy -text Copy -command "
+ clipboard clear
+ clipboard append \[$window.text get 1.0 {end - 1 chars}\]
+ "
button $window.buttons.ok -text OK -command "
set retval \[$window.text get 1.0 {end - 1 chars}\]; destroy $window
"
button $window.buttons.cancel -text Cancel -command "destroy $window"
pack $window.buttons.ok -side left -expand 1
pack $window.buttons.cancel -side left -expand 1
+ pack $window.buttons.copy -side left -expand 1
eval text $window.text -undo 1 -relief sunken -bd 2 -yscrollcommand \"$window.yscroll set\" -setgrid 1 \
-xscrollcommand \"$window.xscroll set\" -wrap none -height 30 $text_tabs_setting
@@ -6567,27 +6847,39 @@ proc viewdata {data {ro {}} {win .view}} {
return $tctx::rcode
}
-proc sub_match_file { f {paths {}} } {
- global pathlist match_file_dir_arr
+proc sub_match_file { f {paths {}} {maxdepth -1} } {
+ global pathlist match_file_dir_arr match_file_level nolist_libs
set res {}
if {$paths eq {}} {set paths $pathlist}
foreach i $paths {
foreach j [glob -nocomplain -directory $i *] {
- # puts "--> $j $f"
- # set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
+ set skip 0
+ foreach k $nolist_libs {
+ if {[regexp $k $j]} {
+ set skip 1
+ break
+ }
+ }
+ if {$skip} { continue }
+
if {[file isdirectory $j] && [file readable $j]} {
- set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
- if {[array names match_file_dir_arr -exact $jj] == {}} {
- set match_file_dir_arr($jj) 1
- # puts "********** directory $jj"
- set sub_res [sub_match_file $f $j] ;# recursive call
- if {$sub_res != {} } {set res [concat $res $sub_res]}
+ if { $maxdepth == -1 || $match_file_level < $maxdepth} {
+ set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
+ # if {[array names match_file_dir_arr -exact $jj] == {}} { ... }
+ if {![info exists match_file_dir_arr($jj)]} {
+ set match_file_dir_arr($jj) 1
+ incr match_file_level
+ set sub_res [sub_match_file $f $j $maxdepth] ;# recursive call
+ incr match_file_level -1
+ if {$sub_res != {} } {set res [concat $res $sub_res]}
+ }
}
} else {
- # set fname [file tail $j]
- set fname $j
- if {[regexp $f $fname]} {
- lappend res $j
+ if {![info exists match_file_dir_arr($j)]} {
+ set match_file_dir_arr($j) 1
+ if {[regexp $f $j]} {
+ lappend res $j
+ }
}
}
}
@@ -6598,37 +6890,56 @@ proc sub_match_file { f {paths {}} } {
# find files into $paths directories matching $f
# use $pathlist global search path if $paths empty
# recursively descend directories
-proc match_file { f {paths {}} } {
- global match_file_dir_arr
+proc match_file { f {paths {}} {maxdepth -1} } {
+ global match_file_dir_arr match_file_level
+ set err [catch {regexp $f {12345}} res]
+ if {$err} {return {}}
+ set match_file_level 0
catch {unset match_file_dir_arr}
- set res [sub_match_file $f $paths]
+ set res [sub_match_file $f $paths $maxdepth]
catch {unset match_file_dir_arr}
return $res
}
-proc sub_find_file { f {paths {}} {first 0} } {
- global pathlist match_file_dir_arr
+proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} {
+ global pathlist match_file_dir_arr match_file_level nolist_libs
set res {}
if {$paths eq {}} {set paths $pathlist}
foreach i $paths {
foreach j [glob -nocomplain -directory $i *] {
- # puts "--> $j $f"
+
+ set skip 0
+ foreach k $nolist_libs {
+ if {[regexp $k $j]} {
+ set skip 1
+ break
+ }
+ }
+ if {$skip} { continue }
+
if {[file isdirectory $j] && [file readable $j]} {
- set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
- if {[array names match_file_dir_arr -exact $jj] == {}} {
- set match_file_dir_arr($jj) 1
- # puts "********** directory $jj"
- set sub_res [sub_find_file $f $j $first] ;# recursive call
- if {$sub_res != {} } {
- set res [concat $res $sub_res]
- if {$first} {return $res}
+ if { $maxdepth == -1 || $match_file_level < $maxdepth} {
+ set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
+ # if {[array names match_file_dir_arr -exact $jj] == {}} { ... }
+ if {![info exists match_file_dir_arr($jj)]} {
+ set match_file_dir_arr($jj) 1
+ incr match_file_level
+ set sub_res [sub_find_file $f $j $first $maxdepth] ;# recursive call
+ incr match_file_level -1
+ if {$sub_res != {} } {
+ set res [concat $res $sub_res]
+ if {$first} {return $res}
+ }
}
}
} else {
set fname [file tail $j]
- if {$fname == $f} {
- lappend res $j
- if {$first} {return $res}
+ if {![info exists match_file_dir_arr($j)]} {
+ set match_file_dir_arr($j) 1
+ if {$fname == $f} {
+ lappend res $j
+ if {$first} {return $res}
+ }
}
}
}
@@ -6639,10 +6950,11 @@ proc sub_find_file { f {paths {}} {first 0} } {
# find given file $f into $paths directories
# use $pathlist global search path if $paths empty
# recursively descend directories
-proc find_file { f {paths {}} } {
- global match_file_dir_arr
+proc find_file { f {paths {}} {maxdepth -1}} {
+ global match_file_dir_arr match_file_level
+ set match_file_level 0
catch {unset match_file_dir_arr}
- set res [sub_find_file $f $paths 0]
+ set res [sub_find_file $f $paths 0 $maxdepth]
catch {unset match_file_dir_arr}
return $res
}
@@ -6651,10 +6963,11 @@ proc find_file { f {paths {}} } {
# use $pathlist global search path if $paths empty
# recursively descend directories
# only return FIRST FOUND
-proc find_file_first { f {paths {}} } {
- global match_file_dir_arr
+proc find_file_first { f {paths {}} {maxdepth -1}} {
+ global match_file_dir_arr match_file_level
+ set match_file_level 0
catch {unset match_file_dir_arr}
- set res [sub_find_file $f $paths 1]
+ set res [sub_find_file $f $paths 1 $maxdepth]
catch {unset match_file_dir_arr}
return $res
}
@@ -6740,16 +7053,24 @@ proc try_download_url {dirname sch_or_sym} {
# if file is in a library directory (a $pathlist dir)
# Example: rel_sym_path /home/schippes/share/xschem/xschem_library/devices/iopin.sym
# devices/iopin.sym
-proc rel_sym_path {symbol} {
+proc rel_sym_path {symbol {paths {}} } {
global OS pathlist env
+ # puts "rel_sym_path: $symbol $paths"
+ if { $paths eq {}} {set paths $pathlist}
regsub {^~/} $symbol ${env(HOME)}/ symbol
- if {![regexp {^/} $symbol]} {
- set symbol [pwd]/$symbol
- }
+ # if {$OS eq "Windows"} {
+ # if {![regexp {^[A-Za-z]\:/} $symbol]} {
+ # set symbol [pwd]/$symbol
+ # }
+ # } else {
+ # if {![regexp {^/} $symbol]} {
+ # set symbol [pwd]/$symbol
+ # }
+ # }
set curr_dirname [pwd]
set name {}
- foreach path_elem $pathlist {
+ foreach path_elem $paths {
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
set path_elem $curr_dirname
}
@@ -6783,9 +7104,10 @@ proc rel_sym_path {symbol} {
# given a symbol reference 'sym' return its absolute path
# Example: % abs_sym_path devices/iopin.sch
# /home/schippes/share/xschem/xschem_library/devices/iopin.sym
-proc abs_sym_path {fname {ext {} } } {
+proc abs_sym_path {fname {ext {} } {paths {}}} {
global pathlist OS
+ if { $paths eq {}} {set paths $pathlist}
set curr_dirname [pwd]
## empty: do nothing
if {$fname eq {} } return {}
@@ -6845,9 +7167,9 @@ proc abs_sym_path {fname {ext {} } } {
## if file does not exists but directory does return anyway
if { [file exists [file dirname "$tmpfname"]] } { return "$tmpfname" }
}
- ## if fname is present in one of the pathlist paths get the absolute path
+ ## if fname is present in one of the paths paths get the absolute path
set name {}
- foreach path_elem $pathlist {
+ foreach path_elem $paths {
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
set path_elem $curr_dirname
}
@@ -7848,42 +8170,36 @@ proc no_open_dialogs {} {
## "file_dialog_*" only one load_file_dialog window is allowed
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 orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers
- 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
- 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
- enter_text_default_geometry filetmp fix_broken_tiled_fill flat_netlist fullscreen
- gaw_fd gaw_tcp_address graph_autoload graph_bus
- graph_change_done graph_digital graph_dialog_default_geometry
- graph_legend graph_linewidth_mult graph_logx
- graph_logy graph_private_cursor graph_rainbow graph_schname graph_sel_color graph_sel_wave
- graph_selected graph_sort graph_unlocked graph_use_ctrl_key
- hide_empty_graphs hide_symbols tctx::hsize
- incr_hilight incremental_select infix_interface infowindow_text intuitive_interface
- keep_symbols launcher_default_program
- light_colors line_width live_cursor2_backannotate local_netlist_dir lvs_ignore
- lvs_netlist measure_text netlist_dir netlist_show netlist_type no_ask_save
- no_change_attrs nolist_libs noprint_libs old_selected_tok only_probes path pathlist
- persistent_command preserve_unchanged_attrs prev_symbol ps_colors ps_paper_size rainbow_colors
- tctx::rcode recentfile
- retval retval_orig rotated_text search_case search_exact search_found search_schematic
- search_select search_value select_touch selected_tok show_hidden_texts show_infowindow
- show_infowindow_after_netlist
- simconf_default_geometry simconf_vpos simulate_bg spiceprefix split_files svg_colors
- svg_font_name sym_txt symbol symbol_width tabstop tclcmd_txt tclstop text_line_default_geometry
- text_replace_selection text_tabs_setting textwindow_fileid textwindow_filename textwindow_w
- toolbar_horiz toolbar_list
- toolbar_visible top_is_subckt transparent_svg undo_type use_lab_wire unselect_partial_sel_wires
- use_label_prefix use_tclreadline
- user_wants_copy_cell verilog_2001 verilog_bitblast viewdata_fileid viewdata_filename viewdata_w
- tctx::vsize xschem_libs xschem_listen_port zoom_full_center orthogonal_wiring snap_cursor
- snap_cursor_size cadence_compat use_cursor_for_selection
+ INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR PDK PDK_ROOT SKYWATER_MODELS
+ SKYWATER_STDCELLS 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 cadence_compat cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale
+ change_lw color_ps compare_sch constr_mv copy_cell crosshair_layer crosshair_size cursor_2_hook
+ 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 edit_symbol_prop_new_sel editprop_sympath
+ en_hilight_conn_inst enable_dim_bg enable_stretch enter_text_default_geometry filetmp
+ fix_broken_tiled_fill flat_netlist fullscreen gaw_fd gaw_tcp_address graph_autoload graph_bus
+ graph_change_done graph_dialog_default_geometry graph_digital graph_legend graph_linewidth_mult
+ graph_logx graph_logy graph_private_cursor graph_rainbow graph_schname graph_sel_color
+ graph_sel_wave graph_selected graph_sort graph_unlocked graph_use_ctrl_key hide_empty_graphs
+ hide_symbols incr_hilight incremental_select infix_interface infowindow_text intuitive_interface
+ keep_symbols launcher_default_program light_colors line_width live_cursor2_backannotate
+ local_netlist_dir lvs_ignore lvs_netlist measure_text netlist_dir netlist_show netlist_type
+ new_symbol_browser new_symbol_browser_depth new_symbol_browser_ext new_symbol_browser_paths
+ no_ask_save no_change_attrs nolist_libs noprint_libs old_selected_tok only_probes
+ orthogonal_wiring path pathlist persistent_command preserve_unchanged_attrs prev_symbol ps_colors
+ ps_paper_size rainbow_colors recentfile retval retval_orig rotated_text search_case search_exact
+ search_found search_schematic search_select search_value select_touch selected_tok
+ show_hidden_texts show_infowindow show_infowindow_after_netlist simconf_default_geometry
+ simconf_vpos simulate_bg snap_cursor snap_cursor_size spiceprefix split_files svg_colors
+ svg_font_name sym_txt symbol symbol_width tabstop tclcmd_txt tclstop tctx::colors tctx::hsize
+ tctx::rcode tctx::vsize text_line_default_geometry text_replace_selection text_tabs_setting
+ textwindow_fileid textwindow_filename textwindow_w toolbar_horiz toolbar_list toolbar_visible
+ top_is_subckt transparent_svg undo_type unselect_partial_sel_wires uppercase_subckt
+ use_cursor_for_selection use_lab_wire use_label_prefix use_tclreadline user_wants_copy_cell
+ verilog_2001 verilog_bitblast
+ viewdata_fileid viewdata_filename viewdata_w xschem_libs xschem_listen_port zoom_full_center
}
## list of global arrays to save/restore on context switching
@@ -8268,7 +8584,7 @@ proc load_raw {{type {}}} {
proc build_widgets { {topwin {} } } {
global XSCHEM_SHAREDIR tabbed_interface simulate_bg OS sim
- global dark_gui_colorscheme draw_crosshair
+ global dark_gui_colorscheme draw_crosshair grid_point_size
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 cadence_compat
@@ -8332,7 +8648,11 @@ proc build_widgets { {topwin {} } } {
}
$topwin.menubar.file add command -label "Component browser" -accelerator {Shift-Ins, Ctrl-I} \
-command {
- load_file_dialog {Insert symbol} *.sym INITIALINSTDIR 2
+ if {$new_symbol_browser} {
+ insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext
+ } else {
+ load_file_dialog {Insert symbol} *.sym INITIALINSTDIR 2
+ }
}
$topwin.menubar.file add command -label "Open" -command "xschem load" -accelerator {Ctrl+O}
$topwin.menubar.file add command -label "Open Most Recent" \
@@ -8421,6 +8741,19 @@ proc build_widgets { {topwin {} } } {
$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
+ $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" \
+ -command {
+ input_line "Enter crosshair size (int, 0 = full screen width):" \
+ "set crosshair_size" $crosshair_size
+ }
$topwin.menubar.option add command -label "Replace \[ and \] for buses in SPICE netlist" \
-command {
input_line "Enter two characters to replace default bus \[\] delimiters:" "set bus_replacement_char"
@@ -8601,6 +8934,10 @@ proc build_widgets { {topwin {} } } {
set change_lw 0
input_line "Enter linewidth (float):" "xschem line_width"
}
+ $topwin.menubar.view add command -label "Set grid point size" \
+ -command {
+ input_line "Enter Grid point size (int or -1: $grid_point_size)" "set grid_point_size" $grid_point_size
+ }
$topwin.menubar.view add checkbutton -label "Tabbed interface" -variable tabbed_interface \
-selectcolor $selectcolor -command setup_tabbed_interface
@@ -8675,6 +9012,8 @@ proc build_widgets { {topwin {} } } {
-command "xschem net_label 0" -accelerator Alt-Shift-L
$topwin.menubar.sym add command -label "Change selected inst. texts to floaters" \
-command "xschem floaters_from_selected_inst"
+ $topwin.menubar.sym add command -label "Unselect attached floaters" \
+ -command "xschem unselect_attached_floaters"
$topwin.menubar.sym add command -label "Print list of highlight nets" \
-command "xschem print_hilight_net 1" -accelerator J
$topwin.menubar.sym add command -label "Print list of highlight nets, with buses expanded" \
@@ -8834,7 +9173,7 @@ proc build_widgets { {topwin {} } } {
-selectcolor $selectcolor -variable auto_hilight_graph_nodes
$topwin.menubar.simulation.graph add command -label {Add waveform graph} -command {xschem add_graph}
$topwin.menubar.simulation.graph add command -label {Add waveform reload launcher} -command {
- xschem place_symbol [rel_sym_path [find_file_first launcher.sym]] "name=h5\ndescr=\"load waves\"
+ xschem place_symbol [find_file_first launcher.sym] "name=h5\ndescr=\"load waves\"
tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get current_name]]].raw tran\"
"
}
@@ -8864,7 +9203,8 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get
xschem set format {}
}
}
-
+ $topwin.menubar.simulation.lvs add checkbutton -label "Upper case .SUBCKT and .ENDS" \
+ -selectcolor $selectcolor -variable uppercase_subckt
$topwin.menubar.simulation.lvs add checkbutton -label "Top level is a .subckt" \
-selectcolor $selectcolor -variable top_is_subckt
@@ -8947,12 +9287,27 @@ proc trace_set_paths {varname idxname op} {
uplevel #0 set_paths
}
}
+proc cleanup_paths {paths} {
+ global env
+ set pathlist {}
+ foreach i $paths {
+ regsub {^~$} $i ${env(HOME)} i
+ regsub {^~/} $i ${env(HOME)}/ i
+ if { ![string compare $i .] } {
+ lappend pathlist $i
+ } elseif { [ regexp {\.\.\/} $i] } {
+ lappend pathlist [file normalize $i]
+ } elseif { [ file exists $i] } {
+ lappend pathlist $i
+ }
+ }
+ return $pathlist
+}
# when XSCHEM_LIBRARY_PATH is changed call this function to refresh and cache
# new library search path.
proc set_paths {} {
- global XSCHEM_LIBRARY_PATH env pathlist OS add_all_windows_drives file_dialog_names1
- set pathlist {}
+ global XSCHEM_LIBRARY_PATH pathlist OS add_all_windows_drives
# puts stderr "caching search paths"
if { [info exists XSCHEM_LIBRARY_PATH] } {
if {$OS == "Windows"} {
@@ -8966,17 +9321,8 @@ proc set_paths {} {
} else {
set pathlist_orig [split $XSCHEM_LIBRARY_PATH :]
}
- foreach i $pathlist_orig {
- regsub {^~$} $i ${env(HOME)} i
- regsub {^~/} $i ${env(HOME)}/ i
- if { ![string compare $i .] } {
- lappend pathlist $i
- } elseif { [ regexp {\.\.\/} $i] } {
- lappend pathlist [file normalize $i]
- } elseif { [ file exists $i] } {
- lappend pathlist $i
- }
- }
+
+ set pathlist [cleanup_paths $pathlist_orig]
}
if {$pathlist eq {}} { set pathlist [pwd] }
set_initial_dirs
@@ -9067,6 +9413,15 @@ proc source_user_tcl_files {} {
}
}
+proc eval_user_startup_commands {} {
+ global user_startup_commands
+ if {[info exists user_startup_commands]} {
+ if {[catch {uplevel #0 $user_startup_commands} res]} {
+ puts "executing $user_startup_commands:\n\n$res"
+ }
+ }
+}
+
proc eval_postinit_commands {} {
global postinit_commands
if {[info exists postinit_commands]} {
@@ -9296,6 +9651,7 @@ set_ne local_netlist_dir 0 ;# if set use /simulation for netlist and si
set_ne bus_replacement_char {} ;# use {<>} to replace [] with <> in bussed signals
set_ne lvs_netlist 0
set_ne top_is_subckt 0
+set_ne uppercase_subckt 0
set_ne lvs_ignore 0
set_ne hide_empty_graphs 0 ;# if set to 1 waveform boxes will be hidden if no raw file loaded
set_ne graph_use_ctrl_key 0;# if set forces to use Control key to operate on graphs
@@ -9331,6 +9687,7 @@ set_ne enable_stretch 0
set_ne constr_mv 0
set_ne unselect_partial_sel_wires 0
set_ne load_file_dialog_fullpath 1
+set_ne file_dialog_others {} ;# contains 2nd, 3rd, ... selected filenames on mult. selections in load file
# if set show selected elements while dragging the selection rectangle.
# once selected these can not be unselected by retracting the selection rectangle
@@ -9340,6 +9697,7 @@ set_ne select_touch 1
set_ne draw_grid 1
set_ne big_grid_points 0
+set_ne grid_point_size -1 ;# grid point size (>=0) or unspecified (-1)
set_ne draw_grid_axes 1
set_ne persistent_command 0
set_ne intuitive_interface 1
@@ -9399,6 +9757,12 @@ set_ne tabbed_interface 1
## case insensitive symbol lookup (on case insensitive filesystems only!)
set_ne case_insensitive 0
+## New alternate symbol placement browser (default: not enabled).
+set_ne new_symbol_browser 0
+set_ne new_symbol_browser_paths {} ;# if empty use xschem search paths
+set_ne new_symbol_browser_depth 2 ;# depth to descend into each dir of the search paths
+set_ne new_symbol_browser_ext {\.(sym|tcl)$} ;# file extensions (a regex) to look for
+
set_ne file_dialog_ext {*}
## remember edit_prop widget size
diff --git a/src/xschemrc b/src/xschemrc
index 1ccaffd0..ffdf2b1b 100644
--- a/src/xschemrc
+++ b/src/xschemrc
@@ -295,6 +295,9 @@
#### enable to scale grid point size as done with lines at close zoom, default: 0
# set big_grid_points 0
+#### explicitly set grid point size in pixels. Default: -1 (not set)
+# set grid_point_size 2
+
#### enable drawing grid axes. Default: enabled (1)
# set draw_grid_axes 1
@@ -543,6 +546,17 @@
# }
# }
+###########################################################################
+#### TCL COMMANDS TO BE EXECUTED AFTER ANY NEW WINDOW CREATION
+###########################################################################
+#### this hook is useful to execute user UI code (like event binding,
+#### new buttons / menu entries etc).
+# set user_startup_commands {
+# bind [xschem get current_win_path] {
+# puts Hello
+# }
+# }
+
###########################################################################
#### TCL COMMANDS TO BE EXECUTED AFTER GENERATING NETLIST
###########################################################################
@@ -569,6 +583,19 @@
#### or tab is open.
# set tabbed_interface 0
+###########################################################################
+#### ALTERNATE SYMBOL PLACEMENT BROWSER
+###########################################################################
+#### uses a new symbol placement widget. Default: not enabled (0)
+# set new_symbol_browser 1
+#### defines a list of paths to search for. If empty uses all xschem
+#### XSCHEM_LIBRARY_PATH paths
+# set new_symbol_browser_paths [list ... ... ... ]
+#### defines the depth to descend into each path. default: 2
+# set new_symbol_browser_depth 3
+#### defines the extensions to search for. Default: {\.(sym|tcl)$}
+# set new_symbol_browser_ext {\.(sch|sym|tcl)$}
+
###########################################################################
#### CASE INSENSITIVE SYMBOL LOOKUP
###########################################################################
diff --git a/xschem_library/devices/scope.sym b/xschem_library/devices/scope.sym
new file mode 100644
index 00000000..7e36383f
--- /dev/null
+++ b/xschem_library/devices/scope.sym
@@ -0,0 +1,33 @@
+v {xschem version=3.4.6 file_version=1.2
+*
+* 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
+}
+G {}
+K {type=scope
+template="name=l1"
+highlight=true}
+V {}
+S {}
+E {}
+L 4 0 0 10 -20 {}
+B 5 -1.25 -1.25 1.25 1.25 {name=p dir=in}
+P 4 5 10 -20 10 -140 140 -140 140 -20 10 -20 {}
+T {@#0:net_name} 12.5 -18.125 0 0 0.2 0.2 {layer=4}
+T {@#0:spice_get_voltage} 12.5 -139.375 0 0 0.15 0.15 {layer=15}
diff --git a/xschem_library/devices/scope2.sym b/xschem_library/devices/scope2.sym
new file mode 100644
index 00000000..ec7ec36f
--- /dev/null
+++ b/xschem_library/devices/scope2.sym
@@ -0,0 +1,36 @@
+v {xschem version=3.4.6 file_version=1.2
+*
+* 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
+}
+G {}
+K {type=scope
+template="name=l1"
+highlight=true}
+V {}
+S {}
+E {}
+L 4 0 0 10 -20 {}
+L 4 0 -160 10 -140 {}
+B 5 -1.25 -161.25 1.25 -158.75 {name=p dir=in}
+B 5 -1.25 -1.25 1.25 1.25 {name=m dir=in}
+P 4 5 10 -20 10 -140 140 -140 140 -20 10 -20 {}
+T {@#1:net_name} 12.5 -18.125 0 0 0.2 0.2 {layer=4}
+T {@#0:net_name} 12.5 -153.125 0 0 0.2 0.2 {layer=4}
+T {@spice_get_diff_voltage} 12.5 -139.375 0 0 0.15 0.15 {layer=15}
diff --git a/xschem_library/devices/scope_ammeter.sym b/xschem_library/devices/scope_ammeter.sym
new file mode 100644
index 00000000..804b5366
--- /dev/null
+++ b/xschem_library/devices/scope_ammeter.sym
@@ -0,0 +1,31 @@
+v {xschem version=3.4.6 file_version=1.2
+*
+* 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
+}
+G {}
+K {type=scope
+template="name=l1"
+highlight=true}
+V {}
+S {}
+E {}
+P 4 5 10 -20 10 -140 140 -140 140 -20 10 -20 {}
+T {@device} 12.5 -18.125 0 0 0.2 0.2 {layer=4}
+T {tcleval(@spice_get_node [xschem get_fqdevice @device ] )} 12.5 -139.375 0 0 0.15 0.15 {layer=17}
diff --git a/xschem_library/ngspice/comp_ngspice.sch b/xschem_library/ngspice/comp_ngspice.sch
index 36809ee7..c0c08778 100644
--- a/xschem_library/ngspice/comp_ngspice.sch
+++ b/xschem_library/ngspice/comp_ngspice.sch
@@ -1,4 +1,4 @@
-v {xschem version=3.4.6RC file_version=1.2
+v {xschem version=3.4.6 file_version=1.2
*
* This file is part of XSCHEM,
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
@@ -24,6 +24,15 @@ K {}
V {}
S {}
E {}
+B 2 520 -415 630 -315 {name=l4
+flags=graph,unlocked
+lock=1
+color=8
+node="tcleval([xschem get_fqdevice [xschem translate l4 @device]])"
+y1=-0.00014
+y2=0.00013
+x1=0.00044464632
+x2=0.00046163671}
T {( @#0:resolved_net )} 440 -265 0 1 0.2 0.2 {name=l2 layer=15}
T {( @#0:resolved_net )} 100 -285 0 1 0.2 0.2 {name=p1 layer=15}
T {( @#0:resolved_net )} 100 -235 0 1 0.2 0.2 {name=p2 layer=15}
@@ -49,3 +58,6 @@ m=1}
C {parax_cap.sym} 630 -230 0 0 {name=C3 gnd=0 value=\{COUT\} m=1}
C {vsource.sym} 150 -260 1 0 {name=V1 value=0}
C {vsource.sym} 150 -210 1 0 {name=V2 value=0}
+C {scope_ammeter.sym} 500 -290 0 0 {name=l4
+attach=l4
+device=R1}
diff --git a/xschem_library/ngspice/solar_panel.sch b/xschem_library/ngspice/solar_panel.sch
index 8addbfa0..6a383ee2 100644
--- a/xschem_library/ngspice/solar_panel.sch
+++ b/xschem_library/ngspice/solar_panel.sch
@@ -26,34 +26,34 @@ K {}
V {}
S {}
E {}
-L 2 105 -1005 105 -775 {}
-L 2 145 -1005 145 -775 {}
-L 2 185 -1005 185 -775 {}
-L 2 225 -1005 225 -775 {}
-L 2 265 -1005 265 -775 {}
-L 2 305 -1005 305 -775 {}
-L 2 345 -1005 345 -775 {}
-L 2 385 -1005 385 -775 {}
-L 2 65 -975 395 -975 {}
-L 2 65 -935 395 -935 {}
-L 2 65 -895 395 -895 {}
-L 2 65 -855 395 -855 {}
-L 2 65 -815 395 -815 {}
-L 4 65 -1015 65 -755 {}
-L 4 55 -775 405 -775 {}
-L 4 105 -775 105 -765 {}
-L 4 145 -775 145 -765 {}
-L 4 185 -775 185 -765 {}
-L 4 225 -775 225 -765 {}
-L 4 265 -775 265 -765 {}
-L 4 305 -775 305 -765 {}
-L 4 345 -775 345 -765 {}
-L 4 385 -775 385 -765 {}
-L 4 55 -815 65 -815 {}
-L 4 55 -855 65 -855 {}
-L 4 55 -895 65 -895 {}
-L 4 55 -935 65 -935 {}
-L 4 55 -975 65 -975 {}
+L 2 95 -1105 95 -875 {}
+L 2 135 -1105 135 -875 {}
+L 2 175 -1105 175 -875 {}
+L 2 215 -1105 215 -875 {}
+L 2 255 -1105 255 -875 {}
+L 2 295 -1105 295 -875 {}
+L 2 335 -1105 335 -875 {}
+L 2 375 -1105 375 -875 {}
+L 2 55 -1075 385 -1075 {}
+L 2 55 -1035 385 -1035 {}
+L 2 55 -995 385 -995 {}
+L 2 55 -955 385 -955 {}
+L 2 55 -915 385 -915 {}
+L 4 55 -1115 55 -855 {}
+L 4 45 -875 395 -875 {}
+L 4 95 -875 95 -865 {}
+L 4 135 -875 135 -865 {}
+L 4 175 -875 175 -865 {}
+L 4 215 -875 215 -865 {}
+L 4 255 -875 255 -865 {}
+L 4 295 -875 295 -865 {}
+L 4 335 -875 335 -865 {}
+L 4 375 -875 375 -865 {}
+L 4 45 -915 55 -915 {}
+L 4 45 -955 55 -955 {}
+L 4 45 -995 55 -995 {}
+L 4 45 -1035 55 -1035 {}
+L 4 45 -1075 55 -1075 {}
L 4 610 -1100 630 -1140 {}
L 4 630 -1140 650 -1100 {}
L 4 650 -1100 670 -1140 {}
@@ -83,13 +83,13 @@ L 4 960 -340 970 -340 {}
L 4 960 -340 970 -330 {}
L 4 970 -330 980 -340 {}
L 4 970 -340 980 -340 {}
-B 2 1260 -560 1680 -390 {flags=graph
+B 2 1370 -555 1790 -385 {flags=graph
y1 = -0.00068
y2 = 22
divy = 6
subdivy=1
-x1=2.9358714e-05
-x2=0.0010293582
+x1=5e-10
+x2=0.001
divx=8
node="PANEL
LED" unitx=m
@@ -104,13 +104,13 @@ autoload=0
sim_type=tran
xrawfile=$netlist_dir/solar_panel.raw}
-B 2 1260 -390 1680 -220 {flags=graph
+B 2 1370 -385 1790 -215 {flags=graph
y1 = -0.0012
y2 = 6.8
divy = 4
subdivy=1
-x1=2.9358714e-05
-x2=0.0010293582
+x1=5e-10
+x2=0.001
divx=8
unitx=m
color="7 4 6"
@@ -123,13 +123,13 @@ autoload=0
sim_type=tran
xrawfile=$netlist_dir/solar_panel.raw}
-B 2 1260 -750 1680 -560 {flags=graph
+B 2 1370 -745 1790 -555 {flags=graph
y1 = -2.7e-05
y2 = 100
divy = 5
subdivy=1
-x1=2.9358714e-05
-x2=0.0010293582
+x1=5e-10
+x2=0.001
divx=9
unitx=m subdivx=4
@@ -146,13 +146,13 @@ autoload=0
sim_type=tran
xrawfile=$netlist_dir/solar_panel.raw}
-B 2 1260 -940 1680 -750 {flags=graph
+B 2 1370 -935 1790 -745 {flags=graph
y1 = 0
y2 = 1
divy = 5
subdivy=1
-x1=2.9358714e-05
-x2=0.0010293582
+x1=5e-10
+x2=0.001
divx=9
unitx=u subdivx=4
@@ -169,13 +169,13 @@ autoload=0
sim_type=tran
xrawfile=$netlist_dir/solar_panel.raw}
-B 2 1260 -1140 1680 -950 {flags=graph
+B 2 1370 -1135 1790 -945 {flags=graph
y1 = 0
y2 = 1
divy = 5
subdivy=1
-x1=2.9358714e-05
-x2=0.0010293582
+x1=5e-10
+x2=0.001
divx=9
unitx=u subdivx=4
@@ -193,29 +193,65 @@ autoload=0
sim_type=tran
xrawfile=$netlist_dir/solar_panel.raw}
-B 18 65 -960 320 -775 {}
-A 5 320 -960 5.590169943749475 243.434948822922 360 {fill=true}
-P 7 6 395 -775 340 -931.25 335 -945 322.5 -960 310 -965 65 -975 {}
-T {2x10 1W white LED} 1240 -200 0 0 0.4 0.4 {layer=8}
-T {2xseries 1W white LEDs} 1220 -140 0 0 0.4 0.4 {}
-T {2.5} 95 -755 0 0 0.2 0.2 {}
-T {5.0} 135 -755 0 0 0.2 0.2 {}
-T {7.5} 175 -755 0 0 0.2 0.2 {}
-T {10.0} 215 -755 0 0 0.2 0.2 {}
-T {12.5} 255 -755 0 0 0.2 0.2 {}
-T {15.0} 295 -755 0 0 0.2 0.2 {}
-T {17.5} 335 -755 0 0 0.2 0.2 {}
-T {20.0} 375 -755 0 0 0.2 0.2 {}
-T {2.5} 35 -980 0 0 0.2 0.2 {}
-T {2.0} 35 -940 0 0 0.2 0.2 {}
-T {1.5} 35 -895 0 0 0.2 0.2 {}
-T {1.0} 35 -860 0 0 0.2 0.2 {}
-T {0.5} 35 -820 0 0 0.2 0.2 {}
-T {25C, 1000W/m2} 190 -1030 0 0 0.2 0.2 {}
-T {V} 410 -765 0 0 0.4 0.4 {}
-T {I} 40 -1020 0 0 0.4 0.4 {}
-T {SOLAR PANEL} 145 -1055 0 0 0.4 0.4 {}
-T {Maximum Power} 307.5 -980 0 0 0.2 0.2 {layer=8}
+B 2 1210 -605 1320 -505 {name=l21
+flags=graph,unlocked
+lock=1
+color=8
+node="tcleval([xschem translate l21 @#0:net_name] [xschem translate l21 @#1:net_name] -)"
+x1=5e-10
+x2=0.001
+y1=-4.8
+y2=15}
+B 2 400 -735 510 -635 {name=l22
+flags=graph,unlocked
+lock=1
+color=8
+node="tcleval([xschem translate l22 @#0:net_name])"
+y1=0.00033
+y2=21
+x1=5e-10
+x2=0.001}
+B 2 600 -485 710 -385 {name=l23
+flags=graph,unlocked
+lock=1
+color=8
+node="tcleval([xschem get_fqdevice [xschem translate l23 @device]])"
+x1=5e-10
+x2=0.001
+y1=-2.9
+y2=6.8}
+B 2 640 -295 750 -195 {name=l26
+flags=graph,unlocked
+lock=1
+color=8
+node="tcleval([xschem get_fqdevice [xschem translate l26 @device]])"
+x1=5e-10
+x2=0.001
+y1=-2.9
+y2=6.8}
+B 18 55 -1060 310 -875 {}
+A 5 310 -1060 5.590169943749475 243.434948822922 360 {fill=true}
+P 7 6 385 -875 330 -1031.25 325 -1045 312.5 -1060 300 -1065 55 -1075 {}
+T {2x10 1W white LED} 1350 -195 0 0 0.4 0.4 {layer=8}
+T {2xseries 1W white LEDs} 1330 -135 0 0 0.4 0.4 {}
+T {2.5} 85 -855 0 0 0.2 0.2 {}
+T {5.0} 125 -855 0 0 0.2 0.2 {}
+T {7.5} 165 -855 0 0 0.2 0.2 {}
+T {10.0} 205 -855 0 0 0.2 0.2 {}
+T {12.5} 245 -855 0 0 0.2 0.2 {}
+T {15.0} 285 -855 0 0 0.2 0.2 {}
+T {17.5} 325 -855 0 0 0.2 0.2 {}
+T {20.0} 365 -855 0 0 0.2 0.2 {}
+T {2.5} 25 -1080 0 0 0.2 0.2 {}
+T {2.0} 25 -1040 0 0 0.2 0.2 {}
+T {1.5} 25 -995 0 0 0.2 0.2 {}
+T {1.0} 25 -960 0 0 0.2 0.2 {}
+T {0.5} 25 -920 0 0 0.2 0.2 {}
+T {25C, 1000W/m2} 180 -1130 0 0 0.2 0.2 {}
+T {V} 400 -865 0 0 0.4 0.4 {}
+T {I} 30 -1120 0 0 0.4 0.4 {}
+T {SOLAR PANEL} 135 -1155 0 0 0.4 0.4 {}
+T {Maximum Power} 297.5 -1080 0 0 0.2 0.2 {layer=8}
T {set between 0 and 1
to simulate
sun radiation
@@ -232,21 +268,21 @@ T {Floater text
example} 870 -440 0 0 0.4 0.4 {}
T {@spice_get_current} 875 -598.75 0 0 0.3 0.3 {layer=7 name=L2}
T {@spice_get_current} 1015 -268.75 0 0 0.3 0.3 {layer=7 name=C1}
-N 1010 -210 1100 -210 {lab=0}
-N 1100 -300 1100 -210 {lab=0}
+N 1010 -180 1100 -180 {lab=0}
+N 1100 -300 1100 -180 {lab=0}
N 640 -610 730 -610 {lab=#net1}
N 1010 -440 1040 -440 {lab=VO}
N 1010 -440 1010 -310 {lab=VO}
-N 1010 -250 1010 -210 {lab=0}
-N 530 -610 580 -610 {lab=PANEL}
+N 1010 -250 1010 -180 {lab=0}
+N 360 -610 580 -610 {lab=PANEL}
N 1010 -610 1010 -440 {lab=VO}
N 820 -610 860 -610 {lab=SW}
N 820 -610 820 -490 {lab=SW}
N 790 -610 820 -610 {lab=SW}
-N 820 -210 1010 -210 {lab=0}
-N 800 -210 820 -210 {lab=0}
+N 820 -180 1010 -180 {lab=0}
+N 800 -180 820 -180 {lab=0}
N 1000 -610 1010 -610 {lab=VO}
-N 1100 -440 1140 -440 {lab=LED}
+N 1100 -440 1280 -440 {lab=LED}
N 1100 -440 1100 -360 {lab=LED}
N 820 -430 820 -390 { lab=#net2}
N 920 -610 940 -610 { lab=#net3}
@@ -295,12 +331,14 @@ N 770 -1080 770 -1030 {
lab=TRIANG}
N 770 -1030 890 -1030 {
lab=TRIANG}
-N 820 -330 820 -210 {
+N 820 -330 820 -180 {
lab=0}
+N 1190 -480 1190 -440 {lab=LED}
+N 1190 -670 1190 -640 {lab=PANEL}
C {title.sym} 160 -40 0 0 {name=l1 author="Stefan Schippers"}
-C {code_shown.sym} 170 -310 0 0 {name=CONTROL
+C {code_shown.sym} 180 -310 0 0 {name=CONTROL
value="tcleval(
-.probe alli
+.option savecurrents
.control
* example of tcl evaluation of code blocks:
* current path: $path
@@ -318,24 +356,26 @@ C {code.sym} 20 -240 0 0 {name=MODELS value=".MODEL DIODE D(IS=1.139e-08 RS=0.99
.MODEL swmod SW(VT=0.5 VH=0.01 RON=0.01 ROFF=10000000)
"}
C {lab_pin.sym} 650 -530 0 1 {name=l4 lab=PANEL }
-C {lab_pin.sym} 800 -210 0 0 {name=l6 lab=0 }
+C {lab_pin.sym} 800 -180 0 0 {name=l6 lab=0 }
C {ammeter.sym} 1070 -440 3 0 {name=Vled}
C {ind.sym} 890 -610 3 1 {name=L2
m=1
value=40u
footprint=1206
device=inductor
-hide_texts=true}
-C {lab_pin.sym} 1140 -440 0 1 {name=l7 lab=LED }
+hide_texts=true
+attach=L2}
+C {lab_pin.sym} 1280 -440 0 1 {name=l7 lab=LED }
C {lab_pin.sym} 820 -550 0 1 {name=l9 lab=SW }
C {capa.sym} 1010 -280 0 0 {name=C1
m=1
value=500n
footprint=1206
device="ceramic capacitor"
-hide_texts=true}
+hide_texts=true
+attach=C1}
C {lab_pin.sym} 1010 -400 0 1 {name=l10 lab=VO }
-C {lab_pin.sym} 530 -610 0 0 {name=l3 lab=PANEL }
+C {lab_pin.sym} 360 -610 0 0 {name=l3 lab=PANEL }
C {ammeter.sym} 970 -610 3 0 {name=Vind}
C {isource_table.sym} 1100 -330 0 0 {name=G2[9..0] CTRL="V(LED)" TABLE="
+ (0, 0)
@@ -403,3 +443,15 @@ C {spice_probe.sym} 850 -1030 0 1 {name=p4 analysis=tran}
C {spice_probe.sym} 810 -890 0 1 {name=p5 analysis=tran}
C {spice_probe.sym} 760 -670 0 0 {name=p6 analysis=tran}
C {spice_probe.sym} 160 -450 0 0 {name=p7 analysis=tran}
+C {lab_show.sym} 440 -610 2 0 {name=l24}
+C {lab_pin.sym} 1190 -670 0 0 {name=l25 lab=PANEL }
+C {scope2.sym} 1190 -480 0 0 {name=l21
+attach=l21}
+C {scope.sym} 380 -610 0 0 {name=l22
+attach=l22}
+C {scope_ammeter.sym} 580 -360 0 0 {name=l23
+attach=l23
+device=Vcap}
+C {scope_ammeter.sym} 620 -170 0 0 {name=l26
+attach=l26
+device=Vdiode}