1 /*
2 * DBWbuttons.c --
3 *
4 * This file provides a general facility whereby clients that are
5 * willing to provide handlers for button presses in layout windows
6 * can themselves, and the current handler can be switched
7 * between them. This file also provides the default button handler,
8 * which is used to move the box.
9 *
10 * *********************************************************************
11 * * Copyright (C) 1985, 1990 Regents of the University of California. *
12 * * Permission to use, copy, modify, and distribute this *
13 * * software and its documentation for any purpose and without *
14 * * fee is hereby granted, provided that the above copyright *
15 * * notice appear in all copies. The University of California *
16 * * makes no representations about the suitability of this *
17 * * software for any purpose. It is provided "as is" without *
18 * * express or implied warranty. Export of this software outside *
19 * * of the United States of America may require an export license. *
20 * *********************************************************************
21 */
22
23 #ifndef lint
24 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 $";
25 #endif /* not lint */
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "utils/magic.h"
31 #include "utils/geometry.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "database/database.h"
35 #include "windows/windows.h"
36 #include "graphics/graphics.h"
37 #include "dbwind/dbwind.h"
38 #include "utils/styles.h"
39 #include "textio/textio.h"
40 #include "textio/txcommands.h"
41 #include "utils/utils.h"
42
43 /* The arrays below are used to store information about the various
44 * button handlers that have registered themselves.
45 */
46
47 #define MAXBUTTONHANDLERS 10
48
49 static char *dbwButtonHandlers[MAXBUTTONHANDLERS];
50 /* Name of each button handler: used to select
51 * that handler as the current one. A NULL entry
52 * here means that this handler slot isn't in use.
53 */
54 static char *dbwButtonDoc[MAXBUTTONHANDLERS];
55 /* A documentation string for each handler: tells
56 * what the button pushes and releases mean.
57 */
58 static void (*dbwButtonProcs[MAXBUTTONHANDLERS])();
59 /* A procedure for each handler that is invoked
60 * on button presses and releases when that handler
61 * is the current one.
62 */
63 static int dbwButtonCursors[MAXBUTTONHANDLERS];
64 /* Cursor shape to use for each handler. */
65
66 static int dbwButtonCurrentIndex;
67 /* Index of current handler. */
68 void (*DBWButtonCurrentProc)();
69 /* Current button-handling procedure. */
70
71 static int buttonCorner = TOOL_ILG; /* Nearest corner when button went
72 * down.
73 */
74
75 /*
76 * ----------------------------------------------------------------------------
77 *
78 * DBWAddButtonHandler --
79 *
80 * This procedure is called by would-be button handlers to register
81 * themselves. After a client has called this procedure, it may
82 * make itself the current button handler by calling the procedure
83 * DBWChangeButtonHandler.
84 *
85 * Results:
86 * None.
87 *
88 * Side effects:
89 * The client's information is added to the registry of potential
90 * button handlers. When the handler is made the current one (by
91 * a call to DBWChangeButtonHandler) each button press or release
92 * in a layout window causes proc to be invoked as follows:
93 *
94 * int
95 * proc(w, cmd)
96 * MagWindow *w;
97 * TxCommand *cmd;
98 * {
99 * }
100 *
101 * W is the window in which the button was pushed, and cmd describes
102 * exactly what happened.
103 *
104 * ----------------------------------------------------------------------------
105 */
106
107 void
DBWAddButtonHandler(name,proc,cursor,doc)108 DBWAddButtonHandler(name, proc, cursor, doc)
109 char *name; /* Name of this button handler. This name
110 * is what's passed to DBWChangeButtonHandler
111 * to activate the handler.
112 */
113 void (*proc)(); /* Procedure to call on button actions when
114 * this handler is active.
115 */
116 int cursor; /* Cursor shape (e.g. STYLE_CURS_NORMAL) to
117 * use when this handler is active.
118 */
119 char *doc; /* A documentation string for this handler:
120 * describes what the button pushes do when
121 * this handler is active.
122 */
123 {
124 int i;
125
126 for (i = 0; i < MAXBUTTONHANDLERS; i++)
127 {
128 if (dbwButtonHandlers[i] != NULL) continue;
129 (void) StrDup(&dbwButtonHandlers[i], name);
130 (void) StrDup(&dbwButtonDoc[i], doc);
131 dbwButtonProcs[i] = proc;
132 dbwButtonCursors[i] = cursor;
133 return;
134 }
135
136 TxError("Can't add tool \"%s\": no space in button handler\n",
137 name);
138 TxError(" table. Get your Magic wizard to increase the size of\n");
139 TxError(" MAXBUTTONHANDLERS in DBWbuttons.c\n");
140 }
141
142 /*
143 * ----------------------------------------------------------------------------
144 *
145 * DBWChangeButtonHandler --
146 *
147 * Change the active button handler.
148 *
149 * Results:
150 * The return value is the name of the previous button handler, in
151 * case the caller should wish to restore it.
152 *
153 * Side effects:
154 * If name is NULL, then the "next" button handler is activated, in a
155 * circular fashion. If name isn't NULL, then it is the name of a
156 * handler, which is activated. If the name doesn't match a handler
157 * then a message is printed and the handler isn't changed.
158 *
159 * ----------------------------------------------------------------------------
160 */
161
162 char *
DBWChangeButtonHandler(name)163 DBWChangeButtonHandler(name)
164 char *name; /* Name of new handler. Must be a unique
165 * abbreviation of a name passed previously
166 * to DBAddButtonHandler, or NULL.
167 */
168 {
169 char *oldName = dbwButtonHandlers[dbwButtonCurrentIndex];
170 static int firstTime = TRUE;
171
172 if (name == NULL)
173 {
174 /* Just rotate to the next available client. */
175
176 while (TRUE)
177 {
178 dbwButtonCurrentIndex += 1;
179 if (dbwButtonCurrentIndex >= MAXBUTTONHANDLERS)
180 dbwButtonCurrentIndex = 0;
181 if (dbwButtonHandlers[dbwButtonCurrentIndex] == NULL)
182 continue;
183 if (firstTime)
184 {
185 firstTime = FALSE;
186 TxPrintf("Switching to \"%s\" tool.",
187 dbwButtonHandlers[dbwButtonCurrentIndex]);
188 TxPrintf(" If you didn't really want to switch,\n");
189 TxPrintf(" type \":tool box\" to");
190 TxPrintf(" switch back to the box tool.\n");
191 }
192 else
193 {
194 TxPrintf("Switching to \"%s\" tool.\n",
195 dbwButtonHandlers[dbwButtonCurrentIndex]);
196 }
197 break;
198 }
199 }
200 else
201 {
202 int i, match, length;
203
204 match = -1;
205 length = strlen(name);
206 for (i = 0; i < MAXBUTTONHANDLERS; i++)
207 {
208 if (dbwButtonHandlers[i] == NULL) continue;
209 if (strncmp(name, dbwButtonHandlers[i], length) != 0) continue;
210 if (match >= 0)
211 {
212 TxError("\"%s\" is an ambiguous tool name.", name);
213 match = -2;
214 break;
215 }
216 match = i;
217 }
218
219 if (match == -1)
220 TxError("\"%s\" isn't a tool name.", name);
221 if (match < 0)
222 {
223 TxError(" The legal names are:\n");
224 for (i = 0; i < MAXBUTTONHANDLERS; i++)
225 {
226 if (dbwButtonHandlers[i] == NULL) continue;
227 TxError(" %s\n", dbwButtonHandlers[i]);
228 }
229 return oldName;
230 }
231 dbwButtonCurrentIndex = match;
232 }
233
234 GrSetCursor(dbwButtonCursors[dbwButtonCurrentIndex]);
235 DBWButtonCurrentProc = dbwButtonProcs[dbwButtonCurrentIndex];
236 return oldName;
237 }
238
239 /*
240 * ----------------------------------------------------------------------------
241 *
242 * DBWPrintButtonDoc --
243 *
244 * This procedure prints out documentation for the current
245 * button handler.
246 *
247 * Results:
248 * None.
249 *
250 * Side effects:
251 * Stuff gets printed on the tty, ostensibly describing what
252 * the current buttons do.
253 *
254 * ----------------------------------------------------------------------------
255 */
256
257 void
DBWPrintButtonDoc()258 DBWPrintButtonDoc()
259 {
260 TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
261 }
262
263
264 /*
265 * ----------------------------------------------------------------------------
266 * dbwButtonSetCursor --
267 *
268 * Used to set the programmable cursor for a particular
269 * button state.
270 *
271 * Results:
272 * None.
273 *
274 * Side effects:
275 * Selects and sets a programmable cursor based on the given
276 * button (for sizing or moving) and corner.
277 * ----------------------------------------------------------------------------
278 */
279
280 void
dbwButtonSetCursor(button,corner)281 dbwButtonSetCursor(button, corner)
282 int button; /* Button that is down. */
283 int corner; /* Corner to be displayed in cursor. */
284
285 {
286 switch (corner)
287 {
288 case TOOL_BL:
289 if (button == TX_LEFT_BUTTON)
290 GrSetCursor(STYLE_CURS_LLBOX);
291 else
292 GrSetCursor(STYLE_CURS_LLCORNER);
293 break;
294 case TOOL_BR:
295 if (button == TX_LEFT_BUTTON)
296 GrSetCursor(STYLE_CURS_LRBOX);
297 else
298 GrSetCursor(STYLE_CURS_LRCORNER);
299 break;
300 case TOOL_TL:
301 if (button == TX_LEFT_BUTTON)
302 GrSetCursor(STYLE_CURS_ULBOX);
303 else
304 GrSetCursor(STYLE_CURS_ULCORNER);
305 break;
306 case TOOL_TR:
307 if (button == TX_LEFT_BUTTON)
308 GrSetCursor(STYLE_CURS_URBOX);
309 else
310 GrSetCursor(STYLE_CURS_URCORNER);
311 break;
312 }
313 }
314
315
316 /*
317 * ----------------------------------------------------------------------------
318 *
319 * DBWBoxHandler --
320 *
321 * This procedure is called to handle button actions in layout
322 * windows when the "box" handler is active. It adjusts the box
323 * position and size.
324 *
325 * Results:
326 * None.
327 *
328 * Side effects:
329 * Left button: used to move the whole box by the lower-left corner.
330 * Right button: used to re-size the box by its upper-right corner.
331 * If one of the left or right buttons is pushed, then the
332 * other is pushed, the corner is switched to the nearest
333 * one to the cursor. This corner is remembered for use
334 * in box positioning/sizing when both buttons have gone up.
335 * Middle button: used to paint whatever layers are underneath the
336 * crosshair.
337 *
338 * ----------------------------------------------------------------------------
339 */
340
341 void
DBWBoxHandler(w,cmd)342 DBWBoxHandler(w, cmd)
343 MagWindow *w; /* Window containing cursor. */
344 TxCommand *cmd; /* Describes what happened. */
345 {
346 int button = cmd->tx_button;
347
348 if (button == TX_MIDDLE_BUTTON)
349 {
350 if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
351 CmdPaintEraseButton(w, &cmd->tx_p, TRUE);
352 return;
353 }
354
355 if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
356 {
357 if ((WindNewButtons & (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
358 == (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
359 {
360 /* Both buttons are now down. In this case, the FIRST
361 * button pressed determines whether we move or size,
362 * and the second button is just used as a signal to pick
363 * the closest corner.
364 */
365
366 buttonCorner = ToolGetCorner(&cmd->tx_p);
367 if (button == TX_LEFT_BUTTON) button = TX_RIGHT_BUTTON;
368 else button = TX_LEFT_BUTTON;
369 }
370 else if (button == TX_LEFT_BUTTON) buttonCorner = TOOL_BL;
371 else buttonCorner = TOOL_TR;
372 dbwButtonSetCursor(button, buttonCorner);
373 }
374 else
375 {
376 /* A button has just come up. If both buttons are down and one
377 * is released, we just change the cursor to reflect the current
378 * corner and the remaining button (i.e. move or size box).
379 */
380
381 if (WindNewButtons != 0)
382 {
383 if (button == TX_LEFT_BUTTON)
384 dbwButtonSetCursor(TX_RIGHT_BUTTON, buttonCorner);
385 else dbwButtonSetCursor(TX_LEFT_BUTTON, buttonCorner);
386 return;
387 }
388
389 /* The last button has been released. Reset the cursor to normal
390 * form and then move or size the box.
391 */
392
393 GrSetCursor(STYLE_CURS_NORMAL);
394 switch (button)
395 {
396 case TX_LEFT_BUTTON:
397 ToolMoveBox(buttonCorner, &cmd->tx_p, TRUE, (CellDef *) NULL);
398 break;
399 case TX_RIGHT_BUTTON:
400 ToolMoveCorner(buttonCorner, &cmd->tx_p, TRUE,
401 (CellDef *) NULL);
402 }
403 }
404 }
405