/*
* tkCanvText.c --
*
* This file implements text items for canvas widgets.
*
* Copyright (c) 1991-1994 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkCanvText.c 1.56 96/02/17 17:45:17
*/
#include "tkInt.h"
#include "tkCanvas.h"
/*
* One of the following structures is kept for each line of text
* in a text item. It contains geometry and display information
* for that line.
*/
typedef struct TextLine {
* line (in the "text" field of enclosing
* text item). */
* line. */
* part of this line (may include an extra
* space character at the end that isn't
* displayed). */
int x, y; /* Origin at which to draw line on screen
* (in integer pixel units, but in canvas
* coordinates, not screen coordinates). */
* line on screen (again, in integer canvas
* pixel units). */
* line on screen (again, in integer canvas
* pixel units). */
} TextLine;
/*
* The structure below defines the record for each text item.
*/
typedef struct TextItem {
* types. MUST BE FIRST IN STRUCTURE. */
/* Pointer to a structure containing
* information about the selection and
* insertion cursor. The structure is owned
* by (and shared with) the generic canvas
* code. */
double x, y; /* Positioning point for text. */
* Zero means no word-wrap. */
* area of text item. Used for selecting
* up to end of line. */
* individual lines of text item (malloc-ed). */
* of character with this index. */
* to use to draw the insertion cursor when
* it's off. Usedif the selection and
* insertion cursor colors are the same. */
} TextItem;
/*
* Information used for parsing configuration specs:
*/
};
"-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*",
(char *) NULL, 0, 0}
};
/*
* Prototypes for procedures defined in this file:
*/
int maxBytes));
char *indexString, int *indexPtr));
/*
* The structures below defines the rectangle and oval item types
* by means of procedures that can be invoked by generic item code.
*/
"text", /* name */
sizeof(TextItem), /* itemSize */
CreateText, /* createProc */
configSpecs, /* configSpecs */
ConfigureText, /* configureProc */
TextCoords, /* coordProc */
DeleteText, /* deleteProc */
DisplayText, /* displayProc */
0, /* alwaysRedraw */
TextToPoint, /* pointProc */
TextToArea, /* areaProc */
TextToPostscript, /* postscriptProc */
ScaleText, /* scaleProc */
TranslateText, /* translateProc */
GetTextIndex, /* indexProc */
SetTextCursor, /* icursorProc */
GetSelText, /* selectionProc */
TextInsert, /* insertProc */
TextDeleteChars, /* dTextProc */
};
/*
*--------------------------------------------------------------
*
* CreateText --
*
* This procedure is invoked to create a new text item
* in a canvas.
*
* Results:
* A standard Tcl return value. If an error occurred in
* creating the item then an error message is left in
* interp->result; in this case itemPtr is left uninitialized
* so it can be safely freed by the caller.
*
* Side effects:
* A new text item is created.
*
*--------------------------------------------------------------
*/
static int
* has been initialized by caller. */
int argc; /* Number of arguments in argv. */
char **argv; /* Arguments describing rectangle. */
{
if (argc < 2) {
return TCL_ERROR;
}
/*
* Carry out initialization that is needed in order to clean
* up after errors during the the remainder of this procedure.
*/
/*
* Process the arguments to fill in the item record.
*/
!= TCL_OK)) {
return TCL_ERROR;
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* TextCoords --
*
* This procedure is invoked to process the "coords" widget
* command on text items. See the user documentation for
* details on what it does.
*
* Results:
* Returns TCL_OK or TCL_ERROR, and sets interp->result.
*
* Side effects:
* The coordinates for the given item may be changed.
*
*--------------------------------------------------------------
*/
static int
* read or modified. */
int argc; /* Number of coordinates supplied in
* argv. */
char **argv; /* Array of coordinates: x1, y1,
* x2, y2, ... */
{
char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE];
if (argc == 0) {
} else if (argc == 2) {
return TCL_ERROR;
}
} else {
"wrong # coordinates: expected 0 or 2, got %d", argc);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* ConfigureText --
*
* This procedure is invoked to configure various aspects
* of a text item, such as its border and background colors.
*
* Results:
* A standard Tcl result code. If an error occurs, then
* an error message is left in interp->result.
*
* Side effects:
* Configuration information, such as colors and stipple
* patterns, may be set for itemPtr.
*
*--------------------------------------------------------------
*/
static int
int argc; /* Number of elements in argv. */
char **argv; /* Arguments describing things to configure. */
int flags; /* Flags to pass to Tk_ConfigureWidget. */
{
unsigned long mask;
return TCL_ERROR;
}
/*
* A few of the options require additional processing, such as
* graphics contexts.
*/
}
}
}
}
== selBgColorPtr->pixel) {
} else {
}
} else {
}
}
/*
* If the text was changed, move the selection and insertion indices
* to keep them inside the item.
*/
} else {
}
}
}
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* DeleteText --
*
* This procedure is called to clean up the data structure
* associated with a text item.
*
* Results:
* None.
*
* Side effects:
* Resources associated with itemPtr are released.
*
*--------------------------------------------------------------
*/
static void
* canvas. */
{
}
}
}
}
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* ComputeTextBbox --
*
* This procedure is invoked to compute the bounding box of
* all the pixels that may be drawn as part of a text item.
* In addition, it recomputes all of the geometry information
* used to display a text item or check for mouse hits.
*
* Results:
* None.
*
* Side effects:
* The fields x1, y1, x2, and y2 are updated in the header
* for itemPtr, and the linePtr structure is regenerated
* for itemPtr.
*
*--------------------------------------------------------------
*/
static void
* recomputed. */
{
char *p;
}
/*
* Work through the text computing the starting point, number of
* characters, and number of pixels in each line.
*/
maxLinePixels = 0;
} else {
wrapPixels = 10000000;
}
if (numPixels > maxLinePixels) {
}
p += numChars;
/*
* Skip space character that terminates a line, if there is one.
* In the case of multiple spaces, all but one will be displayed.
* This is important to make sure the insertion cursor gets
* displayed when it is in the middle of a multi-space.
*/
p++;
} else if (*p == 0) {
/*
* The code below is tricky. Putting the loop termination
* here guarantees that there's a TextLine for the last
* line of text, even if the line is empty (this can
* also happen if the entire text item is empty). This is
* needed so that we can display the insertion cursor on a
* line even when it is empty.
*/
numLines++;
break;
}
}
/*
* Use overall geometry information to compute the top-left corner
* of the bounding box for the text item.
*/
case TK_ANCHOR_NW:
case TK_ANCHOR_N:
case TK_ANCHOR_NE:
break;
case TK_ANCHOR_W:
case TK_ANCHOR_CENTER:
case TK_ANCHOR_E:
break;
case TK_ANCHOR_SW:
case TK_ANCHOR_S:
case TK_ANCHOR_SE:
break;
}
case TK_ANCHOR_NW:
case TK_ANCHOR_W:
case TK_ANCHOR_SW:
break;
case TK_ANCHOR_N:
case TK_ANCHOR_CENTER:
case TK_ANCHOR_S:
break;
case TK_ANCHOR_NE:
case TK_ANCHOR_E:
case TK_ANCHOR_SE:
leftX -= maxLinePixels;
break;
}
/*
* Create the new TextLine array and fill it in using the geometry
* information gathered already.
*/
if (numLines > 0) {
} else {
}
if (i == (numLines-1)) {
} else {
}
case TK_JUSTIFY_LEFT:
break;
case TK_JUSTIFY_CENTER:
break;
case TK_JUSTIFY_RIGHT:
break;
}
}
/*
* Last of all, update the bounding box for the item. The item's
* bounding box includes the bounding box of all its lines, plus
* an extra fudge factor for the cursor border (which could
* potentially be quite large).
*/
i--, linePtr++) {
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* DisplayText --
*
* This procedure is invoked to draw a text item in a given
* drawable.
*
* Results:
* None.
*
* Side effects:
* ItemPtr is drawn in drawable using the transformation
* information in canvas.
*
*--------------------------------------------------------------
*/
static void
* item. */
* must be redisplayed (not used). */
{
return;
}
/*
* If we're stippling, then modify the stipple offset in the GC. Be
* sure to reset the offset when done, since the GC is supposed to be
* read-only.
*/
}
(textInfoPtr->gotFocus);
i > 0; linePtr++, i--) {
/*
* If part or all of this line is selected, then draw a special
* background under the selected part of the line.
*/
+ linePtr->totalChars))) {
inSelect = 0;
} else {
if (beforeSelect <= 0) {
beforeSelect = 0;
} else {
}
/*
* If the selection spans the end of this line, then display
* selection background all the way to the end of the line.
* However, for the last line we only want to display up to
* the last character, not the end of the line, hence the
* "i != 1" check.
*/
if (i != 1) {
goto fillSelectBackground;
}
}
&selEndX);
}
/*
* If the insertion cursor is in this line, then draw a special
* background for the cursor before drawing the text. Note:
* if we're the cursor item but the cursor is turned off, then
* redraw background over the area of the cursor. This guarantees
* that the selection won't make the cursor invisible on mono
* displays, where both are drawn in the same color.
*/
if (focusHere) {
if (textInfoPtr->cursorOn) {
/* Redraw the background over the area of the cursor,
* even though the cursor is turned off. This guarantees
* that the selection won't make the cursor invisible on
* mono displays, where both may be drawn in the same
* color.
*/
(unsigned) textInfoPtr->insertWidth,
}
}
}
/*
* Display the text in three pieces: the part before the
* selection, the selected part (which needs a different graphics
* context), and the part after the selection.
*/
if (beforeSelect != 0) {
}
if (inSelect != 0) {
}
if (afterSelect > 0) {
}
}
}
}
/*
*--------------------------------------------------------------
*
* TextInsert --
*
* Insert characters into a text item at a given position.
*
* Results:
* None.
*
* Side effects:
* The text in the given item is modified. The cursor and
* selection positions are also modified to reflect the
* insertion.
*
*--------------------------------------------------------------
*/
static void
int beforeThis; /* Index of character before which text is
* to be inserted. */
char *string; /* New characters to be inserted. */
{
int length;
char *new;
if (length == 0) {
return;
}
if (beforeThis < 0) {
beforeThis = 0;
}
}
/*
* Inserting characters invalidates indices such as those for the
* selection and cursor. Update the indices appropriately.
*/
}
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* TextDeleteChars --
*
* Delete one or more characters from a text item.
*
* Results:
* None.
*
* Side effects:
* Characters between "first" and "last", inclusive, get
* deleted from itemPtr, and things like the selection
* position get updated.
*
*--------------------------------------------------------------
*/
static void
int first; /* Index of first character to delete. */
int last; /* Index of last character to delete. */
{
int count;
char *new;
if (first < 0) {
first = 0;
}
}
return;
}
/*
* Update indexes for the selection and cursor to reflect the
* renumbering of the remaining characters.
*/
}
}
}
}
}
}
}
}
}
}
return;
}
/*
*--------------------------------------------------------------
*
* TextToPoint --
*
* Computes the distance from a given point to a given
* text item, in canvas units.
*
* Results:
* The return value is 0 if the point whose x and y coordinates
* are pointPtr[0] and pointPtr[1] is inside the arc. If the
* point isn't inside the arc then the return value is the
* distance from the point to the arc.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static double
double *pointPtr; /* Pointer to x and y coordinates. */
{
int i;
/*
* Treat each line in the text item as a rectangle, compute the
* distance to that rectangle, and take the minimum of these
* distances. Perform most of the calculations in integer pixel
* units, since that's how the dimensions of the text are defined.
*/
minDist = -1.0;
i > 0; linePtr++, i--) {
/*
* If the point is inside the line's rectangle, then can
* return immediately.
*/
return 0.0;
}
/*
* Point is outside line's rectangle; compute distance to nearest
* side.
*/
} else {
xDiff = 0;
}
} else {
yDiff = 0;
}
}
}
return minDist;
}
/*
*--------------------------------------------------------------
*
* TextToArea --
*
* This procedure is called to determine whether an item
* lies entirely inside, entirely outside, or overlapping
* a given rectangle.
*
* Results:
* -1 is returned if the item is entirely outside the area
* given by rectPtr, 0 if it overlaps, and 1 if it is entirely
* inside the given area.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
double *rectPtr; /* Pointer to array of four coordinates
* (x1, y1, x2, y2) describing rectangular
* area. */
{
int i, result;
/*
* Scan the lines one at a time, seeing whether each line is
* entirely in, entirely out, or overlapping the rectangle. If
* an overlap is detected, return immediately; otherwise wait
* until all lines have been processed and see if they were all
* inside or all outside.
*/
result = 0;
i > 0; linePtr++, i--) {
if (result == 1) {
return 0;
}
result = -1;
continue;
}
return 0;
}
if (result == -1) {
return 0;
}
result = 1;
}
return result;
}
/*
*--------------------------------------------------------------
*
* ScaleText --
*
* This procedure is invoked to rescale a text item.
*
* Results:
* None.
*
* Side effects:
* Scales the position of the text, but not the size
* of the font for the text.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static void
double scaleX; /* Amount to scale in X direction. */
double scaleY; /* Amount to scale in Y direction. */
{
return;
}
/*
*--------------------------------------------------------------
*
* TranslateText --
*
* This procedure is called to move a text item by a
* given amount.
*
* Results:
* None.
*
* Side effects:
* The position of the text item is offset by (xDelta, yDelta),
* and the bounding box is updated in the generic part of the
* item structure.
*
*--------------------------------------------------------------
*/
static void
* moved. */
{
}
/*
*--------------------------------------------------------------
*
* GetTextIndex --
*
* Parse an index into a text item and return either its value
* or an error.
*
* Results:
* A standard Tcl result. If all went well, then *indexPtr is
* filled in with the index (into itemPtr) corresponding to
* string. Otherwise an error message is left in
* interp->result.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
* specified. */
char *string; /* Specification of a particular character
* in itemPtr's text. */
int *indexPtr; /* Where to store converted index. */
{
if (string[0] == 'e') {
} else {
/*
* Some of the paths here leave messages in interp->result,
* so we have to clear it out before storing our own message.
*/
(char *) NULL);
return TCL_ERROR;
}
} else if (string[0] == 'i') {
} else {
goto badIndex;
}
} else if (string[0] == 's') {
return TCL_ERROR;
}
if (length < 5) {
goto badIndex;
}
} else {
goto badIndex;
}
} else if (string[0] == '@') {
int x, y, dummy, i;
double tmp;
char *end, *p;
p = string+1;
goto badIndex;
}
p = end+1;
goto badIndex;
}
*indexPtr = 0;
return TCL_OK;
}
return TCL_OK;
}
break;
}
}
} else {
goto badIndex;
}
if (*indexPtr < 0){
*indexPtr = 0;
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* SetTextCursor --
*
* Set the position of the insertion cursor in this item.
*
* Results:
* None.
*
* Side effects:
* The cursor position will change.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static void
* is to be set. */
int index; /* Index of character just before which
* cursor is to be positioned. */
{
if (index < 0) {
} else {
}
}
/*
*--------------------------------------------------------------
*
* GetSelText --
*
* This procedure is invoked to return the selected portion
* of a text item. It is only called when this item has
* the selection.
*
* Results:
* The return value is the number of non-NULL bytes stored
* at buffer. Buffer is filled (or partially filled) with a
* NULL-terminated string containing part or all of the selection,
* as given by offset and maxBytes.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
int offset; /* Offset within selection of first
* character to be returned. */
char *buffer; /* Location in which to place
* selection. */
int maxBytes; /* Maximum number of bytes to place
* at buffer, not including terminating
* NULL character. */
{
int count;
count -= 1;
}
}
if (count <= 0) {
return 0;
}
return count;
}
/*
*--------------------------------------------------------------
*
* TextToPostscript --
*
* This procedure is called to generate Postscript for
* text items.
*
* Results:
* The return value is a standard Tcl result. If an error
* occurs in generating Postscript then an error message is
* left in interp->result, replacing whatever used
* to be there. If no error occurs, then Postscript for the
* item is appended to the result.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
* here. */
* wanted. */
int prepass; /* 1 means this is a prepass to
* collect font information; 0 means
* final Postscript is being created. */
{
int i;
* warnings. */
return TCL_OK;
}
return TCL_ERROR;
}
return TCL_ERROR;
}
(char *) NULL);
}
i > 0; i--, linePtr++) {
}
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* LineToPostscript --
*
* This procedure generates a parenthesized Postscript string
* describing one line of text from a text item.
*
* Results:
* None. The parenthesized string is appended to
* interp->result. It generates proper backslash notation so
* that Postscript can interpret the string correctly.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
char *string; /* String to Postscript-ify. */
int numChars; /* Number of characters in the string. */
{
int used, c;
buffer[0] = '(';
used = 1;
c = (*string) & 0xff;
if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)
|| (c >= 0x7f)) {
/*
* Tricky point: the "03" is necessary in the sprintf below,
* so that a full three digits of octal are always generated.
* Without the "03", a number following this sequence could
* be interpreted by Postscript as part of this sequence.
*/
} else {
used++;
}
if (used >= BUFFER_SIZE) {
used = 0;
}
}
}