diff options
Diffstat (limited to 'tix/generic/tixImgCmp.c')
-rw-r--r-- | tix/generic/tixImgCmp.c | 1456 |
1 files changed, 1456 insertions, 0 deletions
diff --git a/tix/generic/tixImgCmp.c b/tix/generic/tixImgCmp.c new file mode 100644 index 00000000000..c87b99ec6c8 --- /dev/null +++ b/tix/generic/tixImgCmp.c @@ -0,0 +1,1456 @@ +/* + * tkImgCmp.c -- + * + * This procedure implements images of type "compound" for Tix. + * + * Copyright (c) 1996, Expert Interface Technologies + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include <tixPort.h> +#include <tixInt.h> +#include <tixDef.h> + +/* + * ToDo: + * - lineconfig and itemconfig command + */ + +/* + * The following data structure represents the master for a bitmap + * image: + */ +typedef struct CmpMaster { + Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means + * the image is being deleted. */ + Tcl_Interp *interp; /* Interpreter for application that is + * using image. */ + Tcl_Command imageCmd; /* Token for image command (used to delete + * it when the image goes away). NULL means + * the image command has already been + * deleted. */ + Display * display; /* Display of the the window associated with + * this image. We need to keep it + * because Tk_Display(CmpMaster.tkwin) may + * be invalid. */ + Tk_Window tkwin; /* default options are taken from this window. + * If undefined, will use the main window + * of this application */ + int width, height; /* Dimensions of image. */ + int padX, padY; + struct CmpLine * lineHead; + struct CmpLine * lineTail; + + /* Thde default options, etc */ + int borderWidth; /* Width of 3-D borders. */ + Tk_3DBorder background; /* Used for drawing background. */ + int relief; /* Indicates whether window as a whole is + * raised, sunken, or flat. */ + + TixFont font; /* Information about text font.*/ + XColor *foreground; /* Color for drawing text and bitmaps */ + GC gc; /* default GC for drawing text. */ + + int showBackground; /* whether the background should be drawn */ + unsigned int changing; /* is this image going to call Tk_ImageChanged + * in an idle event? */ + unsigned int isDeleted; +} CmpMaster; + +#define TYPE_TEXT 0 +#define TYPE_SPACE 1 +#define TYPE_IMAGE 2 +#define TYPE_BITMAP 3 +#define TYPE_WIDGET 4 + +typedef struct CmpLine { + struct CmpMaster *masterPtr; + struct CmpLine * next; + struct CmpItem * itemHead; + struct CmpItem * itemTail; + int padX, padY; + Tk_Anchor anchor; + int width, height; /* Dimensions of this line. */ + +} CmpLine; + +/* abstract type */ + +#define COMMON_MEMBERS \ + struct CmpLine * line; \ + struct CmpItem * next; \ + Tk_Anchor anchor; \ + char type; \ + int width; \ + int height; \ + int padX, padY + +typedef struct CmpItem { + COMMON_MEMBERS; +} CmpItem; + +typedef struct CmpBitmapItem { + COMMON_MEMBERS; + + Pixmap bitmap; + XColor *foreground; + XColor *background; + GC gc; /* GC for drawing the bitmap. */ +} CmpBitmapItem; + +typedef struct CmpImageItem { + COMMON_MEMBERS; + + Tk_Image image; + char * imageString; +} CmpImageItem; + +typedef struct CmpSpaceItem { + COMMON_MEMBERS; + +} CmpSpaceItem; + +typedef struct CmpTextItem { + COMMON_MEMBERS; + + char * text; + int numChars; + Tk_Justify justify; /* Justification to use for multi-line text. */ + int wrapLength; + int underline; /* Index of character to underline. < 0 means + * don't underline anything. */ + XColor *foreground; + TixFont font; /* Information about text font, or NULL. */ + GC gc; /* GC for drawing the bitmap. */ +} CmpTextItem; + +typedef union CmpItemPtr { + CmpItem * item; + CmpBitmapItem * bitmap; + CmpImageItem * image; + CmpSpaceItem * space; + CmpTextItem * text; +} CmpItemPtr; + +/* + * The type record for bitmap images: + */ +static int ImgCmpCreate _ANSI_ARGS_((Tcl_Interp *interp, + char *name, int objc, Tcl_Obj *CONST *objv, + Tk_ImageType *typePtr, Tk_ImageMaster master, + ClientData *clientDataPtr)); +static ClientData ImgCmpGet _ANSI_ARGS_((Tk_Window tkwin, + ClientData clientData)); +static void ImgCmpDisplay _ANSI_ARGS_((ClientData clientData, + Display *display, Drawable drawable, + int imageX, int imageY, int width, int height, + int drawableX, int drawableY)); +static void ImgCmpFree _ANSI_ARGS_((ClientData clientData, + Display *display)); +static void ImgCmpDelete _ANSI_ARGS_((ClientData clientData)); + +Tk_ImageType tixCompoundImageType = { + "compound", /* name */ + ImgCmpCreate, /* createProc */ + ImgCmpGet, /* getProc */ + ImgCmpDisplay, /* displayProc */ + ImgCmpFree, /* freeProc */ + ImgCmpDelete, /* deleteProc */ + (Tk_ImageType *) NULL /* nextPtr */ +}; + +static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_BORDER, "-background", "background", "Background", + DEF_CMPIMAGE_BG_COLOR, Tk_Offset(CmpMaster, background), + TK_CONFIG_COLOR_ONLY}, + + {TK_CONFIG_BORDER, "-background", "background", "Background", + DEF_CMPIMAGE_BG_MONO, Tk_Offset(CmpMaster, background), + TK_CONFIG_MONO_ONLY}, + + {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", (char *) NULL, + "0", Tk_Offset(CmpMaster, borderWidth), 0}, + + {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_FONT, "-font", "font", "Font", + DEF_CMPIMAGE_FONT, Tk_Offset(CmpMaster, font), 0}, + + {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", + DEF_CMPIMAGE_FG_COLOR, Tk_Offset(CmpMaster, foreground), + TK_CONFIG_COLOR_ONLY}, + + {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", + DEF_CMPIMAGE_FG_MONO, Tk_Offset(CmpMaster, foreground), + TK_CONFIG_MONO_ONLY}, + + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpMaster, padX), 0}, + + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpMaster, padY), 0}, + + {TK_CONFIG_RELIEF, "-relief", (char *) NULL, (char *) NULL, + "flat", Tk_Offset(CmpMaster, relief), 0}, + + {TK_CONFIG_BOOLEAN, "-showbackground", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpMaster, showBackground), 0}, + + {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(CmpMaster, tkwin), TK_CONFIG_NULL_OK}, + + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +static Tk_ConfigSpec lineConfigSpecs[] = { + {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, + "c", Tk_Offset(CmpLine, anchor), 0}, + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpLine, padX), 0}, + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpLine, padY), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +static Tk_ConfigSpec bitmapConfigSpecs[] = { + {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, + "c", Tk_Offset(CmpBitmapItem, anchor), 0}, + + {TK_CONFIG_COLOR, "-background", "background", "Background", + "", Tk_Offset(CmpBitmapItem, background), + TK_CONFIG_NULL_OK}, + + {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, + "", Tk_Offset(CmpBitmapItem, bitmap), TK_CONFIG_NULL_OK}, + + {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", + "", Tk_Offset(CmpBitmapItem, foreground), + TK_CONFIG_NULL_OK}, + + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpBitmapItem, padX), 0}, + + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpBitmapItem, padY), 0}, + + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +static Tk_ConfigSpec imageConfigSpecs[] = { + {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, + "c", Tk_Offset(CmpImageItem, anchor), 0}, + {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(CmpImageItem, imageString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpImageItem, padX), 0}, + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpImageItem, padY), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +static Tk_ConfigSpec spaceConfigSpecs[] = { + {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpSpaceItem, height), 0}, + {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpSpaceItem, width), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +static Tk_ConfigSpec textConfigSpecs[] = { + {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, + "c", Tk_Offset(CmpTextItem, anchor), 0}, + + {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, 0}, + + {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, + "", Tk_Offset(CmpTextItem, font), TK_CONFIG_NULL_OK}, + + {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", + "", Tk_Offset(CmpTextItem, foreground), + TK_CONFIG_NULL_OK}, + + {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, + "left", Tk_Offset(CmpTextItem, justify), 0}, + + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpTextItem, padX), 0}, + + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpTextItem, padY), 0}, + + {TK_CONFIG_STRING, "-text", (char *) NULL, (char *) NULL, + "", Tk_Offset(CmpTextItem, text), TK_CONFIG_NULL_OK}, + + {TK_CONFIG_INT, "-underline", (char *) NULL, (char *) NULL, + "-1", Tk_Offset(CmpTextItem, underline), 0}, + + {TK_CONFIG_PIXELS, "-wraplength", (char *) NULL, (char *) NULL, + "0", Tk_Offset(CmpTextItem, wrapLength), 0}, + + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +/* + * Prototypes for procedures used only locally in this file: + */ + +static int ImgCmpCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +static void ImgCmpCmdDeletedProc _ANSI_ARGS_(( + ClientData clientData)); +static int ImgCmpConfigureMaster _ANSI_ARGS_(( + CmpMaster *masterPtr, int argc, char **argv, + int flags)); +CmpBitmapItem * AddNewBitmap _ANSI_ARGS_((CmpMaster *masterPtr, + CmpLine *line, + int argc, char **argv)); +CmpImageItem * AddNewImage _ANSI_ARGS_((CmpMaster *masterPtr, + CmpLine *line, + int argc, char **argv)); +CmpSpaceItem * AddNewSpace _ANSI_ARGS_((CmpMaster *masterPtr, + CmpLine *line, + int argc, char **argv)); +CmpTextItem * AddNewText _ANSI_ARGS_((CmpMaster *masterPtr, + CmpLine *line, + int argc, char **argv)); +CmpLine* AddNewLine _ANSI_ARGS_((CmpMaster *masterPtr, + int argc, char **argv)); +static void CalculateMasterSize _ANSI_ARGS_(( + ClientData clientData)); +static void ChangeImageWhenIdle _ANSI_ARGS_(( + CmpMaster *masterPtr)); +static void ImageProc _ANSI_ARGS_((ClientData clientData, + int x, int y, int width, int height, + int imgWidth, int imgHeight)); +static void FreeLine _ANSI_ARGS_((CmpLine * lPtr)); +static void FreeItem _ANSI_ARGS_((CmpItemPtr p)); +static void CmpEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); + +/* + *---------------------------------------------------------------------- + * + * ImgCmpCreate -- + * + * This procedure is called by the Tk image code to create "test" + * images. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * The data structure for a new image is allocated. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +ImgCmpCreate(interp, name, objc, objv, typePtr, master, clientDataPtr) + Tcl_Interp *interp; /* Interpreter for application containing + * image. */ + char *name; /* Name to use for image. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST *objv; /* Arguments for options (doesn't + * include image name or type). */ + Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ + Tk_ImageMaster master; /* Token for image, to be used by us in + * later callbacks. */ + ClientData *clientDataPtr; /* Store manager's token for image here; + * it will be returned in later callbacks. */ +{ + CmpMaster *masterPtr; + char **argv; + int i, length; + + argv = (char **) Tcl_Alloc((objc + 1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + argv[i] = Tcl_GetStringFromObj(objv[i], &length); + } + argv[objc] = NULL; + + masterPtr = (CmpMaster *) ckalloc(sizeof(CmpMaster)); + masterPtr->tkMaster = master; + masterPtr->interp = interp; + masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgCmpCmd, + (ClientData)masterPtr, ImgCmpCmdDeletedProc); + masterPtr->tkwin = NULL; + masterPtr->display = NULL; + masterPtr->width = 0; + masterPtr->height = 0; + masterPtr->padX = 0; + masterPtr->padY = 0; + masterPtr->lineHead = NULL; + masterPtr->lineTail = NULL; + masterPtr->borderWidth = 0; + masterPtr->background = NULL; + masterPtr->relief = 0; + masterPtr->font = NULL; + masterPtr->foreground = NULL; + masterPtr->gc = None; + masterPtr->showBackground = 0; + masterPtr->changing = 0; + masterPtr->isDeleted = 0; + + if (ImgCmpConfigureMaster(masterPtr, objc, argv, 0) != TCL_OK) { + ImgCmpDelete((ClientData) masterPtr); + Tcl_Free((char *) argv); + return TCL_ERROR; + } + *clientDataPtr = (ClientData) masterPtr; + Tcl_Free((char *) argv); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpConfigureMaster -- + * + * This procedure is called when a bitmap image is created or + * reconfigured. It process configuration options and resets + * any instances of the image. + * + * Results: + * A standard Tcl return value. If TCL_ERROR is returned then + * an error message is left in masterPtr->interp->result. + * + * Side effects: + * Existing instances of the image will be redisplayed to match + * the new configuration options. + * + *---------------------------------------------------------------------- + */ +static int +ImgCmpConfigureMaster(masterPtr, argc, argv, flags) + CmpMaster *masterPtr; /* Pointer to data structure describing + * overall bitmap image to (reconfigure). */ + int argc; /* Number of entries in argv. */ + char **argv; /* Pairs of configuration options for image. */ + int flags; /* Flags to pass to Tk_ConfigureWidget, + * such as TK_CONFIG_ARGV_ONLY. */ +{ + XGCValues gcValues; + GC newGC; + int i; + + if (argc %2) { + Tcl_AppendResult(masterPtr->interp, "value missing for option \"", + argv[argc-1], "\"", NULL); + return TCL_ERROR; + } + for (i=0; i<argc; i+=2) { + size_t length = strlen(argv[i]); + if (strncmp(argv[i], "-window", length) == 0) { + masterPtr->tkwin = Tk_NameToWindow(masterPtr->interp, argv[i+1], + Tk_MainWindow(masterPtr->interp)); + if (masterPtr->tkwin == NULL) { + return TCL_ERROR; + } + } + } + if (masterPtr->tkwin == NULL) { + Tcl_AppendResult(masterPtr->interp, + "no value given for -window option.", NULL); + return TCL_ERROR; + } + masterPtr->display = Tk_Display(masterPtr->tkwin); + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + configSpecs, argc, argv, (char *) masterPtr, flags) != TCL_OK) { + return TCL_ERROR; + } + + Tk_CreateEventHandler(masterPtr->tkwin, + StructureNotifyMask, CmpEventProc, (ClientData)masterPtr); + /* + * Get the default GC for text and bitmaps + */ + gcValues.foreground = masterPtr->foreground->pixel; + gcValues.background = Tk_3DBorderColor(masterPtr->background)->pixel; + gcValues.font = TixFontId(masterPtr->font); + gcValues.graphics_exposures = False; + newGC = Tk_GetGC(masterPtr->tkwin, + GCBackground|GCForeground|GCFont|GCGraphicsExposures, + &gcValues); + if (masterPtr->gc != None) { + Tk_FreeGC(Tk_Display(masterPtr->tkwin), masterPtr->gc); + } + masterPtr->gc = newGC; + + ChangeImageWhenIdle(masterPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ImgCmpCmd -- + * + * This procedure is invoked to process the Tcl command + * that corresponds to an image managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +static int +ImgCmpCmd(clientData, interp, argc, argv) + ClientData clientData; /* Information about button widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpMaster *masterPtr = (CmpMaster *) clientData; + int c, code; + size_t length; + + if (argc < 2) { + sprintf(interp->result, + "wrong # args: should be \"%.50s option ?arg arg ...?\"", + argv[0]); + return TCL_ERROR; + } + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)) { + if (argc < 3) { + return Tix_ArgcError(interp, argc, argv, 2, + "type ?option value? ..."); + } + c = argv[2][0]; + length = strlen(argv[2]); + + if ((c == 'l') && (strncmp(argv[2], "line", length) == 0)) { + CmpLine * newLine; + + newLine = AddNewLine(masterPtr, argc-3, argv+3); + if (newLine == NULL) { + return TCL_ERROR; + } + } + else { + CmpItemPtr p; + + if (masterPtr->lineTail == 0) { + if (AddNewLine(masterPtr, 0, 0) == NULL) { + return TCL_ERROR; + } + } + if ((c == 'b') && (strncmp(argv[2], "bitmap", length) == 0)) { + p.bitmap = AddNewBitmap(masterPtr, masterPtr->lineTail, + argc-3, argv+3); + if (p.bitmap == NULL) { + return TCL_ERROR; + } + } + else if ((c == 'i') && (strncmp(argv[2], "image", length) == 0)) { + p.image = AddNewImage(masterPtr, masterPtr->lineTail, + argc-3, argv+3); + if (p.image == NULL) { + return TCL_ERROR; + } + } + else if ((c == 's') && (strncmp(argv[2], "space", length) == 0)) { + p.space = AddNewSpace(masterPtr, masterPtr->lineTail, + argc-3, argv+3); + if (p.space == NULL) { + return TCL_ERROR; + } + } + else if ((c == 't') && (strncmp(argv[2], "text", length) == 0)) { + p.text = AddNewText(masterPtr, masterPtr->lineTail, + argc-3, argv+3); + if (p.text == NULL) { + return TCL_ERROR; + } + } + else { + Tcl_AppendResult(interp, "unknown option \"", + argv[2], "\", must be bitmap, image, line, ", + "space, text or widget", NULL); + return TCL_ERROR; + } + + /* append to the end of the line */ + if (masterPtr->lineTail->itemHead == NULL) { + masterPtr->lineTail->itemHead = p.item; + masterPtr->lineTail->itemTail = p.item; + } else { + masterPtr->lineTail->itemTail->next = p.item; + masterPtr->lineTail->itemTail = p.item; + } + } + ChangeImageWhenIdle(masterPtr); + return TCL_OK; + } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) + && (length >= 2)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " cget option\"", + (char *) NULL); + return TCL_ERROR; + } + return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, + (char *) masterPtr, argv[2], 0); + } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) + && (length >= 2)) { + if (argc == 2) { + code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), + configSpecs, (char *) masterPtr, (char *) NULL, 0); + } else if (argc == 3) { + code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), + configSpecs, (char *) masterPtr, argv[2], 0); + } else { + int i; + for (i=2; i<argc-2; i++) { + length = strlen(argv[i]); + if (strncmp(argv[i], "-window", length) == 0) { + Tcl_AppendResult(interp, "The -window option cannot ", + "be changed.", (char *) NULL); + return TCL_ERROR; + } + } + code = ImgCmpConfigureMaster(masterPtr, argc-2, argv+2, + TK_CONFIG_ARGV_ONLY); + } + return code; + } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length)== 0)) { + Tcl_AppendResult(interp, "unimplemented", NULL); + return TCL_ERROR; + } else if ((c == 'l') && (strncmp(argv[1], "lineconfigure", length)== 0)) { + Tcl_AppendResult(interp, "unimplemented", NULL); + return TCL_ERROR; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": must be cget or configure", (char *) NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/*---------------------------------------------------------------------- + * + * + *---------------------------------------------------------------------- + */ +CmpLine * +AddNewLine(masterPtr, argc, argv) + CmpMaster *masterPtr; + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpLine * lPtr = (CmpLine *)ckalloc(sizeof(CmpLine)); + + lPtr->masterPtr = masterPtr; + lPtr->next = NULL; + lPtr->itemHead = NULL; + lPtr->itemTail = NULL; + lPtr->padX = 0; + lPtr->padY = 0; + lPtr->width = 1; + lPtr->height = 1; + + lPtr->anchor = TK_ANCHOR_CENTER; + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + lineConfigSpecs, argc, argv, (char *) lPtr, + TK_CONFIG_ARGV_ONLY) != TCL_OK) { + FreeLine(lPtr); + return NULL; + } + + /* + * Append to the end of the master's lines + */ + if (masterPtr->lineHead == NULL) { + masterPtr->lineHead = masterPtr->lineTail = lPtr; + } else { + masterPtr->lineTail->next = lPtr; + masterPtr->lineTail = lPtr; + } + + return lPtr; +} + +/*---------------------------------------------------------------------- + * + * + *---------------------------------------------------------------------- + */ +CmpBitmapItem * +AddNewBitmap(masterPtr, line, argc, argv) + CmpMaster *masterPtr; + CmpLine *line; + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpItemPtr p; + XGCValues gcValues; + + p.bitmap = (CmpBitmapItem*) ckalloc(sizeof(CmpBitmapItem)); + p.bitmap->line = line; + p.bitmap->next = NULL; + p.bitmap->anchor = TK_ANCHOR_CENTER; + p.bitmap->type = TYPE_BITMAP; + p.bitmap->padX = 0; + p.bitmap->padY = 0; + p.bitmap->width = 0; + p.bitmap->height = 0; + + p.bitmap->bitmap = None; + p.bitmap->foreground = NULL; + p.bitmap->background = NULL; + p.bitmap->gc = None; + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + bitmapConfigSpecs, argc, argv, (char *) p.bitmap, + TK_CONFIG_ARGV_ONLY) != TCL_OK) { + goto error; + } + + /* Get the GC for the bitmap */ + if (p.bitmap->background) { + gcValues.background = p.bitmap->background->pixel; + } else { + gcValues.background = Tk_3DBorderColor(masterPtr->background)->pixel; + } + if (p.bitmap->foreground) { + gcValues.foreground = p.bitmap->foreground->pixel; + } else { + gcValues.foreground = masterPtr->foreground->pixel; + } + gcValues.graphics_exposures = False; + p.bitmap->gc = Tk_GetGC(masterPtr->tkwin, + GCBackground|GCForeground|GCGraphicsExposures, + &gcValues); + + return p.bitmap; + + error: + + FreeItem(p); + return NULL; +} + +/*---------------------------------------------------------------------- + * + * + *---------------------------------------------------------------------- + */ +CmpImageItem * +AddNewImage(masterPtr, line, argc, argv) + CmpMaster *masterPtr; + CmpLine *line; + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpItemPtr p; + + + p.image = (CmpImageItem*) ckalloc(sizeof(CmpImageItem)); + p.image->line = line; + p.image->next = NULL; + p.image->anchor = TK_ANCHOR_CENTER; + p.image->type = TYPE_IMAGE; + p.image->padX = 0; + p.image->padY = 0; + p.image->width = 0; + p.image->height = 0; + + p.image->imageString = NULL; + p.image->image = NULL; + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + imageConfigSpecs, argc, argv, (char *) p.image, + TK_CONFIG_ARGV_ONLY) != TCL_OK) { + goto error; + } + + /* Get the image */ + if (p.image->imageString != NULL) { + p.image->image = Tk_GetImage(masterPtr->interp, masterPtr->tkwin, + p.image->imageString, ImageProc, (ClientData)p.image); + if (p.image->image == NULL) { + goto error; + } + } + + return p.image; + + error: + + FreeItem(p); + return NULL; +} + +/*---------------------------------------------------------------------- + * + * + *---------------------------------------------------------------------- + */ +CmpSpaceItem * +AddNewSpace(masterPtr, line, argc, argv) + CmpMaster *masterPtr; + CmpLine *line; + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpItemPtr p; + + p.space = (CmpSpaceItem*) ckalloc(sizeof(CmpSpaceItem)); + p.space->line = line; + p.space->next = NULL; + p.space->anchor = TK_ANCHOR_CENTER; + p.space->type = TYPE_SPACE; + p.space->padX = 0; + p.space->padY = 0; + p.space->width = 0; + p.space->height = 0; + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + spaceConfigSpecs, argc, argv, (char *)p.space, + TK_CONFIG_ARGV_ONLY) != TCL_OK) { + goto error; + } + + return p.space; + + error: + + FreeItem(p); + return NULL; +} + +/*---------------------------------------------------------------------- + * + * + *---------------------------------------------------------------------- + */ +CmpTextItem * +AddNewText(masterPtr, line, argc, argv) + CmpMaster *masterPtr; + CmpLine *line; + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + CmpItemPtr p; + XGCValues gcValues; + + p.text = (CmpTextItem*) ckalloc(sizeof(CmpTextItem)); + p.text->line = line; + p.text->next = NULL; + p.text->anchor = TK_ANCHOR_CENTER; + p.text->type = TYPE_TEXT; + p.text->padX = 0; + p.text->padY = 0; + p.text->width = 0; + p.text->height = 0; + + p.text->text = NULL; + p.text->numChars = 0; + p.text->justify = TK_JUSTIFY_CENTER; + p.text->underline = -1; + p.text->wrapLength = 0; + + p.text->foreground = NULL; + p.text->font = NULL; + p.text->gc = None; + + if (Tk_ConfigureWidget(masterPtr->interp, masterPtr->tkwin, + textConfigSpecs, argc, argv, (char *) p.text, + TK_CONFIG_ARGV_ONLY) != TCL_OK) { + + goto error; + } + + /* Get the GC for the text */ + if (p.text->foreground) { + gcValues.foreground = p.text->foreground->pixel; + } else { + gcValues.foreground = masterPtr->foreground->pixel; + } + if (p.text->font) { + gcValues.font = TixFontId(p.text->font); + } else { + gcValues.font = TixFontId(masterPtr->font); + } + gcValues.graphics_exposures = False; + p.text->gc = Tk_GetGC(masterPtr->tkwin, + GCFont|GCForeground|GCGraphicsExposures, + &gcValues); + + return p.text; + + error: + + FreeItem(p); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpGet -- + * + * This procedure is called for each use of a bitmap image in a + * widget. + * + * Results: + * The return value is a token for the instance, which is passed + * back to us in calls to ImgCmpDisplay and ImgCmpFree. + * + * Side effects: + * A data structure is set up for the instance (or, an existing + * instance is re-used for the new one). + * + *---------------------------------------------------------------------- + */ +static ClientData +ImgCmpGet(tkwin, masterData) + Tk_Window tkwin; /* Window in which the instance will be + * used. */ + ClientData masterData; /* Pointer to our master structure for the + * image. */ +{ + CmpMaster *masterPtr = (CmpMaster *)masterData; + + if (tkwin == masterPtr->tkwin) { + return masterData; + } + + Tcl_AppendResult(masterPtr->interp, + "Image \"", + Tk_NameOfImage(masterPtr->tkMaster), + "\" can only be assigned to window \"", + Tk_PathName(masterPtr->tkwin), "\"", NULL); + Tcl_AddErrorInfo(masterPtr->interp, "\n (while configuring image \""); + Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); + Tcl_AddErrorInfo(masterPtr->interp, "\")"); + Tk_BackgroundError(masterPtr->interp); + + return NULL; +} + +static void +CalculateMasterSize(clientData) + ClientData clientData; +{ + CmpMaster *masterPtr = (CmpMaster *)clientData; + CmpLine *lPtr; + CmpItemPtr p; + + masterPtr->width = 0; + masterPtr->height = 0; + + for (lPtr = masterPtr->lineHead; lPtr; lPtr=lPtr->next) { + lPtr->width = 0; + lPtr->height = 0; + for (p.item = lPtr->itemHead; p.item; p.item=p.item->next) { + + switch (p.item->type) { + case TYPE_IMAGE: + Tk_SizeOfImage(p.image->image, + &p.image->width, &p.image->height); + break; + + case TYPE_SPACE: + /* Do nothing */ + break; + + case TYPE_TEXT: + { + TixFont font; + + if (p.text->text == NULL) { + break; + } + + if (p.text->font) { + font = p.text->font; + } else { + font = masterPtr->font; + } + + p.text->numChars = strlen(p.text->text); + TixComputeTextGeometry(font, p.text->text, + p.text->numChars, + p.text->wrapLength, + &p.text->width, &p.text->height); + } + break; + + case TYPE_BITMAP: + Tk_SizeOfBitmap(Tk_Display(masterPtr->tkwin), + p.bitmap->bitmap, &p.bitmap->width, + &p.bitmap->height); + break; + + case TYPE_WIDGET: + + + break; + } + p.item->width += 2*p.item->padX; + p.item->height += 2*p.item->padY; + + lPtr->width += p.item->width; + if (lPtr->height < p.item->height) { + lPtr->height = p.item->height; + } + } + lPtr->width += 2*lPtr->padX; + lPtr->height += 2*lPtr->padY; + + if (masterPtr->width < lPtr->width) { + masterPtr->width = lPtr->width; + } + masterPtr->height += lPtr->height; + } + masterPtr->width += 2*masterPtr->padX + 2*masterPtr->borderWidth; + masterPtr->height += 2*masterPtr->padY + 2*masterPtr->borderWidth; + + Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width, + masterPtr->height, masterPtr->width, masterPtr->height); + masterPtr->changing = 0; +} + +static void +ChangeImageWhenIdle(masterPtr) + CmpMaster *masterPtr; +{ + if (!masterPtr->changing) { + masterPtr->changing = 1; + Tk_DoWhenIdle(CalculateMasterSize, (ClientData)masterPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpDisplay -- + * + * This procedure is invoked to draw a bitmap image. + * + * Results: + * None. + * + * Side effects: + * A portion of the image gets rendered in a pixmap or window. + * + *---------------------------------------------------------------------- + */ +static void +ImgCmpDisplay(clientData, display, drawable, imageX, imageY, width, + height, drawableX, drawableY) + ClientData clientData; /* Pointer to CmpInstance structure for + * for instance to be displayed. */ + Display *display; /* Display on which to draw image. */ + Drawable drawable; /* Pixmap or window in which to draw image. */ + int imageX, imageY; /* Upper-left corner of region within image + * to draw. */ + int width, height; /* Dimensions of region within image to draw.*/ + int drawableX, drawableY; /* Coordinates within drawable that + * correspond to imageX and imageY. */ +{ + CmpMaster * masterPtr = (CmpMaster*)clientData; + CmpLine *lPtr; + CmpItemPtr p; + int dx, dy, extraX; + + if (masterPtr == NULL) { + /* attempting to draw into a invalid window (can only be drawn into + * the original window set by the -window option */ + return; + } + + if (masterPtr->showBackground) { + Tk_Fill3DRectangle(masterPtr->tkwin, drawable, + masterPtr->background, + drawableX + masterPtr->padX - imageX, + drawableY + masterPtr->padY - imageY, + masterPtr->width - 2*masterPtr->padX, + masterPtr->height - 2*masterPtr->padY, + masterPtr->borderWidth, masterPtr->relief); + } + + /* ToDo: Set the clipping region according to the imageX,Y, and + * width, height */ + dy = drawableY + masterPtr->padY + masterPtr->borderWidth - imageY; + + for (lPtr = masterPtr->lineHead; lPtr; lPtr=lPtr->next) { + dx = drawableX + masterPtr->padX - imageX; + dx += lPtr->padX; + dy += lPtr->padY; + + extraX = masterPtr->width - 2*masterPtr->padX - lPtr->width; + switch (lPtr->anchor) { + case TK_ANCHOR_SW: case TK_ANCHOR_W: case TK_ANCHOR_NW: + extraX = 0; + break; + case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: + extraX /= 2; + break; + case TK_ANCHOR_SE: case TK_ANCHOR_E: case TK_ANCHOR_NE: + break; + } + dx += extraX; + + for (p.item = lPtr->itemHead; p.item; p.item=p.item->next) { + int extraY; + dx += p.item->padX; + + extraY = lPtr->height - 2*lPtr->padY - p.item->height; + switch (p.item->anchor) { + case TK_ANCHOR_SW: case TK_ANCHOR_S: case TK_ANCHOR_SE: + break; + case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: + extraY /= 2; + break; + case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: + extraY = 0; + break; + } + + switch (p.item->type) { + case TYPE_IMAGE: + Tk_RedrawImage(p.image->image, 0, 0, + p.image->width - 2*p.item->padX, + p.image->height - 2*p.item->padY, + drawable, dx, dy+extraY); + break; + + case TYPE_SPACE: + /* Do nothing */ + break; + + case TYPE_TEXT: + { + TixFont font; + + if (p.text->text == NULL) { + break; + } + + if (p.text->font) { + font = p.text->font; + } else { + font = masterPtr->font; + } + + TixDisplayText(Tk_Display(masterPtr->tkwin), drawable, + font, p.text->text, p.text->numChars, + dx, dy+extraY, + p.text->width - 2*p.item->padX, + p.text->justify, + p.text->underline, + p.text->gc); + } + break; + + case TYPE_BITMAP: + XCopyPlane(Tk_Display(masterPtr->tkwin), p.bitmap->bitmap, + drawable, p.bitmap->gc, 0, 0, + p.bitmap->width - 2*p.item->padX, + p.bitmap->height - 2*p.item->padY, + dx, dy+extraY, 1); + + break; + + case TYPE_WIDGET: + + + break; + } + dx += p.item->width - p.item->padX; + } + dy += lPtr->height - lPtr->padY; + } +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpFree -- + * + * This procedure is called when a widget ceases to use a + * particular instance of an image. + * + * Results: + * None. + * + * Side effects: + * Internal data structures get cleaned up. + * + *---------------------------------------------------------------------- + */ + +static void +ImgCmpFree(clientData, display) + ClientData clientData; /* Pointer to CmpInstance structure for + * for instance to be displayed. */ + Display *display; /* Display containing window that used image.*/ +{ + /* + * Since one compound image can only be used in one window, when that + * window is deleted, this image is now useless and should be deleted as + * well + */ +} + +static void FreeLine(lPtr) + CmpLine * lPtr; +{ + Tk_FreeOptions(lineConfigSpecs, (char *)lPtr, + Tk_Display(lPtr->masterPtr->tkwin), 0); + ckfree((char *) lPtr); +} + +static void FreeItem(p) + CmpItemPtr p; +{ + switch (p.item->type) { + case TYPE_IMAGE: + if (p.image->image) { + Tk_FreeImage(p.image->image); + } + Tk_FreeOptions(imageConfigSpecs, (char *)p.image, + Tk_Display(p.item->line->masterPtr->tkwin), 0); + break; + + case TYPE_SPACE: + Tk_FreeOptions(spaceConfigSpecs, (char *)p.space, + Tk_Display(p.item->line->masterPtr->tkwin), 0); + break; + + case TYPE_TEXT: + if (p.text->gc != None) { + Tk_FreeGC(Tk_Display(p.text->line->masterPtr->tkwin), + p.text->gc); + } + Tk_FreeOptions(textConfigSpecs, (char *)p.text, + Tk_Display(p.item->line->masterPtr->tkwin), 0); + break; + + case TYPE_BITMAP: + if (p.bitmap->gc != None) { + Tk_FreeGC(Tk_Display(p.bitmap->line->masterPtr->tkwin), + p.bitmap->gc); + } + Tk_FreeOptions(bitmapConfigSpecs, (char *)p.bitmap, + Tk_Display(p.item->line->masterPtr->tkwin), 0); + break; + + case TYPE_WIDGET: + break; + } + ckfree((char *) p.item); +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpDelete -- + * + * This procedure is called by the image code to delete the + * master structure for an image. + * + * Results: + * None. + * + * Side effects: + * Resources associated with the image get freed. + * + *---------------------------------------------------------------------- + */ +static void +ImgCmpDelete(masterData) + ClientData masterData; /* Pointer to CmpMaster structure for + * image. Must not have any more instances. */ +{ + CmpMaster *masterPtr = (CmpMaster *) masterData; + CmpLine * lPtr; + CmpItemPtr p; + + if (masterPtr->tkwin == NULL) { + goto done; + } + + Tk_Preserve((ClientData) masterPtr); + + Tk_DeleteEventHandler(masterPtr->tkwin, + StructureNotifyMask, CmpEventProc, (ClientData)masterPtr); + + if (masterPtr->isDeleted) { + Tk_Release((ClientData) masterPtr); + return; + } + masterPtr->isDeleted = 1; + + for (lPtr=masterPtr->lineHead; lPtr;) { + CmpLine * toDelete = lPtr; + lPtr = lPtr->next; + + for (p.item=toDelete->itemHead; p.item;) { + CmpItemPtr toDelete; + + toDelete.item = p.item; + p.item=p.item->next; + + FreeItem(toDelete); + } + FreeLine(toDelete); + } + + if (masterPtr->changing) { + Tk_CancelIdleCall(CalculateMasterSize, (ClientData)masterPtr); + } + masterPtr->tkMaster = NULL; + if (masterPtr->imageCmd != NULL) { + char * cmd = Tcl_GetCommandName(masterPtr->interp,masterPtr->imageCmd); + masterPtr->imageCmd = NULL; + Tcl_DeleteCommand(masterPtr->interp, cmd); + } + if (masterPtr->gc != None) { + Tk_FreeGC(masterPtr->display, masterPtr->gc); + } + + Tk_FreeOptions(configSpecs, (char *) masterPtr, masterPtr->display, 0); + Tk_Release((ClientData) masterPtr); + + done: + ckfree((char *) masterPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ImgCmpCmdDeletedProc -- + * + * This procedure is invoked when the image command for an image + * is deleted. It deletes the image. + * + * Results: + * None. + * + * Side effects: + * The image is deleted. + * + *---------------------------------------------------------------------- + */ +static void +ImgCmpCmdDeletedProc(clientData) + ClientData clientData; /* Pointer to CmpMaster structure for + * image. */ +{ + CmpMaster *masterPtr = (CmpMaster *) clientData; + + Tk_Preserve((ClientData) masterPtr); + if (masterPtr->isDeleted == 1) { + Tk_Release((ClientData) masterPtr); + return; + } else { + if (masterPtr->tkMaster != NULL) { + if (Tk_MainWindow(masterPtr->interp) != NULL) { + Tk_DeleteImage(masterPtr->interp, + Tk_NameOfImage(masterPtr->tkMaster)); + } + } + Tk_Release((ClientData) masterPtr); + } +} +/* + *---------------------------------------------------------------------- + * + * ImageProc -- + * + * This procedure is invoked by the image code whenever the manager + * for an image does something that affects the size of contents + * of an image displayed in a button. + * + * Results: + * None. + * + * Side effects: + * Arranges for the HList to get redisplayed. + * + *---------------------------------------------------------------------- + */ +static void +ImageProc(clientData, x, y, width, height, imgWidth, imgHeight) + ClientData clientData; /* Pointer to widget record. */ + int x, y; /* Upper left pixel (within image) + * that must be redisplayed. */ + int width, height; /* Dimensions of area to redisplay + * (may be <= 0). */ + int imgWidth, imgHeight; /* New dimensions of image. */ +{ + CmpItemPtr p; + + p.image = (CmpImageItem *)clientData; + + ChangeImageWhenIdle(p.item->line->masterPtr); +} + +/* + *-------------------------------------------------------------- + * + * CmpEventProc -- + * + * This procedure is invoked by the Tk dispatcher for various + * events on the window that employs this compound image. + * + * Results: + * None. + * + * Side effects: + * When the window gets deleted, internal structures get + * cleaned up. When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ + +static void +CmpEventProc(clientData, eventPtr) + ClientData clientData; /* Information about window. */ + XEvent *eventPtr; /* Information about event. */ +{ + CmpMaster *masterPtr = (CmpMaster *)clientData; + char * cmd; + + if (eventPtr->type == DestroyNotify) { + if (masterPtr->imageCmd != NULL) { + cmd = Tcl_GetCommandName(masterPtr->interp,masterPtr->imageCmd); + masterPtr->imageCmd = NULL; + Tcl_DeleteCommand(masterPtr->interp, cmd); + } + } +} |