mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-02 20:08:44 +02:00
"tool" command was changed to be overridden by a Tcl command. Due to macro clients being registered with the tool name instead of just "layout", the "macro" command with no arguments or with a window client argument was just broken. In the process of fixing this, I realized that there was a conflict between the use of "netlist" as a window name and also as the name of a tool, so I changed the tool name to "nettool", a change which should be transparent to the end user. Otherwise, "macro netlist" returns the key bindings for the window, and the only way to get the key bindings for the tool is to make the tool active and then use "macro" without arguments. One remaining issue is that there is no syntax error that will cause the list of valid windows and tools to be printed. Probably "macro help" should print usage information instead of acting like "macro" with no arguments.
479 lines
13 KiB
C
479 lines
13 KiB
C
/*
|
|
* DBWbuttons.c --
|
|
*
|
|
* This file provides a general facility whereby clients that are
|
|
* willing to provide handlers for button presses in layout windows
|
|
* can themselves, and the current handler can be switched
|
|
* between them. This file also provides the default button handler,
|
|
* which is used to move the box.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWbuttons.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "windows/windows.h"
|
|
#include "graphics/graphics.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "utils/styles.h"
|
|
#include "textio/textio.h"
|
|
#include "textio/txcommands.h"
|
|
#include "utils/utils.h"
|
|
|
|
/* C99 compat */
|
|
#include "commands/commands.h"
|
|
|
|
/* The arrays below are used to store information about the various
|
|
* button handlers that have registered themselves.
|
|
*/
|
|
|
|
#define MAXBUTTONHANDLERS 10
|
|
|
|
static char *dbwButtonHandlers[MAXBUTTONHANDLERS];
|
|
/* Name of each button handler: used to select
|
|
* that handler as the current one. A NULL entry
|
|
* here means that this handler slot isn't in use.
|
|
*/
|
|
static char *dbwButtonDoc[MAXBUTTONHANDLERS];
|
|
/* A documentation string for each handler: tells
|
|
* what the button pushes and releases mean.
|
|
*/
|
|
static cb_database_buttonhandler_t dbwButtonProcs[MAXBUTTONHANDLERS];
|
|
/* A procedure for each handler that is invoked
|
|
* on button presses and releases when that handler
|
|
* is the current one.
|
|
*/
|
|
static int dbwButtonCursors[MAXBUTTONHANDLERS];
|
|
/* Cursor shape to use for each handler. */
|
|
|
|
static int dbwButtonCurrentIndex;
|
|
/* Index of current handler. */
|
|
cb_database_buttonhandler_t DBWButtonCurrentProc;
|
|
/* Current button-handling procedure. */
|
|
|
|
static int buttonCorner = TOOL_ILG; /* Nearest corner when button went
|
|
* down.
|
|
*/
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBWAddButtonHandler --
|
|
*
|
|
* This procedure is called by would-be button handlers to register
|
|
* themselves. After a client has called this procedure, it may
|
|
* make itself the current button handler by calling the procedure
|
|
* DBWChangeButtonHandler.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The client's information is added to the registry of potential
|
|
* button handlers. When the handler is made the current one (by
|
|
* a call to DBWChangeButtonHandler) each button press or release
|
|
* in a layout window causes proc to be invoked as follows:
|
|
*
|
|
* int
|
|
* proc(w, cmd)
|
|
* MagWindow *w;
|
|
* TxCommand *cmd;
|
|
* {
|
|
* }
|
|
*
|
|
* W is the window in which the button was pushed, and cmd describes
|
|
* exactly what happened.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBWAddButtonHandler(
|
|
const char *name, /* Name of this button handler. This name
|
|
* is what's passed to DBWChangeButtonHandler
|
|
* to activate the handler.
|
|
*/
|
|
const cb_database_buttonhandler_t proc,
|
|
/* Procedure to call on button actions when
|
|
* this handler is active.
|
|
*/
|
|
int cursor, /* Cursor shape (e.g. STYLE_CURS_NORMAL) to
|
|
* use when this handler is active.
|
|
*/
|
|
const char *doc) /* A documentation string for this handler:
|
|
* describes what the button pushes do when
|
|
* this handler is active.
|
|
*/
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
|
{
|
|
if (dbwButtonHandlers[i] != NULL) continue;
|
|
StrDup(&dbwButtonHandlers[i], name);
|
|
if (doc != NULL)
|
|
StrDup(&dbwButtonDoc[i], doc);
|
|
else
|
|
dbwButtonDoc[i] = (char *)NULL;
|
|
dbwButtonProcs[i] = proc;
|
|
dbwButtonCursors[i] = cursor;
|
|
return;
|
|
}
|
|
|
|
TxError("Can't add tool \"%s\": no space in button handler\n",
|
|
name);
|
|
TxError(" table. Get your Magic wizard to increase the size of\n");
|
|
TxError(" MAXBUTTONHANDLERS in DBWbuttons.c\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBWChangeButtonHandler --
|
|
*
|
|
* Change the active button handler.
|
|
*
|
|
* Results:
|
|
* The return value is the name of the previous button handler, in
|
|
* case the caller should wish to restore it.
|
|
*
|
|
* Side effects:
|
|
* If name is NULL, then the "next" button handler is activated, in a
|
|
* circular fashion. If name isn't NULL, then it is the name of a
|
|
* handler, which is activated. If the name doesn't match a handler
|
|
* then a message is printed and the handler isn't changed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
DBWChangeButtonHandler(name)
|
|
char *name; /* Name of new handler. Must be a unique
|
|
* abbreviation of a name passed previously
|
|
* to DBAddButtonHandler, or NULL.
|
|
*/
|
|
{
|
|
char *oldName = dbwButtonHandlers[dbwButtonCurrentIndex];
|
|
static int firstTime = TRUE;
|
|
|
|
if (name == NULL)
|
|
{
|
|
/* Just rotate to the next available client. */
|
|
|
|
while (TRUE)
|
|
{
|
|
dbwButtonCurrentIndex += 1;
|
|
if (dbwButtonCurrentIndex >= MAXBUTTONHANDLERS)
|
|
dbwButtonCurrentIndex = 0;
|
|
if (dbwButtonHandlers[dbwButtonCurrentIndex] == NULL)
|
|
continue;
|
|
if (firstTime)
|
|
{
|
|
firstTime = FALSE;
|
|
TxPrintf("Switching to \"%s\" tool.",
|
|
dbwButtonHandlers[dbwButtonCurrentIndex]);
|
|
TxPrintf(" If you didn't really want to switch,\n");
|
|
TxPrintf(" type \":tool box\" to");
|
|
TxPrintf(" switch back to the box tool.\n");
|
|
}
|
|
else
|
|
{
|
|
TxPrintf("Switching to \"%s\" tool.\n",
|
|
dbwButtonHandlers[dbwButtonCurrentIndex]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i, match, length;
|
|
|
|
match = -1;
|
|
length = strlen(name);
|
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
|
{
|
|
if (dbwButtonHandlers[i] == NULL) continue;
|
|
if (strncmp(name, dbwButtonHandlers[i], length) != 0) continue;
|
|
if (match >= 0)
|
|
{
|
|
TxError("\"%s\" is an ambiguous tool name.", name);
|
|
match = -2;
|
|
break;
|
|
}
|
|
match = i;
|
|
}
|
|
|
|
if (match == -1)
|
|
TxError("\"%s\" isn't a tool name.", name);
|
|
if (match < 0)
|
|
{
|
|
TxError(" The legal names are:\n");
|
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
|
{
|
|
if (dbwButtonHandlers[i] == NULL) continue;
|
|
TxError(" %s\n", dbwButtonHandlers[i]);
|
|
}
|
|
return oldName;
|
|
}
|
|
dbwButtonCurrentIndex = match;
|
|
}
|
|
|
|
GrSetCursor(dbwButtonCursors[dbwButtonCurrentIndex]);
|
|
DBWButtonCurrentProc = dbwButtonProcs[dbwButtonCurrentIndex];
|
|
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];
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBWButtonHandlerIndex()
|
|
*
|
|
* Given a string, return the index of the button handler. If the
|
|
* string does not correspond to any button handler name, then
|
|
* return -1.
|
|
*
|
|
* Results:
|
|
* Index of button handler, if it exists; -1 otherwise.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
DBWButtonHandlerIndex(char *toolName)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
|
{
|
|
if (dbwButtonHandlers[i] == NULL) return -1;
|
|
else if (!strcmp(toolName, dbwButtonHandlers[i])) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBWPrintButtonDoc --
|
|
*
|
|
* This procedure prints out documentation for the current
|
|
* button handler.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Stuff gets printed on the tty, ostensibly describing what
|
|
* the current buttons do.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBWPrintButtonDoc()
|
|
{
|
|
if (dbwButtonDoc[dbwButtonCurrentIndex])
|
|
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
|
else
|
|
TxPrintf("(no usage information)\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* dbwButtonSetCursor --
|
|
*
|
|
* Used to set the programmable cursor for a particular
|
|
* button state.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Selects and sets a programmable cursor based on the given
|
|
* button (for sizing or moving) and corner.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
dbwButtonSetCursor(button, corner)
|
|
int button; /* Button that is down. */
|
|
int corner; /* Corner to be displayed in cursor. */
|
|
|
|
{
|
|
switch (corner)
|
|
{
|
|
case TOOL_BL:
|
|
if (button == TX_LEFT_BUTTON)
|
|
GrSetCursor(STYLE_CURS_LLBOX);
|
|
else
|
|
GrSetCursor(STYLE_CURS_LLCORNER);
|
|
break;
|
|
case TOOL_BR:
|
|
if (button == TX_LEFT_BUTTON)
|
|
GrSetCursor(STYLE_CURS_LRBOX);
|
|
else
|
|
GrSetCursor(STYLE_CURS_LRCORNER);
|
|
break;
|
|
case TOOL_TL:
|
|
if (button == TX_LEFT_BUTTON)
|
|
GrSetCursor(STYLE_CURS_ULBOX);
|
|
else
|
|
GrSetCursor(STYLE_CURS_ULCORNER);
|
|
break;
|
|
case TOOL_TR:
|
|
if (button == TX_LEFT_BUTTON)
|
|
GrSetCursor(STYLE_CURS_URBOX);
|
|
else
|
|
GrSetCursor(STYLE_CURS_URCORNER);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBWBoxHandler --
|
|
*
|
|
* This procedure is called to handle button actions in layout
|
|
* windows when the "box" handler is active. It adjusts the box
|
|
* position and size.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Left button: used to move the whole box by the lower-left corner.
|
|
* Right button: used to re-size the box by its upper-right corner.
|
|
* If one of the left or right buttons is pushed, then the
|
|
* other is pushed, the corner is switched to the nearest
|
|
* one to the cursor. This corner is remembered for use
|
|
* in box positioning/sizing when both buttons have gone up.
|
|
* Middle button: used to paint whatever layers are underneath the
|
|
* crosshair.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBWBoxHandler(w, cmd)
|
|
MagWindow *w; /* Window containing cursor. */
|
|
TxCommand *cmd; /* Describes what happened. */
|
|
{
|
|
int button = cmd->tx_button;
|
|
|
|
if (button == TX_MIDDLE_BUTTON)
|
|
{
|
|
if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
|
|
CmdPaintEraseButton(w, &cmd->tx_p, TRUE, TRUE);
|
|
return;
|
|
}
|
|
|
|
if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
|
|
{
|
|
if ((WindNewButtons & (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
|
|
== (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
|
|
{
|
|
/* Both buttons are now down. In this case, the FIRST
|
|
* button pressed determines whether we move or size,
|
|
* and the second button is just used as a signal to pick
|
|
* the closest corner.
|
|
*/
|
|
|
|
buttonCorner = ToolGetCorner(&cmd->tx_p);
|
|
if (button == TX_LEFT_BUTTON) button = TX_RIGHT_BUTTON;
|
|
else button = TX_LEFT_BUTTON;
|
|
}
|
|
else if (button == TX_LEFT_BUTTON) buttonCorner = TOOL_BL;
|
|
else buttonCorner = TOOL_TR;
|
|
dbwButtonSetCursor(button, buttonCorner);
|
|
}
|
|
else
|
|
{
|
|
/* A button has just come up. If both buttons are down and one
|
|
* is released, we just change the cursor to reflect the current
|
|
* corner and the remaining button (i.e. move or size box).
|
|
*/
|
|
|
|
if (WindNewButtons != 0)
|
|
{
|
|
if (button == TX_LEFT_BUTTON)
|
|
dbwButtonSetCursor(TX_RIGHT_BUTTON, buttonCorner);
|
|
else dbwButtonSetCursor(TX_LEFT_BUTTON, buttonCorner);
|
|
return;
|
|
}
|
|
|
|
/* The last button has been released. Reset the cursor to normal
|
|
* form and then move or size the box.
|
|
*/
|
|
|
|
GrSetCursor(STYLE_CURS_NORMAL);
|
|
switch (button)
|
|
{
|
|
case TX_LEFT_BUTTON:
|
|
ToolMoveBox(buttonCorner, &cmd->tx_p, TRUE, (CellDef *) NULL);
|
|
break;
|
|
case TX_RIGHT_BUTTON:
|
|
ToolMoveCorner(buttonCorner, &cmd->tx_p, TRUE,
|
|
(CellDef *) NULL);
|
|
}
|
|
}
|
|
}
|