From bef19b70576449c5fb21400d3961cb889ece8465 Mon Sep 17 00:00:00 2001 From: Ananth Date: Mon, 10 Feb 2025 13:42:28 -0700 Subject: [PATCH 01/46] refactored : handle_motion_notify for readability --- src/callback.c | 234 +++++++++++++++++++++++++------------------------ 1 file changed, 120 insertions(+), 114 deletions(-) diff --git a/src/callback.c b/src/callback.c index 3b976998..ef49c1bf 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2313,6 +2313,125 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke } #endif +void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, + double mx, double my, int aux, int draw_xhair, char *str, int enable_stretch) +{ + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(draw_xhair) { + draw_crosshair(1, state); /* when moving mouse: first action is delete crosshair, will be drawn later */ + } + /* pan schematic */ + if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); + + if(xctx->semaphore >= 2) { + if(draw_xhair) { + draw_crosshair(2, state); /* locked UI: draw new crosshair and break out */ + } + return; + } + + /* update status bar messages */ + if(xctx->ui_state) { + if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", + xctx->mousex_snap, xctx->mousey_snap, + xctx->lastsel , + xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save + ); + statusmsg(str,1); + } + } + + /* determine direction of a rectangle selection (or unselection with ALT key) */ + if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { + /* Unselect by area : determine direction */ + if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,0); + /* select by area : determine direction */ + } else if(state & Button1Mask) { + if(mx >= xctx->mx_save) xctx->nl_dir = 0; + else xctx->nl_dir = 1; + select_rect(enable_stretch, RUBBER,1); + } + } + /* draw objects being moved */ + if(xctx->ui_state & STARTMOVE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + move_objects(RUBBER,0,0,0); + } + + /* draw objects being copied */ + if(xctx->ui_state & STARTCOPY) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + copy_objects(RUBBER); + } + + /* draw moving objects being inserted, wires, arcs, lines, rectangles, polygons or zoom box */ + redraw_w_a_l_r_p_z_rubbers(0); + + /* start of a mouse area select. Button1 pressed. No shift pressed + * Do not start an area select if user is dragging a polygon/bezier point */ + if(!(xctx->ui_state & STARTPOLYGON) && (state&Button1Mask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & STARTPAN) && !(SET_MODMASK) && !xctx->shape_point_selected && + !(state & ShiftMask) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) + { + if(mx != xctx->mx_save || my != xctx->my_save) { + xctx->mouse_moved = 1; + if(!xctx->drag_elements) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + xctx->onetime=1; + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(xctx->onetime) { + unselect_all(1); /* 20171026 avoid multiple calls of unselect_all() */ + xctx->onetime=0; + } + xctx->ui_state|=STARTSELECT; /* set it again cause unselect_all(1) clears it... */ + } + } + } + } + /* Unselect by area */ + if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && + !(state & ShiftMask) && + !(xctx->ui_state & STARTPAN) && + !xctx->shape_point_selected && + !(xctx->ui_state & STARTSELECT) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ + select_rect(enable_stretch, START,0); + } + /* Select by area. Shift pressed */ + else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !xctx->shape_point_selected && + !xctx->drag_elements && !(xctx->ui_state & STARTPAN) ) { + if(mx != xctx->mx_save || my != xctx->my_save) { + if( !(xctx->ui_state & STARTSELECT)) { + select_rect(enable_stretch, START,1); + } + if(abs(mx-xctx->mx_save) > 8 || + abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ + if(!xctx->already_selected) { + select_object(X_TO_XSCHEM(xctx->mx_save), + Y_TO_XSCHEM(xctx->my_save), 0, 0, NULL); /* remove near obj if dragging */ + } + rebuild_selected_array(); + } + } + } + if(draw_xhair) { + draw_crosshair(2, state); /* what = 2(draw) */ + } +} + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -2508,120 +2627,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case MotionNotify: - if( waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(draw_xhair) { - draw_crosshair(1, state); /* when moving mouse: first action is delete crosshair, will be drawn later */ - } - /* pan schematic */ - if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); - - if(xctx->semaphore >= 2) { - if(draw_xhair) { - draw_crosshair(2, state); /* locked UI: draw new crosshair and break out */ - } - break; - } - - /* update status bar messages */ - if(xctx->ui_state) { - if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", - xctx->mousex_snap, xctx->mousey_snap, - xctx->lastsel , - xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save - ); - statusmsg(str,1); - } - } - - /* determine direction of a rectangle selection (or unselection with ALT key) */ - if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { - /* Unselect by area : determine direction */ - if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { - if(mx >= xctx->mx_save) xctx->nl_dir = 0; - else xctx->nl_dir = 1; - select_rect(enable_stretch, RUBBER,0); - /* select by area : determine direction */ - } else if(state & Button1Mask) { - if(mx >= xctx->mx_save) xctx->nl_dir = 0; - else xctx->nl_dir = 1; - select_rect(enable_stretch, RUBBER,1); - } - } - /* draw objects being moved */ - if(xctx->ui_state & STARTMOVE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - move_objects(RUBBER,0,0,0); - } - - /* draw objects being copied */ - if(xctx->ui_state & STARTCOPY) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - copy_objects(RUBBER); - } - - /* draw moving objects being inserted, wires, arcs, lines, rectangles, polygons or zoom box */ - redraw_w_a_l_r_p_z_rubbers(0); - - /* start of a mouse area select. Button1 pressed. No shift pressed - * Do not start an area select if user is dragging a polygon/bezier point */ - if(!(xctx->ui_state & STARTPOLYGON) && (state&Button1Mask) && !(xctx->ui_state & STARTWIRE) && - !(xctx->ui_state & STARTPAN) && !(SET_MODMASK) && !xctx->shape_point_selected && - !(state & ShiftMask) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) - { - if(mx != xctx->mx_save || my != xctx->my_save) { - xctx->mouse_moved = 1; - if(!xctx->drag_elements) { - if( !(xctx->ui_state & STARTSELECT)) { - select_rect(enable_stretch, START,1); - xctx->onetime=1; - } - if(abs(mx-xctx->mx_save) > 8 || - abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ - if(xctx->onetime) { - unselect_all(1); /* 20171026 avoid multiple calls of unselect_all() */ - xctx->onetime=0; - } - xctx->ui_state|=STARTSELECT; /* set it again cause unselect_all(1) clears it... */ - } - } - } - } - /* Unselect by area */ - if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && - !(state & ShiftMask) && - !(xctx->ui_state & STARTPAN) && - !xctx->shape_point_selected && - !(xctx->ui_state & STARTSELECT) && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ - select_rect(enable_stretch, START,0); - } - /* Select by area. Shift pressed */ - else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !xctx->shape_point_selected && - !xctx->drag_elements && !(xctx->ui_state & STARTPAN) ) { - if(mx != xctx->mx_save || my != xctx->my_save) { - if( !(xctx->ui_state & STARTSELECT)) { - select_rect(enable_stretch, START,1); - } - if(abs(mx-xctx->mx_save) > 8 || - abs(my-xctx->my_save) > 8 ) { /* set reasonable threshold before unsel */ - if(!xctx->already_selected) { - select_object(X_TO_XSCHEM(xctx->mx_save), - Y_TO_XSCHEM(xctx->my_save), 0, 0, NULL); /* remove near obj if dragging */ - } - rebuild_selected_array(); - } - } - } - if(draw_xhair) { - draw_crosshair(2, state); /* what = 2(draw) */ - } + handle_motion_notify(event, key, state, rstate, button, mx, my, aux, draw_xhair, str, enable_stretch); break; case KeyRelease: From 04e7300f48fe8518ada0831846ffe338d699c8d5 Mon Sep 17 00:00:00 2001 From: Ananth Date: Mon, 10 Feb 2025 13:52:57 -0700 Subject: [PATCH 02/46] correct type for mx,my in handle_motion_notify; added handle_key_press --- src/callback.c | 2917 ++++++++++++++++++++++++------------------------ 1 file changed, 1462 insertions(+), 1455 deletions(-) diff --git a/src/callback.c b/src/callback.c index ef49c1bf..a61c6329 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2314,7 +2314,7 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke #endif void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, - double mx, double my, int aux, int draw_xhair, char *str, int enable_stretch) + int mx, int my, int aux, int draw_xhair, char *str, int enable_stretch) { if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); @@ -2432,6 +2432,1465 @@ void handle_motion_notify(int event, KeySym key, int state, int rstate, int butt } } +void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, + int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, char *str ) +{ + if(key==' ') { + if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + + } else if(xctx->ui_state & STARTLINE) { + new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + xctx->manhattan_lines++; + xctx->manhattan_lines %=3; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } else { + if(xctx->semaphore<2) { + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ + } + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + return; + } + if(key == '_' ) /* toggle change line width */ + { + if(!tclgetboolvar("change_lw")) { + tcleval("alert_ { enabling change line width} {}"); + tclsetvar("change_lw","1"); + } + else { + tcleval("alert_ { disabling change line width} {}"); + tclsetvar("change_lw","0"); + } + return; + } + if(key == 'b' && rstate==ControlMask) /* toggle show text in symbol */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->sym_txt =!xctx->sym_txt; + if(xctx->sym_txt) { + /* tcleval("alert_ { enabling text in symbol} {}"); */ + tclsetvar("sym_txt","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling text in symbol} {}"); */ + tclsetvar("sym_txt","0"); + draw(); + } + return; + } + if(key == '%' ) /* toggle draw grid */ + { + int dr_gr; + dr_gr = tclgetboolvar("draw_grid"); + dr_gr =!dr_gr; + if(dr_gr) { + /* tcleval("alert_ { enabling draw grid} {}"); */ + tclsetvar("draw_grid","1"); + draw(); + } + else { + /* tcleval("alert_ { disabling draw grid} {}"); */ + tclsetvar("draw_grid","0"); + draw(); + } + return; + } + if(key == 'j' && rstate==0 ) /* print list of highlight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(1); + return; + } + if(key == 'j' && rstate==ControlMask) /* create ipins from highlight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(0); + return; + } + if(key == 'j' && EQUAL_MODMASK) /* create labels without i prefix from hilight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(4); + return; + } + if(key == 'J' && SET_MODMASK ) /* create labels with i prefix from hilight nets */ + { + if(xctx->semaphore >= 2) return; + print_hilight_net(2); + return; + } + if(key == 'h' && rstate==ControlMask ) /* go to http link */ + { + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); + xctx->semaphore = savesem; + return; + } + if(key == 'h' && EQUAL_MODMASK) /* create symbol pins from schematic pins 20171208 */ + { + tcleval("schpins_to_sympins"); + return; + } + if(key == 'h' && rstate == 0) { + /* horizontally constrained drag 20171023 */ + if ( xctx->constr_mv == 1 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 1" ); + xctx->constr_mv = 1; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + if(key=='H' && rstate == 0) { /* attach labels to selected instances */ + attach_labels_to_inst(1); + return; + } + if (key == 'H' && rstate == ControlMask) { /* create schematic and symbol from selected components */ + make_schematic_symbol_from_sel(); + return; + } + if(key == 'v' && rstate==0) { + /* vertically constrained drag 20171023 */ + if ( xctx->constr_mv == 2 ) { + tcleval("set constr_mv 0" ); + xctx->constr_mv = 0; + } else { + tcleval("set constr_mv 2" ); + xctx->constr_mv = 2; + } + if(xctx->ui_state & STARTWIRE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + if(xctx->ui_state & STARTLINE) { + if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; + if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; + new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); + } + return; + } + if(key == 'j' && SET_MODMASK && (state & ControlMask) ) /* print list of highlight net with label expansion */ + { + print_hilight_net(3); + return; + } + if(key == 'J' && rstate == 0) { + create_plot_cmd(); + return; + } + if(key == '$' && rstate == 0 ) /* toggle pixmap saving */ + { + xctx->draw_pixmap =!xctx->draw_pixmap; + if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); + else tcleval("alert_ { disabling draw pixmap} {}"); + return; + } + if(key == '$' && (state &ControlMask) ) /* toggle window drawing */ + { + xctx->draw_window =!xctx->draw_window; + if(xctx->draw_window) { + tcleval("alert_ { enabling draw window} {}"); + tclsetvar("draw_window","1"); + } else { + tcleval("alert_ { disabling draw window} {}"); + tclsetvar("draw_window","0"); + } + return; + } + if(key == '=' && (state &ControlMask)) /* toggle fill rectangles */ + { + int x; + xctx->fill_pattern++; + if(xctx->fill_pattern==3) xctx->fill_pattern=0; + + if(xctx->fill_pattern==1) { + tcleval("alert_ { Stippled pattern fill} {}"); + for(x=0;xfill_type[x]==1) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); + else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); + } + } + else if(xctx->fill_pattern==2) { + tcleval("alert_ { solid pattern fill} {}"); + for(x=0;xgcstipple[x],FillSolid); + } + else { + tcleval("alert_ { No pattern fill} {}"); + for(x=0;xgcstipple[x],FillStippled); + } + + draw(); + return; + } + if(key == '+' && state & ControlMask) /* change line width */ + { + xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + return; + } + + if(key == '-' && state & ControlMask) /* change line width */ + { + xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); + if(xctx->lw < 0.0) xctx->lw = 0.0; + change_linewidth(xctx->lw); + tclsetboolvar("change_lw", 0); + draw(); + return; + } + if(key == 'X' && rstate == 0) /* highlight discrepanciens between selected instance pin and net names */ + { + hilight_net_pin_mismatches(); + return; + } + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(xctx->semaphore >= 2) return; + if(infix_interface) { + snapped_wire(c_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTSNAPWIRE; + } + return; + } + if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ + { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return; + + if(infix_interface) { + start_wire(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTWIRE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTWIRE; + } + return; + } + if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ + new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); + return; + } + if(key == XK_Escape) /* abort & redraw */ + { + if(xctx->semaphore < 2) { + abort_operation(); + } + /* stuff that can be done reentrantly ... */ + tclsetvar("tclstop", "1"); /* stop simulation if any running */ + return; + } + if(key=='z' && rstate == 0 && + !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) /* zoom box */ + { + dbg(1, "callback(): zoom_rectangle call\n"); + zoom_rectangle(START);return; + } + if(key=='Z' && rstate == 0) /* zoom in */ + { + view_zoom(0.0); return; + } + if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ + { + xctx->push_undo(); + unselect_all(1); + storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, + xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); + xctx->need_reb_sel_arr=1; + rebuild_selected_array(); + move_objects(START,0,0,0); + xctx->ui_state |= START_SYMPIN; + return; + } + if(key=='p' && !(xctx->ui_state & STARTPOLYGON) && rstate==0) /* start polygon */ + { + if(xctx->semaphore >= 2) return; + dbg(1, "callback(): start polygon\n"); + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTPOLYGON; + } + return; + } + if(key=='P' && rstate == 0) /* pan, other way to. */ + { + xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; + xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key=='5' && rstate == 0) { /* 20110112 display only probes */ + xctx->only_probes = !xctx->only_probes; + tclsetboolvar("only_probes", xctx->only_probes); + toggle_only_probes(); + return; + } /* /20110112 */ + if(key<='9' && key >='0' && state==ControlMask) /* choose layer */ + { + char n[30]; + xctx->rectcolor = (int)key - '0'+4; + my_snprintf(n, S(n), "%d", xctx->rectcolor); + tclvareval("xschem set rectcolor ", n, NULL); + + if(has_x) { + if(!strcmp(win_path, ".drw")) { + tclvareval("reconfigure_layers_button {}", NULL); + } else { + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); + } + } + dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); + return; + } + if(key==XK_Delete && (xctx->ui_state & SELECTION) ) /* delete selection */ + { + if(xctx->semaphore >= 2) return; + delete(1/* to_push_undo */);return; + } + if(key==XK_Right && state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->semaphore = 0; + tcleval("next_tab"); + xctx->semaphore = save; + return; + } + if(key==XK_Left && state == ControlMask) { + int save = xctx->semaphore; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->semaphore = 0; + tcleval("prev_tab"); + xctx->semaphore = save; + return; + } + if(key==XK_Right && !(state & ControlMask)) /* left */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->xorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Left && !(state & ControlMask)) /* right */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->xorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Down) /* down */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->yorigin+=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key==XK_Up) /* up */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->yorigin-=-CADMOVESTEP*xctx->zoom; + draw(); + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + if(key=='w' && rstate == ControlMask) /* close current schematic */ + { + int save_sem; + if(xctx->semaphore >= 2) return; + save_sem = xctx->semaphore; + tcleval("xschem exit"); + xctx->semaphore = save_sem; + return; + } + /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ + if(key == 'T' && rstate == 0) { + toggle_ignore(); + } + if(key=='t' && rstate == 0) /* place text */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(xctx->semaphore >= 2) return; + xctx->last_command = 0; + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ + xctx->mousey_snap = xctx->my_double_save; + xctx->mousex_snap = xctx->mx_double_save; + move_objects(START,0,0,0); + xctx->ui_state |= PLACE_TEXT; + } + return; + } + if(key=='t' && (rstate & ControlMask)) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ + { + dbg(1, "callback(): start rect\n"); + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTRECT; + } + return; + } + if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ + { + xctx->netlist_type++; if(xctx->netlist_type==6) xctx->netlist_type=1; + set_tcl_netlist_type(); + draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ + return; + } + if(key=='s' && rstate == 0 ) /* simulate */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + return; + } + if(key=='s' && rstate == ControlMask ) /* save 20121201 */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + /* check if unnamed schematic, use saveas in this case */ + if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { + saveas(NULL, SCHEMATIC); + } else { + save(1, 0); + } + return; + } + if(key=='s' && SET_MODMASK && (state & ControlMask) ) /* save as symbol */ + { + if(xctx->semaphore >= 2) return; + saveas(NULL, SYMBOL); + return; + } + if(key=='S' && rstate == ControlMask) /* save as schematic */ + { + if(xctx->semaphore >= 2) return; + saveas(NULL, SCHEMATIC); + return; + } + if(key=='e' && rstate == 0) /* descend to schematic */ + { + if(xctx->semaphore >= 2) return; + descend_schematic(0, 1, 1, 1);return; + } + if(key=='e' && EQUAL_MODMASK) /* edit schematic in new window */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + /* schematic_in_new_window(0, 1, 0); */ + tcleval("open_sub_schematic"); + xctx->semaphore = save; + return; + } + + if(key=='E' && EQUAL_MODMASK) /* edit schematic in new window - new xschem process */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + schematic_in_new_window(1, 1, 0); + xctx->semaphore = save; + return; + } + + if(key=='i' && EQUAL_MODMASK) /* edit symbol in new window */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(0); + xctx->semaphore = save; + return; + } + + if(key=='I' && EQUAL_MODMASK) /* edit symbol in new window - new xschem process */ + { + int save = xctx->semaphore; + xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ + symbol_in_new_window(1); + xctx->semaphore = save; + return; + } + + + if( (key=='e' && rstate == ControlMask) || (key==XK_BackSpace)) /* back */ + { + if(xctx->semaphore >= 2) return; + go_back(1);return; + } + + if(key=='a' && rstate == 0) /* make symbol */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {do you want to make symbol view ?}"); + if(strcmp(tclresult(),"ok")==0) + { + save_schematic(xctx->sch[xctx->currsch], 0); + make_symbol(); + } + return; + } + if(key=='a' && rstate == ControlMask) /* select all */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + select_all(); + return; + } + if(key=='y' && rstate == 0) /* toggle stretching */ + { + enable_stretch = !enable_stretch; + tclsetboolvar("enable_stretch", enable_stretch); + return; + } + if(key=='x' && EQUAL_MODMASK) /* toggle draw crosshair at mouse pos */ + { + if(tclgetboolvar("draw_crosshair")) { + tclsetvar("draw_crosshair", "0"); + } else { + tclsetvar("draw_crosshair", "1"); + } + draw(); + } + if(key=='x' && rstate == ControlMask) /* cut selection into clipboard */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + delete(1/* to_push_undo */); + } + return; + } + if(key=='c' && rstate == ControlMask) /* copy selection into clipboard */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel) { /* 20071203 check if something selected */ + save_selection(2); + } + return; + } + if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTARC; + } + return; + } + if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + xctx->last_command = 0; + new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCIRCLE; + } + return; + } + if(key=='O' && rstate == ControlMask ) /* load most recent tile */ + { + tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); + return; + } + if(key=='O' && rstate == 0) /* toggle light/dark colorscheme 20171113 */ + { + int d_c; + d_c = tclgetboolvar("dark_colorscheme"); + d_c = !d_c; + tclsetboolvar("dark_colorscheme", d_c); + tclsetdoublevar("dim_value", 0.0); + tclsetdoublevar("dim_bg", 0.0); + build_colors(0.0, 0.0); + draw(); + return; + } + if(key=='v' && rstate == ControlMask) /* paste from clipboard */ + { + if(xctx->semaphore >= 2) return; + merge_file(2,".sch"); + return; + } + if(key=='Q' && rstate == ControlMask ) /* view attributes */ + { + edit_property(2);return; + } + if(key=='q' && rstate==ControlMask) /* quit xschem */ + { + if(xctx->semaphore >= 2) return; + /* must be set to zero, otherwise switch_tab/switch_win does not proceed + * and these are necessary when closing tabs/windows */ + xctx->semaphore = 0; + tcleval("quit_xschem"); + return; + } + if(key=='q' && rstate==0) /* edit attributes */ + { + if(xctx->semaphore >= 2) return; + edit_property(0); + return; + } + if(key=='q' && EQUAL_MODMASK) /* edit .sch file (DANGER!!) */ + { + if(xctx->semaphore >= 2) return; + rebuild_selected_array(); + if(xctx->lastsel==0 ) { + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + tcleval(str); + } + else if(xctx->sel_array[0].type==ELEMENT) { + my_snprintf(str, S(str), "edit_file {%s}", + abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); + tcleval(str); + + } + return; + } + #if defined(__unix__) && HAS_CAIRO==1 + if(key == XK_Print) { + xctx->ui_state |= GRABSCREEN; + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); + return; + } + #endif + if(key=='Q' && rstate == 0) /* edit attributes in editor */ + { + if(xctx->semaphore >= 2) return; + edit_property(1);return; + } + if(key=='i' && rstate==0) /* descend to symbol */ + { + if(xctx->semaphore >= 2) return; + descend_symbol();return; + } + if((key==XK_Insert && state == ShiftMask) || (key == 'i' && rstate == ControlMask)) /* insert sym */ + { + tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); + return; + } + if((key==XK_Insert) || (key == 'I' && rstate == 0) ) /* insert sym */ + { + if(xctx->semaphore >= 2) return; + start_place_symbol(); + + return; + } + if(key=='s' && SET_MODMASK) /* reload */ + { + if(xctx->semaphore >= 2) return; + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Are you sure you want to reload from disk?}"); + if(strcmp(tclresult(),"ok")==0) { + char filename[PATH_MAX]; + unselect_all(1); + remove_symbols(); + my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); + load_schematic(1, filename, 1, 1); + draw(); + } + return; + } + if(key=='o' && rstate == ControlMask) /* load */ + { + if(xctx->semaphore >= 2) return; + ask_new_file(); + return; + } + if(key=='S' && rstate == 0) /* change element order */ + { + if(xctx->semaphore >= 2) return; + change_elem_order(-1); + return; + } + if(key=='k' && EQUAL_MODMASK) /* select whole net (all attached wires/labels/pins) */ + { + select_hilight_net(); + return; + } + if(key=='k' && rstate==ControlMask) /* unhilight net */ + { + if(xctx->semaphore >= 2) return; + unhilight_net(); + return; + } + if(key=='K' && rstate == ControlMask) /* hilight net drilling thru elements */ + /* with 'propag=' prop set on pins */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=1; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + return; + } + if(key=='k' && rstate==0) /* hilight net */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=0; + hilight_net(0); + redraw_hilights(0); + /* draw_hilight_net(1); */ + return; + } + if(key=='K' && rstate == 0) /* delete hilighted nets */ + { + if(xctx->semaphore >= 2) return; + xctx->enable_drill=0; + clear_all_hilights(); + /* undraw_hilight_net(1); */ + draw(); + return; + } + if(key=='g' && EQUAL_MODMASK) { /* highlight net and send to viewer */ + int tool = 0; + int exists = 0; + char *tool_name = NULL; + char str[200]; + + if(xctx->semaphore >= 2) return; + tcleval("winfo exists .graphdialog"); + if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; + else if(xctx->graph_lastsel >=0 && + xctx->rects[GRIDLAYER] > xctx->graph_lastsel && + xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { + tool = XSCHEM_GRAPH; + } + tcleval("info exists sim"); + if(tclresult()[0] == '1') exists = 1; + xctx->enable_drill = 0; + if(exists) { + if(!tool) { + tool = tclgetintvar("sim(spicewave,default)"); + my_snprintf(str, S(str), "sim(spicewave,%d,name)", tool); + my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); + dbg(1,"callback(): tool_name=%s\n", tool_name); + if(strstr(tool_name, "Gaw")) tool=GAW; + else if(strstr(tool_name, "Bespice")) tool=BESPICE; + my_free(_ALLOC_ID_, &tool_name); + } + } + if(tool) { + hilight_net(tool); + redraw_hilights(0); + } + Tcl_ResetResult(interp); + return; + } + if(key=='g' && rstate==0) /* half snap factor */ + { + set_snap(c_snap / 2.0); + change_linewidth(-1.); + draw(); + return; + } + if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ + { + my_snprintf(str, S(str), + "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", + CADSNAP, c_snap, c_snap); + tcleval(str); + return; + } + if(key=='G' && rstate == 0) /* double snap factor */ + { + set_snap(c_snap * 2.0); + change_linewidth(-1.); + draw(); + return; + } + if(key=='*' && EQUAL_MODMASK) /* svg print , 20121108 */ + { + if(xctx->semaphore >= 2) return; + svg_draw(); + return; + } + if(key=='*' && rstate == 0 ) /* postscript print */ + { + if(xctx->semaphore >= 2) return; + ps_draw(7, 0, 0); + return; + } + if(key=='*' && rstate == ControlMask) /* xpm print */ + { + if(xctx->semaphore >= 2) return; + print_image(); + return; + } + if(key=='u' && EQUAL_MODMASK) /* align to grid */ + { + if(xctx->semaphore >= 2) return; + xctx->push_undo(); + round_schematic_to_grid(c_snap); + set_modify(1); + if(tclgetboolvar("autotrim_wires")) trim_wires(); + xctx->prep_hash_inst=0; + xctx->prep_hash_wires=0; + xctx->prep_net_structs=0; + xctx->prep_hi_structs=0; + + draw(); + return; + } + if(0 && (key=='u') && rstate==ControlMask) /* testmode */ + { + static int x = 0; + + if(x == 0) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } else if(x == 1) { + int i; + XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, + xctx->areaw, xctx->areah); + XFlush(display); + sleep_ms(400); + for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { + XDrawLine(display, xctx->window, xctx->gctiled, + i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); + XFlush(display); + sleep_ms(4); + } + } + x++; + x %= 2; + return; + } + if(key=='u' && rstate==0) /* undo */ + { + if(xctx->semaphore >= 2) return; + xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ + draw(); + return; + } + if(key=='U' && rstate == 0) /* redo */ + { + if(xctx->semaphore >= 2) return; + xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ + draw(); + return; + } + if(key=='&') /* check wire connectivity */ + { + if(xctx->semaphore >= 2) return; + xctx->push_undo(); + trim_wires(); + draw(); + return; + } + if(key=='l' && rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ + if(xctx->semaphore >= 2) return; + create_sch_from_sym(); + return; + } + if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ + { + int prev_state = xctx->ui_state; + if(xctx->semaphore >= 2) return; + if(infix_interface) { + start_line(xctx->mousex_snap, xctx->mousey_snap); + if(prev_state == STARTLINE) { + tcleval("set constr_mv 0" ); + xctx->constr_mv=0; + } + } else { + xctx->last_command = 0; + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTLINE; + } + return; + } + if(key=='l' && EQUAL_MODMASK) { /* add pin label*/ + place_net_label(1); + return; + } + if(key >= '0' && key <= '4' && state == 0) { /* toggle pin logic level */ + if(xctx->semaphore >= 2) return; + if(key == '4') logic_set(-1, 1, NULL); + else logic_set((int)key - '0', 1, NULL); + return; + } + if(key=='L' && EQUAL_MODMASK ) { /* add pin label*/ + place_net_label(0); + return; + } + if(key=='F' && rstate == 0) /* flip */ + { + if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='V' && rstate == 0) /* vertical flip */ + { + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE); + copy_objects(ROTATE); + copy_objects(FLIP); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(FLIP,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='v' && EQUAL_MODMASK) /* vertical flip objects around their anchor points */ + { + if(xctx->ui_state & STARTMOVE) { + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + } + else if(xctx->ui_state & STARTCOPY) { + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(ROTATE|ROTATELOCAL); + copy_objects(FLIP|ROTATELOCAL); + } + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + + if(key=='\\' && state==0) /* fullscreen */ + { + + dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); + toggle_fullscreen(win_path); + return; + } + if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ + { + if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(FLIP|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + if(key=='R' && rstate == 0) /* rotate */ + { + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE,0,0,0); + move_objects(END,0,0,0); + } + + return; + } + if(key=='r' && EQUAL_MODMASK) /* rotate objects around their anchor points 20171208 */ + { + if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); + else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); + else { + rebuild_selected_array(); + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + move_objects(ROTATE|ROTATELOCAL,0,0,0); + move_objects(END,0,0,0); + } + return; + } + /* Move selection */ + if(key=='m' && rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + /* Move selection adding wires to moved pins */ + if(((key == 'M' && rstate == 0) || (key == 'm' && EQUAL_MODMASK)) && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + /* move selection stretching attached nets */ + if(key=='m' && rstate == ControlMask && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + + /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ + if(key=='M' && rstate == ControlMask && + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + move_objects(START,0,0,0); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTMOVE; + } + return; + } + + if(key=='c' && EQUAL_MODMASK && /* duplicate selection */ + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(xctx->semaphore >= 2) return; + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + return; + } + + if(key=='c' && rstate==0 && /* duplicate selection */ + !(xctx->ui_state & (STARTMOVE | STARTCOPY))) + { + if(xctx->semaphore >= 2) return; + if(infix_interface) { + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + copy_objects(START); + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTCOPY; + } + return; + } + if(key=='n' && rstate == ControlMask) /* clear schematic */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem clear SCHEMATIC"); + return; + } + if(key=='N' && rstate == ControlMask ) /* clear symbol */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem clear SYMBOL"); + return; + } + if(key=='n' && rstate==0) /* hierarchical netlist */ + { + if(xctx->semaphore >= 2) return; + tcleval("xschem netlist -erc"); + return; + } + if(key=='N' && rstate == 0) /* current level only netlist */ + { + int err = 0; + yyparse_error = 0; + if(xctx->semaphore >= 2) return; + unselect_all(1); + if( set_netlist_dir(0, NULL) ) { + dbg(1, "callback(): -------------\n"); + if(xctx->netlist_type == CAD_SPICE_NETLIST) + err = global_spice_netlist(0, 1); + else if(xctx->netlist_type == CAD_VHDL_NETLIST) + err = global_vhdl_netlist(0, 1); + else if(xctx->netlist_type == CAD_VERILOG_NETLIST) + err = global_verilog_netlist(0, 1); + else if(xctx->netlist_type == CAD_TEDAX_NETLIST) + err = global_tedax_netlist(0, 1); + else + tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " + "-message {Please Set netlisting mode (Options menu)}"); + dbg(1, "callback(): -------------\n"); + } + else { + if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); + else dbg(0, "Can not write into the netlist directory. Please check"); + err = 1; + } + if(err) { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); + } + } else { + if(has_x) { + tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); + tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); + } + } + + return; + } + if(key=='A' && rstate == ControlMask) /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='A' && rstate == 0) /* toggle show netlist */ + { + int net_s; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + net_s = tclgetboolvar("netlist_show"); + net_s = !net_s; + if(net_s) { + tcleval("alert_ { enabling show netlist window} {}"); + tclsetvar("netlist_show","1"); + } + else { + tcleval("alert_ { disabling show netlist window } {}"); + tclsetvar("netlist_show","0"); + } + return; + } + if(key=='>') { + if(xctx->semaphore >= 2) return; + if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; + draw(); + return; + } + if(key=='<') { + if(xctx->semaphore >= 2) return; + if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; + draw(); + return; + } + if(key==':') /* toggle flat netlist (only spice) */ + { + if(!tclgetboolvar("flat_netlist")) { + tcleval("alert_ { enabling flat netlist} {}"); + tclsetvar("flat_netlist","1"); + } + else { + tcleval("alert_ { set hierarchical netlist } {}"); + tclsetvar("flat_netlist","0"); + } + return; + } + if(key=='B' && rstate == ControlMask) /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + return; + } + if(key=='B' && rstate == 0) /* edit schematic header/license */ + { + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("update_schematic_header"); + } + if(key=='b' && rstate==0) /* merge schematic */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ + return; + } + if(key=='b' && EQUAL_MODMASK) /* hide/show instance details */ + { + if(xctx->semaphore >= 2) return; + xctx->hide_symbols++; + if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; + tclsetintvar("hide_symbols", xctx->hide_symbols); + draw(); + return; + } + if(key=='d' && rstate == 0) /* unselect object under the mouse */ + { + if(infix_interface) { + unselect_at_mouse_pos(mx, my); + } else { + xctx->ui_state |= (MENUSTART | DESEL_CLICK); + xctx->ui_state2 = MENUSTARTDESEL; + } + return; + } + if(key=='D' && rstate == 0) /* unselect by area */ + { + if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { + if(infix_interface) { + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTDESEL; + } + } + return; + } + if(key=='d' && rstate == ControlMask) /* delete files */ + { + if(xctx->semaphore >= 2) return; + delete_files(); + return; + } + if(key=='x' && rstate == 0 ) /* new cad session */ + { + new_xschem_process(NULL ,0); + return; + } + if((key=='#') && !(state & ControlMask) ) + { + check_unique_names(0); + return; + } + if((key=='#') && (state & ControlMask) ) + { + check_unique_names(1); + return; + } + if( 0 && (key==';') && (state & ControlMask) ) /* testmode */ + { + return; + } + if(0 && key=='~' && (state & ControlMask)) { /* testmode */ + return; + } + if(0 && key=='|' && !(state & ControlMask)) { /* testmode */ + return; + } + if(0 && key=='|' && (state & ControlMask)) /* testmode */ + { + return; + } + + if(key=='f' && rstate == ControlMask) /* search */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("property_search"); + return; + } + if(key=='F' && rstate == ControlMask ) /* full zoom selection */ + { + if(xctx->ui_state == SELECTION) { + zoom_full(1, 1, 3, 0.97); + } + return; + } + if(key=='f' && rstate == 0 ) /* full zoom */ + { + int flags = 1; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + if(tclgetboolvar("zoom_full_center")) flags |= 2; + zoom_full(1, 0, flags, 0.97); + return; + } + if((key=='z' && rstate==ControlMask)) /* zoom out */ + { + view_unzoom(0.0); + return; + } + if(key=='!' && !(state & ControlMask)) + { + if(xctx->semaphore >= 2) return; + break_wires_at_pins(0); + return; + } + if(key=='!' && (state & ControlMask)) + { + if(xctx->semaphore >= 2) return; + break_wires_at_pins(1); + return; + } +} + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -2634,1460 +4093,8 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case KeyPress: - if(key==' ') { - if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ - new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - - } else if(xctx->ui_state & STARTLINE) { - new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - xctx->manhattan_lines++; - xctx->manhattan_lines %=3; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } else { - if(xctx->semaphore<2) { - rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ - } - pan(START, mx, my); - xctx->ui_state |= STARTPAN; - } - break; - } - if(key == '_' ) /* toggle change line width */ - { - if(!tclgetboolvar("change_lw")) { - tcleval("alert_ { enabling change line width} {}"); - tclsetvar("change_lw","1"); - } - else { - tcleval("alert_ { disabling change line width} {}"); - tclsetvar("change_lw","0"); - } - break; - } - if(key == 'b' && rstate==ControlMask) /* toggle show text in symbol */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->sym_txt =!xctx->sym_txt; - if(xctx->sym_txt) { - /* tcleval("alert_ { enabling text in symbol} {}"); */ - tclsetvar("sym_txt","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling text in symbol} {}"); */ - tclsetvar("sym_txt","0"); - draw(); - } - break; - } - if(key == '%' ) /* toggle draw grid */ - { - int dr_gr; - dr_gr = tclgetboolvar("draw_grid"); - dr_gr =!dr_gr; - if(dr_gr) { - /* tcleval("alert_ { enabling draw grid} {}"); */ - tclsetvar("draw_grid","1"); - draw(); - } - else { - /* tcleval("alert_ { disabling draw grid} {}"); */ - tclsetvar("draw_grid","0"); - draw(); - } - break; - } - if(key == 'j' && rstate==0 ) /* print list of highlight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(1); - break; - } - if(key == 'j' && rstate==ControlMask) /* create ipins from highlight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(0); - break; - } - if(key == 'j' && EQUAL_MODMASK) /* create labels without i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(4); - break; - } - if(key == 'J' && SET_MODMASK ) /* create labels with i prefix from hilight nets */ - { - if(xctx->semaphore >= 2) break; - print_hilight_net(2); - break; - } - if(key == 'h' && rstate==ControlMask ) /* go to http link */ - { - int savesem = xctx->semaphore; - xctx->semaphore = 0; - launcher(); - xctx->semaphore = savesem; - break; - } - if(key == 'h' && EQUAL_MODMASK) /* create symbol pins from schematic pins 20171208 */ - { - tcleval("schpins_to_sympins"); - break; - } - if(key == 'h' && rstate == 0) { - /* horizontally constrained drag 20171023 */ - if ( xctx->constr_mv == 1 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 1" ); - xctx->constr_mv = 1; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - if(key=='H' && rstate == 0) { /* attach labels to selected instances */ - attach_labels_to_inst(1); - break; - } - if (key == 'H' && rstate == ControlMask) { /* create schematic and symbol from selected components */ - make_schematic_symbol_from_sel(); - break; - } - if(key == 'v' && rstate==0) { - /* vertically constrained drag 20171023 */ - if ( xctx->constr_mv == 2 ) { - tcleval("set constr_mv 0" ); - xctx->constr_mv = 0; - } else { - tcleval("set constr_mv 2" ); - xctx->constr_mv = 2; - } - if(xctx->ui_state & STARTWIRE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_wire(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - if(xctx->ui_state & STARTLINE) { - if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; - if(xctx->constr_mv == 2) xctx->mousex_snap = xctx->mx_double_save; - new_line(RUBBER, xctx->mousex_snap, xctx->mousey_snap); - } - break; - } - if(key == 'j' && SET_MODMASK && (state & ControlMask) ) /* print list of highlight net with label expansion */ - { - print_hilight_net(3); - break; - } - if(key == 'J' && rstate == 0) { - create_plot_cmd(); - break; - } - if(key == '$' && rstate == 0 ) /* toggle pixmap saving */ - { - xctx->draw_pixmap =!xctx->draw_pixmap; - if(xctx->draw_pixmap) tcleval("alert_ { enabling draw pixmap} {}"); - else tcleval("alert_ { disabling draw pixmap} {}"); - break; - } - if(key == '$' && (state &ControlMask) ) /* toggle window drawing */ - { - xctx->draw_window =!xctx->draw_window; - if(xctx->draw_window) { - tcleval("alert_ { enabling draw window} {}"); - tclsetvar("draw_window","1"); - } else { - tcleval("alert_ { disabling draw window} {}"); - tclsetvar("draw_window","0"); - } - break; - } - if(key == '=' && (state &ControlMask)) /* toggle fill rectangles */ - { - int x; - xctx->fill_pattern++; - if(xctx->fill_pattern==3) xctx->fill_pattern=0; - - if(xctx->fill_pattern==1) { - tcleval("alert_ { Stippled pattern fill} {}"); - for(x=0;xfill_type[x]==1) XSetFillStyle(display,xctx->gcstipple[x],FillSolid); - else XSetFillStyle(display,xctx->gcstipple[x],FillStippled); - } - } - else if(xctx->fill_pattern==2) { - tcleval("alert_ { solid pattern fill} {}"); - for(x=0;xgcstipple[x],FillSolid); - } - else { - tcleval("alert_ { No pattern fill} {}"); - for(x=0;xgcstipple[x],FillStippled); - } - - draw(); - break; - } - if(key == '+' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw + 0.5, 2); - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - break; - } - - if(key == '-' && state & ControlMask) /* change line width */ - { - xctx->lw = round_to_n_digits(xctx->lw - 0.5, 2); - if(xctx->lw < 0.0) xctx->lw = 0.0; - change_linewidth(xctx->lw); - tclsetboolvar("change_lw", 0); - draw(); - break; - } - if(key == 'X' && rstate == 0) /* highlight discrepanciens between selected instance pin and net names */ - { - hilight_net_pin_mismatches(); - break; - } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ - if(xctx->semaphore >= 2) break; - if(infix_interface) { - snapped_wire(c_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTSNAPWIRE; - } - break; - } - if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) break; - - if(infix_interface) { - start_wire(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTWIRE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTWIRE; - } - break; - } - if(key == XK_Return && (state == 0 ) && xctx->ui_state & STARTPOLYGON) { /* close polygon */ - new_polygon(ADD|END, xctx->mousex_snap, xctx->mousey_snap); - break; - } - if(key == XK_Escape) /* abort & redraw */ - { - if(xctx->semaphore < 2) { - abort_operation(); - } - /* stuff that can be done reentrantly ... */ - tclsetvar("tclstop", "1"); /* stop simulation if any running */ - break; - } - if(key=='z' && rstate == 0 && - !(xctx->ui_state & (STARTRECT | STARTLINE | STARTWIRE | STARTPOLYGON | STARTARC))) /* zoom box */ - { - dbg(1, "callback(): zoom_rectangle call\n"); - zoom_rectangle(START);break; - } - if(key=='Z' && rstate == 0) /* zoom in */ - { - view_zoom(0.0); break; - } - if(key=='p' && EQUAL_MODMASK) /* add symbol pin */ - { - xctx->push_undo(); - unselect_all(1); - storeobject(-1, xctx->mousex_snap-2.5, xctx->mousey_snap-2.5, xctx->mousex_snap+2.5, xctx->mousey_snap+2.5, - xRECT, PINLAYER, SELECTED, "name=XXX\ndir=inout"); - xctx->need_reb_sel_arr=1; - rebuild_selected_array(); - move_objects(START,0,0,0); - xctx->ui_state |= START_SYMPIN; - break; - } - if(key=='p' && !(xctx->ui_state & STARTPOLYGON) && rstate==0) /* start polygon */ - { - if(xctx->semaphore >= 2) break; - dbg(1, "callback(): start polygon\n"); - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTPOLYGON; - } - break; - } - if(key=='P' && rstate == 0) /* pan, other way to. */ - { - xctx->xorigin=-xctx->mousex_snap+xctx->areaw*xctx->zoom/2.0; - xctx->yorigin=-xctx->mousey_snap+xctx->areah*xctx->zoom/2.0; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key=='5' && rstate == 0) { /* 20110112 display only probes */ - xctx->only_probes = !xctx->only_probes; - tclsetboolvar("only_probes", xctx->only_probes); - toggle_only_probes(); - break; - } /* /20110112 */ - if(key<='9' && key >='0' && state==ControlMask) /* choose layer */ - { - char n[30]; - xctx->rectcolor = (int)key - '0'+4; - my_snprintf(n, S(n), "%d", xctx->rectcolor); - tclvareval("xschem set rectcolor ", n, NULL); - - if(has_x) { - if(!strcmp(win_path, ".drw")) { - tclvareval("reconfigure_layers_button {}", NULL); - } else { - tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); - } - } - dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); - break; - } - if(key==XK_Delete && (xctx->ui_state & SELECTION) ) /* delete selection */ - { - if(xctx->semaphore >= 2) break; - delete(1/* to_push_undo */);break; - } - if(key==XK_Right && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->semaphore = 0; - tcleval("next_tab"); - xctx->semaphore = save; - break; - } - if(key==XK_Left && state == ControlMask) { - int save = xctx->semaphore; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->semaphore = 0; - tcleval("prev_tab"); - xctx->semaphore = save; - break; - } - if(key==XK_Right && !(state & ControlMask)) /* left */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->xorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Left && !(state & ControlMask)) /* right */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->xorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Down) /* down */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->yorigin+=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key==XK_Up) /* up */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->yorigin-=-CADMOVESTEP*xctx->zoom; - draw(); - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - if(key=='w' && rstate == ControlMask) /* close current schematic */ - { - int save_sem; - if(xctx->semaphore >= 2) break; - save_sem = xctx->semaphore; - tcleval("xschem exit"); - xctx->semaphore = save_sem; - break; - } - /* toggle spice_ignore, verilog_ignore, ... flag on selected instances. */ - if(key == 'T' && rstate == 0) { - toggle_ignore(); - } - if(key=='t' && rstate == 0) /* place text */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(xctx->semaphore >= 2) break; - xctx->last_command = 0; - xctx->mx_double_save = xctx->mousex_snap; - xctx->my_double_save = xctx->mousey_snap; - if(place_text(0, xctx->mousex_snap, xctx->mousey_snap)) { /* 1 = draw text 24122002 */ - xctx->mousey_snap = xctx->my_double_save; - xctx->mousex_snap = xctx->mx_double_save; - move_objects(START,0,0,0); - xctx->ui_state |= PLACE_TEXT; - } - break; - } - if(key=='t' && (rstate & ControlMask)) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='r' /* && !xctx->ui_state */ && rstate==0) /* start rect */ - { - dbg(1, "callback(): start rect\n"); - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTRECT; - } - break; - } - if(key=='V' && rstate == ControlMask) /* toggle spice/vhdl netlist */ - { - xctx->netlist_type++; if(xctx->netlist_type==6) xctx->netlist_type=1; - set_tcl_netlist_type(); - draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ - break; - } - if(key=='s' && rstate == 0 ) /* simulate */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Run circuit simulation?}"); - if(strcmp(tclresult(),"ok")==0) { - tcleval("[xschem get top_path].menubar invoke Simulate"); - } - break; - } - if(key=='s' && rstate == ControlMask ) /* save 20121201 */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - /* check if unnamed schematic, use saveas in this case */ - if(!strcmp(xctx->sch[xctx->currsch],"") || strstr(xctx->sch[xctx->currsch], "untitled")) { - saveas(NULL, SCHEMATIC); - } else { - save(1, 0); - } - break; - } - if(key=='s' && SET_MODMASK && (state & ControlMask) ) /* save as symbol */ - { - if(xctx->semaphore >= 2) break; - saveas(NULL, SYMBOL); - break; - } - if(key=='S' && rstate == ControlMask) /* save as schematic */ - { - if(xctx->semaphore >= 2) break; - saveas(NULL, SCHEMATIC); - break; - } - if(key=='e' && rstate == 0) /* descend to schematic */ - { - if(xctx->semaphore >= 2) break; - descend_schematic(0, 1, 1, 1);break; - } - if(key=='e' && EQUAL_MODMASK) /* edit schematic in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - /* schematic_in_new_window(0, 1, 0); */ - tcleval("open_sub_schematic"); - xctx->semaphore = save; - break; - } - - if(key=='E' && EQUAL_MODMASK) /* edit schematic in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - schematic_in_new_window(1, 1, 0); - xctx->semaphore = save; - break; - } - - if(key=='i' && EQUAL_MODMASK) /* edit symbol in new window */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(0); - xctx->semaphore = save; - break; - } - - if(key=='I' && EQUAL_MODMASK) /* edit symbol in new window - new xschem process */ - { - int save = xctx->semaphore; - xctx->semaphore--; /* so semaphore for current context wll be saved correctly */ - symbol_in_new_window(1); - xctx->semaphore = save; - break; - } - - - if( (key=='e' && rstate == ControlMask) || (key==XK_BackSpace)) /* back */ - { - if(xctx->semaphore >= 2) break; - go_back(1);break; - } - - if(key=='a' && rstate == 0) /* make symbol */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {do you want to make symbol view ?}"); - if(strcmp(tclresult(),"ok")==0) - { - save_schematic(xctx->sch[xctx->currsch], 0); - make_symbol(); - } - break; - } - if(key=='a' && rstate == ControlMask) /* select all */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - select_all(); - break; - } - if(key=='y' && rstate == 0) /* toggle stretching */ - { - enable_stretch = !enable_stretch; - tclsetboolvar("enable_stretch", enable_stretch); - break; - } - if(key=='x' && EQUAL_MODMASK) /* toggle draw crosshair at mouse pos */ - { - if(tclgetboolvar("draw_crosshair")) { - tclsetvar("draw_crosshair", "0"); - } else { - tclsetvar("draw_crosshair", "1"); - } - draw(); - } - if(key=='x' && rstate == ControlMask) /* cut selection into clipboard */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - delete(1/* to_push_undo */); - } - break; - } - if(key=='c' && rstate == ControlMask) /* copy selection into clipboard */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel) { /* 20071203 check if something selected */ - save_selection(2); - } - break; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == 0) /* place arc */ - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 180., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTARC; - } - break; - } - if(key=='C' /* && !xctx->ui_state */ && rstate == ControlMask) /* place circle */ - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - xctx->last_command = 0; - new_arc(PLACE, 360., xctx->mousex_snap, xctx->mousey_snap); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCIRCLE; - } - break; - } - if(key=='O' && rstate == ControlMask ) /* load most recent tile */ - { - tclvareval("xschem load -gui [lindex $recentfile 0]", NULL); - break; - } - if(key=='O' && rstate == 0) /* toggle light/dark colorscheme 20171113 */ - { - int d_c; - d_c = tclgetboolvar("dark_colorscheme"); - d_c = !d_c; - tclsetboolvar("dark_colorscheme", d_c); - tclsetdoublevar("dim_value", 0.0); - tclsetdoublevar("dim_bg", 0.0); - build_colors(0.0, 0.0); - draw(); - break; - } - if(key=='v' && rstate == ControlMask) /* paste from clipboard */ - { - if(xctx->semaphore >= 2) break; - merge_file(2,".sch"); - break; - } - if(key=='Q' && rstate == ControlMask ) /* view attributes */ - { - edit_property(2);break; - } - if(key=='q' && rstate==ControlMask) /* quit xschem */ - { - if(xctx->semaphore >= 2) break; - /* must be set to zero, otherwise switch_tab/switch_win does not proceed - * and these are necessary when closing tabs/windows */ - xctx->semaphore = 0; - tcleval("quit_xschem"); - break; - } - if(key=='q' && rstate==0) /* edit attributes */ - { - if(xctx->semaphore >= 2) break; - edit_property(0); - break; - } - if(key=='q' && EQUAL_MODMASK) /* edit .sch file (DANGER!!) */ - { - if(xctx->semaphore >= 2) break; - rebuild_selected_array(); - if(xctx->lastsel==0 ) { - my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); - tcleval(str); - } - else if(xctx->sel_array[0].type==ELEMENT) { - my_snprintf(str, S(str), "edit_file {%s}", - abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); - tcleval(str); - - } - break; - } - #if defined(__unix__) && HAS_CAIRO==1 - if(key == XK_Print) { - xctx->ui_state |= GRABSCREEN; - tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); - tclvareval("grab set -global ", xctx->top_path, ".drw", NULL); - break; - } - #endif - if(key=='Q' && rstate == 0) /* edit attributes in editor */ - { - if(xctx->semaphore >= 2) break; - edit_property(1);break; - } - if(key=='i' && rstate==0) /* descend to symbol */ - { - if(xctx->semaphore >= 2) break; - descend_symbol();break; - } - if((key==XK_Insert && state == ShiftMask) || (key == 'i' && rstate == ControlMask)) /* insert sym */ - { - tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); - break; - } - if((key==XK_Insert) || (key == 'I' && rstate == 0) ) /* insert sym */ - { - if(xctx->semaphore >= 2) break; - start_place_symbol(); - - break; - } - if(key=='s' && SET_MODMASK) /* reload */ - { - if(xctx->semaphore >= 2) break; - tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " - "-message {Are you sure you want to reload from disk?}"); - if(strcmp(tclresult(),"ok")==0) { - char filename[PATH_MAX]; - unselect_all(1); - remove_symbols(); - my_strncpy(filename, abs_sym_path(xctx->sch[xctx->currsch], ""), S(filename)); - load_schematic(1, filename, 1, 1); - draw(); - } - break; - } - if(key=='o' && rstate == ControlMask) /* load */ - { - if(xctx->semaphore >= 2) break; - ask_new_file(); - break; - } - if(key=='S' && rstate == 0) /* change element order */ - { - if(xctx->semaphore >= 2) break; - change_elem_order(-1); - break; - } - if(key=='k' && EQUAL_MODMASK) /* select whole net (all attached wires/labels/pins) */ - { - select_hilight_net(); - break; - } - if(key=='k' && rstate==ControlMask) /* unhilight net */ - { - if(xctx->semaphore >= 2) break; - unhilight_net(); - break; - } - if(key=='K' && rstate == ControlMask) /* hilight net drilling thru elements */ - /* with 'propag=' prop set on pins */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=1; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - break; - } - if(key=='k' && rstate==0) /* hilight net */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=0; - hilight_net(0); - redraw_hilights(0); - /* draw_hilight_net(1); */ - break; - } - if(key=='K' && rstate == 0) /* delete hilighted nets */ - { - if(xctx->semaphore >= 2) break; - xctx->enable_drill=0; - clear_all_hilights(); - /* undraw_hilight_net(1); */ - draw(); - break; - } - if(key=='g' && EQUAL_MODMASK) { /* highlight net and send to viewer */ - int tool = 0; - int exists = 0; - char *tool_name = NULL; - char str[200]; - - if(xctx->semaphore >= 2) break; - tcleval("winfo exists .graphdialog"); - if(tclresult()[0] == '1') tool = XSCHEM_GRAPH; - else if(xctx->graph_lastsel >=0 && - xctx->rects[GRIDLAYER] > xctx->graph_lastsel && - xctx->rect[GRIDLAYER][xctx->graph_lastsel].flags & 1) { - tool = XSCHEM_GRAPH; - } - tcleval("info exists sim"); - if(tclresult()[0] == '1') exists = 1; - xctx->enable_drill = 0; - if(exists) { - if(!tool) { - tool = tclgetintvar("sim(spicewave,default)"); - my_snprintf(str, S(str), "sim(spicewave,%d,name)", tool); - my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); - dbg(1,"callback(): tool_name=%s\n", tool_name); - if(strstr(tool_name, "Gaw")) tool=GAW; - else if(strstr(tool_name, "Bespice")) tool=BESPICE; - my_free(_ALLOC_ID_, &tool_name); - } - } - if(tool) { - hilight_net(tool); - redraw_hilights(0); - } - Tcl_ResetResult(interp); - break; - } - if(key=='g' && rstate==0) /* half snap factor */ - { - set_snap(c_snap / 2.0); - change_linewidth(-1.); - draw(); - break; - } - if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ - { - my_snprintf(str, S(str), - "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", - CADSNAP, c_snap, c_snap); - tcleval(str); - break; - } - if(key=='G' && rstate == 0) /* double snap factor */ - { - set_snap(c_snap * 2.0); - change_linewidth(-1.); - draw(); - break; - } - if(key=='*' && EQUAL_MODMASK) /* svg print , 20121108 */ - { - if(xctx->semaphore >= 2) break; - svg_draw(); - break; - } - if(key=='*' && rstate == 0 ) /* postscript print */ - { - if(xctx->semaphore >= 2) break; - ps_draw(7, 0, 0); - break; - } - if(key=='*' && rstate == ControlMask) /* xpm print */ - { - if(xctx->semaphore >= 2) break; - print_image(); - break; - } - if(key=='u' && EQUAL_MODMASK) /* align to grid */ - { - if(xctx->semaphore >= 2) break; - xctx->push_undo(); - round_schematic_to_grid(c_snap); - set_modify(1); - if(tclgetboolvar("autotrim_wires")) trim_wires(); - xctx->prep_hash_inst=0; - xctx->prep_hash_wires=0; - xctx->prep_net_structs=0; - xctx->prep_hi_structs=0; - - draw(); - break; - } - if(0 && (key=='u') && rstate==ControlMask) /* testmode */ - { - static int x = 0; - - if(x == 0) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); - } - } else if(x == 1) { - int i; - XFillRectangle(display, xctx->window, xctx->gc[BACKLAYER], xctx->areax1, xctx->areay1, - xctx->areaw, xctx->areah); - XFlush(display); - sleep_ms(400); - for(i = xctx->xrect[0].x; i < xctx->xrect[0].width; i++) { - XDrawLine(display, xctx->window, xctx->gctiled, - i, xctx->xrect[0].y, i+1, xctx->xrect[0].height); - XFlush(display); - sleep_ms(4); - } - } - x++; - x %= 2; - break; - } - if(key=='u' && rstate==0) /* undo */ - { - if(xctx->semaphore >= 2) break; - xctx->pop_undo(0, 1); /* 2nd parameter: set_modify_status */ - draw(); - break; - } - if(key=='U' && rstate == 0) /* redo */ - { - if(xctx->semaphore >= 2) break; - xctx->pop_undo(1, 1); /* 2nd parameter: set_modify_status */ - draw(); - break; - } - if(key=='&') /* check wire connectivity */ - { - if(xctx->semaphore >= 2) break; - xctx->push_undo(); - trim_wires(); - draw(); - break; - } - if(key=='l' && rstate == ControlMask) { /* create schematic from selected symbol 20171004 */ - if(xctx->semaphore >= 2) break; - create_sch_from_sym(); - break; - } - if(key=='l' /* && !xctx->ui_state */ && rstate == 0) /* start line */ - { - int prev_state = xctx->ui_state; - if(xctx->semaphore >= 2) break; - if(infix_interface) { - start_line(xctx->mousex_snap, xctx->mousey_snap); - if(prev_state == STARTLINE) { - tcleval("set constr_mv 0" ); - xctx->constr_mv=0; - } - } else { - xctx->last_command = 0; - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTLINE; - } - break; - } - if(key=='l' && EQUAL_MODMASK) { /* add pin label*/ - place_net_label(1); - break; - } - if(key >= '0' && key <= '4' && state == 0) { /* toggle pin logic level */ - if(xctx->semaphore >= 2) break; - if(key == '4') logic_set(-1, 1, NULL); - else logic_set((int)key - '0', 1, NULL); - break; - } - if(key=='L' && EQUAL_MODMASK ) { /* add pin label*/ - place_net_label(0); - break; - } - if(key=='F' && rstate == 0) /* flip */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='V' && rstate == 0) /* vertical flip */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE); - copy_objects(ROTATE); - copy_objects(FLIP); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(FLIP,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='v' && EQUAL_MODMASK) /* vertical flip objects around their anchor points */ - { - if(xctx->ui_state & STARTMOVE) { - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - } - else if(xctx->ui_state & STARTCOPY) { - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(ROTATE|ROTATELOCAL); - copy_objects(FLIP|ROTATELOCAL); - } - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - - if(key=='\\' && state==0) /* fullscreen */ - { - - dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); - toggle_fullscreen(win_path); - break; - } - if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(FLIP|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(FLIP|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(FLIP|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - if(key=='R' && rstate == 0) /* rotate */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE,0,0,0); - move_objects(END,0,0,0); - } - - break; - } - if(key=='r' && EQUAL_MODMASK) /* rotate objects around their anchor points 20171208 */ - { - if(xctx->ui_state & STARTMOVE) move_objects(ROTATE|ROTATELOCAL,0,0,0); - else if(xctx->ui_state & STARTCOPY) copy_objects(ROTATE|ROTATELOCAL); - else { - rebuild_selected_array(); - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - move_objects(ROTATE|ROTATELOCAL,0,0,0); - move_objects(END,0,0,0); - } - break; - } - /* Move selection */ - if(key=='m' && rstate==0 && !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - /* Move selection adding wires to moved pins */ - if(((key == 'M' && rstate == 0) || (key == 'm' && EQUAL_MODMASK)) && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - /* select_attached_nets(); */ /* stretch nets that land on selected instance pins */ - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - /* move selection stretching attached nets */ - if(key=='m' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - - /* move selection, stretch attached nets, create new wires on pin-to-moved-pin connections */ - if(key=='M' && rstate == ControlMask && - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(!enable_stretch) select_attached_nets(); /* stretch nets that land on selected instance pins */ - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - move_objects(START,0,0,0); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTMOVE; - } - break; - } - - if(key=='c' && EQUAL_MODMASK && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) break; - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - break; - } - - if(key=='c' && rstate==0 && /* duplicate selection */ - !(xctx->ui_state & (STARTMOVE | STARTCOPY))) - { - if(xctx->semaphore >= 2) break; - if(infix_interface) { - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - copy_objects(START); - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTCOPY; - } - break; - } - if(key=='n' && rstate == ControlMask) /* clear schematic */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem clear SCHEMATIC"); - break; - } - if(key=='N' && rstate == ControlMask ) /* clear symbol */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem clear SYMBOL"); - break; - } - if(key=='n' && rstate==0) /* hierarchical netlist */ - { - if(xctx->semaphore >= 2) break; - tcleval("xschem netlist -erc"); - break; - } - if(key=='N' && rstate == 0) /* current level only netlist */ - { - int err = 0; - yyparse_error = 0; - if(xctx->semaphore >= 2) break; - unselect_all(1); - if( set_netlist_dir(0, NULL) ) { - dbg(1, "callback(): -------------\n"); - if(xctx->netlist_type == CAD_SPICE_NETLIST) - err = global_spice_netlist(0, 1); - else if(xctx->netlist_type == CAD_VHDL_NETLIST) - err = global_vhdl_netlist(0, 1); - else if(xctx->netlist_type == CAD_VERILOG_NETLIST) - err = global_verilog_netlist(0, 1); - else if(xctx->netlist_type == CAD_TEDAX_NETLIST) - err = global_tedax_netlist(0, 1); - else - tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " - "-message {Please Set netlisting mode (Options menu)}"); - dbg(1, "callback(): -------------\n"); - } - else { - if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); - else dbg(0, "Can not write into the netlist directory. Please check"); - err = 1; - } - if(err) { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); - } - } else { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); - } - } - - break; - } - if(key=='A' && rstate == ControlMask) /* only for graph (toggle hcursor1 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='A' && rstate == 0) /* toggle show netlist */ - { - int net_s; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - net_s = tclgetboolvar("netlist_show"); - net_s = !net_s; - if(net_s) { - tcleval("alert_ { enabling show netlist window} {}"); - tclsetvar("netlist_show","1"); - } - else { - tcleval("alert_ { disabling show netlist window } {}"); - tclsetvar("netlist_show","0"); - } - break; - } - if(key=='>') { - if(xctx->semaphore >= 2) break; - if(xctx->draw_single_layer< cadlayers-1) xctx->draw_single_layer++; - draw(); - break; - } - if(key=='<') { - if(xctx->semaphore >= 2) break; - if(xctx->draw_single_layer>=0 ) xctx->draw_single_layer--; - draw(); - break; - } - if(key==':') /* toggle flat netlist (only spice) */ - { - if(!tclgetboolvar("flat_netlist")) { - tcleval("alert_ { enabling flat netlist} {}"); - tclsetvar("flat_netlist","1"); - } - else { - tcleval("alert_ { set hierarchical netlist } {}"); - tclsetvar("flat_netlist","0"); - } - break; - } - if(key=='B' && rstate == ControlMask) /* only for graph (toggle hcursor2 if graph_use_ctrl_key set) */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - break; - } - if(key=='B' && rstate == 0) /* edit schematic header/license */ - { - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("update_schematic_header"); - } - if(key=='b' && rstate==0) /* merge schematic */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - merge_file(0, ""); /* 2nd parameter not used any more for merge 25122002 */ - break; - } - if(key=='b' && EQUAL_MODMASK) /* hide/show instance details */ - { - if(xctx->semaphore >= 2) break; - xctx->hide_symbols++; - if(xctx->hide_symbols >= 3) xctx->hide_symbols = 0; - tclsetintvar("hide_symbols", xctx->hide_symbols); - draw(); - break; - } - if(key=='d' && rstate == 0) /* unselect object under the mouse */ - { - if(infix_interface) { - unselect_at_mouse_pos(mx, my); - } else { - xctx->ui_state |= (MENUSTART | DESEL_CLICK); - xctx->ui_state2 = MENUSTARTDESEL; - } - break; - } - if(key=='D' && rstate == 0) /* unselect by area */ - { - if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && - !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { - if(infix_interface) { - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex; - xctx->my_double_save=xctx->mousey; - xctx->ui_state |= DESEL_AREA; - } else { - xctx->ui_state |= MENUSTART; - xctx->ui_state2 = MENUSTARTDESEL; - } - } - break; - } - if(key=='d' && rstate == ControlMask) /* delete files */ - { - if(xctx->semaphore >= 2) break; - delete_files(); - break; - } - if(key=='x' && rstate == 0 ) /* new cad session */ - { - new_xschem_process(NULL ,0); - break; - } - if((key=='#') && !(state & ControlMask) ) - { - check_unique_names(0); - break; - } - if((key=='#') && (state & ControlMask) ) - { - check_unique_names(1); - break; - } - if( 0 && (key==';') && (state & ControlMask) ) /* testmode */ - { - break; - } - if(0 && key=='~' && (state & ControlMask)) { /* testmode */ - break; - } - if(0 && key=='|' && !(state & ControlMask)) { /* testmode */ - break; - } - if(0 && key=='|' && (state & ControlMask)) /* testmode */ - { - break; - } - - if(key=='f' && rstate == ControlMask) /* search */ - { - if(xctx->semaphore >= 2) break; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - tcleval("property_search"); - break; - } - if(key=='F' && rstate == ControlMask ) /* full zoom selection */ - { - if(xctx->ui_state == SELECTION) { - zoom_full(1, 1, 3, 0.97); - } - break; - } - if(key=='f' && rstate == 0 ) /* full zoom */ - { - int flags = 1; - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - if(tclgetboolvar("zoom_full_center")) flags |= 2; - zoom_full(1, 0, flags, 0.97); - break; - } - if((key=='z' && rstate==ControlMask)) /* zoom out */ - { - view_unzoom(0.0); - break; - } - if(key=='!' && !(state & ControlMask)) - { - if(xctx->semaphore >= 2) break; - break_wires_at_pins(0); - break; - } - if(key=='!' && (state & ControlMask)) - { - if(xctx->semaphore >= 2) break; - break_wires_at_pins(1); - break; - } + handle_key_press(event, key, state, rstate, mx, my, button, aux, + infix_interface, enable_stretch, win_path, c_snap, str); break; case ButtonPress: From 899e7f93d223bc563bb0c4a476514522588412de Mon Sep 17 00:00:00 2001 From: Ananth Date: Mon, 10 Feb 2025 14:34:20 -0700 Subject: [PATCH 03/46] add handle_button_press/release --- src/callback.c | 658 +++++++++++++++++++++++++------------------------ 1 file changed, 336 insertions(+), 322 deletions(-) diff --git a/src/callback.c b/src/callback.c index a61c6329..9846e243 100644 --- a/src/callback.c +++ b/src/callback.c @@ -3891,6 +3891,337 @@ void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int } } +void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, + double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux ) +{ + dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + /* terminate a schematic pan action */ + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + return; + } + + /* select instance and connected nets stopping at wire junctions */ + if(button == Button3 && state == ControlMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(1); + } + + /* break wire at mouse coordinates, move break point to nearest grid point */ + else if(button == Button3 && EQUAL_MODMASK && !(state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); + } + /* break wire at mouse coordinates */ + else if(button == Button3 && EQUAL_MODMASK && (state & ShiftMask) && xctx->semaphore <2) + { + break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); + } + /* select instance and connected nets NOT stopping at wire junctions */ + else if(button == Button3 && state == ShiftMask && xctx->semaphore <2) + { + Selected sel; + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + if(sel.type) select_connected_nets(0); + } + /* moved to Button3 release */ + /* + * else if(button == Button3 && state == 0 && xctx->semaphore <2) { + * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + * } + */ + + /* zoom rectangle by right clicking and drag */ + else if(button == Button3 && state == 0 && xctx->semaphore < 2) { + zoom_rectangle(START);return; + } + + /* Mouse wheel events */ + else if(handle_mouse_wheel(event, mx, my, key, button, aux, state)) return; + + /* terminate wire placement in snap mode */ + else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { + snapped_wire(c_snap); + } + /* Alt - Button1 click to unselect */ + else if(button==Button1 && (SET_MODMASK) ) { + unselect_at_mouse_pos(mx, my); + } + + /* Middle button press (Button2) will pan the schematic. */ + else if(button==Button2 && (state == 0)) { + pan(START, mx, my); + xctx->ui_state |= STARTPAN; + } + + /* button1 click to select another instance while edit prop dialog open */ + else if(button==Button1 && xctx->semaphore >= 2) { + if(tcleval("winfo exists .dialog.textinput")[0] == '1') { /* proc text_line */ + tcleval(".dialog.f1.b1 invoke"); + return; + } else if(tcleval("winfo exists .dialog.txt")[0] == '1') { /* proc enter_text */ + tcleval(".dialog.buttons.ok invoke"); + return; + } else if(state==0 && tclgetvar("edit_symbol_prop_new_sel")[0]) { + tcleval("set edit_symbol_prop_new_sel 1; .dialog.f1.b1 invoke"); /* invoke 'OK' of edit prop dialog */ + } else if((state & ShiftMask) && tclgetvar("edit_symbol_prop_new_sel")[0]) { + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + tclsetvar("preserve_unchanged_attrs", "1"); + rebuild_selected_array(); + } + } + + /* Handle the remaining Button1Press events */ + else if(button==Button1) /* MOD button is not pressed here. Processed above */ + { + xctx->onetime = 0; + xctx->mouse_moved = 0; + xctx->drag_elements = 0; + + /* start another wire or line in persistent mode */ + if(tclgetboolvar("persistent_command") && xctx->last_command) { + if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); + if(xctx->last_command == STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); + return; + } + /* handle all object insertions started from Tools/Edit menu */ + if(check_menu_start_commands(c_snap, mx, my)) return; + + /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ + if(end_place_move_copy_zoom()) return; + + /* Button1Press to select objects */ + if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { + Selected sel; + int already_selected = 0; + int prev_last_sel = xctx->lastsel; + int no_shift_no_ctrl = !(state & (ShiftMask | ControlMask)); + + xctx->shape_point_selected = 0; + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + + #if 0 /* disabled */ + /* Clicking and dragging from a **selected** instance pin will start a new wire + * if no other elements are selected */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) { + if(add_wire_from_wire(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + if(add_wire_from_inst(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) return; + } + #endif + + /* In *NON* intuitive interface a button1 press with no modifiers will + * first unselect everything... + * For intuitive interface unselection see below... */ + if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); + + /* find closest object. Use snap coordinates if full crosshair is enabled + * since the mouse pointer is obscured and crosshair is snapped to grid points */ + if(draw_xhair && crosshair_size == 0) { + sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); + } else { + sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); + } + dbg(1, "sel.type=%d\n", sel.type); + /* determine if closest object was already selected when button1 was pressed */ + switch(sel.type) { + case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; + case xTEXT: if(xctx->text[sel.n].sel) already_selected = 1; break; + case LINE: if(xctx->line[sel.col][sel.n].sel) already_selected = 1; break; + case POLYGON: if(xctx->poly[sel.col][sel.n].sel) already_selected = 1; break; + case xRECT: if(xctx->rect[sel.col][sel.n].sel) already_selected = 1; break; + case ARC: if(xctx->arc[sel.col][sel.n].sel) already_selected = 1; break; + case ELEMENT: if(xctx->inst[sel.n].sel) already_selected = 1; break; + default: break; + } /*end switch */ + + /* Clicking and drag on an instance pin -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_inst(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* Clicking and drag on a wire end -> drag a new wire */ + if(xctx->intuitive_interface && !already_selected) { + if(add_wire_from_wire(&sel, xctx->mousex_snap, xctx->mousey_snap)) return; + } + + /* In intuitive interface a button1 press with no modifiers will + * unselect everything... we do it here */ + if(xctx->intuitive_interface && !already_selected && no_shift_no_ctrl ) unselect_all(1); + + /* select the object under the mouse and rebuild the selected array */ + if(!already_selected) select_object(xctx->mousex, xctx->mousey, SELECTED, 0, &sel); + rebuild_selected_array(); + dbg(1, "Button1Press to select objects, lastsel = %d\n", xctx->lastsel); + + /* if clicking on some object endpoints or vertices set shape_point_selected + * this information will be used in Motion events to draw the stretched vertices */ + if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { + if(edit_polygon_point(state)) return; /* sets xctx->shape_point_selected */ + } + if(xctx->lastsel == 1 && xctx->intuitive_interface) { + int cond = already_selected; + + if(cond && xctx->sel_array[0].type==xRECT) { + if(edit_rect_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==LINE) { + if(edit_line_point(state)) return; /* sets xctx->shape_point_selected */ + } + + if(cond && xctx->sel_array[0].type==WIRE) { + if(edit_wire_point(state)) return; /* sets xctx->shape_point_selected */ + } + } + dbg(1, "shape_point_selected=%d, lastsel=%d\n", xctx->shape_point_selected, xctx->lastsel); + + /* intuitive interface: directly drag elements */ + if(sel.type && xctx->intuitive_interface && xctx->lastsel >= 1 && + !xctx->shape_point_selected) { + /* enable_stretch (from TCL variable) reverses command if enabled: + * - move --> stretch move + * - stretch move (with ctrl key) --> move + */ + int stretch = (state & ControlMask ? 1 : 0) ^ enable_stretch; + xctx->drag_elements = 1; + /* select attached nets depending on ControlMask and enable_stretch */ + if(stretch) { + select_attached_nets(); /* stretch nets that land on selected instance pins */ + } + /* if dragging instances with stretch enabled and Shift down add wires to pins + * attached to something */ + if((state & ShiftMask) && stretch) { + xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ + move_objects(START,0,0,0); + } + /* dragging away an object with Shift pressed is a copy (duplicate object) */ + else if(state & ShiftMask) copy_objects(START); + /* else it is a normal move */ + else move_objects(START,0,0,0); + } + + if(tclgetboolvar("auto_hilight") && !xctx->shape_point_selected) { + if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { + if(!prev_last_sel) { + redraw_hilights(1); /* 1: clear all hilights, then draw */ + } + } + hilight_net(0); + if(xctx->lastsel) { + redraw_hilights(0); + } + } + return; + } + } /* button==Button1 */ +} + +void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, + int aux, double c_snap, int enable_stretch, int draw_xhair, char *str) +{ + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + xctx->ui_state &= ~DESEL_CLICK; + dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); + /* bring up context menu if no pending operation */ + if(state == Button3Mask && xctx->semaphore <2) { + if(!end_place_move_copy_zoom()) { + context_menu_action(xctx->mousex_snap, xctx->mousey_snap); + } + } + + /* launcher, no intuitive interface */ + if(!xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* launcher, intuitive_interface, only if no movement has been done */ + else if(xctx->intuitive_interface && state == (Button1Mask | ControlMask) && + !xctx->shape_point_selected && (xctx->ui_state & STARTMOVE) && xctx->mouse_moved == 0) { + int savesem = xctx->semaphore; + move_objects(ABORT, 0, 0.0, 0.0); + unselect_all(1); + select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); + rebuild_selected_array(); + xctx->semaphore = 0; + launcher(); /* works only if lastsel == 1 */ + xctx->semaphore = savesem; + } + + /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ + else if(state == Button1Mask && xctx->intuitive_interface && + (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { + if(end_place_move_copy_zoom()) return; + } + + /* end intuitive_interface copy or move */ + if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { + copy_objects(END); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + else if(xctx->ui_state & STARTMOVE && xctx->drag_elements) { + move_objects(END,0,0,0); + xctx->constr_mv=0; + tcleval("set constr_mv 0" ); + xctx->drag_elements = 0; + } + + /* if a polygon/bezier/rectangle control point was clicked, end point move operation + * and set polygon state back to SELECTED from SELECTED1 */ + else if((xctx->ui_state & (STARTMOVE | SELECTION)) && xctx->shape_point_selected) { + end_shape_point_edit(c_snap); + } + + if(xctx->ui_state & STARTPAN) { + xctx->ui_state &=~STARTPAN; + /* xctx->mx_save = mx; xctx->my_save = my; */ + /* xctx->mx_double_save=xctx->mousex_snap; */ + /* xctx->my_double_save=xctx->mousey_snap; */ + redraw_w_a_l_r_p_z_rubbers(1); + return; + } + dbg(1, "callback(): ButtonRelease ui_state=%d state=%d\n",xctx->ui_state,state); + if(xctx->semaphore >= 2) return; + if(xctx->ui_state & STARTSELECT) { + if(state & ControlMask) { + select_rect(!enable_stretch, END,-1); + } else { + /* Button1 release: end of rectangle select */ + if(!(state & (Button4Mask|Button5Mask) ) ) { + select_rect(enable_stretch, END,-1); + } + } + xctx->ui_state &= ~DESEL_AREA; + rebuild_selected_array(); + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", + xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); + statusmsg(str,1); + } + + /* clear start from menu flag or infix_interface=0 start commands */ + if(xctx->ui_state & MENUSTART) { + xctx->ui_state &= ~MENUSTART; + return; + } + if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ +} + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -4098,331 +4429,14 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case ButtonPress: - dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - /* terminate a schematic pan action */ - if(xctx->ui_state & STARTPAN) { - xctx->ui_state &=~STARTPAN; - break; - } - - /* select instance and connected nets stopping at wire junctions */ - if(button == Button3 && state == ControlMask && xctx->semaphore <2) - { - Selected sel; - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - if(sel.type) select_connected_nets(1); - } - - /* break wire at mouse coordinates, move break point to nearest grid point */ - else if(button == Button3 && EQUAL_MODMASK && !(state & ShiftMask) && xctx->semaphore <2) - { - break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); - } - /* break wire at mouse coordinates */ - else if(button == Button3 && EQUAL_MODMASK && (state & ShiftMask) && xctx->semaphore <2) - { - break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); - } - /* select instance and connected nets NOT stopping at wire junctions */ - else if(button == Button3 && state == ShiftMask && xctx->semaphore <2) - { - Selected sel; - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - if(sel.type) select_connected_nets(0); - } - /* moved to Button3 release */ - /* - * else if(button == Button3 && state == 0 && xctx->semaphore <2) { - * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); - * } - */ - - /* zoom rectangle by right clicking and drag */ - else if(button == Button3 && state == 0 && xctx->semaphore < 2) { - zoom_rectangle(START);break; - } - - /* Mouse wheel events */ - else if(handle_mouse_wheel(event, mx, my, key, button, aux, state)) break; - - /* terminate wire placement in snap mode */ - else if(button==Button1 && (state & ShiftMask) && (xctx->ui_state & STARTWIRE) ) { - snapped_wire(c_snap); - } - /* Alt - Button1 click to unselect */ - else if(button==Button1 && (SET_MODMASK) ) { - unselect_at_mouse_pos(mx, my); - } - - /* Middle button press (Button2) will pan the schematic. */ - else if(button==Button2 && (state == 0)) { - pan(START, mx, my); - xctx->ui_state |= STARTPAN; - } - - /* button1 click to select another instance while edit prop dialog open */ - else if(button==Button1 && xctx->semaphore >= 2) { - if(tcleval("winfo exists .dialog.textinput")[0] == '1') { /* proc text_line */ - tcleval(".dialog.f1.b1 invoke"); - break; - } else if(tcleval("winfo exists .dialog.txt")[0] == '1') { /* proc enter_text */ - tcleval(".dialog.buttons.ok invoke"); - break; - } else if(state==0 && tclgetvar("edit_symbol_prop_new_sel")[0]) { - tcleval("set edit_symbol_prop_new_sel 1; .dialog.f1.b1 invoke"); /* invoke 'OK' of edit prop dialog */ - } else if((state & ShiftMask) && tclgetvar("edit_symbol_prop_new_sel")[0]) { - select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - tclsetvar("preserve_unchanged_attrs", "1"); - rebuild_selected_array(); - } - } - - /* Handle the remaining Button1Press events */ - else if(button==Button1) /* MOD button is not pressed here. Processed above */ - { - xctx->onetime = 0; - xctx->mouse_moved = 0; - xctx->drag_elements = 0; - - /* start another wire or line in persistent mode */ - if(tclgetboolvar("persistent_command") && xctx->last_command) { - if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); - if(xctx->last_command == STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); - break; - } - /* handle all object insertions started from Tools/Edit menu */ - if(check_menu_start_commands(c_snap, mx, my)) break; - - /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ - if(end_place_move_copy_zoom()) break; - - /* Button1Press to select objects */ - if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { - Selected sel; - int already_selected = 0; - int prev_last_sel = xctx->lastsel; - int no_shift_no_ctrl = !(state & (ShiftMask | ControlMask)); - - xctx->shape_point_selected = 0; - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex; - xctx->my_double_save=xctx->mousey; - - #if 0 /* disabled */ - /* Clicking and dragging from a **selected** instance pin will start a new wire - * if no other elements are selected */ - if(xctx->lastsel == 1 && xctx->sel_array[0].type==ELEMENT) { - if(add_wire_from_wire(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) break; - if(add_wire_from_inst(&xctx->sel_array[0], xctx->mousex_snap, xctx->mousey_snap)) break; - } - #endif - - /* In *NON* intuitive interface a button1 press with no modifiers will - * first unselect everything... - * For intuitive interface unselection see below... */ - if(!xctx->intuitive_interface && no_shift_no_ctrl ) unselect_all(1); - - /* find closest object. Use snap coordinates if full crosshair is enabled - * since the mouse pointer is obscured and crosshair is snapped to grid points */ - if(draw_xhair && crosshair_size == 0) { - sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); - } else { - sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); - } - dbg(1, "sel.type=%d\n", sel.type); - /* determine if closest object was already selected when button1 was pressed */ - switch(sel.type) { - case WIRE: if(xctx->wire[sel.n].sel) already_selected = 1; break; - case xTEXT: if(xctx->text[sel.n].sel) already_selected = 1; break; - case LINE: if(xctx->line[sel.col][sel.n].sel) already_selected = 1; break; - case POLYGON: if(xctx->poly[sel.col][sel.n].sel) already_selected = 1; break; - case xRECT: if(xctx->rect[sel.col][sel.n].sel) already_selected = 1; break; - case ARC: if(xctx->arc[sel.col][sel.n].sel) already_selected = 1; break; - case ELEMENT: if(xctx->inst[sel.n].sel) already_selected = 1; break; - default: break; - } /*end switch */ - - /* Clicking and drag on an instance pin -> drag a new wire */ - if(xctx->intuitive_interface && !already_selected) { - if(add_wire_from_inst(&sel, xctx->mousex_snap, xctx->mousey_snap)) break; - } - - /* Clicking and drag on a wire end -> drag a new wire */ - if(xctx->intuitive_interface && !already_selected) { - if(add_wire_from_wire(&sel, xctx->mousex_snap, xctx->mousey_snap)) break; - } - - /* In intuitive interface a button1 press with no modifiers will - * unselect everything... we do it here */ - if(xctx->intuitive_interface && !already_selected && no_shift_no_ctrl ) unselect_all(1); - - /* select the object under the mouse and rebuild the selected array */ - if(!already_selected) select_object(xctx->mousex, xctx->mousey, SELECTED, 0, &sel); - rebuild_selected_array(); - dbg(1, "Button1Press to select objects, lastsel = %d\n", xctx->lastsel); - - /* if clicking on some object endpoints or vertices set shape_point_selected - * this information will be used in Motion events to draw the stretched vertices */ - if(xctx->lastsel == 1 && xctx->sel_array[0].type==POLYGON) { - if(edit_polygon_point(state)) break; /* sets xctx->shape_point_selected */ - } - if(xctx->lastsel == 1 && xctx->intuitive_interface) { - int cond = already_selected; - - if(cond && xctx->sel_array[0].type==xRECT) { - if(edit_rect_point(state)) break; /* sets xctx->shape_point_selected */ - } - - if(cond && xctx->sel_array[0].type==LINE) { - if(edit_line_point(state)) break; /* sets xctx->shape_point_selected */ - } - - if(cond && xctx->sel_array[0].type==WIRE) { - if(edit_wire_point(state)) break; /* sets xctx->shape_point_selected */ - } - } - dbg(1, "shape_point_selected=%d, lastsel=%d\n", xctx->shape_point_selected, xctx->lastsel); - - /* intuitive interface: directly drag elements */ - if(sel.type && xctx->intuitive_interface && xctx->lastsel >= 1 && - !xctx->shape_point_selected) { - /* enable_stretch (from TCL variable) reverses command if enabled: - * - move --> stretch move - * - stretch move (with ctrl key) --> move - */ - int stretch = (state & ControlMask ? 1 : 0) ^ enable_stretch; - xctx->drag_elements = 1; - /* select attached nets depending on ControlMask and enable_stretch */ - if(stretch) { - select_attached_nets(); /* stretch nets that land on selected instance pins */ - } - /* if dragging instances with stretch enabled and Shift down add wires to pins - * attached to something */ - if((state & ShiftMask) && stretch) { - xctx->connect_by_kissing = 2; /* 2 will be used to reset var to 0 at end of move */ - move_objects(START,0,0,0); - } - /* dragging away an object with Shift pressed is a copy (duplicate object) */ - else if(state & ShiftMask) copy_objects(START); - /* else it is a normal move */ - else move_objects(START,0,0,0); - } - - if(tclgetboolvar("auto_hilight") && !xctx->shape_point_selected) { - if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { - if(!prev_last_sel) { - redraw_hilights(1); /* 1: clear all hilights, then draw */ - } - } - hilight_net(0); - if(xctx->lastsel) { - redraw_hilights(0); - } - } - break; - } - } /* button==Button1 */ - break; + handle_button_press(event, state, rstate, key, button, mx, my, + c_snap, draw_xhair, crosshair_size, enable_stretch, aux); + break; case ButtonRelease: - if(waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } - xctx->ui_state &= ~DESEL_CLICK; - dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); - /* bring up context menu if no pending operation */ - if(state == Button3Mask && xctx->semaphore <2) { - if(!end_place_move_copy_zoom()) { - context_menu_action(xctx->mousex_snap, xctx->mousey_snap); - } - } + handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, draw_xhair, str); + break; - /* launcher, no intuitive interface */ - if(!xctx->intuitive_interface && state == (Button1Mask | ControlMask) && - !xctx->shape_point_selected && xctx->mouse_moved == 0) { - int savesem = xctx->semaphore; - xctx->semaphore = 0; - launcher(); /* works only if lastsel == 1 */ - xctx->semaphore = savesem; - } - - /* launcher, intuitive_interface, only if no movement has been done */ - else if(xctx->intuitive_interface && state == (Button1Mask | ControlMask) && - !xctx->shape_point_selected && (xctx->ui_state & STARTMOVE) && xctx->mouse_moved == 0) { - int savesem = xctx->semaphore; - move_objects(ABORT, 0, 0.0, 0.0); - unselect_all(1); - select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); - rebuild_selected_array(); - xctx->semaphore = 0; - launcher(); /* works only if lastsel == 1 */ - xctx->semaphore = savesem; - } - - /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && - (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { - if(end_place_move_copy_zoom()) break; - } - - /* end intuitive_interface copy or move */ - if(xctx->ui_state & STARTCOPY && xctx->drag_elements) { - copy_objects(END); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - xctx->drag_elements = 0; - } - else if(xctx->ui_state & STARTMOVE && xctx->drag_elements) { - move_objects(END,0,0,0); - xctx->constr_mv=0; - tcleval("set constr_mv 0" ); - xctx->drag_elements = 0; - } - - /* if a polygon/bezier/rectangle control point was clicked, end point move operation - * and set polygon state back to SELECTED from SELECTED1 */ - else if((xctx->ui_state & (STARTMOVE | SELECTION)) && xctx->shape_point_selected) { - end_shape_point_edit(c_snap); - } - - if(xctx->ui_state & STARTPAN) { - xctx->ui_state &=~STARTPAN; - /* xctx->mx_save = mx; xctx->my_save = my; */ - /* xctx->mx_double_save=xctx->mousex_snap; */ - /* xctx->my_double_save=xctx->mousey_snap; */ - redraw_w_a_l_r_p_z_rubbers(1); - break; - } - dbg(1, "callback(): ButtonRelease ui_state=%d state=%d\n",xctx->ui_state,state); - if(xctx->semaphore >= 2) break; - if(xctx->ui_state & STARTSELECT) { - if(state & ControlMask) { - select_rect(!enable_stretch, END,-1); - } else { - /* Button1 release: end of rectangle select */ - if(!(state & (Button4Mask|Button5Mask) ) ) { - select_rect(enable_stretch, END,-1); - } - } - xctx->ui_state &= ~DESEL_AREA; - rebuild_selected_array(); - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", - xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); - statusmsg(str,1); - } - - /* clear start from menu flag or infix_interface=0 start commands */ - if(xctx->ui_state & MENUSTART) { - xctx->ui_state &= ~MENUSTART; - break; - } - if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ - break; case -3: /* double click : edit prop */ if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); From 1753dc6723caaec0e568798b2a4efbbfc4fc1b7a Mon Sep 17 00:00:00 2001 From: Ananth Date: Mon, 10 Feb 2025 14:43:26 -0700 Subject: [PATCH 04/46] add handle_double_click --- src/callback.c | 70 +++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/callback.c b/src/callback.c index 9846e243..b4db2602 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4222,6 +4222,43 @@ void handle_button_release(int event, KeySym key, int state, int button, int mx, if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ } +void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux ) +{ + if( waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } else { + if(xctx->semaphore >= 2) return; + dbg(1, "callback(): DoubleClick ui_state=%d state=%d\n",xctx->ui_state,state); + if(button==Button1) { + Selected sel; + if(!xctx->lastsel && xctx->ui_state == 0) { + /* Following 5 lines do again a selection overriding lock, + * so locked instance attrs can be edited */ + sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 1, NULL); + if(sel.type) { + xctx->ui_state = SELECTION; + rebuild_selected_array(); + } + } + if(xctx->ui_state == 0 || xctx->ui_state == SELECTION) { + edit_property(0); + } else { + if(xctx->ui_state & STARTWIRE) { + xctx->ui_state &= ~STARTWIRE; + } + if(xctx->ui_state & STARTLINE) { + xctx->ui_state &= ~STARTLINE; + } + if( (xctx->ui_state & STARTPOLYGON) && (state ==0 ) ) { + new_polygon(SET, xctx->mousex_snap, xctx->mousey_snap); + } + } + } + } +} + + /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ /* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ @@ -4438,38 +4475,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case -3: /* double click : edit prop */ - if( waves_selected(event, key, state, button)) { - waves_callback(event, mx, my, key, button, aux, state); - break; - } else { - if(xctx->semaphore >= 2) break; - dbg(1, "callback(): DoubleClick ui_state=%d state=%d\n",xctx->ui_state,state); - if(button==Button1) { - Selected sel; - if(!xctx->lastsel && xctx->ui_state == 0) { - /* Following 5 lines do again a selection overriding lock, - * so locked instance attrs can be edited */ - sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 1, NULL); - if(sel.type) { - xctx->ui_state = SELECTION; - rebuild_selected_array(); - } - } - if(xctx->ui_state == 0 || xctx->ui_state == SELECTION) { - edit_property(0); - } else { - if(xctx->ui_state & STARTWIRE) { - xctx->ui_state &= ~STARTWIRE; - } - if(xctx->ui_state & STARTLINE) { - xctx->ui_state &= ~STARTLINE; - } - if( (xctx->ui_state & STARTPOLYGON) && (state ==0 ) ) { - new_polygon(SET, xctx->mousex_snap, xctx->mousey_snap); - } - } - } - } + handle_double_click(event, state, key, button, mx, my, aux); break; default: dbg(1, "callback(): Event:%d\n",event); From b7515c971556a2a987b0b58e4504e797abef0bca Mon Sep 17 00:00:00 2001 From: Ananth Date: Mon, 10 Feb 2025 14:52:19 -0700 Subject: [PATCH 05/46] add handle_enter_notify for readability --- src/callback.c | 62 +++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/callback.c b/src/callback.c index b4db2602..b722d42d 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2313,6 +2313,37 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke } #endif +void handle_enter_notify(int draw_xhair, int crosshair_size, struct stat *buf) +{ + dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); + xctx->mouse_inside = 1; + if(draw_xhair) { + if(crosshair_size == 0) { + tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); + } + } else + tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); + /* xschem window *sending* selected objects + when the pointer comes back in abort copy operation since it has been done + in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ + if(stat(sel_file, buf) && (xctx->ui_state & STARTCOPY) ) + { + copy_objects(ABORT); + unselect_all(1); + } + /* xschem window *receiving* selected objects selection cleared --> abort */ + else if(xctx->paste_from == 1 && stat(sel_file, buf) && (xctx->ui_state & STARTMERGE)) { + abort_operation(); + } + /*xschem window *receiving* selected objects + * no selected objects and selection file exists --> start merge */ + else if(xctx->lastsel == 0 && !stat(sel_file, buf)) { + xctx->mousex_snap = 490; + xctx->mousey_snap = -340; + merge_file(1, ".sch"); + } +} + void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, int mx, int my, int aux, int draw_xhair, char *str, int enable_stretch) { @@ -4359,7 +4390,7 @@ int rstate; /* (reduced state, without ShiftMask) */ state &= ~Mod2Mask; /* 20170511 filter out NumLock status */ state &= ~LockMask; /* filter out Caps Lock */ rstate = state; /* rstate does not have ShiftMask bit, so easier to test for KeyPress events */ - rstate &= ~ShiftMask; /* don't use ShiftMask, identifying characters is sifficient */ + rstate &= ~ShiftMask; /* don't use ShiftMask, identifying characters is sufficient */ rstate &= ~Button1Mask; /* ignore button-1 */ if(xctx->semaphore >= 2) { @@ -4396,33 +4427,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case EnterNotify: - dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); - xctx->mouse_inside = 1; - if(draw_xhair) { - if(crosshair_size == 0) { - tclvareval(xctx->top_path, ".drw configure -cursor none" , NULL); - } - } else - tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); - /* xschem window *sending* selected objects - when the pointer comes back in abort copy operation since it has been done - in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ - if(stat(sel_file, &buf) && (xctx->ui_state & STARTCOPY) ) - { - copy_objects(ABORT); - unselect_all(1); - } - /* xschem window *receiving* selected objects selection cleared --> abort */ - else if(xctx->paste_from == 1 && stat(sel_file, &buf) && (xctx->ui_state & STARTMERGE)) { - abort_operation(); - } - /*xschem window *receiving* selected objects - * no selected objects and selection file exists --> start merge */ - else if(xctx->lastsel == 0 && !stat(sel_file, &buf)) { - xctx->mousex_snap = 490; - xctx->mousey_snap = -340; - merge_file(1, ".sch"); - } + handle_enter_notify(draw_xhair, crosshair_size, &buf); break; case Expose: @@ -4477,6 +4482,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case -3: /* double click : edit prop */ handle_double_click(event, state, key, button, mx, my, aux); break; + default: dbg(1, "callback(): Event:%d\n",event); break; From d1c6f6e34269dccf5adddd65a6fec522730985ac Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Mon, 10 Feb 2025 23:36:21 +0100 Subject: [PATCH 06/46] added eval_expr.c to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0fe49d81..9d85221b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # bison output src/expandlabel.c src/expandlabel.h +src/eval_expr.c # flex output src/parselabel.c src/parselabel.h @@ -39,4 +40,4 @@ scconfig/config.cache doc/manpages/xschem.1 Makefile.conf config.h -*.Identifier \ No newline at end of file +*.Identifier From a4e0471fcc163829b4c1d01107e1990756172ad2 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Tue, 11 Feb 2025 00:16:06 +0100 Subject: [PATCH 07/46] minor changes to callback() refactoring to remove compiler warnings --- src/callback.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/callback.c b/src/callback.c index b722d42d..5a517143 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2313,8 +2313,9 @@ static int grabscreen(const char *win_path, int event, int mx, int my, KeySym ke } #endif -void handle_enter_notify(int draw_xhair, int crosshair_size, struct stat *buf) +static void handle_enter_notify(int draw_xhair, int crosshair_size) { + struct stat buf; dbg(2, "callback(): Enter event, ui_state=%d\n", xctx->ui_state); xctx->mouse_inside = 1; if(draw_xhair) { @@ -2326,25 +2327,25 @@ void handle_enter_notify(int draw_xhair, int crosshair_size, struct stat *buf) /* xschem window *sending* selected objects when the pointer comes back in abort copy operation since it has been done in another xschem xctx->window; STARTCOPY set and selection file does not exist any more */ - if(stat(sel_file, buf) && (xctx->ui_state & STARTCOPY) ) + if(stat(sel_file, &buf) && (xctx->ui_state & STARTCOPY) ) { copy_objects(ABORT); unselect_all(1); } /* xschem window *receiving* selected objects selection cleared --> abort */ - else if(xctx->paste_from == 1 && stat(sel_file, buf) && (xctx->ui_state & STARTMERGE)) { + else if(xctx->paste_from == 1 && stat(sel_file, &buf) && (xctx->ui_state & STARTMERGE)) { abort_operation(); } /*xschem window *receiving* selected objects * no selected objects and selection file exists --> start merge */ - else if(xctx->lastsel == 0 && !stat(sel_file, buf)) { + else if(xctx->lastsel == 0 && !stat(sel_file, &buf)) { xctx->mousex_snap = 490; xctx->mousey_snap = -340; merge_file(1, ".sch"); } } -void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, +static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, int mx, int my, int aux, int draw_xhair, char *str, int enable_stretch) { if( waves_selected(event, key, state, button)) { @@ -2367,7 +2368,7 @@ void handle_motion_notify(int event, KeySym key, int state, int rstate, int butt /* update status bar messages */ if(xctx->ui_state) { if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", + my_snprintf(str, PATH_MAX + 100, "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel , xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save @@ -2463,7 +2464,7 @@ void handle_motion_notify(int event, KeySym key, int state, int rstate, int butt } } -void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, +static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, char *str ) { if(key==' ') { @@ -3167,11 +3168,11 @@ void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int if(xctx->semaphore >= 2) return; rebuild_selected_array(); if(xctx->lastsel==0 ) { - my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + my_snprintf(str, PATH_MAX + 100, "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); tcleval(str); } else if(xctx->sel_array[0].type==ELEMENT) { - my_snprintf(str, S(str), "edit_file {%s}", + my_snprintf(str, PATH_MAX + 100, "edit_file {%s}", abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); tcleval(str); @@ -3294,7 +3295,7 @@ void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int if(exists) { if(!tool) { tool = tclgetintvar("sim(spicewave,default)"); - my_snprintf(str, S(str), "sim(spicewave,%d,name)", tool); + my_snprintf(str, PATH_MAX + 100, "sim(spicewave,%d,name)", tool); my_strdup(_ALLOC_ID_, &tool_name, tclgetvar(str)); dbg(1,"callback(): tool_name=%s\n", tool_name); if(strstr(tool_name, "Gaw")) tool=GAW; @@ -3318,7 +3319,7 @@ void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int } if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ { - my_snprintf(str, S(str), + my_snprintf(str, PATH_MAX + 100, "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", CADSNAP, c_snap, c_snap); tcleval(str); @@ -3922,7 +3923,7 @@ void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int } } -void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, +static void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux ) { dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); @@ -4155,7 +4156,7 @@ void handle_button_press(int event, int state, int rstate, KeySym key, int butto } /* button==Button1 */ } -void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, +static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, int aux, double c_snap, int enable_stretch, int draw_xhair, char *str) { if(waves_selected(event, key, state, button)) { @@ -4240,7 +4241,7 @@ void handle_button_release(int event, KeySym key, int state, int button, int mx, } xctx->ui_state &= ~DESEL_AREA; rebuild_selected_array(); - my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", + my_snprintf(str, PATH_MAX + 100, "mouse = %.16g %.16g - selected: %d path: %s", xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); statusmsg(str,1); } @@ -4253,7 +4254,7 @@ void handle_button_release(int event, KeySym key, int state, int button, int mx, if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ } -void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux ) +static void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux ) { if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); @@ -4297,7 +4298,6 @@ int callback(const char *win_path, int event, int mx, int my, KeySym key, int button, int aux, int state) { char str[PATH_MAX + 100]; - struct stat buf; int redraw_only; double c_snap; #ifndef __unix__ @@ -4427,7 +4427,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case EnterNotify: - handle_enter_notify(draw_xhair, crosshair_size, &buf); + handle_enter_notify(draw_xhair, crosshair_size); break; case Expose: From 8cad7daed5690f0ef4bf8acd5eabcfaf05149fdd Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Tue, 11 Feb 2025 11:11:20 +0100 Subject: [PATCH 08/46] removed `str` parameter to all handle_* functions in callback.c (write-only) --- src/callback.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/callback.c b/src/callback.c index 5a517143..114461b0 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2346,8 +2346,9 @@ static void handle_enter_notify(int draw_xhair, int crosshair_size) } static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, - int mx, int my, int aux, int draw_xhair, char *str, int enable_stretch) + int mx, int my, int aux, int draw_xhair, int enable_stretch) { + char str[PATH_MAX + 100]; if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); return; @@ -2368,7 +2369,7 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i /* update status bar messages */ if(xctx->ui_state) { if(abs(mx-xctx->mx_save) > 8 || abs(my-xctx->my_save) > 8 ) { - my_snprintf(str, PATH_MAX + 100, "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d w=%.6g h=%.6g", xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel , xctx->mousex_snap-xctx->mx_double_save, xctx->mousey_snap-xctx->my_double_save @@ -2465,8 +2466,9 @@ static void handle_motion_notify(int event, KeySym key, int state, int rstate, i } static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, - int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap, char *str ) + int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap) { + char str[PATH_MAX + 100]; if(key==' ') { if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); @@ -3168,11 +3170,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m if(xctx->semaphore >= 2) return; rebuild_selected_array(); if(xctx->lastsel==0 ) { - my_snprintf(str, PATH_MAX + 100, "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(xctx->sch[xctx->currsch], "")); tcleval(str); } else if(xctx->sel_array[0].type==ELEMENT) { - my_snprintf(str, PATH_MAX + 100, "edit_file {%s}", + my_snprintf(str, S(str), "edit_file {%s}", abs_sym_path(tcl_hook2(xctx->inst[xctx->sel_array[0].n].name), "")); tcleval(str); @@ -3279,7 +3281,6 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m int tool = 0; int exists = 0; char *tool_name = NULL; - char str[200]; if(xctx->semaphore >= 2) return; tcleval("winfo exists .graphdialog"); @@ -3319,7 +3320,7 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m } if(key=='g' && rstate==ControlMask) /* set snap factor 20161212 */ { - my_snprintf(str, PATH_MAX + 100, + my_snprintf(str, S(str), "input_line {Enter snap value (default: %.16g current: %.16g)} {xschem set cadsnap} {%g} 10", CADSNAP, c_snap, c_snap); tcleval(str); @@ -4157,8 +4158,9 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, - int aux, double c_snap, int enable_stretch, int draw_xhair, char *str) + int aux, double c_snap, int enable_stretch, int draw_xhair) { + char str[PATH_MAX + 100]; if(waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); return; @@ -4241,7 +4243,7 @@ static void handle_button_release(int event, KeySym key, int state, int button, } xctx->ui_state &= ~DESEL_AREA; rebuild_selected_array(); - my_snprintf(str, PATH_MAX + 100, "mouse = %.16g %.16g - selected: %d path: %s", + my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); statusmsg(str,1); } @@ -4459,7 +4461,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case MotionNotify: - handle_motion_notify(event, key, state, rstate, button, mx, my, aux, draw_xhair, str, enable_stretch); + handle_motion_notify(event, key, state, rstate, button, mx, my, aux, draw_xhair, enable_stretch); break; case KeyRelease: @@ -4467,7 +4469,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case KeyPress: handle_key_press(event, key, state, rstate, mx, my, button, aux, - infix_interface, enable_stretch, win_path, c_snap, str); + infix_interface, enable_stretch, win_path, c_snap); break; case ButtonPress: @@ -4476,7 +4478,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case ButtonRelease: - handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, draw_xhair, str); + handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, draw_xhair); break; case -3: /* double click : edit prop */ From 2eeeebf715bab6f9b11e25228bd3fce8f4b3ee0a Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Tue, 11 Feb 2025 18:52:24 +0100 Subject: [PATCH 09/46] avoid calling Tcl_GetErrorLine() if tcl version < 8.6 --- src/xinit.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/xinit.c b/src/xinit.c index 0ee4bca2..9db98f91 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -1174,12 +1174,27 @@ static int source_tcl_file(char *s) if(Tcl_EvalFile(interp, s)==TCL_ERROR) { fprintf(errfp, "Tcl_AppInit() error: can not execute %s, please fix:\n", s); + + + + #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp)); + #endif + + + fprintf(errfp, "%s", tclresult()); fprintf(errfp, "\n"); + + #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 my_snprintf(tmp, S(tmp), "tk_messageBox -icon error -type ok -message \ {Tcl_AppInit() err 1: can not execute %s, please fix:\n%s\nLine No: %d\n}", s, tclresult(), Tcl_GetErrorLine(interp)); + #else + my_snprintf(tmp, S(tmp), "tk_messageBox -icon error -type ok -message \ + {Tcl_AppInit() err 1: can not execute %s, please fix:\n%s\n}", + s, tclresult()); + #endif if(has_x) { tcleval( "wm withdraw ."); tcleval( tmp); From bf10a025d7eb106e082cbf2f33ca9ba9847b8730 Mon Sep 17 00:00:00 2001 From: Ananth Date: Tue, 11 Feb 2025 10:55:29 -0700 Subject: [PATCH 10/46] added CD's vars - ortho wiring, snap_cursor, snap_cur size, cadence_compat - all not yet used; use_cursor_for_selection - used; updated xschem.tcl to include in global list and set defaults; callback updated to use use_cursor_for_sel when mouse clicked --- src/callback.c | 3 ++- src/xschem.tcl | 8 +++++++- src/xschemrc | 13 +++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 114461b0..133fe31b 100644 --- a/src/callback.c +++ b/src/callback.c @@ -3927,6 +3927,7 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m static void handle_button_press(int event, int state, int rstate, KeySym key, int button, int mx, int my, double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux ) { + int use_cursor_for_sel = tclgetintvar("use_cursor_for_selection"); dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); if(waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); @@ -4057,7 +4058,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in /* find closest object. Use snap coordinates if full crosshair is enabled * since the mouse pointer is obscured and crosshair is snapped to grid points */ - if(draw_xhair && crosshair_size == 0) { + if(draw_xhair && (use_cursor_for_sel || crosshair_size == 0)) { sel = find_closest_obj(xctx->mousex_snap, xctx->mousey_snap, 0); } else { sel = find_closest_obj(xctx->mousex, xctx->mousey, 0); diff --git a/src/xschem.tcl b/src/xschem.tcl index 807cbcd7..41fd2800 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -7768,7 +7768,8 @@ set tctx::global_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 + tctx::vsize xschem_libs xschem_listen_port zoom_full_center orthogonal_wiring snap_cursor + snap_cursor_size cadence_compat use_cursor_for_selection } ## list of global arrays to save/restore on context switching @@ -9220,6 +9221,11 @@ set_ne draw_grid_axes 1 set_ne persistent_command 0 set_ne intuitive_interface 1 set_ne infix_interface 1 +set_ne orthogonal_wiring 0 +set_ne snap_cursor 0 +set_ne snap_cursor_size 6 +set_ne cadence_compat 0 +set_ne use_cursor_for_selection 0 set_ne autotrim_wires 0 set_ne compare_sch 0 set_ne disable_unique_names 0 diff --git a/src/xschemrc b/src/xschemrc index 0d1e0bb3..f6dbf330 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -273,6 +273,19 @@ #### set crosshair size; Default: 0 (full screen spanning crosshair) # set crosshair_size 5 +#### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) +# set snap_cursor 1 + +#### set snap_cursor_size; Default: 6 (Diamond-shaped cursor that snaps to nearest circuit endpoint) +# set snap_cursor_size 6 + +#### set cadence_compat; Default: 0 (Cadence-style keybinds are not used by default) +# set cadence_compat 1 + +#### if set, then, when cursor (regardless of style) is on an object, and user clicks (though mouse pointer is not on the object), +#### the object is selected. Default: 0 +# set use_cursor_for_selection 1 + #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 From 66ec47ccfbde97698400fc8072422430ca2332d5 Mon Sep 17 00:00:00 2001 From: Ananth Date: Tue, 11 Feb 2025 11:49:50 -0700 Subject: [PATCH 11/46] only vars and fn defs (not calls) and inits added for ortho routing and snap cursor --- src/callback.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++- src/xinit.c | 3 ++ src/xschem.h | 4 ++ 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index 133fe31b..66d5eb1e 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,6 +21,7 @@ */ #include "xschem.h" +#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) @@ -1499,6 +1500,89 @@ void draw_crosshair(int what, int state) xctx->draw_pixmap = sdp; } +void find_snap_position(double *x, double *y, bool 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); + } +} + +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; + + // Define crosshair lines + double lines[4][4] = { + {screen_x, top, right, screen_y}, // Top to right + {right, screen_y, screen_x, bottom}, // Right to bottom + {screen_x, bottom, left, screen_y}, // Bottom to left + {left, screen_y, screen_x, top} // Left to top + }; + + // Draw crosshair lines + for (int i = 0; i < 4; i++) { + draw_xhair_line(gc, snapcursor_size, lines[i][0], lines[i][1], lines[i][2], lines[i][3]); + } +} + +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); + } +} + + +/* action = 1 => erase */ +void draw_snap_cursor(int action) { + if (!xctx->mouse_inside) return; // Early exit if mouse is outside + + int snapcursor_size = tclgetintvar("snap_cursor_size"); + bool pos_changed = (xctx->mousex_snap != xctx->prev_gridx) || (xctx->mousey_snap != xctx->prev_gridy); + + // Save current drawing context + int prev_draw_window = xctx->draw_window; + int prev_draw_pixmap = xctx->draw_pixmap; + xctx->draw_pixmap = 0; + xctx->draw_window = 1; + + // Erase and redraw the cursor if needed + if (action & 1) { + erase_snap_cursor(xctx->prev_snapx, xctx->prev_snapy, snapcursor_size); + + 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; + } + + draw_selection(xctx->gc[SELLAYER], 0); + + // Restore previous drawing context + xctx->draw_window = prev_draw_window; + xctx->draw_pixmap = prev_draw_pixmap; +} + /* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ static int end_place_move_copy_zoom() { @@ -2469,6 +2553,8 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m int button, int aux, int infix_interface, int enable_stretch, const char *win_path, double c_snap) { char str[PATH_MAX + 100]; + int cadence_compat = tclgetboolvar("cadence_compat"); + int snap_cursor = tclgetboolvar("snap_cursor"); if(key==' ') { if(xctx->ui_state & STARTWIRE) { /* & instead of == 20190409 */ new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); @@ -2703,7 +2789,7 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m hilight_net_pin_mismatches(); return; } - if(key== 'W' /* && !xctx->ui_state */ && rstate == 0) { /* create wire snapping to closest instance pin */ + if(key== 'W' /* && !xctx->ui_state */ && rstate == 0 && !cadence_compat) { /* create wire snapping to closest instance pin */ if(xctx->semaphore >= 2) return; if(infix_interface) { snapped_wire(c_snap); @@ -2713,6 +2799,11 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m } return; } + if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ + if(xctx->semaphore >= 2) return; + snapped_wire(c_snap); + return; + } if(key == 'w' /* && !xctx->ui_state */ && rstate==0) /* place wire. */ { int prev_state = xctx->ui_state; @@ -2742,6 +2833,13 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m } /* stuff that can be done reentrantly ... */ tclsetvar("tclstop", "1"); /* stop simulation if any running */ + if(xctx->ui_state2 & MENUSTARTWIRE) { + xctx->ui_state2 &= ~MENUSTARTWIRE; + } + if(tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE) && cadence_compat) { + xctx->last_command &= ~STARTWIRE; + if(snap_cursor) draw_snap_cursor(1); + } return; } if(key=='z' && rstate == 0 && @@ -2946,7 +3044,26 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m draw(); /* needed to ungrey or grey out components due to *_ignore attribute */ return; } - if(key=='s' && rstate == 0 ) /* simulate */ + if(key== 's' /* && !xctx->ui_state */ && rstate == 0 && cadence_compat) { /* create wire snapping to closest instance pin (cadence keybind) */ + if(xctx->semaphore >= 2) return; + snapped_wire(c_snap); + return; + } + if((key=='s' && rstate == 0) && !cadence_compat) /* simulate, original binding for s */ + { + if(xctx->semaphore >= 2) return; + if(waves_selected(event, key, state, button)) { + waves_callback(event, mx, my, key, button, aux, state); + return; + } + tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] " + "-message {Run circuit simulation?}"); + if(strcmp(tclresult(),"ok")==0) { + tcleval("[xschem get top_path].menubar invoke Simulate"); + } + return; + } + if((key=='r' && rstate == ControlMask) && cadence_compat) /* simulate (for cadence users) */ { if(xctx->semaphore >= 2) return; if(waves_selected(event, key, state, button)) { diff --git a/src/xinit.c b/src/xinit.c index 0ee4bca2..5e1a83f3 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -648,6 +648,9 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->prev_crossx = xctx->prev_crossy = 0.0; xctx->prev_m_crossx = xctx->prev_m_crossy = 0.0; xctx->prev_rubberx = xctx->prev_rubbery = 0.0; + xctx->prev_gridx = xctx->prev_gridy = 0.0; + xctx->prev_snapx = xctx->prev_snapy = 0.0; + xctx->closest_pin_found = 0; xctx->mouse_inside = 0; xctx->pending_fullzoom = 0; my_strncpy(xctx->hiersep, ".", S(xctx->hiersep)); diff --git a/src/xschem.h b/src/xschem.h index 5f988205..59802adf 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1056,6 +1056,9 @@ typedef struct { /* draw_crosshair */ double prev_crossx, prev_crossy; /* previous closest net/pin found by draw_crosshair() */ double prev_m_crossx, prev_m_crossy; /* previous snap mouse position processed by draw_crosshair() */ + double prev_gridx, prev_gridy; + double prev_snapx, prev_snapy; + int closest_pin_found; int mouse_inside; /* set_modify */ int prev_set_modify; @@ -1397,6 +1400,7 @@ 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 int callback(const char *win_path, int event, int mx, int my, KeySym key, From 2a7a461ace3ee1dd302ede7989407fabe9865f53 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Tue, 11 Feb 2025 20:38:17 +0100 Subject: [PATCH 12/46] update verilogA example tb_diff_amp.sch --- src/xinit.c | 9 +-------- xschem_library/ngspice/diff_amp.sym | 16 ++++++++-------- xschem_library/ngspice/tb_diff_amp.sch | 23 +++++++++++------------ 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/xinit.c b/src/xinit.c index 9db98f91..4c22fa44 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -1174,18 +1174,11 @@ static int source_tcl_file(char *s) if(Tcl_EvalFile(interp, s)==TCL_ERROR) { fprintf(errfp, "Tcl_AppInit() error: can not execute %s, please fix:\n", s); - - - + fprintf(errfp, "%s", tclresult()); #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp)); #endif - - - - fprintf(errfp, "%s", tclresult()); fprintf(errfp, "\n"); - #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 my_snprintf(tmp, S(tmp), "tk_messageBox -icon error -type ok -message \ {Tcl_AppInit() err 1: can not execute %s, please fix:\n%s\nLine No: %d\n}", diff --git a/xschem_library/ngspice/diff_amp.sym b/xschem_library/ngspice/diff_amp.sym index 1d16a1d0..93676b81 100644 --- a/xschem_library/ngspice/diff_amp.sym +++ b/xschem_library/ngspice/diff_amp.sym @@ -21,21 +21,21 @@ v {xschem version=3.4.6 file_version=1.2 } G {} K {type=opamp_va -format="@name @@OUT @@IN1 @@IN2 @model" +format="@name @@OUT @@IN1 @@IN2 @model gain=@gain amplitude=@amplitude offset=@offset" -template="name=X1 model=diff_amp_cell" +template="name=X1 model=diff_amp_cell gain=40 amplitude=3 offset=1.5" device_model="tcleval( -.subckt diff_amp_cell OUT IN1 IN2 -N1 out in1 in2 diff_amp_model -.ends diff_amp_cell - -.model diff_amp_model diff_amp - .control * following line specifies the location for the .osdi file so ngspice can use it. pre_osdi $USER_CONF_DIR/xschem_library/diff_amp.osdi .endc + +.model diff_amp_model diff_amp $ gain=40 amplitude=3 offset=1.5 + +.subckt diff_amp_cell OUT IN1 IN2 gain=40 amplitude=3 offset=1.5 +N1 out in1 in2 diff_amp_model gain=gain amplitude=amplitude offset=offset +.ends diff_amp_cell )" } V {} diff --git a/xschem_library/ngspice/tb_diff_amp.sch b/xschem_library/ngspice/tb_diff_amp.sch index 3c0fc396..3d02e9a5 100644 --- a/xschem_library/ngspice/tb_diff_amp.sch +++ b/xschem_library/ngspice/tb_diff_amp.sch @@ -25,8 +25,8 @@ V {} S {} E {} B 2 840 -580 1640 -170 {flags=graph -y1=0 -y2=6 +y1=6.3e-14 +y2=5 ypos1=0 ypos2=2 divy=5 @@ -49,7 +49,7 @@ logy=0 } B 2 840 -990 1640 -580 {flags=graph y1=0 -y2=40 +y2=100 ypos1=0 ypos2=2 divy=5 @@ -68,10 +68,9 @@ unitx=1 logx=0 logy=0 } -P 4 5 140 -600 140 -880 710 -880 710 -600 140 -600 {} +P 4 5 30 -600 30 -880 740 -880 740 -600 30 -600 {} P 4 7 410 -600 410 -560 420 -560 410 -540 400 -560 410 -560 410 -600 {} T {// importing libs - `include "discipline.h" module diff_amp( @@ -79,17 +78,17 @@ module diff_amp( input electrical in1, input electrical in2); -parameter real gain = 40; // setting gain to 40 of the differential amplifier -parameter real vcc = 3; // swing from -vcc/2 to +vcc/2 -parameter real offset = 3;// added offset +(* desc="gain", units="", type="instance" *) parameter real gain = 40 from [-inf: inf]; +(* desc="amplitude", units="", type="instance" *) parameter real amplitude = 3 from [-inf: inf]; +(* desc="offset", units="", type="instance" *) parameter real offset = 1.5 from [-inf: inf]; analog begin - V(out) <+ offset / 2 + vcc / 2 * tanh( gain / vcc * 2 * V(in1, in2)); + V(out) <+ offset + amplitude / 2 * tanh( gain / amplitude * 2 * V(in1, in2)); end endmodule -} 150 -870 0 0 0.2 0.2 {font=monospace} +} 40 -870 0 0 0.2 0.2 {font=monospace} T {create a diff_amp.va file with following code and compile it into a .osdi file with openvaf.} 190 -940 0 0 0.4 0.4 {} N 180 -450 320 -450 {lab=B} @@ -100,7 +99,6 @@ N 180 -330 180 -290 {lab=0} N 80 -330 80 -290 {lab=0} N 80 -530 80 -390 {lab=A} N 180 -450 180 -390 {lab=B} -C {diff_amp.sym} 420 -490 0 0 {name=X1} C {lab_pin.sym} 640 -490 0 1 {name=p1 sig_type=std_logic lab=Z} C {lab_pin.sym} 80 -530 0 0 {name=p2 sig_type=std_logic lab=A} C {lab_pin.sym} 180 -450 0 0 {name=p3 sig_type=std_logic lab=B} @@ -118,7 +116,7 @@ C {code_shown.sym} 240 -320 0 0 {name=COMMANDS only_toplevel=false value=" set appendwrite remzerovec write tb_diff_amp.raw - quit 0 + * quit 0 .endc "} C {launcher.sym} 670 -120 0 0 {name=h5 @@ -130,3 +128,4 @@ C {launcher.sym} 670 -170 0 0 {name=h1 descr="OP annotate" tclcommand="xschem annotate_op" } +C {diff_amp.sym} 420 -490 0 0 {name=X1 model=diff_amp_cell gain=100 amplitude=5 offset=2.5} From 3adcf40bf7eae4efcf5fa6d914faeff0c0124b76 Mon Sep 17 00:00:00 2001 From: Ananth Date: Tue, 11 Feb 2025 12:44:14 -0700 Subject: [PATCH 13/46] added remaining edits from CD's repo. Tests ok. --- src/callback.c | 67 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/src/callback.c b/src/callback.c index 66d5eb1e..a9a8531d 100644 --- a/src/callback.c +++ b/src/callback.c @@ -110,6 +110,17 @@ void redraw_w_a_l_r_p_z_rubbers(int force) if(xctx->ui_state & STARTWIRE) { if(xctx->constr_mv == 1) my = xctx->my_double_save; if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + if(tclgetboolvar("orthogonal_wiring")) { + new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); + /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ + int origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1, origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; + /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ + if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2){ + xctx->manhattan_lines = 1; + } else { + xctx->manhattan_lines = 2; + } + } new_wire(RUBBER, mx, my); } if(xctx->ui_state & STARTARC) { @@ -220,6 +231,11 @@ static void start_wire(double mx, double my) xctx->ui_state, xctx->ui_state2, xctx->last_command); xctx->last_command = STARTWIRE; if(xctx->ui_state & STARTWIRE) { + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = xctx->manhattan_lines; + new_wire(CLEAR, mx, my); + redraw_w_a_l_r_p_z_rubbers(1); + } if(xctx->constr_mv != 2) { xctx->mx_double_save = mx; } @@ -233,6 +249,10 @@ static void start_wire(double mx, double my) xctx->my_double_save=my; } new_wire(PLACE,mx, my); + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = 0; + } + } static double interpolate_yval(int idx, int p, double x, int sweep_idx, int point_not_last) @@ -1690,6 +1710,7 @@ void snapped_wire(double c_snap) new_wire(PLACE|END, x, y); xctx->constr_mv=0; tcleval("set constr_mv 0" ); + if((xctx->ui_state & MENUSTART) && !tclgetboolvar("persistent_command") ) xctx->ui_state &= ~MENUSTART; /*CD*/ } } @@ -2430,7 +2451,7 @@ static void handle_enter_notify(int draw_xhair, int crosshair_size) } static void handle_motion_notify(int event, KeySym key, int state, int rstate, int button, - int mx, int my, int aux, int draw_xhair, int enable_stretch) + int mx, int my, int aux, int draw_xhair, int enable_stretch, int snap_cursor, int wire_draw_active) { char str[PATH_MAX + 100]; if( waves_selected(event, key, state, button)) { @@ -2439,6 +2460,7 @@ 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); } /* pan schematic */ if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my); @@ -2447,6 +2469,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); return; } @@ -2547,6 +2570,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); } static void handle_key_press(int event, KeySym key, int state, int rstate, int mx, int my, @@ -4138,8 +4162,19 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in /* start another wire or line in persistent mode */ if(tclgetboolvar("persistent_command") && xctx->last_command) { if(xctx->last_command == STARTLINE) start_line(xctx->mousex_snap, xctx->mousey_snap); - if(xctx->last_command == STARTWIRE) start_wire(xctx->mousex_snap, xctx->mousey_snap); - return; + if(xctx->last_command == STARTWIRE){ + if(tclgetboolvar("snap_cursor") + && (xctx->prev_snapx == xctx->mousex_snap + && xctx->prev_snapy == xctx->mousey_snap) + && (xctx->ui_state & STARTWIRE) + && xctx->closest_pin_found){ + new_wire(PLACE|END, xctx->mousex_snap, xctx->mousey_snap); + xctx->ui_state &= ~STARTWIRE; + } + else + start_wire(xctx->mousex_snap, xctx->mousey_snap); + } + return; } /* handle all object insertions started from Tools/Edit menu */ if(check_menu_start_commands(c_snap, mx, my)) return; @@ -4276,7 +4311,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } static void handle_button_release(int event, KeySym key, int state, int button, int mx, int my, - int aux, double c_snap, int enable_stretch, int draw_xhair) + int aux, double c_snap, int enable_stretch, int draw_xhair, int snap_cursor, int wire_draw_active) { char str[PATH_MAX + 100]; if(waves_selected(event, key, state, button)) { @@ -4315,8 +4350,8 @@ static void handle_button_release(int event, KeySym key, int state, int button, } /* end wire creation when dragging in intuitive interface from an inst pin or wire endpoint */ - else if(state == Button1Mask && xctx->intuitive_interface && - (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { + else if(state == Button1Mask && xctx->intuitive_interface && !tclgetboolvar("persistent_command") + && (xctx->ui_state & STARTWIRE) && !(xctx->ui_state & MENUSTART)) { if(end_place_move_copy_zoom()) return; } @@ -4372,9 +4407,10 @@ static void handle_button_release(int event, KeySym key, int state, int button, return; } if(draw_xhair) draw_crosshair(3, state); /* restore crosshair when selecting / unselecting */ + if(snap_cursor && wire_draw_active) draw_snap_cursor(3); } -static void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux ) +static void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux, int cadence_compat ) { if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); @@ -4397,6 +4433,10 @@ static void handle_double_click(int event, int state, KeySym key, int button, in edit_property(0); } else { if(xctx->ui_state & STARTWIRE) { + if( cadence_compat ) { + redraw_w_a_l_r_p_z_rubbers(1); + start_wire(mx, my); + } xctx->ui_state &= ~STARTWIRE; } if(xctx->ui_state & STARTLINE) { @@ -4431,6 +4471,11 @@ int draw_xhair = tclgetboolvar("draw_crosshair"); int crosshair_size = tclgetintvar("crosshair_size"); int infix_interface = tclgetboolvar("infix_interface"); int rstate; /* (reduced state, without ShiftMask) */ +int snap_cursor = tclgetboolvar("snap_cursor"); +int cadence_compat = tclgetboolvar("cadence_compat"); +int wire_draw_active = (xctx->ui_state & STARTWIRE) || + ((xctx->ui_state2 & MENUSTARTWIRE) && (xctx->ui_state & MENUSTART)) || + (tclgetboolvar("persistent_command") && (xctx->last_command & STARTWIRE)); /* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease * events. Some remote connection softwares do not generate the correct coordinates @@ -4542,6 +4587,7 @@ int rstate; /* (reduced state, without ShiftMask) */ case LeaveNotify: if(draw_xhair) draw_crosshair(1, state); /* clear crosshair when exiting window */ + if(snap_cursor && wire_draw_active) draw_snap_cursor(1); tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL); xctx->mouse_inside = 0; break; @@ -4579,7 +4625,8 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case MotionNotify: - handle_motion_notify(event, key, state, rstate, button, mx, my, aux, draw_xhair, enable_stretch); + handle_motion_notify(event, key, state, rstate, button, mx, my, + aux, draw_xhair, enable_stretch, snap_cursor, wire_draw_active); break; case KeyRelease: @@ -4596,11 +4643,11 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case ButtonRelease: - handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, draw_xhair); + handle_button_release(event, key, state, button, mx, my, aux, c_snap, enable_stretch, draw_xhair, snap_cursor, wire_draw_active); break; case -3: /* double click : edit prop */ - handle_double_click(event, state, key, button, mx, my, aux); + handle_double_click(event, state, key, button, mx, my, aux, cadence_compat); break; default: From 99f0e528bfb05ba22b9654dc956305aa258f4778 Mon Sep 17 00:00:00 2001 From: Ananth Date: Tue, 11 Feb 2025 12:51:12 -0700 Subject: [PATCH 14/46] add RC file to help Cadence users --- src/cadence_style_rc | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/cadence_style_rc diff --git a/src/cadence_style_rc b/src/cadence_style_rc new file mode 100644 index 00000000..4086e2e2 --- /dev/null +++ b/src/cadence_style_rc @@ -0,0 +1,10 @@ +# run with $> xschem --script /path/to/cadence_style_rc +set draw_crosshair 1 +set crosshair_size 2 +set infix_interface 0 +set cadence_compat 1 +set orthogonal_wiring 1 +set snap_cursor 1 +set snap_cursor_size 4 +set persistent_command 1 +set use_cursor_for_selection 1 From 5f8c08d7deabf4a409fd57c5398a715e571a70f9 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 00:32:12 +0100 Subject: [PATCH 15/46] eval_expr: CHAR token renamed to XCHAR to avoid name clashes. print_spice_element(): if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance. Same for vhdl and verilog primitives. Fixed a typo in get_sp_cur regex (token.c) --- src/eval_expr.y | 8 ++--- src/token.c | 95 ++++++++++++++++++++++++++++++------------------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/src/eval_expr.y b/src/eval_expr.y index ba954f26..26f8d21d 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -63,7 +63,7 @@ symrec *tptr; /* For returning symbol-table pointers */ } %token STREND 0 -%token CHAR +%token XCHAR %token EXPR /* expr( */ %token NUM /* Simple double precision number */ %token FNCT /* Variable and Function */ @@ -81,7 +81,7 @@ input: ; line: - CHAR {get_char($1);} + XCHAR {get_char($1);} | EXPR exp ')' {get_expr($2);lex_state = 0;} | EXPR '\'' exp '\'' ')' {get_expr($3);lex_state = 0;} | EXPR exp error @@ -216,8 +216,8 @@ static int kklex() c = *str++; if(c) { kklval.c = c; - dbg(dbglev, "lex(): CHAR; %c\n", c); - return CHAR; + dbg(dbglev, "lex(): XCHAR; %c\n", c); + return XCHAR; } else { dbg(dbglev, "lex(): STREND\n"); return STREND; diff --git a/src/token.c b/src/token.c index 4a067718..aa4d5da5 100644 --- a/src/token.c +++ b/src/token.c @@ -1174,26 +1174,34 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 if(c=='\0') { - /* do one level of substitutions to resolve remaining @params and/or tcl expr/code */ - if(result) { - dbg(1, "print_vhdl_primitive(): before translate() result=%s\n", result); - if(!strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - /* since netlist_commands often have @ characters in spice node save / plot commands, do - * not pass through translate, unless a tcleval(...) is present */ - if(strstr(result, "tcleval(")== result) { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); - } - } else { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); - } - dbg(1, "print_vhdl_primitive(): after translate() result=%s\n", result); - } - if(result) fprintf(fd, "%s", result); - fputc('\n',fd); - fprintf(fd, "---- end primitive\n"); - break ; + /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions + * can be calculated. Before that do also a round of translation to remove remaining @params */ + if(result) { + dbg(1, "print_verilog_primitive(): before translate3() result=%s\n", result); + if(strchr(result, '@')) { + /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ + if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); + /* can not put template in above translate3: ------------------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(result, '@')) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + } + } + } + my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */ + if(strstr(result, "expr(") ) { + result = eval_expr(result); + } + dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result); + } + if(result) fprintf(fd, "%s", result); + fputc('\n',fd); + fprintf(fd, "---- end primitive\n"); + break ; } - } + } /* while(1) */ my_free(_ALLOC_ID_, &result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); @@ -2398,7 +2406,13 @@ int print_spice_element(FILE *fd, int inst) * model=nfet_01v8 */ my_strdup2(_ALLOC_ID_, &val, - translate3(token, 2, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); + translate3(token, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, NULL, NULL)); + /* can not put template in above translate3: ---------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(val, '@')) { + my_strdup2(_ALLOC_ID_, &val, translate3(val, 0, template, NULL, NULL, NULL)); + } /* nmos instance format string: @model --> @modeln */ dbg(1, "print_spice_element(): 1st round: val: |%s|\n", val); if(strchr(val, '@')) { @@ -2428,12 +2442,10 @@ int print_spice_element(FILE *fd, int inst) } dbg(1, "print_spice_element(): final: val: |%s|\n", val); } - value = val; - /* xctx->tok_size==0 (set in translate3()) indicates that token(+1) does not exist - * in instance attributes so try to get from symbol template */ - dbg(1, "print_spice_element(): val: %s\n", val); + /* still unresolved: set to empty */ + if(val[0] == '@') value = ""; + else value = val; token_exists = xctx->tok_size; - value = val; tok_val_len = strlen(value); /* @spiceprefix needs a special tag for postprocessing */ if(!strcmp(token, "@spiceprefix") && value[0]) { @@ -3109,26 +3121,35 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level } if(c=='\0') { - /* do one level of substitutions to resolve remaining @params and/or tcl expr/code */ + /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions + * can be calculated. Before that do also a round of translation to remove remaining @params */ if(result) { - dbg(1, "print_verilog_primitive(): before translate() result=%s\n", result); - if(!strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - /* since netlist_commands often have @ characters in spice node save / plot commands, do - * not pass through translate, unless a tcleval(...) is present */ - if(strstr(result, "tcleval(")== result) { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); + dbg(1, "print_verilog_primitive(): before translate3() result=%s\n", result); + if(strchr(result, '@')) { + /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ + if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); + /* can not put template in above translate3: ------------------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(result, '@')) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + } + } - } else { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); } - dbg(1, "print_verilog_primitive(): after translate() result=%s\n", result); + my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */ + if(strstr(result, "expr(") ) { + result = eval_expr(result); + } + dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result); } if(result) fprintf(fd, "%s", result); fputc('\n',fd); fprintf(fd, "---- end primitive\n"); break ; } - } + } /* while(1) */ my_free(_ALLOC_ID_, &result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); @@ -3789,7 +3810,7 @@ const char *translate(int inst, const char* s) /* @spice_get_current(...) or @spice_get_modelparam(...) */ /* @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) */ regcomp(get_sp_cur, - "^@spice_get_(current|modelparam|modelvoltage)(_[a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); + "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); } sp_prefix = tclgetboolvar("spiceprefix"); From 1e23beabd3dbfc329b2a87ada1a8af902dcfad40 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 01:08:52 +0100 Subject: [PATCH 16/46] c89 compliance and fix some double to int assignments, removed stdbool --- src/callback.c | 55 ++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/callback.c b/src/callback.c index a9a8531d..b9565484 100644 --- a/src/callback.c +++ b/src/callback.c @@ -21,7 +21,6 @@ */ #include "xschem.h" -#include /* allow to use the Windows keys as alternate for Alt */ #define SET_MODMASK ( (rstate & Mod1Mask) || (rstate & Mod4Mask) ) @@ -111,10 +110,11 @@ void redraw_w_a_l_r_p_z_rubbers(int force) if(xctx->constr_mv == 1) my = xctx->my_double_save; if(xctx->constr_mv == 2) mx = xctx->mx_double_save; if(tclgetboolvar("orthogonal_wiring")) { + /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ + double origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1, origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap); - /* Origin shift the cartesian coordinate p2(x2,y2) w.r.t. p1(x1,y1) */ - int origin_shifted_x2 = xctx->nl_x2 - xctx->nl_x1, origin_shifted_y2 = xctx->nl_y2 - xctx->nl_y1; - /* Draw whichever component of the resulting orthogonal-wire is bigger (either horizontal or vertical), first */ + /* Draw whichever component of the resulting orthogonal-wire is bigger + * (either horizontal or vertical), first */ if(origin_shifted_x2*origin_shifted_x2 > origin_shifted_y2*origin_shifted_y2){ xctx->manhattan_lines = 1; } else { @@ -1520,7 +1520,7 @@ void draw_crosshair(int what, int state) xctx->draw_pixmap = sdp; } -void find_snap_position(double *x, double *y, bool pos_changed) { +void find_snap_position(double *x, double *y, int pos_changed) { if (!pos_changed) { *x = xctx->prev_snapx; *y = xctx->prev_snapy; @@ -1531,24 +1531,22 @@ void find_snap_position(double *x, double *y, bool pos_changed) { } void draw_snap_cursor_shape(GC gc, double x, double y, int snapcursor_size) { - // Convert coordinates to screen space + /* 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; - - // Define crosshair lines - double lines[4][4] = { - {screen_x, top, right, screen_y}, // Top to right - {right, screen_y, screen_x, bottom}, // Right to bottom - {screen_x, bottom, left, screen_y}, // Bottom to left - {left, screen_y, screen_x, top} // Left to top - }; - - // Draw crosshair lines - for (int i = 0; i < 4; i++) { + 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]); } } @@ -1567,29 +1565,28 @@ void erase_snap_cursor(double prev_x, double prev_y, int snapcursor_size) { } } - /* action = 1 => erase */ void draw_snap_cursor(int action) { - if (!xctx->mouse_inside) return; // Early exit if mouse is outside - - int snapcursor_size = tclgetintvar("snap_cursor_size"); - bool pos_changed = (xctx->mousex_snap != xctx->prev_gridx) || (xctx->mousey_snap != xctx->prev_gridy); - - // Save current drawing context + 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; - - // Erase and redraw the cursor if needed + /* Erase and redraw the cursor if needed */ if (action & 1) { + double new_x, new_y; erase_snap_cursor(xctx->prev_snapx, xctx->prev_snapy, snapcursor_size); - 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 + /* Update previous position tracking */ xctx->prev_gridx = xctx->mousex_snap; xctx->prev_gridy = xctx->mousey_snap; xctx->prev_snapx = new_x; @@ -1598,7 +1595,7 @@ void draw_snap_cursor(int action) { draw_selection(xctx->gc[SELLAYER], 0); - // Restore previous drawing context + /* Restore previous drawing context */ xctx->draw_window = prev_draw_window; xctx->draw_pixmap = prev_draw_pixmap; } From ffe0aba12e4160b1dc825bd2bf91e6b033c77ff2 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 01:22:36 +0100 Subject: [PATCH 17/46] indentation and spacing in callback.c --- src/callback.c | 81 ++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/callback.c b/src/callback.c index b9565484..25884c4a 100644 --- a/src/callback.c +++ b/src/callback.c @@ -120,7 +120,7 @@ void redraw_w_a_l_r_p_z_rubbers(int force) } else { xctx->manhattan_lines = 2; } - } + } new_wire(RUBBER, mx, my); } if(xctx->ui_state & STARTARC) { @@ -227,32 +227,31 @@ static void start_line(double mx, double my) static void start_wire(double mx, double my) { - dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n", - xctx->ui_state, xctx->ui_state2, xctx->last_command); - xctx->last_command = STARTWIRE; - if(xctx->ui_state & STARTWIRE) { - if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ - xctx->constr_mv = xctx->manhattan_lines; - new_wire(CLEAR, mx, my); - redraw_w_a_l_r_p_z_rubbers(1); - } - if(xctx->constr_mv != 2) { - xctx->mx_double_save = mx; - } - if(xctx->constr_mv != 1) { - xctx->my_double_save = my; - } - if(xctx->constr_mv == 1) my = xctx->my_double_save; - if(xctx->constr_mv == 2) mx = xctx->mx_double_save; - } else { - xctx->mx_double_save=mx; - xctx->my_double_save=my; - } - new_wire(PLACE,mx, my); - if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ - xctx->constr_mv = 0; - } - + dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n", + xctx->ui_state, xctx->ui_state2, xctx->last_command); + xctx->last_command = STARTWIRE; + if(xctx->ui_state & STARTWIRE) { + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")){ + xctx->constr_mv = xctx->manhattan_lines; + new_wire(CLEAR, mx, my); + redraw_w_a_l_r_p_z_rubbers(1); + } + if(xctx->constr_mv != 2) { + xctx->mx_double_save = mx; + } + if(xctx->constr_mv != 1) { + xctx->my_double_save = my; + } + if(xctx->constr_mv == 1) my = xctx->my_double_save; + if(xctx->constr_mv == 2) mx = xctx->mx_double_save; + } else { + xctx->mx_double_save=mx; + xctx->my_double_save=my; + } + new_wire(PLACE,mx, my); + if(tclgetboolvar("orthogonal_wiring") && !tclgetboolvar("constr_mv")) { + xctx->constr_mv = 0; + } } static double interpolate_yval(int idx, int p, double x, int sweep_idx, int point_not_last) @@ -1522,11 +1521,11 @@ void draw_crosshair(int what, int state) void find_snap_position(double *x, double *y, int pos_changed) { if (!pos_changed) { - *x = xctx->prev_snapx; - *y = xctx->prev_snapy; + *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); + xctx->closest_pin_found = find_closest_net_or_symbol_pin( + xctx->mousex, xctx->mousey, x, y); } } @@ -1580,21 +1579,19 @@ void draw_snap_cursor(int action) { xctx->draw_window = 1; /* Erase and redraw the cursor if needed */ if (action & 1) { - double new_x, new_y; - erase_snap_cursor(xctx->prev_snapx, xctx->prev_snapy, snapcursor_size); + double new_x, new_y; + erase_snap_cursor(xctx->prev_snapx, xctx->prev_snapy, snapcursor_size); - find_snap_position(&new_x, &new_y, pos_changed); - draw_snap_cursor_shape(xctx->gc[xctx->crosshair_layer],new_x, new_y, snapcursor_size); + 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; + /* 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; } - draw_selection(xctx->gc[SELLAYER], 0); - /* Restore previous drawing context */ xctx->draw_window = prev_draw_window; xctx->draw_pixmap = prev_draw_pixmap; From a559f84bc57d4eccff1751dcc1121e9e50a93d92 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 01:40:15 +0100 Subject: [PATCH 18/46] merged in Ananth Chellappa additions for Cadence compatibility --- src/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.in b/src/Makefile.in index ec2d23ef..83c2d015 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -15,7 +15,7 @@ put /local/install_shares { symgen.awk order_labels.awk sort_labels.awk spice.awk tedax.awk verilog.awk vhdl.awk hspice_backannotate.tcl add_custom_menu.tcl create_graph.tcl add_custom_button.tcl change_index.tcl icon.xpm resources.tcl xschemrc - ngspice_backannotate.tcl gschemtoxschem.awk mouse_bindings.tcl + ngspice_backannotate.tcl gschemtoxschem.awk mouse_bindings.tcl cadence_style_rc place_sym_pins.tcl place_pins.tcl make_sch_from_spice.awk make_sym_from_spice.awk } From bd40674f342c3548cac61969319ae9404d343c29 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 02:11:47 +0100 Subject: [PATCH 19/46] removed %define api.prefix in yacc eval_expr.y, use -p bison on command line --- src/Makefile.in | 2 +- src/eval_expr.y | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 83c2d015..16bf9ac6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -50,7 +50,7 @@ expandlabel.c expandlabel.h: expandlabel.y bison -d -o expandlabel.c expandlabel.y eval_expr.c: eval_expr.y - bison -o eval_expr.c eval_expr.y + bison -p kk -o eval_expr.c eval_expr.y parselabel.o: expandlabel.h diff --git a/src/eval_expr.y b/src/eval_expr.y index 26f8d21d..cb6a3a85 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -55,7 +55,7 @@ struct fn fn_array[] }; %} -%define api.prefix {kk} +/* %define api.prefix {kk} */ %union { int c; double val; /* For returning numbers. */ From bc293a1d8f54cbf3618dc9979dba03328f6007d6 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 03:14:45 +0100 Subject: [PATCH 20/46] fix some warnings (-Wdeprecated-non-prototype, -Wparentheses-equality) --- src/callback.c | 2 +- src/eval_expr.y | 2 +- src/scheduler.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/callback.c b/src/callback.c index 25884c4a..814b79ba 100644 --- a/src/callback.c +++ b/src/callback.c @@ -332,7 +332,7 @@ void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr) cnt = 0; } if(xx >= start && xx <= end) { - if((dataset == sweepvar_wrap)) { + if(dataset == sweepvar_wrap) { dbg(1, "xx=%g cursor2=%g first=%d last=%d start=%g end=%g p=%d wrap=%d sweepvar_wrap=%d ofs=%d\n", xx, cursor2, first, last, start, end, p, wrap, sweepvar_wrap, ofs); if(first == -1) first = p; diff --git a/src/eval_expr.y b/src/eval_expr.y index cb6a3a85..078ffa3b 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -16,7 +16,7 @@ static int dbglev = 1; struct symrec { char *name; /* name of symbol */ - double (*fnctptr)(); /* value of a FNCT */ + double (*fnctptr)(double); /* value of a FNCT */ struct symrec *next; /* link field */ }; diff --git a/src/scheduler.c b/src/scheduler.c index b5611a46..f16988b1 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -2158,7 +2158,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg if(argc > 2 ) { what = atoi(argv[2]); } - if((xctx->semaphore == 0)) go_back(what); + if(xctx->semaphore == 0) go_back(what); Tcl_ResetResult(interp); } @@ -3356,7 +3356,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg "-message {Please Set netlisting mode (Options menu)}"); tclsetboolvar("keep_symbols", save_keep); - if( (erc == 0) ) { + if(erc == 0) { my_strncpy(xctx->netlist_name, "", S(xctx->netlist_name)); } } From 95cbd80767562cc21b0548fa3a2291a79d7758e2 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 16:25:46 +0100 Subject: [PATCH 21/46] merged in TheSUperChayan feature for displaying `Draw Wire` in status bar when in wiring mode. --- src/callback.c | 6 ++++++ src/xschem.tcl | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/callback.c b/src/callback.c index 814b79ba..fdf5b81e 100644 --- a/src/callback.c +++ b/src/callback.c @@ -4503,6 +4503,12 @@ int wire_draw_active = (xctx->ui_state & STARTWIRE) || } #endif + if(wire_draw_active) { + tclvareval(xctx->top_path, ".statusbar.10 configure -state active -text {DRAW WIRE! }", NULL); + } else { + tclvareval(xctx->top_path, ".statusbar.10 configure -state normal -text { }", NULL); + } + tclvareval(xctx->top_path, ".statusbar.7 configure -text $netlist_type", NULL); tclvareval(xctx->top_path, ".statusbar.3 delete 0 end;", xctx->top_path, ".statusbar.3 insert 0 $cadsnap", diff --git a/src/xschem.tcl b/src/xschem.tcl index 41fd2800..217a2452 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -8057,6 +8057,7 @@ proc pack_widgets { { topwin {} } } { pack $topwin.statusbar.6 -side left pack $topwin.statusbar.7 -side left pack $topwin.statusbar.10 -side left + pack $topwin.statusbar.11 -side left pack $topwin.statusbar.9 -side left pack $topwin.statusbar.8 -side left pack $topwin.statusbar.1 -side left -fill x @@ -8797,7 +8798,8 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get entry_replace_selection $topwin.statusbar.5 label $topwin.statusbar.6 -text "MODE:" label $topwin.statusbar.7 -width 7 - label $topwin.statusbar.10 -text {Stretch:} + label $topwin.statusbar.11 -text {Stretch:} + label $topwin.statusbar.10 -activebackground green -text {} label $topwin.statusbar.9 -textvariable enable_stretch label $topwin.statusbar.8 -activebackground red -text {} add_toolbuttons $topwin From 4517ff3b8713cb9bd0b61ad72f27eafe18f9f510 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Feb 2025 23:26:00 +0100 Subject: [PATCH 22/46] fix netlist error if in symbol attributes model="xxx@name" is given, @name was looked up in symbol template instead of again in instance properties. --- src/token.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/token.c b/src/token.c index aa4d5da5..bf4c2049 100644 --- a/src/token.c +++ b/src/token.c @@ -2411,7 +2411,8 @@ int print_spice_element(FILE *fd, int inst) * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ if(strchr(val, '@')) { - my_strdup2(_ALLOC_ID_, &val, translate3(val, 0, template, NULL, NULL, NULL)); + my_strdup2(_ALLOC_ID_, &val, + translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); } /* nmos instance format string: @model --> @modeln */ dbg(1, "print_spice_element(): 1st round: val: |%s|\n", val); From 2c703aa12de08a33b5dc59be48033314d34f5697 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 13 Feb 2025 00:46:39 +0100 Subject: [PATCH 23/46] backport previous fix to print_verilog_primitive and print_vhdl_primitive --- src/token.c | 34 ++++++++++++++++++++++++---------- src/xschemrc | 3 +++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/token.c b/src/token.c index bf4c2049..418f7e44 100644 --- a/src/token.c +++ b/src/token.c @@ -1174,19 +1174,26 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 if(c=='\0') { + char *parent_prop_ptr = NULL; + + if(xctx->currsch > 0) { + parent_prop_ptr = xctx->hier_attr[xctx->currsch - 1].prop_ptr; + } /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions * can be calculated. Before that do also a round of translation to remove remaining @params */ if(result) { - dbg(1, "print_verilog_primitive(): before translate3() result=%s\n", result); + dbg(1, "print_vhdl_primitive(): before translate3() result=%s\n", result); if(strchr(result, '@')) { /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); - /* can not put template in above translate3: ------------------------------------^^^^ + my_strdup2(_ALLOC_ID_, &result, + translate3(result, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, NULL, NULL)); + /* can not put template in above translate3: -----------------------^^^^ * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ - if(strchr(result, '@')) { - my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + if(strchr(result, '@')) { + my_strdup2(_ALLOC_ID_, &result, + translate3(result, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); } } } @@ -1194,7 +1201,7 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 if(strstr(result, "expr(") ) { result = eval_expr(result); } - dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result); + dbg(1, "print_vhdl_primitive(): after translate3() result=%s\n", result); } if(result) fprintf(fd, "%s", result); fputc('\n',fd); @@ -3122,6 +3129,12 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level } if(c=='\0') { + char *parent_prop_ptr = NULL; + + if(xctx->currsch > 0) { + parent_prop_ptr = xctx->hier_attr[xctx->currsch - 1].prop_ptr; + } + /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions * can be calculated. Before that do also a round of translation to remove remaining @params */ if(result) { @@ -3129,14 +3142,15 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level if(strchr(result, '@')) { /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); - /* can not put template in above translate3: ------------------------------------^^^^ + my_strdup2(_ALLOC_ID_, &result, + translate3(result, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, NULL, NULL)); + /* can not put template in above translate3: -----------------------^^^^ * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ if(strchr(result, '@')) { - my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + my_strdup2(_ALLOC_ID_, &result, + translate3(result, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); } - } } my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */ diff --git a/src/xschemrc b/src/xschemrc index f6dbf330..b472f338 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -639,3 +639,6 @@ #### Default: not enabled (0) # set fix_mouse_coord 0 +#### redefine some variables to emulate Cadence UI / bindkeys +# source /home/schippes/share/xschem/cadence_style_rc + From 7087ae5a2a3c143dce196a95f9b467ee8fd683f6 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 13 Feb 2025 02:38:19 +0100 Subject: [PATCH 24/46] fix graphical artifacts when inserting objects and pressing Button3 --- src/callback.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/callback.c b/src/callback.c index fdf5b81e..b4188c65 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1624,11 +1624,11 @@ static int end_place_move_copy_zoom() } xctx->constr_mv=0; tcleval("set constr_mv 0" ); - return 1; + return 0; } else if(xctx->ui_state & STARTARC) { new_arc(SET, 0, xctx->mousex_snap, xctx->mousey_snap); - return 1; + return 0; } else if(xctx->ui_state & STARTLINE) { if(tclgetboolvar("persistent_command")) { @@ -1646,11 +1646,11 @@ static int end_place_move_copy_zoom() } xctx->constr_mv=0; tcleval("set constr_mv 0" ); - return 1; + return 0; } else if(xctx->ui_state & STARTRECT) { new_rect(PLACE|END,xctx->mousex_snap, xctx->mousey_snap); - return 1; + return 0; } else if(xctx->ui_state & STARTPOLYGON) { if(xctx->constr_mv == 1) xctx->mousey_snap = xctx->my_double_save; @@ -1660,8 +1660,9 @@ static int end_place_move_copy_zoom() xctx->my_double_save=xctx->mousey_snap; xctx->constr_mv=0; tcleval("set constr_mv 0" ); - return 1; + return 0; } + #if 0 /* this code never executed */ else if(xctx->ui_state & STARTMOVE) { move_objects(END,0,0,0); xctx->ui_state &=~START_SYMPIN; @@ -1675,6 +1676,7 @@ static int end_place_move_copy_zoom() tcleval("set constr_mv 0" ); return 1; } + #endif return 0; } @@ -4063,6 +4065,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in double c_snap, int draw_xhair, int crosshair_size, int enable_stretch, int aux ) { int use_cursor_for_sel = tclgetintvar("use_cursor_for_selection"); + int excl = xctx->ui_state & (STARTWIRE | STARTRECT | STARTLINE | STARTPOLYGON | STARTARC); dbg(1, "callback(): ButtonPress ui_state=%d state=%d\n",xctx->ui_state,state); if(waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); @@ -4075,7 +4078,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } /* select instance and connected nets stopping at wire junctions */ - if(button == Button3 && state == ControlMask && xctx->semaphore <2) + if(!excl && button == Button3 && state == ControlMask && xctx->semaphore <2) { Selected sel; sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); @@ -4083,17 +4086,19 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } /* break wire at mouse coordinates, move break point to nearest grid point */ - else if(button == Button3 && EQUAL_MODMASK && !(state & ShiftMask) && xctx->semaphore <2) + else if(!excl && button == Button3 && EQUAL_MODMASK && + !(state & ShiftMask) && xctx->semaphore <2) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); } /* break wire at mouse coordinates */ - else if(button == Button3 && EQUAL_MODMASK && (state & ShiftMask) && xctx->semaphore <2) + else if(!excl && button == Button3 && EQUAL_MODMASK && + (state & ShiftMask) && xctx->semaphore <2) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 0); } /* select instance and connected nets NOT stopping at wire junctions */ - else if(button == Button3 && state == ShiftMask && xctx->semaphore <2) + else if(!excl && button == Button3 && state == ShiftMask && xctx->semaphore <2) { Selected sel; sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0, NULL); @@ -4101,13 +4106,13 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in } /* moved to Button3 release */ /* - * else if(button == Button3 && state == 0 && xctx->semaphore <2) { + * else if(button == Button3 && state == 0 && xctx->semaphore <2) { * context_menu_action(xctx->mousex_snap, xctx->mousey_snap); * } */ /* zoom rectangle by right clicking and drag */ - else if(button == Button3 && state == 0 && xctx->semaphore < 2) { + else if(!excl && button == Button3 && state == 0 && xctx->semaphore < 2) { zoom_rectangle(START);return; } @@ -4404,7 +4409,8 @@ static void handle_button_release(int event, KeySym key, int state, int button, if(snap_cursor && wire_draw_active) draw_snap_cursor(3); } -static void handle_double_click(int event, int state, KeySym key, int button, int mx, int my, int aux, int cadence_compat ) +static void handle_double_click(int event, int state, KeySym key, int button, + int mx, int my, int aux, int cadence_compat ) { if( waves_selected(event, key, state, button)) { waves_callback(event, mx, my, key, button, aux, state); From ed3190c9b167abdbba97be294f1593757cacd55e Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 13 Feb 2025 02:44:26 +0100 Subject: [PATCH 25/46] complete previous fix --- src/callback.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/callback.c b/src/callback.c index b4188c65..54d7ff0b 100644 --- a/src/callback.c +++ b/src/callback.c @@ -1662,7 +1662,6 @@ static int end_place_move_copy_zoom() tcleval("set constr_mv 0" ); return 0; } - #if 0 /* this code never executed */ else if(xctx->ui_state & STARTMOVE) { move_objects(END,0,0,0); xctx->ui_state &=~START_SYMPIN; @@ -1676,7 +1675,6 @@ static int end_place_move_copy_zoom() tcleval("set constr_mv 0" ); return 1; } - #endif return 0; } From b0d740757a11052e461372d792b4af2cc449c0ef Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 13 Feb 2025 20:43:39 +0100 Subject: [PATCH 26/46] fix regression in psprint.c --- src/psprint.c | 138 ++++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/src/psprint.c b/src/psprint.c index 295ed1ed..26a003fd 100644 --- a/src/psprint.c +++ b/src/psprint.c @@ -301,7 +301,6 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl rwi = (int)(rw * scale + 1.0); rhi = (int)(rh * scale + 1.0); dbg(1, "graph size: %dx%d\n", rwi, rhi); - dbg(1, "ps_embedded_graph: saving zoom\n"); save_restore_zoom(1, &zi); set_viewport_size(rwi, rhi, xctx->lw); @@ -354,7 +353,6 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl cairo_surface_destroy(png_sfc); xctx->draw_pixmap = 1; tclsetboolvar("draw_grid", save_draw_grid); - dbg(1, "ps_embedded_graph: restoring zoom\n"); save_restore_zoom(0, &zi); resetwin(1, 1, 1, 0, 0); change_linewidth(xctx->lw); @@ -1192,83 +1190,78 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) old_grid=tclgetboolvar("draw_grid"); tclsetvar("draw_grid", "0"); + /* xschem window aspect ratio decides if portrait or landscape */ + boundbox.x1 = xctx->areax1; + boundbox.x2 = xctx->areax2; + boundbox.y1 = xctx->areay1; + boundbox.y2 = xctx->areay2; + dx=boundbox.x2-boundbox.x1; + dy=boundbox.y2-boundbox.y1; + + /* xschem drawing bbox decides if portrait or landscape */ + if(fullzoom == 1) { + calc_drawing_bbox(&boundbox, 0); + dx=boundbox.x2-boundbox.x1; + dy=boundbox.y2-boundbox.y1; + } + if(dx >= dy) { + landscape = 1; + } else { + landscape = 0; + } + dbg(1, "dx=%g, dy=%g\n", dx, dy); - if(!(what & 4)) { - /* xschem window aspect ratio decides if portrait or landscape */ + if(fullzoom == 1) { + /* save size and zoom factor */ + save_restore_zoom(1, &zi); + /* this zoom only done to reset lw */ + zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); + /* adjust aspect ratio to paper size */ + if(landscape) + xctx->xrect[0].height = (short unsigned int) (xctx->xrect[0].width * pagey / pagex); + else + xctx->xrect[0].width = (short unsigned int) (xctx->xrect[0].height * pagey / pagex); + dbg(1, "xrect.width=%d, xrect.height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); + xctx->areax1 = -2*INT_WIDTH(xctx->lw); + xctx->areay1 = -2*INT_WIDTH(xctx->lw); + xctx->areax2 = xctx->xrect[0].width+2*INT_WIDTH(xctx->lw); + xctx->areay2 = xctx->xrect[0].height+2*INT_WIDTH(xctx->lw); + xctx->areaw = xctx->areax2-xctx->areax1; + xctx->areah = xctx->areay2 - xctx->areay1; + dbg(1, "dx=%g, dy=%g\n", dx, dy); + /* fit schematic into adjusted size */ + zoom_full(0, 0, 0 + 2 * tclgetboolvar("zoom_full_center"), 0.97); boundbox.x1 = xctx->areax1; boundbox.x2 = xctx->areax2; boundbox.y1 = xctx->areay1; boundbox.y2 = xctx->areay2; dx=boundbox.x2-boundbox.x1; dy=boundbox.y2-boundbox.y1; - - /* xschem drawing bbox decides if portrait or landscape */ - if(fullzoom == 1) { - calc_drawing_bbox(&boundbox, 0); - dx=boundbox.x2-boundbox.x1; - dy=boundbox.y2-boundbox.y1; - } - if(dx >= dy) { - landscape = 1; + } + + if(!landscape) { /* decide paper orientation for best schematic fit */ + double tmp; + tmp = pagex; + pagex = pagey; + pagey = tmp; + } + if(fullzoom == 2) { /* set media size to bbox */ + double sc; + my_strncpy(papername, "bbox", S(papername)); + pagex = xctx->xrect[0].width; + pagey = xctx->xrect[0].height; + if(pagex > pagey) { + sc = 842. / pagex; + pagex = my_round(pagex * sc); + pagey = my_round(pagey * sc); } else { - landscape = 0; + sc = 842. / pagey; + pagex = my_round(pagex * sc); + pagey = my_round(pagey * sc); } - dbg(1, "dx=%g, dy=%g\n", dx, dy); - - - if(fullzoom == 1) { - /* save size and zoom factor */ - dbg(1, "create_ps: saving zoom\n"); - save_restore_zoom(1, &zi); - /* this zoom only done to reset lw */ - zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); - /* adjust aspect ratio to paper size */ - if(landscape) - xctx->xrect[0].height = (short unsigned int) (xctx->xrect[0].width * pagey / pagex); - else - xctx->xrect[0].width = (short unsigned int) (xctx->xrect[0].height * pagey / pagex); - dbg(1, "xrect.width=%d, xrect.height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); - xctx->areax1 = -2*INT_WIDTH(xctx->lw); - xctx->areay1 = -2*INT_WIDTH(xctx->lw); - xctx->areax2 = xctx->xrect[0].width+2*INT_WIDTH(xctx->lw); - xctx->areay2 = xctx->xrect[0].height+2*INT_WIDTH(xctx->lw); - xctx->areaw = xctx->areax2-xctx->areax1; - xctx->areah = xctx->areay2 - xctx->areay1; - dbg(1, "dx=%g, dy=%g\n", dx, dy); - /* fit schematic into adjusted size */ - zoom_full(0, 0, 0 + 2 * tclgetboolvar("zoom_full_center"), 0.97); - boundbox.x1 = xctx->areax1; - boundbox.x2 = xctx->areax2; - boundbox.y1 = xctx->areay1; - boundbox.y2 = xctx->areay2; - dx=boundbox.x2-boundbox.x1; - dy=boundbox.y2-boundbox.y1; - } - - if(!landscape) { /* decide paper orientation for best schematic fit */ - double tmp; - tmp = pagex; - pagex = pagey; - pagey = tmp; - } - if(fullzoom == 2) { /* set media size to bbox */ - double sc; - my_strncpy(papername, "bbox", S(papername)); - pagex = xctx->xrect[0].width; - pagey = xctx->xrect[0].height; - if(pagex > pagey) { - sc = 842. / pagex; - pagex = my_round(pagex * sc); - pagey = my_round(pagey * sc); - } else { - sc = 842. / pagey; - pagex = my_round(pagex * sc); - pagey = my_round(pagey * sc); - } - margin = 0.0; - } - } /* if(!(what & 4)) */ + margin = 0.0; + } if(what & 1) {/* prolog */ dbg(1, "ps_draw(): bbox: x1=%g y1=%g x2=%g y2=%g\n", boundbox.x1, boundbox.y1, boundbox.x2, boundbox.y2); @@ -1341,6 +1334,7 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) fprintf(fd, "%%%%EndProlog\n"); } + if(what & 2) { /* page */ ++numpages; @@ -1497,7 +1491,7 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) dbg(1, "ps_draw(): INT_WIDTH(lw)=%d plotfile=%s\n",INT_WIDTH(xctx->lw), xctx->plotfile); fprintf(fd, "showpage\n\n"); - } /* if(what & 2) */ + } if(what & 4) { /* trailer */ fprintf(fd, "%%%%trailer\n"); fprintf(fd, "%%%%Pages: %d\n", numpages); @@ -1515,10 +1509,10 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) /* restore original size and zoom factor */ - if(!(what & 4) && fullzoom == 1) { - dbg(1, "create_ps: restoring zoom\n"); + if(fullzoom == 1) { save_restore_zoom(0, &zi); } + } int ps_draw(int what, int fullzoom, int eps) From afac3f7620a980f9a413cec4cf036c098a2d6a4d Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 13 Feb 2025 22:18:23 +0100 Subject: [PATCH 27/46] token.c: translate(): protect regex*() calls with #ifdef __unix__ --- src/token.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/token.c b/src/token.c index 418f7e44..5082c016 100644 --- a/src/token.c +++ b/src/token.c @@ -3784,7 +3784,9 @@ const char *spice_get_node(const char *token) /* if s==NULL return emty string */ const char *translate(int inst, const char* s) { + #ifdef __unix__ static regex_t *get_sp_cur = NULL; + #endif static const char *empty=""; static char *result=NULL; /* safe to keep even with multiple schematics */ size_t size=0; @@ -3809,16 +3811,19 @@ const char *translate(int inst, const char* s) if(!s && inst == -1) { if(result) my_free(_ALLOC_ID_, &result); + #ifdef __unix__ if(get_sp_cur) { regfree(get_sp_cur); get_sp_cur = NULL; } + #endif } if(!s || !xctx || !xctx->inst) { return empty; } + #ifdef __unix__ if(!get_sp_cur) { get_sp_cur = my_malloc(_ALLOC_ID_, sizeof(regex_t)); /* @spice_get_current_param(...) or @spice_get_modelparam_param(...) */ @@ -3827,6 +3832,7 @@ const char *translate(int inst, const char* s) regcomp(get_sp_cur, "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); } + #endif sp_prefix = tclgetboolvar("spiceprefix"); @@ -4158,7 +4164,11 @@ const char *translate(int inst, const char* s) * * Only @spice_get_current(...) and @spice_get_current_param(...) are processed * the other types are ignored */ + #ifdef __unix__ else if(!regexec(get_sp_cur, token, 0 , NULL, 0) ) + # else + else if(0) /* FIXME: windows workaround for missing regex* functions */ + #endif { int start_level; /* hierarchy level where waves were loaded */ int live = tclgetboolvar("live_cursor2_backannotate"); From 9fe67cd242940d0bcc21aaf2db4166c77558c9f0 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 02:15:03 +0100 Subject: [PATCH 28/46] eval_expr.y: fix eval_expr_clear_table, remove unneeded unistd.h --- XSchemWin/XSchemWin.vcxproj | 7 + XSchemWin/XSchemWin_cairo.vcxproj | 7 + XSchemWin/XSchemWix/Product.wxs | 6 +- XSchemWin/XSchemWix/heat_xschem_library.wxs | 3912 ++++++++++--------- XSchemWin/XSchemWix/xschem_library.wxs | 4 + XSchemWin/XSchemWix/xschemrc | 61 +- src/eval_expr.y | 7 +- src/hilight.c | 6 +- src/token.c | 2 +- src/xschem.h | 1 + 10 files changed, 2043 insertions(+), 1970 deletions(-) diff --git a/XSchemWin/XSchemWin.vcxproj b/XSchemWin/XSchemWin.vcxproj index a601fc21..f630ae55 100644 --- a/XSchemWin/XSchemWin.vcxproj +++ b/XSchemWin/XSchemWin.vcxproj @@ -254,6 +254,7 @@ + @@ -261,6 +262,7 @@ + @@ -284,6 +286,11 @@ + + Document + bison -p kk -o eval_expr.c ..\src\eval_expr.y + eval_expr.c + diff --git a/XSchemWin/XSchemWin_cairo.vcxproj b/XSchemWin/XSchemWin_cairo.vcxproj index 793d0135..b4a64661 100644 --- a/XSchemWin/XSchemWin_cairo.vcxproj +++ b/XSchemWin/XSchemWin_cairo.vcxproj @@ -254,6 +254,7 @@ + @@ -261,6 +262,7 @@ + @@ -284,6 +286,11 @@ + + Document + bison -p kk -o eval_expr.c ..\src\eval_expr.y + eval_expr.c + diff --git a/XSchemWin/XSchemWix/Product.wxs b/XSchemWin/XSchemWix/Product.wxs index 8a036a35..2d3e9335 100644 --- a/XSchemWin/XSchemWix/Product.wxs +++ b/XSchemWin/XSchemWix/Product.wxs @@ -250,10 +250,7 @@ - - - - + @@ -374,7 +371,6 @@ - diff --git a/XSchemWin/XSchemWix/heat_xschem_library.wxs b/XSchemWin/XSchemWix/heat_xschem_library.wxs index 76fc66cb..08996ad1 100644 --- a/XSchemWin/XSchemWix/heat_xschem_library.wxs +++ b/XSchemWin/XSchemWix/heat_xschem_library.wxs @@ -3,5917 +3,5920 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -6026,6 +6029,7 @@ + diff --git a/XSchemWin/XSchemWix/xschem_library.wxs b/XSchemWin/XSchemWix/xschem_library.wxs index e39f2c4c..db02bb6c 100644 --- a/XSchemWin/XSchemWix/xschem_library.wxs +++ b/XSchemWin/XSchemWix/xschem_library.wxs @@ -293,6 +293,9 @@ + + + @@ -457,6 +460,7 @@ + diff --git a/XSchemWin/XSchemWix/xschemrc b/XSchemWin/XSchemWix/xschemrc index 94adef3a..a9081bb5 100644 --- a/XSchemWin/XSchemWix/xschemrc +++ b/XSchemWin/XSchemWix/xschemrc @@ -171,8 +171,14 @@ #### this is the default: # set initial_geometry {900x600} -#### initial geometry of load /save / insert component file selector -# set file_dialog_default_geometry 800x600 +#### initial size of the load_file_dialog (the file selector) dialog box +# set file_dialog_default_geometry 700x680+100+40 +#### load_file_dialog directory list (+ recent if shown) X width in pixels +# set file_dialog_sp0 350 +#### load_file_dialog recent components list X width in pixels +# set file_dialog_sp1 100 +#### load_file_dialog components list Y height in pixels +# set file_dialog_v_sp0 420 #### display full path (1) or only name (0) for component directories. Default: 1 # set load_file_dialog_fullpath 1 @@ -195,6 +201,11 @@ #### default: 0 # set persistent_command 1 +#### if set to 0 users must click a point after hitting a command key +#### like 'w(ire)', 'l(ine)' and so on. +#### default is 1 (hitting the command key sets also the first point). +# set infix_interface 0 + #### if set to 1 allow click & drag objects in the schematic #### to move them without keyboard commands ('m') #### default: enabled (1) @@ -256,8 +267,24 @@ #### enable drawing crosshairs at mouse coordinates. Default: disabled (0) # set draw_crosshair 1 -#### set crosshair layer; Default 3 (TEXTLAYER) -# set crosshair_layer 3 +#### set crosshair layer; Default 8 (Yellow) +# set crosshair_layer 8 + +#### set crosshair size; Default: 0 (full screen spanning crosshair) +# set crosshair_size 5 + +#### enable drawing a diamond-shaped cursor at the closest circuit endpoint. Default: disabled (0) +# set snap_cursor 1 + +#### set snap_cursor_size; Default: 6 (Diamond-shaped cursor that snaps to nearest circuit endpoint) +# set snap_cursor_size 6 + +#### set cadence_compat; Default: 0 (Cadence-style keybinds are not used by default) +# set cadence_compat 1 + +#### if set, then, when cursor (regardless of style) is on an object, and user clicks (though mouse pointer is not on the object), +#### the object is selected. Default: 0 +# set use_cursor_for_selection 1 #### enable to scale grid point size as done with lines at close zoom, default: 0 # set big_grid_points 0 @@ -510,7 +537,10 @@ set editor {notepad.exe} # } # } - +########################################################################### +#### TCL COMMANDS TO BE EXECUTED AFTER GENERATING NETLIST +########################################################################### +# set netlist_postprocess {textfile $netlist_dir/[xschem get netlist_name fallback]} ########################################################################### #### WEB URL DOWNLOAD HELPER APPLICATION @@ -553,6 +583,14 @@ set editor {notepad.exe} #### default: 0 (not set) # set show_hidden_texts 1 +########################################################################### +#### USE CTRL MODIFIER TO OPERATE ON GRAPHS WITH MOUSE & KEYBOARD +########################################################################### +#### if enabled forces to hold Control key pressed to operate on graphs +#### to prevent "graph event stealing to schematic" +#### Default: 0 (not set) +# set graph_use_ctrl_key 1 + ########################################################################### #### HIDE GRAPHS IF NO SPICE DATA LOADED ########################################################################### @@ -560,6 +598,16 @@ set editor {notepad.exe} #### default: not enabled (0) # set hide_empty_graphs 0 + +########################################################################### +#### ATTACH HOOK FUNCTION TO CURSOR 2 MOVEMENT +########################################################################### +#### if enabled whenever the cursor2 is moved the specified script is +#### executed. Examples: +#### set cursor_2_hook {conducting_devices 10e-3 nodraw} +#### set cursor_2_hook {hilight_high_nets 0 1.8 nodraw} +#### this can be used to add backannotation actions. + ########################################################################### #### LIVE BACKANNOTATION OF DATA AT CURSOR 2 (B) POSITION ########################################################################### @@ -591,3 +639,6 @@ set editor {notepad.exe} #### Default: not enabled (0) # set fix_mouse_coord 0 +#### redefine some variables to emulate Cadence UI / bindkeys +# source /home/schippes/share/xschem/cadence_style_rc + diff --git a/src/eval_expr.y b/src/eval_expr.y index 078ffa3b..f2bc525f 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -2,7 +2,6 @@ #include #include /* For math functions, cos(), sin(), etc. */ #include -#include #include #include #include "xschem.h" @@ -193,13 +192,15 @@ void eval_expr_init_table(void) /* puts arithmetic functions in table. */ void eval_expr_clear_table(void) { - symrec *ptr; - for (ptr = sym_table; ptr; ptr = ptr->next) { + symrec *ptr = sym_table; + while(ptr) { symrec *tmp = ptr; + ptr = ptr->next; my_free(_ALLOC_ID_, &(tmp->name)); my_free(_ALLOC_ID_, &tmp); } } + static int kklex() { diff --git a/src/hilight.c b/src/hilight.c index 19c18a34..fa7b8916 100644 --- a/src/hilight.c +++ b/src/hilight.c @@ -696,7 +696,7 @@ static int bus_search(const char*s) } #ifndef __unix__ -static int win_regexec(const char *options, const char *pattern, const char *name) +int win_regexec(const char *options, const char *pattern, const char *name) { if (options!=NULL) tclvareval("regexp {", options,"} {", pattern, "} {", name, "}", NULL); @@ -754,7 +754,7 @@ int search(const char *tok, const char *val, int sub, int sel, int match_case) if(regcomp(&re, val , cflags)) return TCL_ERROR; #else if(!match_case) { - regexp_options = "-nocase"; + my_strdup(_ALLOC_ID_, ®exp_options, "-nocase"); } #endif dbg(1, "search():val=%s\n", val); @@ -1014,6 +1014,8 @@ int search(const char *tok, const char *val, int sub, int sel, int match_case) } #ifdef __unix__ regfree(&re); +#else + my_free(_ALLOC_ID_, ®exp_options); #endif xctx->draw_window = save_draw; my_free(_ALLOC_ID_, &tmpname); diff --git a/src/token.c b/src/token.c index 5082c016..635d2a8f 100644 --- a/src/token.c +++ b/src/token.c @@ -4167,7 +4167,7 @@ const char *translate(int inst, const char* s) #ifdef __unix__ else if(!regexec(get_sp_cur, token, 0 , NULL, 0) ) # else - else if(0) /* FIXME: windows workaround for missing regex* functions */ + else if ((win_regexec(NULL/*options*/, "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", token))) #endif { int start_level; /* hierarchy level where waves were loaded */ diff --git a/src/xschem.h b/src/xschem.h index 59802adf..a6f5007b 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1764,4 +1764,5 @@ extern const char *create_tmpdir(char *prefix); extern FILE *open_tmpfile(char *prefix, char *suffix, char **filename); extern void create_ps(char** psfile, int what, int fullzoom, int eps); extern void MyXCopyArea(Display* display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y); +extern int win_regexec(const char *options, const char *pattern, const char *name); #endif /*CADGLOBALS */ From e9c927d8825a44ef640687494512264418de5e06 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 02:55:47 +0100 Subject: [PATCH 29/46] default orientation for wire creation is manhattan (H-V). Lines still start oblique by default --- src/callback.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/callback.c b/src/callback.c index 54d7ff0b..1853799d 100644 --- a/src/callback.c +++ b/src/callback.c @@ -219,6 +219,7 @@ static void start_line(double mx, double my) if(xctx->constr_mv == 1) my = xctx->my_double_save; if(xctx->constr_mv == 2) mx = xctx->mx_double_save; } else { + xctx->manhattan_lines = 0; xctx->mx_double_save=mx; xctx->my_double_save=my; } @@ -245,6 +246,7 @@ static void start_wire(double mx, double my) if(xctx->constr_mv == 1) my = xctx->my_double_save; if(xctx->constr_mv == 2) mx = xctx->mx_double_save; } else { + xctx->manhattan_lines = 1; xctx->mx_double_save=mx; xctx->my_double_save=my; } From 05434cb5e4bf8fbc7b80e08bff4fc7f68d19aefa Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 13:32:17 +0100 Subject: [PATCH 30/46] fix @spice_get_*_*(...) regex --- src/token.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/token.c b/src/token.c index 635d2a8f..24149633 100644 --- a/src/token.c +++ b/src/token.c @@ -3826,11 +3826,11 @@ const char *translate(int inst, const char* s) #ifdef __unix__ if(!get_sp_cur) { get_sp_cur = my_malloc(_ALLOC_ID_, sizeof(regex_t)); - /* @spice_get_current_param(...) or @spice_get_modelparam_param(...) */ + /* @spice_get_current_(...) or @spice_get_modelparam_(...) */ /* @spice_get_current(...) or @spice_get_modelparam(...) */ - /* @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) */ + /* @spice_get_modelvoltage(...) or @spice_get_modelvoltage_(...) */ regcomp(get_sp_cur, - "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); + "^@spice_get_(current|modelparam|modelvoltage)(_[a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); } #endif @@ -4158,16 +4158,16 @@ const char *translate(int inst, const char* s) } } } - /* @spice_get_current(...) or @spice_get_current_param(...) - * @spice_get_modelparam(...) or @spice_get_modelparam_param(...) - * @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) + /* @spice_get_current(...) or @spice_get_current_(...) + * @spice_get_modelparam(...) or @spice_get_modelparam_(...) + * @spice_get_modelvoltage(...) or @spice_get_modelvoltage_(...) * - * Only @spice_get_current(...) and @spice_get_current_param(...) are processed + * Only @spice_get_current(...) and @spice_get_current_(...) are processed * the other types are ignored */ #ifdef __unix__ else if(!regexec(get_sp_cur, token, 0 , NULL, 0) ) # else - else if ((win_regexec(NULL/*options*/, "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", token))) + else if ((win_regexec(NULL/*options*/, "^@spice_get_(current|modelparam|modelvoltage)(_[a-zA-Z][a-zA-Z0-9_]*)*\\(", token))) #endif { int start_level; /* hierarchy level where waves were loaded */ @@ -4194,7 +4194,8 @@ const char *translate(int inst, const char* s) n = sscanf(token + 19, "%[^)]", dev); } else { param = my_malloc(_ALLOC_ID_, tmp); - n = sscanf(token, "@spice_get_current_%s(%[^)]", param, dev); + n = sscanf(token, "@spice_get_current_%[^(](%[^)]", param, dev); + dbg(1, "token=%s, param=%s, dev=%s\n", token, param, dev); if(n < 2) { my_free(_ALLOC_ID_, ¶m); n = sscanf(token, "@spice_get_current[^(](%[^)]", dev); @@ -4219,6 +4220,7 @@ const char *translate(int inst, const char* s) my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "ic"); } else if(prefix == 'd' || prefix == 'm') { my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "id"); + dbg(1, "translate(): fqdev=%s\n", fqdev); } else if(prefix == 'i') { my_snprintf(fqdev, len, "i(@%c.%s%s.%s[current])", prefix, path, instname, dev); } else { From 26710d3bd0a4f498e74c477d870ea668924bbba9 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 13:58:36 +0100 Subject: [PATCH 31/46] fix setting netlist_type to CAD_SYMBOL_ATTRS when doing a descend symbol (`i` key) into a LCC schematic and setting back to previous netlist_type when going back --- src/save.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/save.c b/src/save.c index 05638341..bee040f1 100644 --- a/src/save.c +++ b/src/save.c @@ -5107,6 +5107,7 @@ int descend_symbol(void) char name_embedded[PATH_MAX]; int n = 0; struct stat buf; + int save_netlist_type = xctx->netlist_type; if(xctx->currsch + 1 >= CADMAXHIER) { dbg(0, "descend_symbol(): max hierarchy depth reached: %d", CADMAXHIER); return 0; @@ -5216,6 +5217,10 @@ int descend_symbol(void) } my_free(_ALLOC_ID_, &sympath); } + xctx->save_netlist_type = save_netlist_type; + xctx->loaded_symbol = 1; + xctx->netlist_type = CAD_SYMBOL_ATTRS; + set_tcl_netlist_type(); zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); return 1; } From be643d5a92bed24444fbb792ecdf58a50e3c6d84 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 14:00:34 +0100 Subject: [PATCH 32/46] remove here() dbg call --- src/token.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/token.c b/src/token.c index 24149633..ee6a1a55 100644 --- a/src/token.c +++ b/src/token.c @@ -4653,7 +4653,6 @@ const char *translate2(Lcc *lcc, int level, char* s) } else if(strcmp(token,"@path")==0) { char *path = NULL; - here(level); my_strdup2(_ALLOC_ID_, &path, "@path@name\\."); if(level > 1) { /* add parent LCC instance names (X1, Xinv etc) */ int i; From 5c4be8313b761e34325b417099353c20fd715c4d Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 14 Feb 2025 14:40:56 +0100 Subject: [PATCH 33/46] better xctx->save_netlist_type setting when navigating in the hierarchy (of LCC schematics specifically) --- src/save.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/save.c b/src/save.c index bee040f1..b549c589 100644 --- a/src/save.c +++ b/src/save.c @@ -3545,7 +3545,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler } len = strlen(name); if(!strcmp(name + len - 4, ".sym")) { - xctx->save_netlist_type = xctx->netlist_type; + if(xctx->netlist_type != CAD_SYMBOL_ATTRS) xctx->save_netlist_type = xctx->netlist_type; xctx->netlist_type = CAD_SYMBOL_ATTRS; set_tcl_netlist_type(); xctx->loaded_symbol = 1; @@ -3564,7 +3564,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler if(reset_undo) { tclvareval("is_xschem_file {", xctx->sch[xctx->currsch], "}", NULL); if(!strcmp(tclresult(), "SYMBOL") || xctx->instances == 0) { - xctx->save_netlist_type = xctx->netlist_type; + if(xctx->netlist_type != CAD_SYMBOL_ATTRS) xctx->save_netlist_type = xctx->netlist_type; xctx->netlist_type = CAD_SYMBOL_ATTRS; set_tcl_netlist_type(); xctx->loaded_symbol = 1; @@ -5217,7 +5217,7 @@ int descend_symbol(void) } my_free(_ALLOC_ID_, &sympath); } - xctx->save_netlist_type = save_netlist_type; + if(save_netlist_type != CAD_SYMBOL_ATTRS) xctx->save_netlist_type = save_netlist_type; xctx->loaded_symbol = 1; xctx->netlist_type = CAD_SYMBOL_ATTRS; set_tcl_netlist_type(); From 279d24288dda18715a3ce31f959f4ac01ce80edf Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Sat, 15 Feb 2025 00:50:02 +0100 Subject: [PATCH 34/46] proc rel_sym_path: resolve ~/... or relative paths (by prepending HOME or PWD) to input path before calculating relative symbol path. Added command `xschem load_symbol` --- doc/xschem_man/developer_info.html | 28 ++++++++++++++++------------ src/draw.c | 12 ++++++++---- src/scheduler.c | 18 ++++++++++++++++++ src/xschem.tcl | 6 +++++- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 4cc88d12..a133d8be 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -551,6 +551,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" +
  • abort_operation
  • @@ -588,7 +589,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        all inside selected instances will be deleted 
  • build_colors
  •     Rebuild color palette using values of tcl vars dim_value and dim_bg 
    -
  • callback winpath event mx my key button aux state
  • +   
  • callback win_path event mx my key button aux state
  •     Invoke the callback event dispatcher with a software event 
  • case_insensitive 1|0
  •     Set case insensitive symbol lookup. Use only on case insensitive filesystems 
    @@ -713,6 +714,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
  • escape_chars source [charset]
  •     escape tcl special characters with backslash
        if charset is given escape characters in charset 
    +
  • eval_expr str
  • +   debug function: evaluate arithmetic expression in str 
  • exit [exit_code] [closewindow] [force]
  •     Exit the program, ask for confirm if current file modified.
        if exit_code is given exit with its value, otherwise use 0 exit code
    @@ -974,7 +977,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        Example: xschem instances_to_net PANEL
         --> { {Vsw} {plus} {580} {-560} } { {p2} {p} {660} {-440} }
             { {Vpanel1} {minus} {600} {-440} } 
    -
  • is_symgen symbol
  • +   
  • is_generator symbol
  •     tell if 'symbol' is a generator (symbol(param1,param2,...) 
  • line [x1 y1 x2 y2] [pos] [propstring] [draw]
  •     if 'x1 y1 x2 y2'is given place line on current
    @@ -1025,6 +1028,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        If 'f' is given output stderr messages to file 'f'
        if 'f' is not given and a file log is open, close log
        file and resume logging to stderr 
    +
  • load_symbol [symbol_file]
  • +   Load specified symbol_file  
  • log_write text
  •     write given string to log file, so tcl can write messages on the log file
  • logic_get_net net_name
  • @@ -1096,22 +1101,22 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        
  • new_process [f]
  •     Start a new xschem process for a schematic.
        If 'f' is given load specified schematic. 
    -
  • new_schematic create|destroy|destroy_all|switch winpath file [draw]
  • +   
  • new_schematic create|destroy|destroy_all|switch win_path file [draw]
  •     Open/destroy a new tab or window
          create: create new empty window or with 'file' loaded if 'file' given.
    -             The winpath must be given (even {} is ok).
    -             non empty winpath ({1}) will avoid warnings if opening the
    +             The win_path must be given (even {} is ok).
    +             non empty win_path ({1}) will avoid warnings if opening the
                  same file multiple times.
    -     destroy: destroy tab/window identified by winpath. Example:
    +     destroy: destroy tab/window identified by win_path. Example:
                   xschem new_schematic destroy .x1.drw
          destroy_all: close all tabs/additional windows
                   if the 'force'argument is given do not issue a warning if modified
                   tabs are about to be closed.
    -     switch: switch context to specified 'winpath' window or specified schematic name
    +     switch: switch context to specified 'win_path' window or specified schematic name
                   If 'draw' is given and set to 0 do not redraw after switching tab
                   (only tab i/f)
    -   Main window/tab has winpath set to .drw,
    -   Additional windows/tabs have winpath set to .x1.drw, .x2.drw and so on...
    + Main window/tab has win_path set to .drw, + Additional windows/tabs have win_path set to .x1.drw, .x2.drw and so on...
  • only_probes
  •         dim schematic to better show highlights 
  • origin x y [zoom]
  • @@ -1146,7 +1151,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        Start a GUI placement of a text object 
  • polygon
  •     Start a GUI placement of a polygon 
    -
  • preview_window create|draw|destroy|close [winpath] [file]
  • +   
  • preview_window create|draw|destroy|close [win_path] [file]
  •     destroy: will delete preview schematic data and destroy container window
        close: same as destroy but leave the container window.
        Used in fileselector to show a schematic preview.
    @@ -1548,7 +1553,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
  • switch [window_path |schematic_name]
  •     Switch context to indicated window path or schematic name
        returns 0 if switch was successfull or 1 in case of errors
    -   (no tabs/windows present or no matching winpath / schematic name
    +   (no tabs/windows present or no matching win_path / schematic name
        found).
  • symbols [n | 'derived_symbols']
  •     if 'n' given list symbol with name or number 'n', else list all
    @@ -1723,7 +1728,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
     
     
     
    -
     
     
      
    diff --git a/src/draw.c b/src/draw.c
    index b7c057dc..b726ecf6 100644
    --- a/src/draw.c
    +++ b/src/draw.c
    @@ -3487,10 +3487,12 @@ int edit_wave_attributes(int what, int i, Graph_ctx *gr)
               } else {
                  if(gr->hilight_wave == wcnt) {
                    gr->hilight_wave = -1;
    -               my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
    +               my_strdup2(_ALLOC_ID_, &r->prop_ptr,
    +                          subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
                  } else {
                    gr->hilight_wave = wcnt;
    -               my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
    +               my_strdup2(_ALLOC_ID_, &r->prop_ptr,
    +                          subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
                  }
               }
             }
    @@ -3512,10 +3514,12 @@ int edit_wave_attributes(int what, int i, Graph_ctx *gr)
             } else {
               if(gr->hilight_wave == wcnt) {
                 gr->hilight_wave = -1;
    -            my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
    +            my_strdup2(_ALLOC_ID_, &r->prop_ptr,
    +                       subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
               } else {
                 gr->hilight_wave = wcnt;
    -            my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
    +            my_strdup2(_ALLOC_ID_, &r->prop_ptr,
    +                       subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave)));
               }
             }
           }
    diff --git a/src/scheduler.c b/src/scheduler.c
    index f16988b1..d0a98a66 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -3024,6 +3024,24 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           else if(argc==2 && errfp != stderr) { fclose(errfp); errfp=stderr; }
         }
     
    +    /* load_symbol [symbol_file]
    +     *   Load specified symbol_file  */
    +    else if(!strcmp(argv[1], "load_symbol") )
    +    {
    +      int res = -1;
    +      struct stat buf;
    +      if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    +      if(argc > 2) { 
    +        int i = get_symbol(rel_sym_path(argv[2]));
    +        if(i < 0 ) {
    +          if(!stat(argv[2], &buf)) { /* file exists */
    +            res = load_sym_def(rel_sym_path(argv[2]), NULL);
    +          }
    +        }
    +      }
    +      Tcl_SetResult(interp, my_itoa(res), TCL_VOLATILE);
    +    }
    +
         /* log_write text
          *   write given string to log file, so tcl can write messages on the log file
          */
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 217a2452..d78af432 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -6631,8 +6631,12 @@ proc try_download_url {dirname sch_or_sym} {
     # Example: rel_sym_path /home/schippes/share/xschem/xschem_library/devices/iopin.sym
     #          devices/iopin.sym
     proc rel_sym_path {symbol} {
    -  global OS pathlist
    +  global OS pathlist env
     
    +  regsub {^~/} $symbol ${env(HOME)}/ symbol
    +  if {![regexp {^/} $symbol]} {
    +    set symbol [pwd]/$symbol
    +  }
       set curr_dirname [pwd]
       set name {}
       foreach path_elem $pathlist {
    
    From cefd320ef6639f37726e118ec43b47ea50c3e87a Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Sat, 15 Feb 2025 01:33:13 +0100
    Subject: [PATCH 35/46] complete previous `xschem load_symbol` command
    
    ---
     doc/xschem_man/developer_info.html |  5 ++++-
     src/scheduler.c                    | 13 +++++++++++--
     2 files changed, 15 insertions(+), 3 deletions(-)
    
    diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html
    index a133d8be..2d795720 100644
    --- a/doc/xschem_man/developer_info.html
    +++ b/doc/xschem_man/developer_info.html
    @@ -1029,7 +1029,10 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        if 'f' is not given and a file log is open, close log
        file and resume logging to stderr 
  • load_symbol [symbol_file]
  • -   Load specified symbol_file  
    + Load specified symbol_file + Returns: + >= 0: symbol is already loaded or has been loaded + < 0: symbol was not loaded
  • log_write text
  •     write given string to log file, so tcl can write messages on the log file
  • logic_get_net net_name
  • diff --git a/src/scheduler.c b/src/scheduler.c
    index d0a98a66..c7aaf8e4 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -3025,10 +3025,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
         }
     
         /* load_symbol [symbol_file]
    -     *   Load specified symbol_file  */
    +     *   Load specified symbol_file
    +     *   Returns:
    +     *     >= 0: symbol is already loaded or has been loaded
    +     *     <  0: symbol was not loaded
    +     */
         else if(!strcmp(argv[1], "load_symbol") )
         {
    -      int res = -1;
    +      int res = -2;
           struct stat buf;
           if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
           if(argc > 2) { 
    @@ -3036,7 +3040,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
             if(i < 0 ) {
               if(!stat(argv[2], &buf)) { /* file exists */
                 res = load_sym_def(rel_sym_path(argv[2]), NULL);
    +            if(res == 0) res = -1;
    +          } else {
    +            res = -3;
               }
    +        } else {
    +          res = 1;
             }
           }
           Tcl_SetResult(interp, my_itoa(res), TCL_VOLATILE);
    
    From 446f7949b41eedbf92e9f34013f14191c3d7cbda Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Sun, 16 Feb 2025 01:09:28 +0100
    Subject: [PATCH 36/46] integrated @georgtree proc symbolParse
    
    ---
     src/xschem.tcl | 44 ++++++++++++++++++++++++++++++++++++++++++++
     1 file changed, 44 insertions(+)
    
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index d78af432..10f92d1a 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -6021,6 +6021,50 @@ proc edit_prop {txtlabel} {
       return $tctx::rcode
     }
     
    +# reads metadata tokens from header component of the symbol inside `v {data}` element
    +# and returns dictionary in name of the token as key and value of the token as value in dictionary
    +# Courtesy @georgtree
    +proc symbolParse {file} {
    +    try {
    +        set file [open $file r]
    +    } on error {errmsg erropts} {
    +        puts stderr "Error while reading symbol file '$file': $errmsg"
    +        return
    +    }
    +    set data [read $file]
    +    close $file
    +    # pattern to find v {} and extract content inside brackets
    +    set pattern {(?:^|\n)v\s+\{((?:[^{}]|\\[{}])*)\}}
    +    if {![regexp $pattern $data -> content]} {
    +        return
    +    }
    +    # outer braces {...} are not part of content, so remove escaping of inner {, } and \ .
    +    set content [string map { \\\{ \{ \\\} \} \\\\ \\ } $content]
    +    # pattern to find: name="value" or name=value or name = "value" or name = value
    +    set pattern {(\w+)\s*=\s*(?:"((?:[^"]|\\["])*)"|(\S+))}
    +    set start 0
    +    # 'match' variable holds the complete matched pattern, used for searching next one
    +    while {[regexp -start $start $pattern $content -> name quotedValue unquotedValue]} {
    +        # Determine the value (quoted or unquoted)
    +        if {[string length $quotedValue] > 0} {
    +            # outer quotes are not part of quotedValue,
    +            # remove escaping of internal backslashes and doublequotes
    +            set value $quotedValue
    +            dict append tokens $name [string map {\\\\ \\ \\\" \" } $value]
    +        } else {
    +            set value $unquotedValue
    +            dict append tokens $name $value
    +        }
    +        # Update the start index to continue searching after this match
    +        set start [expr {[string first $value $content $start] + [string length $value]}]
    +        # Safety check to prevent infinite loops
    +        if {$start <= 0} {
    +            break
    +        }
    +    }
    +    return $tokens
    +}
    +
     proc read_data_nonewline {f} {
       set fid [open $f r]
       set data [read -nonewline $fid]
    
    From 51c6eded14417b5f94b620b9e5acbbb635419aab Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Sun, 16 Feb 2025 01:11:32 +0100
    Subject: [PATCH 37/46] (2) integrated @georgtree proc symbolParse
    
    ---
     src/xschem.tcl | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 10f92d1a..9dae3ee5 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -6047,10 +6047,10 @@ proc symbolParse {file} {
         while {[regexp -start $start $pattern $content -> name quotedValue unquotedValue]} {
             # Determine the value (quoted or unquoted)
             if {[string length $quotedValue] > 0} {
    -            # outer quotes are not part of quotedValue,
    -            # remove escaping of internal backslashes and doublequotes
                 set value $quotedValue
    -            dict append tokens $name [string map {\\\\ \\ \\\" \" } $value]
    +            # outer quotes are removed from value,
    +            # remove escaping of internal backslashes and doublequotes
    +            dict append tokens $name [string map {\\\\ \\ \\\" \" } $value] 
             } else {
                 set value $unquotedValue
                 dict append tokens $name $value
    
    From 1e1c56801dac6b56377b3498837803a5ea448297 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Sun, 16 Feb 2025 14:08:31 +0100
    Subject: [PATCH 38/46] when loading a raw file, if graphs are present and
     cursor2 is enabled in 1st graph setup annotation in the schematic (no need to
     move the cursor)
    
    ---
     src/save.c                     | 12 ++++++++++++
     xschem_library/devices/ind.sym |  8 ++++----
     2 files changed, 16 insertions(+), 4 deletions(-)
    
    diff --git a/src/save.c b/src/save.c
    index b549c589..4445f20a 100644
    --- a/src/save.c
    +++ b/src/save.c
    @@ -1038,6 +1038,18 @@ int raw_read(const char *f, Raw **rawptr, const char *type, int no_warning, doub
           dbg(0, "Raw file data read: %s\n", f);
           dbg(0, "points=%d, vars=%d, datasets=%d sim_type=%s\n", 
                  raw->allpoints, raw->nvars, raw->datasets, raw->sim_type ? raw->sim_type : "");
    +
    +      if(xctx->graph_flags & 4) { /* if cursor2 is enabled in first graph setup schematic annotation */
    +        if(xctx->rects[GRIDLAYER] > 0)  {
    +          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);
    +          }
    +        }
    +      }
    +
         } else {
           /* free_rawfile(rawptr, 0, 0); */ /* do not free: already done in read_dataset()->extra_rawfile() */
           if(!no_warning) {
    diff --git a/xschem_library/devices/ind.sym b/xschem_library/devices/ind.sym
    index b645c028..913da636 100644
    --- a/xschem_library/devices/ind.sym
    +++ b/xschem_library/devices/ind.sym
    @@ -1,4 +1,4 @@
    -v {xschem version=3.4.5 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
    @@ -47,7 +47,7 @@ T {@#0:pinnumber} -10 -27.5 0 1 0.2 0.2 {layer=13}
     T {@#1:pinnumber} -10 17.5 0 1 0.2 0.2 {layer=13}
     T {@#0:net_name} 5 -42.5 0 0 0.15 0.15 {layer=15 hide=instance}
     T {@#1:net_name} 5 32.5 0 0 0.15 0.15 {layer=15 hide=instance}
    -T {@name} 15 -18.75 0 0 0.2 0.2 {}
    -T {@value} 15 -3.75 0 0 0.2 0.2 {}
    -T {m=@m} 15 11.25 0 0 0.2 0.2 {}
     T {@spice_get_current} -12.5 5 0 1 0.2 0.2 {layer=17}
    +T {@name} 15 -18.75 0 0 0.2 0.2 {}
    +T {@value} 15 -6.25 0 0 0.2 0.2 {}
    +T {m=@m} 15 6.25 0 0 0.2 0.2 {}
    
    From a7ae4eaca875b0f226d5a16655eb84125541a1a2 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Mon, 17 Feb 2025 13:45:12 +0100
    Subject: [PATCH 39/46] added some simple helper complex number procedures
    
    ---
     src/xschem.tcl | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
     1 file changed, 55 insertions(+)
    
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 9dae3ee5..56fcda69 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -693,6 +693,61 @@ proc spaces {n {indent 4}} {
       return [string repeat { } $n]
     }
     
    +# complex number operators
    +# a + b
    +proc cadd {a b} {
    +  lassign $a ra ia
    +  lassign $b rb ib
    +  set c [list [expr {$ra + $rb}] [expr {$ia + $ib}]]
    +  return $c
    +}
    +
    +# a - b
    +proc csub {a b} {
    +  lassign $a ra ia
    +  lassign $b rb ib
    +  set c [list [expr {$ra - $rb}] [expr {$ia - $ib}]]
    +  return $c
    +}
    +
    +# a * b
    +proc cmul {a b} {
    +  lassign $a ra ia
    +  lassign $b rb ib
    +  set c [list [expr {$ra * $rb - $ia * $ib}] [expr {$ra * $ib + $rb * $ia}]]
    +  return $c
    +}
    +
    +# a / b
    +proc cdiv {a b} {
    +  lassign $a ra ia
    +  lassign $b rb ib
    +  set ra [expr {double($ra)}]
    +  set ia [expr {double($ia)}]
    +  set rb [expr {double($rb)}]
    +  set ib [expr {double($ib)}]
    +  set m [expr {$rb * $rb + $ib * $ib}]
    +  set c [list [expr {($ra * $rb + $ia * $ib) / $m}] [expr {($rb * $ia - $ra * $ib) / $m}]]
    +  return $c
    +}
    +
    +# return real component
    +proc creal {a} {
    +  lassign $a ra ia
    +  return $ra
    +}
    +
    +# return imaginary component
    +proc cimag {a} {
    +  lassign $a ra ia
    +  return $ia
    +}
    +
    +# return resulting impedance of parallel connected impedances a and b
    +proc cparallel {a b} {
    +  return [cdiv [cmul $a $b] [cadd $a $b]]
    +}
    +
     # wraps provided table formatted text into a nice looking bordered table 
     # sep is the list of characters used as separators, default are { }, {,}, {\t}
     # if you want to tabulate data with spaces use only {,} as separator or any other character.
    
    From 4623b1c8699df3e2ec8efdb7a7c9daff61a29fb4 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Mon, 17 Feb 2025 16:10:44 +0100
    Subject: [PATCH 40/46] add ellipses/ellipse_arcs rendering in svg export
    
    ---
     src/svgdraw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++------
     1 file changed, 62 insertions(+), 8 deletions(-)
    
    diff --git a/src/svgdraw.c b/src/svgdraw.c
    index a6b8d885..2f48e875 100644
    --- a/src/svgdraw.c
    +++ b/src/svgdraw.c
    @@ -154,7 +154,8 @@ static void svg_drawpolygon(int c, int what, double *x, double *y, int points, i
       fprintf(fd, "\"/>\n");
     }
     
    -static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2, int dash, int fill)
    +static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2,
    +                           int dash, int fill, int e_a, int e_b)
     {
      double x1,y1,x2,y2;
     
    @@ -164,7 +165,41 @@ static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,dou
       y2=Y_TO_SCREEN(recty2);
       if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) )
       {
    -   svg_xfillrectangle(gc, x1,y1,x2,y2, dash, fill);
    +    if(e_a != -1) {
    +      double rx = (x2 - x1) / 2.0;
    +      double ry = (y2 - y1) / 2.0;
    +      double cx = (x2 + x1) / 2.0;
    +      double cy = (y2 + y1) / 2.0;
    +
    +      if(e_b == 360.) {
    +        fprintf(fd, "zoom, 1.4*dash/xctx->zoom);
    +        if(fill == 0) fprintf(fd, "style=\"fill:none;\" ");
    +        else if(fill == 3) fprintf(fd, "style=\"fill-opacity:1.0;\" ");
    +        fprintf(fd, "/>\n");
    +      } else {
    +        double xx1 = rx * cos(e_a * XSCH_PI / 180.) + cx;
    +        double yy1 = -ry * sin(e_a * XSCH_PI / 180.) + cy;
    +        double xx2 = rx * cos((e_a + e_b) * XSCH_PI / 180.) + cx;
    +        double yy2 = -ry * sin((e_a + e_b) * XSCH_PI / 180.) + cy;
    +        int fa = e_b > 180 ? 1 : 0;
    +        int fs = e_b > 0 ? 0 : 1;
    +
    +        fprintf(fd,"zoom, 1.4*dash/xctx->zoom);
    +        if(fill == 0) {
    +           fprintf(fd,"style=\"fill:none;\" ");
    +           fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %g\"/>\n", xx1, yy1, rx, ry, fa, fs, xx2, yy2);
    +        } else if(fill == 3) {
    +          fprintf(fd, "style=\"fill-opacity:1.0;\" ");
    +          fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rx, ry, fa, fs, xx2, yy2, cx, cy);
    +        } else {
    +          fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rx, ry, fa, fs, xx2, yy2, cx, cy);
    +        }
    +      }
    +    } else {
    +      svg_xfillrectangle(gc, x1,y1,x2,y2, dash, fill);
    +    }
       }
     }
     
    @@ -231,7 +266,7 @@ static void svg_drawarc(int gc, int fillarc, double x,double y,double r,double a
             fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rr, rr, fa, fs, xx2, yy2, xx, yy);
           } else {
             fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rr, rr, fa, fs, xx2, yy2, xx, yy);
    -     }
    +      }
         }
       }
     }
    @@ -603,7 +638,7 @@ static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot,
         }
         else if((xctx->inst[n].x2 - xctx->inst[n].x1) * xctx->mooz < 3 &&
                            (xctx->inst[n].y2 - xctx->inst[n].y1) * xctx->mooz < 3) {
    -      svg_filledrect(c, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 0, 0);
    +      svg_filledrect(c, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 0, 0, -1, -1);
           xctx->inst[n].flags|=1;
           return;
         }
    @@ -612,7 +647,7 @@ static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot,
         }
         if(hide) {
           int color = (disabled==1) ? GRIDLAYER : (disabled == 2) ? PINLAYER : SYMLAYER;
    -      svg_filledrect(color, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 2, 0);
    +      svg_filledrect(color, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 2, 0, -1, -1);
         }
       }
       else if(xctx->inst[n].flags&1) {
    @@ -692,9 +727,27 @@ static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot,
             double xx2 = x0 + x2;
             double yy2 = y0 + y2;
             svg_embedded_image(rect, xx1, yy1, xx2, yy2, rot, flip);
    -        continue;
    +      } else {
    +        int ellipse_a = rect->ellipse_a;
    +        int ellipse_b = rect->ellipse_b;
    +
    +        if(ellipse_a != -1 && ellipse_b != 360) {
    +          if(flip) {
    +            ellipse_a = 180 - ellipse_a - ellipse_b;
    +          }
    +          if(rot) {
    +            if(rot == 3) {
    +              ellipse_a += 90;
    +            } else if(rot == 2) {
    +              ellipse_a += 180;
    +            } else if(rot == 1) {
    +              ellipse_a += 270;
    +            }
    +            ellipse_a %= 360;
    +          }
    +        }
    +        svg_filledrect(c, x0+x1, y0+y1, x0+x2, y0+y2, dash, rect->fill, ellipse_a, ellipse_b);
           }
    -      svg_filledrect(c, x0+x1, y0+y1, x0+x2, y0+y2, dash, rect->fill);
         }
       }
     
    @@ -976,7 +1029,8 @@ void svg_draw(void)
          } else {
            svg_filledrect(c, xctx->rect[c][i].x1, xctx->rect[c][i].y1,
                              xctx->rect[c][i].x2, xctx->rect[c][i].y2,
    -                         xctx->rect[c][i].dash,  xctx->rect[c][i].fill);
    +                         xctx->rect[c][i].dash,  xctx->rect[c][i].fill,
    +                         xctx->rect[c][i].ellipse_a, xctx->rect[c][i].ellipse_b);
          }
        }
        for(i=0;iarcs[c]; ++i)
    
    From 9eb012e6a306ffd15e953158f95982e3d203e438 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Mon, 17 Feb 2025 17:53:49 +0100
    Subject: [PATCH 41/46] fix image in symbols rotation/flip for svg exports
    
    ---
     src/draw.c    |  4 ++--
     src/svgdraw.c | 31 ++++++++++++++++++++++++++++---
     2 files changed, 30 insertions(+), 5 deletions(-)
    
    diff --git a/src/draw.c b/src/draw.c
    index b726ecf6..b8dd83b6 100644
    --- a/src/draw.c
    +++ b/src/draw.c
    @@ -4534,7 +4534,7 @@ static cairo_surface_t *get_surface_from_file(const char *filename, const char *
             #endif
           }
           if(!surface || cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
    -        if(jpg != 1) dbg(0, "draw_image(): failure creating image surface from %s\n", filename);
    +        if(jpg != 1) dbg(0, "get_surface_from_file(): failure creating image surface from %s\n", filename);
             if(surface) cairo_surface_destroy(surface);
             my_free(_ALLOC_ID_, &closure.buffer);
             *buffer = NULL;
    @@ -4736,7 +4736,7 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
         cairo_translate(xctx->cairo_ctx, x, y);
         cairo_rotate(xctx->cairo_ctx, rot * XSCH_PI * 0.5);
         if(flip && (rot == 0 || rot == 2)) cairo_scale(xctx->cairo_ctx, -scalex, scaley);
    -    else if(flip && (rot == 1 || rot == 3)) cairo_scale(xctx->cairo_ctx, scalex, -scaley);
    +    else if(flip && (rot == 1 || rot == 3)) cairo_scale(xctx->cairo_ctx, -scalex, scaley);
         else cairo_scale(xctx->cairo_ctx, scalex, scaley);
         cairo_set_source_surface(xctx->cairo_ctx, emb_ptr->image, 0. , 0.);
         cairo_rectangle(xctx->cairo_ctx, 0, 0, w , h );
    diff --git a/src/svgdraw.c b/src/svgdraw.c
    index 2f48e875..4db04c17 100644
    --- a/src/svgdraw.c
    +++ b/src/svgdraw.c
    @@ -513,6 +513,7 @@ static int svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, doub
       double alpha = 1.0;
       unsigned char *buffer = NULL;
       size_t buffer_size;
    +  double xorig, yorig; /* image anchor point, upper left corner in SVG */
     
       x1=X_TO_SCREEN(rx1);
       y1=Y_TO_SCREEN(ry1);
    @@ -523,7 +524,6 @@ static int svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, doub
       if(RECT_OUTSIDE(x1, y1, x2, y2,
                       xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return 0;
          
    -
       if(rot == 1 || rot == 3) {
         w = fabs(y2 - y1);
         h = fabs(x2 - x1);
    @@ -533,7 +533,8 @@ static int svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, doub
       }
     
       if(flip && (rot == 0 || rot == 2)) scalex = -1.0;
    -  else if(flip && (rot == 1 || rot == 3)) scaley = -1.0;
    +  else if(flip && (rot == 1 || rot == 3)) scalex = -1.0;
    +
       alpha_str = get_tok_value(r->prop_ptr, "alpha", 0);
       if(alpha_str[0]) alpha = atof(alpha_str);
       attr_len = my_strdup2(_ALLOC_ID_, &attr, get_tok_value(r->prop_ptr, "image_data", 0));
    @@ -558,8 +559,32 @@ static int svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, doub
         my_free(_ALLOC_ID_, &attr);
         return 0;
       }
    +
    +  xorig = x1;
    +  yorig = y1;
    +  if(rot == 0) {
    +    if(flip) xorig += w;
    +  } else if(rot == 1) {
    +    if(flip) {
    +      xorig += h;
    +      yorig += w;
    +    } else xorig += h;
    +  } else if(rot == 2) {
    +    if(flip) {
    +      yorig += h;
    +    } else {
    +      xorig += w;
    +      yorig += h;
    +    }
    +  } else if(rot == 3) {
    +    if(flip) {
    +    } else {
    +      yorig += w;
    +    }
    +  }
    +
       my_snprintf(transform, S(transform), 
    -    "transform=\"translate(%g,%g) scale(%g,%g) rotate(%d)\"", x1, y1, scalex, scaley, rot * 90);
    +    "transform=\"translate(%g,%g) rotate(%d) scale(%g,%g)\"", xorig, yorig, rot * 90, scalex, scaley);
       if(alpha == 1.0)  strcpy(opacity, "");
       else my_snprintf(opacity, S(opacity), "style=\"opacity:%g;\"", alpha);
       /*    png         jpg */
    
    From 25db8b8f9acaaea05f04d72dc4482e5417bb1bbd Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Tue, 18 Feb 2025 02:25:55 +0100
    Subject: [PATCH 42/46] ellipses rendered in ps/pdf export. Do not allow to
     select objects with mouse button press if a poligon insertion is ongoing.
     my_fopen() for read mode open, check for regular file. More checks for failed
     fopen()s.
    
    ---
     src/actions.c         |  2 +-
     src/cairo_jpg.c       |  4 +--
     src/callback.c        |  7 ++--
     src/draw.c            | 36 +++++++++----------
     src/editprop.c        | 27 ++++++++++----
     src/hilight.c         |  2 +-
     src/netlist.c         |  3 +-
     src/options.c         |  3 +-
     src/paste.c           | 20 +++++------
     src/psprint.c         | 84 ++++++++++++++++++++++++++++++++++++++-----
     src/save.c            | 61 +++++++++++++++----------------
     src/scheduler.c       |  2 +-
     src/select.c          |  2 +-
     src/spice_netlist.c   |  6 ++++
     src/store.c           | 18 +++++-----
     src/svgdraw.c         | 12 +++----
     src/verilog_netlist.c |  6 ++++
     src/vhdl_netlist.c    |  6 ++++
     src/xinit.c           |  8 ++---
     src/xschem.h          |  3 +-
     20 files changed, 206 insertions(+), 106 deletions(-)
    
    diff --git a/src/actions.c b/src/actions.c
    index 59afb731..ba5bac99 100644
    --- a/src/actions.c
    +++ b/src/actions.c
    @@ -45,7 +45,7 @@ unsigned int hash_file(const char *f, int skip_path_lines)
       int cr = 0;
       unsigned int h=5381;
       char *line = NULL;
    -  fd = fopen(f, "r"); /* windows won't return \r in the lines and we chop them out anyway in the code */
    +  fd = my_fopen(f, "r"); /* windows won't return \r in the lines and we chop them out anyway in the code */
       if(fd) {
         while((line = my_fgets(fd, &n))) {
           /* skip lines of type: '** sch_path: ...' or '-- sch_path: ...' or '// sym_path: ...'
    diff --git a/src/cairo_jpg.c b/src/cairo_jpg.c
    index 62bc20cf..5c8b3359 100644
    --- a/src/cairo_jpg.c
    +++ b/src/cairo_jpg.c
    @@ -460,7 +460,7 @@ cairo_surface_t *cairo_image_surface_create_from_jpeg_stream(cairo_read_func_t r
      * @return Returns a pointer to a cairo_surface_t structure. It should be
      * checked with cairo_surface_status() for errors.
      * @note If the returned surface is invalid you can use errno to determine
    - * further reasons. Errno is set according to fopen(3) and malloc(3). If you
    + * further reasons. Errno is set according to my_fopen(3) and malloc(3). If you
      * intend to check errno you shall set it to 0 before calling this function
      * because it does not modify errno itself.
      */
    @@ -520,7 +520,7 @@ static cairo_status_t cj_read(void *closure, unsigned char *data, unsigned int l
      * @return Returns a pointer to a cairo_surface_t structure. It should be
      * checked with cairo_surface_status() for errors.
      * @note If the returned surface is invalid you can use errno to determine
    - * further reasons. Errno is set according to fopen(3) and malloc(3). If you
    + * further reasons. Errno is set according to my_fopen(3) and malloc(3). If you
      * intend to check errno you shall set it to 0 before calling this function
      * because it does not modify errno itself.
      */
    diff --git a/src/callback.c b/src/callback.c
    index 1853799d..374b4389 100644
    --- a/src/callback.c
    +++ b/src/callback.c
    @@ -2763,12 +2763,12 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
        {
         int x;
         xctx->fill_pattern++;
    -    if(xctx->fill_pattern==3) xctx->fill_pattern=0;
    +    if(xctx->fill_pattern==2) xctx->fill_pattern=0;
     
         if(xctx->fill_pattern==1) {
          tcleval("alert_ { Stippled pattern fill} {}");
          for(x=0;xfill_type[x]==1) XSetFillStyle(display,xctx->gcstipple[x],FillSolid);
    +       if(xctx->fill_type[x]==2) XSetFillStyle(display,xctx->gcstipple[x],FillSolid);
            else XSetFillStyle(display,xctx->gcstipple[x],FillStippled);
          }
         }
    @@ -4182,7 +4182,8 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in
          if(end_place_move_copy_zoom()) return;
     
          /* Button1Press to select objects */
    -     if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) {
    +     if( !(xctx->ui_state & STARTPOLYGON) && !(xctx->ui_state & STARTSELECT) &&
    +         !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) {
            Selected sel;
            int already_selected = 0;
            int prev_last_sel = xctx->lastsel;
    diff --git a/src/draw.c b/src/draw.c
    index b8dd83b6..bee7b42b 100644
    --- a/src/draw.c
    +++ b/src/draw.c
    @@ -1591,9 +1591,9 @@ void drawarc(int c, int what, double x, double y, double r, double a, double b,
                   (int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64));
        }
     
    -   if(xctx->fill_pattern && (xctx->fill_type[c] || arc_fill == 3) ){
    +   if(xctx->fill_pattern && (xctx->fill_type[c] || arc_fill == 2) ){
     
    -     if(arc_fill & 2) gc = xctx->gc[c];
    +     if(arc_fill == 2) gc = xctx->gc[c];
          else             gc = xctx->gcstipple[c];
          if(arc_fill) {
            if(xctx->draw_window)
    @@ -1631,8 +1631,8 @@ void filledrect(int c, int what, double rectx1,double recty1,double rectx2,doubl
     
      if(!has_x) return;
      if(!xctx->fill_pattern) return;
    - if(fill != 3 && !xctx->fill_type[c]) return;
    - if(fill == 3) { /* full fill */
    + if(fill != 2 && !xctx->fill_type[c]) return;
    + if(fill == 2) { /* full fill */
        gc = xctx->gc[c];
        r = rf;
        i = &iif;
    @@ -1782,7 +1782,7 @@ void arc_bbox(double x, double y, double r, double a, double b,
     /* Convex Nonconvex Complex */
     #define Polygontype Nonconvex
     
    -/* fill = 1: stippled fill, fill == 3: solid fill */
    +/* fill = 1: stippled fill, fill == 2: solid fill */
     void drawbezier(Drawable w, GC gc, int c, double *x, double *y, int points, int fill)
     {
       const double bez_steps = 1.0/32.0; /* divide the t = [0,1] interval into 32 steps */
    @@ -1846,7 +1846,7 @@ void drawbezier(Drawable w, GC gc, int c, double *x, double *y, int points, int
       XDrawLines(display, w, gc, p, i, CoordModeOrigin);
       if(fill == 1) 
         XFillPolygon(display, w, xctx->gcstipple[c], p, i, Polygontype, CoordModeOrigin);
    -  else if(fill==3) 
    +  else if(fill==2) 
         XFillPolygon(display, w, xctx->gc[c], p, i, Polygontype, CoordModeOrigin);
     }
     
    @@ -1882,7 +1882,7 @@ void drawpolygon(int c, int what, double *x, double *y, int points, int poly_fil
           for(i=0;ifill_pattern && ((xctx->fill_type[c] && poly_fill == 1) || poly_fill == 3 ) &&
    +  fill = xctx->fill_pattern && ((xctx->fill_type[c] && poly_fill == 1) || poly_fill == 2 ) &&
              (x[0] == x[points-1]) && (y[0] == y[points-1]);
       bezier = (flags & 1)  && (points > 2);
       if(dash) {
    @@ -1893,19 +1893,19 @@ void drawpolygon(int c, int what, double *x, double *y, int points, int poly_fil
       }
       if(xctx->draw_window) {
         if(bezier) {
    -      drawbezier(xctx->window, xctx->gc[c], c, x, y, points, fill | (poly_fill & 2) );
    +      drawbezier(xctx->window, xctx->gc[c], c, x, y, points, fill ? poly_fill : 0 );
         } else {
           XDrawLines(display, xctx->window, xctx->gc[c], p, points, CoordModeOrigin);
         }
       }
       if(xctx->draw_pixmap) {
         if(bezier) {
    -      drawbezier(xctx->save_pixmap, xctx->gc[c], c, x, y, points, fill | (poly_fill & 2) );
    +      drawbezier(xctx->save_pixmap, xctx->gc[c], c, x, y, points, fill ? poly_fill : 0);
         } else {
           XDrawLines(display, xctx->save_pixmap, xctx->gc[c], p, points, CoordModeOrigin);
         }
       }
    -  if(poly_fill & 2) gc = xctx->gc[c];
    +  if(poly_fill == 2) gc = xctx->gc[c];
       else              gc = xctx->gcstipple[c];
       if(fill && !bezier) {
         if(xctx->draw_window)
    @@ -2836,9 +2836,9 @@ static void draw_graph_grid(Graph_ctx *gr, void *ct)
     
       /* clipping everything outside container area */
       /* background */
    -  filledrect(0, NOW, gr->rx1, gr->ry1, gr->rx2, gr->ry2, 3, -1, -1);
    +  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, 2, -1, -1);
    +  drawrect(GRIDLAYER, NOW, gr->rx1, gr->ry1, gr->rx2, gr->ry2, 0, -1, -1);
     
       bbox(START, 0.0, 0.0, 0.0, 0.0);
       bbox(ADD, gr->rx1, gr->ry1, gr->rx2, gr->ry2);
    @@ -3133,7 +3133,7 @@ static void draw_cursor(double active_cursorx, double other_cursorx, int cursor_
         else
            my_snprintf(tmpstr, S(tmpstr), "%s",  dtoa_eng(active_cursorx));
         text_bbox(tmpstr, txtsize, txtsize, 2, flip, 0, 0, xx + xoffs, gr->ry2-1, &tx1, &ty1, &tx2, &ty2, &tmp, &dtmp);
    -    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 3, -1, -1);
    +    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 2, -1, -1);
         draw_string(cursor_color, NOW, tmpstr, 2, flip, 0, 0, xx + xoffs, gr->ry2-1, txtsize, txtsize);
       }
     }
    @@ -3198,7 +3198,7 @@ static void draw_hcursor(double active_cursory, int cursor_color, Graph_ctx *gr)
         th = (ty2 - ty1) / 2.; /* half text height */
         ty1 -= th;
         ty2 -= th;
    -    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 3, -1, -1);
    +    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 2, -1, -1);
         draw_string(cursor_color, NOW, tmpstr, 0, 0, 0, 0, gr->rx1 + 5, yy - th, txtsize, txtsize);
       }
     }
    @@ -3230,7 +3230,7 @@ static void draw_hcursor_difference(double c1, double c2, Graph_ctx *gr)
          my_snprintf(tmpstr, S(tmpstr), " %s ",  dtoa_eng(diffh));
       text_bbox(tmpstr, txtsize, txtsize, 0, 0, 0, 1, xx, yy, &tx1, &ty1, &tx2, &ty2, &tmp, &dtmp);
       if( 2 * (ty2 - ty1) < diff ) {
    -    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 3, -1, -1);
    +    filledrect(0, NOW,  tx1, ty1, tx2, ty2, 2, -1, -1);
         draw_string(3, NOW, tmpstr, 0, 0, 0, 1, xx, yy, txtsize, txtsize);
         if( a > b) {
           dtmp = a; a = b; b = dtmp;
    @@ -4476,7 +4476,7 @@ static cairo_surface_t *get_surface_from_file(const char *filename, const char *
         }
         filesize = (size_t)buf.st_size;
         if(filesize > 0) {
    -      fd = fopen(filename, fopen_read_mode);
    +      fd = my_fopen(filename, fopen_read_mode);
           if(fd) {
             size_t bytes_read;
             filedata = my_malloc(_ALLOC_ID_, filesize);
    @@ -4990,7 +4990,7 @@ void draw(void)
                 draw_symbol(ADD, cc, i,c, 0, 0, 0.0, 0.0);     /* ... then draw current layer      */
             }
           }
    -      filledrect(cc, END, 0.0, 0.0, 0.0, 0.0, 3, -1, -1); /* last parameter must be 3! */
    +      filledrect(cc, END, 0.0, 0.0, 0.0, 0.0, 2, -1, -1); /* fill parameter must be 2! */
           drawarc(cc, END, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0);
           drawrect(cc, END, 0.0, 0.0, 0.0, 0.0, 0, -1, -1);
           drawline(cc, END, 0.0, 0.0, 0.0, 0.0, 0, NULL);
    @@ -5017,7 +5017,7 @@ void draw(void)
                 xctx->wire[i].x2,xctx->wire[i].y2, 0, NULL);
           }
           update_conn_cues(cc, 1, xctx->draw_window);
    -      filledrect(cc, END, 0.0, 0.0, 0.0, 0.0, 3, -1, -1); /* fill parameter must be 3! */
    +      filledrect(cc, END, 0.0, 0.0, 0.0, 0.0, 2, -1, -1); /* fill parameter must be 2! */
           drawline(cc, END, 0.0, 0.0, 0.0, 0.0, 0, NULL);
         }
         if(xctx->draw_single_layer ==-1 || xctx->draw_single_layer==TEXTLAYER) {
    diff --git a/src/editprop.c b/src/editprop.c
    index 44a5d8e0..3a7f9323 100644
    --- a/src/editprop.c
    +++ b/src/editprop.c
    @@ -586,6 +586,19 @@ char *dtoa_prec(double i)
       return s;
     }
     
    +FILE *my_fopen(const char *f, const char *m)
    +{
    +  struct stat buf;
    +  FILE *fd = NULL;
    +  int st;
    +
    +  st = stat(f, &buf);
    +  if(st) return NULL; /* not existing or error */
    +  if(!S_ISREG(buf.st_mode)) return NULL; /* not a regular file/symlink to a regular file */
    +  fd = fopen(f, m);
    +  return fd;
    +}
    +
     size_t my_mstrcat(int id, char **str, const char *add, ...)
     {
       va_list args;
    @@ -1020,7 +1033,7 @@ static int edit_rect_property(int x)
           }
     
           attr = get_tok_value(xctx->rect[c][n].prop_ptr,"fill", 0);
    -      if(!strcmp(attr, "full")) xctx->rect[c][n].fill = 3;
    +      if(!strcmp(attr, "full")) xctx->rect[c][n].fill = 2;
           else if(!strboolcmp(attr, "false")) xctx->rect[c][n].fill = 0;
           else xctx->rect[c][n].fill = 1;
     
    @@ -1203,11 +1216,11 @@ static int edit_arc_property(void)
          old_fill = xctx->arc[c][i].fill;
          fill_ptr = get_tok_value(xctx->arc[c][i].prop_ptr,"fill",0);
          if( !strcmp(fill_ptr,"full") )
    -       xctx->arc[c][i].fill =3; /* bit 1: solid fill (not stippled) */
    +       xctx->arc[c][i].fill = 2; /* bit 1: solid fill (not stippled) */
          else if( !strboolcmp(fill_ptr,"true") )
    -       xctx->arc[c][i].fill =1;
    +       xctx->arc[c][i].fill = 1;
          else
    -       xctx->arc[c][i].fill =0;
    +       xctx->arc[c][i].fill = 0;
          old_dash = xctx->arc[c][i].dash;
          dash = get_tok_value(xctx->arc[c][i].prop_ptr,"dash",0);
          if( strcmp(dash, "") ) {
    @@ -1281,11 +1294,11 @@ static int edit_polygon_property(void)
     
          fill_ptr = get_tok_value(xctx->poly[c][i].prop_ptr,"fill",0);
          if( !strcmp(fill_ptr,"full") )
    -       xctx->poly[c][i].fill =3; /* bit 1: solid fill (not stippled) */
    +       xctx->poly[c][i].fill = 2; /* bit 1: solid fill (not stippled) */
          else if( !strboolcmp(fill_ptr,"true") )
    -       xctx->poly[c][i].fill =1;
    +       xctx->poly[c][i].fill = 1;
          else
    -       xctx->poly[c][i].fill =0;
    +       xctx->poly[c][i].fill = 0;
          dash = get_tok_value(xctx->poly[c][i].prop_ptr,"dash",0);
          if( strcmp(dash, "") ) {
            int d = atoi(dash);
    diff --git a/src/hilight.c b/src/hilight.c
    index fa7b8916..f7081c33 100644
    --- a/src/hilight.c
    +++ b/src/hilight.c
    @@ -2226,7 +2226,7 @@ void draw_hilight_net(int on_window)
               ((c==TEXTWIRELAYER || c==TEXTLAYER) && symptr->texts)) {
             draw_symbol(ADD, col, i,c,0,0,0.0,0.0);
           }
    -      filledrect(col, END, 0.0, 0.0, 0.0, 0.0, 3, -1, -1); /* last parameter must be 3! */
    +      filledrect(col, END, 0.0, 0.0, 0.0, 0.0, 2, -1, -1); /* last parameter must be 2! */
           drawarc(col, END, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0);
           drawrect(col, END, 0.0, 0.0, 0.0, 0.0, 0, -1, -1);
           drawline(col, END, 0.0, 0.0, 0.0, 0.0, 0, NULL);
    diff --git a/src/netlist.c b/src/netlist.c
    index 4180d46d..afa7f5b0 100644
    --- a/src/netlist.c
    +++ b/src/netlist.c
    @@ -1665,8 +1665,7 @@ int sym_vs_sch_pins(int all)
           /* pass through symbols, duplicated pins: do not check with schematic */
           if(rects > unique_pins) continue;
           get_sch_from_sym(filename, xctx->sym + i, -1, 0);
    -      if(!stat(filename, &buf)) {
    -        fd = fopen(filename, "r");
    +      if(!stat(filename, &buf) && (fd = my_fopen(filename, fopen_read_mode))) {
             pin_cnt = 0;
             endfile = 0;
             f_version[0] = '\0';
    diff --git a/src/options.c b/src/options.c
    index e2872111..732cc3ed 100644
    --- a/src/options.c
    +++ b/src/options.c
    @@ -111,10 +111,11 @@ static void check_opt(char *opt, char *optval, int type)
         } else if( (type == SHORT && *opt == 'l') || (type == LONG && !strcmp("log", opt)) ) {
             if(optval) {
               errfp = fopen(optval, "w");
    -          setvbuf(errfp, NULL, _IOLBF, 0); /* line (_IOLBF) or disable (_IONBF) buffering on error log */
               if(!errfp) {
                 errfp = stderr;
                 dbg(0, "Problems opening log file: %s\n", optval);
    +          } else {
    +            setvbuf(errfp, NULL, _IOLBF, 0); /* line (_IOLBF) or disable (_IONBF) buffering on error log */
               }
             }
         } else if( (type == SHORT && *opt == 'o') || (type == LONG && !strcmp("netlist_path", opt)) ) {
    diff --git a/src/paste.c b/src/paste.c
    index 125905e9..7ed3c536 100644
    --- a/src/paste.c
    +++ b/src/paste.c
    @@ -120,11 +120,11 @@ static void merge_box(FILE *fd)
     
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3;
    +      ptr[i].fill = 2;
         else if( !strboolcmp(fill_ptr, "false") )
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         else
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         set_rect_flags(&xctx->rect[c][i]); /* set cached .flags bitmask from on attributes */
         select_box(c,i, SELECTED, 1, 1);
         xctx->rects[c]++;
    @@ -159,11 +159,11 @@ static void merge_arc(FILE *fd)
     
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3; /* bit 1: solid fill (not stippled) */
    +      ptr[i].fill = 2; /* bit 1: solid fill (not stippled) */
         else if( !strboolcmp(fill_ptr, "true") )
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         else
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
         if(strcmp(dash, "")) {
           int d = atoi(dash);
    @@ -219,11 +219,11 @@ static void merge_polygon(FILE *fd)
         load_ascii_string( &ptr[i].prop_ptr, fd);
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3; /* bit 1: solid fill (not stippled) */
    +      ptr[i].fill = 2; /* bit 1: solid fill (not stippled) */
         else if( !strboolcmp(fill_ptr, "true") )
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         else
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
         if(strcmp(dash, "")) {
           int d = atoi(dash);
    @@ -379,7 +379,7 @@ void merge_file(int selection_load, const char ext[])
             my_free(_ALLOC_ID_, &cmd);
           } else fd = NULL;
         } else {
    -      fd=fopen(name, fopen_read_mode);
    +      fd=my_fopen(name, fopen_read_mode);
         }
         if(fd) {
          xctx->prep_hi_structs=0;
    diff --git a/src/psprint.c b/src/psprint.c
    index 26a003fd..3332aeb8 100644
    --- a/src/psprint.c
    +++ b/src/psprint.c
    @@ -443,11 +443,27 @@ static void ps_xdrawpoint(int layer, double x1, double y1)
      fprintf(fd, "%g %g %g %g L\n", x1, y1,x1,y1);
     }
     
    -static void ps_xfillrectange(int layer, double x1, double y1, double x2,
    +/* fill_pattern:
    + * 0 : no fill
    + * 1 : stippled fill
    + * 2 : solid fill
    + *
    + * fill_type[i]: 
    + * 0 : no fill
    + * 1 : patterned (stippled) fill
    + * 2 : solid fill
    + *
    + * fill:
    + * 0 : no fill
    + * 1 : stippled fill
    + * 2 : solid fill
    + */
    +
    +static void ps_xfillrectangle(int layer, double x1, double y1, double x2,
                       double y2, int fill)
     {
      fprintf(fd, "%g %g %g %g R\n", x1,y1,x2-x1,y2-y1);
    - if(fill &&  (xctx->fill_type[layer] == 1) && xctx->fill_pattern) {
    + if(xctx->fill_pattern && xctx->fill_type[layer] && fill) {
        fprintf(fd, "%g %g %g %g RF\n", x1,y1,x2-x1,y2-y1);
        /* fprintf(fd,"fill\n"); */
      }
    @@ -545,7 +561,8 @@ static void ps_drawpolygon(int c, int what, double *x, double *y, int points, in
     }
     
     
    -static void ps_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2, int dash, int fill)
    +static void ps_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2,
    +     int dash, int fill, int e_a, int e_b)
     {
      double x1,y1,x2,y2, tmp;
      double psdash;
    @@ -560,7 +577,21 @@ static void ps_filledrect(int gc, double rectx1,double recty1,double rectx2,doub
         if(dash) {
           fprintf(fd, "[%g %g] 0 setdash\n", psdash, psdash);
         }
    -    ps_xfillrectange(gc, x1,y1,x2,y2, fill);
    +    if(e_a != -1) {
    +      double rx = (x2 - x1) / 2.0;
    +      double ry = (y2 - y1) / 2.0;
    +      double cx = (x2 + x1) / 2.0;
    +      double cy = (y2 + y1) / 2.0;
    +
    +      if(xctx->fill_pattern && xctx->fill_type[gc] && fill) {
    +        fprintf(fd, "%g %g MT %g %g %g %g %d %d E %g %g LT C F S\n",
    +                    cx, cy, cx, cy, rx, ry, -e_a, -e_a-e_b, cx, cy);
    +      } else {
    +        fprintf(fd, "%g %g %g %g %d %d E S\n", cx, cy, rx, ry, -e_a, -e_a-e_b);
    +      }
    +    } else {
    +      ps_xfillrectangle(gc, x1,y1,x2,y2, fill);
    +    }
         if(dash) {
           fprintf(fd, "[] 0 setdash\n");
         }
    @@ -935,7 +966,7 @@ static void ps_draw_symbol(int c, int n,int layer, int what, short tmp_flip, sho
         #endif
         else if((xctx->inst[n].x2 - xctx->inst[n].x1) * xctx->mooz < 3 &&
                            (xctx->inst[n].y2 - xctx->inst[n].y1) * xctx->mooz < 3) {
    -      ps_filledrect(c, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 0, 0);
    +      ps_filledrect(c, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 0, 0, -1, -1);
           xctx->inst[n].flags|=1;
           return;
         }
    @@ -944,7 +975,7 @@ static void ps_draw_symbol(int c, int n,int layer, int what, short tmp_flip, sho
         }
         if(hide) {
           int color = (disabled==1) ? GRIDLAYER : (disabled == 2) ? PINLAYER : SYMLAYER;
    -      ps_filledrect(color, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 2, 0);
    +      ps_filledrect(color, xctx->inst[n].xx1, xctx->inst[n].yy1, xctx->inst[n].xx2, xctx->inst[n].yy2, 2, 0, -1, -1);
         }
         /* pdfmarks, only if doing hierarchy print and if symbol has a subcircuit */ 
         if(what != 7) {
    @@ -1031,6 +1062,7 @@ static void ps_draw_symbol(int c, int n,int layer, int what, short tmp_flip, sho
     
       if( (!hide && xctx->enable_layer[layer]) ||
           (hide && layer == PINLAYER && xctx->enable_layer[layer]) ) {
    +    if(symptr->rects[layer]) fprintf(fd, "NP\n"); /* newpath */
         for(j=0;j< symptr->rects[layer]; ++j)
         {
            int dash;
    @@ -1042,9 +1074,27 @@ static void ps_draw_symbol(int c, int n,int layer, int what, short tmp_flip, sho
            if (layer == GRIDLAYER && rect->flags & 1024) /* image */
            {
              ps_embedded_image(rect, x0 + x1, y0 + y1, x0 + x2, y0 + y2, rot, flip);
    -         continue;
    +       } else {
    +         int ellipse_a = rect->ellipse_a;
    +         int ellipse_b = rect->ellipse_b;
    +      
    +         if(ellipse_a != -1 && ellipse_b != 360) {
    +           if(flip) {
    +             ellipse_a = 180 - ellipse_a - ellipse_b;
    +           }
    +           if(rot) {
    +             if(rot == 3) {
    +               ellipse_a += 90;
    +             } else if(rot == 2) {
    +               ellipse_a += 180;
    +             } else if(rot == 1) {
    +               ellipse_a += 270;
    +             }
    +             ellipse_a %= 360;
    +           }
    +         }              
    +         ps_filledrect(c, x0+x1, y0+y1, x0+x2, y0+y2, dash, rect->fill, ellipse_a, ellipse_b);
            }
    -       ps_filledrect(c, x0+x1, y0+y1, x0+x2, y0+y2, dash, rect->fill);
         }
       } /* if( (!hide && xctx->enable_layer[layer]) || ... */
       
    @@ -1331,6 +1381,19 @@ void create_ps(char **psfile, int what, int fullzoom, int eps)
         fprintf(fd,"/C {closepath} bind def\n");
         fprintf(fd,"/F {fill} bind def\n");
         fprintf(fd,"/RF {rectfill} bind def\n");
    +    fprintf(fd,"/E {\n"); /* function for drawing ellipses */
    +    fprintf(fd,"/endangle exch def\n");
    +    fprintf(fd,"/startangle exch def\n");
    +    fprintf(fd,"/yrad exch def\n");
    +    fprintf(fd,"/xrad exch def\n");
    +    fprintf(fd,"/y exch def\n");
    +    fprintf(fd,"/x exch def\n");
    +    fprintf(fd,"/savematrix matrix currentmatrix def\n");
    +    fprintf(fd,"x y translate\n");
    +    fprintf(fd,"xrad yrad scale\n");
    +    fprintf(fd,"0 0 1 startangle endangle arcn\n");
    +    fprintf(fd,"savematrix setmatrix\n");
    +    fprintf(fd,"} def %% ellipse\n");
         fprintf(fd, "%%%%EndProlog\n");
       }
     
    @@ -1375,6 +1438,7 @@ void create_ps(char **psfile, int what, int fullzoom, int eps)
           for(i=0;ilines[c]; ++i)
             ps_drawline(c, xctx->line[c][i].x1, xctx->line[c][i].y1,
               xctx->line[c][i].x2, xctx->line[c][i].y2, xctx->line[c][i].dash);
    +      if(xctx->rects[c]) fprintf(fd, "NP\n"); /* newpath */
           for(i=0;irects[c]; ++i)
           {
             
    @@ -1390,7 +1454,9 @@ void create_ps(char **psfile, int what, int fullzoom, int eps)
             }
             if(c != GRIDLAYER || !(xctx->rect[c][i].flags & 1) )  {
               ps_filledrect(c, xctx->rect[c][i].x1, xctx->rect[c][i].y1,
    -            xctx->rect[c][i].x2, xctx->rect[c][i].y2, xctx->rect[c][i].dash, xctx->rect[c][i].fill);
    +            xctx->rect[c][i].x2, xctx->rect[c][i].y2,
    +            xctx->rect[c][i].dash, xctx->rect[c][i].fill,
    +            xctx->rect[c][i].ellipse_a, xctx->rect[c][i].ellipse_b);
             }
           }
           if(xctx->arcs[c]) fprintf(fd, "NP\n"); /* newpath */
    diff --git a/src/save.c b/src/save.c
    index 4445f20a..cefd1a04 100644
    --- a/src/save.c
    +++ b/src/save.c
    @@ -909,7 +909,7 @@ char *base64_from_file(const char *f, size_t *length)
       stat_res = stat(f, &st);
       if (stat_res == 0 && ( (st.st_mode & S_IFMT) == S_IFREG) ) {
         len = st.st_size;
    -    fd = fopen(f, fopen_read_mode);
    +    fd = my_fopen(f, fopen_read_mode);
         if(fd) {
           size_t bytes_read;
           s = my_malloc(_ALLOC_ID_, len);
    @@ -1023,7 +1023,7 @@ int raw_read(const char *f, Raw **rawptr, const char *type, int no_warning, doub
       raw->annot_sweep_idx = -1;
     
       int_hash_init(&raw->table, HASHSIZE);
    -  fd = fopen(f, fopen_read_mode);
    +  fd = my_fopen(f, fopen_read_mode);
       if(fd) {
         if((res = read_dataset(fd, rawptr, type, no_warning)) == 1) {
           int i;
    @@ -1467,7 +1467,7 @@ int table_read(const char *f)
       close(ufd);
     
       int_hash_init(&raw->table, HASHSIZE);
    -  fd = fopen(f, fopen_read_mode);
    +  fd = my_fopen(f, fopen_read_mode);
       if(fd) {
         int nline = 0;
         int field;
    @@ -2852,11 +2852,11 @@ static void load_polygon(FILE *fd)
         load_ascii_string( &ptr[i].prop_ptr, fd);
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3; /* bit 1: solid fill (not stippled) */
    +      ptr[i].fill = 2; /* bit 1: solid fill (not stippled) */
         else if( !strboolcmp(fill_ptr, "true") )
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         else
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
         if(strcmp(dash, "")) {
           int d = atoi(dash);
    @@ -2895,11 +2895,11 @@ static void load_arc(FILE *fd)
     
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3; /* bit 1: solid fill (not stippled) */
    +      ptr[i].fill = 2; /* bit 1: solid fill (not stippled) */
         else if( !strboolcmp(fill_ptr, "true") )
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         else
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
         if(strcmp(dash, "")) {
           int d = atoi(dash);
    @@ -2939,11 +2939,11 @@ static void load_box(FILE *fd)
         load_ascii_string( &ptr[i].prop_ptr, fd);
         fill_ptr = get_tok_value(ptr[i].prop_ptr,"fill",0);
         if( !strcmp(fill_ptr, "full") )
    -      ptr[i].fill =3;
    +      ptr[i].fill = 2;
         else if( !strboolcmp(fill_ptr, "false") )
    -      ptr[i].fill =0;
    +      ptr[i].fill = 0;
         else
    -      ptr[i].fill =1;
    +      ptr[i].fill = 1;
         attr = get_tok_value(ptr[i].prop_ptr,"dash",0);
         if(strcmp(attr, "")) {
           int d = atoi(attr);
    @@ -3544,7 +3544,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler
             my_free(_ALLOC_ID_, &cmd);
           } else fd = NULL;
         }
    -    else fd=fopen(name,fopen_read_mode);
    +    else fd=my_fopen(name,fopen_read_mode);
         if( fd == NULL) {
           size_t len;
           ret = 0;
    @@ -3823,7 +3823,7 @@ void pop_undo(int redo, int set_modify_status)
       fd=fdopen(pd[0],"r");
       #else /* uncompressed undo */
       my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
    -  fd=fopen(diff_name, "r");
    +  fd=my_fopen(diff_name, fopen_read_mode);
       if(!fd) {
         fprintf(errfp, "pop_undo(): failed to open read pipe %s\n", diff_name);
         xctx->no_undo=1;
    @@ -3894,9 +3894,9 @@ static void get_sym_type(const char *symname, char **type,
       if( !found ) {
         dbg(1, "get_sym_type(): open file %s, pintable %s\n",name, pintable ? "set" : "");
         /* ... if not found open file and look for 'type' into the global attributes. */
    -
    +    
         if(embed_fd) fd = embed_fd;
    -    else fd=fopen(name,fopen_read_mode);
    +    else fd=my_fopen(name,fopen_read_mode);
     
         if(fd==NULL) {
           dbg(1, "get_sym_type(): Symbol not found: %s\n",name);
    @@ -4238,15 +4238,15 @@ int load_sym_def(const char *name, FILE *embed_fd)
         } else {
           my_strncpy(sympath, abs_sym_path(transl_name, ""), S(sympath));
         }
    -    if((lcc[level].fd=fopen(sympath,fopen_read_mode))==NULL) {
    +    if((lcc[level].fd=my_fopen(sympath,fopen_read_mode))==NULL) {
           /* not found: try web URL */
           if(is_from_web(xctx->current_dirname)) {
             my_snprintf(sympath, S(sympath), "%s/%s", xschem_web_dirname, get_cell_w_ext(transl_name, 0));
    -        if((lcc[level].fd=fopen(sympath,fopen_read_mode))==NULL) {
    +        if((lcc[level].fd=my_fopen(sympath,fopen_read_mode))==NULL) {
               /* not already cached in .../xschem_web_xxxxx/ so download */
               tclvareval("try_download_url {", xctx->current_dirname, "} {", transl_name, "}", NULL);
             }
    -        lcc[level].fd=fopen(sympath,fopen_read_mode);
    +        lcc[level].fd=my_fopen(sympath,fopen_read_mode);
           }
         }
         dbg(1, "l_s_d(): fopen1(%s), level=%d, fd=%p\n",sympath, level, lcc[level].fd);
    @@ -4258,7 +4258,7 @@ int load_sym_def(const char *name, FILE *embed_fd)
         /* issue warning only on top level symbol loading */
         if(recursion_counter == 1) dbg(0, "l_s_d(): Symbol not found: %s\n", transl_name);
         my_snprintf(sympath, S(sympath), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/missing.sym");
    -    if((lcc[level].fd=fopen(sympath, fopen_read_mode))==NULL)
    +    if((lcc[level].fd=my_fopen(sympath, fopen_read_mode))==NULL)
         {
          fprintf(errfp, "l_s_d(): systemlib/missing.sym missing, I give up\n");
          tcleval("exit");
    @@ -4453,11 +4453,11 @@ int load_sym_def(const char *name, FILE *embed_fd)
       
             fill_ptr = get_tok_value(pp[c][i].prop_ptr,"fill",0);
             if( !strcmp(fill_ptr, "full") )
    -          pp[c][i].fill =3; /* bit 1: solid fill (not stippled) */
    +          pp[c][i].fill = 2; /* bit 1: solid fill (not stippled) */
             else if( !strboolcmp(fill_ptr, "true") )
    -          pp[c][i].fill =1;
    +          pp[c][i].fill = 1;
             else
    -          pp[c][i].fill =0;
    +          pp[c][i].fill = 0;
       
             attr = get_tok_value(pp[c][i].prop_ptr,"dash", 0);
             if( strcmp(attr, "") ) {
    @@ -4519,11 +4519,11 @@ int load_sym_def(const char *name, FILE *embed_fd)
             }
             fill_ptr = get_tok_value(aa[c][i].prop_ptr,"fill",0);
             if( !strcmp(fill_ptr, "full") )
    -          aa[c][i].fill =3; /* bit 1: solid fill (not stiaaled) */
    +          aa[c][i].fill = 2; /* bit 1: solid fill (not stiaaled) */
             else if( !strboolcmp(fill_ptr, "true") )
    -          aa[c][i].fill =1;
    +          aa[c][i].fill = 1;
             else
    -          aa[c][i].fill =0;
    +          aa[c][i].fill = 0;
             attr = get_tok_value(aa[c][i].prop_ptr,"dash", 0);
             if( strcmp(attr, "") ) {
               int d = atoi(attr);
    @@ -4582,11 +4582,11 @@ int load_sym_def(const char *name, FILE *embed_fd)
             dbg(2, "l_s_d(): loaded rect: ptr=%lx\n", (unsigned long)bb[c]);
             fill_ptr = get_tok_value(bb[c][i].prop_ptr,"fill",0);
             if( !strcmp(fill_ptr, "full") )
    -          bb[c][i].fill =3;
    +          bb[c][i].fill = 2;
             else if( !strboolcmp(fill_ptr, "false") )
    -          bb[c][i].fill =0;
    +          bb[c][i].fill = 0;
             else
    -          bb[c][i].fill =1;
    +          bb[c][i].fill = 1;
             attr = get_tok_value(bb[c][i].prop_ptr,"dash", 0);
             if( strcmp(attr, "") ) {
               int d = atoi(attr);
    @@ -4799,6 +4799,7 @@ int load_sym_def(const char *name, FILE *embed_fd)
              dbg(1, "l_s_d(): level=%d, symname=%s symtype=%s\n", level, symname, symtype);
              
              if(  /* add here symbol types not to consider when loading schematic-as-symbol instances */
    +             !symtype ||
                  !strcmp(symtype, "logo") ||
                  !strcmp(symtype, "netlist_commands") ||
                  !strcmp(symtype, "netlist_options") ||
    @@ -4829,7 +4830,7 @@ int load_sym_def(const char *name, FILE *embed_fd)
       
              dbg(1, "l_s_d(): fopen2(%s), level=%d\n",sympath, level);
              /* find out if symbol is in an external file or embedded, set fd_tmp accordingly */
    -         if ((fd_tmp = fopen(sympath, fopen_read_mode)) == NULL) {
    +         if ((fd_tmp = my_fopen(sympath, fopen_read_mode)) == NULL) {
                char c;
                fprintf(errfp, "l_s_d(): unable to open file to read schematic: %s\n", sympath);
                if(!generator) {
    diff --git a/src/scheduler.c b/src/scheduler.c
    index c7aaf8e4..21292799 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -5574,7 +5574,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
             set_rect_flags(r); /* set cached .flags bitmask from attributes */
             if(argc > 5 && !strcmp(argv[5], "fill")) {
               const char *attr = get_tok_value(r->prop_ptr,"fill", 0);
    -          if(!strcmp(attr, "full")) xctx->rect[c][n].fill = 3;
    +          if(!strcmp(attr, "full")) xctx->rect[c][n].fill = 2;
               else if(!strboolcmp(attr, "false")) xctx->rect[c][n].fill = 0;
               else xctx->rect[c][n].fill = 1;
             }
    diff --git a/src/select.c b/src/select.c
    index ca5105d2..620bac21 100644
    --- a/src/select.c
    +++ b/src/select.c
    @@ -439,7 +439,7 @@ static void del_rect_line_arc_poly()
        {
         ++j;
     
    -    if(xctx->arc[c][i].fill & 1) /* .fill: 1: stippled fill, 3: solid fill */
    +    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
    diff --git a/src/spice_netlist.c b/src/spice_netlist.c
    index c341895a..663a2a7d 100644
    --- a/src/spice_netlist.c
    +++ b/src/spice_netlist.c
    @@ -635,6 +635,11 @@ int spice_block_netlist(FILE *fd, int i, int alert)
              tclgetvar("netlist_dir"), get_cell(name, 0), getpid());
         dbg(1, "spice_block_netlist(): split_files: netl_filename=%s\n", netl_filename);
         fd=fopen(netl_filename, "w");
    +    if(!fd) {
    +      dbg(0, "spice_block_netlist(): unable to write file %s\n", netl_filename);
    +      err = 1;
    +      goto err;
    +    }
         my_snprintf(cellname, S(cellname), "%s.spice", get_cell(name, 0));
       }
       fprintf(fd, "\n* expanding   symbol:  %s # of pins=%d\n", name,xctx->sym[i].rects[PINLAYER] );
    @@ -689,6 +694,7 @@ int spice_block_netlist(FILE *fd, int i, int alert)
         set_tcl_netlist_type();
         if(debug_var==0) xunlink(netl_filename);
       }
    +  err:
       xctx->netlist_count++;
       my_free(_ALLOC_ID_, &name);
       return err;
    diff --git a/src/store.c b/src/store.c
    index e9fed4f1..ce02bdb6 100644
    --- a/src/store.c
    +++ b/src/store.c
    @@ -156,11 +156,11 @@ void store_arc(int pos, double x, double y, double r, double a, double b,
     
       fill_ptr = get_tok_value(xctx->arc[rectc][n].prop_ptr,"fill",0);
       if(!strcmp(fill_ptr, "full") )
    -    xctx->arc[rectc][n].fill =3; /* bit 1: solid fill (not stippled) */
    +    xctx->arc[rectc][n].fill = 2; /* bit 1: solid fill (not stippled) */
       else if(!strboolcmp(fill_ptr, "true") )
    -    xctx->arc[rectc][n].fill =1;
    +    xctx->arc[rectc][n].fill = 1;
       else
    -    xctx->arc[rectc][n].fill =0;
    +    xctx->arc[rectc][n].fill = 0;
       dash = get_tok_value(xctx->arc[rectc][n].prop_ptr,"dash",0);
       if( strcmp(dash, "") ) {
         int d = atoi(dash);
    @@ -206,11 +206,11 @@ void store_poly(int pos, double *x, double *y, int points, unsigned int rectc,
     
       fill_ptr = get_tok_value(xctx->poly[rectc][n].prop_ptr,"fill",0);
       if(!strcmp(fill_ptr, "full") )
    -    xctx->poly[rectc][n].fill =3; /* bit 1: solid fill (not stippled) */
    +    xctx->poly[rectc][n].fill = 2; /* bit 1: solid fill (not stippled) */
       else if(!strboolcmp(fill_ptr, "true") )
    -    xctx->poly[rectc][n].fill =1;
    +    xctx->poly[rectc][n].fill = 1;
       else
    -    xctx->poly[rectc][n].fill =0;
    +    xctx->poly[rectc][n].fill = 0;
       dash = get_tok_value(xctx->poly[rectc][n].prop_ptr,"dash",0);
       if( strcmp(dash, "") ) {
         int d = atoi(dash);
    @@ -307,11 +307,11 @@ int storeobject(int pos, double x1,double y1,double x2,double y2,
     
          fill_ptr = get_tok_value(xctx->rect[rectc][n].prop_ptr, "fill", 0);
          if(!strcmp(fill_ptr, "full") )
    -       xctx->rect[rectc][n].fill =3;
    +       xctx->rect[rectc][n].fill = 2;
          else if(!strboolcmp(fill_ptr,"false") )
    -       xctx->rect[rectc][n].fill =0;
    +       xctx->rect[rectc][n].fill = 0;
          else
    -       xctx->rect[rectc][n].fill =1;
    +       xctx->rect[rectc][n].fill = 1;
          set_rect_flags(&xctx->rect[rectc][n]); /* set cached .flags bitmask from on attributes */
          if(rectc == GRIDLAYER && (xctx->rect[rectc][n].flags & 1024)) {
             xRect *r = &xctx->rect[GRIDLAYER][n];
    diff --git a/src/svgdraw.c b/src/svgdraw.c
    index 4db04c17..44e0229a 100644
    --- a/src/svgdraw.c
    +++ b/src/svgdraw.c
    @@ -62,7 +62,7 @@ static void svg_xfillrectangle(int layer, double x1, double y1, double x2, doubl
       if(dash) fprintf(fd, "stroke-dasharray=\"%g,%g\" ", 1.4*dash/xctx->zoom, 1.4*dash/xctx->zoom);
       if(fill == 0) {
         fprintf(fd,"style=\"fill:none;\" ");
    -  } else if(fill == 3) {
    +  } else if(fill == 2) {
        fprintf(fd, "style=\"fill-opacity:1.0;\" ");
       }
       fprintf(fd,"d=\"M%g %gL%g %gL%g %gL%g %gL%g %gz\"/>\n", x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
    @@ -135,7 +135,7 @@ static void svg_drawpolygon(int c, int what, double *x, double *y, int points, i
       if(dash) fprintf(fd, "stroke-dasharray=\"%g,%g\" ", 1.4*dash/xctx->zoom, 1.4*dash/xctx->zoom);
       if(fill == 0) {
         fprintf(fd,"style=\"fill:none;\" ");
    -  } else if(fill == 3) {
    +  } else if(fill == 2) {
        fprintf(fd, "style=\"fill-opacity:1.0;\" ");
       }
       bezier = flags && (points > 2);
    @@ -175,7 +175,7 @@ static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,dou
             fprintf(fd, "zoom, 1.4*dash/xctx->zoom);
             if(fill == 0) fprintf(fd, "style=\"fill:none;\" ");
    -        else if(fill == 3) fprintf(fd, "style=\"fill-opacity:1.0;\" ");
    +        else if(fill == 2) fprintf(fd, "style=\"fill-opacity:1.0;\" ");
             fprintf(fd, "/>\n");
           } else {
             double xx1 = rx * cos(e_a * XSCH_PI / 180.) + cx;
    @@ -190,7 +190,7 @@ static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,dou
             if(fill == 0) {
                fprintf(fd,"style=\"fill:none;\" ");
                fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %g\"/>\n", xx1, yy1, rx, ry, fa, fs, xx2, yy2);
    -        } else if(fill == 3) {
    +        } else if(fill == 2) {
               fprintf(fd, "style=\"fill-opacity:1.0;\" ");
               fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rx, ry, fa, fs, xx2, yy2, cx, cy);
             } else {
    @@ -245,7 +245,7 @@ static void svg_drawarc(int gc, int fillarc, double x,double y,double r,double a
           fprintf(fd, "zoom, 1.4*dash/xctx->zoom);
           if(fillarc == 0) fprintf(fd, "style=\"fill:none;\" ");
    -      else if(fillarc == 3) fprintf(fd, "style=\"fill-opacity:1.0;\" ");
    +      else if(fillarc == 2) fprintf(fd, "style=\"fill-opacity:1.0;\" ");
     
           fprintf(fd, "/>\n");
         } else {
    @@ -261,7 +261,7 @@ static void svg_drawarc(int gc, int fillarc, double x,double y,double r,double a
           if(fillarc == 0) {
              fprintf(fd,"style=\"fill:none;\" ");
              fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %g\"/>\n", xx1, yy1, rr, rr, fa, fs, xx2, yy2);
    -      } else if(fillarc == 3) {
    +      } else if(fillarc == 2) {
             fprintf(fd, "style=\"fill-opacity:1.0;\" ");
             fprintf(fd, "d=\"M%g %g A%g %g 0 %d %d %g %gL%g %gz\"/>\n", xx1, yy1, rr, rr, fa, fs, xx2, yy2, xx, yy);
           } else {
    diff --git a/src/verilog_netlist.c b/src/verilog_netlist.c
    index bb675e55..630acc58 100644
    --- a/src/verilog_netlist.c
    +++ b/src/verilog_netlist.c
    @@ -453,6 +453,11 @@ int verilog_block_netlist(FILE *fd, int i, int alert)
            tclgetvar("netlist_dir"),  get_cell(name, 0), getpid());
         dbg(1, "global_vhdl_netlist(): split_files: netl_filename=%s\n", netl_filename);
         fd=fopen(netl_filename, "w");
    +    if(!fd) {
    +      dbg(0, "verilog_block_netlist(): unable to write file %s\n", netl_filename);
    +      err = 1;
    +      goto err;
    +    }
         my_snprintf(cellname, S(cellname), "%s.v", get_cell(name, 0));
     
       }
    @@ -619,6 +624,7 @@ int verilog_block_netlist(FILE *fd, int i, int alert)
         set_tcl_netlist_type();
         if(debug_var==0) xunlink(netl_filename);
       }
    +  err:
       xctx->netlist_count++;
       my_free(_ALLOC_ID_, &name);
       return err;
    diff --git a/src/vhdl_netlist.c b/src/vhdl_netlist.c
    index 5db254b2..c7d218c4 100644
    --- a/src/vhdl_netlist.c
    +++ b/src/vhdl_netlist.c
    @@ -538,6 +538,11 @@ int vhdl_block_netlist(FILE *fd, int i, int alert)
            tclgetvar("netlist_dir"), get_cell(xctx->sym[i].name, 0), getpid());
         dbg(1, "vhdl_block_netlist(): split_files: netl_filename=%s\n", netl_filename);
         fd=fopen(netl_filename, "w");
    +    if(!fd) {
    +      dbg(0, "vhdl_block_netlist(): unable to write file %s\n", netl_filename);
    +      err = 1;
    +      goto err;
    +    }
         my_snprintf(cellname, S(cellname), "%s.vhdl", get_cell(xctx->sym[i].name, 0) );
       }
     
    @@ -721,6 +726,7 @@ int vhdl_block_netlist(FILE *fd, int i, int alert)
         set_tcl_netlist_type();
         if(debug_var==0) xunlink(netl_filename);
       }
    +  err:
       xctx->netlist_count++;
       return err;
     }
    diff --git a/src/xinit.c b/src/xinit.c
    index a13674a5..288b4e8c 100644
    --- a/src/xinit.c
    +++ b/src/xinit.c
    @@ -361,10 +361,10 @@ void init_pixdata()/* populate xctx->fill_type array that is used in create_gc()
          if(pixdata[i][j]!=0xff) full=0;
          if(pixdata[i][j]!=0x00) empty=0;
        }
    -   if(full) xctx->fill_type[i] = 1;
    +   if(full) xctx->fill_type[i] = 2;
        else if(empty) xctx->fill_type[i] = 0;
    -   else xctx->fill_type[i]=2;
    -   if(rainbow_colors && i>5) xctx->fill_type[i]=1; /* 20171212 solid fill style */
    +   else xctx->fill_type[i]=1;
    +   if(rainbow_colors && i>5) xctx->fill_type[i]=2; /* 20171212 solid fill style */
        /*fprintf(errfp, "fill_type[%d]= %d\n", i, xctx->fill_type[i]); */
      }
     }
    @@ -434,7 +434,7 @@ void create_gc(void)
         xctx->gc[i] = XCreateGC(display,xctx->window,0L,NULL);
         xctx->gcstipple[i] = XCreateGC(display,xctx->window,0L,NULL);
         XSetStipple(display,xctx->gcstipple[i],pixmap[i]);
    -    if(xctx->fill_type[i]==1)  XSetFillStyle(display,xctx->gcstipple[i],FillSolid);
    +    if(xctx->fill_type[i]==2)  XSetFillStyle(display,xctx->gcstipple[i],FillSolid);
         else XSetFillStyle(display,xctx->gcstipple[i],FillStippled);
       }
     }
    diff --git a/src/xschem.h b/src/xschem.h
    index a6f5007b..27700e9f 100644
    --- a/src/xschem.h
    +++ b/src/xschem.h
    @@ -491,7 +491,7 @@ typedef struct
       unsigned short sel;
       char *prop_ptr;
       void *extraptr; /* generic data pointer (images) */
    -  short fill;
    +  short fill; /* 0: no fill, 1: stippled fill, 2: solid fill */
       short dash;
       int ellipse_a, ellipse_b;
       /* bit0=1 for graph function, bit1=1 for unlocked x axis
    @@ -1648,6 +1648,7 @@ extern char *my_free(int id, void *ptr);
     extern size_t my_strcat(int id, char **, const char *);
     extern size_t my_strcat2(int id, char **, const char *);
     extern size_t my_mstrcat(int id, char **str, const char *append_str, ...);
    +extern FILE * my_fopen(const char *f, const char *m);
     extern void *my_memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen);
     extern char *my_itoa(int i);
     extern double atof_spice(const char *s);
    
    From 821aa77b0a6c9b25ac15e73eeaca01331c27af75 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Tue, 18 Feb 2025 02:45:24 +0100
    Subject: [PATCH 43/46] fix svg fill rules
    
    ---
     src/svgdraw.c | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/src/svgdraw.c b/src/svgdraw.c
    index 44e0229a..601de7da 100644
    --- a/src/svgdraw.c
    +++ b/src/svgdraw.c
    @@ -994,8 +994,8 @@ void svg_draw(void)
        * 2 : solid fill
        * fill_type[i]: 
        * 0 : no fill
    -   * 1 : solid fill
    -   * 2 : patterned (stippled) fill
    +   * 1 : patterned (stippled) fill
    +   * 2 : solid fill
        */
       for(i=0;ifill_pattern == 2 && xctx->fill_type[i]) 
           fprintf(fd, "  fill: #%02x%02x%02x;\n", svg_colors[i].red, svg_colors[i].green, svg_colors[i].blue);
    -    else if( xctx->fill_pattern && xctx->fill_type[i] == 1) 
    +    else if( xctx->fill_pattern && xctx->fill_type[i] == 2) 
           fprintf(fd, "  fill: #%02x%02x%02x;\n", svg_colors[i].red, svg_colors[i].green, svg_colors[i].blue);
         else 
           fprintf(fd, "  fill: #%02x%02x%02x; fill-opacity: 0.5;\n", 
    
    From 936b72c7fc875bcb130ab56f11c38354b8fbcdff Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Tue, 18 Feb 2025 11:49:32 +0100
    Subject: [PATCH 44/46] Escape pressed while drawing polygon will cancel last
     segment instead of the whole poly
    
    ---
     src/callback.c | 7 ++++---
     1 file changed, 4 insertions(+), 3 deletions(-)
    
    diff --git a/src/callback.c b/src/callback.c
    index 374b4389..92e82414 100644
    --- a/src/callback.c
    +++ b/src/callback.c
    @@ -150,6 +150,8 @@ void abort_operation(void)
       tcleval("set constr_mv 0" );
       dbg(1, "abort_operation(): Escape: ui_state=%d, last_command=%d\n", xctx->ui_state, xctx->last_command);
       xctx->constr_mv=0;
    +
    +  if(xctx->ui_state & STARTPOLYGON) new_polygon(END, xctx->mousex_snap, xctx->mousey_snap);
       if(xctx->last_command && xctx->ui_state & (STARTWIRE | STARTLINE)) {
         if(xctx->ui_state & STARTWIRE) new_wire(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap);
         if(xctx->ui_state & STARTLINE) new_line(RUBBER|CLEAR, xctx->mousex_snap, xctx->mousey_snap);
    @@ -4182,8 +4184,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in
          if(end_place_move_copy_zoom()) return;
     
          /* Button1Press to select objects */
    -     if( !(xctx->ui_state & STARTPOLYGON) && !(xctx->ui_state & STARTSELECT) &&
    -         !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) {
    +     if(!excl) {
            Selected sel;
            int already_selected = 0;
            int prev_last_sel = xctx->lastsel;
    @@ -4306,7 +4307,7 @@ static void handle_button_press(int event, int state, int rstate, KeySym key, in
              }
            }
            return;
    -     }
    +     } /* if(!excl) */
        } /* button==Button1 */
     }
     
    
    From fc3a3ed4e02293cd9382b6ff886aacc784ab89af Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Tue, 18 Feb 2025 17:45:09 +0100
    Subject: [PATCH 45/46] add proc cinv (complex inversion)
    
    ---
     doc/xschem_man/developer_info.html |  1 +
     src/scheduler.c                    |  4 ++++
     src/xschem.tcl                     | 11 +++++++++++
     3 files changed, 16 insertions(+)
    
    diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html
    index 2d795720..0cc1b8b6 100644
    --- a/doc/xschem_man/developer_info.html
    +++ b/doc/xschem_man/developer_info.html
    @@ -760,6 +760,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
          
  • bbox bounding box schematic
  • bbox_hilighted bounding box of highlinhted objects
  • bbox_selected bounding box of selected objects
  • +
  • build_date time and date this file was built.
  • cadlayers number of layers
  • case_insensitive case_insensitive symbol matching
  • color_ps color postscript flag
  • diff --git a/src/scheduler.c b/src/scheduler.c index 21292799..38e6866e 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1344,6 +1344,10 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg my_snprintf(res, S(res), "%g %g %g %g", boundbox.x1, boundbox.y1, boundbox.x2, boundbox.y2); Tcl_SetResult(interp, res, TCL_VOLATILE); } + else if(!strcmp(argv[2], "build_date")) { /* time and date this file was built. */ + char date[] = __DATE__ " : " __TIME__; + Tcl_SetResult(interp, date, TCL_STATIC); + } break; case 'c': if(!strcmp(argv[2], "cadlayers")) { /* number of layers */ diff --git a/src/xschem.tcl b/src/xschem.tcl index 56fcda69..a3ed1fd3 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -731,6 +731,17 @@ proc cdiv {a b} { return $c } +# 1/b +proc cinv {b} { + + lassign $b rb ib + set rb [expr {double($rb)}] + set ib [expr {double($ib)}] + set m [expr {$rb * $rb + $ib * $ib}] + set c [list [expr {$rb / $m}] [expr {-$ib / $m}]] + return $c +} + # return real component proc creal {a} { lassign $a ra ia From b7c611828875129e7df557ef85360a36acc2da9e Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 19 Feb 2025 02:39:02 +0100 Subject: [PATCH 46/46] add physical constants in eval_expr.y --- src/eval_expr.y | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/eval_expr.y b/src/eval_expr.y index f2bc525f..5198718f 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -16,6 +16,7 @@ struct symrec { char *name; /* name of symbol */ double (*fnctptr)(double); /* value of a FNCT */ + double value; struct symrec *next; /* link field */ }; @@ -31,29 +32,41 @@ static void kkerror(char *s); static double toint(double x); static void get_expr(double x); static void get_char(int c); +static double rnd6(double x) {return round_to_n_digits(x, 6);} struct fn { char *fname; double (*fnct)(); + double value; }; static int lex_state = 0; struct fn fn_array[] = { - {"int" , toint}, - {"sin" , sin}, - {"cos" , cos}, - {"asin", asin}, - {"acos", acos}, - {"atan", atan}, - {"log" , log10}, - {"ln" , log}, - {"exp" , exp}, - {"sqrt", sqrt}, - {0 , 0} + {"int" , toint, 0}, + {"sin" , sin, 0}, + {"cos" , cos, 0}, + {"exp" , exp, 0}, + {"asin" , asin, 0}, + {"acos" , acos, 0}, + {"atan" , atan, 0}, + {"log" , log10, 0}, + {"ln" , log, 0}, + {"exp" , exp, 0}, + {"sqrt" , sqrt, 0}, + {"round" , rnd6, 0}, + {"pi" , NULL, 3.141592653589793}, + {"e" , NULL, 2.718281828459045}, + {"k" , NULL, 1.380649e-23}, + {"h" , NULL, 6.62607e-34}, + {"echarge" , NULL, 1.60217646e-19}, + {"abszero" , NULL, 273.15}, + {"c" , NULL, 2.99792458e8}, + {0 , 0, 0} }; %} + /* %define api.prefix {kk} */ %union { int c; @@ -87,7 +100,8 @@ line: ; exp: NUM {$$ = $1;} - | FNCT '(' exp ')' {$$ = $1 ? (*($1->fnctptr))($3) : 0.0;} + | FNCT '(' exp ')' {$$ = $1 ? ($1->fnctptr ? (*($1->fnctptr))($3) : 0.0) : 0.0;} + | FNCT {$$ = $1 ? $1->value : 0.0;} | exp '+' exp {$$ = $1 + $3; } | exp '-' exp {$$ = $1 - $3;} | exp '*' exp {$$ = $1 * $3;} @@ -187,6 +201,7 @@ void eval_expr_init_table(void) /* puts arithmetic functions in table. */ { ptr = putsym (fn_array[i].fname); ptr->fnctptr = fn_array[i].fnct; + ptr->value = fn_array[i].value; } } @@ -238,7 +253,7 @@ static int kklex() str--; sscanf(str, "%99[.0-9a-zA-Z_]%n", s, &rd); - kklval.val = atof_spice(s); + kklval.val = atof_eng(s); str += rd; dbg(dbglev, "lex(): NUM: %s\n", s); return NUM;