1/*
2 * tkCanvBmap.c --
3 *
4 *	This file implements bitmap items for canvas widgets.
5 *
6 * Copyright (c) 1992-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 bitmap item.
21 */
22
23typedef struct BitmapItem  {
24    Tk_Item header;		/* Generic stuff that's the same for all
25				 * types. MUST BE FIRST IN STRUCTURE. */
26    double x, y;		/* Coordinates of positioning point for
27				 * bitmap. */
28    Tk_Anchor anchor;		/* Where to anchor bitmap relative to (x,y) */
29    Pixmap bitmap;		/* Bitmap to display in window. */
30    Pixmap activeBitmap;	/* Bitmap to display in window. */
31    Pixmap disabledBitmap;	/* Bitmap to display in window. */
32    XColor *fgColor;		/* Foreground color to use for bitmap. */
33    XColor *activeFgColor;	/* Foreground color to use for bitmap. */
34    XColor *disabledFgColor;	/* Foreground color to use for bitmap. */
35    XColor *bgColor;		/* Background color to use for bitmap. */
36    XColor *activeBgColor;	/* Background color to use for bitmap. */
37    XColor *disabledBgColor;	/* Background color to use for bitmap. */
38    GC gc;			/* Graphics context to use for drawing bitmap
39				 * on screen. */
40} BitmapItem;
41
42/*
43 * Information used for parsing configuration specs:
44 */
45
46static Tk_CustomOption stateOption = {
47    (Tk_OptionParseProc *) TkStateParseProc,
48    TkStatePrintProc, (ClientData) 2
49};
50static Tk_CustomOption tagsOption = {
51    (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
52    Tk_CanvasTagsPrintProc, (ClientData) NULL
53};
54
55static Tk_ConfigSpec configSpecs[] = {
56    {TK_CONFIG_COLOR, "-activebackground", NULL, NULL,
57	NULL, Tk_Offset(BitmapItem, activeBgColor), TK_CONFIG_NULL_OK},
58    {TK_CONFIG_BITMAP, "-activebitmap", NULL, NULL,
59	NULL, Tk_Offset(BitmapItem, activeBitmap), TK_CONFIG_NULL_OK},
60    {TK_CONFIG_COLOR, "-activeforeground", NULL, NULL,
61	NULL, Tk_Offset(BitmapItem, activeFgColor), TK_CONFIG_NULL_OK},
62    {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL,
63	"center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT},
64    {TK_CONFIG_COLOR, "-background", NULL, NULL,
65	NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK},
66    {TK_CONFIG_BITMAP, "-bitmap", NULL, NULL,
67	NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK},
68    {TK_CONFIG_COLOR, "-disabledbackground", NULL, NULL,
69	NULL, Tk_Offset(BitmapItem, disabledBgColor),
70	TK_CONFIG_NULL_OK},
71    {TK_CONFIG_BITMAP, "-disabledbitmap", NULL, NULL,
72	NULL, Tk_Offset(BitmapItem, disabledBitmap),
73	TK_CONFIG_NULL_OK},
74    {TK_CONFIG_COLOR, "-disabledforeground", NULL, NULL,
75	NULL, Tk_Offset(BitmapItem, disabledFgColor),
76	TK_CONFIG_NULL_OK},
77    {TK_CONFIG_COLOR, "-foreground", NULL, NULL,
78	"black", Tk_Offset(BitmapItem, fgColor), 0},
79    {TK_CONFIG_CUSTOM, "-state", NULL, NULL,
80	NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,
81	&stateOption},
82    {TK_CONFIG_CUSTOM, "-tags", NULL, NULL,
83	NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
84    {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
85};
86
87/*
88 * Prototypes for functions defined in this file:
89 */
90
91static int		BitmapCoords(Tcl_Interp *interp,
92			    Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
93			    Tcl_Obj *CONST objv[]);
94static int		BitmapToArea(Tk_Canvas canvas,
95			    Tk_Item *itemPtr, double *rectPtr);
96static double		BitmapToPoint(Tk_Canvas canvas,
97			    Tk_Item *itemPtr, double *coordPtr);
98static int		BitmapToPostscript(Tcl_Interp *interp,
99			    Tk_Canvas canvas, Tk_Item *itemPtr, int prepass);
100static void		ComputeBitmapBbox(Tk_Canvas canvas,
101			    BitmapItem *bmapPtr);
102static int		ConfigureBitmap(Tcl_Interp *interp,
103			    Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
104			    Tcl_Obj *CONST objv[], int flags);
105static int		TkcCreateBitmap(Tcl_Interp *interp,
106			    Tk_Canvas canvas, struct Tk_Item *itemPtr,
107			    int objc, Tcl_Obj *CONST objv[]);
108static void		DeleteBitmap(Tk_Canvas canvas,
109			    Tk_Item *itemPtr, Display *display);
110static void		DisplayBitmap(Tk_Canvas canvas,
111			    Tk_Item *itemPtr, Display *display, Drawable dst,
112			    int x, int y, int width, int height);
113static void		ScaleBitmap(Tk_Canvas canvas,
114			    Tk_Item *itemPtr, double originX, double originY,
115			    double scaleX, double scaleY);
116static void		TranslateBitmap(Tk_Canvas canvas, Tk_Item *itemPtr,
117			    double deltaX, double deltaY);
118
119/*
120 * The structures below defines the bitmap item type in terms of functions
121 * that can be invoked by generic item code.
122 */
123
124Tk_ItemType tkBitmapType = {
125    "bitmap",			/* name */
126    sizeof(BitmapItem),		/* itemSize */
127    TkcCreateBitmap,		/* createProc */
128    configSpecs,		/* configSpecs */
129    ConfigureBitmap,		/* configureProc */
130    BitmapCoords,		/* coordProc */
131    DeleteBitmap,		/* deleteProc */
132    DisplayBitmap,		/* displayProc */
133    TK_CONFIG_OBJS,		/* flags */
134    BitmapToPoint,		/* pointProc */
135    BitmapToArea,		/* areaProc */
136    BitmapToPostscript,		/* postscriptProc */
137    ScaleBitmap,		/* scaleProc */
138    TranslateBitmap,		/* translateProc */
139    NULL,			/* indexProc */
140    NULL,			/* icursorProc */
141    NULL,			/* selectionProc */
142    NULL,			/* insertProc */
143    NULL,			/* dTextProc */
144    NULL,			/* nextPtr */
145};
146
147/*
148 *--------------------------------------------------------------
149 *
150 * TkcCreateBitmap --
151 *
152 *	This function is invoked to create a new bitmap item in a canvas.
153 *
154 * Results:
155 *	A standard Tcl return value. If an error occurred in creating the
156 *	item, then an error message is left in the interp's result; in this
157 *	case itemPtr is left uninitialized, so it can be safely freed by the
158 *	caller.
159 *
160 * Side effects:
161 *	A new bitmap item is created.
162 *
163 *--------------------------------------------------------------
164 */
165
166static int
167TkcCreateBitmap(
168    Tcl_Interp *interp,		/* Interpreter for error reporting. */
169    Tk_Canvas canvas,		/* Canvas to hold new item. */
170    Tk_Item *itemPtr,		/* Record to hold new item; header has been
171				 * initialized by caller. */
172    int objc,			/* Number of arguments in objv. */
173    Tcl_Obj *CONST objv[])	/* Arguments describing rectangle. */
174{
175    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
176    int i;
177
178    if (objc == 0) {
179	Tcl_Panic("canvas did not pass any coords\n");
180    }
181
182    /*
183     * Initialize item's record.
184     */
185
186    bmapPtr->anchor = TK_ANCHOR_CENTER;
187    bmapPtr->bitmap = None;
188    bmapPtr->activeBitmap = None;
189    bmapPtr->disabledBitmap = None;
190    bmapPtr->fgColor = NULL;
191    bmapPtr->activeFgColor = NULL;
192    bmapPtr->disabledFgColor = NULL;
193    bmapPtr->bgColor = NULL;
194    bmapPtr->activeBgColor = NULL;
195    bmapPtr->disabledBgColor = NULL;
196    bmapPtr->gc = None;
197
198    /*
199     * Process the arguments to fill in the item record. Only 1 (list) or 2 (x
200     * y) coords are allowed.
201     */
202
203    if (objc == 1) {
204	i = 1;
205    } else {
206	char *arg = Tcl_GetString(objv[1]);
207	i = 2;
208	if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) {
209	    i = 1;
210	}
211    }
212    if (BitmapCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) {
213	goto error;
214    }
215    if (ConfigureBitmap(interp, canvas, itemPtr, objc-i, objv+i, 0)
216	    == TCL_OK) {
217	return TCL_OK;
218    }
219
220  error:
221    DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
222    return TCL_ERROR;
223}
224
225/*
226 *--------------------------------------------------------------
227 *
228 * BitmapCoords --
229 *
230 *	This function is invoked to process the "coords" widget command on
231 *	bitmap items. See the user documentation for details on what it does.
232 *
233 * Results:
234 *	Returns TCL_OK or TCL_ERROR, and sets the interp's result.
235 *
236 * Side effects:
237 *	The coordinates for the given item may be changed.
238 *
239 *--------------------------------------------------------------
240 */
241
242static int
243BitmapCoords(
244    Tcl_Interp *interp,		/* Used for error reporting. */
245    Tk_Canvas canvas,		/* Canvas containing item. */
246    Tk_Item *itemPtr,		/* Item whose coordinates are to be read or
247				 * modified. */
248    int objc,			/* Number of coordinates supplied in objv. */
249    Tcl_Obj *CONST objv[])	/* Array of coordinates: x1, y1, x2, y2, ... */
250{
251    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
252
253    if (objc == 0) {
254	Tcl_Obj *obj = Tcl_NewObj();
255
256	Tcl_Obj *subobj = Tcl_NewDoubleObj(bmapPtr->x);
257	Tcl_ListObjAppendElement(interp, obj, subobj);
258	subobj = Tcl_NewDoubleObj(bmapPtr->y);
259	Tcl_ListObjAppendElement(interp, obj, subobj);
260	Tcl_SetObjResult(interp, obj);
261    } else if (objc < 3) {
262	if (objc == 1) {
263	    if (Tcl_ListObjGetElements(interp, objv[0], &objc,
264		    (Tcl_Obj ***) &objv) != TCL_OK) {
265		return TCL_ERROR;
266	    } else if (objc != 2) {
267		char buf[64 + TCL_INTEGER_SPACE];
268
269		sprintf(buf, "wrong # coordinates: expected 2, got %d", objc);
270		Tcl_SetResult(interp, buf, TCL_VOLATILE);
271		return TCL_ERROR;
272	    }
273	}
274	if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0],
275		&bmapPtr->x) != TCL_OK)
276		|| (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1],
277			&bmapPtr->y) != TCL_OK)) {
278	    return TCL_ERROR;
279	}
280	ComputeBitmapBbox(canvas, bmapPtr);
281    } else {
282	char buf[64 + TCL_INTEGER_SPACE];
283
284	sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc);
285	Tcl_SetResult(interp, buf, TCL_VOLATILE);
286	return TCL_ERROR;
287    }
288    return TCL_OK;
289}
290
291/*
292 *--------------------------------------------------------------
293 *
294 * ConfigureBitmap --
295 *
296 *	This function is invoked to configure various aspects of a bitmap
297 *	item, such as its anchor position.
298 *
299 * Results:
300 *	A standard Tcl result code. If an error occurs, then an error message
301 *	is left in the interp's result.
302 *
303 * Side effects:
304 *	Configuration information may be set for itemPtr.
305 *
306 *--------------------------------------------------------------
307 */
308
309static int
310ConfigureBitmap(
311    Tcl_Interp *interp,		/* Used for error reporting. */
312    Tk_Canvas canvas,		/* Canvas containing itemPtr. */
313    Tk_Item *itemPtr,		/* Bitmap item to reconfigure. */
314    int objc,			/* Number of elements in objv.  */
315    Tcl_Obj *CONST objv[],	/* Arguments describing things to configure. */
316    int flags)			/* Flags to pass to Tk_ConfigureWidget. */
317{
318    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
319    XGCValues gcValues;
320    GC newGC;
321    Tk_Window tkwin;
322    unsigned long mask;
323    XColor *fgColor;
324    XColor *bgColor;
325    Pixmap bitmap;
326    Tk_State state;
327
328    tkwin = Tk_CanvasTkwin(canvas);
329    if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,
330	    (CONST char **) objv, (char *) bmapPtr, flags|TK_CONFIG_OBJS)) {
331	return TCL_ERROR;
332    }
333
334    /*
335     * A few of the options require additional processing, such as those that
336     * determine the graphics context.
337     */
338
339    state = itemPtr->state;
340
341    if (bmapPtr->activeFgColor!=NULL ||
342	    bmapPtr->activeBgColor!=NULL ||
343	    bmapPtr->activeBitmap!=None) {
344	itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
345    } else {
346	itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
347    }
348
349    if (state == TK_STATE_NULL) {
350	state = ((TkCanvas *)canvas)->canvas_state;
351    }
352    if (state == TK_STATE_HIDDEN) {
353	ComputeBitmapBbox(canvas, bmapPtr);
354	return TCL_OK;
355    }
356    fgColor = bmapPtr->fgColor;
357    bgColor = bmapPtr->bgColor;
358    bitmap = bmapPtr->bitmap;
359    if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
360	if (bmapPtr->activeFgColor!=NULL) {
361	    fgColor = bmapPtr->activeFgColor;
362	}
363	if (bmapPtr->activeBgColor!=NULL) {
364	    bgColor = bmapPtr->activeBgColor;
365	}
366	if (bmapPtr->activeBitmap!=None) {
367	    bitmap = bmapPtr->activeBitmap;
368	}
369    } else if (state == TK_STATE_DISABLED) {
370	if (bmapPtr->disabledFgColor!=NULL) {
371	    fgColor = bmapPtr->disabledFgColor;
372	}
373	if (bmapPtr->disabledBgColor!=NULL) {
374	    bgColor = bmapPtr->disabledBgColor;
375	}
376	if (bmapPtr->disabledBitmap!=None) {
377	    bitmap = bmapPtr->disabledBitmap;
378	}
379    }
380
381    if (bitmap == None) {
382	newGC = None;
383    } else {
384	gcValues.foreground = fgColor->pixel;
385	mask = GCForeground;
386	if (bgColor != NULL) {
387	    gcValues.background = bgColor->pixel;
388	    mask |= GCBackground;
389	} else {
390	    gcValues.clip_mask = bitmap;
391	    mask |= GCClipMask;
392	}
393	newGC = Tk_GetGC(tkwin, mask, &gcValues);
394    }
395    if (bmapPtr->gc != None) {
396	Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc);
397    }
398    bmapPtr->gc = newGC;
399
400    ComputeBitmapBbox(canvas, bmapPtr);
401    return TCL_OK;
402}
403
404/*
405 *--------------------------------------------------------------
406 *
407 * DeleteBitmap --
408 *
409 *	This function is called to clean up the data structure associated with
410 *	a bitmap item.
411 *
412 * Results:
413 *	None.
414 *
415 * Side effects:
416 *	Resources associated with itemPtr are released.
417 *
418 *--------------------------------------------------------------
419 */
420
421static void
422DeleteBitmap(
423    Tk_Canvas canvas,		/* Info about overall canvas widget. */
424    Tk_Item *itemPtr,		/* Item that is being deleted. */
425    Display *display)		/* Display containing window for canvas. */
426{
427    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
428
429    if (bmapPtr->bitmap != None) {
430	Tk_FreeBitmap(display, bmapPtr->bitmap);
431    }
432    if (bmapPtr->activeBitmap != None) {
433	Tk_FreeBitmap(display, bmapPtr->activeBitmap);
434    }
435    if (bmapPtr->disabledBitmap != None) {
436	Tk_FreeBitmap(display, bmapPtr->disabledBitmap);
437    }
438    if (bmapPtr->fgColor != NULL) {
439	Tk_FreeColor(bmapPtr->fgColor);
440    }
441    if (bmapPtr->activeFgColor != NULL) {
442	Tk_FreeColor(bmapPtr->activeFgColor);
443    }
444    if (bmapPtr->disabledFgColor != NULL) {
445	Tk_FreeColor(bmapPtr->disabledFgColor);
446    }
447    if (bmapPtr->bgColor != NULL) {
448	Tk_FreeColor(bmapPtr->bgColor);
449    }
450    if (bmapPtr->activeBgColor != NULL) {
451	Tk_FreeColor(bmapPtr->activeBgColor);
452    }
453    if (bmapPtr->disabledBgColor != NULL) {
454	Tk_FreeColor(bmapPtr->disabledBgColor);
455    }
456    if (bmapPtr->gc != NULL) {
457	Tk_FreeGC(display, bmapPtr->gc);
458    }
459}
460
461/*
462 *--------------------------------------------------------------
463 *
464 * ComputeBitmapBbox --
465 *
466 *	This function is invoked to compute the bounding box of all the pixels
467 *	that may be drawn as part of a bitmap item. This function is where the
468 *	child bitmap's placement is computed.
469 *
470 * Results:
471 *	None.
472 *
473 * Side effects:
474 *	The fields x1, y1, x2, and y2 are updated in the header for itemPtr.
475 *
476 *--------------------------------------------------------------
477 */
478
479	/* ARGSUSED */
480static void
481ComputeBitmapBbox(
482    Tk_Canvas canvas,		/* Canvas that contains item. */
483    BitmapItem *bmapPtr)	/* Item whose bbox is to be recomputed. */
484{
485    int width, height;
486    int x, y;
487    Pixmap bitmap;
488    Tk_State state = bmapPtr->header.state;
489
490    if (state == TK_STATE_NULL) {
491	state = ((TkCanvas *)canvas)->canvas_state;
492    }
493    bitmap = bmapPtr->bitmap;
494    if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)bmapPtr) {
495	if (bmapPtr->activeBitmap!=None) {
496	    bitmap = bmapPtr->activeBitmap;
497	}
498    } else if (state==TK_STATE_DISABLED) {
499	if (bmapPtr->disabledBitmap!=None) {
500	    bitmap = bmapPtr->disabledBitmap;
501	}
502    }
503
504    x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5));
505    y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5));
506
507    if (state==TK_STATE_HIDDEN || bitmap == None) {
508	bmapPtr->header.x1 = bmapPtr->header.x2 = x;
509	bmapPtr->header.y1 = bmapPtr->header.y2 = y;
510	return;
511    }
512
513    /*
514     * Compute location and size of bitmap, using anchor information.
515     */
516
517    Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap,
518	    &width, &height);
519    switch (bmapPtr->anchor) {
520    case TK_ANCHOR_N:
521	x -= width/2;
522	break;
523    case TK_ANCHOR_NE:
524	x -= width;
525	break;
526    case TK_ANCHOR_E:
527	x -= width;
528	y -= height/2;
529	break;
530    case TK_ANCHOR_SE:
531	x -= width;
532	y -= height;
533	break;
534    case TK_ANCHOR_S:
535	x -= width/2;
536	y -= height;
537	break;
538    case TK_ANCHOR_SW:
539	y -= height;
540	break;
541    case TK_ANCHOR_W:
542	y -= height/2;
543	break;
544    case TK_ANCHOR_NW:
545	break;
546    case TK_ANCHOR_CENTER:
547	x -= width/2;
548	y -= height/2;
549	break;
550    }
551
552    /*
553     * Store the information in the item header.
554     */
555
556    bmapPtr->header.x1 = x;
557    bmapPtr->header.y1 = y;
558    bmapPtr->header.x2 = x + width;
559    bmapPtr->header.y2 = y + height;
560}
561
562/*
563 *--------------------------------------------------------------
564 *
565 * DisplayBitmap --
566 *
567 *	This function is invoked to draw a bitmap item in a given drawable.
568 *
569 * Results:
570 *	None.
571 *
572 * Side effects:
573 *	ItemPtr is drawn in drawable using the transformation information in
574 *	canvas.
575 *
576 *--------------------------------------------------------------
577 */
578
579static void
580DisplayBitmap(
581    Tk_Canvas canvas,		/* Canvas that contains item. */
582    Tk_Item *itemPtr,		/* Item to be displayed. */
583    Display *display,		/* Display on which to draw item. */
584    Drawable drawable,		/* Pixmap or window in which to draw item. */
585    int x, int y, int width, int height)
586				/* Describes region of canvas that must be
587				 * redisplayed (not used). */
588{
589    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
590    int bmapX, bmapY, bmapWidth, bmapHeight;
591    short drawableX, drawableY;
592    Pixmap bitmap;
593    Tk_State state = itemPtr->state;
594
595    /*
596     * If the area being displayed doesn't cover the whole bitmap, then only
597     * redisplay the part of the bitmap that needs redisplay.
598     */
599
600    if (state == TK_STATE_NULL) {
601	state = ((TkCanvas *)canvas)->canvas_state;
602    }
603    bitmap = bmapPtr->bitmap;
604    if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
605	if (bmapPtr->activeBitmap!=None) {
606	    bitmap = bmapPtr->activeBitmap;
607	}
608    } else if (state == TK_STATE_DISABLED) {
609	if (bmapPtr->disabledBitmap!=None) {
610	    bitmap = bmapPtr->disabledBitmap;
611	}
612    }
613
614    if (bitmap != None) {
615	if (x > bmapPtr->header.x1) {
616	    bmapX = x - bmapPtr->header.x1;
617	    bmapWidth = bmapPtr->header.x2 - x;
618	} else {
619	    bmapX = 0;
620	    if ((x+width) < bmapPtr->header.x2) {
621		bmapWidth = x + width - bmapPtr->header.x1;
622	    } else {
623		bmapWidth = bmapPtr->header.x2 - bmapPtr->header.x1;
624	    }
625	}
626	if (y > bmapPtr->header.y1) {
627	    bmapY = y - bmapPtr->header.y1;
628	    bmapHeight = bmapPtr->header.y2 - y;
629	} else {
630	    bmapY = 0;
631	    if ((y+height) < bmapPtr->header.y2) {
632		bmapHeight = y + height - bmapPtr->header.y1;
633	    } else {
634		bmapHeight = bmapPtr->header.y2 - bmapPtr->header.y1;
635	    }
636	}
637	Tk_CanvasDrawableCoords(canvas,
638		(double) (bmapPtr->header.x1 + bmapX),
639		(double) (bmapPtr->header.y1 + bmapY),
640		&drawableX, &drawableY);
641
642	/*
643	 * Must modify the mask origin within the graphics context to line up
644	 * with the bitmap's origin (in order to make bitmaps with
645	 * "-background {}" work right).
646	 */
647
648	XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX,
649		drawableY - bmapY);
650	XCopyPlane(display, bitmap, drawable,
651		bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth,
652		(unsigned int) bmapHeight, drawableX, drawableY, 1);
653	XSetClipOrigin(display, bmapPtr->gc, 0, 0);
654    }
655}
656
657/*
658 *--------------------------------------------------------------
659 *
660 * BitmapToPoint --
661 *
662 *	Computes the distance from a given point to a given rectangle, in
663 *	canvas units.
664 *
665 * Results:
666 *	The return value is 0 if the point whose x and y coordinates are
667 *	coordPtr[0] and coordPtr[1] is inside the bitmap. If the point isn't
668 *	inside the bitmap then the return value is the distance from the point
669 *	to the bitmap.
670 *
671 * Side effects:
672 *	None.
673 *
674 *--------------------------------------------------------------
675 */
676
677	/* ARGSUSED */
678static double
679BitmapToPoint(
680    Tk_Canvas canvas,		/* Canvas containing item. */
681    Tk_Item *itemPtr,		/* Item to check against point. */
682    double *coordPtr)		/* Pointer to x and y coordinates. */
683{
684    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
685    double x1, x2, y1, y2, xDiff, yDiff;
686
687    x1 = bmapPtr->header.x1;
688    y1 = bmapPtr->header.y1;
689    x2 = bmapPtr->header.x2;
690    y2 = bmapPtr->header.y2;
691
692    /*
693     * Point is outside rectangle.
694     */
695
696    if (coordPtr[0] < x1) {
697	xDiff = x1 - coordPtr[0];
698    } else if (coordPtr[0] > x2)  {
699	xDiff = coordPtr[0] - x2;
700    } else {
701	xDiff = 0;
702    }
703
704    if (coordPtr[1] < y1) {
705	yDiff = y1 - coordPtr[1];
706    } else if (coordPtr[1] > y2)  {
707	yDiff = coordPtr[1] - y2;
708    } else {
709	yDiff = 0;
710    }
711
712    return hypot(xDiff, yDiff);
713}
714
715/*
716 *--------------------------------------------------------------
717 *
718 * BitmapToArea --
719 *
720 *	This function is called to determine whether an item lies entirely
721 *	inside, entirely outside, or overlapping a given rectangle.
722 *
723 * Results:
724 *	-1 is returned if the item is entirely outside the area given by
725 *	rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given
726 *	area.
727 *
728 * Side effects:
729 *	None.
730 *
731 *--------------------------------------------------------------
732 */
733
734	/* ARGSUSED */
735static int
736BitmapToArea(
737    Tk_Canvas canvas,		/* Canvas containing item. */
738    Tk_Item *itemPtr,		/* Item to check against rectangle. */
739    double *rectPtr)		/* Pointer to array of four coordinates
740				 * (x1,y1,x2,y2) describing rectangular
741				 * area. */
742{
743    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
744
745    if ((rectPtr[2] <= bmapPtr->header.x1)
746	    || (rectPtr[0] >= bmapPtr->header.x2)
747	    || (rectPtr[3] <= bmapPtr->header.y1)
748	    || (rectPtr[1] >= bmapPtr->header.y2)) {
749	return -1;
750    }
751    if ((rectPtr[0] <= bmapPtr->header.x1)
752	    && (rectPtr[1] <= bmapPtr->header.y1)
753	    && (rectPtr[2] >= bmapPtr->header.x2)
754	    && (rectPtr[3] >= bmapPtr->header.y2)) {
755	return 1;
756    }
757    return 0;
758}
759
760/*
761 *--------------------------------------------------------------
762 *
763 * ScaleBitmap --
764 *
765 *	This function is invoked to rescale a bitmap item in a canvas. It is
766 *	one of the standard item functions for bitmap items, and is invoked by
767 *	the generic canvas code.
768 *
769 * Results:
770 *	None.
771 *
772 * Side effects:
773 *	The item referred to by itemPtr is rescaled so that the following
774 *	transformation is applied to all point coordinates:
775 *		x' = originX + scaleX*(x-originX)
776 *		y' = originY + scaleY*(y-originY)
777 *
778 *--------------------------------------------------------------
779 */
780
781static void
782ScaleBitmap(
783    Tk_Canvas canvas,		/* Canvas containing rectangle. */
784    Tk_Item *itemPtr,		/* Rectangle to be scaled. */
785    double originX, double originY,
786				/* Origin about which to scale item. */
787    double scaleX,		/* Amount to scale in X direction. */
788    double scaleY)		/* Amount to scale in Y direction. */
789{
790    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
791
792    bmapPtr->x = originX + scaleX*(bmapPtr->x - originX);
793    bmapPtr->y = originY + scaleY*(bmapPtr->y - originY);
794    ComputeBitmapBbox(canvas, bmapPtr);
795}
796
797/*
798 *--------------------------------------------------------------
799 *
800 * TranslateBitmap --
801 *
802 *	This function is called to move an item by a given amount.
803 *
804 * Results:
805 *	None.
806 *
807 * Side effects:
808 *	The position of the item is offset by (xDelta, yDelta), and the
809 *	bounding box is updated in the generic part of the item structure.
810 *
811 *--------------------------------------------------------------
812 */
813
814static void
815TranslateBitmap(
816    Tk_Canvas canvas,		/* Canvas containing item. */
817    Tk_Item *itemPtr,		/* Item that is being moved. */
818    double deltaX, double deltaY)
819				/* Amount by which item is to be moved. */
820{
821    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
822
823    bmapPtr->x += deltaX;
824    bmapPtr->y += deltaY;
825    ComputeBitmapBbox(canvas, bmapPtr);
826}
827
828/*
829 *--------------------------------------------------------------
830 *
831 * BitmapToPostscript --
832 *
833 *	This function is called to generate Postscript for bitmap items.
834 *
835 * Results:
836 *	The return value is a standard Tcl result. If an error occurs in
837 *	generating Postscript then an error message is left in the interp's
838 *	result, replacing whatever used to be there. If no error occurs, then
839 *	Postscript for the item is appended to the result.
840 *
841 * Side effects:
842 *	None.
843 *
844 *--------------------------------------------------------------
845 */
846
847static int
848BitmapToPostscript(
849    Tcl_Interp *interp,		/* Leave Postscript or error message here. */
850    Tk_Canvas canvas,		/* Information about overall canvas. */
851    Tk_Item *itemPtr,		/* Item for which Postscript is wanted. */
852    int prepass)		/* 1 means this is a prepass to collect font
853				 * information; 0 means final Postscript is
854				 * being created. */
855{
856    BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
857    double x, y;
858    int width, height, rowsAtOnce, rowsThisTime;
859    int curRow;
860    char buffer[100 + TCL_DOUBLE_SPACE * 2 + TCL_INTEGER_SPACE * 4];
861    XColor *fgColor;
862    XColor *bgColor;
863    Pixmap bitmap;
864    Tk_State state = itemPtr->state;
865
866    if (state == TK_STATE_NULL) {
867	state = ((TkCanvas *)canvas)->canvas_state;
868    }
869    fgColor = bmapPtr->fgColor;
870    bgColor = bmapPtr->bgColor;
871    bitmap = bmapPtr->bitmap;
872    if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
873	if (bmapPtr->activeFgColor!=NULL) {
874	    fgColor = bmapPtr->activeFgColor;
875	}
876	if (bmapPtr->activeBgColor!=NULL) {
877	    bgColor = bmapPtr->activeBgColor;
878	}
879	if (bmapPtr->activeBitmap!=None) {
880	    bitmap = bmapPtr->activeBitmap;
881	}
882    } else if (state == TK_STATE_DISABLED) {
883	if (bmapPtr->disabledFgColor!=NULL) {
884	    fgColor = bmapPtr->disabledFgColor;
885	}
886	if (bmapPtr->disabledBgColor!=NULL) {
887	    bgColor = bmapPtr->disabledBgColor;
888	}
889	if (bmapPtr->disabledBitmap!=None) {
890	    bitmap = bmapPtr->disabledBitmap;
891	}
892    }
893
894    if (bitmap == None) {
895	return TCL_OK;
896    }
897
898    /*
899     * Compute the coordinates of the lower-left corner of the bitmap, taking
900     * into account the anchor position for the bitmp.
901     */
902
903    x = bmapPtr->x;
904    y = Tk_CanvasPsY(canvas, bmapPtr->y);
905    Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap,
906	    &width, &height);
907    switch (bmapPtr->anchor) {
908    case TK_ANCHOR_NW:			   y -= height;		break;
909    case TK_ANCHOR_N:	   x -= width/2.0; y -= height;		break;
910    case TK_ANCHOR_NE:	   x -= width;	   y -= height;		break;
911    case TK_ANCHOR_E:	   x -= width;	   y -= height/2.0;	break;
912    case TK_ANCHOR_SE:	   x -= width;				break;
913    case TK_ANCHOR_S:	   x -= width/2.0;			break;
914    case TK_ANCHOR_SW:						break;
915    case TK_ANCHOR_W:			   y -= height/2.0;	break;
916    case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0;	break;
917    }
918
919    /*
920     * Color the background, if there is one.
921     */
922
923    if (bgColor != NULL) {
924	sprintf(buffer,
925		"%.15g %.15g moveto %d 0 rlineto 0 %d rlineto %d %s\n",
926		x, y, width, height, -width, "0 rlineto closepath");
927	Tcl_AppendResult(interp, buffer, NULL);
928	if (Tk_CanvasPsColor(interp, canvas, bgColor) != TCL_OK) {
929	    return TCL_ERROR;
930	}
931	Tcl_AppendResult(interp, "fill\n", NULL);
932    }
933
934    /*
935     * Draw the bitmap, if there is a foreground color. If the bitmap is very
936     * large, then chop it up into multiple bitmaps, each consisting of one or
937     * more rows. This is needed because Postscript can't handle single
938     * strings longer than 64 KBytes long.
939     */
940
941    if (fgColor != NULL) {
942	if (Tk_CanvasPsColor(interp, canvas, fgColor) != TCL_OK) {
943	    return TCL_ERROR;
944	}
945	if (width > 60000) {
946	    Tcl_ResetResult(interp);
947	    Tcl_AppendResult(interp, "can't generate Postscript",
948		    " for bitmaps more than 60000 pixels wide", NULL);
949	    return TCL_ERROR;
950	}
951	rowsAtOnce = 60000/width;
952	if (rowsAtOnce < 1) {
953	    rowsAtOnce = 1;
954	}
955	sprintf(buffer, "%.15g %.15g translate\n", x, y+height);
956	Tcl_AppendResult(interp, buffer, NULL);
957	for (curRow = 0; curRow < height; curRow += rowsAtOnce) {
958	    rowsThisTime = rowsAtOnce;
959	    if (rowsThisTime > (height - curRow)) {
960		rowsThisTime = height - curRow;
961	    }
962	    sprintf(buffer, "0 -%.15g translate\n%d %d true matrix {\n",
963		    (double) rowsThisTime, width, rowsThisTime);
964	    Tcl_AppendResult(interp, buffer, NULL);
965	    if (Tk_CanvasPsBitmap(interp, canvas, bitmap,
966		    0, curRow, width, rowsThisTime) != TCL_OK) {
967		return TCL_ERROR;
968	    }
969	    Tcl_AppendResult(interp, "\n} imagemask\n", NULL);
970	}
971    }
972    return TCL_OK;
973}
974
975/*
976 * Local Variables:
977 * mode: c
978 * c-basic-offset: 4
979 * fill-column: 78
980 * End:
981 */
982