405 lines
11 KiB
C
405 lines
11 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 "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"
|
||
|
||
/* 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 void (*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. */
|
||
void (*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(name, proc, cursor, doc)
|
||
char *name; /* Name of this button handler. This name
|
||
* is what's passed to DBWChangeButtonHandler
|
||
* to activate the handler.
|
||
*/
|
||
void (*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.
|
||
*/
|
||
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;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* 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);
|
||
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);
|
||
}
|
||
}
|
||
}
|