home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkTextImage.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  25.9 KB  |  892 lines  |  [TEXT/CWIE]

  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.  * SCCS: @(#) tkTextImage.c 1.6 97/04/30 15:55:44
  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_INT, "-padx", (char *) NULL, (char *) NULL,
  97.     "0", Tk_Offset(TkTextEmbImage, padX),
  98.     TK_CONFIG_DONT_SET_DEFAULT},
  99.     {TK_CONFIG_INT, "-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.  
  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.  
  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.     len = strlen(name);
  361.     for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
  362.         hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  363.     char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr);
  364.     if (strncmp(name, haveName, len) == 0) {
  365.         new = 0;
  366.         sscanf(haveName+len,"#%d",&new);
  367.         if (new > count) {
  368.         count = new;
  369.         }
  370.         if (len == (int) strlen(haveName)) {
  371.             conflict = 1;
  372.         }
  373.     }
  374.     }
  375.  
  376.     Tcl_DStringInit(&newName);
  377.     Tcl_DStringAppend(&newName,name, -1);
  378.  
  379.     if (conflict) {
  380.         char buf[10];
  381.     sprintf(buf, "#%d",count+1);
  382.     Tcl_DStringAppend(&newName,buf, -1);
  383.     }
  384.     name = Tcl_DStringValue(&newName);
  385.     hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new);
  386.     Tcl_SetHashValue(hPtr, eiPtr);
  387.     Tcl_AppendResult(textPtr->interp, name , (char *) NULL);
  388.     eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1);
  389.     strcpy(eiPtr->body.ei.name,name);
  390.     Tcl_DStringFree(&newName);
  391.  
  392.     return TCL_OK;
  393. }
  394.  
  395. /*
  396.  *--------------------------------------------------------------
  397.  *
  398.  * AlignParseProc --
  399.  *
  400.  *    This procedure is invoked by Tk_ConfigureWidget during
  401.  *    option processing to handle "-align" options for embedded
  402.  *    images.
  403.  *
  404.  * Results:
  405.  *    A standard Tcl return value.
  406.  *
  407.  * Side effects:
  408.  *    The alignment for the embedded image may change.
  409.  *
  410.  *--------------------------------------------------------------
  411.  */
  412.  
  413.     /* ARGSUSED */
  414. static int
  415. AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)
  416.     ClientData clientData;        /* Not used.*/
  417.     Tcl_Interp *interp;            /* Used for reporting errors. */
  418.     Tk_Window tkwin;            /* Window for text widget. */
  419.     char *value;            /* Value of option. */
  420.     char *widgRec;            /* Pointer to TkTextEmbWindow
  421.                      * structure. */
  422.     int offset;                /* Offset into item (ignored). */
  423. {
  424.     register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec;
  425.  
  426.     if (strcmp(value, "baseline") == 0) {
  427.     embPtr->align = ALIGN_BASELINE;
  428.     } else if (strcmp(value, "bottom") == 0) {
  429.     embPtr->align = ALIGN_BOTTOM;
  430.     } else if (strcmp(value, "center") == 0) {
  431.     embPtr->align = ALIGN_CENTER;
  432.     } else if (strcmp(value, "top") == 0) {
  433.     embPtr->align = ALIGN_TOP;
  434.     } else {
  435.     Tcl_AppendResult(interp, "bad alignment \"", value,
  436.         "\": must be baseline, bottom, center, or top",
  437.         (char *) NULL);
  438.     return TCL_ERROR;
  439.     }
  440.     return TCL_OK;
  441. }
  442.  
  443. /*
  444.  *--------------------------------------------------------------
  445.  *
  446.  * AlignPrintProc --
  447.  *
  448.  *    This procedure is invoked by the Tk configuration code
  449.  *    to produce a printable string for the "-align" configuration
  450.  *    option for embedded images.
  451.  *
  452.  * Results:
  453.  *    The return value is a string describing the embedded
  454.  *    images's current alignment.
  455.  *
  456.  * Side effects:
  457.  *    None.
  458.  *
  459.  *--------------------------------------------------------------
  460.  */
  461.  
  462.     /* ARGSUSED */
  463. static char *
  464. AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  465.     ClientData clientData;        /* Ignored. */
  466.     Tk_Window tkwin;            /* Window for text widget. */
  467.     char *widgRec;            /* Pointer to TkTextEmbImage
  468.                      * structure. */
  469.     int offset;                /* Ignored. */
  470.     Tcl_FreeProc **freeProcPtr;        /* Pointer to variable to fill in with
  471.                      * information about how to reclaim
  472.                      * storage for return string. */
  473. {
  474.     switch (((TkTextEmbImage *) widgRec)->align) {
  475.     case ALIGN_BASELINE:
  476.         return "baseline";
  477.     case ALIGN_BOTTOM:
  478.         return "bottom";
  479.     case ALIGN_CENTER:
  480.         return "center";
  481.     case ALIGN_TOP:
  482.         return "top";
  483.     default:
  484.         return "??";
  485.     }
  486. }
  487.  
  488. /*
  489.  *--------------------------------------------------------------
  490.  *
  491.  * EmbImageDeleteProc --
  492.  *
  493.  *    This procedure is invoked by the text B-tree code whenever
  494.  *    an embedded image lies in a range of characters being deleted.
  495.  *
  496.  * Results:
  497.  *    Returns 0 to indicate that the deletion has been accepted.
  498.  *
  499.  * Side effects:
  500.  *    The embedded image is deleted, if it exists, and any resources
  501.  *    associated with it are released.
  502.  *
  503.  *--------------------------------------------------------------
  504.  */
  505.  
  506.     /* ARGSUSED */
  507. static int
  508. EmbImageDeleteProc(eiPtr, linePtr, treeGone)
  509.     TkTextSegment *eiPtr;        /* Segment being deleted. */
  510.     TkTextLine *linePtr;        /* Line containing segment. */
  511.     int treeGone;            /* Non-zero means the entire tree is
  512.                      * being deleted, so everything must
  513.                      * get cleaned up. */
  514. {
  515.     Tcl_HashEntry *hPtr;
  516.  
  517.     if (eiPtr->body.ei.image != NULL) {
  518.     hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable,
  519.         eiPtr->body.ei.name);
  520.     if (hPtr != NULL) {
  521.         /*
  522.          * (It's possible for there to be no hash table entry for this
  523.          * image, if an error occurred while creating the image segment
  524.          * but before the image got added to the table)
  525.          */
  526.  
  527.         Tcl_DeleteHashEntry(hPtr);
  528.     }
  529.     Tk_FreeImage(eiPtr->body.ei.image);
  530.     }
  531.     Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei,
  532.         eiPtr->body.ei.textPtr->display, 0);
  533.     if (eiPtr->body.ei.name != NULL) {
  534.     ckfree(eiPtr->body.ei.name);
  535.     }
  536.     ckfree((char *) eiPtr);
  537.     return 0;
  538. }
  539.  
  540. /*
  541.  *--------------------------------------------------------------
  542.  *
  543.  * EmbImageCleanupProc --
  544.  *
  545.  *    This procedure is invoked by the B-tree code whenever a
  546.  *    segment containing an embedded image is moved from one
  547.  *    line to another.
  548.  *
  549.  * Results:
  550.  *    None.
  551.  *
  552.  * Side effects:
  553.  *    The linePtr field of the segment gets updated.
  554.  *
  555.  *--------------------------------------------------------------
  556.  */
  557.  
  558. static TkTextSegment *
  559. EmbImageCleanupProc(eiPtr, linePtr)
  560.     TkTextSegment *eiPtr;        /* Mark segment that's being moved. */
  561.     TkTextLine *linePtr;        /* Line that now contains segment. */
  562. {
  563.     eiPtr->body.ei.linePtr = linePtr;
  564.     return eiPtr;
  565. }
  566.  
  567. /*
  568.  *--------------------------------------------------------------
  569.  *
  570.  * EmbImageLayoutProc --
  571.  *
  572.  *    This procedure is the "layoutProc" for embedded image
  573.  *    segments.
  574.  *
  575.  * Results:
  576.  *    1 is returned to indicate that the segment should be
  577.  *    displayed.  The chunkPtr structure is filled in.
  578.  *
  579.  * Side effects:
  580.  *    None, except for filling in chunkPtr.
  581.  *
  582.  *--------------------------------------------------------------
  583.  */
  584.  
  585.     /*ARGSUSED*/
  586. static int
  587. EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars,
  588.     noCharsYet, wrapMode, chunkPtr)
  589.     TkText *textPtr;        /* Text widget being layed out. */
  590.     TkTextIndex *indexPtr;    /* Identifies first character in chunk. */
  591.     TkTextSegment *eiPtr;    /* Segment corresponding to indexPtr. */
  592.     int offset;            /* Offset within segPtr corresponding to
  593.                  * indexPtr (always 0). */
  594.     int maxX;            /* Chunk must not occupy pixels at this
  595.                  * position or higher. */
  596.     int maxChars;        /* Chunk must not include more than this
  597.                  * many characters. */
  598.     int noCharsYet;        /* Non-zero means no characters have been
  599.                  * assigned to this line yet. */
  600.     Tk_Uid wrapMode;        /* Wrap mode to use for line: tkTextCharUid,
  601.                  * tkTextNoneUid, or tkTextWordUid. */
  602.     register TkTextDispChunk *chunkPtr;
  603.                 /* Structure to fill in with information
  604.                  * about this chunk.  The x field has already
  605.                  * been set by the caller. */
  606. {
  607.     int width, height;
  608.  
  609.     if (offset != 0) {
  610.     panic("Non-zero offset in EmbImageLayoutProc");
  611.     }
  612.  
  613.     /*
  614.      * See if there's room for this image on this line.
  615.      */
  616.  
  617.     if (eiPtr->body.ei.image == NULL) {
  618.     width = 0;
  619.     height = 0;
  620.     } else {
  621.     Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height);
  622.     width += 2*eiPtr->body.ei.padX;
  623.     height += 2*eiPtr->body.ei.padY;
  624.     }
  625.     if ((width > (maxX - chunkPtr->x))
  626.         && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) {
  627.     return 0;
  628.     }
  629.  
  630.     /*
  631.      * Fill in the chunk structure.
  632.      */
  633.  
  634.     chunkPtr->displayProc = EmbImageDisplayProc;
  635.     chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL;
  636.     chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
  637.     chunkPtr->bboxProc = EmbImageBboxProc;
  638.     chunkPtr->numChars = 1;
  639.     if (eiPtr->body.ei.align == ALIGN_BASELINE) {
  640.     chunkPtr->minAscent = height - eiPtr->body.ei.padY;
  641.     chunkPtr->minDescent = eiPtr->body.ei.padY;
  642.     chunkPtr->minHeight = 0;
  643.     } else {
  644.     chunkPtr->minAscent = 0;
  645.     chunkPtr->minDescent = 0;
  646.     chunkPtr->minHeight = height;
  647.     }
  648.     chunkPtr->width = width;
  649.     chunkPtr->breakIndex = -1;
  650.     chunkPtr->breakIndex = 1;
  651.     chunkPtr->clientData = (ClientData) eiPtr;
  652.     eiPtr->body.ei.chunkCount += 1;
  653.     return 1;
  654. }
  655.  
  656. /*
  657.  *--------------------------------------------------------------
  658.  *
  659.  * EmbImageCheckProc --
  660.  *
  661.  *    This procedure is invoked by the B-tree code to perform
  662.  *    consistency checks on embedded images.
  663.  *
  664.  * Results:
  665.  *    None.
  666.  *
  667.  * Side effects:
  668.  *    The procedure panics if it detects anything wrong with
  669.  *    the embedded image.
  670.  *
  671.  *--------------------------------------------------------------
  672.  */
  673.  
  674. static void
  675. EmbImageCheckProc(eiPtr, linePtr)
  676.     TkTextSegment *eiPtr;        /* Segment to check. */
  677.     TkTextLine *linePtr;        /* Line containing segment. */
  678. {
  679.     if (eiPtr->nextPtr == NULL) {
  680.     panic("EmbImageCheckProc: embedded image is last segment in line");
  681.     }
  682.     if (eiPtr->size != 1) {
  683.     panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size);
  684.     }
  685. }
  686.  
  687. /*
  688.  *--------------------------------------------------------------
  689.  *
  690.  * EmbImageDisplayProc --
  691.  *
  692.  *    This procedure is invoked by the text displaying code
  693.  *    when it is time to actually draw an embedded image
  694.  *    chunk on the screen.
  695.  *
  696.  * Results:
  697.  *    None.
  698.  *
  699.  * Side effects:
  700.  *    The embedded image gets moved to the correct location
  701.  *    and drawn onto the display.
  702.  *
  703.  *--------------------------------------------------------------
  704.  */
  705.  
  706. static void
  707. EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)
  708.     TkTextDispChunk *chunkPtr;        /* Chunk that is to be drawn. */
  709.     int x;                /* X-position in dst at which to
  710.                      * draw this chunk (differs from
  711.                      * the x-position in the chunk because
  712.                      * of scrolling). */
  713.     int y;                /* Top of rectangular bounding box
  714.                      * for line: tells where to draw this
  715.                      * chunk in dst (x-position is in
  716.                      * the chunk itself). */
  717.     int lineHeight;            /* Total height of line. */
  718.     int baseline;            /* Offset of baseline from y. */
  719.     Display *display;            /* Display to use for drawing. */
  720.     Drawable dst;            /* Pixmap or window in which to draw */
  721.     int screenY;            /* Y-coordinate in text window that
  722.                      * corresponds to y. */
  723. {
  724.     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
  725.     int lineX, imageX, imageY, width, height;
  726.     Tk_Image image;
  727.  
  728.     image = eiPtr->body.ei.image;
  729.     if (image == NULL) {
  730.     return;
  731.     }
  732.     if ((x + chunkPtr->width) <= 0) {
  733.     return;
  734.     }
  735.  
  736.     /*
  737.      * Compute the image's location and size in the text widget, taking
  738.      * into account the align value for the image.
  739.      */
  740.  
  741.     EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX,
  742.         &imageY, &width, &height);
  743.     imageX = lineX - chunkPtr->x + x;
  744.  
  745.     Tk_RedrawImage(image, 0, 0, width, height, dst,
  746.         imageX, imageY);
  747. }
  748.  
  749. /*
  750.  *--------------------------------------------------------------
  751.  *
  752.  * EmbImageBboxProc --
  753.  *
  754.  *    This procedure is called to compute the bounding box of
  755.  *    the area occupied by an embedded image.
  756.  *
  757.  * Results:
  758.  *    There is no return value.  *xPtr and *yPtr are filled in
  759.  *    with the coordinates of the upper left corner of the
  760.  *    image, and *widthPtr and *heightPtr are filled in with
  761.  *    the dimensions of the image in pixels.  Note:  not all
  762.  *    of the returned bbox is necessarily visible on the screen
  763.  *    (the rightmost part might be off-screen to the right,
  764.  *    and the bottommost part might be off-screen to the bottom).
  765.  *
  766.  * Side effects:
  767.  *    None.
  768.  *
  769.  *--------------------------------------------------------------
  770.  */
  771.  
  772. static void
  773. EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,
  774.     widthPtr, heightPtr)
  775.     TkTextDispChunk *chunkPtr;        /* Chunk containing desired char. */
  776.     int index;                /* Index of desired character within
  777.                      * the chunk. */
  778.     int y;                /* Topmost pixel in area allocated
  779.                      * for this line. */
  780.     int lineHeight;            /* Total height of line. */
  781.     int baseline;            /* Location of line's baseline, in
  782.                      * pixels measured down from y. */
  783.     int *xPtr, *yPtr;            /* Gets filled in with coords of
  784.                      * character's upper-left pixel. */
  785.     int *widthPtr;            /* Gets filled in with width of
  786.                      * character, in pixels. */
  787.     int *heightPtr;            /* Gets filled in with height of
  788.                      * character, in pixels. */
  789. {
  790.     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
  791.     Tk_Image image;
  792.  
  793.     image = eiPtr->body.ei.image;
  794.     if (image != NULL) {
  795.     Tk_SizeOfImage(image, widthPtr, heightPtr);
  796.     } else {
  797.     *widthPtr = 0;
  798.     *heightPtr = 0;
  799.     }
  800.     *xPtr = chunkPtr->x + eiPtr->body.ei.padX;
  801.     switch (eiPtr->body.ei.align) {
  802.     case ALIGN_BOTTOM:
  803.         *yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY);
  804.         break;
  805.     case ALIGN_CENTER:
  806.         *yPtr = y + (lineHeight - *heightPtr)/2;
  807.         break;
  808.     case ALIGN_TOP:
  809.         *yPtr = y + eiPtr->body.ei.padY;
  810.         break;
  811.     case ALIGN_BASELINE:
  812.         *yPtr = y + (baseline - *heightPtr);
  813.         break;
  814.     }
  815. }
  816.  
  817. /*
  818.  *--------------------------------------------------------------
  819.  *
  820.  * TkTextImageIndex --
  821.  *
  822.  *    Given the name of an embedded image within a text widget,
  823.  *    returns an index corresponding to the image's position
  824.  *    in the text.
  825.  *
  826.  * Results:
  827.  *    The return value is 1 if there is an embedded image by
  828.  *    the given name in the text widget, 0 otherwise.  If the
  829.  *    image exists, *indexPtr is filled in with its index.
  830.  *
  831.  * Side effects:
  832.  *    None.
  833.  *
  834.  *--------------------------------------------------------------
  835.  */
  836.  
  837. int
  838. TkTextImageIndex(textPtr, name, indexPtr)
  839.     TkText *textPtr;        /* Text widget containing image. */
  840.     char *name;            /* Name of image. */
  841.     TkTextIndex *indexPtr;    /* Index information gets stored here. */
  842. {
  843.     Tcl_HashEntry *hPtr;
  844.     TkTextSegment *eiPtr;
  845.  
  846.     hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name);
  847.     if (hPtr == NULL) {
  848.     return 0;
  849.     }
  850.     eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
  851.     indexPtr->tree = textPtr->tree;
  852.     indexPtr->linePtr = eiPtr->body.ei.linePtr;
  853.     indexPtr->charIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr);
  854.     return 1;
  855. }
  856.  
  857. /*
  858.  *--------------------------------------------------------------
  859.  *
  860.  * EmbImageProc --
  861.  *
  862.  *    This procedure is called by the image code whenever an
  863.  *    image or its contents changes.
  864.  *
  865.  * Results:
  866.  *    None.
  867.  *
  868.  * Side effects:
  869.  *    The image will be redisplayed.
  870.  *
  871.  *--------------------------------------------------------------
  872.  */
  873.  
  874. static void
  875. EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
  876.     ClientData clientData;              /* Pointer to widget record. */
  877.     int x, y;                           /* Upper left pixel (within image)
  878.                                          * that must be redisplayed. */
  879.     int width, height;                  /* Dimensions of area to redisplay
  880.                                          * (may be <= 0). */
  881.     int imgWidth, imgHeight;            /* New dimensions of image. */
  882.  
  883. {
  884.     TkTextSegment *eiPtr = (TkTextSegment *) clientData;
  885.     TkTextIndex index;
  886.  
  887.     index.tree = eiPtr->body.ei.textPtr->tree;
  888.     index.linePtr = eiPtr->body.ei.linePtr;
  889.     index.charIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr);
  890.     TkTextChanged(eiPtr->body.ei.textPtr, &index, &index);
  891. }
  892.