source: branches/1.5/pkgs/placard/placard.c @ 5904

Last change on this file since 5904 was 5904, checked in by gah, 9 years ago

first pass on new build

  • Property svn:eol-style set to native
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 * ------------------------------------------------------------------------
418 *  CreatePlacard --
419 *
420 *    This procedure is invoked to create a new placard item
421 *    in a canvas.  A placard is a text item with a box behind it.
422 *
423 *  Results:
424 *    A standard Tcl return name.  If an error occurred in creating
425 *    the item then an error message is left in the interp's result.
426 *    In this case itemPtr is left uninitialized so it can be safely
427 *    freed by the caller.
428 *
429 *  Side effects:
430 *    A new item is created.
431 * ------------------------------------------------------------------------
432 */
433static int
434CreatePlacard(interp, canvas, itemPtr, argc, argv)
435    Tcl_Interp *interp;           /* interpreter for error reporting */
436    Tk_Canvas canvas;             /* canvas to hold new item */
437    Tk_Item *itemPtr;             /* record to hold new item; header has been
438                                   * initialized by caller */
439    int argc;                     /* number of arguments in argv */
440    Tcl_Obj *CONST argv[];        /* arguments describing item */
441{
442    PlacardItem *plPtr = (PlacardItem *) itemPtr;
443    int i;
444
445    if (argc == 1) {
446        i = 1;
447    } else {
448        char *arg = Tcl_GetStringFromObj(argv[1], NULL);
449        if ((argc > 1) && (arg[0] == '-')
450                && (arg[1] >= 'a') && (arg[1] <= 'z')) {
451            i = 1;
452        } else {
453            i = 2;
454        }
455    }
456
457    if (argc < i) {
458        Tcl_AppendResult(interp, "wrong # args: should be \"",
459            Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
460            itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL);
461        return TCL_ERROR;
462    }
463
464    /*
465     * Carry out initialization that is needed in order to clean up after
466     * errors during the the remainder of this procedure.
467     */
468    plPtr->interp           = interp;
469    plPtr->tkwin            = Tk_CanvasTkwin(canvas);
470    plPtr->canvas           = canvas;
471    plPtr->dots             = Tk_GetBitmap(interp, plPtr->tkwin,
472                                  Tk_GetUid("rp_ellipsis"));
473    plPtr->text             = NULL;
474    plPtr->anchor           = TK_ANCHOR_CENTER;
475    plPtr->textColor        = NULL;
476    plPtr->bgBorder         = NULL;
477    plPtr->lineColor        = NULL;
478    plPtr->tkfont           = NULL;
479    plPtr->width            = 0;
480    plPtr->maxWidth         = 0;
481    plPtr->borderWidth      = 0;
482    plPtr->relief           = TK_RELIEF_FLAT;
483    plPtr->padding          = 0;
484    plPtr->imageLeftString  = NULL;
485    plPtr->imageRightString = NULL;
486    plPtr->imageLeft        = NULL;
487    plPtr->imageRight       = NULL;
488    plPtr->textNumChars     = 0;
489    plPtr->textNumBytes     = 0;
490    plPtr->textDrawChars    = 0;
491    plPtr->textWidth        = 0;
492    plPtr->textLayout       = NULL;
493    plPtr->leftEdge         = 0;
494    plPtr->rightEdge        = 0;
495    plPtr->gcText           = None;
496    plPtr->gcLineRect       = None;
497
498    /*
499     * Process the arguments to fill in the item record.
500     */
501    if ((PlacardCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) {
502        goto error;
503    }
504    if (ConfigurePlacard(interp, canvas, itemPtr,
505            argc-i, argv+i, 0) == TCL_OK) {
506
507        return TCL_OK;
508    }
509
510error:
511    DeletePlacard(canvas, itemPtr, Tk_Display(plPtr->tkwin));
512    return TCL_ERROR;
513}
514
515/*
516 * ------------------------------------------------------------------------
517 *  PlacardCoords --
518 *
519 *    This procedure is invoked to process the "coords" widget command on
520 *    placard items.  See the user documentation for details on what
521 *    it does.
522 *
523 *  Results:
524 *    Returns TCL_OK or TCL_ERROR, and sets the interp's result.
525 *
526 *  Side effects:
527 *    The coordinates for the given item may be changed.
528 * ------------------------------------------------------------------------
529 */
530static int
531PlacardCoords(interp, canvas, itemPtr, argc, argv)
532    Tcl_Interp *interp;     /* Used for error reporting. */
533    Tk_Canvas canvas;       /* Canvas containing item. */
534    Tk_Item *itemPtr;       /* Item whose coordinates are to be read or
535                             * modified. */
536    int argc;               /* Number of coordinates supplied in argv. */
537    Tcl_Obj *CONST argv[];  /* Array of coordinates: x1, y1, x2, y2, ... */
538{
539    PlacardItem *plPtr = (PlacardItem *) itemPtr;
540    char buf[64 + TCL_INTEGER_SPACE];
541
542    if (argc == 0) {
543        Tcl_Obj *obj = Tcl_NewObj();
544        Tcl_Obj *subobj = Tcl_NewDoubleObj(plPtr->x);
545        Tcl_ListObjAppendElement(interp, obj, subobj);
546        subobj = Tcl_NewDoubleObj(plPtr->y);
547        Tcl_ListObjAppendElement(interp, obj, subobj);
548        Tcl_SetObjResult(interp, obj);
549    }
550    else if (argc < 3) {
551        if (argc == 1) {
552            if (Tcl_ListObjGetElements(interp, argv[0], &argc,
553                    (Tcl_Obj ***) &argv) != TCL_OK) {
554                return TCL_ERROR;
555            } else if (argc != 2) {
556
557                sprintf(buf, "wrong # coordinates: expected 2, got %d", argc);
558                Tcl_SetResult(interp, buf, TCL_VOLATILE);
559                return TCL_ERROR;
560            }
561        }
562        if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0],
563                   &plPtr->x) != TCL_OK)
564                || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1],
565                          &plPtr->y) != TCL_OK)) {
566            return TCL_ERROR;
567        }
568        ComputePlacardBbox(canvas, plPtr);
569    } else {
570        sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc);
571        Tcl_SetResult(interp, buf, TCL_VOLATILE);
572        return TCL_ERROR;
573    }
574    return TCL_OK;
575}
576
577/*
578 * ------------------------------------------------------------------------
579 *  ConfigurePlacard --
580 *
581 *    This procedure is invoked to configure various aspects of a
582 *    placard item, such as its color and font.
583 *
584 *  Results:
585 *    A standard Tcl result code.  If an error occurs, then an error
586 *    message is left in the interp's result.
587 *
588 *  Side effects:
589 *    Configuration information, such as colors and GCs, may be set
590 *    for itemPtr.
591 * ------------------------------------------------------------------------
592 */
593static int
594ConfigurePlacard(interp, canvas, itemPtr, argc, argv, flags)
595    Tcl_Interp *interp;           /* Interpreter for error reporting. */
596    Tk_Canvas canvas;             /* Canvas containing itemPtr. */
597    Tk_Item *itemPtr;             /* Rectangle item to reconfigure. */
598    int argc;                     /* Number of elements in argv.  */
599    Tcl_Obj *CONST argv[];        /* Args describing things to configure. */
600    int flags;                    /* Flags to pass to Tk_ConfigureWidget. */
601{
602    PlacardItem *plPtr = (PlacardItem *) itemPtr;
603    XGCValues gcValues;
604    GC newGC;
605    unsigned long mask;
606    Tk_Window tkwin;
607    XColor *color;
608    Tk_Image image;
609
610    tkwin = Tk_CanvasTkwin(canvas);
611    if (Tk_ConfigureWidget(interp, tkwin, configSpecs,
612            argc, (CONST char **) argv,
613            (char*)plPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
614        return TCL_ERROR;
615    }
616
617    /*
618     * A few of the options require additional processing, such as
619     * graphics contexts.
620     */
621    color = plPtr->textColor;
622    newGC = None;
623    if (plPtr->tkfont != NULL) {
624        gcValues.font = Tk_FontId(plPtr->tkfont);
625        mask = GCFont;
626        if (color != NULL) {
627            gcValues.foreground = color->pixel;
628            mask |= GCForeground;
629            newGC = Tk_GetGC(tkwin, mask, &gcValues);
630        }
631    }
632    if (plPtr->gcText != None) {
633        Tk_FreeGC(Tk_Display(tkwin), plPtr->gcText);
634    }
635    plPtr->gcText = newGC;
636
637
638    newGC = None;
639    if (plPtr->lineColor != NULL) {
640        gcValues.foreground = plPtr->lineColor->pixel;
641        gcValues.line_width = 1;
642        mask = GCForeground | GCLineWidth;
643        newGC = Tk_GetGC(tkwin, mask, &gcValues);
644    }
645    if (plPtr->gcLineRect != None) {
646        Tk_FreeGC(Tk_Display(tkwin), plPtr->gcLineRect);
647    }
648    plPtr->gcLineRect = newGC;
649
650
651    if (plPtr->imageLeftString != NULL) {
652        image = Tk_GetImage(interp, tkwin, plPtr->imageLeftString,
653                ImageLeftChangedProc, (ClientData)plPtr);
654        if (image == NULL) {
655            return TCL_ERROR;
656        }
657    } else {
658        image = NULL;
659    }
660    if (plPtr->imageLeft != NULL) {
661        Tk_FreeImage(plPtr->imageLeft);
662    }
663    plPtr->imageLeft = image;
664
665    if (image != NULL) {
666        Tk_SizeOfImage(image,&plPtr->imageLeftW, &plPtr->imageLeftH);
667    }
668
669
670    if (plPtr->imageRightString != NULL) {
671        image = Tk_GetImage(interp, tkwin, plPtr->imageRightString,
672                ImageRightChangedProc, (ClientData)plPtr);
673        if (image == NULL) {
674            return TCL_ERROR;
675        }
676    } else {
677        image = NULL;
678    }
679    if (plPtr->imageRight != NULL) {
680        Tk_FreeImage(plPtr->imageRight);
681    }
682    plPtr->imageRight = image;
683
684    if (image != NULL) {
685        Tk_SizeOfImage(image,&plPtr->imageRightW, &plPtr->imageRightH);
686    }
687
688
689    if (plPtr->text != NULL) {
690        plPtr->textNumBytes = strlen(plPtr->text);
691        plPtr->textNumChars = Tcl_NumUtfChars(plPtr->text, plPtr->textNumBytes);
692    };
693
694    ComputePlacardBbox(canvas, plPtr);
695    return TCL_OK;
696}
697
698/*
699 * ------------------------------------------------------------------------
700 *  DeletePlacard --
701 *
702 *    This procedure is called to clean up the data structure
703 *    associated with a placard item.
704 *
705 *  Results:
706 *    None.
707 *
708 *  Side effects:
709 *    Resources associated with itemPtr are released.
710 * ------------------------------------------------------------------------
711 */
712static void
713DeletePlacard(canvas, itemPtr, display)
714    Tk_Canvas canvas;          /* Info about overall canvas widget. */
715    Tk_Item *itemPtr;          /* Item that is being deleted. */
716    Display *display;          /* Display containing window for canvas. */
717{
718    PlacardItem *plPtr = (PlacardItem *) itemPtr;
719
720    if (plPtr->textColor != NULL) {
721        Tk_FreeColor(plPtr->textColor);
722    }
723    if (plPtr->lineColor != NULL) {
724        Tk_FreeColor(plPtr->lineColor);
725    }
726    if (plPtr->text != NULL) {
727        ckfree(plPtr->text);
728    }
729
730
731    if (plPtr->imageLeftString != NULL) {
732        ckfree(plPtr->imageLeftString);
733    }
734    if (plPtr->imageLeft != NULL ) {
735        Tk_FreeImage(plPtr->imageLeft);
736    }
737    if (plPtr->imageRightString != NULL) {
738        ckfree(plPtr->imageRightString);
739    }
740    if (plPtr->imageRight != NULL ) {
741        Tk_FreeImage(plPtr->imageRight);
742    }
743
744    Tk_FreeTextLayout(plPtr->textLayout);
745
746    Tk_FreeFont(plPtr->tkfont);
747
748    if (plPtr->gcText != None) {
749        Tk_FreeGC(display, plPtr->gcText);
750    }
751    if (plPtr->gcLineRect != None) {
752        Tk_FreeGC(display, plPtr->gcLineRect);
753    }
754}
755
756/*
757 * ------------------------------------------------------------------------
758 *  ComputePlacardBbox --
759 *
760 *    This procedure is invoked to compute the bounding box of
761 *    all the pixels that may be drawn as part of a text item.
762 *    In addition, it recomputes all of the geometry information
763 *    used to display a text item or check for mouse hits.
764 *
765 *  Results:
766 *    None.
767 *
768 *  Side effects:
769 *    The fields x1, y1, x2, and y2 are updated in the header
770 *    for itemPtr, and the linePtr structure is regenerated
771 *    for itemPtr.
772 * ------------------------------------------------------------------------
773 */
774static void
775ComputePlacardBbox(canvas, plPtr)
776    Tk_Canvas canvas;           /* Canvas that contains item. */
777    PlacardItem *plPtr;       /* Item whose bbox is to be recomputed. */
778{
779    int leftX, topY, width, height, maxwidth, ellw, ellh;
780
781    /*
782     * Get the layout for the placard text.
783     */
784    plPtr->textDrawChars = plPtr->textNumChars;
785
786    Tk_FreeTextLayout(plPtr->textLayout);
787    plPtr->textLayout = Tk_ComputeTextLayout(plPtr->tkfont,
788            plPtr->text, plPtr->textNumChars, -1,
789            TK_JUSTIFY_LEFT, 0, &width, &height);
790
791    plPtr->textWidth = width;
792
793    if (plPtr->textColor == NULL) {
794        width = height = 0;
795    } else {
796        width += 2*plPtr->padding;
797        height += 2*plPtr->padding;
798    }
799
800    /*
801     * If the current value has an image, add on its width.
802     */
803    if (plPtr->imageLeft) {
804        width += plPtr->imageLeftW;
805        if (plPtr->textWidth > 0) {
806            width += plPtr->padding;
807        }
808        if (plPtr->imageLeftH > height) {
809            height = plPtr->imageLeftH;
810        }
811    }
812    if (plPtr->imageRight) {
813        width += plPtr->imageRightW;
814        if (plPtr->textWidth > 0) {
815            width += plPtr->padding;
816        }
817        if (plPtr->imageRightH > height) {
818            height = plPtr->imageRightH;
819        }
820    }
821
822    /*
823     * Add on extra size for the 3D border (if there is one).
824     */
825    if (plPtr->borderWidth > 0) {
826        width += 2*plPtr->borderWidth;
827        height += 2*plPtr->borderWidth;
828    }
829
830    /*
831     * If the overall width exceeds the -maxwidth, then we must
832     * truncate the text to make it fit.
833     */
834    maxwidth = 0;
835    if (plPtr->maxWidth > 0 && plPtr->width > 0) {
836        maxwidth = (plPtr->width < plPtr->maxWidth) ? plPtr->width : plPtr->maxWidth;
837    } else if (plPtr->maxWidth > 0) {
838        maxwidth = plPtr->maxWidth;
839    } else if (plPtr->width > 0) {
840        maxwidth = plPtr->width;
841    }
842
843    if (maxwidth > 0 && width > maxwidth) {
844        Tk_SizeOfBitmap(Tk_Display(plPtr->tkwin), plPtr->dots, &ellw, &ellh);
845        width = maxwidth - 2*plPtr->padding - 2*plPtr->borderWidth - ellw;
846        if (plPtr->imageLeft) {
847            width -= plPtr->imageLeftW + plPtr->padding;
848        }
849        if (plPtr->imageRight) {
850            width -= plPtr->imageRightW + plPtr->padding;
851        }
852        if (width < 0) { width = 0; }
853
854        plPtr->textDrawChars = Tk_MeasureChars(plPtr->tkfont,
855            plPtr->text, plPtr->textNumChars, width, /*flags*/ 0,
856            &plPtr->textWidth);
857
858        /* recompute layout for truncated text */
859        Tk_FreeTextLayout(plPtr->textLayout);
860        plPtr->textLayout = Tk_ComputeTextLayout(plPtr->tkfont,
861                plPtr->text, plPtr->textDrawChars, -1,
862                TK_JUSTIFY_LEFT, 0, NULL, NULL);
863
864        width = maxwidth;  /* fit everything in this width */
865    }
866
867    /*
868     * If there's a fixed -width, then use that instead.
869     */
870    if (plPtr->width > 0) {
871        width = plPtr->width;
872    }
873
874    /*
875     * Use overall geometry information to compute the top-left corner
876     * of the bounding box for the text item.
877     */
878    leftX = (int) (plPtr->x + 0.5);
879    topY = (int) (plPtr->y + 0.5);
880    switch (plPtr->anchor) {
881        case TK_ANCHOR_NW:
882        case TK_ANCHOR_N:
883        case TK_ANCHOR_NE:
884            break;
885
886        case TK_ANCHOR_W:
887        case TK_ANCHOR_CENTER:
888        case TK_ANCHOR_E:
889            topY -= height / 2;
890            break;
891
892        case TK_ANCHOR_SW:
893        case TK_ANCHOR_S:
894        case TK_ANCHOR_SE:
895            topY -= height;
896            break;
897    }
898    switch (plPtr->anchor) {
899        case TK_ANCHOR_NW:
900        case TK_ANCHOR_W:
901        case TK_ANCHOR_SW:
902            break;
903
904        case TK_ANCHOR_N:
905        case TK_ANCHOR_CENTER:
906        case TK_ANCHOR_S:
907            leftX -= width / 2;
908            break;
909
910        case TK_ANCHOR_NE:
911        case TK_ANCHOR_E:
912        case TK_ANCHOR_SE:
913            leftX -= width;
914            break;
915    }
916
917    plPtr->leftEdge  = leftX;
918    plPtr->rightEdge = leftX + width;
919
920    /*
921     * Last of all, update the bounding box for the item.
922     */
923    plPtr->header.x1 = leftX;
924    plPtr->header.y1 = topY;
925    plPtr->header.x2 = leftX + width;
926    plPtr->header.y2 = topY + height;
927}
928
929/*
930 * ------------------------------------------------------------------------
931 *  DisplayCanvPlacard --
932 *
933 *    This procedure is invoked to draw a text item in a given drawable.
934 *
935 *  Results:
936 *    None.
937 *
938 *  Side effects:
939 *    ItemPtr is drawn in drawable using the transformation information
940 *    in canvas.
941 * ------------------------------------------------------------------------
942 */
943static void
944DisplayCanvPlacard(canvas, itemPtr, display, drawable, x, y, width, height)
945    Tk_Canvas canvas;           /* Canvas that contains item. */
946    Tk_Item *itemPtr;           /* Item to be displayed. */
947    Display *display;           /* Display on which to draw item. */
948    Drawable drawable;          /* Pixmap or window in which to draw item. */
949    int x, y, width, height;    /* Describes region of canvas that must be
950                                 * redisplayed (not used). */
951{
952    PlacardItem *plPtr = (PlacardItem *) itemPtr;
953    int imagew, delta, ellx, elly, ellw, ellh;
954    short drawableX, drawableY;
955    Tk_FontMetrics fm;
956
957    if (plPtr->gcText == None) {
958        return;
959    }
960
961    /*
962     * If there's a background rectangle, draw it first.
963     */
964    Tk_CanvasDrawableCoords(canvas, (double)plPtr->leftEdge,
965            (double)plPtr->header.y1, &drawableX, &drawableY);
966
967    if (plPtr->bgBorder) {
968        Tk_Fill3DRectangle(plPtr->tkwin, drawable, plPtr->bgBorder,
969            (int)drawableX, (int)drawableY,
970            (int)(plPtr->rightEdge - plPtr->leftEdge),
971            (int)(plPtr->header.y2 - plPtr->header.y1),
972            plPtr->borderWidth, plPtr->relief);
973    }
974
975    if (plPtr->gcLineRect) {
976        XDrawRectangle(display, drawable, plPtr->gcLineRect,
977            (int)drawableX, (int)drawableY,
978            (unsigned int)(plPtr->rightEdge - plPtr->leftEdge - 1),
979            (unsigned int)(plPtr->header.y2 - plPtr->header.y1 - 1));
980    }
981
982    /*
983     * If there's a right-hand image, draw it first.
984     */
985    imagew = 0;
986    if (plPtr->imageRight) {
987        Tk_CanvasDrawableCoords(canvas, (double)plPtr->rightEdge,
988                (double)plPtr->header.y1, &drawableX, &drawableY);
989
990        delta = (plPtr->header.y2 - plPtr->header.y1)/2 - plPtr->imageRightH/2;
991        drawableX -= plPtr->imageRightW + plPtr->padding + plPtr->borderWidth;
992        Tk_RedrawImage(plPtr->imageRight, 0, 0,
993                       plPtr->imageRightW, plPtr->imageRightH,
994                       drawable,
995                       (int)drawableX, (int)(drawableY+delta));
996        imagew += plPtr->imageRightW;
997    }
998
999    /*
1000     * If there's a left-hand image, draw it next.
1001     */
1002    Tk_CanvasDrawableCoords(canvas, (double)plPtr->leftEdge,
1003            (double)plPtr->header.y1, &drawableX, &drawableY);
1004
1005    drawableX += plPtr->padding + plPtr->borderWidth;
1006    drawableY += plPtr->padding + plPtr->borderWidth;
1007
1008    if (plPtr->imageLeft) {
1009        delta = (plPtr->header.y2 - plPtr->header.y1)/2
1010                       - plPtr->imageLeftH/2 - plPtr->padding
1011                       - plPtr->borderWidth;
1012
1013        Tk_RedrawImage(plPtr->imageLeft, 0, 0,
1014                       plPtr->imageLeftW, plPtr->imageLeftH,
1015                       drawable,
1016                       (int)drawableX, (int)(drawableY+delta));
1017        drawableX += plPtr->imageLeftW + plPtr->padding;
1018        imagew += plPtr->imageLeftW;
1019    }
1020
1021    /*
1022     * Draw the text.
1023     */
1024    Tk_DrawTextLayout(display, drawable, plPtr->gcText, plPtr->textLayout,
1025            drawableX, drawableY, 0, -1);
1026
1027    if (plPtr->textDrawChars < plPtr->textNumChars
1028          && plPtr->rightEdge - plPtr->leftEdge - imagew > ellw) {
1029        Tk_SizeOfBitmap(Tk_Display(plPtr->tkwin), plPtr->dots, &ellw, &ellh);
1030        Tk_GetFontMetrics(plPtr->tkfont, &fm);
1031        ellx = drawableX+plPtr->textWidth;
1032        elly = drawableY+fm.ascent-1;
1033
1034        XSetClipMask(display, plPtr->gcText, plPtr->dots);
1035        XSetClipOrigin(display, plPtr->gcText, ellx, elly);
1036
1037        XCopyPlane(display, plPtr->dots, drawable, plPtr->gcText, 0, 0,
1038            (unsigned int)ellw, (unsigned int)ellh, ellx, elly, 1);
1039
1040        XSetClipOrigin(display, plPtr->gcText, 0, 0);
1041        XSetClipMask(display, plPtr->gcText, None);
1042    }
1043}
1044
1045/*
1046 * ------------------------------------------------------------------------
1047 *  PlacardToPoint --
1048 *
1049 *    Computes the distance from a given point to a given placard
1050 *    item, in canvas units.
1051 *
1052 *  Results:
1053 *    The return value is 0 if the point whose x and y coordinates
1054 *    are pointPtr[0] and pointPtr[1] is inside the text item.  If
1055 *    the point isn't inside the text item then the return value
1056 *    is the distance from the point to the text item.
1057 *
1058 *  Side effects:
1059 *    None.
1060 * ------------------------------------------------------------------------
1061 */
1062static double
1063PlacardToPoint(canvas, itemPtr, pointPtr)
1064    Tk_Canvas canvas;                /* Canvas containing itemPtr. */
1065    Tk_Item *itemPtr;                /* Item to check against point. */
1066    double *pointPtr;                /* Pointer to x and y coordinates. */
1067{
1068    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1069    double value, x0, y0, x1, y1, xDiff, yDiff;
1070
1071    if (plPtr->bgBorder || plPtr->lineColor) {
1072        /* have a rectangle -- compare directly against that */
1073        x0 = plPtr->leftEdge;
1074        y0 = plPtr->header.y1;
1075        x1 = plPtr->rightEdge;
1076        y1 = plPtr->header.y2;
1077    }
1078    else if (plPtr->imageLeft || plPtr->imageRight) {
1079        /* have images -- compare against a rectangle around image/text */
1080        x0 = plPtr->leftEdge + plPtr->padding + plPtr->borderWidth;
1081        y0 = plPtr->header.y1 + plPtr->padding + plPtr->borderWidth;
1082        x1 = plPtr->rightEdge - plPtr->padding - plPtr->borderWidth;
1083        y1 = plPtr->header.y2 - plPtr->padding - plPtr->borderWidth;
1084    }
1085    else {
1086        value = (double) Tk_DistanceToTextLayout(plPtr->textLayout,
1087                    (int) pointPtr[0] - plPtr->leftEdge,
1088                    (int) pointPtr[1] - plPtr->header.y1);
1089
1090        if ((plPtr->textColor == NULL) || (plPtr->text == NULL)
1091              || (*plPtr->text == 0)) {
1092            value = 1.0e36;
1093        }
1094        return value;
1095    }
1096
1097    if (pointPtr[0] < x0) {
1098        xDiff = x0 - pointPtr[0];
1099    } else if (pointPtr[0] >= x1)  {
1100        xDiff = pointPtr[0] + 1 - x1;
1101    } else {
1102        xDiff = 0;
1103    }
1104
1105    if (pointPtr[1] < y0) {
1106        yDiff = y0 - pointPtr[1];
1107    } else if (pointPtr[1] >= y1)  {
1108        yDiff = pointPtr[1] + 1 - y1;
1109    } else {
1110        yDiff = 0;
1111    }
1112
1113    return hypot(xDiff, yDiff);
1114}
1115
1116/*
1117 * ------------------------------------------------------------------------
1118 *  PlacardToArea --
1119 *
1120 *    This procedure is called to determine whether an item lies
1121 *    entirely inside, entirely outside, or overlapping a given
1122 *    rectangle.
1123 *
1124 *  Results:
1125 *    -1 is returned if the item is entirely outside the area given
1126 *    by rectPtr, 0 if it overlaps, and 1 if it is entirely inside
1127 *    the given area.
1128 *
1129 *  Side effects:
1130 *    None.
1131 * ------------------------------------------------------------------------
1132 */
1133static int
1134PlacardToArea(canvas, itemPtr, rectPtr)
1135    Tk_Canvas canvas;       /* Canvas containing itemPtr. */
1136    Tk_Item *itemPtr;       /* Item to check against rectangle. */
1137    double *rectPtr;        /* Pointer to array of four coordinates
1138                             * (x1, y1, x2, y2) describing rectangular
1139                             * area.  */
1140{
1141    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1142    int x0, y0, x1, y1;
1143
1144    if (plPtr->bgBorder || plPtr->lineColor) {
1145        /* have a rectangle -- compare directly against that */
1146        x0 = plPtr->leftEdge;
1147        y0 = plPtr->header.y1;
1148        x1 = plPtr->rightEdge;
1149        y1 = plPtr->header.y2;
1150    }
1151    else if (plPtr->imageLeft || plPtr->imageRight) {
1152        /* have images -- compare against a rectangle around image/text */
1153        x0 = plPtr->leftEdge + plPtr->padding + plPtr->borderWidth;
1154        y0 = plPtr->header.y1 + plPtr->padding + plPtr->borderWidth;
1155        x1 = plPtr->rightEdge - plPtr->padding - plPtr->borderWidth;
1156        y1 = plPtr->header.y2 - plPtr->padding - plPtr->borderWidth;
1157    }
1158    else {
1159        /* have only text -- compare against text layout */
1160        return Tk_IntersectTextLayout(plPtr->textLayout,
1161            (int) (rectPtr[0] + 0.5) - (plPtr->leftEdge + plPtr->padding + plPtr->borderWidth),
1162            (int) (rectPtr[1] + 0.5) - (plPtr->header.y1 + plPtr->padding + plPtr->borderWidth),
1163            (int) (rectPtr[2] - rectPtr[0] + 0.5),
1164            (int) (rectPtr[3] - rectPtr[1] + 0.5));
1165    }
1166
1167    /* compare against rectangle... */
1168    if (rectPtr[0] > x1 || rectPtr[1] > y1
1169          || rectPtr[2] < x0 || rectPtr[3] < y0) {
1170        return -1;  /* completely outside */
1171    }
1172    if (rectPtr[0] >= x0 && rectPtr[1] >= y0
1173          && rectPtr[2] <= x1 && rectPtr[3] <= y1) {
1174        return 1;  /* completely inside */
1175    }
1176    return 0;  /* must be overlapping */
1177}
1178
1179/*
1180 * ------------------------------------------------------------------------
1181 *  ScalePlacard --
1182 *
1183 *    This procedure is invoked to rescale a text item.
1184 *
1185 * Results:
1186 *    None.
1187 *
1188 * Side effects:
1189 *    Scales the position of the text, but not the size of the font
1190 *    for the text.
1191 * ------------------------------------------------------------------------
1192 */
1193        /* ARGSUSED */
1194static void
1195ScalePlacard(canvas, itemPtr, originX, originY, scaleX, scaleY)
1196    Tk_Canvas canvas;             /* Canvas containing rectangle. */
1197    Tk_Item *itemPtr;             /* Rectangle to be scaled. */
1198    double originX, originY;      /* Origin about which to scale rect. */
1199    double scaleX;                /* Amount to scale in X direction. */
1200    double scaleY;                /* Amount to scale in Y direction. */
1201{
1202    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1203
1204    plPtr->x = originX + scaleX*(plPtr->x - originX);
1205    plPtr->y = originY + scaleY*(plPtr->y - originY);
1206    ComputePlacardBbox(canvas, plPtr);
1207    return;
1208}
1209
1210/*
1211 * ------------------------------------------------------------------------
1212 *  TranslatePlacard --
1213 *
1214 *    This procedure is called to move a text item by a given amount.
1215 *
1216 *  Results:
1217 *    None.
1218 *
1219 *  Side effects:
1220 *    The position of the text item is offset by (xDelta, yDelta),
1221 *    and the bounding box is updated in the generic part of the
1222 *    item structure.
1223 * ------------------------------------------------------------------------
1224 */
1225static void
1226TranslatePlacard(canvas, itemPtr, deltaX, deltaY)
1227    Tk_Canvas canvas;             /* Canvas containing item. */
1228    Tk_Item *itemPtr;             /* Item that is being moved. */
1229    double deltaX, deltaY;        /* Amount by which item is to be moved. */
1230{
1231    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1232
1233    plPtr->x += deltaX;
1234    plPtr->y += deltaY;
1235    ComputePlacardBbox(canvas, plPtr);
1236}
1237
1238/*
1239 * ------------------------------------------------------------------------
1240 *  PlacardToPostscript --
1241 *
1242 *    This procedure is called to generate Postscript for placard
1243 *    items.
1244 *
1245 *  Results:
1246 *    The return value is a standard Tcl result.  If an error
1247 *    occurs in generating Postscript then an error message is
1248 *    left in the interp's result, replacing whatever used
1249 *    to be there.  If no error occurs, then Postscript for the
1250 *    item is appended to the result.
1251 *
1252 *  Side effects:
1253 *    None.
1254 * ------------------------------------------------------------------------
1255 */
1256static int
1257PlacardToPostscript(interp, canvas, itemPtr, prepass)
1258    Tcl_Interp *interp;         /* Leave Postscript or error message here. */
1259    Tk_Canvas canvas;           /* Information about overall canvas. */
1260    Tk_Item *itemPtr;           /* Item for which Postscript is wanted. */
1261    int prepass;                /* 1 means this is a prepass to collect
1262                                 * font information; 0 means final Postscript
1263                                 * is being created. */
1264{
1265    PlacardItem *plPtr = (PlacardItem *) itemPtr;
1266    Tk_Window canvasWin = Tk_CanvasTkwin(canvas);
1267
1268    int x, y;
1269    double xpos;
1270    Tk_FontMetrics fm;
1271    char *justify;
1272    char buffer[500];
1273    int delta;
1274
1275    if (plPtr->textColor == NULL || plPtr->text == NULL
1276          || *plPtr->text == 0) {
1277        return TCL_OK;
1278    }
1279
1280    if (Tk_CanvasPsFont(interp, canvas, plPtr->tkfont) != TCL_OK) {
1281        return TCL_ERROR;
1282    }
1283
1284
1285    if (!prepass &&
1286        Tk_CanvasPsColor(interp, canvas, plPtr->textColor) != TCL_OK) {
1287        return TCL_ERROR;
1288    }
1289    xpos = plPtr->x;
1290
1291    /*
1292     * Check for an image to print.
1293     */
1294
1295    if (plPtr->imageLeft) {
1296      if(!prepass) {
1297        delta = (plPtr->header.y2 - plPtr->header.y1)/2 - plPtr->imageLeftH/2;
1298        sprintf(buffer, "%.15g %.15g", xpos,
1299                Tk_CanvasPsY(canvas, plPtr->y+delta+2));
1300        Tcl_AppendResult(interp, buffer, " translate\n", (char *) NULL);
1301      }
1302
1303      Tk_PostscriptImage(plPtr->imageLeft, interp, canvasWin,
1304                         ((TkCanvas*)canvas)->psInfo, 0, 0,
1305                         plPtr->imageLeftW, plPtr->imageLeftH, prepass);
1306
1307      if ( !prepass ) {
1308        /*
1309         * This PS code is needed in order for the label to display
1310         * correctly
1311         */
1312       
1313        Tcl_AppendResult(interp,"grestore\ngsave\n",(char *)NULL);
1314      }
1315
1316      xpos += plPtr->imageLeftW + plPtr->padding;
1317    }
1318
1319   
1320    if (prepass != 0 ) {
1321      return TCL_OK;
1322    }
1323
1324    /*
1325     * Before drawing the text, reset the font and color information.
1326     * Otherwise the text won't appear.
1327     */
1328
1329    if ( plPtr->imageLeft ){
1330      if (Tk_CanvasPsFont(interp, canvas, plPtr->tkfont) != TCL_OK) {
1331        return TCL_ERROR;
1332      }
1333     
1334      if (Tk_CanvasPsColor(interp, canvas, plPtr->textColor) != TCL_OK) {
1335        return TCL_ERROR;
1336      }
1337    }
1338
1339
1340    /*
1341     * Draw the text for the placard.
1342     */
1343    sprintf(buffer, "%.15g %.15g [\n", xpos,
1344        Tk_CanvasPsY(canvas, plPtr->y));
1345    Tcl_AppendResult(interp, buffer, (char *) NULL);
1346
1347    Tk_TextLayoutToPostscript(interp, plPtr->textLayout);
1348
1349    x = 0;  y = 0;  justify = NULL;
1350    switch (plPtr->anchor) {
1351        case TK_ANCHOR_NW:        x = 0; y = 0;        break;
1352        case TK_ANCHOR_N:         x = 1; y = 0;        break;
1353        case TK_ANCHOR_NE:        x = 2; y = 0;        break;
1354        case TK_ANCHOR_E:         x = 2; y = 1;        break;
1355        case TK_ANCHOR_SE:        x = 2; y = 2;        break;
1356        case TK_ANCHOR_S:         x = 1; y = 2;        break;
1357        case TK_ANCHOR_SW:        x = 0; y = 2;        break;
1358        case TK_ANCHOR_W:         x = 0; y = 1;        break;
1359        case TK_ANCHOR_CENTER:    x = 1; y = 1;        break;
1360    }
1361    justify = "0"; /* TK_JUSTIFY_LEFT */
1362
1363    Tk_GetFontMetrics(plPtr->tkfont, &fm);
1364    sprintf(buffer, "] %d %g %g %s %s DrawText\n",
1365            fm.linespace, x / -2.0, y / 2.0, justify,
1366            "false" /* stipple */);
1367    Tcl_AppendResult(interp, buffer, (char *) NULL);
1368
1369    return TCL_OK;
1370}
1371
1372/*
1373 * ----------------------------------------------------------------------
1374 *
1375 * ImageLeftChangedProc --
1376 *
1377 *      This procedure is invoked by the image code whenever the manager
1378 *      for an image does something that affects the image's size or
1379 *      how it is displayed.
1380 *
1381 * Results:
1382 *      None.
1383 *
1384 * Side effects:
1385 *      Arranges for the canvas to get redisplayed.
1386 *
1387 * ----------------------------------------------------------------------
1388 */
1389static void
1390ImageLeftChangedProc(clientData, x, y, width, height, imgWidth, imgHeight)
1391    ClientData clientData;              /* Pointer to canvas item for image. */
1392    int x, y;                           /* Upper left pixel (within image)
1393                                         * that must be redisplayed. */
1394    int width, height;                  /* Dimensions of area to redisplay
1395                                         * (may be <= 0). */
1396    int imgWidth, imgHeight;            /* New dimensions of image. */
1397{     
1398    PlacardItem *plPtr = (PlacardItem *) clientData;
1399   
1400    plPtr->imageLeftW = imgWidth;
1401    plPtr->imageLeftH = imgHeight;
1402    ComputePlacardBbox(plPtr->canvas, plPtr);
1403    return;
1404}
1405
1406/*
1407 * ----------------------------------------------------------------------
1408 *
1409 * ImageRightChangedProc --
1410 *
1411 *      This procedure is invoked by the image code whenever the manager
1412 *      for an image does something that affects the image's size or
1413 *      how it is displayed.
1414 *
1415 * Results:
1416 *      None.
1417 *
1418 * Side effects:
1419 *      Arranges for the canvas to get redisplayed.
1420 *
1421 * ----------------------------------------------------------------------
1422 */
1423static void
1424ImageRightChangedProc(clientData, x, y, width, height, imgWidth, imgHeight)
1425    ClientData clientData;              /* Pointer to canvas item for image. */
1426    int x, y;                           /* Upper left pixel (within image)
1427                                         * that must be redisplayed. */
1428    int width, height;                  /* Dimensions of area to redisplay
1429                                         * (may be <= 0). */
1430    int imgWidth, imgHeight;            /* New dimensions of image. */
1431{     
1432    PlacardItem *plPtr = (PlacardItem *) clientData;
1433   
1434    plPtr->imageRightW = imgWidth;
1435    plPtr->imageRightH = imgHeight;
1436    ComputePlacardBbox(plPtr->canvas, plPtr);
1437    return;
1438}
1439
1440/*
1441 * ------------------------------------------------------------------------
1442 *  Rappture_canvas_placard_Init --
1443 *
1444 *  Invoked when the Rappture GUI library is being initialized
1445 *  to install the "placard" item on the Tk canvas widget.
1446 *
1447 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
1448 *  message in the interp) if anything goes wrong.
1449 * ------------------------------------------------------------------------
1450 */
1451int
1452Rappture_canvas_placard_Init(interp)
1453    Tcl_Interp *interp;         /* interpreter being initialized */
1454{
1455    Tk_CreateItemType(&rpPlacardType);
1456
1457    Tk_DefineBitmap(interp, Tk_GetUid("rp_ellipsis"),
1458        (char*)ellipsis_bits, ellipsis_width, ellipsis_height);
1459
1460    return TCL_OK;
1461}
Note: See TracBrowser for help on using the repository browser.