added commands `xschem switch [win_path|schname]`, `xschem destroy_all [force]`, added `[force]` option to xschem exit

This commit is contained in:
stefan schippers 2023-06-08 10:40:52 +02:00
parent a27a187bb4
commit de1f4f0d86
5 changed files with 139 additions and 67 deletions

View File

@ -490,6 +490,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
<li><kbd> abort_operation</kbd></li><pre>
Resets UI state, unselect all and abort any pending operation </pre>
<li><kbd> add_symbol_pin</kbd></li><pre>
@ -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). </pre>
<li><kbd> descend_symbol</kbd></li><pre>
Descend into the symbol view of selected component instance </pre>
<li><kbd> destroy_all [force]</kbd></li><pre>
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 </pre>
<li><kbd> display_hilights [nets|instances]</kbd></li><pre>
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"
<li><kbd> exit [closewindow]</kbd></li><pre>
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 </pre>
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 </pre>
<li><kbd> expandlabel lab</kbd></li><pre>
Expand vectored labels/instance names:
xschem expandlabel {2*A[3:0]} --&gt; 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"
<li><kbd> new_process [f]</kbd></li><pre>
Start a new xschem process for a schematic.
If 'f' is given load specified schematic. </pre>
<li><kbd> new_schematic create|destroy|destroy_all|switch_win|switch_tab winpath file</kbd></li><pre>
<li><kbd> new_schematic create|destroy|destroy_all|switch winpath file</kbd></li><pre>
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...</pre>
<li><kbd> only_probes</kbd></li><pre>
@ -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 </pre>
<li><kbd> switch [window_path |schematic_name]</kbd></li><pre>
Switch context to indicated window path or schematic name
returns the # of windows/tabs in addition to main window/tab</pre>
<li><kbd> symbols [n]</kbd></li><pre>
if 'n' given list symbol with name or number 'n', else
list all used symbols </pre>

View File

@ -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)) {

View File

@ -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 */

View File

@ -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," <ButtonPress> {swap_tabs %X %Y press}", NULL);
tclvareval("bind .tabs.x",nn," <ButtonRelease> {swap_tabs %X %Y release}", NULL);
tclvareval(
@ -1612,6 +1636,10 @@ static void destroy_window(int *window_count, const char *win_path)
if(*window_count) {
int close = 0;
dbg(1, "new_schematic() destroy {%s}\n", win_path);
if(!win_path) {
dbg(0, "destroy_window(): no window path given\n");
return;
}
if(xctx->modified && has_x) {
tcleval("tk_messageBox -type okcancel -parent [xschem get topwindow] -message \""
"[get_cell [xschem get schname] 0]"
@ -1666,6 +1694,10 @@ static void destroy_tab(int *window_count, const char *win_path)
int close = 0;
dbg(1, "new_schematic() destroy_tab\n");
if(!win_path) {
dbg(0, "destroy_tab(): no window path given\n");
return;
}
if(strcmp(win_path, xctx->current_win_path)) {
dbg(0, "new_schematic(\"destroy_tab\", %s): must be in this tab to destroy\n", win_path);
return;
@ -1844,10 +1876,11 @@ int new_schematic(const char *what, const char *win_path, const char *fname)
} else {
destroy_all_tabs(&window_count, win_path ? 1 : 0);
}
} 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);
} else if(!strcmp(what, "switch")) {
if(tabbed_interface) switch_tab(&window_count, win_path);
else switch_window(&window_count, win_path, 1);
} else if(!strcmp(what, "switch_no_tcl_ctx") && !tabbed_interface) {
switch_window(&window_count, win_path, 0);
}
return window_count;
}

View File

@ -5230,7 +5230,7 @@ proc setup_tabbed_interface {} {
if { ![winfo exists .tabs] } {
frame .tabs
button .tabs.x0 -padx 2 -pady 0 -anchor nw -takefocus 0 \
-text Main -command "xschem new_schematic switch_tab .drw"
-text Main -command "xschem new_schematic switch .drw"
bind .tabs.x0 <ButtonPress> {swap_tabs %X %Y press}
bind .tabs.x0 <ButtonRelease> {swap_tabs %X %Y release}
button .tabs.add -padx 0 -pady 0 -takefocus 0 -text { + } -command "xschem new_schematic create"
@ -5255,12 +5255,12 @@ proc setup_tabbed_interface {} {
save_ctx $old
restore_ctx .drw
housekeeping_ctx
xschem new_schematic switch_win .drw
xschem new_schematic switch .drw
xschem exit closewindow
# did not exit (user cancel) ... switch back
restore_ctx $old
housekeeping_ctx
xschem new_schematic switch_win $old
xschem new_schematic switch $old
}
}
}
@ -5371,12 +5371,12 @@ proc quit_xschem {} {
if {$remaining == 0 } {
save_ctx [xschem get current_win_path]
restore_ctx .drw
xschem new_schematic switch_win .drw
xschem new_schematic switch .drw
housekeeping_ctx
xschem exit closewindow
}
} else {
xschem new_schematic switch_tab .drw
xschem new_schematic switch .drw
xschem exit closewindow
}
}
@ -6265,12 +6265,12 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get
save_ctx $old
restore_ctx .drw
housekeeping_ctx
xschem new_schematic switch_win .drw
xschem new_schematic switch .drw
xschem exit closewindow
# did not exit ... switch back
restore_ctx $old
housekeeping_ctx
xschem new_schematic switch_win $old
xschem new_schematic switch $old
}
} else {
wm protocol $rootwin WM_DELETE_WINDOW "xschem new_schematic destroy $topwin.drw {}"