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..25369cc1 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
@@ -828,6 +827,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
@@ -1192,8 +1200,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 +1217,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 +1296,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>
@@ -1634,6 +1646,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
@@ -1732,6 +1747,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..d56798ac 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;
@@ -1450,7 +1450,6 @@ 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]");
place_symbol(-1, lab, xctx->mousex_snap, xctx->mousey_snap, 0, 0, NULL, 4, 1, 1/*to_push_undo*/);
@@ -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));
}
-
+ 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]);
@@ -3830,7 +3881,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..504a19eb 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 */) ) {
@@ -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;
}
@@ -2827,20 +2835,23 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
draw();
return;
}
- if(key == 'X' && rstate == 0) /* highlight discrepanciens between selected instance pin and net names */
+ /* highlight discrepanciens between selected instance pin and net names */
+ if(key == 'X' && rstate == 0)
{
hilight_net_pin_mismatches();
return;
}
- if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { /* create wire snapping to closest instance pin (original keybind) */
+ /* create wire snapping to closest instance pin */
+ if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) {
if(xctx->semaphore >= 2) return;
snapped_wire(c_snap);
return;
}
- 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;
+ /* create wire snapping to closest instance pin (cadence keybind) */
+ if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) {
+ if(xctx->semaphore >= 2) return;
+ snapped_wire(c_snap);
+ return;
}
if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */
{
@@ -2875,9 +2886,9 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
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;
- if(snap_cursor) draw_snap_cursor(1);
}
return;
}
@@ -3394,6 +3405,9 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
{
if(xctx->semaphore >= 2) return;
ask_new_file();
+ xctx->semaphore--;
+ tcleval("load_additional_files");
+ xctx->semaphore++;
return;
}
if(key=='S' && rstate == 0) /* change element order */
@@ -3530,7 +3544,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
draw();
return;
}
- if(0 && (key=='u') && rstate==ControlMask) /* testmode */
+ if(key=='u' && rstate==ControlMask) /* unselect attached floater elements */
+ {
+ unselect_attached_floaters();
+ }
+ if(0 && (key=='|') && rstate==ControlMask) /* testmode */
{
static int x = 0;
@@ -4036,21 +4054,6 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
check_unique_names(1);
return;
}
- if( 0 && (key==';') && (state & ControlMask) ) /* testmode */
- {
- return;
- }
- if(0 && key=='~' && (state & ControlMask)) { /* testmode */
- return;
- }
- if(0 && key=='|' && !(state & ControlMask)) { /* testmode */
- return;
- }
- if(0 && key=='|' && (state & ControlMask)) /* testmode */
- {
- return;
- }
-
if(key=='f' && rstate == ControlMask) /* search */
{
if(xctx->semaphore >= 2) return;
@@ -4215,7 +4218,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 +4385,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 +4446,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 +4637,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 +4681,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..fb0c1ddc 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
@@ -2838,7 +2857,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 +3074,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 +3101,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 +3277,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 +3801,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 +3823,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 +4107,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 +4788,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 +4842,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 +4857,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..6ec3ba09 100644
--- a/src/move.c
+++ b/src/move.c
@@ -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,
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..84f94fa5 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -1798,8 +1798,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 +2129,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);
@@ -2888,11 +2915,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 +2938,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 +2970,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 +3017,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 +3051,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 +3660,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) {
@@ -3969,8 +4024,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 +4041,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 +4120,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 +4188,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 +4220,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;
@@ -4960,7 +5022,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 +5032,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 +5052,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 +5062,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 +5071,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 +5523,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 +5532,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 +5554,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 +5565,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 +5998,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 +6286,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"))
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/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..192ae975 100644
--- a/src/xinit.c
+++ b/src/xinit.c
@@ -2060,6 +2060,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 */
diff --git a/src/xschem.h b/src/xschem.h
index 27700e9f..eb62ea35 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,9 @@ 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 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);
@@ -1547,6 +1548,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 +1614,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 +1692,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..ca58107d 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
}
}
}
@@ -4365,8 +4374,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 +4410,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 +4443,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)
@@ -4506,11 +4538,15 @@ 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 \
+ -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
@@ -6447,12 +6483,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
@@ -6744,8 +6785,14 @@ proc rel_sym_path {symbol} {
global OS pathlist env
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 {}
@@ -7848,42 +7895,34 @@ 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
+ 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 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 +8307,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
@@ -8421,6 +8460,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 +8653,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 +8731,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" \
@@ -9331,6 +9389,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 +9399,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
diff --git a/src/xschemrc b/src/xschemrc
index 1ccaffd0..fae161fe 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
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}