Substantially revised the "macro" command callback functions and
the "tool" implementation. Previously, the "tool" implementation would overwrite the button bindings for the mouse. The problem with that is that if the user customizes one or more of the bindings, such as using the mouse wheel for zooming instead of panning, then the custom macro gets obliterated when the tool changes. The reimplementation creates multiple macro sets which are unique to each tool. The "enable_tools" function sets up the initial unique default bindings for each tool. The user can then customize the bindings for any tool, and the implementation no longer requires the constant changing of key bindings. Note that the new implementation is slightly less efficient because the macro tables are found by string hash based on the name of the tool or client type, not the integer client ID. The reduction in efficiency is balanced by the increased flexibility of the macros.
This commit is contained in:
parent
53e7dfe04c
commit
27c423c2ed
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
151
utils/macros.c
151
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 --
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue