diff --git a/VERSION b/VERSION index ac26a2d6..1a008949 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.559 +8.3.560 diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index b834463d..9663432a 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -671,6 +671,15 @@ CmdTool( if (strcmp(cmd->tx_argv[1], "info") == 0) DBWPrintButtonDoc(); + else if (strcmp(cmd->tx_argv[1], "type") == 0) + { + char *toolType = DBWGetButtonHandler(); +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(toolType, -1)); +#else + TxPrintf("Current tool is \"%s\".\n", toolType); +#endif /* MAGIC_WRAPPER */ + } else (void) DBWChangeButtonHandler(cmd->tx_argv[1]); } diff --git a/dbwind/DBWbuttons.c b/dbwind/DBWbuttons.c index b786148d..49080da5 100644 --- a/dbwind/DBWbuttons.c +++ b/dbwind/DBWbuttons.c @@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include +#include "tcltk/tclmagic.h" #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" @@ -240,6 +241,38 @@ DBWChangeButtonHandler(name) return oldName; } +/* + * ---------------------------------------------------------------------------- + * + * DBWGetButtonHandler -- + * + * Return the name of the current button handler. This does the same + * thing as DBWChangeButtonHandler(name) with an invalid name, but + * without printing the error messages. However, if magic is running + * with the Tcl interpreter wrapper, then return the string value of + * $Opts(tool), if it exists. + * + * Results: + * A pointer to the name of the current button handler. + * + * Side effects: + * None. + * + * ---------------------------------------------------------------------------- + */ + +char * +DBWGetButtonHandler() +{ +#ifdef MAGIC_WRAPPER + char *toolName; + toolName = (char *)Tcl_GetVar2(magicinterp, "Opts", "tool", TCL_GLOBAL_ONLY); + if (toolName != NULL) return toolName; +#endif + + return dbwButtonHandlers[dbwButtonCurrentIndex]; +} + /* * ---------------------------------------------------------------------------- * diff --git a/dbwind/dbwind.h b/dbwind/dbwind.h index 9348a0ba..a46cce36 100644 --- a/dbwind/dbwind.h +++ b/dbwind/dbwind.h @@ -145,6 +145,7 @@ extern void (*DBWButtonCurrentProc)(); typedef void (*cb_database_buttonhandler_t)(MagWindow *w, TxCommand *cmd); extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandler_t proc, int cursor, const char *doc); +extern char *DBWGetButtonHandler(); extern char *DBWChangeButtonHandler(); extern void DBWPrintButtonDoc(); extern void DBWBoxHandler(); diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index f064b785..b646393f 100644 --- a/tcltk/tools.tcl +++ b/tcltk/tools.tcl @@ -516,8 +516,55 @@ proc magic::enable_tools {} { magic::macro space {magic::tool} magic::macro Shift_space {magic::tool box} + # Set these first because the magic::tool command defined + # in this script depends on them being valid. set Opts(tool) box set Opts(motion) {} + + # Set up unique key macros for each individual tool. This + # effectively defines what the tools are, since each tool + # is really just a collection of unique key bindings. The + # default bindings are copied from the "box" tool, and + # then replacement bindings for button actions are applied. + # The user can change these bindings at will by using the + # "macro" command when the tool is active. + + magic::macro copy wiring + magic::macro copy netlist + magic::macro copy pick + + magic::tool wiring + macro Button1 "magic::trackwire %W pick" + macro Button2 "magic::trackwire %W done" + macro Button3 "magic::trackwire %W cancel" + macro Shift_Button1 "wire incr type ; wire show" + macro Shift_Button2 "wire switch" + macro Shift_Button3 "wire decr type ; wire show" + macro Button4 "wire incr width ; wire show" + macro Button5 "wire decr width ; wire show" + + magic::tool netlist + macro Button1 "netlist select" + macro Button2 "netlist join" + macro Button3 "netlist terminal" + # Remove shift-button bindings + macro Shift_Button1 "" + macro Shift_Button2 "" + macro Shift_Button3 "" + macro Button4 "scroll u .05 w" + macro Button5 "scroll d .05 w" + + magic::tool pick + macro Button1 "magic::keepselect %W" + macro Shift_Button2 "magic::startselect %W copy" + macro Button2 "magic::startselect %W pick" + macro Button3 "magic::cancelselect %W" + macro Shift_Button1 "box corner bl cursor" + macro Shift_Button3 "box move ur cursor" + macro Button4 "scroll u .05 w" + macro Button5 "scroll d .05 w" + + magic::tool box set Opts(origin) {0 0} set Opts(backupinterval) 60000 magic::crashbackups start @@ -644,6 +691,9 @@ proc magic::tool {{type next}} { } } switch $type { + type { + return $Opts(tool) + } info { # print information about the current tool. puts stdout "Current tool is $Opts(tool)." @@ -675,63 +725,32 @@ proc magic::tool {{type next}} { if {[llength [macro Control_Button3]] > 0} { macro Control_Button3 } + if {[llength [macro Button4]] > 0} { + macro Button4 + } + if {[llength [macro Button5]] > 0} { + macro Button5 + } } box { puts stdout {Switching to BOX tool.} set Opts(tool) box cursor 0 ;# sets the cursor - macro Button1 "box move bl cursor; magic::boxview %W %1" - macro Shift_Button1 "box corner bl cursor; magic::boxview %W %1" - macro Button2 "paint cursor" - macro Shift_Button2 "erase cursor" - macro Button3 "box corner ur cursor" - macro Shift_Button3 "box move ur cursor; magic::boxview %W %1" - macro Button4 "scroll u .05 w; magic::boxview %W %1" - macro Button5 "scroll d .05 w; magic::boxview %W %1" - macro Shift_XK_Pointer_Button4 "scroll r .05 w; magic::boxview %W %1" - macro Shift_XK_Pointer_Button5 "scroll l .05 w; magic::boxview %W %1" - } wiring { puts stdout {Switching to WIRING tool.} set Opts(tool) wiring cursor 19 ;# sets the cursor - macro Button1 "magic::trackwire %W pick" - macro Button2 "magic::trackwire %W done" - macro Button3 "magic::trackwire %W cancel" - macro Shift_Button1 "wire incr type ; wire show" - macro Shift_Button2 "wire switch" - macro Shift_Button3 "wire decr type ; wire show" - macro Button4 "wire incr width ; wire show" - macro Button5 "wire decr width ; wire show" - } netlist { puts stdout {Switching to NETLIST tool.} set Opts(tool) netlist cursor 18 ;# sets the cursor - macro Button1 "netlist select" - macro Button2 "netlist join" - macro Button3 "netlist terminal" - # Remove shift-button bindings - macro Shift_Button1 "" - macro Shift_Button2 "" - macro Shift_Button3 "" - macro Button4 "scroll u .05 w" - macro Button5 "scroll d .05 w" } pick { puts stdout {Switching to PICK tool.} set Opts(tool) pick cursor 22 ;# set the cursor - macro Button1 "magic::keepselect %W" - macro Shift_Button2 "magic::startselect %W copy" - macro Button2 "magic::startselect %W pick" - macro Button3 "magic::cancelselect %W" - macro Shift_Button1 "box corner bl cursor" - macro Shift_Button3 "box move ur cursor" - macro Button4 "scroll u .05 w" - macro Button5 "scroll d .05 w" } } diff --git a/utils/macros.c b/utils/macros.c index 878673ee..25ab1adc 100644 --- a/utils/macros.c +++ b/utils/macros.c @@ -38,6 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/malloc.h" #include "utils/macros.h" #include "windows/windows.h" +#include "dbwind/dbwind.h" /* C99 compat */ #include "textio/textio.h" @@ -58,20 +59,29 @@ HashTable MacroClients; * Side Effects: * Memory allocated for the hash table MacroClients. * + * Note: + * Hash type changed from WORDKEYS to STRINGKEYS. + * This is slightly less efficient but allows the + * layout window client to be divided into separate + * macro clients for each tool type, accessed by + * name. + * *--------------------------------------------------------- */ void MacroInit() { - HashInit(&MacroClients, 4, HT_WORDKEYS); + HashInit(&MacroClients, 4, HT_STRINGKEYS); } /* *--------------------------------------------------------- - * MacroDefine --- + * MacroDefineByName --- * - * This procedure defines a macro. + * This procedure defines a macro. The macro table is + * defined by name, not by client. MacroDefine() is a + * wrapper for this routine. * * Results: * None. @@ -83,8 +93,8 @@ MacroInit() */ void -MacroDefine(client, xc, str, help, imacro) - WindClient client; /* window client type */ +MacroDefineByName(clientName, xc, str, help, imacro) + char *clientName; /* window client name */ int xc; /* full (X11) keycode of macro with modifiers */ char *str; /* ...and the string to be attached to it */ char *help; /* ...and/or the help text for the macro */ @@ -95,7 +105,7 @@ MacroDefine(client, xc, str, help, imacro) macrodef *oldMacro, *newMacro; /* If a macro exists, delete the old string and redefine it */ - h = HashFind(&MacroClients, (char *)client); + h = HashFind(&MacroClients, (char *)clientName); clienttable = (HashTable *)HashGetValue(h); if (clienttable == NULL) { @@ -127,6 +137,45 @@ MacroDefine(client, xc, str, help, imacro) newMacro->helptext = NULL; } +/* + *------------------------------------------------------------------ + * MacroDefine --- + * + * This procedure is a simple wrapper for MacroDefineByName(). + * The window client is given as a client ID. This limits + * macros to one set per client type. To allow a more + * flexible macro handling, if the client is a layout window + * (DBWclientID), then the name is instead taken from the + * name of the tool currently active. This allows macros + * to be uniquely defined for each tool. + * + * Results: + * None. + * + * Side Effects: + * The string passed is copied and considered to be the + * macro definition for the character. + *------------------------------------------------------------------ + */ + +void +MacroDefine(client, xc, str, help, imacro) + WindClient client; /* window client type */ + int xc; /* full (X11) keycode of macro with modifiers */ + char *str; /* ...and the string to be attached to it */ + char *help; /* ...and/or the help text for the macro */ + bool imacro; /* is this an interactive macro? */ +{ + char *clientName = NULL; + + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); + + MacroDefineByName(clientName, xc, str, help, imacro); +} + /* *--------------------------------------------------------- * MacroDefineHelp --- @@ -152,9 +201,15 @@ MacroDefineHelp(client, xc, help) HashEntry *h; HashTable *clienttable; macrodef *curMacro; + char *clientName = NULL; + + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); /* If a macro exists, delete the old string and redefine it */ - h = HashFind(&MacroClients, (char *)client); + h = HashFind(&MacroClients, (char *)clientName); clienttable = (HashTable *)HashGetValue(h); if (clienttable == NULL) return; @@ -194,9 +249,17 @@ MacroRetrieve(client, xc, iReturn) HashEntry *h; HashTable *clienttable; macrodef *cMacro; + char *clientName = NULL; + + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); + if (clientName == NULL) + return NULL; /* If a macro exists, delete the old string and redefine it */ - h = HashLookOnly(&MacroClients, (char *)client); + h = HashLookOnly(&MacroClients, (char *)clientName); if (h != NULL) { clienttable = (HashTable *)HashGetValue(h); @@ -241,9 +304,15 @@ MacroRetrieveHelp(client, xc) HashEntry *h; HashTable *clienttable; macrodef *cMacro; + char *clientName = NULL; + + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); /* If a macro exists, delete the old string and redefine it */ - h = HashLookOnly(&MacroClients, (char *)client); + h = HashLookOnly(&MacroClients, (char *)clientName); if (h != NULL) { clienttable = (HashTable *)HashGetValue(h); @@ -340,8 +409,14 @@ MacroDelete(client, xc) HashEntry *h; HashTable *clienttable; macrodef *cMacro; + char *clientName = NULL; - h = HashLookOnly(&MacroClients, (char *)client); + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); + + h = HashLookOnly(&MacroClients, (char *)clientName); if (h != NULL) { clienttable = (HashTable *)HashGetValue(h); @@ -365,6 +440,62 @@ MacroDelete(client, xc) } } +/* + * ---------------------------------------------------------------------------- + * MacroCopy -- + * Copy all macros from one table to another. + * This is used with the "tool" command to simplify the process + * of defining new macro sets for button and keypress actions + * for a new tool type. It copies all of the macros from the + * table for the client passed as (WindClient type) "client" to + * the table for the client named by (string) "clientkey". + * + * Results: + * None. + * + * Side effects: + * New hash entries are created. + * ---------------------------------------------------------------------------- + */ + +void +MacroCopy(client, clientkey) + WindClient client; /* Current window client */ + char *clientkey; /* Name of client to copy macros to */ +{ + HashTable *clienttable; + HashTable *copytable; + HashEntry *h, *he; + HashSearch hs; + char *clientName; + int cKey; + macrodef *cMacro; + + if (clientkey == NULL) return; + if (client == (WindClient)NULL) return; + + if (client == DBWclientID) + clientName = DBWGetButtonHandler(); + if (clientName == NULL) + clientName = WindGetClientName(client); + + h = HashLookOnly(&MacroClients, (char *)clientName); + if (h == NULL) return; /* No clients, nothing can be done */ + + clienttable = (HashTable *)HashGetValue(h); + if (clienttable == NULL) return; /* Also nothing can be done */ + + HashStartSearch(&hs); + while (TRUE) + { + he = HashNext(clienttable, &hs); + if (he == NULL) break; + cMacro = (macrodef *)HashGetValue(he); + cKey = (int)CD2INT(he->h_key.h_ptr); + MacroDefineByName(clientkey, cKey, cMacro->macrotext, + cMacro->helptext, cMacro->interactive); + } +} /* * ---------------------------------------------------------------------------- diff --git a/utils/macros.h b/utils/macros.h index 1e232f68..b55cf626 100644 --- a/utils/macros.h +++ b/utils/macros.h @@ -48,6 +48,7 @@ extern char *MacroRetrieveHelp(); /* returns a malloc'ed string */ extern char *MacroSubstitute(); /* returns a malloc'ed string */ extern void MacroDelete(); extern char *MacroName(); /* returns a malloc'ed string */ +extern void MacroCopy(); extern int MacroKey(); extern int MacroCode(); diff --git a/windows/windCmdAM.c b/windows/windCmdAM.c index b1a57b99..1ec32e78 100644 --- a/windows/windCmdAM.c +++ b/windows/windCmdAM.c @@ -1087,6 +1087,22 @@ windDoMacro(w, cmd, interactive) do_reverse = TRUE; argstart++; } + else if (!strcmp(cmd->tx_argv[argstart], "copy")) + { + if (cmd->tx_argc > (argstart + 1)) + { + argstart++; + if (wc == (WindClient)NULL) + { + if (w != NULL) + wc = w->w_client; + else + wc = DBWclientID; + } + MacroCopy(wc, cmd->tx_argv[argstart]); + } + return; + } else break; } diff --git a/windows/windMain.c b/windows/windMain.c index f24c15bf..018123b6 100644 --- a/windows/windMain.c +++ b/windows/windMain.c @@ -323,6 +323,30 @@ WindGetClient(clientName, exact) return (WindClient) found; } +/* + * ---------------------------------------------------------------------------- + * WindGetClientName -- + * + * Looks up the name of a client from the unique client ID for a window. + * + * Results: + * A pointer to the client name is returned. If the client is NULL, + * then NULL is returned. + * + * Side effects: + * None. + * ---------------------------------------------------------------------------- + */ + +char * +WindGetClientName(client) + WindClient client; +{ + clientRec *clientrec = (clientRec *)client; + if (client == (WindClient)NULL) return NULL; + return clientrec->w_clientName; +} + /* * ---------------------------------------------------------------------------- * WindNextClient -- diff --git a/windows/windows.h b/windows/windows.h index 2a741440..cd1b2c09 100644 --- a/windows/windows.h +++ b/windows/windows.h @@ -240,6 +240,7 @@ extern MagWindow *WindCreate(); extern WindClient WindGetClient(); extern WindClient WindNextClient(); extern WindClient WindAddClient(); +extern char *WindGetClientName(); extern void WindInit(); extern void WindUpdate(); extern void WindDrawBorder();