|
|
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.