stk/Tk/generic/tkTextImage.c

903 lines
26 KiB
C
Raw Normal View History

1998-04-10 06:59:06 -04:00
/*
* tkImage.c --
*
* This file contains code that allows images to be
* nested inside text widgets. It also implements the "image"
* widget command for texts.
*
* Copyright (c) 1996 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
1998-09-30 07:11:02 -04:00
* SCCS: @(#) tkTextImage.c 1.7 97/08/25 15:47:27
1998-04-10 06:59:06 -04:00
*/
#include "tk.h"
#include "tkText.h"
#include "tkPort.h"
/*
* Definitions for alignment values:
*/
#define ALIGN_BOTTOM 0
#define ALIGN_CENTER 1
#define ALIGN_TOP 2
#define ALIGN_BASELINE 3
/*
* Macro that determines the size of an embedded image segment:
*/
#define EI_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
+ sizeof(TkTextEmbImage)))
/*
* Prototypes for procedures defined in this file:
*/
static int AlignParseProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, Tk_Window tkwin, char *value,
char *widgRec, int offset));
static char * AlignPrintProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin, char *widgRec, int offset,
Tcl_FreeProc **freeProcPtr));
static TkTextSegment * EmbImageCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr));
static void EmbImageCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr));
static void EmbImageBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr,
int index, int y, int lineHeight, int baseline,
int *xPtr, int *yPtr, int *widthPtr,
int *heightPtr));
static int EmbImageConfigure _ANSI_ARGS_((TkText *textPtr,
TkTextSegment *eiPtr, int argc, char **argv));
static int EmbImageDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr, int treeGone));
static void EmbImageDisplayProc _ANSI_ARGS_((
TkTextDispChunk *chunkPtr, int x, int y,
int lineHeight, int baseline, Display *display,
Drawable dst, int screenY));
static int EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr,
TkTextIndex *indexPtr, TkTextSegment *segPtr,
int offset, int maxX, int maxChars,
int noCharsYet, Tk_Uid wrapMode,
TkTextDispChunk *chunkPtr));
static void EmbImageProc _ANSI_ARGS_((ClientData clientData,
int x, int y, int width, int height,
int imageWidth, int imageHeight));
/*
* The following structure declares the "embedded image" segment type.
*/
static Tk_SegType tkTextEmbImageType = {
"image", /* name */
0, /* leftGravity */
(Tk_SegSplitProc *) NULL, /* splitProc */
EmbImageDeleteProc, /* deleteProc */
EmbImageCleanupProc, /* cleanupProc */
(Tk_SegLineChangeProc *) NULL, /* lineChangeProc */
EmbImageLayoutProc, /* layoutProc */
EmbImageCheckProc /* checkProc */
};
/*
* Information used for parsing image configuration options:
*/
static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc,
(ClientData) NULL};
static Tk_ConfigSpec configSpecs[] = {
{TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL,
"center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption},
1998-09-30 07:11:02 -04:00
{TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL,
1998-04-10 06:59:06 -04:00
"0", Tk_Offset(TkTextEmbImage, padX),
TK_CONFIG_DONT_SET_DEFAULT},
1998-09-30 07:11:02 -04:00
{TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL,
1998-04-10 06:59:06 -04:00
"0", Tk_Offset(TkTextEmbImage, padY),
TK_CONFIG_DONT_SET_DEFAULT},
1999-09-05 07:16:41 -04:00
#ifdef SCM_CODE
1998-04-10 06:59:06 -04:00
{TK_CONFIG_IMAGE, "-image", (char *) NULL, (char *) NULL,
#else
{TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL,
#endif
(char *) NULL, Tk_Offset(TkTextEmbImage, imageString),
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL,
(char *) NULL, Tk_Offset(TkTextEmbImage, imageName),
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
/*
*--------------------------------------------------------------
*
* TkTextImageCmd --
*
* This procedure implements the "image" widget command
* for text widgets. See the user documentation for details
* on what it does.
*
* Results:
* A standard Tcl result or error.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
TkTextImageCmd(textPtr, interp, argc, argv)
register TkText *textPtr; /* Information about text widget. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. Someone else has already
* parsed this command enough to know that
* argv[1] is "image". */
{
size_t length;
register TkTextSegment *eiPtr;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " image option ?arg arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
length = strlen(argv[2]);
if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) {
TkTextIndex index;
TkTextSegment *eiPtr;
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " image cget index option\"",
(char *) NULL);
return TCL_ERROR;
}
if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
return TCL_ERROR;
}
eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
if (eiPtr->typePtr != &tkTextEmbImageType) {
Tcl_AppendResult(interp, "no embedded image at index \"",
argv[3], "\"", (char *) NULL);
return TCL_ERROR;
}
return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs,
(char *) &eiPtr->body.ei, argv[4], 0);
} else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) {
TkTextIndex index;
TkTextSegment *eiPtr;
if (argc < 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " image configure index ?option value ...?\"",
(char *) NULL);
return TCL_ERROR;
}
if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
return TCL_ERROR;
}
eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
if (eiPtr->typePtr != &tkTextEmbImageType) {
Tcl_AppendResult(interp, "no embedded image at index \"",
argv[3], "\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 4) {
return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
(char *) &eiPtr->body.ei, (char *) NULL, 0);
} else if (argc == 5) {
return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
(char *) &eiPtr->body.ei, argv[4], 0);
} else {
TkTextChanged(textPtr, &index, &index);
return EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4);
}
} else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) {
TkTextIndex index;
int lineIndex;
/*
* Add a new image. Find where to put the new image, and
* mark that position for redisplay.
*/
if (argc < 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " image create index ?option value ...?\"",
(char *) NULL);
return TCL_ERROR;
}
if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
return TCL_ERROR;
}
/*
* Don't allow insertions on the last (dummy) line of the text.
*/
lineIndex = TkBTreeLineIndex(index.linePtr);
if (lineIndex == TkBTreeNumLines(textPtr->tree)) {
lineIndex--;
TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index);
}
/*
* Create the new image segment and initialize it.
*/
eiPtr = (TkTextSegment *) ckalloc(EI_SEG_SIZE);
eiPtr->typePtr = &tkTextEmbImageType;
eiPtr->size = 1;
eiPtr->body.ei.textPtr = textPtr;
eiPtr->body.ei.linePtr = NULL;
eiPtr->body.ei.imageName = NULL;
eiPtr->body.ei.imageString = NULL;
eiPtr->body.ei.name = NULL;
eiPtr->body.ei.image = NULL;
eiPtr->body.ei.align = ALIGN_CENTER;
eiPtr->body.ei.padX = eiPtr->body.ei.padY = 0;
eiPtr->body.ei.chunkCount = 0;
/*
* Link the segment into the text widget, then configure it (delete
* it again if the configuration fails).
*/
TkTextChanged(textPtr, &index, &index);
TkBTreeLinkSegment(eiPtr, &index);
if (EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4) != TCL_OK) {
TkTextIndex index2;
TkTextIndexForwChars(&index, 1, &index2);
TkBTreeDeleteChars(&index, &index2);
return TCL_ERROR;
}
} else if (strncmp(argv[2], "names", length) == 0) {
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " image names\"", (char *) NULL);
return TCL_ERROR;
}
for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
Tcl_AppendElement(interp,
Tcl_GetHashKey(&textPtr->markTable, hPtr));
}
} else {
Tcl_AppendResult(interp, "bad image option \"", argv[2],
"\": must be cget, configure, create, or names",
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* EmbImageConfigure --
*
* This procedure is called to handle configuration options
* for an embedded image, using an argc/argv list.
*
* Results:
* The return value is a standard Tcl result. If TCL_ERROR is
* returned, then interp->result contains an error message..
*
* Side effects:
* Configuration information for the embedded image changes,
* such as alignment, or name of the image.
*
*--------------------------------------------------------------
*/
static int
EmbImageConfigure(textPtr, eiPtr, argc, argv)
TkText *textPtr; /* Information about text widget that
* contains embedded image. */
TkTextSegment *eiPtr; /* Embedded image to be configured. */
int argc; /* Number of strings in argv. */
char **argv; /* Array of strings describing configuration
* options. */
{
Tk_Image image;
Tcl_DString newName;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
int new;
char *name;
int count = 0; /* The counter for picking a unique name */
int conflict = 0; /* True if we have a name conflict */
unsigned int len; /* length of image name */
if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs,
argc, argv, (char *) &eiPtr->body.ei,TK_CONFIG_ARGV_ONLY)
!= TCL_OK) {
return TCL_ERROR;
}
/*
* Create the image. Save the old image around and don't free it
* until after the new one is allocated. This keeps the reference
* count from going to zero so the image doesn't have to be recreated
* if it hasn't changed.
*/
if (eiPtr->body.ei.imageString != NULL) {
image = Tk_GetImage(textPtr->interp, textPtr->tkwin, eiPtr->body.ei.imageString,
EmbImageProc, (ClientData) eiPtr);
if (image == NULL) {
return TCL_ERROR;
}
} else {
image = NULL;
}
if (eiPtr->body.ei.image != NULL) {
Tk_FreeImage(eiPtr->body.ei.image);
}
eiPtr->body.ei.image = image;
if (eiPtr->body.ei.name != NULL) {
return TCL_OK;
}
/*
* Find a unique name for this image. Use imageName (or imageString)
* if available, otherwise tack on a #nn and use it. If a name is already
* associated with this image, delete the name.
*/
name = eiPtr->body.ei.imageName;
if (name == NULL) {
name = eiPtr->body.ei.imageString;
}
1998-09-30 07:11:02 -04:00
if (name == NULL) {
Tcl_AppendResult(textPtr->interp,"Either a \"-name\" ",
"or a \"-image\" argument must be provided ",
"to the \"image create\" subcommand.",
(char *) NULL);
return TCL_ERROR;
}
1998-04-10 06:59:06 -04:00
len = strlen(name);
for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr);
if (strncmp(name, haveName, len) == 0) {
new = 0;
sscanf(haveName+len,"#%d",&new);
if (new > count) {
count = new;
}
if (len == (int) strlen(haveName)) {
conflict = 1;
}
}
}
Tcl_DStringInit(&newName);
Tcl_DStringAppend(&newName,name, -1);
if (conflict) {
char buf[10];
sprintf(buf, "#%d",count+1);
Tcl_DStringAppend(&newName,buf, -1);
}
name = Tcl_DStringValue(&newName);
hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new);
Tcl_SetHashValue(hPtr, eiPtr);
Tcl_AppendResult(textPtr->interp, name , (char *) NULL);
eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1);
strcpy(eiPtr->body.ei.name,name);
Tcl_DStringFree(&newName);
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* AlignParseProc --
*
* This procedure is invoked by Tk_ConfigureWidget during
* option processing to handle "-align" options for embedded
* images.
*
* Results:
* A standard Tcl return value.
*
* Side effects:
* The alignment for the embedded image may change.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static int
AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)
ClientData clientData; /* Not used.*/
Tcl_Interp *interp; /* Used for reporting errors. */
Tk_Window tkwin; /* Window for text widget. */
char *value; /* Value of option. */
char *widgRec; /* Pointer to TkTextEmbWindow
* structure. */
int offset; /* Offset into item (ignored). */
{
register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec;
if (strcmp(value, "baseline") == 0) {
embPtr->align = ALIGN_BASELINE;
} else if (strcmp(value, "bottom") == 0) {
embPtr->align = ALIGN_BOTTOM;
} else if (strcmp(value, "center") == 0) {
embPtr->align = ALIGN_CENTER;
} else if (strcmp(value, "top") == 0) {
embPtr->align = ALIGN_TOP;
} else {
Tcl_AppendResult(interp, "bad alignment \"", value,
"\": must be baseline, bottom, center, or top",
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* AlignPrintProc --
*
* This procedure is invoked by the Tk configuration code
* to produce a printable string for the "-align" configuration
* option for embedded images.
*
* Results:
* The return value is a string describing the embedded
* images's current alignment.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static char *
AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
ClientData clientData; /* Ignored. */
Tk_Window tkwin; /* Window for text widget. */
char *widgRec; /* Pointer to TkTextEmbImage
* structure. */
int offset; /* Ignored. */
Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
* information about how to reclaim
* storage for return string. */
{
switch (((TkTextEmbImage *) widgRec)->align) {
case ALIGN_BASELINE:
return "baseline";
case ALIGN_BOTTOM:
return "bottom";
case ALIGN_CENTER:
return "center";
case ALIGN_TOP:
return "top";
default:
return "??";
}
}
/*
*--------------------------------------------------------------
*
* EmbImageDeleteProc --
*
* This procedure is invoked by the text B-tree code whenever
* an embedded image lies in a range of characters being deleted.
*
* Results:
* Returns 0 to indicate that the deletion has been accepted.
*
* Side effects:
* The embedded image is deleted, if it exists, and any resources
* associated with it are released.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static int
EmbImageDeleteProc(eiPtr, linePtr, treeGone)
TkTextSegment *eiPtr; /* Segment being deleted. */
TkTextLine *linePtr; /* Line containing segment. */
int treeGone; /* Non-zero means the entire tree is
* being deleted, so everything must
* get cleaned up. */
{
Tcl_HashEntry *hPtr;
if (eiPtr->body.ei.image != NULL) {
hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable,
eiPtr->body.ei.name);
if (hPtr != NULL) {
/*
* (It's possible for there to be no hash table entry for this
* image, if an error occurred while creating the image segment
* but before the image got added to the table)
*/
Tcl_DeleteHashEntry(hPtr);
}
Tk_FreeImage(eiPtr->body.ei.image);
}
Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei,
eiPtr->body.ei.textPtr->display, 0);
if (eiPtr->body.ei.name != NULL) {
ckfree(eiPtr->body.ei.name);
}
ckfree((char *) eiPtr);
return 0;
}
/*
*--------------------------------------------------------------
*
* EmbImageCleanupProc --
*
* This procedure is invoked by the B-tree code whenever a
* segment containing an embedded image is moved from one
* line to another.
*
* Results:
* None.
*
* Side effects:
* The linePtr field of the segment gets updated.
*
*--------------------------------------------------------------
*/
static TkTextSegment *
EmbImageCleanupProc(eiPtr, linePtr)
TkTextSegment *eiPtr; /* Mark segment that's being moved. */
TkTextLine *linePtr; /* Line that now contains segment. */
{
eiPtr->body.ei.linePtr = linePtr;
return eiPtr;
}
/*
*--------------------------------------------------------------
*
* EmbImageLayoutProc --
*
* This procedure is the "layoutProc" for embedded image
* segments.
*
* Results:
* 1 is returned to indicate that the segment should be
* displayed. The chunkPtr structure is filled in.
*
* Side effects:
* None, except for filling in chunkPtr.
*
*--------------------------------------------------------------
*/
/*ARGSUSED*/
static int
EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars,
noCharsYet, wrapMode, chunkPtr)
TkText *textPtr; /* Text widget being layed out. */
TkTextIndex *indexPtr; /* Identifies first character in chunk. */
TkTextSegment *eiPtr; /* Segment corresponding to indexPtr. */
int offset; /* Offset within segPtr corresponding to
* indexPtr (always 0). */
int maxX; /* Chunk must not occupy pixels at this
* position or higher. */
int maxChars; /* Chunk must not include more than this
* many characters. */
int noCharsYet; /* Non-zero means no characters have been
* assigned to this line yet. */
Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid,
* tkTextNoneUid, or tkTextWordUid. */
register TkTextDispChunk *chunkPtr;
/* Structure to fill in with information
* about this chunk. The x field has already
* been set by the caller. */
{
int width, height;
if (offset != 0) {
panic("Non-zero offset in EmbImageLayoutProc");
}
/*
* See if there's room for this image on this line.
*/
if (eiPtr->body.ei.image == NULL) {
width = 0;
height = 0;
} else {
Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height);
width += 2*eiPtr->body.ei.padX;
height += 2*eiPtr->body.ei.padY;
}
if ((width > (maxX - chunkPtr->x))
&& !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) {
return 0;
}
/*
* Fill in the chunk structure.
*/
chunkPtr->displayProc = EmbImageDisplayProc;
chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL;
chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
chunkPtr->bboxProc = EmbImageBboxProc;
chunkPtr->numChars = 1;
if (eiPtr->body.ei.align == ALIGN_BASELINE) {
chunkPtr->minAscent = height - eiPtr->body.ei.padY;
chunkPtr->minDescent = eiPtr->body.ei.padY;
chunkPtr->minHeight = 0;
} else {
chunkPtr->minAscent = 0;
chunkPtr->minDescent = 0;
chunkPtr->minHeight = height;
}
chunkPtr->width = width;
chunkPtr->breakIndex = -1;
chunkPtr->breakIndex = 1;
chunkPtr->clientData = (ClientData) eiPtr;
eiPtr->body.ei.chunkCount += 1;
return 1;
}
/*
*--------------------------------------------------------------
*
* EmbImageCheckProc --
*
* This procedure is invoked by the B-tree code to perform
* consistency checks on embedded images.
*
* Results:
* None.
*
* Side effects:
* The procedure panics if it detects anything wrong with
* the embedded image.
*
*--------------------------------------------------------------
*/
static void
EmbImageCheckProc(eiPtr, linePtr)
TkTextSegment *eiPtr; /* Segment to check. */
TkTextLine *linePtr; /* Line containing segment. */
{
if (eiPtr->nextPtr == NULL) {
panic("EmbImageCheckProc: embedded image is last segment in line");
}
if (eiPtr->size != 1) {
panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size);
}
}
/*
*--------------------------------------------------------------
*
* EmbImageDisplayProc --
*
* This procedure is invoked by the text displaying code
* when it is time to actually draw an embedded image
* chunk on the screen.
*
* Results:
* None.
*
* Side effects:
* The embedded image gets moved to the correct location
* and drawn onto the display.
*
*--------------------------------------------------------------
*/
static void
EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)
TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */
int x; /* X-position in dst at which to
* draw this chunk (differs from
* the x-position in the chunk because
* of scrolling). */
int y; /* Top of rectangular bounding box
* for line: tells where to draw this
* chunk in dst (x-position is in
* the chunk itself). */
int lineHeight; /* Total height of line. */
int baseline; /* Offset of baseline from y. */
Display *display; /* Display to use for drawing. */
Drawable dst; /* Pixmap or window in which to draw */
int screenY; /* Y-coordinate in text window that
* corresponds to y. */
{
TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
int lineX, imageX, imageY, width, height;
Tk_Image image;
image = eiPtr->body.ei.image;
if (image == NULL) {
return;
}
if ((x + chunkPtr->width) <= 0) {
return;
}
/*
* Compute the image's location and size in the text widget, taking
* into account the align value for the image.
*/
EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX,
&imageY, &width, &height);
imageX = lineX - chunkPtr->x + x;
Tk_RedrawImage(image, 0, 0, width, height, dst,
imageX, imageY);
}
/*
*--------------------------------------------------------------
*
* EmbImageBboxProc --
*
* This procedure is called to compute the bounding box of
* the area occupied by an embedded image.
*
* Results:
* There is no return value. *xPtr and *yPtr are filled in
* with the coordinates of the upper left corner of the
* image, and *widthPtr and *heightPtr are filled in with
* the dimensions of the image in pixels. Note: not all
* of the returned bbox is necessarily visible on the screen
* (the rightmost part might be off-screen to the right,
* and the bottommost part might be off-screen to the bottom).
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,
widthPtr, heightPtr)
TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */
int index; /* Index of desired character within
* the chunk. */
int y; /* Topmost pixel in area allocated
* for this line. */
int lineHeight; /* Total height of line. */
int baseline; /* Location of line's baseline, in
* pixels measured down from y. */
int *xPtr, *yPtr; /* Gets filled in with coords of
* character's upper-left pixel. */
int *widthPtr; /* Gets filled in with width of
* character, in pixels. */
int *heightPtr; /* Gets filled in with height of
* character, in pixels. */
{
TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
Tk_Image image;
image = eiPtr->body.ei.image;
if (image != NULL) {
Tk_SizeOfImage(image, widthPtr, heightPtr);
} else {
*widthPtr = 0;
*heightPtr = 0;
}
*xPtr = chunkPtr->x + eiPtr->body.ei.padX;
switch (eiPtr->body.ei.align) {
case ALIGN_BOTTOM:
*yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY);
break;
case ALIGN_CENTER:
*yPtr = y + (lineHeight - *heightPtr)/2;
break;
case ALIGN_TOP:
*yPtr = y + eiPtr->body.ei.padY;
break;
case ALIGN_BASELINE:
*yPtr = y + (baseline - *heightPtr);
break;
}
}
/*
*--------------------------------------------------------------
*
* TkTextImageIndex --
*
* Given the name of an embedded image within a text widget,
* returns an index corresponding to the image's position
* in the text.
*
* Results:
* The return value is 1 if there is an embedded image by
* the given name in the text widget, 0 otherwise. If the
* image exists, *indexPtr is filled in with its index.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
TkTextImageIndex(textPtr, name, indexPtr)
TkText *textPtr; /* Text widget containing image. */
char *name; /* Name of image. */
TkTextIndex *indexPtr; /* Index information gets stored here. */
{
Tcl_HashEntry *hPtr;
TkTextSegment *eiPtr;
hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name);
if (hPtr == NULL) {
return 0;
}
eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
indexPtr->tree = textPtr->tree;
indexPtr->linePtr = eiPtr->body.ei.linePtr;
indexPtr->charIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr);
return 1;
}
/*
*--------------------------------------------------------------
*
* EmbImageProc --
*
* This procedure is called by the image code whenever an
* image or its contents changes.
*
* Results:
* None.
*
* Side effects:
* The image will be redisplayed.
*
*--------------------------------------------------------------
*/
static void
EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
ClientData clientData; /* Pointer to widget record. */
int x, y; /* Upper left pixel (within image)
* that must be redisplayed. */
int width, height; /* Dimensions of area to redisplay
* (may be <= 0). */
int imgWidth, imgHeight; /* New dimensions of image. */
{
TkTextSegment *eiPtr = (TkTextSegment *) clientData;
TkTextIndex index;
index.tree = eiPtr->body.ei.textPtr->tree;
index.linePtr = eiPtr->body.ei.linePtr;
index.charIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr);
TkTextChanged(eiPtr->body.ei.textPtr, &index, &index);
}