/* File: select.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2024 Stefan Frederik Schippers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xschem.h" /* select all nets and pins/labels that are *physically* connected to current selected wire segments * stop_at_junction==1 --> stop selecting wires at 'T' junctions * stop_at_junction==2 --> select only wires directly attached to selected net/instance * Recursive routine */ static void check_connected_nets(int stop_at_junction, int n) { int k, touches; xWire * const wire = xctx->wire; Wireentry *wireptr; Instentry *instptr; char *type; double x1, y1, x2, y2; Iterator_ctx ctx; x1 = wire[n].x1; y1 = wire[n].y1; x2 = wire[n].x2; y2 = wire[n].y2; RECTORDER(x1, y1, x2, y2); dbg(1, "check_connected_nets(): n=%d, %g %g %g %g\n", n, x1, y1, x2, y2); for(init_inst_iterator(&ctx, x1, y1, x2, y2); (instptr = inst_iterator_next(&ctx)) ;) { k = instptr->n; type = (xctx->inst[k].ptr+ xctx->sym)->type; if( type && (IS_LABEL_SH_OR_PIN(type) || !strcmp(type, "probe") )) { double x0, y0; xRect *rct; rct=(xctx->inst[k].ptr+ xctx->sym)->rect[PINLAYER]; if(rct) { get_inst_pin_coord(k, 0, &x0, &y0); touches = touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, x0, y0); if(touches) { xctx->need_reb_sel_arr=1; xctx->inst[k].sel = SELECTED; } } } } if(!(stop_at_junction & 2)) { for(init_wire_iterator(&ctx, x1, y1, x2, y2); (wireptr = wire_iterator_next(&ctx)) ;) { k = wireptr->n; if(n == k || xctx->wire[k].sel == SELECTED) continue; if((stop_at_junction & 1)== 0) { touches = touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, wire[k].x1, wire[k].y1) || touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, wire[k].x2, wire[k].y2) || touch(wire[k].x1, wire[k].y1, wire[k].x2, wire[k].y2, wire[n].x1, wire[n].y1) || touch(wire[k].x1, wire[k].y1, wire[k].x2, wire[k].y2, wire[n].x2, wire[n].y2); } else { touches = (wire[n].x1 == wire[k].x1 && wire[n].y1 == wire[k].y1 && wire[n].end1 < 2 && wire[k].end1 < 2) || (wire[n].x1 == wire[k].x2 && wire[n].y1 == wire[k].y2 && wire[n].end1 < 2 && wire[k].end2 < 2) || (wire[n].x2 == wire[k].x1 && wire[n].y2 == wire[k].y1 && wire[n].end2 < 2 && wire[k].end1 < 2) || (wire[n].x2 == wire[k].x2 && wire[n].y2 == wire[k].y2 && wire[n].end2 < 2 && wire[k].end2 < 2); } if(touches) { xctx->wire[k].sel = SELECTED; check_connected_nets(stop_at_junction, k); /* recursive check */ } } } } /* stop_at_junction==1 --> stop selecting wires at 'T' junctions * stop_at_junction==2 --> select only wires directly attached to selected net/instance */ void select_connected_nets(int stop_at_junction) { int i, n; int netlist_lvs_ignore=tclgetboolvar("lvs_ignore"); if(stop_at_junction & 1) trim_wires(); hash_wires(); hash_instances(); rebuild_selected_array(); /* does nothing as already done in most of use cases */ for(n=0; nlastsel; ++n) { i = xctx->sel_array[n].n; switch(xctx->sel_array[n].type) { double x0, y0; int sqx, sqy, p, rects; Wireentry *wptr; Instentry *iptr; case WIRE: if(xctx->wire[i].sel == SELECTED) check_connected_nets(stop_at_junction, i); break; case ELEMENT: rects = (xctx->inst[i].ptr + xctx->sym)->rects[PINLAYER]; for(p = 0; p < rects; p++) { get_inst_pin_coord(i, p, &x0, &y0); get_square(x0, y0, &sqx, &sqy); for(wptr = xctx->wire_spatial_table[sqx][sqy]; wptr; wptr = wptr->next) { dbg(1, "select_connected_nets(): x0=%g y0=%g wire[%d]=%g %g %g %g\n", x0, y0, wptr->n, xctx->wire[wptr->n].x1, xctx->wire[wptr->n].y1, xctx->wire[wptr->n].x2, xctx->wire[wptr->n].y2); if (touch(xctx->wire[wptr->n].x1, xctx->wire[wptr->n].y1, xctx->wire[wptr->n].x2, xctx->wire[wptr->n].y2, x0,y0)) { xctx->wire[wptr->n].sel = SELECTED; check_connected_nets(stop_at_junction, wptr->n); } } for(iptr = xctx->inst_spatial_table[sqx][sqy]; iptr; iptr = iptr->next) { int rects, p, touches; char *type; xRect *rct; int n = iptr->n; double x1, y1; if(n == i) continue; type = (xctx->inst[n].ptr+ xctx->sym)->type; if( type && (!strcmp(type, "label") || !strcmp(type, "probe")) ) { if(skip_instance(n, 0, netlist_lvs_ignore)) continue; rct = (xctx->inst[n].ptr+ xctx->sym)->rect[PINLAYER]; if(!rct) continue; rects = (xctx->inst[n].ptr + xctx->sym)->rects[PINLAYER]; for(p = 0; p < rects; p++) { get_inst_pin_coord(n, p, &x1, &y1); touches = (x0 == x1 && y0 == y1); if(touches) { xctx->inst[n].sel = SELECTED; } } } } } /* for(p...) */ break; default: break; } /* switch(...) */ } /* for(... lastsel ...) */ xctx->need_reb_sel_arr=1; rebuild_selected_array(); draw_selection(xctx->gc[SELLAYER], 0); } int select_dangling_nets(void) { int netlist_lvs_ignore=tclgetboolvar("lvs_ignore"); int i, p, w, touches, rects, done; int ret = 0; /* return code: 1: dangling elements found */ int *table = NULL; xRect *rct; xWire * const wire = xctx->wire; Instentry *instptr; Wireentry *wireptr; Iterator_ctx ctx; char *type; double x0, y0, x1, y1, x2, y2; table = my_calloc(_ALLOC_ID_, xctx->wires, sizeof(int)); hash_instances(); hash_wires(); /* Mark nets connected to non pin/label/probe components as NOT dangling (table[w] = 1) */ for(w = 0; w < xctx->wires; w++) { x1 = xctx->wire[w].x1; y1 = xctx->wire[w].y1; x2 = xctx->wire[w].x2; y2 = xctx->wire[w].y2; RECTORDER(x1, y1, x2, y2); for(init_inst_iterator(&ctx, x1, y1, x2, y2); (instptr = inst_iterator_next(&ctx)) ;) { i = instptr->n; if(skip_instance(i, 0, netlist_lvs_ignore)) continue; type = (xctx->inst[i].ptr+ xctx->sym)->type; rct=(xctx->inst[i].ptr+ xctx->sym)->rect[PINLAYER]; if(!rct) continue; if( type && (!strcmp(type, "label") || !strcmp(type, "probe") )) { continue; } rects = (xctx->inst[i].ptr + xctx->sym)->rects[PINLAYER]; for(p = 0; p < rects; p++) { get_inst_pin_coord(i, p, &x0, &y0); touches = touch(xctx->wire[w].x1, xctx->wire[w].y1, xctx->wire[w].x2, xctx->wire[w].y2, x0, y0); if(touches) { table[w] = 1; /* wire[w] is NOT dangling */ dbg(1, "wire %d touches inst %d\n", w, i); } } } } /* Propagate NOT dangling nets to other nets */ done = 0; while(!done) { done = 1; for(w = 0; w < xctx->wires; w++) { if(table[w] == 0) continue; /* wire[w] is not dangling */ x1 = xctx->wire[w].x1; y1 = xctx->wire[w].y1; x2 = xctx->wire[w].x2; y2 = xctx->wire[w].y2; RECTORDER(x1, y1, x2, y2); for(init_wire_iterator(&ctx, x1, y1, x2, y2); (wireptr = wire_iterator_next(&ctx)) ;) { i = wireptr->n; if(i == w) continue; if(table[i]) continue; touches = touch(wire[w].x1, wire[w].y1, wire[w].x2, wire[w].y2, wire[i].x1, wire[i].y1) || touch(wire[w].x1, wire[w].y1, wire[w].x2, wire[w].y2, wire[i].x2, wire[i].y2) || touch(wire[i].x1, wire[i].y1, wire[i].x2, wire[i].y2, wire[w].x1, wire[w].y1) || touch(wire[i].x1, wire[i].y1, wire[i].x2, wire[i].y2, wire[w].x2, wire[w].y2); if(touches) { table[i] = 1; /* wire[i] also not dangling */ done = 0; } } } } /* Select all nets that are dangling */ for(w = 0; w < xctx->wires; w++) { if(!table[w]) { xctx->wire[w].sel = SELECTED; ret = 1; } } /* select pins/labels/probes attached to dangling nets */ for(w = 0; w < xctx->wires; w++) { if(table[w]) continue; x1 = xctx->wire[w].x1; y1 = xctx->wire[w].y1; x2 = xctx->wire[w].x2; y2 = xctx->wire[w].y2; RECTORDER(x1, y1, x2, y2); for(init_inst_iterator(&ctx, x1, y1, x2, y2); (instptr = inst_iterator_next(&ctx)) ;) { i = instptr->n; type = (xctx->inst[i].ptr+ xctx->sym)->type; if( type && (!strcmp(type, "label") || !strcmp(type, "probe") )) { rct = (xctx->inst[i].ptr+ xctx->sym)->rect[PINLAYER]; if(!rct) continue; get_inst_pin_coord(i, 0, &x0, &y0); touches = touch(xctx->wire[w].x1, xctx->wire[w].y1, xctx->wire[w].x2, xctx->wire[w].y2, x0, y0); if(touches) { xctx->inst[i].sel = SELECTED; ret = 1; } } } } /* select dangling labels/probes (not connected to anything) */ for(i = 0; i < xctx->instances; i++) { int dangling = 1; if(xctx->inst[i].sel == SELECTED) continue; type = (xctx->inst[i].ptr+ xctx->sym)->type; if( type && (!strcmp(type, "label") || !strcmp(type, "probe")) ) { int sqx, sqy; rct = (xctx->inst[i].ptr+ xctx->sym)->rect[PINLAYER]; if(!rct) continue; get_inst_pin_coord(i, 0, &x0, &y0); get_square(x0, y0, &sqx, &sqy); for(wireptr = xctx->wire_spatial_table[sqx][sqy]; wireptr; wireptr = wireptr->next) { int n = wireptr->n; if (touch(xctx->wire[n].x1, xctx->wire[n].y1, xctx->wire[n].x2, xctx->wire[n].y2, x0, y0)) { dangling = 0; /* inst[i] connected to a wire */ } } for(instptr = xctx->inst_spatial_table[sqx][sqy]; instptr; instptr = instptr->next) { int n = instptr->n; if(n == i) continue; type = (xctx->inst[n].ptr+ xctx->sym)->type; if( type && (!strcmp(type, "label") || !strcmp(type, "probe")) ) continue; if(skip_instance(n, 0, netlist_lvs_ignore)) continue; rct = (xctx->inst[n].ptr+ xctx->sym)->rect[PINLAYER]; if(!rct) continue; rects = (xctx->inst[n].ptr + xctx->sym)->rects[PINLAYER]; for(p = 0; p < rects; p++) { get_inst_pin_coord(n, p, &x1, &y1); touches = (x0 == x1 && y0 == y1); if(touches) { dangling = 0; /* inst[i] connected to non label/probe inst[n] */ } } } if(dangling) { xctx->inst[i].sel = SELECTED; ret = 1; } } } /* draw selection */ xctx->need_reb_sel_arr = 1; rebuild_selected_array(); draw_selection(xctx->gc[SELLAYER], 0); my_free(_ALLOC_ID_, &table); return ret; } void symbol_bbox(int i, double *x1,double *y1, double *x2, double *y2) { int j, tmp; xText text; const char *tmp_txt; short rot,flip; double x0, y0, dtmp; double text_x0, text_y0; short sym_rot, sym_flip; double xx1,yy1,xx2,yy2; #if HAS_CAIRO==1 int customfont; #endif /* symbol bbox */ flip = xctx->inst[i].flip; rot = xctx->inst[i].rot; x0=xctx->inst[i].x0; y0=xctx->inst[i].y0; ROTATION(rot, flip, 0.0,0.0,(xctx->inst[i].ptr+ xctx->sym)->minx, (xctx->inst[i].ptr+ xctx->sym)->miny,*x1,*y1); ROTATION(rot, flip, 0.0,0.0,(xctx->inst[i].ptr+ xctx->sym)->maxx, (xctx->inst[i].ptr+ xctx->sym)->maxy,*x2,*y2); RECTORDER(*x1,*y1,*x2,*y2); *x1+=x0;*y1+=y0; *x2+=x0;*y2+=y0; xctx->inst[i].xx1 = *x1; /* 20070314 added bbox without text */ xctx->inst[i].yy1 = *y1; /* for easier select */ xctx->inst[i].xx2 = *x2; xctx->inst[i].yy2 = *y2; dbg(2, "symbol_bbox(): instance=%s %.16g %.16g %.16g %.16g\n",xctx->inst[i].instname,*x1, *y1, *x2, *y2); /* strings bbox */ for(j=0;j< (xctx->inst[i].ptr+ xctx->sym)->texts; ++j) { double xscale, yscale; char *estr = NULL; get_sym_text_size(i, j, &xscale, &yscale); text = (xctx->inst[i].ptr+ xctx->sym)->text[j]; if(!xctx->show_hidden_texts && (text.flags & (HIDE_TEXT | HIDE_TEXT_INSTANTIATED))) continue; sym_flip = flip; sym_rot = rot; dbg(1, "symbol_bbox(): instance %d text n: %d text str=%s\n", i,j, text.txt_ptr? text.txt_ptr:""); tmp_txt = translate(i, text.txt_ptr); dbg(1, "symbol_bbox(): translated text: %s\n", tmp_txt); if(tmp_txt && !strncmp(tmp_txt, "@spice", 6)) continue; /* annotator texts not used in bbox */ ROTATION(rot, flip, 0.0,0.0,text.x0, text.y0,text_x0,text_y0); #if HAS_CAIRO==1 customfont=set_text_custom_font(&text); #endif estr = my_expand(tmp_txt, tclgetintvar("tabstop")); text_bbox(estr, xscale, yscale, (text.rot + ( (sym_flip && (text.rot & 1) ) ? sym_rot+2 : sym_rot)) &0x3, sym_flip ^ text.flip, text.hcenter, text.vcenter, x0+text_x0,y0+text_y0, &xx1,&yy1,&xx2,&yy2, &tmp, &dtmp); dbg(1, "symbol bbox: text bbox: %s, %g %g %g %g\n", tmp_txt, xx1, yy1, xx2, yy2); dbg(1, "symbol bbox: text bbox: zoom=%g, lw=%g\n", xctx->zoom, xctx->lw); my_free(_ALLOC_ID_, &estr); #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif if(xx1<*x1) *x1=xx1; if(yy1<*y1) *y1=yy1; if(xx2>*x2) *x2=xx2; if(yy2>*y2) *y2=yy2; } dbg(1, "symbol_bbox(): instance=%s %.16g %.16g %.16g %.16g\n", xctx->inst[i].instname, *x1, *y1, *x2, *y2); } static void del_rect_line_arc_poly() { xRect tmp; int c, j, i; int deleted = 0; for(c=0;crects[c]; ++i) { if(xctx->rect[c][i].sel == SELECTED) { if(c == GRIDLAYER) xctx->graph_lastsel = -1; /* invalidate last selected graph */ ++j; my_free(_ALLOC_ID_, &xctx->rect[c][i].prop_ptr); set_rect_extraptr(0, &xctx->rect[c][i]); deleted = 1; continue; } if(j) { xctx->rect[c][i-j] = xctx->rect[c][i]; } } xctx->rects[c] -= j; j = 0; for(i=0;ilines[c]; ++i) { if(xctx->line[c][i].sel == SELECTED) { ++j; deleted = 1; my_free(_ALLOC_ID_, &xctx->line[c][i].prop_ptr); continue; } if(j) { xctx->line[c][i-j] = xctx->line[c][i]; } } xctx->lines[c] -= j; j = 0; for(i=0;iarcs[c]; ++i) { if(xctx->arc[c][i].sel == SELECTED) { ++j; if(xctx->arc[c][i].fill) /* .fill: 1: stippled fill, 2: solid fill */ arc_bbox(xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, 0, 360, &tmp.x1, &tmp.y1, &tmp.x2, &tmp.y2); else arc_bbox(xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b, &tmp.x1, &tmp.y1, &tmp.x2, &tmp.y2); my_free(_ALLOC_ID_, &xctx->arc[c][i].prop_ptr); deleted = 1; continue; } if(j) { xctx->arc[c][i-j] = xctx->arc[c][i]; } } xctx->arcs[c] -= j; j = 0; for(i=0;ipolygons[c]; ++i) { if(xctx->poly[c][i].sel == SELECTED) { int k; double x1=0., y1=0., x2=0., y2=0.; for(k=0; kpoly[c][i].points; ++k) { if(k==0 || xctx->poly[c][i].x[k] < x1) x1 = xctx->poly[c][i].x[k]; if(k==0 || xctx->poly[c][i].y[k] < y1) y1 = xctx->poly[c][i].y[k]; if(k==0 || xctx->poly[c][i].x[k] > x2) x2 = xctx->poly[c][i].x[k]; if(k==0 || xctx->poly[c][i].y[k] > y2) y2 = xctx->poly[c][i].y[k]; } ++j; my_free(_ALLOC_ID_, &xctx->poly[c][i].prop_ptr); my_free(_ALLOC_ID_, &xctx->poly[c][i].x); my_free(_ALLOC_ID_, &xctx->poly[c][i].y); my_free(_ALLOC_ID_, &xctx->poly[c][i].selected_point); /*fprintf(errfp, "bbox: %.16g %.16g %.16g %.16g\n", x1, y1, x2, y2); */ deleted = 1; continue; } if(j) { xctx->poly[c][i-j] = xctx->poly[c][i]; } } xctx->polygons[c] -= j; } if(deleted) { set_modify(1); xctx->need_reb_sel_arr = 1; } } int delete_wires(int selected_flag) { int i, j = 0, deleted = 0; for(i=0;iwires; ++i) { if(xctx->wire[i].sel == selected_flag) { ++j; /* hash_wire(XDELETE, i, 0); */ /* can not be done since wire deletions change wire idexes in array */ my_free(_ALLOC_ID_, &xctx->wire[i].prop_ptr); my_free(_ALLOC_ID_, &xctx->wire[i].node); deleted = 1; continue; } if(j) { xctx->wire[i-j] = xctx->wire[i]; } } xctx->wires -= j; if(j) { xctx->prep_hash_wires=0; xctx->prep_net_structs=0; xctx->prep_hi_structs=0; } if(xctx->hilight_nets) { propagate_hilights(1, 1, XINSERT_NOREPLACE); } return deleted; } void delete(int to_push_undo) { int i, j, deleted = 0; #if HAS_CAIRO==1 int customfont; #endif dbg(3, "delete(): start\n"); j = 0; rebuild_selected_array(); if(to_push_undo && xctx->lastsel) xctx->push_undo(); del_rect_line_arc_poly(); for(i=0;itexts; ++i) { if(xctx->text[i].sel == SELECTED) { #if HAS_CAIRO==1 customfont = set_text_custom_font(&xctx->text[i]); #endif #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif my_free(_ALLOC_ID_, &xctx->text[i].prop_ptr); my_free(_ALLOC_ID_, &xctx->text[i].font); my_free(_ALLOC_ID_, &xctx->text[i].floater_instname); my_free(_ALLOC_ID_, &xctx->text[i].floater_ptr); my_free(_ALLOC_ID_, &xctx->text[i].txt_ptr); deleted = 1; ++j; continue; } if(j) { dbg(1, "select(); deleting string %d\n",i-j); xctx->text[i-j] = xctx->text[i]; dbg(1, "select(); new string %d = %s\n",i-j,xctx->text[i-j].txt_ptr); } } xctx->texts -= j; j = 0; for(i=0;iinstances; ++i) { if(xctx->inst[i].sel == SELECTED) { deleted = 1; if(xctx->inst[i].prop_ptr != NULL) { my_free(_ALLOC_ID_, &xctx->inst[i].prop_ptr); } delete_inst_node(i); my_free(_ALLOC_ID_, &xctx->inst[i].name); my_free(_ALLOC_ID_, &xctx->inst[i].instname); my_free(_ALLOC_ID_, &xctx->inst[i].lab); ++j; continue; } if(j) { xctx->inst[i-j] = xctx->inst[i]; } } xctx->instances-=j; if(j) { xctx->prep_hash_inst=0; xctx->prep_net_structs=0; xctx->prep_hi_structs=0; } if(delete_wires(SELECTED)) { deleted = 1; if(tclgetboolvar("autotrim_wires")) trim_wires(); update_conn_cues(WIRELAYER, 0, 0); } if(xctx->hilight_nets) { propagate_hilights(1, 1, XINSERT_NOREPLACE); } if(deleted) set_modify(1); xctx->lastsel = 0; draw(); xctx->ui_state &= ~SELECTION; set_first_sel(0, -1, 0); } void delete_only_rect_line_arc_poly(void) { del_rect_line_arc_poly(); draw(); xctx->ui_state &= ~SELECTION; set_first_sel(0, -1, 0); } void bbox(int what,double x1,double y1, double x2, double y2) { dbg(1, "bbox: what=%d\n", what); switch(what) { case START: if(xctx->bbox_set==1) { fprintf(errfp, "ERROR: rentrant bbox() call\n"); tcleval("alert_ {ERROR: reentrant bbox() call} {}"); } xctx->bbx1 = 300000000; /* screen coordinates */ xctx->bbx2 = 0; xctx->bby1 = 300000000; xctx->bby2 = 0; xctx->savex1 = xctx->areax1; xctx->savex2 = xctx->areax2; xctx->savey1 = xctx->areay1; xctx->savey2 = xctx->areay2; xctx->savew = xctx->areaw; xctx->saveh = xctx->areah; xctx->savexrect = xctx->xrect[0]; xctx->bbox_set=1; break; case ADD: if(xctx->bbox_set==0) { fprintf(errfp, "ERROR: bbox(ADD) call before bbox(START)\n"); tcleval("alert_ {ERROR: bbox(ADD) call before bbox(START)} {}"); } dbg(2, "bbox(ADD): %.16g %.16g %.16g %.16g\n", x1, y1, x2, y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); x1=CLIP(x1,xctx->savex1,xctx->savex2); x2=CLIP(x2,xctx->savex1,xctx->savex2); y1=CLIP(y1,xctx->savey1,xctx->savey2); y2=CLIP(y2,xctx->savey1,xctx->savey2); if(x1 < xctx->bbx1) xctx->bbx1 = (int) x1; if(x2 > xctx->bbx2) xctx->bbx2 = (int) x2; if(y1 < xctx->bby1) xctx->bby1 = (int) y1; if(y2 > xctx->bby2) xctx->bby2 = (int) y2; if(y2 < xctx->bby1) xctx->bby1 = (int) y2; if(y1 > xctx->bby2) xctx->bby2 = (int) y1; break; case END: if(xctx->bbox_set) { xctx->areax1 = xctx->savex1; xctx->areax2 = xctx->savex2; xctx->areay1 = xctx->savey1; xctx->areay2 = xctx->savey2; xctx->areaw = xctx->savew; xctx->areah = xctx->saveh; xctx->xrect[0] = xctx->savexrect; if(has_x) { dbg(2, "bbox(END): resetting clip area: %d %d %d %d\n", xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); set_clip_mask(END); } xctx->bbox_set=0; } break; case SET: if(xctx->bbox_set==0) { fprintf(errfp, "ERROR: bbox(SET) call before bbox(START)\n"); tcleval("alert_ {ERROR: bbox(SET) call before bbox(START)} {}"); } xctx->areax1 = xctx->bbx1-2*INT_LINE_W(xctx->lw); xctx->areax2 = xctx->bbx2+2*INT_LINE_W(xctx->lw); xctx->areay1 = xctx->bby1-2*INT_LINE_W(xctx->lw); xctx->areay2 = xctx->bby2+2*INT_LINE_W(xctx->lw); xctx->areaw = (xctx->areax2-xctx->areax1); xctx->areah = (xctx->areay2-xctx->areay1); xctx->xrect[0].x = (short)(xctx->bbx1-INT_LINE_W(xctx->lw)); xctx->xrect[0].y = (short)(xctx->bby1-INT_LINE_W(xctx->lw)); xctx->xrect[0].width = (unsigned short)(xctx->bbx2-xctx->bbx1+2*INT_LINE_W(xctx->lw)); xctx->xrect[0].height = (unsigned short)(xctx->bby2-xctx->bby1+2*INT_LINE_W(xctx->lw)); if(has_x) { set_clip_mask(SET); dbg(2, "bbox(SET): setting clip area: %d %d %d %d\n", xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); } break; case SET_INSIDE: /* do not add line widths to clip rectangle so everything remains inside */ if(xctx->bbox_set==0) { fprintf(errfp, "ERROR: bbox(SET_INSIDE) call before bbox(START)\n"); tcleval("alert_ {ERROR: bbox(SET_INSIDE) call before bbox(START)} {}"); } xctx->areax1 = xctx->bbx1-2*INT_LINE_W(xctx->lw); xctx->areax2 = xctx->bbx2+2*INT_LINE_W(xctx->lw); xctx->areay1 = xctx->bby1-2*INT_LINE_W(xctx->lw); xctx->areay2 = xctx->bby2+2*INT_LINE_W(xctx->lw); xctx->areaw = (xctx->areax2-xctx->areax1); xctx->areah = (xctx->areay2-xctx->areay1); xctx->xrect[0].x = (short)(xctx->bbx1+INT_LINE_W(xctx->lw)); xctx->xrect[0].y = (short)(xctx->bby1+INT_LINE_W(xctx->lw)); xctx->xrect[0].width = (unsigned short)(xctx->bbx2-xctx->bbx1-2*INT_LINE_W(xctx->lw)); xctx->xrect[0].height = (unsigned short)(xctx->bby2-xctx->bby1-2*INT_LINE_W(xctx->lw)); if(has_x) { set_clip_mask(SET); dbg(2, "bbox(SET): setting clip area: %d %d %d %d\n", xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); } break; default: break; } } /* n = -1 : clear first selected info * n = -2 : return first selected element if still selected, or get first from * 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) { if(n == -2) { int j; /* retrieve first selected element (if still selected)... */ if(xctx->first_sel.n >=0 && xctx->first_sel.type == ELEMENT && xctx->inst[xctx->first_sel.n].sel == SELECTED) { for(j=0; j < xctx->lastsel; j++) { if(xctx->sel_array[j].type == ELEMENT && xctx->sel_array[j].n == xctx->first_sel.n) { break; } } /* ... otherwise get first from sel_array[] list */ } else { for(j=0; j < xctx->lastsel; j++) { if(xctx->sel_array[j].type == ELEMENT) { break; } } } dbg(1, "set_first_sel(): j=%d, i=%d\n", j, xctx->sel_array[j].n); if(j >= xctx->lastsel) j = 0; return j; } else if(n == -1) { /* reset first_sel */ xctx->first_sel.type = 0; xctx->first_sel.n = -1; xctx->first_sel.col = 0; dbg(1, "set_first_sel(): clearing\n"); } else if(xctx->first_sel.n == -1) { xctx->first_sel.type = type; xctx->first_sel.n = n; xctx->first_sel.col = col; dbg(1, "set_first_sel(): storing %d\n", n); } return 0; } void unselect_all(int dr) { int i,c; char str[PATH_MAX]; #if HAS_CAIRO==1 int customfont; #endif set_first_sel(0, -1, 0); if((xctx->ui_state & SELECTION) || xctx->lastsel) { dbg(1, "unselect_all(%d): start\n", dr); xctx->ui_state = 0; xctx->lastsel = 0; for(i=0;iwires; ++i) { if(xctx->wire[i].sel) { xctx->wire[i].sel = 0; { if(dr) { if(xctx->wire[i].bus == -1.0) drawtempline(xctx->gctiled, THICK, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); else drawtempline(xctx->gctiled, ADD, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); } } } } for(i=0;iinstances; ++i) { if(xctx->inst[i].sel == SELECTED) { xctx->inst[i].sel = 0; if(dr) for(c=0;cgctiled, i, c,0,0,0.0,0.0); } } for(i=0;itexts; ++i) { if(xctx->text[i].sel == SELECTED) { xctx->text[i].sel = 0; if(dr) { #if HAS_CAIRO==1 customfont = set_text_custom_font(& xctx->text[i]); /* needed for bbox calculation */ #endif draw_temp_string(xctx->gctiled,ADD, get_text_floater(i), xctx->text[i].rot, xctx->text[i].flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0, xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif } } } for(c=0;carcs[c]; ++i) { if(xctx->arc[c][i].sel) { xctx->arc[c][i].sel = 0; if(dr) drawtemparc(xctx->gctiled, ADD, xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b); } } for(i=0;irects[c]; ++i) { if(xctx->rect[c][i].sel) { xctx->rect[c][i].sel = 0; if(dr) drawtemprect(xctx->gctiled, ADD, xctx->rect[c][i].x1, xctx->rect[c][i].y1, xctx->rect[c][i].x2, xctx->rect[c][i].y2); } } for(i=0;ilines[c]; ++i) { if(xctx->line[c][i].sel) { xctx->line[c][i].sel = 0; if(dr) { if(xctx->line[c][i].bus == -1.0) drawtempline(xctx->gctiled, THICK, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); else drawtempline(xctx->gctiled, ADD, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); } } } for(i=0;ipolygons[c]; ++i) { if(xctx->poly[c][i].sel) { int k; int bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); for(k=0;kpoly[c][i].points; ++k) xctx->poly[c][i].selected_point[k] = 0; xctx->poly[c][i].sel = 0; if(dr) { drawtemppolygon(xctx->gctiled, NOW, xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, bezier); } } } } if(dr) { drawtemparc(xctx->gctiled, END, 0.0, 0.0, 0.0, 0.0, 0.0); drawtemprect(xctx->gctiled, END, 0.0, 0.0, 0.0, 0.0); drawtempline(xctx->gctiled,END, 0.0, 0.0, 0.0, 0.0); } xctx->ui_state &= ~SELECTION; my_snprintf(str, S(str), "%s/%s", user_conf_dir, ".selection.sch"); /* 20161115 PWD->HOME */ xunlink(str); dbg(2, "unselect_all(1): done\n"); } } 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 & 1)) { my_snprintf(str, S(str), "Info: selected wire: n=%d end1=%d end2=%d\nnode=%s",i, xctx->wire[i].end1, xctx->wire[i].end2, xctx->wire[i].prop_ptr? xctx->wire[i].prop_ptr: ""); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g w = %.16g h = %.16g", i, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2-xctx->wire[i].x1, xctx->wire[i].y2-xctx->wire[i].y1 ); statusmsg(str,1); } if( ((xctx->wire[i].sel|select_mode) == (SELECTED1|SELECTED2)) || ((xctx->wire[i].sel == SELECTED) && select_mode) ) { xctx->wire[i].sel = SELECTED; } else { xctx->wire[i].sel = select_mode; } if( xctx->wire[i].sel == SELECTED) set_first_sel(WIRE, i, 0); if(select_mode) { dbg(1, "select(): wire[%d].end1=%d, ,end2=%d\n", i, xctx->wire[i].end1, xctx->wire[i].end2); if(xctx->wire[i].bus == -1.0) { if(!(fast & 2)) drawtempline(xctx->gc[SELLAYER], THICK, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); } else { if(!(fast & 2)) drawtempline(xctx->gc[SELLAYER], ADD, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); } } else { if(xctx->wire[i].bus == -1.0) { if(!(fast & 2)) drawtempline(xctx->gctiled, THICK, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); } else { if(!(fast & 2)) drawtempline(xctx->gctiled, NOW, xctx->wire[i].x1, xctx->wire[i].y1, xctx->wire[i].x2, xctx->wire[i].y2); } } 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 */ void select_element(int i,unsigned short select_mode, int fast, int override_lock) { int c, j; char str[1024]; /* overflow safe */ char s[256]; /* overflow safe */ if(!strboolcmp(get_tok_value(xctx->inst[i].prop_ptr, "lock", 0), "true") && select_mode == SELECTED && !override_lock) return; my_strncpy(s,xctx->inst[i].prop_ptr!=NULL?xctx->inst[i].prop_ptr:"",S(s)); if( !(fast & 1) ) { my_snprintf(str, S(str), "Info: selected element %d: %s\nproperties:\n%s", i, xctx->inst[i].name ? xctx->inst[i].name : "" , s); statusmsg(str,3); /* 20190526 */ /*Why this? 20191125 only on small schematics. slow down on big schematics */ if(xctx->instances < 150) { prepare_netlist_structs(0); if(xctx->inst[i].ptr != -1) for(j=0;j< (xctx->inst[i].ptr+ xctx->sym)->rects[PINLAYER] ; ++j) { if(j == 0) statusmsg("pinlist:", 2); if(xctx->inst[i].node && (xctx->inst[i].ptr+ xctx->sym)->rect[PINLAYER][j].prop_ptr) { my_snprintf(str, S(str), "pin:%s -> %s", get_tok_value(xctx->sym[xctx->inst[i].ptr].rect[PINLAYER][j].prop_ptr,"name",0), xctx->inst[i].node[j] ? xctx->inst[i].node[j] : "__UNCONNECTED_PIN__"); statusmsg(str,2); } } } tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g w = %.16g h = %.16g",i, xctx->inst[i].xx1, xctx->inst[i].yy1, xctx->inst[i].xx2-xctx->inst[i].xx1, xctx->inst[i].yy2-xctx->inst[i].yy1 ); statusmsg(str,1); } xctx->inst[i].sel = select_mode; if(select_mode == SELECTED) set_first_sel(ELEMENT, i, 0); if(!(fast & 2) ) { if(select_mode) { for(c=0;cgc[SELLAYER], i,c,0,0,0.0,0.0); } } else { symbol_bbox(i, &xctx->inst[i].x1, &xctx->inst[i].y1, &xctx->inst[i].x2, &xctx->inst[i].y2 ); for(c=0;cgctiled, i,c,0,0,0.0,0.0); } } } 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; } /* fast == 1: do not update status line * fast == 2: do not draw / undraw selected elements * fast == 3: 1 + 2 */ 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 & 1)) { 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); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g", i, xctx->text[i].x0, xctx->text[i].y0); statusmsg(str,1); } xctx->text[i].sel = select_mode; #if HAS_CAIRO==1 customfont = set_text_custom_font(&xctx->text[i]); #endif if(select_mode) { set_first_sel(xTEXT, i, 0); if(!(fast & 2)) draw_temp_string(xctx->gc[SELLAYER],ADD, get_text_floater(i), xctx->text[i].rot, xctx->text[i].flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0, xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); } else { if(!(fast & 2)) draw_temp_string(xctx->gctiled,NOW, get_text_floater(i), xctx->text[i].rot, xctx->text[i].flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0, xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); } #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif xctx->need_reb_sel_arr=1; } /* fast == 1: do not update status line * fast == 2: do not draw / undraw selected elements * fast == 3: 1 + 2 */ void select_box(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->rect[c][i].prop_ptr, "lock", 0), "true") && select_mode == SELECTED && !override_lock) return; if(!(fast & 1)) { my_strncpy(s,xctx->rect[c][i].prop_ptr!=NULL?xctx->rect[c][i].prop_ptr:"",S(s)); my_snprintf(str, S(str), "Info: selected box : layer=%d, n=%d properties: %s",c-4,i,s); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g w = %.16g h = %.16g", i, xctx->rect[c][i].x1, xctx->rect[c][i].y1, xctx->rect[c][i].x2-xctx->rect[c][i].x1, xctx->rect[c][i].y2-xctx->rect[c][i].y1 ); statusmsg(str,1); } if(select_mode) { if(select_mode==SELECTED) { xctx->rect[c][i].sel = select_mode; /* remember last selected graph */ if(c == GRIDLAYER && (xctx->rect[c][i].flags & 1)) xctx->graph_lastsel = i; } else { xctx->rect[c][i].sel |= select_mode; } if(!(fast & 2)) drawtemprect(xctx->gc[SELLAYER], ADD, xctx->rect[c][i].x1, xctx->rect[c][i].y1, xctx->rect[c][i].x2, xctx->rect[c][i].y2); } else { xctx->rect[c][i].sel = 0; if(!(fast & 2)) drawtemprect(xctx->gctiled, NOW, xctx->rect[c][i].x1, xctx->rect[c][i].y1, xctx->rect[c][i].x2, xctx->rect[c][i].y2); } if( xctx->rect[c][i].sel == (SELECTED1|SELECTED2|SELECTED3|SELECTED4)) xctx->rect[c][i].sel = SELECTED; if(xctx->rect[c][i].sel == SELECTED) set_first_sel(xRECT, i, c); xctx->need_reb_sel_arr=1; } /* fast == 1: do not update status line * fast == 2: do not draw / undraw selected elements * fast == 3: 1 + 2 */ 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 */ if(!(fast & 1)) { my_strncpy(s,xctx->rect[c][i].prop_ptr!=NULL?xctx->rect[c][i].prop_ptr:"",S(s)); my_snprintf(str, S(str), "Info: selected arc : layer=%d, n=%d properties: %s",c-4,i,s); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g r = %.16g a = %.16g b = %.16g", i, xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b); statusmsg(str,1); } if(select_mode) { xctx->arc[c][i].sel = select_mode; if(!(fast & 2)) drawtemparc(xctx->gc[SELLAYER], ADD, xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b); } else { xctx->arc[c][i].sel = 0; if(!(fast & 2)) drawtemparc(xctx->gctiled, NOW, xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b); } if(xctx->arc[c][i].sel == SELECTED) set_first_sel(ARC, i, c); xctx->need_reb_sel_arr=1; } 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 & 1) ) { my_strncpy(s,xctx->poly[c][i].prop_ptr!=NULL?xctx->poly[c][i].prop_ptr:"",S(s)); my_snprintf(str, S(str), "Info: selected polygon: layer=%d, n=%d properties: %s",c-4,i,s); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x0 = %.16g y0 = %.16g ...", i, xctx->poly[c][i].x[0], xctx->poly[c][i].y[0]); statusmsg(str,1); } bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); xctx->poly[c][i].sel = select_mode; if(select_mode) { if(!(fast & 2)) drawtemppolygon(xctx->gc[SELLAYER], NOW, xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, bezier); } else { if(!(fast & 2)) drawtemppolygon(xctx->gctiled, NOW, xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, bezier); } if(xctx->poly[c][i].sel == SELECTED) set_first_sel(POLYGON, i, c); xctx->need_reb_sel_arr=1; } 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 & 1) ) { my_strncpy(s,xctx->line[c][i].prop_ptr!=NULL?xctx->line[c][i].prop_ptr:"",S(s)); my_snprintf(str, S(str), "Info: selected line: layer=%d, n=%d properties: %s",c-4,i,s); statusmsg(str,3); tcleval("infowindow"); my_snprintf(str, S(str), "n=%4d x = %.16g y = %.16g w = %.16g h = %.16g", i, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2-xctx->line[c][i].x1, xctx->line[c][i].y2-xctx->line[c][i].y1 ); statusmsg(str,1); } if( ((xctx->line[c][i].sel|select_mode) == (SELECTED1|SELECTED2)) || ((xctx->line[c][i].sel == SELECTED) && select_mode) ) { xctx->line[c][i].sel = SELECTED; } else { xctx->line[c][i].sel = select_mode; } if(xctx->line[c][i].sel == SELECTED) set_first_sel(LINE, i, c); if(select_mode) { if(xctx->line[c][i].bus == -1.0) { if(!(fast & 2)) drawtempline(xctx->gc[SELLAYER], THICK, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); } else { if(!(fast & 2)) drawtempline(xctx->gc[SELLAYER], ADD, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); } } else { if(xctx->line[c][i].bus == -1.0) { if(!(fast & 2)) drawtempline(xctx->gctiled, THICK, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); } else { if(!(fast & 2)) drawtempline(xctx->gctiled, NOW, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2); } } xctx->need_reb_sel_arr=1; } /* 20160503 return type field */ Selected select_object(double mx,double my, unsigned short select_mode, int override_lock, const Selected *selptr) { Selected sel; xctx->already_selected = 0; if(!selptr) sel = find_closest_obj(mx, my, override_lock); else sel = *selptr; dbg(1, "select_object(): sel.n=%d, sel.col=%d, sel.type=%d\n", sel.n, sel.col, sel.type); switch(sel.type) { case WIRE: if(xctx->wire[sel.n].sel) xctx->already_selected = 1; 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, 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, 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, override_lock); break; case xRECT: if(xctx->rect[sel.col][sel.n].sel) xctx->already_selected = 1; select_box(sel.col,sel.n, select_mode,0, override_lock); break; case ARC: if(xctx->arc[sel.col][sel.n].sel) xctx->already_selected = 1; 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); break; default: break; } /*end switch */ 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); drawtempline(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0); if(sel.type) xctx->ui_state |= SELECTION; if(!select_mode) { rebuild_selected_array(); draw_selection(xctx->gc[SELLAYER], 0); } return sel; } /* Partial-select wire ends that land on instance pins and selected nets */ void select_attached_nets(void) { int wire, inst, j, i, rects, r, sqx, sqy; double x0, y0; Wireentry *wptr; hash_wires(); rebuild_selected_array(); for(j=0;jlastsel; ++j) { if(xctx->sel_array[j].type==ELEMENT) { inst = xctx->sel_array[j].n; if((xctx->inst[inst].ptr >= 0)) { rects = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; for(r = 0; r < rects; r++) { get_inst_pin_coord(inst, r, &x0, &y0); get_square(x0, y0, &sqx, &sqy); 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, 0); } if(xctx->wire[i].x2 == x0 && xctx->wire[i].y2 == y0) { select_wire(i,SELECTED2, 1, 0); } } } } } if(xctx->sel_array[j].type==WIRE) { wire = xctx->sel_array[j].n; if(xctx->wire[wire].sel != SELECTED) continue; for(r = 0; r < 2; r++) { if(r == 0) { x0 = xctx->wire[wire].x1; y0 = xctx->wire[wire].y1; } else { x0 = xctx->wire[wire].x2; y0 = xctx->wire[wire].y2; } get_square(x0, y0, &sqx, &sqy); for(wptr=xctx->wire_spatial_table[sqx][sqy]; wptr; wptr=wptr->next) { i = wptr->n; if(i == wire) continue; if(xctx->wire[i].x1 == x0 && xctx->wire[i].y1 == y0) { select_wire(i,SELECTED1, 1, 0); } if(xctx->wire[i].x2 == x0 && xctx->wire[i].y2 == y0) { select_wire(i,SELECTED2, 1, 0); } } } } } /* for(j=0;jlastsel; ++j) */ rebuild_selected_array(); } void select_inside(int stretch, double x1,double y1, double x2, double y2, int sel) { int c,i, tmpint; double x, y, r, a, b, xa, ya, xb, yb; /* arc */ double xx1,yy1,xx2,yy2, dtmp; xRect tmp; int select_rot = 0, select_flip = 0; #if HAS_CAIRO==1 int customfont; #endif char *estr = NULL; for(i=0;iwires; ++i) { if(sel) { 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, 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, 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, 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, 0); } } } for(i=0;itexts; ++i) { select_rot = xctx->text[i].rot; select_flip = xctx->text[i].flip; #if HAS_CAIRO==1 customfont = set_text_custom_font(&xctx->text[i]); #endif estr = my_expand(get_text_floater(i), tclgetintvar("tabstop")); text_bbox(estr, xctx->text[i].xscale, xctx->text[i].yscale, (short)select_rot, (short)select_flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0, xctx->text[i].y0, &xx1,&yy1, &xx2,&yy2, &tmpint, &dtmp); my_free(_ALLOC_ID_, &estr); #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif 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, 0): select_text(i, 0, 1, 0); } } for(i=0;iinstances; ++i) { if(RECT_INSIDE(xctx->inst[i].xx1, xctx->inst[i].yy1, xctx->inst[i].xx2, xctx->inst[i].yy2, x1,y1,x2,y2)) { xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */ if(sel) { 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)); } else { select_element(i, 0, 1, 0); } } #if 0 else { xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */ if(sel) { select_element(i, 0, 1, 0); } } #endif } for(c=0;cenable_layer[c]) continue; for(i=0;ipolygons[c]; ++i) { int k, selected_points, flag; polygon_bbox(xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, &xa, &ya, &xb, &yb); if(RECT_OUTSIDE(xa, ya, xb, yb, x1, y1, x2, y2)) continue; selected_points = 0; flag=0; for(k=0; kpoly[c][i].points; ++k) { if(xctx->poly[c][i].sel==SELECTED) xctx->poly[c][i].selected_point[k] = 1; if( POINTINSIDE(xctx->poly[c][i].x[k],xctx->poly[c][i].y[k], x1,y1,x2,y2)) { flag=1; xctx->poly[c][i].selected_point[k] = (short)sel; } if(xctx->poly[c][i].selected_point[k]) selected_points++; } if(flag) { if(selected_points==0) { 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, 0); } else if(selected_points) { /* for polygon, SELECTED1 means partial sel */ if(sel && stretch) select_polygon(c, i, SELECTED1, 1, 0); } } } for(i=0;ilines[c]; ++i) { if(sel) { 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, 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, 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, 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, 0); } } } for(i=0;iarcs[c]; ++i) { x = xctx->arc[c][i].x; y = xctx->arc[c][i].y; a = xctx->arc[c][i].a; b = xctx->arc[c][i].b; r = xctx->arc[c][i].r; xa = x + r * cos(a * XSCH_PI/180.); ya = y - r * sin(a * XSCH_PI/180.); xb = x + r * cos((a+b) * XSCH_PI/180.); yb = y - r * sin((a+b) * XSCH_PI/180.); 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, 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, 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, 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, 0); } } for(i=0;irects[c]; ++i) { if(RECT_INSIDE(xctx->rect[c][i].x1,xctx->rect[c][i].y1,xctx->rect[c][i].x2,xctx->rect[c][i].y2, x1,y1,x2,y2)) { xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */ if(sel) { select_box(c,i, SELECTED, 1, 0); } else { select_box(c,i, 0, 1, 0); } } else if(c != GRIDLAYER || !(xctx->rect[c][i].flags & 2048)){ /* no stretch on unscaled images */ if( sel && stretch && POINTINSIDE(xctx->rect[c][i].x1,xctx->rect[c][i].y1, x1,y1,x2,y2) ) { /*20070302 added stretch select */ xctx->ui_state |= SELECTION; select_box(c, i,SELECTED1,1, 0); } if( sel && stretch && POINTINSIDE(xctx->rect[c][i].x2,xctx->rect[c][i].y1, x1,y1,x2,y2) ) { xctx->ui_state |= SELECTION; select_box(c, i,SELECTED2,1, 0); } if( sel && stretch && POINTINSIDE(xctx->rect[c][i].x1,xctx->rect[c][i].y2, x1,y1,x2,y2) ) { xctx->ui_state |= SELECTION; select_box(c, i,SELECTED3,1, 0); } if( sel && stretch && POINTINSIDE(xctx->rect[c][i].x2,xctx->rect[c][i].y2, x1,y1,x2,y2) ) { xctx->ui_state |= SELECTION; select_box(c, i,SELECTED4,1, 0); } } } /* end for i */ } /* end for c */ 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); drawtempline(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0); #if 0 if(!sel) { rebuild_selected_array(); draw_selection(xctx->gc[SELLAYER], 0); } #endif } void select_touch(double x1,double y1, double x2, double y2, int sel) /*added unselect (sel param) */ { int c,i, tmpint; double x, y, r, a, b, xa, ya, xb, yb; /* arc */ double xx1,yy1,xx2,yy2, dtmp; xRect tmp; int select_rot = 0, select_flip = 0; #if HAS_CAIRO==1 int customfont; #endif char *estr = NULL; for(i=0;iwires; ++i) { double lx1, ly1, lx2, ly2; lx1 = xctx->wire[i].x1; ly1 = xctx->wire[i].y1; lx2 = xctx->wire[i].x2; 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, 0): select_wire(i,0, 1, 0); } } for(i=0;itexts; ++i) { select_rot = xctx->text[i].rot; select_flip = xctx->text[i].flip; #if HAS_CAIRO==1 customfont = set_text_custom_font(&xctx->text[i]); #endif estr = my_expand(get_text_floater(i), tclgetintvar("tabstop")); text_bbox(estr, xctx->text[i].xscale, xctx->text[i].yscale, (short)select_rot, (short)select_flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0, xctx->text[i].y0, &xx1,&yy1, &xx2,&yy2, &tmpint, &dtmp); my_free(_ALLOC_ID_, &estr); #if HAS_CAIRO==1 if(customfont) { cairo_restore(xctx->cairo_ctx); } #endif 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, 0): select_text(i, 0, 1, 0); } } for(i=0;iinstances; ++i) { if(RECT_TOUCH(xctx->inst[i].xx1, xctx->inst[i].yy1, xctx->inst[i].xx2, xctx->inst[i].yy2, x1,y1,x2,y2)) { xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */ if(sel) { 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)); } else { select_element(i, 0, 1, 0); } } } for(c=0;cenable_layer[c]) continue; for(i=0;ipolygons[c]; ++i) { int k, flag; polygon_bbox(xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, &xa, &ya, &xb, &yb); if(RECT_OUTSIDE(xa, ya, xb, yb, x1, y1, x2, y2)) continue; flag=0; for(k=0; kpoly[c][i].points; ++k) { if(xctx->poly[c][i].sel==SELECTED) xctx->poly[c][i].selected_point[k] = 1; if( POINTINSIDE(xctx->poly[c][i].x[k],xctx->poly[c][i].y[k], x1,y1,x2,y2)) { xctx->ui_state |= SELECTION; flag=1; break; } } if(flag) { sel ? select_polygon(c, i, SELECTED, 1, 0): select_polygon(c, i, 0, 1, 0); } } for(i=0;ilines[c]; ++i) { double lx1, ly1, lx2, ly2; lx1 = xctx->line[c][i].x1; ly1 = xctx->line[c][i].y1; lx2 = xctx->line[c][i].x2; 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, 0): select_line(c, i, 0, 1, 0); } } for(i=0;iarcs[c]; ++i) { x = xctx->arc[c][i].x; y = xctx->arc[c][i].y; a = xctx->arc[c][i].a; b = xctx->arc[c][i].b; r = xctx->arc[c][i].r; xa = x + r * cos(a * XSCH_PI/180.); ya = y - r * sin(a * XSCH_PI/180.); xb = x + r * cos((a+b) * XSCH_PI/180.); yb = y - r * sin((a+b) * XSCH_PI/180.); 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, 0): select_arc(c, i, 0,1, 0); } } for(i=0;irects[c]; ++i) { if(RECT_TOUCH(xctx->rect[c][i].x1,xctx->rect[c][i].y1,xctx->rect[c][i].x2,xctx->rect[c][i].y2, x1,y1,x2,y2)) { xctx->ui_state |= SELECTION; /* set xctx->ui_state to SELECTION also if unselecting by area ???? */ if(sel) { select_box(c,i, SELECTED, 1, 0); } else { select_box(c,i, 0, 1, 0); } } } /* end for i */ } /* end for c */ 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); drawtempline(xctx->gc[SELLAYER], END, 0.0, 0.0, 0.0, 0.0); #if 0 if(!sel) { rebuild_selected_array(); draw_selection(xctx->gc[SELLAYER], 0); } #endif } int floaters_from_selected_inst() { int res = 0, first = 1; int i, n, t; int instrot, instflip; double instx0, insty0; xSymbol *sym; for(n = 0; n < xctx->lastsel; ++n) { i = xctx->sel_array[n].n; if(xctx->sel_array[n].type == ELEMENT) { if(xctx->inst[i].ptr < 0) continue; if(xctx->inst[i].flags & HIDE_SYMBOL_TEXTS) continue; sym = xctx->sym + xctx->inst[i].ptr; if( sym->type && (IS_LABEL_SH_OR_PIN(sym->type) || !strcmp(sym->type, "probe") )) continue; instx0 = xctx->inst[i].x0; insty0 = xctx->inst[i].y0; instrot = xctx->inst[i].rot; instflip = xctx->inst[i].flip; if(first) { xctx->push_undo(); set_modify(1); first = 0; } 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; int txtrot, txtflip; int rot, flip; double x0, y0; xText *symtxt; symtxt = &sym->text[t]; if(strstr(symtxt->txt_ptr, ":net_name")) continue; txtx0 = symtxt->x0; txty0 = symtxt->y0; txtrot = symtxt->rot; txtflip = symtxt->flip; rot = (txtrot + ( (instflip && (txtrot & 1) ) ? instrot+2 : instrot) ) & 0x3; flip = txtflip ^ instflip; ROTATION(instrot, instflip, 0.0, 0.0, txtx0, txty0, x0, y0); x0 += instx0; y0 += insty0; create_text(0, x0, y0, rot, flip, symtxt->txt_ptr, subst_token(symtxt->prop_ptr, "name", xctx->inst[i].instname), symtxt->xscale, symtxt->yscale); xctx->text[xctx->texts - 1].sel = SELECTED; set_text_flags(&xctx->text[xctx->texts - 1]); dbg(1, "instance %d: symtext %d: %s\n", i, t, symtxt->txt_ptr); } } } xctx->need_reb_sel_arr=1; rebuild_selected_array(); draw(); return res; } void select_all(void) { int c,i; for(i=0;iwires; ++i) { select_wire(i,SELECTED, 1, 0); } for(i=0;itexts; ++i) { select_text(i, SELECTED, 1, 0); } for(i=0;iinstances; ++i) { 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, 0); } for(i=0;ilines[c]; ++i) { select_line(c, i, SELECTED, 1, 0); } for(i=0;iarcs[c]; ++i) { select_arc(c, i, SELECTED, 1, 0); } for(i=0;irects[c]; ++i) { 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); 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); rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ }