diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | doc/ttk_image.n | 31 | ||||
-rw-r--r-- | generic/ttk/ttkButton.c | 127 | ||||
-rw-r--r-- | generic/ttk/ttkImage.c | 300 | ||||
-rw-r--r-- | generic/ttk/ttkLabel.c | 75 | ||||
-rw-r--r-- | generic/ttk/ttkNotebook.c | 4 | ||||
-rw-r--r-- | generic/ttk/ttkTheme.h | 11 | ||||
-rw-r--r-- | generic/ttk/ttkTreeview.c | 12 | ||||
-rw-r--r-- | generic/ttk/ttkWidget.h | 9 | ||||
-rw-r--r-- | tests/ttk/image.test | 27 |
10 files changed, 302 insertions, 306 deletions
@@ -1,3 +1,15 @@ +2006-12-09 Joe English <jenglish@users.sourceforge.net> + + * generic/ttk/ttkButton.c, generic/ttk/ttkImage.c, + generic/ttk/ttkLabel.c, generic/ttk/ttkWidget.h, + generic/ttk/ttkTheme.h, generic/ttk/ttkNotebook.c, + generic/ttk/ttkTreeview.c, doc/ttk_image.n: + Merged duplicate functionality between image element factory, + image element, and -image option processing. Image element + factory now takes an imageSpec argument instead of a separate + image name and -map option. + * tests/ttk/image.test(image-1.1): Can catch this error earlier now. + 2006-12-06 Kevin Kenny <kennykb@acm.org> * unix/configure.in: Further changes to avoid attempting to link diff --git a/doc/ttk_image.n b/doc/ttk_image.n index bcda678..30c6698 100644 --- a/doc/ttk_image.n +++ b/doc/ttk_image.n @@ -1,6 +1,6 @@ '\" '\" Copyright (c) 2004 Joe English -'\" $Id: ttk_image.n,v 1.3 2006/11/16 13:25:11 dkf Exp $ +'\" $Id: ttk_image.n,v 1.4 2006/12/09 20:53:35 jenglish Exp $ '\" .so man.macros .TH ttk_image n 8.5 Tk "Tk Themed Widget" @@ -8,12 +8,17 @@ .SH NAME ttk_image \- Define an element based on an image .SH SYNOPSIS -\fBttk::style create element \fIname\fR \fBimage\fR \fIimageName\fR ?\fIoptions\fR? +\fBttk::style element create \fIname\fR \fBimage\fR \fIimageSpec\fR ?\fIoptions\fR? .BE .SH DESCRIPTION The \fIimage\fR element factory creates a new element in the current theme whose visual appearance is determined -by a Tk image. +by Tk images. +\fIimageSpec\fP is a list of one or more elements. +The first element is the default image name. +The rest of the list is a sequence of \fIstatespec / value\fR +pairs specifying other images to use when the element is +in a particular state or combination of states. .SH OPTIONS Valid \fIoptions\fR are: .TP @@ -26,16 +31,6 @@ See \fBIMAGE STRETCHING\fR, below. Specifies a minimum height for the element. If less than zero, the base image's height is used as a default. .TP -\fB-map { \fIstatespec\fR \fIimage\fR.. } -Specifies auxilliary images to use in different states. -Each \fIstatespec\fR is a list of state names optionally -prefixed by an exclamation point, as in \fBttk::style map\fR. -Each \fIimageName\fR is the name of a Tk image -defined with \fBimage create ...\fR. -When the element is displayed, each \fIstatespec\fR is -tested in order, and the \fIimage\fR corresponding to -the first matching \fIstatespec\fR is used. -If none match, the base \fIimageName\fR is used. .TP \fB-padding\fR \fIpadding\fR Specifies the element's interior padding. Defaults to @@ -62,10 +57,12 @@ left and right edges (which may be tiled vertically), and the central area (which may be tiled in both directions). .SH "EXAMPLE" .CS -set button(normal) [image create photo -file button.png] -set button(pressed) [image create photo -file button-pressed.png] -ttk::style element create Button.button \fBimage\fR $button(normal) \e - -border {2 4} -map [list pressed $button(pressed)] -sticky nswe +set img1 [image create photo -file button.png] +set img2 [image create photo -file button-pressed.png] +set img3 [image create photo -file button-active.png] +style element create Button.button image \e + [list $img1 pressed $img2 active $img3] \e + -border {2 4} -sticky we .CE .SH "SEE ALSO" image(n), photo(n) diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c index e69c5c2..033279f 100644 --- a/generic/ttk/ttkButton.c +++ b/generic/ttk/ttkButton.c @@ -1,8 +1,7 @@ -/* $Id: ttkButton.c,v 1.2 2006/11/03 03:06:22 das Exp $ +/* $Id: ttkButton.c,v 1.3 2006/12/09 20:53:35 jenglish Exp $ * Copyright (c) 2003, Joe English * - * Ttk widget set: label, button, checkbutton, radiobutton, and - * menubutton widgets. + * label, button, checkbutton, radiobutton, and menubutton widgets. */ #include <string.h> @@ -29,7 +28,7 @@ typedef struct Tcl_Obj *widthObj; Ttk_TraceHandle *textVariableTrace; - Tk_Image *images; + Ttk_ImageSpec *imageSpec; /* * Image element resources: @@ -119,106 +118,12 @@ static void TextVariableChanged(void *clientData, const char *value) TtkResizeWidget(&basePtr->core); } -/* - * Tk_ImageChangedProc for -image option: - */ -static void CoreImageChangedProc(ClientData clientData, - int x, int y, int width, int height, int imageWidth, int imageHeight) -{ - WidgetCore *corePtr = (WidgetCore *)clientData; - TtkRedisplayWidget(corePtr); -} - -/* TtkGetImageList -- - * ConfigureProc utility routine for handling -image option. - * Verifies that -image is a valid image specification, - * registers image-changed callbacks for each image (via Tk_GetImage). - * - * The -image option is a multi-element list; the first element - * is the name of the default image to use, the remainder of the - * list is a sequence of statespec/imagename options as per - * [style map]. - * - * Returns: TCL_OK if image specification is valid and sets *imageListPtr - * to a NULL-terminated list of Tk_Images; otherwise TCL_ERROR - * and leaves an error message in the interpreter result. - */ -int TtkGetImageList( - Tcl_Interp *interp, - WidgetCore *corePtr, - Tcl_Obj *imageOption, - Tk_Image **imageListPtr) -{ - int i, mapCount, imageCount; - Tcl_Obj **mapList; - Tk_Image *images; - - if (Tcl_ListObjGetElements(interp, - imageOption, &mapCount, &mapList) != TCL_OK) - { - return TCL_ERROR; - } - - if (mapCount == 0) { - *imageListPtr = 0; - return TCL_OK; - } - - if ((mapCount % 2) != 1) { - Tcl_SetResult(interp, - "-image value must contain an odd number of elements", TCL_STATIC); - return TCL_ERROR; - } - - /* Verify state specifications: - */ - for (i = 1; i < mapCount -1; i += 2) { - Ttk_StateSpec spec; - if (Ttk_GetStateSpecFromObj(interp, mapList[i], &spec) != TCL_OK) - return TCL_ERROR; - } - - /* Get images: - */ - imageCount = (mapCount + 1) / 2; - images = (Tk_Image*)ckalloc((imageCount+1) * sizeof(Tk_Image)); - - for (i = 0; i < imageCount; ++i) { - const char *imageName = Tcl_GetString(mapList[i * 2]); - images[i] = Tk_GetImage(interp, corePtr->tkwin, - imageName, CoreImageChangedProc, corePtr); - - if (!images[i]) { - while (i--) - Tk_FreeImage(images[i]); - ckfree((ClientData)images); - return TCL_ERROR; - } - } - images[i] = NULL; /* Add null terminator */ - - *imageListPtr = images; - return TCL_OK; -} - -/* - * TtkFreeImageList -- - * Release an image list obtained by TtkGetImageList. - */ -void TtkFreeImageList(Tk_Image *imageList) -{ - Tk_Image *p; - for (p = imageList; *p; ++p) - Tk_FreeImage(*p); - ckfree((ClientData)imageList); -} - static int BaseInitialize(Tcl_Interp *interp, void *recordPtr) { Base *basePtr = recordPtr; basePtr->base.textVariableTrace = 0; - basePtr->base.images = NULL; + basePtr->base.imageSpec = NULL; return TCL_OK; } @@ -228,8 +133,8 @@ BaseCleanup(void *recordPtr) Base *basePtr = recordPtr; if (basePtr->base.textVariableTrace) Ttk_UntraceVariable(basePtr->base.textVariableTrace); - if (basePtr->base.images) - TtkFreeImageList(basePtr->base.images); + if (basePtr->base.imageSpec) + TtkFreeImageSpec(basePtr->base.imageSpec); } static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask) @@ -237,22 +142,24 @@ static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask) Base *basePtr = recordPtr; Tcl_Obj *textVarName = basePtr->base.textVariableObj; Ttk_TraceHandle *vt = 0; - Tk_Image *images = NULL; + Ttk_ImageSpec *imageSpec = NULL; if (textVarName != NULL && *Tcl_GetString(textVarName) != '\0') { vt = Ttk_TraceVariable(interp,textVarName,TextVariableChanged,basePtr); if (!vt) return TCL_ERROR; } - if (basePtr->base.imageObj && TtkGetImageList(interp, - &basePtr->core, basePtr->base.imageObj, &images) != TCL_OK) - { - goto error; + if (basePtr->base.imageObj) { + imageSpec = TtkGetImageSpec( + interp, basePtr->core.tkwin, basePtr->base.imageObj); + if (!imageSpec) { + goto error; + } } if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) { error: - if (images) TtkFreeImageList(images); + if (imageSpec) TtkFreeImageSpec(imageSpec); if (vt) Ttk_UntraceVariable(vt); return TCL_ERROR; } @@ -262,10 +169,10 @@ error: } basePtr->base.textVariableTrace = vt; - if (basePtr->base.images) { - TtkFreeImageList(basePtr->base.images); + if (basePtr->base.imageSpec) { + TtkFreeImageSpec(basePtr->base.imageSpec); } - basePtr->base.images = images; + basePtr->base.imageSpec = imageSpec; if (mask & STATE_CHANGED) { TtkCheckStateOption(&basePtr->core, basePtr->base.stateObj); diff --git a/generic/ttk/ttkImage.c b/generic/ttk/ttkImage.c index 4d80f48..7f0a2af 100644 --- a/generic/ttk/ttkImage.c +++ b/generic/ttk/ttkImage.c @@ -1,9 +1,13 @@ -/* $Id: ttkImage.c,v 1.3 2006/11/27 06:53:55 jenglish Exp $ - * Ttk widget set -- image element factory. +/* $Id: ttkImage.c,v 1.4 2006/12/09 20:53:35 jenglish Exp $ + * Image specifications and image element factory. * * Copyright (C) 2004 Pat Thoyts <patthoyts@users.sf.net> * Copyright (C) 2004 Joe English * + * An imageSpec is a multi-element list; the first element + * is the name of the default image to use, the remainder of the + * list is a sequence of statespec/imagename options as per + * [style map]. */ #include <string.h> @@ -13,6 +17,127 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) /*------------------------------------------------------------------------ + * +++ ImageSpec management. + */ + +struct TtkImageSpec { + Tk_Image baseImage; /* Base image to use */ + int mapCount; /* #state-specific overrides */ + Ttk_StateSpec *states; /* array[mapCount] of states ... */ + Tk_Image *images; /* ... per-state images to use */ +}; + +/* NullImageChanged -- + * Do-nothing Tk_ImageChangedProc. + */ +static void NullImageChanged(ClientData clientData, + int x, int y, int width, int height, int imageWidth, int imageHeight) +{ /* No-op */ } + +/* TtkGetImageSpec -- + * Constructs a Ttk_ImageSpec * from a Tcl_Obj *. + * Result must be released using TtkFreeImageSpec. + * + * TODO: Need a variant of this that takes a user-specified ImageChanged proc + */ +Ttk_ImageSpec * +TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr) +{ + Ttk_ImageSpec *imageSpec = 0; + int i = 0, n = 0, objc; + Tcl_Obj **objv; + + imageSpec = (Ttk_ImageSpec *)ckalloc(sizeof(*imageSpec)); + imageSpec->baseImage = 0; + imageSpec->mapCount = 0; + imageSpec->states = 0; + imageSpec->images = 0; + + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + goto error; + } + + if ((objc % 2) != 1) { + if (interp) { + Tcl_SetResult(interp, + "image specification must contain an odd number of elements", + TCL_STATIC); + } + goto error; + } + + n = (objc - 1) / 2; + imageSpec->states = (Ttk_StateSpec*)ckalloc(n * sizeof(Ttk_StateSpec)); + imageSpec->images = (Tk_Image*)ckalloc(n * sizeof(Tk_Image *)); + + /* Get base image: + */ + imageSpec->baseImage = Tk_GetImage( + interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL); + if (!imageSpec->baseImage) { + goto error; + } + + /* Extract state and image specifications: + */ + for (i = 0; i < n; ++i) { + Tcl_Obj *stateSpec = objv[2*i + 1]; + const char *imageName = Tcl_GetString(objv[2*i + 2]); + Ttk_StateSpec state; + + if (Ttk_GetStateSpecFromObj(interp, stateSpec, &state) != TCL_OK) { + goto error; + } + imageSpec->states[i] = state; + + imageSpec->images[i] = Tk_GetImage( + interp, tkwin, imageName, NullImageChanged, NULL); + if (imageSpec->images[i] == NULL) { + goto error; + } + imageSpec->mapCount = i+1; + } + + return imageSpec; + +error: + TtkFreeImageSpec(imageSpec); + return NULL; +} + +/* TtkFreeImageSpec -- + * Dispose of an image specification. + */ +void TtkFreeImageSpec(Ttk_ImageSpec *imageSpec) +{ + int i; + + for (i=0; i < imageSpec->mapCount; ++i) { + Tk_FreeImage(imageSpec->images[i]); + } + + if (imageSpec->baseImage) { Tk_FreeImage(imageSpec->baseImage); } + if (imageSpec->states) { ckfree((ClientData)imageSpec->states); } + if (imageSpec->images) { ckfree((ClientData)imageSpec->images); } + + ckfree((ClientData)imageSpec); +} + +/* TtkSelectImage -- + * Return a state-specific image from an ImageSpec + */ +Tk_Image TtkSelectImage(Ttk_ImageSpec *imageSpec, Ttk_State state) +{ + int i; + for (i = 0; i < imageSpec->mapCount; ++i) { + if (Ttk_StateMatches(state, imageSpec->states+i)) { + return imageSpec->images[i]; + } + } + return imageSpec->baseImage; +} + +/*------------------------------------------------------------------------ * +++ Drawing utilities. */ @@ -92,59 +217,35 @@ static void Ttk_Tile( */ typedef struct { /* ClientData for image elements */ - Ttk_ResourceCache cache; /* Resource cache for images */ - Tcl_Obj *baseImage; /* Name of default image */ - Ttk_StateMap imageMap; /* State-based lookup table for images */ - Tcl_Obj *stickyObj; /* Stickiness specification, NWSE */ - Tcl_Obj *borderObj; /* Border specification */ - Tcl_Obj *paddingObj; /* Padding specification */ + Ttk_ImageSpec *imageSpec; /* Image(s) to use */ int minWidth; /* Minimum width; overrides image width */ int minHeight; /* Minimum width; overrides image width */ - unsigned sticky; + Ttk_Sticky sticky; /* -stickiness specification */ Ttk_Padding border; /* Fixed border region */ Ttk_Padding padding; /* Internal padding */ + +#if TILE_07_COMPAT + Ttk_ResourceCache cache; /* Resource cache for images */ + Ttk_StateMap imageMap; /* State-based lookup table for images */ +#endif } ImageData; static void FreeImageData(void *clientData) { ImageData *imageData = clientData; - Tcl_DecrRefCount(imageData->baseImage); + if (imageData->imageSpec) { TtkFreeImageSpec(imageData->imageSpec); } +#if TILE_07_COMPAT if (imageData->imageMap) { Tcl_DecrRefCount(imageData->imageMap); } - if (imageData->stickyObj) { Tcl_DecrRefCount(imageData->stickyObj); } - if (imageData->borderObj) { Tcl_DecrRefCount(imageData->borderObj); } - if (imageData->paddingObj) { Tcl_DecrRefCount(imageData->paddingObj); } +#endif ckfree(clientData); } -static Tk_OptionSpec ImageOptionSpecs[] = -{ - { TK_OPTION_STRING, "-sticky", "sticky", "Sticky", - "nswe", Tk_Offset(ImageData,stickyObj), -1, - 0,0,0 }, - { TK_OPTION_STRING, "-border", "border", "Border", - "0", Tk_Offset(ImageData,borderObj), -1, - 0,0,0 }, - { TK_OPTION_STRING, "-padding", "padding", "Padding", - NULL, Tk_Offset(ImageData,paddingObj), -1, - TK_OPTION_NULL_OK,0,0 }, - { TK_OPTION_STRING, "-map", "map", "Map", - "", Tk_Offset(ImageData,imageMap), -1, - 0,0,0 }, - { TK_OPTION_INT, "-width", "width", "Width", - "-1", -1, Tk_Offset(ImageData, minWidth), - 0, 0, 0}, - { TK_OPTION_INT, "-height", "height", "Height", - "-1", -1, Tk_Offset(ImageData, minHeight), - 0, 0, 0}, - { TK_OPTION_END } -}; - -static void ImageElementGeometry( +static void ImageElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { ImageData *imageData = clientData; - Tk_Image image = Ttk_UseImage(imageData->cache,tkwin,imageData->baseImage); + Tk_Image image = imageData->imageSpec->baseImage; if (image) { Tk_SizeOfImage(image, widthPtr, heightPtr); @@ -166,18 +267,23 @@ static void ImageElementDraw( Drawable d, Ttk_Box b, unsigned int state) { ImageData *imageData = clientData; - Tcl_Obj *imageObj = 0; - Tk_Image image; + Tk_Image image = 0; int imgWidth, imgHeight; Ttk_Box src, dst; +#if TILE_07_COMPAT if (imageData->imageMap) { - imageObj = Ttk_StateMapLookup(NULL, imageData->imageMap, state); + Tcl_Obj *imageObj = Ttk_StateMapLookup(NULL,imageData->imageMap,state); + if (imageObj) { + image = Ttk_UseImage(imageData->cache, tkwin, imageObj); + } } - if (!imageObj) { - imageObj = imageData->baseImage; + if (!image) { + image = TtkSelectImage(imageData->imageSpec, state); } - image = Ttk_UseImage(imageData->cache, tkwin, imageObj); +#else + image = TtkSelectImage(imageData->imageSpec, state); +#endif if (!image) { return; @@ -195,7 +301,7 @@ static Ttk_ElementSpec ImageElementSpec = TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, - ImageElementGeometry, + ImageElementSize, ImageElementDraw }; @@ -210,58 +316,85 @@ Ttk_CreateImageElement( const char *elementName, int objc, Tcl_Obj *CONST objv[]) { - Tk_OptionTable imageOptionTable = - Tk_CreateOptionTable(interp, ImageOptionSpecs); - ImageData *imageData; + const char *optionStrings[] = + { "-border","-height","-padding","-sticky","-width",NULL }; + enum { O_BORDER, O_HEIGHT, O_PADDING, O_STICKY, O_WIDTH }; - imageData = (ImageData*)ckalloc(sizeof(*imageData)); + Ttk_ImageSpec *imageSpec = 0; + ImageData *imageData = 0; + int padding_specified = 0; + int i; if (objc <= 0) { Tcl_AppendResult(interp, "Must supply a base image", NULL); return TCL_ERROR; } - imageData->cache = Ttk_GetResourceCache(interp); - imageData->imageMap = imageData->stickyObj - = imageData->borderObj = imageData->paddingObj = 0; - imageData->minWidth = imageData->minHeight = -1; - imageData->sticky = TTK_FILL_BOTH; /* ??? Is this sensible */ - imageData->border = imageData->padding = Ttk_UniformPadding(0); - - /* Can't use Tk_InitOptions() here, since we don't have a Tk_Window - */ - if (TCL_OK != Tk_SetOptions(interp, (ClientData)imageData, - imageOptionTable, objc-1, objv+1, - NULL/*tkwin*/, NULL/*savedOptions*/, NULL/*mask*/)) - { - ckfree((ClientData)imageData); + imageSpec = TtkGetImageSpec(interp, Tk_MainWindow(interp), objv[0]); + if (!imageSpec) { return TCL_ERROR; } - imageData->baseImage = Tcl_DuplicateObj(objv[0]); - - if (imageData->borderObj && Ttk_GetBorderFromObj( - interp, imageData->borderObj, &imageData->border) != TCL_OK) - { - goto error; - } + imageData = (ImageData*)ckalloc(sizeof(*imageData)); + imageData->imageSpec = imageSpec; + imageData->minWidth = imageData->minHeight = -1; + imageData->sticky = TTK_FILL_BOTH; + imageData->border = imageData->padding = Ttk_UniformPadding(0); +#if TILE_07_COMPAT + imageData->cache = Ttk_GetResourceCache(interp); + imageData->imageMap = 0; +#endif - imageData->padding = imageData->border; + for (i = 1; i < objc; i += 2) { + int option; - if (imageData->paddingObj && Ttk_GetBorderFromObj( - interp, imageData->paddingObj, &imageData->padding) != TCL_OK) - { - goto error; - } + if (i == objc - 1) { + Tcl_AppendResult(interp, + "Value for ", Tcl_GetString(objv[i]), " missing", + NULL); + goto error; + } - if (imageData->stickyObj && Ttk_GetStickyFromObj( - interp, imageData->stickyObj, &imageData->sticky) != TCL_OK) - { - goto error; +#if TILE_07_COMPAT + if (!strcmp("-map", Tcl_GetString(objv[i]))) { + imageData->imageMap = objv[i+1]; + Tcl_IncrRefCount(imageData->imageMap); + continue; + } +#endif + + if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, + "option", 0, &option) != TCL_OK) { goto error; } + + switch (option) { + case O_BORDER: + if (Ttk_GetBorderFromObj(interp, objv[i+1], &imageData->border) + != TCL_OK) { goto error; } + if (!padding_specified) { + imageData->padding = imageData->border; + } + break; + case O_PADDING: + if (Ttk_GetBorderFromObj(interp, objv[i+1], &imageData->padding) + != TCL_OK) { goto error; } + padding_specified = 1; + break; + case O_WIDTH: + if (Tcl_GetIntFromObj(interp, objv[i+1], &imageData->minWidth) + != TCL_OK) { goto error; } + break; + case O_HEIGHT: + if (Tcl_GetIntFromObj(interp, objv[i+1], &imageData->minHeight) + != TCL_OK) { goto error; } + break; + case O_STICKY: + if (Ttk_GetStickyFromObj(interp, objv[i+1], &imageData->sticky) + != TCL_OK) { goto error; } + } } - if (!Ttk_RegisterElement(interp, theme, - elementName, &ImageElementSpec, imageData)) + if (!Ttk_RegisterElement(interp, theme, elementName, &ImageElementSpec, + imageData)) { goto error; } @@ -278,7 +411,8 @@ error: MODULE_SCOPE int Ttk_ImageInit(Tcl_Interp *); int Ttk_ImageInit(Tcl_Interp *interp) { - return Ttk_RegisterElementFactory(interp, "image", Ttk_CreateImageElement, NULL); + return Ttk_RegisterElementFactory(interp, "image", + Ttk_CreateImageElement, NULL); } /*EOF*/ diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c index 4d90722..e03fea4 100644 --- a/generic/ttk/ttkLabel.c +++ b/generic/ttk/ttkLabel.c @@ -1,6 +1,6 @@ -/* $Id: ttkLabel.c,v 1.2 2006/11/03 03:06:22 das Exp $ +/* $Id: ttkLabel.c,v 1.3 2006/12/09 20:53:35 jenglish Exp $ * - * Ttk widget set: text, image, and label elements. + * text, image, and label elements. * * The label element combines text and image elements, * with layout determined by the "-compound" option. @@ -263,14 +263,13 @@ MODULE_SCOPE Ttk_ElementSpec ttkImageTextElementSpec; typedef struct { Tcl_Obj *imageObj; - Tcl_Obj *stippleObj; /* For TTK_STATE_DISABLED */ Tcl_Obj *backgroundObj; /* " " */ + Ttk_ImageSpec *imageSpec; Tk_Image tkimg; int width; int height; - int doStipple; } ImageElement; /* ===> NB: Keep in sync with label element option table. <=== @@ -286,13 +285,6 @@ static Ttk_ElementOptionSpec ImageElementOptions[] = {NULL} }; -/* NullImageChanged -- - * No-op Tk_ImageChangedProc for Tk_GetImage. - */ -static void NullImageChanged(ClientData clientData, - int x, int y, int width, int height, int imageWidth, int imageHeight) -{ } - /* * ImageSetup() -- * Look up the Tk_Image from the image element's imageObj resource. @@ -306,51 +298,19 @@ static void NullImageChanged(ClientData clientData, static int ImageSetup( ImageElement *image, Tk_Window tkwin, Tcl_Interp *interp, Ttk_State state) { - const char *imageName; - Tcl_Obj *imageObj = image->imageObj; - Tcl_Obj **mapList = NULL; - int i, mapCnt = 0; - - if (!imageObj) /* No -image option specified */ - return 0; - - if (Tcl_ListObjGetElements(interp,imageObj,&mapCnt,&mapList) == TCL_ERROR) - return 0; - if (mapCnt == 0) /* -image is an empty list */ + if (!image->imageObj) { return 0; - - /* Only enable disabled-stippling if there's no state map: - * @@@ Possibly: Don't do disabled-stippling at all; - * @@@ it's ugly and out of fashion. - */ - image->doStipple = mapCnt == 1; - - /* Locate which image to use based on current state: - */ - imageObj = mapList[0]; - for (i = 1; i < mapCnt - 1; i += 2) { - Ttk_StateSpec stateSpec; - - if (Ttk_GetStateSpecFromObj(interp,mapList[i],&stateSpec) != TCL_OK) { - /* shouldn't happen, but can */ - break; - } - - if (Ttk_StateMatches(state, &stateSpec)) { - imageObj = mapList[i+1]; - break; - } } - - imageName = Tcl_GetString(imageObj); - if (!imageName || !*imageName) /* Empty string. */ + image->imageSpec = TtkGetImageSpec(NULL, tkwin, image->imageObj); + if (!image->imageSpec) { return 0; - - image->tkimg = Tk_GetImage(interp, tkwin, imageName, NullImageChanged, 0); - if (!image->tkimg) /* No such image */ + } + image->tkimg = TtkSelectImage(image->imageSpec, state); + if (!image->tkimg) { + TtkFreeImageSpec(image->imageSpec); return 0; - + } Tk_SizeOfImage(image->tkimg, &image->width, &image->height); return 1; @@ -358,7 +318,7 @@ static int ImageSetup( static void ImageCleanup(ImageElement *image) { - Tk_FreeImage(image->tkimg); + TtkFreeImageSpec(image->imageSpec); } /* @@ -402,8 +362,15 @@ static void ImageDraw( Tk_RedrawImage(image->tkimg, 0,0, width, height, d, b.x, b.y); - if (image->doStipple && (state & TTK_STATE_DISABLED)) { - StippleOver(image, tkwin, d, b.x,b.y); + /* If we're disabled there's no state-specific 'disabled' image, + * stipple the image. + * @@@ Possibly: Don't do disabled-stippling at all; + * @@@ it's ugly and out of fashion. + */ + if (state & TTK_STATE_DISABLED) { + if (TtkSelectImage(image->imageSpec, 0ul) == image->tkimg) { + StippleOver(image, tkwin, d, b.x,b.y); + } } } diff --git a/generic/ttk/ttkNotebook.c b/generic/ttk/ttkNotebook.c index c801bfe..4e8caf9 100644 --- a/generic/ttk/ttkNotebook.c +++ b/generic/ttk/ttkNotebook.c @@ -1,4 +1,4 @@ -/* $Id: ttkNotebook.c,v 1.2 2006/11/03 03:06:22 das Exp $ +/* $Id: ttkNotebook.c,v 1.3 2006/12/09 20:53:35 jenglish Exp $ * Copyright (c) 2004, Joe English * * NOTE-ACTIVE: activeTabIndex is not always correct (it's @@ -638,7 +638,7 @@ static int TabConfigured( Tk_Window tkwin = mgr->masterWindow; /* Check options: - * @@@ TODO: validate -image option with TtkGetImageList() + * @@@ TODO: validate -image option. */ if (Ttk_GetStickyFromObj(interp, tab->stickyObj, &sticky) != TCL_OK) { return TCL_ERROR; diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h index 513701d..27f1e5b 100644 --- a/generic/ttk/ttkTheme.h +++ b/generic/ttk/ttkTheme.h @@ -4,7 +4,7 @@ * * Copyright (c) 2003 Joe English. Freely redistributable. * - * $Id: ttkTheme.h,v 1.4 2006/12/01 15:05:28 jenglish Exp $ + * $Id: ttkTheme.h,v 1.5 2006/12/09 20:53:35 jenglish Exp $ */ #ifndef _TTKTHEME @@ -364,6 +364,15 @@ MODULE_SCOPE Tk_Image Ttk_UseImage(Ttk_ResourceCache, Tk_Window, Tcl_Obj *); MODULE_SCOPE void Ttk_RegisterNamedColor(Ttk_ResourceCache, const char *, XColor *); /*------------------------------------------------------------------------ + * +++ Image specifications. + */ + +typedef struct TtkImageSpec Ttk_ImageSpec; +extern Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *); +extern void TtkFreeImageSpec(Ttk_ImageSpec *); +extern Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State); + +/*------------------------------------------------------------------------ * +++ Miscellaneous enumerations. * Other stuff that element implementations need to know about. */ diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c index 70b328e..6990c8f 100644 --- a/generic/ttk/ttkTreeview.c +++ b/generic/ttk/ttkTreeview.c @@ -1,5 +1,5 @@ /* - * $Id: ttkTreeview.c,v 1.5 2006/11/27 06:53:55 jenglish Exp $ + * $Id: ttkTreeview.c,v 1.6 2006/12/09 20:53:35 jenglish Exp $ * Copyright (c) 2004, Joe English * * ttk::treeview widget implementation. @@ -949,14 +949,14 @@ static int ConfigureItem( } /* Validate -image option. - * @@@ TODO: keep images array around */ if (item->imageObj) { - Tk_Image *images = NULL; - if (TtkGetImageList(interp, &tv->core, item->imageObj, &images) != TCL_OK) + Ttk_ImageSpec *imageSpec = + TtkGetImageSpec(interp, tv->core.tkwin, item->imageObj); + if (!imageSpec) { goto error; - if (images) - TtkFreeImageList(images); + } + TtkFreeImageSpec(imageSpec); /* @@@TODO: Keep this around */ } /* Keep TTK_STATE_OPEN flag in sync with item->openObj. diff --git a/generic/ttk/ttkWidget.h b/generic/ttk/ttkWidget.h index 0a0f10f..9312040 100644 --- a/generic/ttk/ttkWidget.h +++ b/generic/ttk/ttkWidget.h @@ -1,4 +1,4 @@ -/* $Id: ttkWidget.h,v 1.2 2006/11/03 03:06:22 das Exp $ +/* $Id: ttkWidget.h,v 1.3 2006/12/09 20:53:35 jenglish Exp $ * Copyright (c) 2003, Joe English * * Helper routines for widget implementations. @@ -170,13 +170,6 @@ MODULE_SCOPE void Ttk_UntraceVariable(Ttk_TraceHandle *); MODULE_SCOPE int Ttk_FireTrace(Ttk_TraceHandle *); /* - * Utility routines for managing -image option: - */ -MODULE_SCOPE int TtkGetImageList( - Tcl_Interp *, WidgetCore *, Tcl_Obj *imageOption, Tk_Image **imageListPtr); -MODULE_SCOPE void TtkFreeImageList(Tk_Image *); - -/* * Virtual events: */ MODULE_SCOPE void TtkSendVirtualEvent(Tk_Window tgtWin, const char *eventName); diff --git a/tests/ttk/image.test b/tests/ttk/image.test index b1f66bd..e9c1248 100644 --- a/tests/ttk/image.test +++ b/tests/ttk/image.test @@ -1,37 +1,14 @@ # -# $Id: image.test,v 1.1 2006/10/31 01:42:27 hobbs Exp $ +# $Id: image.test,v 1.2 2006/12/09 20:53:35 jenglish Exp $ # package require Tk 8.5 package require tcltest ; namespace import -force tcltest::* loadTestedCommands -# catch background errors: -# -if {[info procs bgerror] == "bgerror"} { rename bgerror {} } -array set BGerror { caught 0 message {} } -proc bgerror {message} { - variable BGerror - set BGerror(caught) 1 - set BGerror(message) $message -} -proc caughtbgerror {} { - variable BGerror - if {!$BGerror(caught)} { - error "No bgerror caught" - } - set BGerror(caught) 0 - return $BGerror(message) -} - test image-1.1 "Bad image element" -body { ttk::style element create BadImage image badimage - ttk::style layout BadImage { BadImage } - ttk::label .l -style BadImage - pack .l ; update - destroy .l - caughtbgerror -} -result {image "badimage" doesn't exist} +} -returnCodes error -result {image "badimage" doesn't exist} test image-1.2 "Duplicate element" -setup { image create photo test.element -width 10 -height 10 |