summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkImage.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/ttk/ttkImage.c')
-rw-r--r--generic/ttk/ttkImage.c300
1 files changed, 217 insertions, 83 deletions
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*/