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