diff --git a/src/actions.c b/src/actions.c index 7feb40db..369a6e98 100644 --- a/src/actions.c +++ b/src/actions.c @@ -982,9 +982,12 @@ void symbol_in_new_window(void) if(xctx->lastsel !=1 || xctx->sel_array[0].type!=ELEMENT) { my_strncpy(filename, xctx->sch[xctx->currsch], S(filename)); - if(tclgetvar("tabbed_interface")[0] == '1' && !check_loaded(filename, win_path)) { - tcleval("create_new_tab"); - tclvareval("xschem load ", filename, NULL); + if(tclgetvar("tabbed_interface")[0] == '1') { + dbg(1, "symbol_in_new_window(): filename=%s, current=%s\n", + filename, xctx->sch[xctx->currsch]); + if(!check_loaded(filename, win_path)) { + new_schematic("create", NULL, filename); + } } else { new_xschem_process(filename, 1); } @@ -994,8 +997,7 @@ void symbol_in_new_window(void) my_strncpy(filename, abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), S(filename)); if(tclgetvar("tabbed_interface")[0] == '1') { if(!check_loaded(filename, win_path)) { - tcleval("create_new_tab"); - tclvareval("xschem load ", filename, NULL); + new_schematic("create", NULL, filename); } } else { new_xschem_process(filename, 1); @@ -1040,8 +1042,7 @@ void schematic_in_new_window(void) if(tclgetvar("tabbed_interface")[0] == '1') { if(!check_loaded(filename, win_path)) { - tcleval("create_new_tab"); - tclvareval("xschem load ", filename, NULL); + new_schematic("create", NULL, filename); } } else { new_xschem_process(filename, 0); diff --git a/src/callback.c b/src/callback.c index 7c193580..1c1c854c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -814,7 +814,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, tclvareval("restore_ctx ", winpath, NULL); tclvareval("housekeeping_ctx", NULL); } - new_schematic("switch", winpath, ""); + new_schematic("switch_win", winpath, ""); } /* artificially set semaphore to allow only redraw operations in switched schematic, * so we don't need to switch tcl context which is costly performance-wise @@ -1636,7 +1636,6 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, } if(key=='o' && state == ControlMask) /* load */ { - if(xctx->semaphore >= 2) break; ask_new_file(); break; @@ -2579,7 +2578,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key, if(redraw_only) { xctx->semaphore--; /* decrement articially incremented semaphore (see above) */ dbg(1, "callback(): semaphore >=2 restoring window context: %s <-- %s\n", old_winpath, winpath); - if(old_winpath[0]) new_schematic("switch", old_winpath, ""); + if(old_winpath[0]) new_schematic("switch_win", old_winpath, ""); } else if(strcmp(old_winpath, winpath)) { diff --git a/src/scheduler.c b/src/scheduler.c index 1b6a2ba7..a3fc0ad4 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1544,15 +1544,25 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg else if(!strcmp(argv[1],"load") ) { + int load_symbols = 1, force = 0, i; cmd_found = 1; - if(argc==3) { - if(!has_x || !xctx->modified || save(1) != -1 ) { /* save(1)==-1 --> user cancel */ + if(argc > 3) { + for(i = 3; i < argc; i++) { + if(!strcmp(argv[i], "symbol")) load_symbols = 0; + if(!strcmp(argv[i], "force")) force = 1; + } + } + if(argc>2) { + i = strlen(argv[2]); + if(i > 4 && !strcmp(argv[2] + i - 4, ".sym")) { + load_symbols = 0; + } + if(force || !has_x || !xctx->modified || save(1) != -1 ) { /* save(1)==-1 --> user cancel */ char f[PATH_MAX]; char win_path[WINDOW_PATH_SIZE]; int skip = 0; dbg(1, "scheduler(): load: filename=%s\n", argv[2]); my_strncpy(f, abs_sym_path(argv[2], ""), S(f)); - if(f[0] && check_loaded(f, win_path)) { char msg[PATH_MAX + 100]; my_snprintf(msg, S(msg), "alert_ {xschem load: %s already open: %s}", f, win_path); @@ -1565,7 +1575,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg xctx->currsch = 0; unselect_all(); remove_symbols(); - load_schematic(1, f, 1); + load_schematic(load_symbols, f, 1); tclvareval("update_recent_file {", f, "}", NULL); my_strdup(375, &xctx->sch_path[xctx->currsch],"."); xctx->sch_path_hash[xctx->currsch] = 0; @@ -1594,26 +1604,6 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg tclvareval("update_recent_file {", fullname, "}", NULL); } } - - else if(!strcmp(argv[1],"load_symbol") ) - { - cmd_found = 1; - if(argc==3) { - char f[PATH_MAX]; - dbg(1, "scheduler(): load: filename=%s\n", argv[2]); - my_strncpy(f, abs_sym_path(argv[2], ""), S(f)); - clear_all_hilights(); - xctx->currsch = 0; - unselect_all(); - remove_symbols(); - load_schematic(0, f, 1); - my_strdup(374, &xctx->sch_path[xctx->currsch],"."); - xctx->sch_path_hash[xctx->currsch] = 0; - xctx->sch_inst_number[xctx->currsch] = 1; - zoom_full(1, 0, 1, 0.97); - } - } - else if(!strcmp(argv[1],"log")) { cmd_found = 1; @@ -1719,11 +1709,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg else if(!strcmp(argv[1],"new_schematic")) { + int r; + char s[20]; cmd_found = 1; - if(argc == 3) new_schematic(argv[2], NULL, NULL); - else if(argc == 4) new_schematic(argv[2], argv[3], NULL); - else if(argc == 5) new_schematic(argv[2], argv[3], argv[4]); - Tcl_ResetResult(interp); + if(argc == 3) r = new_schematic(argv[2], NULL, NULL); + else if(argc == 4) r = new_schematic(argv[2], argv[3], NULL); + else if(argc == 5) r = new_schematic(argv[2], argv[3], argv[4]); + my_snprintf(s, S(s), "%d", r); + Tcl_SetResult(interp, s, TCL_VOLATILE); } else if(!strcmp(argv[1],"new_symbol_window")) diff --git a/src/spice_netlist.c b/src/spice_netlist.c index 8e81e1a5..3257bb8d 100644 --- a/src/spice_netlist.c +++ b/src/spice_netlist.c @@ -84,7 +84,6 @@ void hier_psprint(void) /* netlister driver */ my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); xctx->currsch--; unselect_all(); - /* load_schematic(1, xctx->sch[xctx->currsch], 0); */ xctx->pop_undo(0, 0); my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); ps_draw(4); /* trailer */ @@ -298,8 +297,6 @@ void global_spice_netlist(int global) /* netlister driver */ my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); xctx->currsch--; unselect_all(); - /* remove_symbols(); */ - /* load_schematic(1, xctx->sch[xctx->currsch], 0); */ xctx->pop_undo(0, 0); my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */ diff --git a/src/tedax_netlist.c b/src/tedax_netlist.c index d651d3cb..fe81fcb7 100644 --- a/src/tedax_netlist.c +++ b/src/tedax_netlist.c @@ -113,8 +113,6 @@ void global_tedax_netlist(int global) /* netlister driver */ my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); xctx->currsch--; unselect_all(); - /* remove_symbols(); */ - /* load_schematic(1, xctx->sch[xctx->currsch], 0); */ xctx->pop_undo(0, 0); my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */ diff --git a/src/verilog_netlist.c b/src/verilog_netlist.c index 30f284ed..bd209a3a 100644 --- a/src/verilog_netlist.c +++ b/src/verilog_netlist.c @@ -320,8 +320,6 @@ void global_verilog_netlist(int global) /* netlister driver */ my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); xctx->currsch--; unselect_all(); - /* remove_symbols(); */ - /* load_schematic(1,xctx->sch[xctx->currsch], 0); */ xctx->pop_undo(0, 0); my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */ diff --git a/src/vhdl_netlist.c b/src/vhdl_netlist.c index 63752288..eb2a0b81 100644 --- a/src/vhdl_netlist.c +++ b/src/vhdl_netlist.c @@ -378,8 +378,6 @@ void global_vhdl_netlist(int global) /* netlister driver */ my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); xctx->currsch--; unselect_all(); - /* remove_symbols(); */ - /* load_schematic(1, xctx->sch[xctx->currsch], 0); */ xctx->pop_undo(0, 0); my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */ diff --git a/src/xinit.c b/src/xinit.c index 1e3ed8f1..a85769e9 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -972,8 +972,11 @@ int check_loaded(const char *f, char *win_path) int found = 0; for(i = 0; i < MAX_NEW_WINDOWS; i++) { ctx = save_xctx[i]; + /* if only one schematic it is not yet saved in save_xctx */ + if(window_count == 0 && i == 0) ctx = xctx; if(ctx) { if(!strcmp(ctx->sch[ctx->currsch], f)) { + dbg(1, "check_loaded(): f=%s, sch=%s\n", f, ctx->sch[ctx->currsch]); found = 1; my_strncpy(win_path, window_path[i], S(window_path[i])); break; @@ -983,14 +986,21 @@ int check_loaded(const char *f, char *win_path) return found; } +/* caller (via new_schematic() ) should take care of switching tcl context + * before calling this function, see callback() + * + * tclvareval("save_ctx ", old_winpath, NULL); + * tclvareval("restore_ctx ", winpath, NULL); + * tclvareval("housekeeping_ctx", NULL); + */ static void switch_window(int *window_count, const char *win_path) { int i, n; Tk_Window tkwin; if(*window_count) { - dbg(1, "new_schematic() switch: %s\n", win_path); + dbg(1, "new_schematic(\"switch_win\"...): %s\n", win_path); tkwin = Tk_NameToWindow(interp, win_path, mainwindow); /* NULL if win_path not existing */ - if(!tkwin) dbg(0, "new_schematic(\"switch\",...): Warning: %s has been destroyed\n", win_path); + if(!tkwin) dbg(0, "new_schematic(\"switch_win\",...): Warning: %s has been destroyed\n", win_path); n = -1; if(tkwin) for(i = 0; i < MAX_NEW_WINDOWS; i++) { if(!strcmp(win_path, window_path[i])) { @@ -999,7 +1009,7 @@ static void switch_window(int *window_count, const char *win_path) } } if(n == -1) { - dbg(0, "new_schematic(\"switch\"...): no window to switch to found: %s\n", win_path); + dbg(0, "new_schematic(\"switch_win\"...): no window to switch to found: %s\n", win_path); return; } /* if window was closed then tkwin == 0 --> do nothing */ @@ -1115,10 +1125,12 @@ static void create_new_window(int *window_count, const char *fname) windowid(toppath); } -static void create_new_tab(int *window_count, const char *win_path, const char *fname) +static void create_new_tab(int *window_count, const char *fname) { int i, n; char open_path[WINDOW_PATH_SIZE]; + char nn[WINDOW_PATH_SIZE]; + char win_path[WINDOW_PATH_SIZE]; dbg(1, "new_schematic() new_tab, creating...\n"); if(*window_count && fname && fname[0] && check_loaded(fname, open_path)) { @@ -1157,6 +1169,19 @@ static void create_new_tab(int *window_count, const char *win_path, const char * dbg(0, "new_schematic(\"newtab\"...): no more free slots\n"); return; } + /* tcl code to create the tab button */ + my_snprintf(nn, S(nn), "%d", n); + tclvareval( + "button ", xctx->top_path, ".tabs.x", nn, " -padx 2 -pady 0 -text Tab2 " + "-command \"xschem new_schematic switch_tab .x", nn, ".drw\"", NULL); + tclvareval( + "if {![info exists tctx::tab_bg] } {set tctx::tab_bg [", + xctx->top_path, ".tabs.x", nn, " cget -bg]}", NULL); + tclvareval("pack ", xctx->top_path, ".tabs.x", nn, + " -before ", xctx->top_path, ".tabs.add -side left", NULL); + /* */ + + my_snprintf(win_path, S(win_path), "%s.x%d.drw", xctx->top_path, n); my_strncpy(window_path[n], win_path, S(window_path[n])); xctx = NULL; alloc_xschem_data("", win_path); /* alloc data into xctx */ @@ -1399,7 +1424,7 @@ int new_schematic(const char *what, const char *win_path, const char *fname) if(!tabbed_interface) { create_new_window(&window_count, fname); } else { - create_new_tab(&window_count, win_path, fname); + create_new_tab(&window_count, fname); } } else if(!strcmp(what, "destroy")) { if(!tabbed_interface) { @@ -1413,12 +1438,10 @@ int new_schematic(const char *what, const char *win_path, const char *fname) } else { destroy_all_tabs(&window_count); } - } else if(!strcmp(what, "switch")) { - if(!tabbed_interface) { - switch_window(&window_count, win_path); - } else { - switch_tab(&window_count, win_path); - } + } else if(!strcmp(what, "switch_win")) { + switch_window(&window_count, win_path); /* see comments in switch_window() */ + } else if(!strcmp(what, "switch_tab")) { + switch_tab(&window_count, win_path); } return window_count; } diff --git a/src/xschem.tcl b/src/xschem.tcl index fa305dd4..7104ec30 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -3720,14 +3720,13 @@ proc setup_tabbed_interface {} { set top_path {} if { $tabbed_interface } { - frame $top_path.tabs - button $top_path.tabs.x0 -padx 2 -pady 0 -text Main -command {xschem new_schematic switch .drw} - # button $topwin.tabs.x1 -padx 2 -pady 0 -text Tab1 -command {xschem new_schematic switch .x1.drw} - # button $topwin.tabs.x2 -padx 2 -pady 0 -text Tab2 -command {xschem new_schematic switch .x2.drw} - button $top_path.tabs.add -padx 0 -pady 0 -text { + } -command create_new_tab - # pack $topwin.tabs.x0 $topwin.tabs.x1 $topwin.tabs.x2 $topwin.tabs.add -side left - pack $top_path.tabs.x0 $top_path.tabs.add -side left - pack $top_path.tabs -fill x -side top -expand false -side top -before $top_path.drw + if { ![winfo exists $top_path.tabs] } { + frame $top_path.tabs + button $top_path.tabs.x0 -padx 2 -pady 0 -text Main -command "xschem new_schematic switch_tab .drw" + button $top_path.tabs.add -padx 0 -pady 0 -text { + } -command "xschem new_schematic create" + pack $top_path.tabs.x0 $top_path.tabs.add -side left + pack $top_path.tabs -fill x -side top -expand false -side top -before $top_path.drw + } } else { destroy $top_path.tabs } @@ -3797,24 +3796,6 @@ proc next_tab {} { $top_path.tabs.x$next_tab invoke } -proc create_new_tab {} { - global tabbed_interface - if { !$tabbed_interface} {return} - set top_path [xschem get top_path] - set found 0 - for { set i 1} { $i < $tctx::max_new_windows} { incr i} { - if { ![winfo exists ${top_path}.tabs.x$i] } { - button $top_path.tabs.x$i -padx 2 -pady 0 -text Tab2 -command "xschem new_schematic switch .x$i.drw" - if {![info exists tctx::tab_bg] } {set tctx::tab_bg [$top_path.tabs.x$i cget -bg]} - pack $top_path.tabs.x$i -before .tabs.add -side left - xschem new_schematic create .x$i.drw - set found 1 - break - } - } - if {!$found} { puts "no more available tabs"} -} - proc set_tab_names {} { global tabbed_interface has_x @@ -3833,45 +3814,6 @@ proc set_tab_names {} { } } -proc test2 {} { - global tabbed_interface - - set tabbed_interface 0 - xschem load [abs_sym_path testbench.sch] - xschem load_new_window [abs_sym_path poweramp.sch] - xschem load_new_window [abs_sym_path mos_power_ampli.sch] - xschem load_new_window [abs_sym_path rom8k.sch] - xschem load_new_window [abs_sym_path autozero_comp.sch] - xschem load_new_window [abs_sym_path LCC_instances.sch] - xschem load_new_window [abs_sym_path simulate_ff.sch] - xschem load_new_window [abs_sym_path led_driver.sch] - xschem load_new_window [abs_sym_path solar_panel.sch] -} - -proc test1 {} { - global tabbed_interface - - set tabbed_interface 1 - setup_tabbed_interface - xschem load [abs_sym_path testbench.sch] - create_new_tab - xschem load [abs_sym_path poweramp.sch] - create_new_tab - xschem load [abs_sym_path mos_power_ampli.sch] - create_new_tab - xschem load [abs_sym_path rom8k.sch] - create_new_tab - xschem load [abs_sym_path autozero_comp.sch] - create_new_tab - xschem load [abs_sym_path LCC_instances.sch] - create_new_tab - xschem load [abs_sym_path simulate_ff.sch] - create_new_tab - xschem load [abs_sym_path led_driver.sch] - create_new_tab - xschem load [abs_sym_path solar_panel.sch] -} - proc raise_dialog {parent window_path } { if {[winfo exists .dialog] && [winfo ismapped .dialog] && [winfo ismapped $parent] && [wm stackorder .dialog isbelow $parent ]} { @@ -4260,12 +4202,13 @@ proc build_widgets { {topwin {} } } { $topwin.menubar.file.menu add command -label "PNG Export" -command "xschem print png" -accelerator {Ctrl+*} $topwin.menubar.file.menu add command -label "SVG Export" -command "xschem print svg" -accelerator {Alt+*} $topwin.menubar.file.menu add separator - $topwin.menubar.file.menu add command -label "Exit" -accelerator {Ctrl+Q} -command " - if { \[xschem get current_win_path\] eq {.drw} } { - xschem exit - } else { - xschem new_schematic destroy \[xschem get current_win_path\] {} - }" + $topwin.menubar.file.menu add command -label "Exit" -accelerator {Ctrl+Q} -command { + if {[xschem get current_win_path] eq {.drw} } { + xschem exit + } else { + xschem new_schematic destroy [xschem get current_win_path] {} + } + } $topwin.menubar.option.menu add checkbutton -label "Color Postscript/SVG" -variable color_ps \ -command { if { $color_ps==1 } {xschem set color_ps 1} else { xschem set color_ps 0} @@ -4349,9 +4292,9 @@ proc build_widgets { {topwin {} } } { $topwin.menubar.edit.menu add command -label "Delete" -command "xschem delete" -accelerator Del toolbar_create EditDelete "xschem delete" "Delete" $topwin $topwin.menubar.edit.menu add command -label "Select all" -command "xschem select_all" -accelerator Ctrl+A - $topwin.menubar.edit.menu add command -label "Edit selected schematic in new window" \ + $topwin.menubar.edit.menu add command -label "Edit schematic in new window/tab" \ -command "xschem schematic_in_new_window" -accelerator Alt+E - $topwin.menubar.edit.menu add command -label "Edit selected symbol in new window" \ + $topwin.menubar.edit.menu add command -label "Edit symbol in new window/tab" \ -command "xschem symbol_in_new_window" -accelerator Alt+I $topwin.menubar.edit.menu add command -label "Duplicate objects" -command "xschem copy_objects" -accelerator C toolbar_create EditDuplicate "xschem copy_objects" "Duplicate objects" $topwin @@ -4633,12 +4576,13 @@ proc build_widgets { {topwin {} } } { wm geometry $rootwin $initial_geometry #wm maxsize . 1600 1200 if { $rootwin == {.}} { - wm protocol $rootwin WM_DELETE_WINDOW " - if { \[xschem get current_win_path\] eq {.drw} } { + wm protocol $rootwin WM_DELETE_WINDOW { + if { [xschem get current_win_path] eq {.drw} } { xschem exit } else { - xschem new_schematic destroy \[xschem get current_win_path\] {} - }" + xschem new_schematic destroy [xschem get current_win_path] {} + } + } } else { wm protocol $topwin WM_DELETE_WINDOW "xschem new_schematic destroy $topwin.drw {}" } diff --git a/tests/xschemtest.tcl b/tests/xschemtest.tcl index 4b293f0c..e8b07083 100644 --- a/tests/xschemtest.tcl +++ b/tests/xschemtest.tcl @@ -46,6 +46,34 @@ proc draw_test {{filelist {-}} {hide_graphs 0}} { } set show_pin_net_names 0 } +proc test_windows { {tabs 0} {destroy 1} } { + global tabbed_interface + + xschem clear force + set tabbed_interface $tabs + setup_tabbed_interface + xschem load [abs_sym_path testbench.sch] + xschem load_new_window [abs_sym_path poweramp.sch] + xschem load_new_window [abs_sym_path mos_power_ampli.sch] + xschem load_new_window [abs_sym_path rom8k.sch] + xschem load_new_window [abs_sym_path autozero_comp.sch] + xschem load_new_window [abs_sym_path LCC_instances.sch] + xschem load_new_window [abs_sym_path simulate_ff.sch] + xschem load_new_window [abs_sym_path led_driver.sch] + xschem load_new_window [abs_sym_path solar_panel.sch] + update + if {[xschem new_schematic ntabs] == 8} {set res OK} else {set res FAIL} + if {$tabs} { + puts "test tabbed windows: $res" + } else { + puts "test multiple windows: $res" + } + if {$destroy} { + after 2000 + xschem new_schematic destroy_all + xschem clear force + } +} ## select all loaded schematic and paste 32 times in different places, ## check if number of elements after paste matches. @@ -198,6 +226,8 @@ proc xschemtest {{view 0}} { copy_paste_test mos_power_ampli.sch draw_trim_wiregrid test_xschem_simulation simulate_ff.sch + test_windows 0 ;# windows + test_windows 1 ;# tabs }] puts "Test time: [lindex $t 0] microseconds" }