|
|
1.1 root 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:
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:
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:
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:
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:
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:
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:
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.