source: branches/1.3/gui/src/RpCanvPlacard.c @ 3877

Last change on this file since 3877 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 50.3 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpCanvPlacard - canvas item with text and background box
4 *
5 *  This canvas item makes it easy to create a box with text inside.
6 *  The box is normally stretched around the text, but can be given
7 *  a max size and causing text to be clipped.
8 *
9 *    .c create placard <x> <y> -anchor <nsew> \
10 *        -text <text>         << text to be displayed
11 *        -font <name>         << font used for text
12 *        -imageleft <image>   << image displayed on the left of text
13 *        -imageright <image>  << image displayed on the right of text
14 *        -maxwidth <size>     << maximum size
15 *        -textcolor <color>   << text color
16 *        -background <color>  << fill for rect behind text
17 *        -outline <color>     << outline around text
18 *        -borderwidth <size>  << for 3D border
19 *        -relief <value>      << for 3D border (drawn under -outline)
20 *        -tags <taglist>      << usual Tk canvas tags
21 *
22 * ======================================================================
23 *  AUTHOR:  Michael McLennan, Purdue University
24 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
25 *
26 *  See the file "license.terms" for information on usage and
27 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
28 * ======================================================================
29 */
30#include <string.h>
31#include <math.h>
32#include "tk.h"
33
34/* used for text within the placard that needs to be truncated */
35#define ellipsis_width 9
36#define ellipsis_height 1
37static unsigned char ellipsis_bits[] = {
38   0x92, 0x00};
39
40/*
41 * Record for each placard item:
42 */
43typedef struct PlacardItem  {
44    Tk_Item header;             /* Generic stuff that's the same for all
45                                 * types.  MUST BE FIRST IN STRUCTURE. */
46    Tcl_Interp *interp;         /* Interp that owns this item */
47    Tk_Window tkwin;            /* Window that represents this canvas */
48    Tk_Canvas canvas;           /* Canvas that owns this item */
49    Pixmap dots;                /* ellipsis used for truncated text */
50
51    /*
52     * Fields that are set by widget commands other than "configure":
53     */
54    double x, y;                /* Positioning point for text */
55
56    /*
57     * Configuration settings that are updated by Tk_ConfigureWidget:
58     */
59    char *text;                 /* text to be displayed */
60    Tk_Anchor anchor;           /* Where to anchor text relative to (x,y) */
61    XColor *textColor;          /* Color for text */
62    XColor *lineColor;          /* Color for outline of rectangle */
63    Tk_3DBorder bgBorder;       /* used for drawing background rectangle */
64    Tk_Font tkfont;             /* Font for drawing text */
65    int width;                  /* Fixed width for placard (0 = not set) */
66    int maxWidth;               /* Maximum overall width for placard */
67    int borderWidth;            /* supports 3D border (drawn under -outline) */
68    int relief;                 /* indicates whether placard as a whole is
69                                 * raised, sunken, or flat */
70    int padding;                /* Padding around text and images */
71
72    char *imageLeftString;      /* Name of image displayed on the left */
73    char *imageRightString;     /* Name of image displayed on the right */
74 
75    /*
76     * Fields whose values are derived from the current values of the
77     * configuration settings above:
78     */
79    int textNumChars;           /* Length of text in characters. */
80    int textNumBytes;           /* Length of text in bytes. */
81    int textDrawChars;          /* Same as textNumChars or shorter, if
82                                 * text is too long for -maxwidth */
83    int textWidth;              /* Overall width of text (perhaps truncated)
84                                 * in pixels */
85    Tk_TextLayout textLayout;   /* Cached text layout information for value */
86
87    Tk_Image imageLeft;         /* icon drawn to left of text */
88    int imageLeftW;             /* width of image (if image is not NULL) */
89    int imageLeftH;             /* height of image (if image is not NULL) */
90
91    Tk_Image imageRight;        /* icon drawn to right of text */
92    int imageRightW;            /* width of image (if image is not NULL) */
93    int imageRightH;            /* height of image (if image is not NULL) */
94
95    int leftEdge;               /* Pixel location of the left edge of the
96                                 * item. (Where the left border of the
97                                 * text layout is drawn.) */
98    int rightEdge;              /* Pixel just to right of right edge of
99                                 * area of text item. */
100    GC gcText;                  /* Graphics context for drawing text. */
101    GC gcLineRect;              /* Graphics context for rectangle outline. */
102} PlacardItem;
103
104/*
105 * Information used for parsing configuration specs:
106 */
107static Tk_CustomOption tagsOption = {
108    (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
109    Tk_CanvasTagsPrintProc, (ClientData) NULL
110};
111
112static Tk_ConfigSpec configSpecs[] = {
113    {TK_CONFIG_ANCHOR, "-anchor", (char*)NULL, (char*)NULL,
114        "center", Tk_Offset(PlacardItem, anchor),
115        TK_CONFIG_DONT_SET_DEFAULT},
116    {TK_CONFIG_BORDER, "-background", (char*)NULL, (char*)NULL,
117        "", Tk_Offset(PlacardItem, bgBorder), TK_CONFIG_NULL_OK},
118    {TK_CONFIG_PIXELS, "-borderwidth", (char*)NULL, (char*)NULL,
119        "0", Tk_Offset(PlacardItem, borderWidth), 0},
120    {TK_CONFIG_FONT, "-font", (char*)NULL, (char*)NULL,
121        "helvetica -12", Tk_Offset(PlacardItem, tkfont), 0},
122    {TK_CONFIG_COLOR, "-foreground", (char*)NULL, (char*)NULL,
123        "black", Tk_Offset(PlacardItem, textColor), TK_CONFIG_NULL_OK},
124    {TK_CONFIG_STRING, "-imageleft", (char*)NULL, (char*)NULL,
125        (char*)NULL, Tk_Offset(PlacardItem, imageLeftString),
126        TK_CONFIG_NULL_OK},
127    {TK_CONFIG_STRING, "-imageright", (char*)NULL, (char*)NULL,
128        (char*)NULL, Tk_Offset(PlacardItem, imageRightString),
129        TK_CONFIG_NULL_OK},
130    {TK_CONFIG_PIXELS, "-maxwidth", (char*)NULL, (char*)NULL,
131        "0", Tk_Offset(PlacardItem, maxWidth), 0},
132    {TK_CONFIG_COLOR, "-outline", (char*)NULL, (char*)NULL,
133        "", Tk_Offset(PlacardItem, lineColor), TK_CONFIG_NULL_OK},
134    {TK_CONFIG_PIXELS, "-padding", (char*)NULL, (char*)NULL,
135        "4", Tk_Offset(PlacardItem, padding), 0},
136    {TK_CONFIG_RELIEF, "-relief", (char*)NULL, (char*)NULL,
137        "flat", Tk_Offset(PlacardItem, relief), 0},
138    {TK_CONFIG_CUSTOM, "-tags", (char*)NULL, (char*)NULL,
139        (char*)NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
140    {TK_CONFIG_STRING, "-text", (char*)NULL, (char*)NULL,
141        "", Tk_Offset(PlacardItem, text), 0},
142    {TK_CONFIG_PIXELS, "-width", (char*)NULL, (char*)NULL,
143        "0", Tk_Offset(PlacardItem, width), 0},
144    {TK_CONFIG_END, (char*)NULL, (char*)NULL, (char*)NULL,
145        (char*)NULL, 0, 0}
146};
147
148/*
149 * Prototypes for procedures defined in this file
150 */
151static void ComputePlacardBbox _ANSI_ARGS_((Tk_Canvas canvas,
152    PlacardItem *plPtr));
153static int ConfigurePlacard _ANSI_ARGS_((Tcl_Interp *interp,
154    Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
155    Tcl_Obj *CONST argv[], int flags));
156static int CreatePlacard _ANSI_ARGS_((Tcl_Interp *interp,
157    Tk_Canvas canvas, struct Tk_Item *itemPtr,
158    int argc, Tcl_Obj *CONST argv[]));
159static void DeletePlacard _ANSI_ARGS_((Tk_Canvas canvas,
160    Tk_Item *itemPtr, Display *display));
161static void DisplayCanvPlacard _ANSI_ARGS_((Tk_Canvas canvas,
162    Tk_Item *itemPtr, Display *display, Drawable dst,
163    int x, int y, int width, int height));
164static void ScalePlacard _ANSI_ARGS_((Tk_Canvas canvas,
165    Tk_Item *itemPtr, double originX, double originY,
166    double scaleX, double scaleY));
167static void TranslatePlacard _ANSI_ARGS_((Tk_Canvas canvas,
168    Tk_Item *itemPtr, double deltaX, double deltaY));
169static int PlacardCoords _ANSI_ARGS_((Tcl_Interp *interp,
170    Tk_Canvas canvas, Tk_Item *itemPtr,
171    int argc, Tcl_Obj *CONST argv[]));
172static int PlacardToArea _ANSI_ARGS_((Tk_Canvas canvas,
173    Tk_Item *itemPtr, double *rectPtr));
174static double PlacardToPoint _ANSI_ARGS_((Tk_Canvas canvas,
175    Tk_Item *itemPtr, double *pointPtr));
176static int PlacardToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
177    Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
178
179static void ImageLeftChangedProc _ANSI_ARGS_((ClientData clientData,
180    int x, int y, int width, int height, int imgWidth,
181    int imgHeight));
182static void ImageRightChangedProc _ANSI_ARGS_((ClientData clientData,
183    int x, int y, int width, int height, int imgWidth,
184    int imgHeight));
185
186/*
187 * The structures below defines the canvas item type:
188 */
189Tk_ItemType rpPlacardType = {
190    "placard",                          /* name */
191    sizeof(PlacardItem),                /* itemSize */
192    CreatePlacard,                      /* createProc */
193    configSpecs,                        /* configSpecs */
194    ConfigurePlacard,                   /* configureProc */
195    PlacardCoords,                      /* coordProc */
196    DeletePlacard,                      /* deleteProc */
197    DisplayCanvPlacard,                 /* displayProc */
198    TK_CONFIG_OBJS,                     /* flags */
199    PlacardToPoint,                     /* pointProc */
200    PlacardToArea,                      /* areaProc */
201    PlacardToPostscript,                /* postscriptProc */
202    ScalePlacard,                       /* scaleProc */
203    TranslatePlacard,                   /* translateProc */
204    (Tk_ItemIndexProc *) NULL,          /* indexProc */
205    (Tk_ItemCursorProc *) NULL,         /* icursorProc */
206    (Tk_ItemSelectionProc *) NULL,      /* selectionProc */
207    (Tk_ItemInsertProc *) NULL,         /* insertProc */
208    (Tk_ItemDCharsProc *) NULL,         /* dTextProc */
209    (Tk_ItemType *) NULL,               /* nextPtr */
210};
211
212/*
213 * The record below describes a canvas widget.  It is made available
214 * to the item procedures so they can access certain shared fields such
215 * as the overall displacement and scale factor for the canvas.
216 */
217
218typedef struct TkCanvas {
219    Tk_Window tkwin;            /* Window that embodies the canvas.  NULL
220                                 * means that the window has been destroyed
221                                 * but the data structures haven't yet been
222                                 * cleaned up.*/
223    Display *display;           /* Display containing widget;  needed, among
224                                 * other things, to release resources after
225                                 * tkwin has already gone away. */
226    Tcl_Interp *interp;         /* Interpreter associated with canvas. */
227    Tcl_Command widgetCmd;      /* Token for canvas's widget command. */
228    Tk_Item *firstItemPtr;      /* First in list of all items in canvas,
229                                 * or NULL if canvas empty. */
230    Tk_Item *lastItemPtr;       /* Last in list of all items in canvas,
231                                 * or NULL if canvas empty. */
232
233    /*
234     * Information used when displaying widget:
235     */
236
237    int borderWidth;            /* Width of 3-D border around window. */
238    Tk_3DBorder bgBorder;       /* Used for canvas background. */
239    int relief;                 /* Indicates whether window as a whole is
240                                 * raised, sunken, or flat. */
241    int highlightWidth;         /* Width in pixels of highlight to draw
242                                 * around widget when it has the focus.
243                                 * <= 0 means don't draw a highlight. */
244    XColor *highlightBgColorPtr;
245                                /* Color for drawing traversal highlight
246                                 * area when highlight is off. */
247    XColor *highlightColorPtr;  /* Color for drawing traversal highlight. */
248    int inset;                  /* Total width of all borders, including
249                                 * traversal highlight and 3-D border.
250                                 * Indicates how much interior stuff must
251                                 * be offset from outside edges to leave
252                                 * room for borders. */
253    GC pixmapGC;                /* Used to copy bits from a pixmap to the
254                                 * screen and also to clear the pixmap. */
255    int width, height;          /* Dimensions to request for canvas window,
256                                 * specified in pixels. */
257    int redrawX1, redrawY1;     /* Upper left corner of area to redraw,
258                                 * in pixel coordinates.  Border pixels
259                                 * are included.  Only valid if
260                                 * REDRAW_PENDING flag is set. */
261    int redrawX2, redrawY2;     /* Lower right corner of area to redraw,
262                                 * in integer canvas coordinates.  Border
263                                 * pixels will *not* be redrawn. */
264    int confine;                /* Non-zero means constrain view to keep
265                                 * as much of canvas visible as possible. */
266
267    /*
268     * Information used to manage the selection and insertion cursor:
269     */
270
271    Tk_CanvasTextInfo textInfo; /* Contains lots of fields;  see tk.h for
272                                 * details.  This structure is shared with
273                                 * the code that implements individual items. */
274    int insertOnTime;           /* Number of milliseconds cursor should spend
275                                 * in "on" state for each blink. */
276    int insertOffTime;          /* Number of milliseconds cursor should spend
277                                 * in "off" state for each blink. */
278    Tcl_TimerToken insertBlinkHandler;
279                                /* Timer handler used to blink cursor on and
280                                 * off. */
281
282    /*
283     * Transformation applied to canvas as a whole:  to compute screen
284     * coordinates (X,Y) from canvas coordinates (x,y), do the following:
285     *
286     * X = x - xOrigin;
287     * Y = y - yOrigin;
288     */
289
290    int xOrigin, yOrigin;       /* Canvas coordinates corresponding to
291                                 * upper-left corner of window, given in
292                                 * canvas pixel units. */
293    int drawableXOrigin, drawableYOrigin;
294                                /* During redisplay, these fields give the
295                                 * canvas coordinates corresponding to
296                                 * the upper-left corner of the drawable
297                                 * where items are actually being drawn
298                                 * (typically a pixmap smaller than the
299                                 * whole window). */
300
301    /*
302     * Information used for event bindings associated with items.
303     */
304
305    Tk_BindingTable bindingTable;
306                                /* Table of all bindings currently defined
307                                 * for this canvas.  NULL means that no
308                                 * bindings exist, so the table hasn't been
309                                 * created.  Each "object" used for this
310                                 * table is either a Tk_Uid for a tag or
311                                 * the address of an item named by id. */
312    Tk_Item *currentItemPtr;    /* The item currently containing the mouse
313                                 * pointer, or NULL if none. */
314    Tk_Item *newCurrentPtr;     /* The item that is about to become the
315                                 * current one, or NULL.  This field is
316                                 * used to detect deletions  of the new
317                                 * current item pointer that occur during
318                                 * Leave processing of the previous current
319                                 * item.  */
320    double closeEnough;         /* The mouse is assumed to be inside an
321                                 * item if it is this close to it. */
322    XEvent pickEvent;           /* The event upon which the current choice
323                                 * of currentItem is based.  Must be saved
324                                 * so that if the currentItem is deleted,
325                                 * can pick another. */
326    int state;                  /* Last known modifier state.  Used to
327                                 * defer picking a new current object
328                                 * while buttons are down. */
329
330    /*
331     * Information used for managing scrollbars:
332     */
333
334    char *xScrollCmd;           /* Command prefix for communicating with
335                                 * horizontal scrollbar.  NULL means no
336                                 * horizontal scrollbar.  Malloc'ed*/
337    char *yScrollCmd;           /* Command prefix for communicating with
338                                 * vertical scrollbar.  NULL means no
339                                 * vertical scrollbar.  Malloc'ed*/
340    int scrollX1, scrollY1, scrollX2, scrollY2;
341                                /* These four coordinates define the region
342                                 * that is the 100% area for scrolling (i.e.
343                                 * these numbers determine the size and
344                                 * location of the sliders on scrollbars).
345                                 * Units are pixels in canvas coords. */
346    char *regionString;         /* The option string from which scrollX1
347                                 * etc. are derived.  Malloc'ed. */
348    int xScrollIncrement;       /* If >0, defines a grid for horizontal
349                                 * scrolling.  This is the size of the "unit",
350                                 * and the left edge of the screen will always
351                                 * lie on an even unit boundary. */
352    int yScrollIncrement;       /* If >0, defines a grid for horizontal
353                                 * scrolling.  This is the size of the "unit",
354                                 * and the left edge of the screen will always
355                                 * lie on an even unit boundary. */
356
357    /*
358     * Information used for scanning:
359     */
360
361    int scanX;                  /* X-position at which scan started (e.g.
362                                 * button was pressed here). */
363    int scanXOrigin;            /* Value of xOrigin field when scan started. */
364    int scanY;                  /* Y-position at which scan started (e.g.
365                                 * button was pressed here). */
366    int scanYOrigin;            /* Value of yOrigin field when scan started. */
367
368    /*
369     * Information used to speed up searches by remembering the last item
370     * created or found with an item id search.
371     */
372
373    Tk_Item *hotPtr;            /* Pointer to "hot" item (one that's been
374                                 * recently used.  NULL means there's no
375                                 * hot item. */
376    Tk_Item *hotPrevPtr;        /* Pointer to predecessor to hotPtr (NULL
377                                 * means item is first in list).  This is
378                                 * only a hint and may not really be hotPtr's
379                                 * predecessor. */
380
381    /*
382     * Miscellaneous information:
383     */
384
385    Tk_Cursor cursor;           /* Current cursor for window, or None. */
386    char *takeFocus;            /* Value of -takefocus option;  not used in
387                                 * the C code, but used by keyboard traversal
388                                 * scripts.  Malloc'ed, but may be NULL. */
389    double pixelsPerMM;         /* Scale factor between MM and pixels;
390                                 * used when converting coordinates. */
391    int flags;                  /* Various flags;  see below for
392                                 * definitions. */
393    int nextId;                 /* Number to use as id for next item
394                                 * created in widget. */
395    Tk_PostscriptInfo psInfo;
396                                /* Pointer to information used for generating
397                                 * Postscript for the canvas.  NULL means
398                                 * no Postscript is currently being
399                                 * generated. */
400    Tcl_HashTable idTable;      /* Table of integer indices. */
401    /*
402     * Additional information, added by the 'dash'-patch
403     */
404    VOID *reserved1;
405    Tk_State canvas_state;      /* state of canvas */
406    VOID *reserved2;
407    VOID *reserved3;
408    Tk_TSOffset tsoffset;
409#ifndef USE_OLD_TAG_SEARCH
410    void *bindTagExprs; /* linked list of tag expressions used in bindings */
411#endif
412} TkCanvas;
413
414
415/*
416 * ------------------------------------------------------------------------
417 *  RpCanvPlacard_Init --
418 *
419 *  Invoked when the Rappture GUI library is being initialized
420 *  to install the "placard" item on the Tk canvas widget.
421 *
422 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
423 *  message in the interp) if anything goes wrong.
424 * ------------------------------------------------------------------------
425 */
426int
427RpCanvPlacard_Init(interp)
428    Tcl_Interp *interp;         /* interpreter being initialized */
429{
430    Tk_CreateItemType(&rpPlacardType);
431
432    Tk_DefineBitmap(interp, Tk_GetUid("rp_ellipsis"),
433        (char*)ellipsis_bits, ellipsis_width, ellipsis_height);
434
435    return TCL_OK;
436}
437
438/*
439 * ------------------------------------------------------------------------
440 *  CreatePlacard --
441 *
442 *    This procedure is invoked to create a new placard item
443 *    in a canvas.  A placard is a text item with a box behind it.
444 *
445 *  Results:
446 *    A standard Tcl return name.  If an error occurred in creating
447 *    the item then an error message is left in the interp's result.
448 *    In this case itemPtr is left uninitialized so it can be safely
449 *    freed by the caller.
450 *
451 *  Side effects:
452 *    A new item is created.
453 * ------------------------------------------------------------------------
454 */
455static int
456CreatePlacard(interp, canvas, itemPtr, argc, argv)
457    Tcl_Interp *interp;           /* interpreter for error reporting */
458    Tk_Canvas canvas;             /* canvas to hold new item */
459    Tk_Item *itemPtr;             /* record to hold new item; header has been
460                                   * initialized by caller */
461    int argc;                     /* number of arguments in argv */
462    Tcl_Obj *CONST argv[];        /* arguments describing item */
463{
464    PlacardItem *plPtr = (PlacardItem *) itemPtr;
465    int i;
466
467    if (argc == 1) {
468        i = 1;
469    } else {
470        char *arg = Tcl_GetStringFromObj(argv[1], NULL);
471        if ((argc > 1) && (arg[0] == '-')
472                && (arg[1] >= 'a') && (arg[1] <= 'z')) {
473            i = 1;
474        } else {
475            i = 2;
476        }
477    }
478
479    if (argc < i) {
480        Tcl_AppendResult(interp, "wrong # args: should be \"",
481            Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
482            itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL);
483        return TCL_ERROR;
484    }
485
486    /*
487     * Carry out initialization that is needed in order to clean up after
488     * errors during the the remainder of this procedure.
489     */
490    plPtr->interp           = interp;
491    plPtr->tkwin            = Tk_CanvasTkwin(canvas);
492    plPtr->canvas           = canvas;
493    plPtr->dots             = Tk_GetBitmap(interp, plPtr->tkwin,
494                                  Tk_GetUid("rp_ellipsis"));
495    plPtr->text             = NULL;
496    plPtr->anchor           = TK_ANCHOR_CENTER;
497    plPtr->textColor        = NULL;
498    plPtr->bgBorder         = NULL;
499    plPtr->lineColor        = NULL;
500    plPtr->tkfont           = NULL;
501    plPtr->width            = 0;
502    plPtr->maxWidth         = 0;
503    plPtr->borderWidth      = 0;
504    plPtr->relief           = TK_RELIEF_FLAT;
505    plPtr->padding          = 0;
506    plPtr->imageLeftString  = NULL;
507    plPtr->imageRightString = NULL;
508    plPtr->imageLeft        = NULL;
509    plPtr->imageRight       = NULL;
510    plPtr->textNumChars     = 0;
511    plPtr->textNumBytes     = 0;
512    plPtr->textDrawChars    = 0;
513    plPtr->textWidth        = 0;
514    plPtr->textLayout       = NULL;
515    plPtr->leftEdge         = 0;
516    plPtr->rightEdge        = 0;
517    plPtr->gcText           = None;
518    plPtr->gcLineRect       = None;
519
520    /*
521     * Process the arguments to fill in the item record.
522     */
523    if ((PlacardCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) {
524        goto error;
525    }
526    if (ConfigurePlacard(interp, canvas, itemPtr,
527            argc-i, argv+i, 0) == TCL_OK) {
528
529        return TCL_OK;
530    }
531
532error:
533    DeletePlacard(canvas, itemPtr, Tk_Display(plPtr->tkwin));
534    return TCL_ERROR;
535}
536
537/*
538 * ------------------------------------------------------------------------
539 *  PlacardCoords --
540 *
541 *    This procedure is invoked to process the "coords" widget command on
542 *    placard items.  See the user documentation for details on what
543 *    it does.
544 *
545 *  Results:
546 *    Returns TCL_OK or TCL_ERROR, and sets the interp's result.
547 *
548 *  Side effects:
549 *    The coordinates for the given item may be changed.
550 * ------------------------------------------------------------------------
551 */
552static int
553PlacardCoords(interp, canvas, itemPtr, argc, argv)
554    Tcl_Interp *interp;     /* Used for error reporting. */
555    Tk_Canvas canvas;       /* Canvas containing item. */
556    Tk_Item *itemPtr;       /* Item whose coordinates are to be read or
557                             * modified. */
558    int argc;               /* Number of coordinates supplied in argv. */
559    Tcl_Obj *CONST argv[];  /* Array of coordinates: x1, y1, x2, y2, ... */
560{
561    PlacardItem *plPtr = (PlacardItem *) itemPtr;
562    char buf[64 + TCL_INTEGER_SPACE];
563
564    if (argc == 0) {
565        Tcl_Obj *obj = Tcl_NewObj();
566        Tcl_Obj *subobj = Tcl_NewDoubleObj(plPtr->x);
567        Tcl_ListObjAppendElement(interp, obj, subobj);
568        subobj = Tcl_NewDoubleObj(plPtr->y);
569        Tcl_ListObjAppendElement(interp, obj, subobj);
570        Tcl_SetObjResult(interp, obj);
571    }
572    else if (argc < 3) {
573        if (argc == 1) {
574            if (Tcl_ListObjGetElements(interp, argv[0], &argc,
575                    (Tcl_Obj ***) &argv) != TCL_OK) {
576                return TCL_ERROR;
577            } else if (argc != 2) {
578
579                sprintf(buf, "wrong # coordinates: expected 2, got %d", argc);
580                Tcl_SetResult(interp, buf, TCL_VOLATILE);
581                return TCL_ERROR;
582            }
583        }
584        if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0],
585                   &plPtr->x) != TCL_OK)
586                || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1],
587                          &plPtr->y) != TCL_OK)) {
588            return TCL_ERROR;
589        }
590        ComputePlacardBbox(canvas, plPtr);
591    } else {
592        sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc);
593        Tcl_SetResult(interp, buf, TCL_VOLATILE);
594        return TCL_ERROR;
595    }
596    return TCL_OK;
597}
598
599/*
600 * ------------------------------------------------------------------------
601 *  ConfigurePlacard --
602 *
603 *    This procedure is invoked to configure various aspects of a
604 *    placard item, such as its color and font.
605 *
606 *  Results:
607 *    A standard Tcl result code.  If an error occurs, then an error
608 *    message is left in the interp's result.
609 *
610 *  Side effects:
611 *    Configuration information, such as colors and GCs, may be set
612 *    for itemPtr.
613 * ------------------------------------------------------------------------
614 */
615static int
616ConfigurePlacard(interp, canvas, itemPtr, argc, argv, flags)
617    Tcl_Interp *interp;           /* Interpreter for error reporting. */
618    Tk_Canvas canvas;             /* Canvas containing itemPtr. */
619    Tk_Item *itemPtr;             /* Rectangle item to reconfigure. */
620    int argc;                     /* Number of elements in argv.  */
621    Tcl_Obj *CONST argv[];        /* Args describing things to configure. */
622    int flags;                    /* Flags to pass to Tk_ConfigureWidget. */
623{
624    PlacardItem *plPtr = (PlacardItem *) itemPtr;
625    XGCValues gcValues;
626    GC newGC;
627    unsigned long mask;
628    Tk_Window tkwin;
629    XColor *color;
630    Tk_Image image;
631
632    tkwin = Tk_CanvasTkwin(canvas);
633    if (Tk_ConfigureWidget(interp, tkwin, configSpecs,
634            argc, (CONST char **) argv,
635            (char*)plPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
636        return TCL_ERROR;
637    }
638
639    /*
640     * A few of the options require additional processing, such as
641     * graphics contexts.
642     */
643    color = plPtr->textColor;
644    newGC = None;
645    if (plPtr->tkfont != NULL) {
646        gcValues.font = Tk_FontId(plPtr->tkfont);
647        mask = GCFont;
648        if (color != NULL) {
649            gcValues.foreground = color->pixel;
650            mask |= GCForeground;
651            newGC = Tk_GetGC(tkwin, mask, &gcValues);
652        }
653    }
654    if (plPtr->gcText != None) {
655        Tk_FreeGC(Tk_Display(tkwin), plPtr->gcText);
656    }
657    plPtr->gcText = newGC;
658
659
660    newGC = None;
661    if (plPtr->lineColor != NULL) {
662        gcValues.foreground = plPtr->lineColor->pixel;
663        gcValues.line_width = 1;
664        mask = GCForeground | GCLineWidth;
665        newGC = Tk_GetGC(tkwin, mask, &gcValues);
666    }
667    if (plPtr->gcLineRect != None) {
668        Tk_FreeGC(Tk_Display(tkwin), plPtr->gcLineRect);
669    }
670    plPtr->gcLineRect = newGC;
671
672
673    if (plPtr->imageLeftString != NULL) {
674        image = Tk_GetImage(interp, tkwin, plPtr->imageLeftString,
675                ImageLeftChangedProc, (ClientData)plPtr);
676        if (image == NULL) {
677            return TCL_ERROR;
678        }
679    } else {
680        image = NULL;
681    }
682    if (plPtr->imageLeft != NULL) {
683        Tk_FreeImage(plPtr->imageLeft);
684    }
685    plPtr->imageLeft = image;
686
687    if (image != NULL) {
688        Tk_SizeOfImage(image,&plPtr->imageLeftW, &plPtr->imageLeftH);
689    }
690
691
692    if (plPtr->imageRightString != NULL) {
693        image = Tk_GetImage(interp, tkwin, plPtr->imageRightString,
694                ImageRightChangedProc, (ClientData)plPtr);
695        if (image == NULL) {
696            return TCL_ERROR;
697        }
698    } else {
699        image = NULL;
700    }
701    if (plPtr->imageRight != NULL) {
702        Tk_FreeImage(plPtr->imageRight);
703    }
704    plPtr->imageRight = image;
705
706    if (image != NULL) {
707        Tk_SizeOfImage(image,&plPtr->imageRightW, &plPtr->imageRightH);
708    }
709
710
711    if (plPtr->text != NULL) {
712        plPtr->textNumBytes = strlen(plPtr->text);
713        plPtr->textNumChars = Tcl_NumUtfChars(plPtr->text, plPtr->textNumBytes);
714    };
715
716    ComputePlacardBbox(canvas, plPtr);
717    return TCL_OK;
718}
719
720/*
721 * ------------------------------------------------------------------------
722 *  DeletePlacard --
723 *
724 *    This procedure is called to clean up the data structure
725 *    associated with a placard item.
726 *
727 *  Results:
728 *    None.
729 *
730 *  Side effects:
731 *    Resources associated with itemPtr are released.
732 * ------------------------------------------------------------------------
733 */
734static void
735DeletePlacard(canvas, itemPtr, display)
736    Tk_Canvas canvas;          /* Info about overall canvas widget. */
737    Tk_Item *itemPtr;          /* Item that is being deleted. */
738    Display *display;          /* Display containing window for canvas. */
739{
740    PlacardItem *plPtr = (PlacardItem *) itemPtr;
741
742    if (plPtr->textColor != NULL) {
743        Tk_FreeColor(plPtr->textColor);
744    }
745    if (plPtr->lineColor != NULL) {
746        Tk_FreeColor(plPtr->lineColor);
747    }
748    if (plPtr->text != NULL) {
749        ckfree(plPtr->text);
750    }
751
752
753    if (plPtr->imageLeftString != NULL) {
754        ckfree(plPtr->imageLeftString);
755    }
756    if (plPtr->imageLeft != NULL ) {
757        Tk_FreeImage(plPtr->imageLeft);
758    }
759    if (plPtr->imageRightString != NULL) {
760        ckfree(plPtr->imageRightString);
761    }
762    if (plPtr->imageRight != NULL ) {
763        Tk_FreeImage(plPtr->imageRight);
764    }
765
766    Tk_FreeTextLayout(plPtr->textLayout);
767
768    Tk_FreeFont(plPtr->tkfont);
769
770    if (plPtr->gcText != None) {
771        Tk_FreeGC(display, plPtr->gcText);
772    }
773    if (plPtr->gcLineRect != None) {
774        Tk_FreeGC(display, plPtr->gcLineRect);
775    }
776}
777
778/*
779 * ------------------------------------------------------------------------
780 *  ComputePlacardBbox --
781 *
782 *    This procedure is invoked to compute the bounding box of
783 *    all the pixels that may be drawn as part of a text item.
784 *    In addition, it recomputes all of the geometry information
785 *    used to display a text item or check for mouse hits.
786 *
787 *  Results:
788 *    None.
789 *
790 *  Side effects:
791 *    The fields x1, y1, x2, and y2 are updated in the header
792 *    for itemPtr, and the linePtr structure is regenerated
793 *    for itemPtr.
794 * ------------------------------------------------------------------------
795 */
796static void
797ComputePlacardBbox(canvas, plPtr)
798    Tk_Canvas canvas;           /* Canvas that contains item. */
799    PlacardItem *plPtr;       /* Item whose bbox is to be recomputed. */
800{
801    int leftX, topY, width, height, maxwidth, ellw, ellh;
802
803    /*
804     * Get the layout for the placard text.
805     */
806    plPtr->textDrawChars = plPtr->textNumChars;
807
808    Tk_FreeTextLayout(plPtr->textLayout);
809    plPtr->textLayout = Tk_ComputeTextLayout(plPtr->tkfont,
810            plPtr->text, plPtr->textNumChars, -1,
811            TK_JUSTIFY_LEFT, 0, &width, &height);
812
813    plPtr->textWidth = width;
814
815    if (plPtr->textColor == NULL) {
816        width = height = 0;
817    } else {
818        width += 2*plPtr->padding;
819        height += 2*plPtr->padding;
820    }
821
822    /*
823     * If the current value has an image, add on its width.
824     */
825    if (plPtr->imageLeft) {
826        width += plPtr->imageLeftW;
827        if (plPtr->textWidth > 0) {
828            width += plPtr->padding;
829        }
830        if (plPtr->imageLeftH > height) {
831            height = plPtr->imageLeftH;
832        }
833    }
834    if (plPtr->imageRight) {
835        width += plPtr->imageRightW;
836        if (plPtr->textWidth > 0) {
837            width += plPtr->padding;
838        }
839        if (plPtr->imageRightH > height) {
840            height = plPtr->imageRightH;
841        }
842    }
843
844    /*
845     * Add on extra size for the 3D border (if there is one).
846     */
847    if (plPtr->borderWidth > 0) {
848        width += 2*plPtr->borderWidth;
849        height += 2*plPtr->borderWidth;
850    }
851
852    /*
853     * If the overall width exceeds the -maxwidth, then we must
854     * truncate the text to make it fit.
855     */
856    maxwidth = 0;
857    if (plPtr->maxWidth > 0 && plPtr->width > 0) {
858        maxwidth = (plPtr->width < plPtr->maxWidth) ? plPtr->width : plPtr->maxWidth;
859    } else if (plPtr->maxWidth > 0) {
860        maxwidth = plPtr->maxWidth;
861    } else if (plPtr->width > 0) {
862        maxwidth = plPtr->width;
863    }
864
865    if (maxwidth > 0 && width > maxwidth) {
866        Tk_SizeOfBitmap(Tk_Display(plPtr->tkwin), plPtr->dots, &ellw, &ellh);
867        width = maxwidth - 2*plPtr->padding - 2*plPtr->borderWidth - ellw;
868        if (plPtr->imageLeft) {
869            width -= plPtr->imageLeftW + plPtr->padding;
870        }
871        if (plPtr->imageRight) {
872            width -= plPtr->imageRightW + plPtr->padding;
873        }
874        if (width < 0) { width = 0; }
875
876        plPtr->textDrawChars = Tk_MeasureChars(plPtr->tkfont,
877            plPtr->text, plPtr->textNumChars, width, /*flags*/ 0,
878            &plPtr->textWidth);
879
880        /* recompute layout for truncated text */
881        Tk_FreeTextLayout(plPtr->textLayout);
882        plPtr->textLayout = Tk_ComputeTextLayout(plPtr->tkfont,
883                plPtr->text, plPtr->textDrawChars, -1,
884                TK_JUSTIFY_LEFT, 0, NULL, NULL);
885
886        width = maxwidth;  /* fit everything in this width */
887    }
888
889    /*
890     * If there's a fixed -width, then use that instead.
891     */
892    if (plPtr->width > 0) {
893        width = plPtr->width;
894    }
895
896    /*
897     * Use overall geometry information to compute the top-left corner
898     * of the bounding box for the text item.
899     */
900    leftX = (int) (plPtr->x + 0.5);
901    topY = (int) (plPtr->y + 0.5);
902    switch (plPtr->anchor) {
903        case TK_ANCHOR_NW:
904        case TK_ANCHOR_N:
905        case TK_ANCHOR_NE:
906            break;
907
908        case TK_ANCHOR_W:
909        case TK_ANCHOR_CENTER:
910        case TK_ANCHOR_E:
911            topY -= height / 2;
912            break;
913
914        case TK_ANCHOR_SW:
915        case TK_ANCHOR_S:
916        case TK_ANCHOR_SE:
917            topY -= height;
918            break;
919    }
920    switch (plPtr->anchor) {
921        case TK_ANCHOR_NW:
922        case TK_ANCHOR_W:
923        case TK_ANCHOR_SW:
924            break;
925
926        case TK_ANCHOR_N:
927        case TK_ANCHOR_CENTER:
928        case TK_ANCHOR_S:
929            leftX -= width / 2;
930            break;
931
932        case TK_ANCHOR_NE:
933        case TK_ANCHOR_E:
934        case TK_ANCHOR_SE:
935            leftX -= width;
936            break;
937    }
938
939    plPtr->leftEdge  = leftX;
940    plPtr->rightEdge = leftX + width;
941
942    /*
943     * Last of all, update the bounding box for the item.
944     */
945    plPtr->header.x1 = leftX;
946    plPtr->header.y1 = topY;
947    plPtr->header.x2 = leftX + width;
948    plPtr->header.y2 = topY + height;
949}
950
951/*
952 * ------------------------------------------------------------------------
953 *  DisplayCanvPlacard --
954 *
955 *    This procedure is invoked to draw a text item in a given drawable.
956 *
957 *  Results:
958 *    None.
959 *
960 *  Side effects:
961 *    ItemPtr is drawn in drawable using the transformation information
962 *    in canvas.
963 * ------------------------------------------------------------------------
964 */
965static void
966DisplayCanvPlacard(canvas, itemPtr, display, drawable, x, y, width, height)
967    Tk_Canvas canvas;           /* Canvas that contains item. */
968    Tk_Item *itemPtr;           /* Item to be displayed. */
969    Display *display;           /* Display on which to draw item. */
970    Drawable drawable;          /* Pixmap or window in which to draw item. */
971    int x, y, width, height;    /* Describes region of canvas that must be
972                                 * redisplayed (not used). */
973{
974    PlacardItem *plPtr = (PlacardItem *) itemPtr;
975    int imagew, delta, ellx, elly, ellw, ellh;
976    short drawableX, drawableY;
977    Tk_FontMetrics fm;
978
979    if (plPtr->gcText == None) {
980        return;
981    }
982
983    /*
984     * If there's a background rectangle, draw it first.
985     */
986    Tk_CanvasDrawableCoords(canvas, (double)plPtr->leftEdge,
987            (double)plPtr->header.y1, &drawableX, &drawableY);
988
989    if (plPtr->bgBorder) {
990        Tk_Fill3DRectangle(plPtr->tkwin, drawable, plPtr->bgBorder,
991            (int)drawableX, (int)drawableY,
992            (int)(plPtr->rightEdge - plPtr->leftEdge),
993            (int)(plPtr->header.y2 - plPtr->header.y1),
994            plPtr->borderWidth, plPtr->relief);
995    }
996
997    if (plPtr->gcLineRect) {
998        XDrawRectangle(display, drawable, plPtr->gcLineRect,
999            (int)drawableX, (int)drawableY,
1000            (unsigned int)(plPtr->rightEdge - plPtr->leftEdge - 1),
1001            (unsigned int)(plPtr->header.y2 - plPtr->header.y1 - 1));
1002    }
1003
1004    /*
1005     * If there's a right-hand image, draw it first.
1006     */
1007    imagew = 0;
1008    if (plPtr->imageRight) {
1009        Tk_CanvasDrawableCoords(canvas, (double)plPtr->rightEdge,
1010                (double)plPtr->header.y1, &drawableX, &drawableY);
1011
1012        delta = (plPtr->header.y2 - plPtr->header.y1)/2 - plPtr->imageRightH/2;
1013        drawableX -= plPtr->imageRightW + plPtr->padding + plPtr->borderWidth;
1014        Tk_RedrawImage(plPtr->imageRight, 0, 0,
1015                       plPtr->imageRightW, plPtr->imageRightH,
1016                       drawable,
1017                       (int)drawableX, (int)(drawableY+delta));
1018        imagew += plPtr->imageRightW;
1019    }
1020
1021    /*
1022     * If there's a left-hand image, draw it next.
1023     */
1024    Tk_CanvasDrawableCoords(canvas, (double)plPtr->leftEdge,
1025            (double)plPtr->header.y1, &drawableX, &drawableY);
1026
1027    drawableX += plPtr->padding + plPtr->borderWidth;
1028    drawableY += plPtr->padding + plPtr->borderWidth;
1029
1030    if (plPtr->imageLeft) {
1031        delta = (plPtr->header.y2 - plPtr->header.y1)/2
1032                       - plPtr->imageLeftH/2 - plPtr->padding
1033                       - plPtr->borderWidth;
1034
1035        Tk_RedrawImage(plPtr->imageLeft, 0, 0,
1036                       plPtr->imageLeftW, plPtr->imageLeftH,
1037                       drawable,
1038                       (int)drawableX, (int)(drawableY+delta));
1039        drawableX += plPtr->imageLeftW + plPtr->padding;
1040        imagew += plPtr->imageLeftW;
1041    }
1042
1043    /*
1044     * Draw the text.
1045     */
1046    Tk_DrawTextLayout(display, drawable, plPtr->gcText, plPtr->textLayout,
1047            drawableX, drawableY, 0, -1);
1048
1049    if (plPtr->textDrawChars < plPtr->textNumChars
1050          && plPtr->rightEdge - plPtr->leftEdge - imagew > ellw) {
1051        Tk_SizeOfBitmap(Tk_Display(plPtr->tkwin), plPtr->dots, &ellw, &ellh);
1052        Tk_GetFontMetrics(plPtr->tkfont, &fm);
1053        ellx = drawableX+plPtr->textWidth;
1054        elly = drawableY+fm.ascent-1;
1055
1056        XSetClipMask(display, plPtr->gcText, plPtr->dots);
1057        XSetClipOrigin(display, plPtr->gcText, ellx, elly);
1058
1059        XCopyPlane(display, plPtr->dots, drawable, plPtr->gcText, 0, 0,
1060            (unsigned int)ellw, (unsigned int)ellh, ellx, elly, 1);
1061
1062        XSetClipOrigin(display, plPtr->gcText, 0, 0);
1063        XSetClipMask(display, plPtr->gcText, None);
1064    }
1065}
1066
1067/*
1068 * ------------------------------------------------------------------------
1069 *  PlacardToPoint --
1070 *
1071 *    Computes the distance from a given point to a given placard
1072 *    item, in canvas units.
1073 *
1074 *  Results:
1075 *    The return value is 0 if the point whose x and y coordinates
1076 *    are pointPtr[0] and pointPtr[1] is inside the text item.  If
1077 *    the point isn't inside the text item then the return value
1078 *    is the distance from the point to the text item.
1079 *
1080 *  Side effects:
1081 *    None.
1082 * ------------------------------------------------------------------------
1083 */
1084static double
1085PlacardToPoint(canvas, itemPtr, pointPtr)
1086    Tk_Canvas canvas;                /* Canvas containing itemPtr. */
1087    Tk_Item *itemPtr;                /* Item to check against point. */
1088    double *pointPtr;                /* Pointer to x and y coordinates. */
1089{
1090    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1091    double value, x0, y0, x1, y1, xDiff, yDiff;
1092
1093    if (plPtr->bgBorder || plPtr->lineColor) {
1094        /* have a rectangle -- compare directly against that */
1095        x0 = plPtr->leftEdge;
1096        y0 = plPtr->header.y1;
1097        x1 = plPtr->rightEdge;
1098        y1 = plPtr->header.y2;
1099    }
1100    else if (plPtr->imageLeft || plPtr->imageRight) {
1101        /* have images -- compare against a rectangle around image/text */
1102        x0 = plPtr->leftEdge + plPtr->padding + plPtr->borderWidth;
1103        y0 = plPtr->header.y1 + plPtr->padding + plPtr->borderWidth;
1104        x1 = plPtr->rightEdge - plPtr->padding - plPtr->borderWidth;
1105        y1 = plPtr->header.y2 - plPtr->padding - plPtr->borderWidth;
1106    }
1107    else {
1108        value = (double) Tk_DistanceToTextLayout(plPtr->textLayout,
1109                    (int) pointPtr[0] - plPtr->leftEdge,
1110                    (int) pointPtr[1] - plPtr->header.y1);
1111
1112        if ((plPtr->textColor == NULL) || (plPtr->text == NULL)
1113              || (*plPtr->text == 0)) {
1114            value = 1.0e36;
1115        }
1116        return value;
1117    }
1118
1119    if (pointPtr[0] < x0) {
1120        xDiff = x0 - pointPtr[0];
1121    } else if (pointPtr[0] >= x1)  {
1122        xDiff = pointPtr[0] + 1 - x1;
1123    } else {
1124        xDiff = 0;
1125    }
1126
1127    if (pointPtr[1] < y0) {
1128        yDiff = y0 - pointPtr[1];
1129    } else if (pointPtr[1] >= y1)  {
1130        yDiff = pointPtr[1] + 1 - y1;
1131    } else {
1132        yDiff = 0;
1133    }
1134
1135    return hypot(xDiff, yDiff);
1136}
1137
1138/*
1139 * ------------------------------------------------------------------------
1140 *  PlacardToArea --
1141 *
1142 *    This procedure is called to determine whether an item lies
1143 *    entirely inside, entirely outside, or overlapping a given
1144 *    rectangle.
1145 *
1146 *  Results:
1147 *    -1 is returned if the item is entirely outside the area given
1148 *    by rectPtr, 0 if it overlaps, and 1 if it is entirely inside
1149 *    the given area.
1150 *
1151 *  Side effects:
1152 *    None.
1153 * ------------------------------------------------------------------------
1154 */
1155static int
1156PlacardToArea(canvas, itemPtr, rectPtr)
1157    Tk_Canvas canvas;       /* Canvas containing itemPtr. */
1158    Tk_Item *itemPtr;       /* Item to check against rectangle. */
1159    double *rectPtr;        /* Pointer to array of four coordinates
1160                             * (x1, y1, x2, y2) describing rectangular
1161                             * area.  */
1162{
1163    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1164    int x0, y0, x1, y1;
1165
1166    if (plPtr->bgBorder || plPtr->lineColor) {
1167        /* have a rectangle -- compare directly against that */
1168        x0 = plPtr->leftEdge;
1169        y0 = plPtr->header.y1;
1170        x1 = plPtr->rightEdge;
1171        y1 = plPtr->header.y2;
1172    }
1173    else if (plPtr->imageLeft || plPtr->imageRight) {
1174        /* have images -- compare against a rectangle around image/text */
1175        x0 = plPtr->leftEdge + plPtr->padding + plPtr->borderWidth;
1176        y0 = plPtr->header.y1 + plPtr->padding + plPtr->borderWidth;
1177        x1 = plPtr->rightEdge - plPtr->padding - plPtr->borderWidth;
1178        y1 = plPtr->header.y2 - plPtr->padding - plPtr->borderWidth;
1179    }
1180    else {
1181        /* have only text -- compare against text layout */
1182        return Tk_IntersectTextLayout(plPtr->textLayout,
1183            (int) (rectPtr[0] + 0.5) - (plPtr->leftEdge + plPtr->padding + plPtr->borderWidth),
1184            (int) (rectPtr[1] + 0.5) - (plPtr->header.y1 + plPtr->padding + plPtr->borderWidth),
1185            (int) (rectPtr[2] - rectPtr[0] + 0.5),
1186            (int) (rectPtr[3] - rectPtr[1] + 0.5));
1187    }
1188
1189    /* compare against rectangle... */
1190    if (rectPtr[0] > x1 || rectPtr[1] > y1
1191          || rectPtr[2] < x0 || rectPtr[3] < y0) {
1192        return -1;  /* completely outside */
1193    }
1194    if (rectPtr[0] >= x0 && rectPtr[1] >= y0
1195          && rectPtr[2] <= x1 && rectPtr[3] <= y1) {
1196        return 1;  /* completely inside */
1197    }
1198    return 0;  /* must be overlapping */
1199}
1200
1201/*
1202 * ------------------------------------------------------------------------
1203 *  ScalePlacard --
1204 *
1205 *    This procedure is invoked to rescale a text item.
1206 *
1207 * Results:
1208 *    None.
1209 *
1210 * Side effects:
1211 *    Scales the position of the text, but not the size of the font
1212 *    for the text.
1213 * ------------------------------------------------------------------------
1214 */
1215        /* ARGSUSED */
1216static void
1217ScalePlacard(canvas, itemPtr, originX, originY, scaleX, scaleY)
1218    Tk_Canvas canvas;             /* Canvas containing rectangle. */
1219    Tk_Item *itemPtr;             /* Rectangle to be scaled. */
1220    double originX, originY;      /* Origin about which to scale rect. */
1221    double scaleX;                /* Amount to scale in X direction. */
1222    double scaleY;                /* Amount to scale in Y direction. */
1223{
1224    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1225
1226    plPtr->x = originX + scaleX*(plPtr->x - originX);
1227    plPtr->y = originY + scaleY*(plPtr->y - originY);
1228    ComputePlacardBbox(canvas, plPtr);
1229    return;
1230}
1231
1232/*
1233 * ------------------------------------------------------------------------
1234 *  TranslatePlacard --
1235 *
1236 *    This procedure is called to move a text item by a given amount.
1237 *
1238 *  Results:
1239 *    None.
1240 *
1241 *  Side effects:
1242 *    The position of the text item is offset by (xDelta, yDelta),
1243 *    and the bounding box is updated in the generic part of the
1244 *    item structure.
1245 * ------------------------------------------------------------------------
1246 */
1247static void
1248TranslatePlacard(canvas, itemPtr, deltaX, deltaY)
1249    Tk_Canvas canvas;             /* Canvas containing item. */
1250    Tk_Item *itemPtr;             /* Item that is being moved. */
1251    double deltaX, deltaY;        /* Amount by which item is to be moved. */
1252{
1253    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1254
1255    plPtr->x += deltaX;
1256    plPtr->y += deltaY;
1257    ComputePlacardBbox(canvas, plPtr);
1258}
1259
1260/*
1261 * ------------------------------------------------------------------------
1262 *  PlacardToPostscript --
1263 *
1264 *    This procedure is called to generate Postscript for placard
1265 *    items.
1266 *
1267 *  Results:
1268 *    The return value is a standard Tcl result.  If an error
1269 *    occurs in generating Postscript then an error message is
1270 *    left in the interp's result, replacing whatever used
1271 *    to be there.  If no error occurs, then Postscript for the
1272 *    item is appended to the result.
1273 *
1274 *  Side effects:
1275 *    None.
1276 * ------------------------------------------------------------------------
1277 */
1278static int
1279PlacardToPostscript(interp, canvas, itemPtr, prepass)
1280    Tcl_Interp *interp;         /* Leave Postscript or error message here. */
1281    Tk_Canvas canvas;           /* Information about overall canvas. */
1282    Tk_Item *itemPtr;           /* Item for which Postscript is wanted. */
1283    int prepass;                /* 1 means this is a prepass to collect
1284                                 * font information; 0 means final Postscript
1285                                 * is being created. */
1286{
1287    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1288    Tk_Window canvasWin = Tk_CanvasTkwin(canvas);
1289
1290    int x, y;
1291    double xpos;
1292    Tk_FontMetrics fm;
1293    char *justify;
1294    char buffer[500];
1295    int delta;
1296
1297    if (plPtr->textColor == NULL || plPtr->text == NULL
1298          || *plPtr->text == 0) {
1299        return TCL_OK;
1300    }
1301
1302    if (Tk_CanvasPsFont(interp, canvas, plPtr->tkfont) != TCL_OK) {
1303        return TCL_ERROR;
1304    }
1305
1306
1307    if (!prepass &&
1308        Tk_CanvasPsColor(interp, canvas, plPtr->textColor) != TCL_OK) {
1309        return TCL_ERROR;
1310    }
1311    xpos = plPtr->x;
1312
1313    /*
1314     * Check for an image to print.
1315     */
1316
1317    if (plPtr->imageLeft) {
1318      if(!prepass) {
1319        delta = (plPtr->header.y2 - plPtr->header.y1)/2 - plPtr->imageLeftH/2;
1320        sprintf(buffer, "%.15g %.15g", xpos,
1321                Tk_CanvasPsY(canvas, plPtr->y+delta+2));
1322        Tcl_AppendResult(interp, buffer, " translate\n", (char *) NULL);
1323      }
1324
1325      Tk_PostscriptImage(plPtr->imageLeft, interp, canvasWin,
1326                         ((TkCanvas*)canvas)->psInfo, 0, 0,
1327                         plPtr->imageLeftW, plPtr->imageLeftH, prepass);
1328
1329      if ( !prepass ) {
1330        /*
1331         * This PS code is needed in order for the label to display
1332         * correctly
1333         */
1334       
1335        Tcl_AppendResult(interp,"grestore\ngsave\n",(char *)NULL);
1336      }
1337
1338      xpos += plPtr->imageLeftW + plPtr->padding;
1339    }
1340
1341   
1342    if (prepass != 0 ) {
1343      return TCL_OK;
1344    }
1345
1346    /*
1347     * Before drawing the text, reset the font and color information.
1348     * Otherwise the text won't appear.
1349     */
1350
1351    if ( plPtr->imageLeft ){
1352      if (Tk_CanvasPsFont(interp, canvas, plPtr->tkfont) != TCL_OK) {
1353        return TCL_ERROR;
1354      }
1355     
1356      if (Tk_CanvasPsColor(interp, canvas, plPtr->textColor) != TCL_OK) {
1357        return TCL_ERROR;
1358      }
1359    }
1360
1361
1362    /*
1363     * Draw the text for the placard.
1364     */
1365    sprintf(buffer, "%.15g %.15g [\n", xpos,
1366        Tk_CanvasPsY(canvas, plPtr->y));
1367    Tcl_AppendResult(interp, buffer, (char *) NULL);
1368
1369    Tk_TextLayoutToPostscript(interp, plPtr->textLayout);
1370
1371    x = 0;  y = 0;  justify = NULL;
1372    switch (plPtr->anchor) {
1373        case TK_ANCHOR_NW:        x = 0; y = 0;        break;
1374        case TK_ANCHOR_N:         x = 1; y = 0;        break;
1375        case TK_ANCHOR_NE:        x = 2; y = 0;        break;
1376        case TK_ANCHOR_E:         x = 2; y = 1;        break;
1377        case TK_ANCHOR_SE:        x = 2; y = 2;        break;
1378        case TK_ANCHOR_S:         x = 1; y = 2;        break;
1379        case TK_ANCHOR_SW:        x = 0; y = 2;        break;
1380        case TK_ANCHOR_W:         x = 0; y = 1;        break;
1381        case TK_ANCHOR_CENTER:    x = 1; y = 1;        break;
1382    }
1383    justify = "0"; /* TK_JUSTIFY_LEFT */
1384
1385    Tk_GetFontMetrics(plPtr->tkfont, &fm);
1386    sprintf(buffer, "] %d %g %g %s %s DrawText\n",
1387            fm.linespace, x / -2.0, y / 2.0, justify,
1388            "false" /* stipple */);
1389    Tcl_AppendResult(interp, buffer, (char *) NULL);
1390
1391    return TCL_OK;
1392}
1393
1394/*
1395 * ----------------------------------------------------------------------
1396 *
1397 * ImageLeftChangedProc --
1398 *
1399 *      This procedure is invoked by the image code whenever the manager
1400 *      for an image does something that affects the image's size or
1401 *      how it is displayed.
1402 *
1403 * Results:
1404 *      None.
1405 *
1406 * Side effects:
1407 *      Arranges for the canvas to get redisplayed.
1408 *
1409 * ----------------------------------------------------------------------
1410 */
1411static void
1412ImageLeftChangedProc(clientData, x, y, width, height, imgWidth, imgHeight)
1413    ClientData clientData;              /* Pointer to canvas item for image. */
1414    int x, y;                           /* Upper left pixel (within image)
1415                                         * that must be redisplayed. */
1416    int width, height;                  /* Dimensions of area to redisplay
1417                                         * (may be <= 0). */
1418    int imgWidth, imgHeight;            /* New dimensions of image. */
1419{     
1420    PlacardItem *plPtr = (PlacardItem *) clientData;
1421   
1422    plPtr->imageLeftW = imgWidth;
1423    plPtr->imageLeftH = imgHeight;
1424    ComputePlacardBbox(plPtr->canvas, plPtr);
1425    return;
1426}
1427
1428/*
1429 * ----------------------------------------------------------------------
1430 *
1431 * ImageRightChangedProc --
1432 *
1433 *      This procedure is invoked by the image code whenever the manager
1434 *      for an image does something that affects the image's size or
1435 *      how it is displayed.
1436 *
1437 * Results:
1438 *      None.
1439 *
1440 * Side effects:
1441 *      Arranges for the canvas to get redisplayed.
1442 *
1443 * ----------------------------------------------------------------------
1444 */
1445static void
1446ImageRightChangedProc(clientData, x, y, width, height, imgWidth, imgHeight)
1447    ClientData clientData;              /* Pointer to canvas item for image. */
1448    int x, y;                           /* Upper left pixel (within image)
1449                                         * that must be redisplayed. */
1450    int width, height;                  /* Dimensions of area to redisplay
1451                                         * (may be <= 0). */
1452    int imgWidth, imgHeight;            /* New dimensions of image. */
1453{     
1454    PlacardItem *plPtr = (PlacardItem *) clientData;
1455   
1456    plPtr->imageRightW = imgWidth;
1457    plPtr->imageRightH = imgHeight;
1458    ComputePlacardBbox(plPtr->canvas, plPtr);
1459    return;
1460}
Note: See TracBrowser for help on using the repository browser.