mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-01 18:48:37 +02:00
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.
442 lines
12 KiB
C
442 lines
12 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;
|
|
(void) StrDup(&dbwButtonHandlers[i], name);
|
|
(void) StrDup(&dbwButtonDoc[i], doc);
|
|
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];
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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()
|
|
{
|
|
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* 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);
|
|
}
|
|
}
|
|
}
|