source: branches/r9/packages/CanvasPlacard/canvPlacard.c @ 4842

Last change on this file since 4842 was 4842, checked in by gah, 9 years ago
File size: 50.3 KB
RevLine 
[4841]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.