OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / tk / generic / tkTextImage.c
1 /* 
2  * tkImage.c --
3  *
4  *      This file contains code that allows images to be
5  *      nested inside text widgets.  It also implements the "image"
6  *      widget command for texts.
7  *
8  * Copyright (c) 1996 Sun Microsystems, Inc.
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * RCS: @(#) $Id$
14  */
15
16 #include "tk.h"
17 #include "tkText.h"
18 #include "tkPort.h"
19
20 /*
21  * Definitions for alignment values:
22  */
23
24 #define ALIGN_BOTTOM            0
25 #define ALIGN_CENTER            1
26 #define ALIGN_TOP               2
27 #define ALIGN_BASELINE          3
28
29 /*
30  * Macro that determines the size of an embedded image segment:
31  */
32
33 #define EI_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
34         + sizeof(TkTextEmbImage)))
35
36 /*
37  * Prototypes for procedures defined in this file:
38  */
39
40 static int              AlignParseProc _ANSI_ARGS_((ClientData clientData,
41                             Tcl_Interp *interp, Tk_Window tkwin, char *value,
42                             char *widgRec, int offset));
43 static char *           AlignPrintProc _ANSI_ARGS_((ClientData clientData,
44                             Tk_Window tkwin, char *widgRec, int offset,
45                             Tcl_FreeProc **freeProcPtr));
46 static TkTextSegment *  EmbImageCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
47                             TkTextLine *linePtr));
48 static void             EmbImageCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
49                             TkTextLine *linePtr));
50 static void             EmbImageBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr,
51                             int index, int y, int lineHeight, int baseline,
52                             int *xPtr, int *yPtr, int *widthPtr,
53                             int *heightPtr));
54 static int              EmbImageConfigure _ANSI_ARGS_((TkText *textPtr,
55                             TkTextSegment *eiPtr, int argc, char **argv));
56 static int              EmbImageDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
57                             TkTextLine *linePtr, int treeGone));
58 static void             EmbImageDisplayProc _ANSI_ARGS_((
59                             TkTextDispChunk *chunkPtr, int x, int y,
60                             int lineHeight, int baseline, Display *display,
61                             Drawable dst, int screenY));
62 static int              EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr,
63                             TkTextIndex *indexPtr, TkTextSegment *segPtr,
64                             int offset, int maxX, int maxChars,
65                             int noCharsYet, Tk_Uid wrapMode,
66                             TkTextDispChunk *chunkPtr));
67 static void             EmbImageProc _ANSI_ARGS_((ClientData clientData,
68                             int x, int y, int width, int height,
69                             int imageWidth, int imageHeight));
70
71 /*
72  * The following structure declares the "embedded image" segment type.
73  */
74
75 static Tk_SegType tkTextEmbImageType = {
76     "image",                                    /* name */
77     0,                                          /* leftGravity */
78     (Tk_SegSplitProc *) NULL,                   /* splitProc */
79     EmbImageDeleteProc,                         /* deleteProc */
80     EmbImageCleanupProc,                        /* cleanupProc */
81     (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */
82     EmbImageLayoutProc,                         /* layoutProc */
83     EmbImageCheckProc                           /* checkProc */
84 };
85
86 /*
87  * Information used for parsing image configuration options:
88  */
89
90 static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc,
91         (ClientData) NULL};
92
93 static Tk_ConfigSpec configSpecs[] = {
94     {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL,
95         "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption},
96     {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL,
97         "0", Tk_Offset(TkTextEmbImage, padX),
98         TK_CONFIG_DONT_SET_DEFAULT},
99     {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL,
100         "0", Tk_Offset(TkTextEmbImage, padY),
101         TK_CONFIG_DONT_SET_DEFAULT},
102     {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL,
103         (char *) NULL, Tk_Offset(TkTextEmbImage, imageString),
104         TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
105     {TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL,
106         (char *) NULL, Tk_Offset(TkTextEmbImage, imageName),
107         TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
108     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
109         (char *) NULL, 0, 0}
110 };
111 \f
112 /*
113  *--------------------------------------------------------------
114  *
115  * TkTextImageCmd --
116  *
117  *      This procedure implements the "image" widget command
118  *      for text widgets.  See the user documentation for details
119  *      on what it does.
120  *
121  * Results:
122  *      A standard Tcl result or error.
123  *
124  * Side effects:
125  *      See the user documentation.
126  *
127  *--------------------------------------------------------------
128  */
129
130 int
131 TkTextImageCmd(textPtr, interp, argc, argv)
132     register TkText *textPtr;   /* Information about text widget. */
133     Tcl_Interp *interp;         /* Current interpreter. */
134     int argc;                   /* Number of arguments. */
135     char **argv;                /* Argument strings.  Someone else has already
136                                  * parsed this command enough to know that
137                                  * argv[1] is "image". */
138 {
139     size_t length;
140     register TkTextSegment *eiPtr;
141
142     if (argc < 3) {
143         Tcl_AppendResult(interp, "wrong # args: should be \"",
144                 argv[0], " image option ?arg arg ...?\"", (char *) NULL);
145         return TCL_ERROR;
146     }
147     length = strlen(argv[2]);
148     if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) {
149         TkTextIndex index;
150         TkTextSegment *eiPtr;
151
152         if (argc != 5) {
153             Tcl_AppendResult(interp, "wrong # args: should be \"",
154                     argv[0], " image cget index option\"",
155                     (char *) NULL);
156             return TCL_ERROR;
157         }
158         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
159             return TCL_ERROR;
160         }
161         eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
162         if (eiPtr->typePtr != &tkTextEmbImageType) {
163             Tcl_AppendResult(interp, "no embedded image at index \"",
164                     argv[3], "\"", (char *) NULL);
165             return TCL_ERROR;
166         }
167         return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs,
168                 (char *) &eiPtr->body.ei, argv[4], 0);
169     } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) {
170         TkTextIndex index;
171         TkTextSegment *eiPtr;
172
173         if (argc < 4) {
174             Tcl_AppendResult(interp, "wrong # args: should be \"",
175                     argv[0], " image configure index ?option value ...?\"",
176                     (char *) NULL);
177             return TCL_ERROR;
178         }
179         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
180             return TCL_ERROR;
181         }
182         eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
183         if (eiPtr->typePtr != &tkTextEmbImageType) {
184             Tcl_AppendResult(interp, "no embedded image at index \"",
185                     argv[3], "\"", (char *) NULL);
186             return TCL_ERROR;
187         }
188         if (argc == 4) {
189             return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
190                     (char *) &eiPtr->body.ei, (char *) NULL, 0);
191         } else if (argc == 5) {
192             return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
193                     (char *) &eiPtr->body.ei, argv[4], 0);
194         } else {
195             TkTextChanged(textPtr, &index, &index);
196             return EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4);
197         }
198     } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) {
199         TkTextIndex index;
200         int lineIndex;
201
202         /*
203          * Add a new image.  Find where to put the new image, and
204          * mark that position for redisplay.
205          */
206
207         if (argc < 4) {
208             Tcl_AppendResult(interp, "wrong # args: should be \"",
209                     argv[0], " image create index ?option value ...?\"",
210                     (char *) NULL);
211             return TCL_ERROR;
212         }
213         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
214             return TCL_ERROR;
215         }
216
217         /*
218          * Don't allow insertions on the last (dummy) line of the text.
219          */
220     
221         lineIndex = TkBTreeLineIndex(index.linePtr);
222         if (lineIndex == TkBTreeNumLines(textPtr->tree)) {
223             lineIndex--;
224             TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index);
225         }
226
227         /*
228          * Create the new image segment and initialize it.
229          */
230
231         eiPtr = (TkTextSegment *) ckalloc(EI_SEG_SIZE);
232         eiPtr->typePtr = &tkTextEmbImageType;
233         eiPtr->size = 1;
234         eiPtr->body.ei.textPtr = textPtr;
235         eiPtr->body.ei.linePtr = NULL;
236         eiPtr->body.ei.imageName = NULL;
237         eiPtr->body.ei.imageString = NULL;
238         eiPtr->body.ei.name = NULL;
239         eiPtr->body.ei.image = NULL;
240         eiPtr->body.ei.align = ALIGN_CENTER;
241         eiPtr->body.ei.padX = eiPtr->body.ei.padY = 0;
242         eiPtr->body.ei.chunkCount = 0;
243
244         /*
245          * Link the segment into the text widget, then configure it (delete
246          * it again if the configuration fails).
247          */
248
249         TkTextChanged(textPtr, &index, &index);
250         TkBTreeLinkSegment(eiPtr, &index);
251         if (EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4) != TCL_OK) {
252             TkTextIndex index2;
253
254             TkTextIndexForwChars(&index, 1, &index2);
255             TkBTreeDeleteChars(&index, &index2);
256             return TCL_ERROR;
257         }
258     } else if (strncmp(argv[2], "names", length) == 0) {
259         Tcl_HashSearch search;
260         Tcl_HashEntry *hPtr;
261
262         if (argc != 3) {
263             Tcl_AppendResult(interp, "wrong # args: should be \"",
264                     argv[0], " image names\"", (char *) NULL);
265             return TCL_ERROR;
266         }
267         for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
268                 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
269             Tcl_AppendElement(interp,
270                     Tcl_GetHashKey(&textPtr->markTable, hPtr));
271         }
272     } else {
273         Tcl_AppendResult(interp, "bad image option \"", argv[2],
274                 "\": must be cget, configure, create, or names",
275                 (char *) NULL);
276         return TCL_ERROR;
277     }
278     return TCL_OK;
279 }
280 \f
281 /*
282  *--------------------------------------------------------------
283  *
284  * EmbImageConfigure --
285  *
286  *      This procedure is called to handle configuration options
287  *      for an embedded image, using an argc/argv list.
288  *
289  * Results:
290  *      The return value is a standard Tcl result.  If TCL_ERROR is
291  *      returned, then interp->result contains an error message..
292  *
293  * Side effects:
294  *      Configuration information for the embedded image changes,
295  *      such as alignment, or name of the image.
296  *
297  *--------------------------------------------------------------
298  */
299
300 static int
301 EmbImageConfigure(textPtr, eiPtr, argc, argv)
302     TkText *textPtr;            /* Information about text widget that
303                                  * contains embedded image. */
304     TkTextSegment *eiPtr;       /* Embedded image to be configured. */
305     int argc;                   /* Number of strings in argv. */
306     char **argv;                /* Array of strings describing configuration
307                                  * options. */
308 {
309     Tk_Image image;
310     Tcl_DString newName;
311     Tcl_HashEntry *hPtr;
312     Tcl_HashSearch search;
313     int new;
314     char *name;
315     int count = 0;              /* The counter for picking a unique name */
316     int conflict = 0;           /* True if we have a name conflict */
317     unsigned int len;           /* length of image name */
318
319     if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs,
320             argc, argv, (char *) &eiPtr->body.ei,TK_CONFIG_ARGV_ONLY)
321             != TCL_OK) {
322         return TCL_ERROR;
323     }
324
325     /*
326      * Create the image.  Save the old image around and don't free it
327      * until after the new one is allocated.  This keeps the reference
328      * count from going to zero so the image doesn't have to be recreated
329      * if it hasn't changed.
330      */
331
332     if (eiPtr->body.ei.imageString != NULL) {
333         image = Tk_GetImage(textPtr->interp, textPtr->tkwin, eiPtr->body.ei.imageString,
334                 EmbImageProc, (ClientData) eiPtr);
335         if (image == NULL) {
336             return TCL_ERROR;
337         }
338     } else {
339         image = NULL;
340     }
341     if (eiPtr->body.ei.image != NULL) {
342         Tk_FreeImage(eiPtr->body.ei.image);
343     }
344     eiPtr->body.ei.image = image;
345
346     if (eiPtr->body.ei.name != NULL) {
347         return TCL_OK;
348     }
349
350     /* 
351      * Find a unique name for this image.  Use imageName (or imageString)
352      * if available, otherwise tack on a #nn and use it.  If a name is already
353      * associated with this image, delete the name.
354      */
355
356     name = eiPtr->body.ei.imageName;
357     if (name == NULL) {
358         name = eiPtr->body.ei.imageString;
359     }
360     if (name == NULL) {
361         Tcl_AppendResult(textPtr->interp,"Either a \"-name\" ",
362                 "or a \"-image\" argument must be provided ",
363                 "to the \"image create\" subcommand.",
364                 (char *) NULL);
365         return TCL_ERROR;
366     }
367     len = strlen(name);
368     for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
369             hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
370         char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr);
371         if (strncmp(name, haveName, len) == 0) {
372             new = 0;
373             sscanf(haveName+len,"#%d",&new);
374             if (new > count) {
375                 count = new;
376             }
377             if (len == (int) strlen(haveName)) {
378                 conflict = 1;
379             }
380         }
381     }
382
383     Tcl_DStringInit(&newName);
384     Tcl_DStringAppend(&newName,name, -1);
385
386     if (conflict) {
387         char buf[10];
388         sprintf(buf, "#%d",count+1);
389         Tcl_DStringAppend(&newName,buf, -1);
390     }
391     name = Tcl_DStringValue(&newName);
392     hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new);
393     Tcl_SetHashValue(hPtr, eiPtr);
394     Tcl_AppendResult(textPtr->interp, name , (char *) NULL);
395     eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1);
396     strcpy(eiPtr->body.ei.name,name);
397     Tcl_DStringFree(&newName);
398
399     return TCL_OK;
400 }
401 \f
402 /*
403  *--------------------------------------------------------------
404  *
405  * AlignParseProc --
406  *
407  *      This procedure is invoked by Tk_ConfigureWidget during
408  *      option processing to handle "-align" options for embedded
409  *      images.
410  *
411  * Results:
412  *      A standard Tcl return value.
413  *
414  * Side effects:
415  *      The alignment for the embedded image may change.
416  *
417  *--------------------------------------------------------------
418  */
419
420         /* ARGSUSED */
421 static int
422 AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)
423     ClientData clientData;              /* Not used.*/
424     Tcl_Interp *interp;                 /* Used for reporting errors. */
425     Tk_Window tkwin;                    /* Window for text widget. */
426     char *value;                        /* Value of option. */
427     char *widgRec;                      /* Pointer to TkTextEmbWindow
428                                          * structure. */
429     int offset;                         /* Offset into item (ignored). */
430 {
431     register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec;
432
433     if (strcmp(value, "baseline") == 0) {
434         embPtr->align = ALIGN_BASELINE;
435     } else if (strcmp(value, "bottom") == 0) {
436         embPtr->align = ALIGN_BOTTOM;
437     } else if (strcmp(value, "center") == 0) {
438         embPtr->align = ALIGN_CENTER;
439     } else if (strcmp(value, "top") == 0) {
440         embPtr->align = ALIGN_TOP;
441     } else {
442         Tcl_AppendResult(interp, "bad alignment \"", value,
443                 "\": must be baseline, bottom, center, or top",
444                 (char *) NULL);
445         return TCL_ERROR;
446     }
447     return TCL_OK;
448 }
449 \f
450 /*
451  *--------------------------------------------------------------
452  *
453  * AlignPrintProc --
454  *
455  *      This procedure is invoked by the Tk configuration code
456  *      to produce a printable string for the "-align" configuration
457  *      option for embedded images.
458  *
459  * Results:
460  *      The return value is a string describing the embedded
461  *      images's current alignment.
462  *
463  * Side effects:
464  *      None.
465  *
466  *--------------------------------------------------------------
467  */
468
469         /* ARGSUSED */
470 static char *
471 AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
472     ClientData clientData;              /* Ignored. */
473     Tk_Window tkwin;                    /* Window for text widget. */
474     char *widgRec;                      /* Pointer to TkTextEmbImage
475                                          * structure. */
476     int offset;                         /* Ignored. */
477     Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
478                                          * information about how to reclaim
479                                          * storage for return string. */
480 {
481     switch (((TkTextEmbImage *) widgRec)->align) {
482         case ALIGN_BASELINE:
483             return "baseline";
484         case ALIGN_BOTTOM:
485             return "bottom";
486         case ALIGN_CENTER:
487             return "center";
488         case ALIGN_TOP:
489             return "top";
490         default:
491             return "??";
492     }
493 }
494 \f
495 /*
496  *--------------------------------------------------------------
497  *
498  * EmbImageDeleteProc --
499  *
500  *      This procedure is invoked by the text B-tree code whenever
501  *      an embedded image lies in a range of characters being deleted.
502  *
503  * Results:
504  *      Returns 0 to indicate that the deletion has been accepted.
505  *
506  * Side effects:
507  *      The embedded image is deleted, if it exists, and any resources
508  *      associated with it are released.
509  *
510  *--------------------------------------------------------------
511  */
512
513         /* ARGSUSED */
514 static int
515 EmbImageDeleteProc(eiPtr, linePtr, treeGone)
516     TkTextSegment *eiPtr;               /* Segment being deleted. */
517     TkTextLine *linePtr;                /* Line containing segment. */
518     int treeGone;                       /* Non-zero means the entire tree is
519                                          * being deleted, so everything must
520                                          * get cleaned up. */
521 {
522     Tcl_HashEntry *hPtr;
523
524     if (eiPtr->body.ei.image != NULL) {
525         hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable,
526                 eiPtr->body.ei.name);
527         if (hPtr != NULL) {
528             /*
529              * (It's possible for there to be no hash table entry for this
530              * image, if an error occurred while creating the image segment
531              * but before the image got added to the table)
532              */
533
534             Tcl_DeleteHashEntry(hPtr);
535         }
536         Tk_FreeImage(eiPtr->body.ei.image);
537     }
538     Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei,
539             eiPtr->body.ei.textPtr->display, 0);
540     if (eiPtr->body.ei.name != NULL) {
541         ckfree(eiPtr->body.ei.name);
542     }
543     ckfree((char *) eiPtr);
544     return 0;
545 }
546 \f
547 /*
548  *--------------------------------------------------------------
549  *
550  * EmbImageCleanupProc --
551  *
552  *      This procedure is invoked by the B-tree code whenever a
553  *      segment containing an embedded image is moved from one
554  *      line to another.
555  *
556  * Results:
557  *      None.
558  *
559  * Side effects:
560  *      The linePtr field of the segment gets updated.
561  *
562  *--------------------------------------------------------------
563  */
564
565 static TkTextSegment *
566 EmbImageCleanupProc(eiPtr, linePtr)
567     TkTextSegment *eiPtr;               /* Mark segment that's being moved. */
568     TkTextLine *linePtr;                /* Line that now contains segment. */
569 {
570     eiPtr->body.ei.linePtr = linePtr;
571     return eiPtr;
572 }
573 \f
574 /*
575  *--------------------------------------------------------------
576  *
577  * EmbImageLayoutProc --
578  *
579  *      This procedure is the "layoutProc" for embedded image
580  *      segments.
581  *
582  * Results:
583  *      1 is returned to indicate that the segment should be
584  *      displayed.  The chunkPtr structure is filled in.
585  *
586  * Side effects:
587  *      None, except for filling in chunkPtr.
588  *
589  *--------------------------------------------------------------
590  */
591
592         /*ARGSUSED*/
593 static int
594 EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars,
595         noCharsYet, wrapMode, chunkPtr)
596     TkText *textPtr;            /* Text widget being layed out. */
597     TkTextIndex *indexPtr;      /* Identifies first character in chunk. */
598     TkTextSegment *eiPtr;       /* Segment corresponding to indexPtr. */
599     int offset;                 /* Offset within segPtr corresponding to
600                                  * indexPtr (always 0). */
601     int maxX;                   /* Chunk must not occupy pixels at this
602                                  * position or higher. */
603     int maxChars;               /* Chunk must not include more than this
604                                  * many characters. */
605     int noCharsYet;             /* Non-zero means no characters have been
606                                  * assigned to this line yet. */
607     Tk_Uid wrapMode;            /* Wrap mode to use for line: tkTextCharUid,
608                                  * tkTextNoneUid, or tkTextWordUid. */
609     register TkTextDispChunk *chunkPtr;
610                                 /* Structure to fill in with information
611                                  * about this chunk.  The x field has already
612                                  * been set by the caller. */
613 {
614     int width, height;
615
616     if (offset != 0) {
617         panic("Non-zero offset in EmbImageLayoutProc");
618     }
619
620     /*
621      * See if there's room for this image on this line.
622      */
623
624     if (eiPtr->body.ei.image == NULL) {
625         width = 0;
626         height = 0;
627     } else {
628         Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height);
629         width += 2*eiPtr->body.ei.padX;
630         height += 2*eiPtr->body.ei.padY;
631     }
632     if ((width > (maxX - chunkPtr->x))
633             && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) {
634         return 0;
635     }
636
637     /*
638      * Fill in the chunk structure.
639      */
640
641     chunkPtr->displayProc = EmbImageDisplayProc;
642     chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL;
643     chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
644     chunkPtr->bboxProc = EmbImageBboxProc;
645     chunkPtr->numChars = 1;
646     if (eiPtr->body.ei.align == ALIGN_BASELINE) {
647         chunkPtr->minAscent = height - eiPtr->body.ei.padY;
648         chunkPtr->minDescent = eiPtr->body.ei.padY;
649         chunkPtr->minHeight = 0;
650     } else {
651         chunkPtr->minAscent = 0;
652         chunkPtr->minDescent = 0;
653         chunkPtr->minHeight = height;
654     }
655     chunkPtr->width = width;
656     chunkPtr->breakIndex = -1;
657     chunkPtr->breakIndex = 1;
658     chunkPtr->clientData = (ClientData) eiPtr;
659     eiPtr->body.ei.chunkCount += 1;
660     return 1;
661 }
662 \f
663 /*
664  *--------------------------------------------------------------
665  *
666  * EmbImageCheckProc --
667  *
668  *      This procedure is invoked by the B-tree code to perform
669  *      consistency checks on embedded images.
670  *
671  * Results:
672  *      None.
673  *
674  * Side effects:
675  *      The procedure panics if it detects anything wrong with
676  *      the embedded image.
677  *
678  *--------------------------------------------------------------
679  */
680
681 static void
682 EmbImageCheckProc(eiPtr, linePtr)
683     TkTextSegment *eiPtr;               /* Segment to check. */
684     TkTextLine *linePtr;                /* Line containing segment. */
685 {
686     if (eiPtr->nextPtr == NULL) {
687         panic("EmbImageCheckProc: embedded image is last segment in line");
688     }
689     if (eiPtr->size != 1) {
690         panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size);
691     }
692 }
693 \f
694 /*
695  *--------------------------------------------------------------
696  *
697  * EmbImageDisplayProc --
698  *
699  *      This procedure is invoked by the text displaying code
700  *      when it is time to actually draw an embedded image
701  *      chunk on the screen.
702  *
703  * Results:
704  *      None.
705  *
706  * Side effects:
707  *      The embedded image gets moved to the correct location
708  *      and drawn onto the display.
709  *
710  *--------------------------------------------------------------
711  */
712
713 static void
714 EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)
715     TkTextDispChunk *chunkPtr;          /* Chunk that is to be drawn. */
716     int x;                              /* X-position in dst at which to
717                                          * draw this chunk (differs from
718                                          * the x-position in the chunk because
719                                          * of scrolling). */
720     int y;                              /* Top of rectangular bounding box
721                                          * for line: tells where to draw this
722                                          * chunk in dst (x-position is in
723                                          * the chunk itself). */
724     int lineHeight;                     /* Total height of line. */
725     int baseline;                       /* Offset of baseline from y. */
726     Display *display;                   /* Display to use for drawing. */
727     Drawable dst;                       /* Pixmap or window in which to draw */
728     int screenY;                        /* Y-coordinate in text window that
729                                          * corresponds to y. */
730 {
731     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
732     int lineX, imageX, imageY, width, height;
733     Tk_Image image;
734
735     image = eiPtr->body.ei.image;
736     if (image == NULL) {
737         return;
738     }
739     if ((x + chunkPtr->width) <= 0) {
740         return;
741     }
742
743     /*
744      * Compute the image's location and size in the text widget, taking
745      * into account the align value for the image.
746      */
747
748     EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX,
749             &imageY, &width, &height);
750     imageX = lineX - chunkPtr->x + x;
751
752     Tk_RedrawImage(image, 0, 0, width, height, dst,
753             imageX, imageY);
754 }
755 \f
756 /*
757  *--------------------------------------------------------------
758  *
759  * EmbImageBboxProc --
760  *
761  *      This procedure is called to compute the bounding box of
762  *      the area occupied by an embedded image.
763  *
764  * Results:
765  *      There is no return value.  *xPtr and *yPtr are filled in
766  *      with the coordinates of the upper left corner of the
767  *      image, and *widthPtr and *heightPtr are filled in with
768  *      the dimensions of the image in pixels.  Note:  not all
769  *      of the returned bbox is necessarily visible on the screen
770  *      (the rightmost part might be off-screen to the right,
771  *      and the bottommost part might be off-screen to the bottom).
772  *
773  * Side effects:
774  *      None.
775  *
776  *--------------------------------------------------------------
777  */
778
779 static void
780 EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,
781         widthPtr, heightPtr)
782     TkTextDispChunk *chunkPtr;          /* Chunk containing desired char. */
783     int index;                          /* Index of desired character within
784                                          * the chunk. */
785     int y;                              /* Topmost pixel in area allocated
786                                          * for this line. */
787     int lineHeight;                     /* Total height of line. */
788     int baseline;                       /* Location of line's baseline, in
789                                          * pixels measured down from y. */
790     int *xPtr, *yPtr;                   /* Gets filled in with coords of
791                                          * character's upper-left pixel. */
792     int *widthPtr;                      /* Gets filled in with width of
793                                          * character, in pixels. */
794     int *heightPtr;                     /* Gets filled in with height of
795                                          * character, in pixels. */
796 {
797     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
798     Tk_Image image;
799
800     image = eiPtr->body.ei.image;
801     if (image != NULL) {
802         Tk_SizeOfImage(image, widthPtr, heightPtr);
803     } else {
804         *widthPtr = 0;
805         *heightPtr = 0;
806     }
807     *xPtr = chunkPtr->x + eiPtr->body.ei.padX;
808     switch (eiPtr->body.ei.align) {
809         case ALIGN_BOTTOM:
810             *yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY);
811             break;
812         case ALIGN_CENTER:
813             *yPtr = y + (lineHeight - *heightPtr)/2;
814             break;
815         case ALIGN_TOP:
816             *yPtr = y + eiPtr->body.ei.padY;
817             break;
818         case ALIGN_BASELINE:
819             *yPtr = y + (baseline - *heightPtr);
820             break;
821     }
822 }
823 \f
824 /*
825  *--------------------------------------------------------------
826  *
827  * TkTextImageIndex --
828  *
829  *      Given the name of an embedded image within a text widget,
830  *      returns an index corresponding to the image's position
831  *      in the text.
832  *
833  * Results:
834  *      The return value is 1 if there is an embedded image by
835  *      the given name in the text widget, 0 otherwise.  If the
836  *      image exists, *indexPtr is filled in with its index.
837  *
838  * Side effects:
839  *      None.
840  *
841  *--------------------------------------------------------------
842  */
843
844 int
845 TkTextImageIndex(textPtr, name, indexPtr)
846     TkText *textPtr;            /* Text widget containing image. */
847     char *name;                 /* Name of image. */
848     TkTextIndex *indexPtr;      /* Index information gets stored here. */
849 {
850     Tcl_HashEntry *hPtr;
851     TkTextSegment *eiPtr;
852
853     hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name);
854     if (hPtr == NULL) {
855         return 0;
856     }
857     eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
858     indexPtr->tree = textPtr->tree;
859     indexPtr->linePtr = eiPtr->body.ei.linePtr;
860     indexPtr->charIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr);
861     return 1;
862 }
863 \f
864 /*
865  *--------------------------------------------------------------
866  *
867  * EmbImageProc --
868  *
869  *      This procedure is called by the image code whenever an
870  *      image or its contents changes.
871  *
872  * Results:
873  *      None.
874  *
875  * Side effects:
876  *      The image will be redisplayed.
877  *
878  *--------------------------------------------------------------
879  */
880
881 static void
882 EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
883     ClientData clientData;              /* Pointer to widget record. */
884     int x, y;                           /* Upper left pixel (within image)
885                                          * that must be redisplayed. */
886     int width, height;                  /* Dimensions of area to redisplay
887                                          * (may be <= 0). */
888     int imgWidth, imgHeight;            /* New dimensions of image. */
889
890 {
891     TkTextSegment *eiPtr = (TkTextSegment *) clientData;
892     TkTextIndex index;
893
894     index.tree = eiPtr->body.ei.textPtr->tree;
895     index.linePtr = eiPtr->body.ei.linePtr;
896     index.charIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr);
897     TkTextChanged(eiPtr->body.ei.textPtr, &index, &index);
898 }