magic/dbwind/DBWbuttons.c

405 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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);
}
}
}