]> git.zerfleddert.de Git - micropolis/blob - src/tk/library/demos/tkSquare.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[micropolis] / src / tk / library / demos / tkSquare.c
1 /*
2 * tkSquare.c --
3 *
4 * This module implements "square" widgets. A "square" is
5 * a widget that displays a single square that can be moved
6 * around and resized. This file is intended as an example
7 * of how to build a widget.
8 *
9 * Copyright 1991-1992 Regents of the University of California.
10 * Permission to use, copy, modify, and distribute this
11 * software and its documentation for any purpose and without
12 * fee is hereby granted, provided that the above copyright
13 * notice appear in all copies. The University of California
14 * makes no representations about the suitability of this
15 * software for any purpose. It is provided "as is" without
16 * express or implied warranty.
17 */
18
19 #ifndef lint
20 static char rcsid[] = "$Header: /user6/ouster/wish/scripts/demos/RCS/tkSquare.c,v 1.2 92/04/29 11:45:17 ouster Exp $ SPRITE (Berkeley)";
21 #endif
22
23 #include "tkConfig.h"
24 #include "tk.h"
25
26 /*
27 * A data structure of the following type is kept for each square
28 * widget managed by this file:
29 */
30
31 typedef struct {
32 Tk_Window tkwin; /* Window that embodies the square. NULL
33 * means that the window has been destroyed
34 * but the data structures haven't yet been
35 * cleaned up.*/
36 Tcl_Interp *interp; /* Interpreter associated with widget. */
37 int x, y; /* Position of square's upper-left corner
38 * within widget. */
39 int size; /* Width and height of square. */
40 int flags; /* Various flags; see below for
41 * definitions. */
42
43 /*
44 * Information used when displaying widget:
45 */
46
47 int borderWidth; /* Width of 3-D border around whole widget. */
48 Tk_3DBorder bgBorder; /* Used for drawing background. */
49 Tk_3DBorder fgBorder; /* For drawing square. */
50 int relief; /* Indicates whether window as a whole is
51 * raised, sunken, or flat. */
52 int doubleBuffer; /* Non-zero means double-buffer redisplay
53 * with pixmap; zero means draw straight
54 * onto the display. */
55 } Square;
56
57 /*
58 * Flag bits for squares:
59 *
60 * REDRAW_PENDING - 1 means redraw has already been scheduled.
61 */
62
63 #define REDRAW_PENDING 1
64
65 /*
66 * Information used for argv parsing.
67 */
68
69 static Tk_ConfigSpec configSpecs[] = {
70 {TK_CONFIG_BORDER, "-background", "background", "Background",
71 "#cdb79e", Tk_Offset(Square, bgBorder), TK_CONFIG_COLOR_ONLY},
72 {TK_CONFIG_BORDER, "-background", "background", "Background",
73 "white", Tk_Offset(Square, bgBorder), TK_CONFIG_MONO_ONLY},
74 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
75 (char *) NULL, 0, 0},
76 {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
77 (char *) NULL, 0, 0},
78 {TK_CONFIG_INT, "-borderwidth", "borderWidth", "BorderWidth",
79 "2", Tk_Offset(Square, borderWidth), 0},
80 {TK_CONFIG_INT, "-dbl", "doubleBuffer", "DoubleBuffer",
81 "1", Tk_Offset(Square, doubleBuffer), 0},
82 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
83 (char *) NULL, 0, 0},
84 {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
85 "#b03060", Tk_Offset(Square, fgBorder), TK_CONFIG_COLOR_ONLY},
86 {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
87 "black", Tk_Offset(Square, fgBorder), TK_CONFIG_MONO_ONLY},
88 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
89 "raised", Tk_Offset(Square, relief), 0},
90 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
91 (char *) NULL, 0, 0}
92 };
93
94 /*
95 * Forward declarations for procedures defined later in this file:
96 */
97
98 static int ConfigureSquare _ANSI_ARGS_((Tcl_Interp *interp,
99 Square *squarePtr, int argc, char **argv,
100 int flags));
101 static void DestroySquare _ANSI_ARGS_((ClientData clientData));
102 static void DisplaySquare _ANSI_ARGS_((ClientData clientData));
103 static void KeepInWindow _ANSI_ARGS_((Square *squarePtr));
104 static void SquareEventProc _ANSI_ARGS_((ClientData clientData,
105 XEvent *eventPtr));
106 static int SquareWidgetCmd _ANSI_ARGS_((ClientData clientData,
107 Tcl_Interp *, int argc, char **argv));
108 \f
109 /*
110 *--------------------------------------------------------------
111 *
112 * Tk_SquareCmd --
113 *
114 * This procedure is invoked to process the "square" Tcl
115 * command. It creates a new "square" widget.
116 *
117 * Results:
118 * A standard Tcl result.
119 *
120 * Side effects:
121 * A new widget is created and configured.
122 *
123 *--------------------------------------------------------------
124 */
125
126 int
127 Tk_SquareCmd(clientData, interp, argc, argv)
128 ClientData clientData; /* Main window associated with
129 * interpreter. */
130 Tcl_Interp *interp; /* Current interpreter. */
131 int argc; /* Number of arguments. */
132 char **argv; /* Argument strings. */
133 {
134 Tk_Window main = (Tk_Window) clientData;
135 register Square *squarePtr;
136 Tk_Window tkwin;
137
138 if (argc < 2) {
139 Tcl_AppendResult(interp, "wrong # args: should be \"",
140 argv[0], " pathName ?options?\"", (char *) NULL);
141 return TCL_ERROR;
142 }
143
144 tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL);
145 if (tkwin == NULL) {
146 return TCL_ERROR;
147 }
148
149 /*
150 * Initialize fields that won't be initialized by ConfigureSquare,
151 * or which ConfigureSquare expects to have reasonable values
152 * (e.g. resource pointers).
153 */
154
155 squarePtr = (Square *) ckalloc(sizeof(Square));
156 squarePtr->tkwin = tkwin;
157 squarePtr->interp = interp;
158 squarePtr->x = 0;
159 squarePtr->y = 0;
160 squarePtr->size = 20;
161 squarePtr->bgBorder = NULL;
162 squarePtr->fgBorder = NULL;
163 squarePtr->flags = 0;
164
165 Tk_SetClass(squarePtr->tkwin, "Square");
166 Tk_CreateEventHandler(squarePtr->tkwin, ExposureMask|StructureNotifyMask,
167 SquareEventProc, (ClientData) squarePtr);
168 Tcl_CreateCommand(interp, Tk_PathName(squarePtr->tkwin), SquareWidgetCmd,
169 (ClientData) squarePtr, (void (*)()) NULL);
170 if (ConfigureSquare(interp, squarePtr, argc-2, argv+2, 0) != TCL_OK) {
171 Tk_DestroyWindow(squarePtr->tkwin);
172 return TCL_ERROR;
173 }
174
175 interp->result = Tk_PathName(squarePtr->tkwin);
176 return TCL_OK;
177 }
178 \f
179 /*
180 *----------------------------------------------------------------------
181 *
182 * ConfigureSquare --
183 *
184 * This procedure is called to process an argv/argc list in
185 * conjunction with the Tk option database to configure (or
186 * reconfigure) a square widget.
187 *
188 * Results:
189 * The return value is a standard Tcl result. If TCL_ERROR is
190 * returned, then interp->result contains an error message.
191 *
192 * Side effects:
193 * Configuration information, such as colors, border width,
194 * etc. get set for squarePtr; old resources get freed,
195 * if there were any.
196 *
197 *----------------------------------------------------------------------
198 */
199
200 static int
201 ConfigureSquare(interp, squarePtr, argc, argv, flags)
202 Tcl_Interp *interp; /* Used for error reporting. */
203 register Square *squarePtr; /* Information about widget. */
204 int argc; /* Number of valid entries in argv. */
205 char **argv; /* Arguments. */
206 int flags; /* Flags to pass to
207 * Tk_ConfigureWidget. */
208 {
209 if (Tk_ConfigureWidget(interp, squarePtr->tkwin, configSpecs,
210 argc, argv, (char *) squarePtr, flags) != TCL_OK) {
211 return TCL_ERROR;
212 }
213
214 /*
215 * A few options need special processing, such as setting the
216 * background from a 3-D border.
217 */
218
219 Tk_SetBackgroundFromBorder(squarePtr->tkwin, squarePtr->bgBorder);
220
221 /*
222 * Register the desired geometry for the window. Then arrange for
223 * the window to be redisplayed.
224 */
225
226 Tk_GeometryRequest(squarePtr->tkwin, 200, 150);
227 Tk_SetInternalBorder(squarePtr->tkwin, squarePtr->borderWidth);
228 if (!(squarePtr->flags & REDRAW_PENDING)) {
229 Tk_DoWhenIdle(DisplaySquare, (ClientData) squarePtr);
230 squarePtr->flags |= REDRAW_PENDING;
231 }
232 return TCL_OK;
233 }
234 \f
235 /*
236 *--------------------------------------------------------------
237 *
238 * DisplaySquare --
239 *
240 * This procedure redraws the contents of a square window.
241 * It is invoked as a do-when-idle handler, so it only runs
242 * when there's nothing else for the application to do.
243 *
244 * Results:
245 * None.
246 *
247 * Side effects:
248 * Information appears on the screen.
249 *
250 *--------------------------------------------------------------
251 */
252
253 static void
254 DisplaySquare(clientData)
255 ClientData clientData; /* Information about window. */
256 {
257 register Square *squarePtr = (Square *) clientData;
258 register Tk_Window tkwin = squarePtr->tkwin;
259 Pixmap pm = None;
260 Drawable d;
261
262 squarePtr->flags &= ~REDRAW_PENDING;
263 if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) {
264 return;
265 }
266
267 /*
268 * Create a pixmap for double-buffering, if necessary.
269 */
270
271 if (squarePtr->doubleBuffer) {
272 pm = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
273 Tk_Width(tkwin), Tk_Height(tkwin),
274 DefaultDepthOfScreen(Tk_Screen(tkwin)));
275 d = pm;
276 } else {
277 d = Tk_WindowId(tkwin);
278 }
279
280 /*
281 * Redraw the widget's background and border.
282 */
283
284 Tk_Fill3DRectangle(Tk_Display(tkwin), d, squarePtr->bgBorder,
285 0, 0, Tk_Width(tkwin), Tk_Height(tkwin),
286 squarePtr->borderWidth, squarePtr->relief);
287
288 /*
289 * Display the square.
290 */
291
292 Tk_Fill3DRectangle(Tk_Display(tkwin), d, squarePtr->fgBorder,
293 squarePtr->x, squarePtr->y, squarePtr->size, squarePtr->size,
294 squarePtr->borderWidth, TK_RELIEF_RAISED);
295
296 /*
297 * If double-buffered, copy to the screen and release the pixmap.
298 */
299
300 if (squarePtr->doubleBuffer) {
301 XCopyArea(Tk_Display(tkwin), pm, Tk_WindowId(tkwin),
302 DefaultGCOfScreen(Tk_Screen(tkwin)), 0, 0,
303 Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
304 XFreePixmap(Tk_Display(tkwin), pm);
305 }
306 }
307 \f
308 /*
309 *--------------------------------------------------------------
310 *
311 * SquareWidgetCmd --
312 *
313 * This procedure is invoked to process the Tcl command
314 * that corresponds to a widget managed by this module.
315 * See the user documentation for details on what it does.
316 *
317 * Results:
318 * A standard Tcl result.
319 *
320 * Side effects:
321 * See the user documentation.
322 *
323 *--------------------------------------------------------------
324 */
325
326 static int
327 SquareWidgetCmd(clientData, interp, argc, argv)
328 ClientData clientData; /* Information about square widget. */
329 Tcl_Interp *interp; /* Current interpreter. */
330 int argc; /* Number of arguments. */
331 char **argv; /* Argument strings. */
332 {
333 register Square *squarePtr = (Square *) clientData;
334 int result = TCL_OK;
335 int length;
336 char c;
337
338 if (argc < 2) {
339 Tcl_AppendResult(interp, "wrong # args: should be \"",
340 argv[0], " option ?arg arg ...?\"", (char *) NULL);
341 return TCL_ERROR;
342 }
343 Tk_Preserve((ClientData) squarePtr);
344 c = argv[1][0];
345 length = strlen(argv[1]);
346 if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
347 if (argc == 2) {
348 result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs,
349 (char *) squarePtr, (char *) NULL, 0);
350 } else if (argc == 3) {
351 result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs,
352 (char *) squarePtr, argv[2], 0);
353 } else {
354 result = ConfigureSquare(interp, squarePtr, argc-2, argv+2,
355 TK_CONFIG_ARGV_ONLY);
356 }
357 } else if ((c == 'p') && (strncmp(argv[1], "position", length) == 0)) {
358 if ((argc != 2) && (argc != 4)) {
359 Tcl_AppendResult(interp, "wrong # args: should be \"",
360 argv[0], " position ?x y?\"", (char *) NULL);
361 goto error;
362 }
363 if (argc == 4) {
364 if ((Tcl_GetInt(interp, argv[2], &squarePtr->x) != TCL_OK)
365 || (Tcl_GetInt(interp, argv[3], &squarePtr->y) != TCL_OK)) {
366 goto error;
367 }
368 KeepInWindow(squarePtr);
369 }
370 sprintf(interp->result, "%d %d", squarePtr->x, squarePtr->y);
371 } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)) {
372 if ((argc != 2) && (argc != 3)) {
373 Tcl_AppendResult(interp, "wrong # args: should be \"",
374 argv[0], " size ?amount?\"", (char *) NULL);
375 goto error;
376 }
377 if (argc == 3) {
378 int i;
379
380 if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) {
381 goto error;
382 }
383 if ((i <= 0) || (i > 100)) {
384 Tcl_AppendResult(interp, "bad size \"", argv[2],
385 "\"", (char *) NULL);
386 goto error;
387 }
388 squarePtr->size = i;
389 KeepInWindow(squarePtr);
390 }
391 sprintf(interp->result, "%d", squarePtr->size);
392 } else {
393 Tcl_AppendResult(interp, "bad option \"", argv[1],
394 "\": must be configure, position, or size", (char *) NULL);
395 goto error;
396 }
397 if (!(squarePtr->flags & REDRAW_PENDING)) {
398 Tk_DoWhenIdle(DisplaySquare, (ClientData) squarePtr);
399 squarePtr->flags |= REDRAW_PENDING;
400 }
401 Tk_Release((ClientData) squarePtr);
402 return result;
403
404 error:
405 Tk_Release((ClientData) squarePtr);
406 return TCL_ERROR;
407 }
408 \f
409 /*
410 *--------------------------------------------------------------
411 *
412 * SquareEventProc --
413 *
414 * This procedure is invoked by the Tk dispatcher for various
415 * events on squares.
416 *
417 * Results:
418 * None.
419 *
420 * Side effects:
421 * When the window gets deleted, internal structures get
422 * cleaned up. When it gets exposed, it is redisplayed.
423 *
424 *--------------------------------------------------------------
425 */
426
427 static void
428 SquareEventProc(clientData, eventPtr)
429 ClientData clientData; /* Information about window. */
430 XEvent *eventPtr; /* Information about event. */
431 {
432 Square *squarePtr = (Square *) clientData;
433
434 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
435 if (!(squarePtr->flags & REDRAW_PENDING)) {
436 Tk_DoWhenIdle(DisplaySquare, (ClientData) squarePtr);
437 squarePtr->flags |= REDRAW_PENDING;
438 }
439 } else if (eventPtr->type == ConfigureNotify) {
440 KeepInWindow(squarePtr);
441 if (!(squarePtr->flags & REDRAW_PENDING)) {
442 Tk_DoWhenIdle(DisplaySquare, (ClientData) squarePtr);
443 squarePtr->flags |= REDRAW_PENDING;
444 }
445 } else if (eventPtr->type == DestroyNotify) {
446 Tcl_DeleteCommand(squarePtr->interp, Tk_PathName(squarePtr->tkwin));
447 squarePtr->tkwin = NULL;
448 if (squarePtr->flags & REDRAW_PENDING) {
449 Tk_CancelIdleCall(DisplaySquare, (ClientData) squarePtr);
450 }
451 Tk_EventuallyFree((ClientData) squarePtr, DestroySquare);
452 }
453 }
454 \f
455 /*
456 *----------------------------------------------------------------------
457 *
458 * DestroySquare --
459 *
460 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
461 * to clean up the internal structure of a square at a safe time
462 * (when no-one is using it anymore).
463 *
464 * Results:
465 * None.
466 *
467 * Side effects:
468 * Everything associated with the square is freed up.
469 *
470 *----------------------------------------------------------------------
471 */
472
473 static void
474 DestroySquare(clientData)
475 ClientData clientData; /* Info about square widget. */
476 {
477 register Square *squarePtr = (Square *) clientData;
478
479 if (squarePtr->bgBorder != NULL) {
480 Tk_Free3DBorder(squarePtr->bgBorder);
481 }
482 if (squarePtr->fgBorder != NULL) {
483 Tk_Free3DBorder(squarePtr->fgBorder);
484 }
485 ckfree((char *) squarePtr);
486 }
487 \f
488 /*
489 *----------------------------------------------------------------------
490 *
491 * KeepInWindow --
492 *
493 * Adjust the position of the square if necessary to keep it in
494 * the widget's window.
495 *
496 * Results:
497 * None.
498 *
499 * Side effects:
500 * The x and y position of the square are adjusted if necessary
501 * to keep the square in the window.
502 *
503 *----------------------------------------------------------------------
504 */
505
506 static void
507 KeepInWindow(squarePtr)
508 register Square *squarePtr; /* Pointer to widget record. */
509 {
510 int i, bd;
511
512 if (squarePtr->relief == TK_RELIEF_FLAT) {
513 bd = 0;
514 } else {
515 bd = squarePtr->borderWidth;
516 }
517 i = (Tk_Width(squarePtr->tkwin) - bd) - (squarePtr->x + squarePtr->size);
518 if (i < 0) {
519 squarePtr->x += i;
520 }
521 i = (Tk_Height(squarePtr->tkwin) - bd) - (squarePtr->y + squarePtr->size);
522 if (i < 0) {
523 squarePtr->y += i;
524 }
525 if (squarePtr->x < bd) {
526 squarePtr->x = bd;
527 }
528 if (squarePtr->y < bd) {
529 squarePtr->y = bd;
530 }
531 }
Impressum, Datenschutz