1/*
2 * tkCanvImg.c --
3 *
4 *	This file implements image items for canvas widgets.
5 *
6 * Copyright (c) 1994 The Regents of the University of California.
7 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id$
13 */
14
15#include <stdio.h>
16#include "tkInt.h"
17#include "tkCanvas.h"
18
19/*
20 * The structure below defines the record for each image item.
21 */
22
23typedef struct ImageItem  {
24    Tk_Item header;		/* Generic stuff that's the same for all
25				 * types. MUST BE FIRST IN STRUCTURE. */
26    Tk_Canvas canvas;		/* Canvas containing the image. */
27    double x, y;		/* Coordinates of positioning point for
28				 * image. */
29    Tk_Anchor anchor;		/* Where to anchor image relative to (x,y). */
30    char *imageString;		/* String describing -image option
31				 * (malloc-ed). NULL means no image right
32				 * now. */
33    char *activeImageString;	/* String describing -activeimage option.
34				 * NULL means no image right now. */
35    char *disabledImageString;	/* String describing -disabledimage option.
36				 * NULL means no image right now. */
37    Tk_Image image;		/* Image to display in window, or NULL if no
38				 * image at present. */
39    Tk_Image activeImage;	/* Image to display in window, or NULL if no
40				 * image at present. */
41    Tk_Image disabledImage;	/* Image to display in window, or NULL if no
42				 * image at present. */
43} ImageItem;
44
45/*
46 * Information used for parsing configuration specs:
47 */
48
49static Tk_CustomOption stateOption = {
50    (Tk_OptionParseProc *) TkStateParseProc,
51    TkStatePrintProc, (ClientData) 2
52};
53static Tk_CustomOption tagsOption = {
54    (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
55    Tk_CanvasTagsPrintProc, (ClientData) NULL
56};
57
58static Tk_ConfigSpec configSpecs[] = {
59    {TK_CONFIG_STRING, "-activeimage", NULL, NULL,
60	NULL, Tk_Offset(ImageItem, activeImageString), TK_CONFIG_NULL_OK},
61    {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL,
62	"center", Tk_Offset(ImageItem, anchor), TK_CONFIG_DONT_SET_DEFAULT},
63    {TK_CONFIG_STRING, "-disabledimage", NULL, NULL,
64	NULL, Tk_Offset(ImageItem, disabledImageString), TK_CONFIG_NULL_OK},
65    {TK_CONFIG_STRING, "-image", NULL, NULL,
66	NULL, Tk_Offset(ImageItem, imageString), TK_CONFIG_NULL_OK},
67    {TK_CONFIG_CUSTOM, "-state", NULL, NULL,
68	NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, &stateOption},
69    {TK_CONFIG_CUSTOM, "-tags", NULL, NULL,
70	NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
71    {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
72};
73
74/*
75 * Prototypes for functions defined in this file:
76 */
77
78static void		ImageChangedProc(ClientData clientData,
79			    int x, int y, int width, int height, int imgWidth,
80			    int imgHeight);
81static int		ImageCoords(Tcl_Interp *interp,
82			    Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
83			    Tcl_Obj *CONST argv[]);
84static int		ImageToArea(Tk_Canvas canvas,
85			    Tk_Item *itemPtr, double *rectPtr);
86static double		ImageToPoint(Tk_Canvas canvas,
87			    Tk_Item *itemPtr, double *coordPtr);
88static int		ImageToPostscript(Tcl_Interp *interp,
89			    Tk_Canvas canvas, Tk_Item *itemPtr, int prepass);
90static void		ComputeImageBbox(Tk_Canvas canvas, ImageItem *imgPtr);
91static int		ConfigureImage(Tcl_Interp *interp,
92			    Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
93			    Tcl_Obj *CONST argv[], int flags);
94static int		CreateImage(Tcl_Interp *interp,
95			    Tk_Canvas canvas, struct Tk_Item *itemPtr,
96			    int argc, Tcl_Obj *CONST argv[]);
97static void		DeleteImage(Tk_Canvas canvas,
98			    Tk_Item *itemPtr, Display *display);
99static void		DisplayImage(Tk_Canvas canvas,
100			    Tk_Item *itemPtr, Display *display, Drawable dst,
101			    int x, int y, int width, int height);
102static void		ScaleImage(Tk_Canvas canvas,
103			    Tk_Item *itemPtr, double originX, double originY,
104			    double scaleX, double scaleY);
105static void		TranslateImage(Tk_Canvas canvas,
106			    Tk_Item *itemPtr, double deltaX, double deltaY);
107
108/*
109 * The structures below defines the image item type in terms of functions that
110 * can be invoked by generic item code.
111 */
112
113Tk_ItemType tkImageType = {
114    "image",			/* name */
115    sizeof(ImageItem),		/* itemSize */
116    CreateImage,		/* createProc */
117    configSpecs,		/* configSpecs */
118    ConfigureImage,		/* configureProc */
119    ImageCoords,		/* coordProc */
120    DeleteImage,		/* deleteProc */
121    DisplayImage,		/* displayProc */
122    TK_CONFIG_OBJS,		/* flags */
123    ImageToPoint,		/* pointProc */
124    ImageToArea,		/* areaProc */
125    ImageToPostscript,		/* postscriptProc */
126    ScaleImage,			/* scaleProc */
127    TranslateImage,		/* translateProc */
128    NULL,			/* indexProc */
129    NULL,			/* icursorProc */
130    NULL,			/* selectionProc */
131    NULL,			/* insertProc */
132    NULL,			/* dTextProc */
133    NULL,			/* nextPtr */
134};
135
136/*
137 *--------------------------------------------------------------
138 *
139 * CreateImage --
140 *
141 *	This function is invoked to create a new image item in a canvas.
142 *
143 * Results:
144 *	A standard Tcl return value. If an error occurred in creating the
145 *	item, then an error message is left in the interp's result; in this
146 *	case itemPtr is left uninitialized, so it can be safely freed by the
147 *	caller.
148 *
149 * Side effects:
150 *	A new image item is created.
151 *
152 *--------------------------------------------------------------
153 */
154
155static int
156CreateImage(
157    Tcl_Interp *interp,		/* Interpreter for error reporting. */
158    Tk_Canvas canvas,		/* Canvas to hold new item. */
159    Tk_Item *itemPtr,		/* Record to hold new item; header has been
160				 * initialized by caller. */
161    int objc,			/* Number of arguments in objv. */
162    Tcl_Obj *CONST objv[])	/* Arguments describing rectangle. */
163{
164    ImageItem *imgPtr = (ImageItem *) itemPtr;
165    int i;
166
167    if (objc == 0) {
168	Tcl_Panic("canvas did not pass any coords\n");
169    }
170
171    /*
172     * Initialize item's record.
173     */
174
175    imgPtr->canvas = canvas;
176    imgPtr->anchor = TK_ANCHOR_CENTER;
177    imgPtr->imageString = NULL;
178    imgPtr->activeImageString = NULL;
179    imgPtr->disabledImageString = NULL;
180    imgPtr->image = NULL;
181    imgPtr->activeImage = NULL;
182    imgPtr->disabledImage = NULL;
183
184    /*
185     * Process the arguments to fill in the item record. Only 1 (list) or 2 (x
186     * y) coords are allowed.
187     */
188
189    if (objc == 1) {
190	i = 1;
191    } else {
192	char *arg = Tcl_GetString(objv[1]);
193	i = 2;
194	if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) {
195	    i = 1;
196	}
197    }
198    if ((ImageCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) {
199	goto error;
200    }
201    if (ConfigureImage(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) {
202	return TCL_OK;
203    }
204
205  error:
206    DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
207    return TCL_ERROR;
208}
209
210/*
211 *--------------------------------------------------------------
212 *
213 * ImageCoords --
214 *
215 *	This function is invoked to process the "coords" widget command on
216 *	image items. See the user documentation for details on what it does.
217 *
218 * Results:
219 *	Returns TCL_OK or TCL_ERROR, and sets the interp's result.
220 *
221 * Side effects:
222 *	The coordinates for the given item may be changed.
223 *
224 *--------------------------------------------------------------
225 */
226
227static int
228ImageCoords(
229    Tcl_Interp *interp,		/* Used for error reporting. */
230    Tk_Canvas canvas,		/* Canvas containing item. */
231    Tk_Item *itemPtr,		/* Item whose coordinates are to be read or
232				 * modified. */
233    int objc,			/* Number of coordinates supplied in objv. */
234    Tcl_Obj *CONST objv[])	/* Array of coordinates: x1, y1, x2, y2, ... */
235{
236    ImageItem *imgPtr = (ImageItem *) itemPtr;
237
238    if (objc == 0) {
239	Tcl_Obj *obj = Tcl_NewObj();
240
241	Tcl_Obj *subobj = Tcl_NewDoubleObj(imgPtr->x);
242	Tcl_ListObjAppendElement(interp, obj, subobj);
243	subobj = Tcl_NewDoubleObj(imgPtr->y);
244	Tcl_ListObjAppendElement(interp, obj, subobj);
245	Tcl_SetObjResult(interp, obj);
246    } else if (objc < 3) {
247	if (objc==1) {
248	    if (Tcl_ListObjGetElements(interp, objv[0], &objc,
249		    (Tcl_Obj ***) &objv) != TCL_OK) {
250		return TCL_ERROR;
251	    } else if (objc != 2) {
252		char buf[64];
253
254		sprintf(buf, "wrong # coordinates: expected 2, got %d", objc);
255		Tcl_SetResult(interp, buf, TCL_VOLATILE);
256		return TCL_ERROR;
257	    }
258	}
259	if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], &imgPtr->x) != TCL_OK)
260		|| (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1],
261  		    &imgPtr->y) != TCL_OK)) {
262	    return TCL_ERROR;
263	}
264	ComputeImageBbox(canvas, imgPtr);
265    } else {
266	char buf[64];
267
268	sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc);
269	Tcl_SetResult(interp, buf, TCL_VOLATILE);
270	return TCL_ERROR;
271    }
272    return TCL_OK;
273}
274
275/*
276 *--------------------------------------------------------------
277 *
278 * ConfigureImage --
279 *
280 *	This function is invoked to configure various aspects of an image
281 *	item, such as its anchor position.
282 *
283 * Results:
284 *	A standard Tcl result code. If an error occurs, then an error message
285 *	is left in the interp's result.
286 *
287 * Side effects:
288 *	Configuration information may be set for itemPtr.
289 *
290 *--------------------------------------------------------------
291 */
292
293static int
294ConfigureImage(
295    Tcl_Interp *interp,		/* Used for error reporting. */
296    Tk_Canvas canvas,		/* Canvas containing itemPtr. */
297    Tk_Item *itemPtr,		/* Image item to reconfigure. */
298    int objc,			/* Number of elements in objv.  */
299    Tcl_Obj *CONST objv[],	/* Arguments describing things to configure. */
300    int flags)			/* Flags to pass to Tk_ConfigureWidget. */
301{
302    ImageItem *imgPtr = (ImageItem *) itemPtr;
303    Tk_Window tkwin;
304    Tk_Image image;
305
306    tkwin = Tk_CanvasTkwin(canvas);
307    if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,
308	    (CONST char **) objv, (char *) imgPtr, flags|TK_CONFIG_OBJS)) {
309	return TCL_ERROR;
310    }
311
312    /*
313     * Create the image. Save the old image around and don't free it until
314     * after the new one is allocated. This keeps the reference count from
315     * going to zero so the image doesn't have to be recreated if it hasn't
316     * changed.
317     */
318
319    if (imgPtr->activeImageString != NULL) {
320	itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
321    } else {
322	itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
323    }
324    if (imgPtr->imageString != NULL) {
325	image = Tk_GetImage(interp, tkwin, imgPtr->imageString,
326		ImageChangedProc, (ClientData) imgPtr);
327	if (image == NULL) {
328	    return TCL_ERROR;
329	}
330    } else {
331	image = NULL;
332    }
333    if (imgPtr->image != NULL) {
334	Tk_FreeImage(imgPtr->image);
335    }
336    imgPtr->image = image;
337    if (imgPtr->activeImageString != NULL) {
338	image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString,
339		ImageChangedProc, (ClientData) imgPtr);
340	if (image == NULL) {
341	    return TCL_ERROR;
342	}
343    } else {
344	image = NULL;
345    }
346    if (imgPtr->activeImage != NULL) {
347	Tk_FreeImage(imgPtr->activeImage);
348    }
349    imgPtr->activeImage = image;
350    if (imgPtr->disabledImageString != NULL) {
351	image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString,
352		ImageChangedProc, (ClientData) imgPtr);
353	if (image == NULL) {
354	    return TCL_ERROR;
355	}
356    } else {
357	image = NULL;
358    }
359    if (imgPtr->disabledImage != NULL) {
360	Tk_FreeImage(imgPtr->disabledImage);
361    }
362    imgPtr->disabledImage = image;
363    ComputeImageBbox(canvas, imgPtr);
364    return TCL_OK;
365}
366
367/*
368 *--------------------------------------------------------------
369 *
370 * DeleteImage --
371 *
372 *	This function is called to clean up the data structure associated with
373 *	a image item.
374 *
375 * Results:
376 *	None.
377 *
378 * Side effects:
379 *	Resources associated with itemPtr are released.
380 *
381 *--------------------------------------------------------------
382 */
383
384static void
385DeleteImage(
386    Tk_Canvas canvas,		/* Info about overall canvas widget. */
387    Tk_Item *itemPtr,		/* Item that is being deleted. */
388    Display *display)		/* Display containing window for canvas. */
389{
390    ImageItem *imgPtr = (ImageItem *) itemPtr;
391
392    if (imgPtr->imageString != NULL) {
393	ckfree(imgPtr->imageString);
394    }
395    if (imgPtr->activeImageString != NULL) {
396	ckfree(imgPtr->activeImageString);
397    }
398    if (imgPtr->disabledImageString != NULL) {
399	ckfree(imgPtr->disabledImageString);
400    }
401    if (imgPtr->image != NULL) {
402	Tk_FreeImage(imgPtr->image);
403    }
404    if (imgPtr->activeImage != NULL) {
405	Tk_FreeImage(imgPtr->activeImage);
406    }
407    if (imgPtr->disabledImage != NULL) {
408	Tk_FreeImage(imgPtr->disabledImage);
409    }
410}
411
412/*
413 *--------------------------------------------------------------
414 *
415 * ComputeImageBbox --
416 *
417 *	This function is invoked to compute the bounding box of all the pixels
418 *	that may be drawn as part of a image item. This function is where the
419 *	child image's placement is computed.
420 *
421 * Results:
422 *	None.
423 *
424 * Side effects:
425 *	The fields x1, y1, x2, and y2 are updated in the header for itemPtr.
426 *
427 *--------------------------------------------------------------
428 */
429
430	/* ARGSUSED */
431static void
432ComputeImageBbox(
433    Tk_Canvas canvas,		/* Canvas that contains item. */
434    ImageItem *imgPtr)		/* Item whose bbox is to be recomputed. */
435{
436    int width, height;
437    int x, y;
438    Tk_Image image;
439    Tk_State state = imgPtr->header.state;
440
441    if(state == TK_STATE_NULL) {
442	state = ((TkCanvas *)canvas)->canvas_state;
443    }
444    image = imgPtr->image;
445    if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)imgPtr) {
446	if (imgPtr->activeImage != NULL) {
447	    image = imgPtr->activeImage;
448	}
449    } else if (state == TK_STATE_DISABLED) {
450	if (imgPtr->disabledImage != NULL) {
451	    image = imgPtr->disabledImage;
452	}
453    }
454
455    x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5));
456    y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5));
457
458    if ((state == TK_STATE_HIDDEN) || (image == None)) {
459	imgPtr->header.x1 = imgPtr->header.x2 = x;
460	imgPtr->header.y1 = imgPtr->header.y2 = y;
461	return;
462    }
463
464    /*
465     * Compute location and size of image, using anchor information.
466     */
467
468    Tk_SizeOfImage(image, &width, &height);
469    switch (imgPtr->anchor) {
470    case TK_ANCHOR_N:
471	x -= width/2;
472	break;
473    case TK_ANCHOR_NE:
474	x -= width;
475	break;
476    case TK_ANCHOR_E:
477	x -= width;
478	y -= height/2;
479	break;
480    case TK_ANCHOR_SE:
481	x -= width;
482	y -= height;
483	break;
484    case TK_ANCHOR_S:
485	x -= width/2;
486	y -= height;
487	break;
488    case TK_ANCHOR_SW:
489	y -= height;
490	break;
491    case TK_ANCHOR_W:
492	y -= height/2;
493	break;
494    case TK_ANCHOR_NW:
495	break;
496    case TK_ANCHOR_CENTER:
497	x -= width/2;
498	y -= height/2;
499	break;
500    }
501
502    /*
503     * Store the information in the item header.
504     */
505
506    imgPtr->header.x1 = x;
507    imgPtr->header.y1 = y;
508    imgPtr->header.x2 = x + width;
509    imgPtr->header.y2 = y + height;
510}
511
512/*
513 *--------------------------------------------------------------
514 *
515 * DisplayImage --
516 *
517 *	This function is invoked to draw a image item in a given drawable.
518 *
519 * Results:
520 *	None.
521 *
522 * Side effects:
523 *	ItemPtr is drawn in drawable using the transformation information in
524 *	canvas.
525 *
526 *--------------------------------------------------------------
527 */
528
529static void
530DisplayImage(
531    Tk_Canvas canvas,		/* Canvas that contains item. */
532    Tk_Item *itemPtr,		/* Item to be displayed. */
533    Display *display,		/* Display on which to draw item. */
534    Drawable drawable,		/* Pixmap or window in which to draw item. */
535    int x, int y, int width, int height)
536				/* Describes region of canvas that must be
537				 * redisplayed (not used). */
538{
539    ImageItem *imgPtr = (ImageItem *) itemPtr;
540    short drawableX, drawableY;
541    Tk_Image image;
542    Tk_State state = itemPtr->state;
543
544    if (state == TK_STATE_NULL) {
545	state = ((TkCanvas *)canvas)->canvas_state;
546    }
547
548    image = imgPtr->image;
549    if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
550	if (imgPtr->activeImage != NULL) {
551	    image = imgPtr->activeImage;
552	}
553    } else if (state == TK_STATE_DISABLED) {
554	if (imgPtr->disabledImage != NULL) {
555	    image = imgPtr->disabledImage;
556	}
557    }
558
559    if (image == NULL) {
560	return;
561    }
562
563    /*
564     * Translate the coordinates to those of the image, then redisplay it.
565     */
566
567    Tk_CanvasDrawableCoords(canvas, (double) x, (double) y,
568	    &drawableX, &drawableY);
569    Tk_RedrawImage(image, x - imgPtr->header.x1, y - imgPtr->header.y1,
570	    width, height, drawable, drawableX, drawableY);
571}
572
573/*
574 *--------------------------------------------------------------
575 *
576 * ImageToPoint --
577 *
578 *	Computes the distance from a given point to a given rectangle, in
579 *	canvas units.
580 *
581 * Results:
582 *	The return value is 0 if the point whose x and y coordinates are
583 *	coordPtr[0] and coordPtr[1] is inside the image. If the point isn't
584 *	inside the image then the return value is the distance from the point
585 *	to the image.
586 *
587 * Side effects:
588 *	None.
589 *
590 *--------------------------------------------------------------
591 */
592
593static double
594ImageToPoint(
595    Tk_Canvas canvas,		/* Canvas containing item. */
596    Tk_Item *itemPtr,		/* Item to check against point. */
597    double *coordPtr)		/* Pointer to x and y coordinates. */
598{
599    ImageItem *imgPtr = (ImageItem *) itemPtr;
600    double x1, x2, y1, y2, xDiff, yDiff;
601
602    x1 = imgPtr->header.x1;
603    y1 = imgPtr->header.y1;
604    x2 = imgPtr->header.x2;
605    y2 = imgPtr->header.y2;
606
607    /*
608     * Point is outside rectangle.
609     */
610
611    if (coordPtr[0] < x1) {
612	xDiff = x1 - coordPtr[0];
613    } else if (coordPtr[0] > x2)  {
614	xDiff = coordPtr[0] - x2;
615    } else {
616	xDiff = 0;
617    }
618
619    if (coordPtr[1] < y1) {
620	yDiff = y1 - coordPtr[1];
621    } else if (coordPtr[1] > y2)  {
622	yDiff = coordPtr[1] - y2;
623    } else {
624	yDiff = 0;
625    }
626
627    return hypot(xDiff, yDiff);
628}
629
630/*
631 *--------------------------------------------------------------
632 *
633 * ImageToArea --
634 *
635 *	This function is called to determine whether an item lies entirely
636 *	inside, entirely outside, or overlapping a given rectangle.
637 *
638 * Results:
639 *	-1 is returned if the item is entirely outside the area given by
640 *	rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given
641 *	area.
642 *
643 * Side effects:
644 *	None.
645 *
646 *--------------------------------------------------------------
647 */
648
649static int
650ImageToArea(
651    Tk_Canvas canvas,		/* Canvas containing item. */
652    Tk_Item *itemPtr,		/* Item to check against rectangle. */
653    double *rectPtr)		/* Pointer to array of four coordinates
654				 * (x1,y1,x2,y2) describing rectangular
655				 * area. */
656{
657    ImageItem *imgPtr = (ImageItem *) itemPtr;
658
659    if ((rectPtr[2] <= imgPtr->header.x1)
660	    || (rectPtr[0] >= imgPtr->header.x2)
661	    || (rectPtr[3] <= imgPtr->header.y1)
662	    || (rectPtr[1] >= imgPtr->header.y2)) {
663	return -1;
664    }
665    if ((rectPtr[0] <= imgPtr->header.x1)
666	    && (rectPtr[1] <= imgPtr->header.y1)
667	    && (rectPtr[2] >= imgPtr->header.x2)
668	    && (rectPtr[3] >= imgPtr->header.y2)) {
669	return 1;
670    }
671    return 0;
672}
673
674/*
675 *--------------------------------------------------------------
676 *
677 * ImageToPostscript --
678 *
679 *	This function is called to generate Postscript for image items.
680 *
681 * Results:
682 *	The return value is a standard Tcl result. If an error occurs in
683 *	generating Postscript then an error message is left in interp->result,
684 *	replacing whatever used to be there. If no error occurs, then
685 *	Postscript for the item is appended to the result.
686 *
687 * Side effects:
688 *	None.
689 *
690 *--------------------------------------------------------------
691 */
692
693static int
694ImageToPostscript(
695    Tcl_Interp *interp,		/* Leave Postscript or error message here. */
696    Tk_Canvas canvas,		/* Information about overall canvas. */
697    Tk_Item *itemPtr,		/* Item for which Postscript is wanted. */
698    int prepass)		/* 1 means this is a prepass to collect font
699				 * information; 0 means final Postscript is
700				 * being created.*/
701{
702    ImageItem *imgPtr = (ImageItem *)itemPtr;
703    Tk_Window canvasWin = Tk_CanvasTkwin(canvas);
704
705    char buffer[256];
706    double x, y;
707    int width, height;
708    Tk_Image image;
709    Tk_State state = itemPtr->state;
710
711    if(state == TK_STATE_NULL) {
712	state = ((TkCanvas *)canvas)->canvas_state;
713    }
714
715    image = imgPtr->image;
716    if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
717	if (imgPtr->activeImage != NULL) {
718	    image = imgPtr->activeImage;
719	}
720    } else if (state == TK_STATE_DISABLED) {
721	if (imgPtr->disabledImage != NULL) {
722	    image = imgPtr->disabledImage;
723	}
724    }
725    if (image == NULL) {
726	/*
727	 * Image item without actual image specified.
728	 */
729
730        return TCL_OK;
731    }
732    Tk_SizeOfImage(image, &width, &height);
733
734    /*
735     * Compute the coordinates of the lower-left corner of the image, taking
736     * into account the anchor position for the image.
737     */
738
739    x = imgPtr->x;
740    y = Tk_CanvasPsY(canvas, imgPtr->y);
741
742    switch (imgPtr->anchor) {
743    case TK_ANCHOR_NW:			   y -= height;		break;
744    case TK_ANCHOR_N:	   x -= width/2.0; y -= height;		break;
745    case TK_ANCHOR_NE:	   x -= width;	   y -= height;		break;
746    case TK_ANCHOR_E:	   x -= width;	   y -= height/2.0;	break;
747    case TK_ANCHOR_SE:	   x -= width;				break;
748    case TK_ANCHOR_S:	   x -= width/2.0;			break;
749    case TK_ANCHOR_SW:						break;
750    case TK_ANCHOR_W:			   y -= height/2.0;	break;
751    case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0;	break;
752    }
753
754    if (!prepass) {
755	sprintf(buffer, "%.15g %.15g", x, y);
756	Tcl_AppendResult(interp, buffer, " translate\n", NULL);
757    }
758
759    return Tk_PostscriptImage(image, interp, canvasWin,
760	    ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass);
761}
762
763/*
764 *--------------------------------------------------------------
765 *
766 * ScaleImage --
767 *
768 *	This function is invoked to rescale an item.
769 *
770 * Results:
771 *	None.
772 *
773 * Side effects:
774 *	The item referred to by itemPtr is rescaled so that the following
775 *	transformation is applied to all point coordinates:
776 *		x' = originX + scaleX*(x-originX)
777 *		y' = originY + scaleY*(y-originY)
778 *
779 *--------------------------------------------------------------
780 */
781
782static void
783ScaleImage(
784    Tk_Canvas canvas,		/* Canvas containing rectangle. */
785    Tk_Item *itemPtr,		/* Rectangle to be scaled. */
786    double originX, double originY,
787				/* Origin about which to scale rect. */
788    double scaleX,		/* Amount to scale in X direction. */
789    double scaleY)		/* Amount to scale in Y direction. */
790{
791    ImageItem *imgPtr = (ImageItem *) itemPtr;
792
793    imgPtr->x = originX + scaleX*(imgPtr->x - originX);
794    imgPtr->y = originY + scaleY*(imgPtr->y - originY);
795    ComputeImageBbox(canvas, imgPtr);
796}
797
798/*
799 *--------------------------------------------------------------
800 *
801 * TranslateImage --
802 *
803 *	This function is called to move an item by a given amount.
804 *
805 * Results:
806 *	None.
807 *
808 * Side effects:
809 *	The position of the item is offset by (xDelta, yDelta), and the
810 *	bounding box is updated in the generic part of the item structure.
811 *
812 *--------------------------------------------------------------
813 */
814
815static void
816TranslateImage(
817    Tk_Canvas canvas,		/* Canvas containing item. */
818    Tk_Item *itemPtr,		/* Item that is being moved. */
819    double deltaX, double deltaY)
820				/* Amount by which item is to be moved. */
821{
822    ImageItem *imgPtr = (ImageItem *) itemPtr;
823
824    imgPtr->x += deltaX;
825    imgPtr->y += deltaY;
826    ComputeImageBbox(canvas, imgPtr);
827}
828
829/*
830 *----------------------------------------------------------------------
831 *
832 * ImageChangedProc --
833 *
834 *	This function is invoked by the image code whenever the manager for an
835 *	image does something that affects the image's size or how it is
836 *	displayed.
837 *
838 * Results:
839 *	None.
840 *
841 * Side effects:
842 *	Arranges for the canvas to get redisplayed.
843 *
844 *----------------------------------------------------------------------
845 */
846
847static void
848ImageChangedProc(
849    ClientData clientData,	/* Pointer to canvas item for image. */
850    int x, int y,		/* Upper left pixel (within image) that must
851				 * be redisplayed. */
852    int width, int height,	/* Dimensions of area to redisplay (may be <=
853				 * 0). */
854    int imgWidth, int imgHeight)/* New dimensions of image. */
855{
856    ImageItem *imgPtr = (ImageItem *) clientData;
857
858    /*
859     * If the image's size changed and it's not anchored at its northwest
860     * corner then just redisplay the entire area of the image. This is a bit
861     * over-conservative, but we need to do something because a size change
862     * also means a position change.
863     */
864
865    if (((imgPtr->header.x2 - imgPtr->header.x1) != imgWidth)
866	    || ((imgPtr->header.y2 - imgPtr->header.y1) != imgHeight)) {
867	x = y = 0;
868	width = imgWidth;
869	height = imgHeight;
870	Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1,
871		imgPtr->header.y1, imgPtr->header.x2, imgPtr->header.y2);
872    }
873    ComputeImageBbox(imgPtr->canvas, imgPtr);
874    Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1 + x,
875	    imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width),
876	    (int) (imgPtr->header.y1 + y + height));
877}
878
879/*
880 * Local Variables:
881 * mode: c
882 * c-basic-offset: 4
883 * fill-column: 78
884 * End:
885 */
886