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