diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 2565f969..ba9dfddc 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -490,6 +490,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" +
Resets UI state, unselect all and abort any pending operation
@@ -566,6 +567,10 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
instance number to descend into for vector instances (default: 0).
Descend into the symbol view of selected component instance
+ + Close all additional windows/.tabs. If 'force' is given do not ask for + confirmation for changed schematics + Returns the remaining # of windows/tabs in addition to main window/tab
Print a list of highlighted objects (nets, net labels/pins, instances)
if 'instances' is specified list only instance highlights
@@ -595,7 +600,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Exit the program, ask for confirm if current file modified.
if 'closewindow' is given close the window, otherwise leave with a blank schematic
- when closing the last remaining window
+ if 'force' is given do not ask before closing modified schematic windows/tabs
+ when closing the last remaining window
+ This command returns the list of remaining open windows in addition to main window
Expand vectored labels/instance names:
xschem expandlabel {2*A[3:0]} --> A[3],A[2],A[1],A[0],A[3],A[2],A[1],A[0] 8
@@ -853,7 +860,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Start a new xschem process for a schematic.
If 'f' is given load specified schematic.
- +
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).
@@ -862,8 +869,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
destroy: destroy tab/window identified by winpath. Example:
xschem new_schematic destroy .x1.drw
destroy_all: close all tabs/additional windows
- switch_win: switch context to specified 'winpath' window
- switch_tab: switch context to specified 'winpath' tab
+ switch: switch context to specified 'winpath' window or specified schematic name
Main window/tab has winpath set to .drw,
Additional windows/tabs have winpath set to .x1.drw, .x2.drw and so on...
@@ -1113,6 +1119,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
When a symbol is selected edit it in a new tab/window if not already open.
If nothing selected open another window of the second schematic (issues a warning).
if 'new_process' is given start a new xschem process
+ + Switch context to indicated window path or schematic name + returns the # of windows/tabs in addition to main window/tab
if 'n' given list symbol with name or number 'n', else
list all used symbols
diff --git a/src/callback.c b/src/callback.c
index 675c1848..95d86d9e 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -1033,12 +1033,11 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key,
if( xctx->semaphore >= 1 || event == Expose) {
dbg(1, "callback(): semaphore >=2 (or Expose) switching window context: %s --> %s\n", old_winpath, winpath);
redraw_only = 1;
+ new_schematic("switch_no_tcl_ctx", winpath, "");
} else {
dbg(1, "callback(): switching window context: %s --> %s, semaphore=%d\n", old_winpath, winpath, xctx->semaphore);
- if(old_winpath[0]) tclvareval("save_ctx ", old_winpath, NULL);
- tclvareval("restore_ctx ", winpath, NULL);
+ new_schematic("switch", winpath, "");
}
- new_schematic("switch_win", winpath, "");
tclvareval("housekeeping_ctx", NULL);
}
/* artificially set semaphore to allow only redraw operations in switched schematic,
@@ -2863,7 +2862,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_win", old_winpath, "");
+ if(old_winpath[0]) new_schematic("switch_no_tcl_ctx", old_winpath, "");
}
else
if(strcmp(old_winpath, winpath)) {
diff --git a/src/scheduler.c b/src/scheduler.c
index 19564f79..24b8daae 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -571,6 +571,21 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
+ /* destroy_all [force]
+ * Close all additional windows/.tabs. If 'force' is given do not ask for
+ * confirmation for changed schematics
+ * Returns the remaining # of windows/tabs in addition to main window/tab */
+ else if(!strcmp(argv[1], "destroy_all"))
+ {
+ int force = 0;
+ if(argc > 2 && !strcmp(argv[2], "force")) force = 1;
+ if(force)
+ new_schematic("destroy_all", "force", NULL);
+ else
+ new_schematic("destroy_all", NULL, NULL);
+ Tcl_SetResult(interp, my_itoa(get_window_count()), TCL_VOLATILE);
+ }
+
/* display_hilights [nets|instances]
* Print a list of highlighted objects (nets, net labels/pins, instances)
* if 'instances' is specified list only instance highlights
@@ -683,12 +698,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
/* exit [closewindow]
* Exit the program, ask for confirm if current file modified.
* if 'closewindow' is given close the window, otherwise leave with a blank schematic
- * when closing the last remaining window */
+ * if 'force' is given do not ask before closing modified schematic windows/tabs
+ * when closing the last remaining window
+ * This command returns the list of remaining open windows in addition to main window */
else if(!strcmp(argv[1], "exit"))
{
int closewindow = 0;
+ int force = 0;
- if(argc > 2 && !strcmp(argv[2], "closewindow")) closewindow = 1;
+ for(i = 2; i < argc; ++i) {
+ if(!strcmp(argv[i], "closewindow")) closewindow = 1;
+ if(!strcmp(argv[i], "force")) force = 1;
+ }
if(!strcmp(xctx->current_win_path, ".drw")) {
if(has_x) {
/* non tabbed interface */
@@ -696,23 +717,23 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int wc = get_window_count();
dbg(1, "wc=%d\n", wc);
if(wc > 0 ) {
- if(xctx->modified) {
+ if(!force && xctx->modified) {
tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \""
"[get_cell [xschem get schname] 0]"
": UNSAVED data: want to exit?\"");
}
- if(!xctx->modified || !strcmp(tclresult(), "ok")) {
+ if(force || !xctx->modified || !strcmp(tclresult(), "ok")) {
swap_windows();
set_modify(0); /* set modified status to 0 to avoid another confirm in following line */
new_schematic("destroy", xctx->current_win_path, NULL);
}
} else {
- if(xctx->modified) {
+ if(!force && xctx->modified) {
tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \""
"[get_cell [xschem get schname] 0]"
": UNSAVED data: want to exit?\"");
}
- if(!xctx->modified || !strcmp(tclresult(), "ok")) {
+ if(force || !xctx->modified || !strcmp(tclresult(), "ok")) {
if(closewindow) tcleval("exit");
else clear_schematic(0, 0);
}
@@ -723,23 +744,23 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
int wc = get_window_count();
dbg(1, "wc=%d\n", wc);
if(wc > 0 ) {
- if(xctx->modified) {
+ if(!force && xctx->modified) {
tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \""
"[get_cell [xschem get schname] 0]"
": UNSAVED data: want to exit?\"");
}
- if(!xctx->modified || !strcmp(tclresult(), "ok")) {
+ if(force || !xctx->modified || !strcmp(tclresult(), "ok")) {
swap_tabs();
set_modify(0);
new_schematic("destroy", xctx->current_win_path, NULL);
}
} else {
- if(xctx->modified) {
+ if(!force && xctx->modified) {
tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \""
"[get_cell [xschem get schname] 0]"
": UNSAVED data: want to exit?\"");
}
- if(!xctx->modified || !strcmp(tclresult(), "ok")) {
+ if(force || !xctx->modified || !strcmp(tclresult(), "ok")) {
if(closewindow) tcleval("exit");
else clear_schematic(0, 0);
}
@@ -747,10 +768,11 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
}
else tcleval("exit"); /* if has_x == 0 there are no additional windows to close */
- } else {
+ } else {
+ if(force) set_modify(0); /* avoid ask to save downstream */
new_schematic("destroy", xctx->current_win_path, NULL);
}
- Tcl_ResetResult(interp);
+ Tcl_SetResult(interp, my_itoa(get_window_count()), TCL_VOLATILE);
}
/* expandlabel lab
@@ -2229,7 +2251,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
- /* new_schematic create|destroy|destroy_all|switch_win|switch_tab winpath file
+ /* new_schematic create|destroy|destroy_all|switch winpath file
* 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).
@@ -2238,8 +2260,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* destroy: destroy tab/window identified by winpath. Example:
* xschem new_schematic destroy .x1.drw
* destroy_all: close all tabs/additional windows
- * switch_win: switch context to specified 'winpath' window
- * switch_tab: switch context to specified 'winpath' tab
+ * switch: switch context to specified 'winpath' window or specified schematic name
* Main window/tab has winpath set to .drw,
* Additional windows/tabs have winpath set to .x1.drw, .x2.drw and so on...
*/
@@ -3669,6 +3690,16 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
+ /* switch [window_path |schematic_name]
+ * Switch context to indicated window path or schematic name
+ * returns the # of windows/tabs in addition to main window/tab
+ */
+ else if(!strcmp(argv[1], "switch"))
+ {
+ if(argc > 2) new_schematic("switch", argv[2], NULL);
+ Tcl_SetResult(interp, my_itoa(get_window_count()), TCL_VOLATILE);
+ }
+
/* symbols [n]
* if 'n' given list symbol with name or number 'n', else
* list all used symbols */
diff --git a/src/xinit.c b/src/xinit.c
index a1fa93bb..acc2581f 100644
--- a/src/xinit.c
+++ b/src/xinit.c
@@ -1183,6 +1183,33 @@ void preview_window(const char *what, const char *win_path, const char *fname)
semaphore--;
}
+
+static int get_tab_or_window_number(const char *win_path)
+{
+ int i, n = -1;
+ Xschem_ctx *ctx, **save_xctx = get_save_xctx();
+ for(i = 0; i < MAX_NEW_WINDOWS; ++i) {
+ if(!strcmp(win_path, window_path[i])) {
+ n = i;
+ break;
+ }
+ }
+ if(n == -1) {
+ 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(get_window_count() == 0 && i == 0) {
+ ctx = xctx;
+ }
+ if(ctx && !strcmp(win_path, get_cell_w_ext(ctx->current_name, 0))) {
+ n = i;
+ break;
+ }
+ }
+ }
+ return n;
+}
+
/* swap primary view (.drw) with first valid tab (x1.drw, x2.drw, ...)
* used for window close ('xschem exit' command) */
void swap_tabs(void)
@@ -1304,7 +1331,7 @@ void swap_windows(void)
/* rebuld colors and pixmaps, redraw swapped schematics */
tclvareval("restore_ctx ", wp_i, NULL);
- new_schematic("switch_win", wp_i, "");
+ new_schematic("switch", wp_i, "");
tclvareval("housekeeping_ctx", NULL);
tclvareval("xschem build_colors", NULL);
resetwin(1, 1, 1, 0, 0);
@@ -1314,7 +1341,7 @@ void swap_windows(void)
/* set context to window that is about to be deleted */
tclvareval("restore_ctx ", wp_j, NULL);
- new_schematic("switch_win", wp_j, "");
+ new_schematic("switch", wp_j, "");
tclvareval("housekeeping_ctx", NULL);
tclvareval("xschem build_colors", NULL);
resetwin(1, 1, 1, 0, 0);
@@ -1353,37 +1380,36 @@ 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);
- * new_schematic("switch_win", winpath, "");
- * tclvareval("housekeeping_ctx", NULL);
- */
-static void switch_window(int *window_count, const char *win_path)
+static void switch_window(int *window_count, const char *win_path, int tcl_ctx)
{
- int i, n;
+ int n;
+ char my_win_path[80];
Tk_Window tkwin;
+ if(!win_path) {
+ dbg(0, "switch_window(): no filename or window path given\n");
+ return;
+ }
if(!strcmp(win_path, xctx->current_win_path)) return; /* already there */
if(*window_count) {
- 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_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])) {
- n = i;
- break;
- }
- }
+ n = get_tab_or_window_number(win_path);
if(n == -1) {
- dbg(0, "new_schematic(\"switch_win\"...): no window to switch to found: %s\n", win_path);
+ dbg(0, "new_schematic(\"switch\"...): no window to switch to found: %s\n", win_path);
return;
}
+ /* build my_win_path since win_path can also be a filename */
+ if(n == 0) my_snprintf(my_win_path, S(my_win_path), ".drw");
+ else my_snprintf(my_win_path, S(my_win_path), ".x%d.drw", n);
+ dbg(1, "new_schematic(\"switch\"...): %s\n", my_win_path);
+ tkwin = Tk_NameToWindow(interp, my_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 window was closed then tkwin == 0 --> do nothing */
if(tkwin && n >= 0 && n < MAX_NEW_WINDOWS) {
+
+ if(tcl_ctx) tclvareval("save_ctx ", xctx->current_win_path, NULL);
xctx = save_xctx[n];
+ if(tcl_ctx) tclvareval("restore_ctx ", win_path, NULL);
+ tclvareval("housekeeping_ctx", NULL);
+ if(tcl_ctx) tclvareval("reconfigure_layers_button {}", NULL);
set_modify(-1); /* sets window title */
}
}
@@ -1391,19 +1417,17 @@ static void switch_window(int *window_count, const char *win_path)
static void switch_tab(int *window_count, const char *win_path)
{
- int i, n;
+ int n;
if(xctx->semaphore) return; /* some editing operation ongoing. do nothing */
+ if(!win_path) {
+ dbg(0, "switch_tab(): no filename or window path given\n");
+ return;
+ }
if(!strcmp(win_path, xctx->current_win_path)) return; /* already there */
if(*window_count) {
dbg(1, "new_schematic() switch_tab: %s\n", win_path);
- n = -1;
- for(i = 0; i < MAX_NEW_WINDOWS; ++i) {
- if(!strcmp(win_path, window_path[i])) {
- n = i;
- break;
- }
- }
+ n = get_tab_or_window_number(win_path);
if(n == -1) {
dbg(0, "new_schematic(\"switch_tab\"...): no tab to switch to found: %s\n", win_path);
return;
@@ -1508,7 +1532,7 @@ static void create_new_window(int *window_count, const char *noconfirm, const ch
* because the Expose event after new window creation does a context switch prev win -> new win
*/
tclvareval("restore_ctx ", prev_window, NULL);
- new_schematic("switch_win", prev_window, "");
+ new_schematic("switch", prev_window, "");
tclvareval("housekeeping_ctx", NULL);
windowid(toppath);
@@ -1570,7 +1594,7 @@ static void create_new_tab(int *window_count, const char *noconfirm, const char
my_snprintf(nn, S(nn), "%d", i);
tclvareval(
"button ", ".tabs.x", nn, " -padx 2 -pady 0 -takefocus 0 -anchor nw -text Tab2 "
- "-command \"xschem new_schematic switch_tab .x", nn, ".drw\"", NULL);
+ "-command \"xschem new_schematic switch .x", nn, ".drw\"", NULL);
tclvareval("bind .tabs.x",nn,"