1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
|
|
|
|
* tkFont.c --
|
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* This file maintains a database of fonts for the Tk toolkit.
|
|
|
|
|
* It also provides several utility procedures for measuring and
|
|
|
|
|
* displaying text.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 1990-1994 The Regents of the University of California.
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* 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: @(#) tkFont.c 1.74 97/10/10 14:34:11
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "tkInt.h"
|
1998-04-10 06:59:06 -04:00
|
|
|
|
#include "tkFont.h"
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef BGLK_CODE
|
|
|
|
|
# define STk_create_tcl_object SCM_CREATE_TCL_OBJECT
|
|
|
|
|
# define STk_convert_Tcl_string2list SCM_tk_string_to_scm_list
|
|
|
|
|
# define STk_NewKeywordObj SCM_KEYWORD_OBJ
|
|
|
|
|
#endif
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The following structure is used to keep track of all the fonts that
|
|
|
|
|
* exist in the current application. It must be stored in the
|
|
|
|
|
* TkMainInfo for the application.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct TkFontInfo {
|
|
|
|
|
Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font.
|
|
|
|
|
* Keys are CachedFontKey structs, values are
|
|
|
|
|
* TkFont structs. */
|
|
|
|
|
Tcl_HashTable namedTable; /* Map a name to a set of attributes for a
|
|
|
|
|
* font, used when constructing a Tk_Font from
|
|
|
|
|
* a named font description. Keys are
|
|
|
|
|
* Tk_Uids, values are NamedFont structs. */
|
|
|
|
|
TkMainInfo *mainPtr; /* Application that owns this structure. */
|
|
|
|
|
int updatePending;
|
|
|
|
|
} TkFontInfo;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following structure is used as a key in the fontCache.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
typedef struct CachedFontKey {
|
|
|
|
|
Display *display; /* Display for which font was constructed. */
|
|
|
|
|
Tk_Uid string; /* String that describes font. */
|
|
|
|
|
} CachedFontKey;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The following data structure is used to keep track of the font attributes
|
|
|
|
|
* for each named font that has been defined. The named font is only deleted
|
|
|
|
|
* when the last reference to it goes away.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct NamedFont {
|
|
|
|
|
int refCount; /* Number of users of named font. */
|
|
|
|
|
int deletePending; /* Non-zero if font should be deleted when
|
|
|
|
|
* last reference goes away. */
|
|
|
|
|
TkFontAttributes fa; /* Desired attributes for named font. */
|
|
|
|
|
} NamedFont;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following two structures are used to keep track of string
|
|
|
|
|
* measurement information when using the text layout facilities.
|
|
|
|
|
*
|
|
|
|
|
* A LayoutChunk represents a contiguous range of text that can be measured
|
|
|
|
|
* and displayed by low-level text calls. In general, chunks will be
|
|
|
|
|
* delimited by newlines and tabs. Low-level, platform-specific things
|
|
|
|
|
* like kerning and non-integer character widths may occur between the
|
|
|
|
|
* characters in a single chunk, but not between characters in different
|
|
|
|
|
* chunks.
|
|
|
|
|
*
|
|
|
|
|
* A TextLayout is a collection of LayoutChunks. It can be displayed with
|
|
|
|
|
* respect to any origin. It is the implementation of the Tk_TextLayout
|
|
|
|
|
* opaque token.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
typedef struct LayoutChunk {
|
|
|
|
|
CONST char *start; /* Pointer to simple string to be displayed.
|
|
|
|
|
* This is a pointer into the TkTextLayout's
|
|
|
|
|
* string. */
|
|
|
|
|
int numChars; /* The number of characters in this chunk. */
|
|
|
|
|
int numDisplayChars; /* The number of characters to display when
|
|
|
|
|
* this chunk is displayed. Can be less than
|
|
|
|
|
* numChars if extra space characters were
|
|
|
|
|
* absorbed by the end of the chunk. This
|
|
|
|
|
* will be < 0 if this is a chunk that is
|
|
|
|
|
* holding a tab or newline. */
|
|
|
|
|
int x, y; /* The origin of the first character in this
|
|
|
|
|
* chunk with respect to the upper-left hand
|
|
|
|
|
* corner of the TextLayout. */
|
|
|
|
|
int totalWidth; /* Width in pixels of this chunk. Used
|
|
|
|
|
* when hit testing the invisible spaces at
|
|
|
|
|
* the end of a chunk. */
|
|
|
|
|
int displayWidth; /* Width in pixels of the displayable
|
|
|
|
|
* characters in this chunk. Can be less than
|
|
|
|
|
* width if extra space characters were
|
|
|
|
|
* absorbed by the end of the chunk. */
|
|
|
|
|
} LayoutChunk;
|
|
|
|
|
|
|
|
|
|
typedef struct TextLayout {
|
|
|
|
|
Tk_Font tkfont; /* The font used when laying out the text. */
|
|
|
|
|
CONST char *string; /* The string that was layed out. */
|
|
|
|
|
int width; /* The maximum width of all lines in the
|
|
|
|
|
* text layout. */
|
|
|
|
|
int numChunks; /* Number of chunks actually used in
|
|
|
|
|
* following array. */
|
|
|
|
|
LayoutChunk chunks[1]; /* Array of chunks. The actual size will
|
|
|
|
|
* be maxChunks. THIS FIELD MUST BE THE LAST
|
|
|
|
|
* IN THE STRUCTURE. */
|
|
|
|
|
} TextLayout;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The following structures are used as two-way maps between the values for
|
|
|
|
|
* the fields in the TkFontAttributes structure and the strings used in
|
|
|
|
|
* Tcl, when parsing both option-value format and style-list format font
|
|
|
|
|
* name strings.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static TkStateMap weightMap[] = {
|
|
|
|
|
{TK_FW_NORMAL, "normal"},
|
|
|
|
|
{TK_FW_BOLD, "bold"},
|
|
|
|
|
{TK_FW_UNKNOWN, NULL}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static TkStateMap slantMap[] = {
|
|
|
|
|
{TK_FS_ROMAN, "roman"},
|
|
|
|
|
{TK_FS_ITALIC, "italic"},
|
|
|
|
|
{TK_FS_UNKNOWN, NULL}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static TkStateMap underlineMap[] = {
|
|
|
|
|
{1, "underline"},
|
|
|
|
|
{0, NULL}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static TkStateMap overstrikeMap[] = {
|
|
|
|
|
{1, "overstrike"},
|
|
|
|
|
{0, NULL}
|
|
|
|
|
};
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The following structures are used when parsing XLFD's into a set of
|
|
|
|
|
* TkFontAttributes.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static TkStateMap xlfdWeightMap[] = {
|
|
|
|
|
{TK_FW_NORMAL, "normal"},
|
|
|
|
|
{TK_FW_NORMAL, "medium"},
|
|
|
|
|
{TK_FW_NORMAL, "book"},
|
|
|
|
|
{TK_FW_NORMAL, "light"},
|
|
|
|
|
{TK_FW_BOLD, "bold"},
|
|
|
|
|
{TK_FW_BOLD, "demi"},
|
|
|
|
|
{TK_FW_BOLD, "demibold"},
|
|
|
|
|
{TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static TkStateMap xlfdSlantMap[] = {
|
|
|
|
|
{TK_FS_ROMAN, "r"},
|
|
|
|
|
{TK_FS_ITALIC, "i"},
|
|
|
|
|
{TK_FS_OBLIQUE, "o"},
|
|
|
|
|
{TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */
|
|
|
|
|
};
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static TkStateMap xlfdSetwidthMap[] = {
|
|
|
|
|
{TK_SW_NORMAL, "normal"},
|
|
|
|
|
{TK_SW_CONDENSE, "narrow"},
|
|
|
|
|
{TK_SW_CONDENSE, "semicondensed"},
|
|
|
|
|
{TK_SW_CONDENSE, "condensed"},
|
|
|
|
|
{TK_SW_UNKNOWN, NULL}
|
|
|
|
|
};
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static TkStateMap xlfdCharsetMap[] = {
|
|
|
|
|
{TK_CS_NORMAL, "iso8859"},
|
|
|
|
|
{TK_CS_SYMBOL, "adobe"},
|
|
|
|
|
{TK_CS_SYMBOL, "sun"},
|
|
|
|
|
{TK_CS_OTHER, NULL}
|
|
|
|
|
};
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The following structure and defines specify the valid builtin options
|
|
|
|
|
* when configuring a set of font attributes.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static char *fontOpt[] = {
|
|
|
|
|
"-family",
|
|
|
|
|
"-size",
|
|
|
|
|
"-weight",
|
|
|
|
|
"-slant",
|
|
|
|
|
"-underline",
|
|
|
|
|
"-overstrike",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define FONT_FAMILY 0
|
|
|
|
|
#define FONT_SIZE 1
|
|
|
|
|
#define FONT_WEIGHT 2
|
|
|
|
|
#define FONT_SLANT 3
|
|
|
|
|
#define FONT_UNDERLINE 4
|
|
|
|
|
#define FONT_OVERSTRIKE 5
|
|
|
|
|
#define FONT_NUMFIELDS 6 /* Length of fontOpt array. */
|
|
|
|
|
|
|
|
|
|
#define GetFontAttributes(tkfont) \
|
|
|
|
|
((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)
|
|
|
|
|
|
|
|
|
|
#define GetFontMetrics(tkfont) \
|
|
|
|
|
((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,
|
|
|
|
|
Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],
|
|
|
|
|
TkFontAttributes *faPtr));
|
|
|
|
|
static int FieldSpecified _ANSI_ARGS_((CONST char *field));
|
1998-09-30 07:11:02 -04:00
|
|
|
|
static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,
|
1998-04-10 06:59:06 -04:00
|
|
|
|
CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));
|
|
|
|
|
static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,
|
|
|
|
|
int *maxPtr, CONST char *start, int numChars,
|
|
|
|
|
int curX, int newX, int y));
|
|
|
|
|
static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,
|
|
|
|
|
Tk_Window tkwin, Tcl_Obj *objPtr,
|
|
|
|
|
TkFontAttributes *faPtr));
|
|
|
|
|
static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));
|
|
|
|
|
static void TheWorldHasChanged _ANSI_ARGS_((
|
|
|
|
|
ClientData clientData));
|
|
|
|
|
static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
|
|
|
|
|
Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
|
|
|
|
|
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TkFontPkgInit --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called when an application is created. It
|
|
|
|
|
* initializes all the structures that are used by the font
|
|
|
|
|
* package on a per application basis.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a token that must be stored in the TkMainInfo for this
|
|
|
|
|
* application.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Memory allocated.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
TkFontPkgInit(mainPtr)
|
|
|
|
|
TkMainInfo *mainPtr; /* The application being created. */
|
|
|
|
|
{
|
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
|
|
|
|
|
fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
|
|
|
|
|
Tcl_InitHashTable(&fiPtr->fontCache, sizeof(CachedFontKey) / sizeof(int));
|
|
|
|
|
Tcl_InitHashTable(&fiPtr->namedTable, TCL_ONE_WORD_KEYS);
|
|
|
|
|
fiPtr->mainPtr = mainPtr;
|
|
|
|
|
fiPtr->updatePending = 0;
|
|
|
|
|
mainPtr->fontInfoPtr = fiPtr;
|
|
|
|
|
}
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TkFontPkgFree --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called when an application is deleted. It
|
|
|
|
|
* deletes all the structures that were used by the font package
|
|
|
|
|
* for this application.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Memory freed.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
void
|
|
|
|
|
TkFontPkgFree(mainPtr)
|
|
|
|
|
TkMainInfo *mainPtr; /* The application being deleted. */
|
|
|
|
|
{
|
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
Tcl_HashEntry *hPtr;
|
|
|
|
|
Tcl_HashSearch search;
|
|
|
|
|
|
|
|
|
|
fiPtr = mainPtr->fontInfoPtr;
|
|
|
|
|
|
|
|
|
|
if (fiPtr->fontCache.numEntries != 0) {
|
|
|
|
|
panic("TkFontPkgFree: all fonts should have been freed already");
|
|
|
|
|
}
|
|
|
|
|
Tcl_DeleteHashTable(&fiPtr->fontCache);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
|
|
|
|
|
while (hPtr != NULL) {
|
|
|
|
|
ckfree((char *) Tcl_GetHashValue(hPtr));
|
|
|
|
|
hPtr = Tcl_NextHashEntry(&search);
|
|
|
|
|
}
|
|
|
|
|
Tcl_DeleteHashTable(&fiPtr->namedTable);
|
|
|
|
|
if (fiPtr->updatePending != 0) {
|
|
|
|
|
Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);
|
|
|
|
|
}
|
|
|
|
|
ckfree((char *) fiPtr);
|
|
|
|
|
}
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_FontObjCmd --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is implemented to process the "font" Tcl command.
|
|
|
|
|
* See the user documentation for details on what it does.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A standard Tcl result.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See the user documentation.
|
|
|
|
|
*
|
|
|
|
|
*----------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
int
|
|
|
|
|
Tk_FontObjCmd(clientData, interp, objc, objv)
|
|
|
|
|
ClientData clientData; /* Main window associated with interpreter. */
|
|
|
|
|
Tcl_Interp *interp; /* Current interpreter. */
|
|
|
|
|
int objc; /* Number of arguments. */
|
|
|
|
|
Tcl_Obj *CONST objv[]; /* Argument objects. */
|
|
|
|
|
{
|
|
|
|
|
int index;
|
|
|
|
|
Tk_Window tkwin;
|
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
static char *optionStrings[] = {
|
|
|
|
|
"actual", "configure", "create", "delete",
|
|
|
|
|
"families", "measure", "metrics", "names",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
enum options {
|
|
|
|
|
FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE,
|
|
|
|
|
FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tkwin = (Tk_Window) clientData;
|
|
|
|
|
fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
|
|
|
|
|
|
|
|
|
|
if (objc < 2) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
|
|
|
|
|
&index) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ((enum options) index) {
|
|
|
|
|
case FONT_ACTUAL: {
|
1998-09-30 07:11:02 -04:00
|
|
|
|
int skip, result;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tk_Font tkfont;
|
|
|
|
|
Tcl_Obj *objPtr;
|
|
|
|
|
CONST TkFontAttributes *faPtr;
|
|
|
|
|
|
|
|
|
|
skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
|
|
|
|
|
if (skip < 0) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if ((objc < 3) || (objc - skip > 4)) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv,
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
"font ?:displayof window? ?option?");
|
|
|
|
|
#else
|
|
|
|
|
"font ?-displayof window? ?option?");
|
|
|
|
|
#endif
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
|
|
|
|
|
if (tkfont == NULL) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
1998-09-30 07:11:02 -04:00
|
|
|
|
objc -= skip;
|
|
|
|
|
objv += skip;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
faPtr = GetFontAttributes(tkfont);
|
|
|
|
|
objPtr = NULL;
|
|
|
|
|
if (objc > 3) {
|
1998-09-30 07:11:02 -04:00
|
|
|
|
objPtr = objv[3];
|
1998-04-10 06:59:06 -04:00
|
|
|
|
}
|
1998-09-30 07:11:02 -04:00
|
|
|
|
result = GetAttributeInfoObj(interp, faPtr, objPtr);
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tk_FreeFont(tkfont);
|
1998-09-30 07:11:02 -04:00
|
|
|
|
return result;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
}
|
|
|
|
|
case FONT_CONFIGURE: {
|
|
|
|
|
int result;
|
|
|
|
|
char *string;
|
|
|
|
|
Tcl_Obj *objPtr;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;
|
|
|
|
|
|
|
|
|
|
if (objc < 3) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
string = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL));
|
|
|
|
|
namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
|
|
|
|
|
nfPtr = NULL; /* lint. */
|
|
|
|
|
if (namedHashPtr != NULL) {
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
}
|
|
|
|
|
if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
|
|
|
|
|
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string,
|
|
|
|
|
"\" doesn't exist", NULL);
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (objc == 3) {
|
|
|
|
|
objPtr = NULL;
|
|
|
|
|
} else if (objc == 4) {
|
|
|
|
|
objPtr = objv[3];
|
|
|
|
|
} else {
|
|
|
|
|
result = ConfigAttributesObj(interp, tkwin, objc - 3,
|
|
|
|
|
objv + 3, &nfPtr->fa);
|
|
|
|
|
UpdateDependantFonts(fiPtr, tkwin, namedHashPtr);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
1998-09-30 07:11:02 -04:00
|
|
|
|
return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
|
1998-04-10 06:59:06 -04:00
|
|
|
|
}
|
|
|
|
|
case FONT_CREATE: {
|
|
|
|
|
int skip, i;
|
|
|
|
|
char *name;
|
|
|
|
|
char buf[32];
|
|
|
|
|
TkFontAttributes fa;
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;
|
|
|
|
|
|
|
|
|
|
skip = 3;
|
|
|
|
|
if (objc < 3) {
|
|
|
|
|
name = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
name = Tcl_GetStringFromObj(objv[2], NULL);
|
|
|
|
|
if (name[0] == '-') {
|
|
|
|
|
name = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (name == NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* No font name specified. Generate one of the form "fontX".
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (i = 1; ; i++) {
|
|
|
|
|
sprintf(buf, "font%d", i);
|
|
|
|
|
namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
|
|
|
|
|
Tk_GetUid(buf));
|
|
|
|
|
if (namedHashPtr == NULL) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
name = buf;
|
|
|
|
|
skip = 2;
|
|
|
|
|
}
|
|
|
|
|
TkInitFontAttributes(&fa);
|
|
|
|
|
if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,
|
|
|
|
|
&fa) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FONT_DELETE: {
|
|
|
|
|
int i;
|
|
|
|
|
char *string;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Delete the named font. If there are still widgets using this
|
|
|
|
|
* font, then it isn't deleted right away.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (objc < 3) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
for (i = 2; i < objc; i++) {
|
|
|
|
|
string = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL));
|
|
|
|
|
namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
|
|
|
|
|
if (namedHashPtr == NULL) {
|
|
|
|
|
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string,
|
|
|
|
|
"\" doesn't exist", (char *) NULL);
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
if (nfPtr->refCount != 0) {
|
|
|
|
|
nfPtr->deletePending = 1;
|
|
|
|
|
} else {
|
|
|
|
|
Tcl_DeleteHashEntry(namedHashPtr);
|
|
|
|
|
ckfree((char *) nfPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FONT_FAMILIES: {
|
|
|
|
|
int skip;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
|
|
|
|
|
if (skip < 0) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (objc - skip != 2) {
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv, "?:displayof window?");
|
|
|
|
|
#else
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
|
|
|
|
|
#endif
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
TkpGetFontFamilies(interp, tkwin);
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_SetObjResult(interp,
|
|
|
|
|
STk_create_tcl_object(
|
|
|
|
|
STk_convert_Tcl_string2list(interp->result)));
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FONT_MEASURE: {
|
|
|
|
|
char *string;
|
|
|
|
|
Tk_Font tkfont;
|
|
|
|
|
int length, skip;
|
|
|
|
|
|
1998-09-30 07:11:02 -04:00
|
|
|
|
skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (skip < 0) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (objc - skip != 4) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv,
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
"font ?:displayof window? text");
|
|
|
|
|
#else
|
|
|
|
|
"font ?-displayof window? text");
|
|
|
|
|
#endif
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
|
|
|
|
|
if (tkfont == NULL) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
string = Tcl_GetStringFromObj(objv[3 + skip], &length);
|
|
|
|
|
Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_TextWidth(tkfont, string, length));
|
|
|
|
|
Tk_FreeFont(tkfont);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FONT_METRICS: {
|
|
|
|
|
char buf[64];
|
|
|
|
|
Tk_Font tkfont;
|
|
|
|
|
int skip, index, i;
|
|
|
|
|
CONST TkFontMetrics *fmPtr;
|
|
|
|
|
static char *switches[] = {
|
|
|
|
|
"-ascent", "-descent", "-linespace", "-fixed", NULL
|
|
|
|
|
};
|
|
|
|
|
|
1998-09-30 07:11:02 -04:00
|
|
|
|
skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (skip < 0) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if ((objc < 3) || ((objc - skip) > 4)) {
|
|
|
|
|
Tcl_WrongNumArgs(interp, 2, objv,
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
"font ?:displayof window? ?option?");
|
|
|
|
|
#else
|
|
|
|
|
"font ?-displayof window? ?option?");
|
|
|
|
|
#endif
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
|
|
|
|
|
if (tkfont == NULL) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
1998-09-30 07:11:02 -04:00
|
|
|
|
objc -= skip;
|
|
|
|
|
objv += skip;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
fmPtr = GetFontMetrics(tkfont);
|
|
|
|
|
if (objc == 3) {
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
sprintf(buf, ":ascent %d :descent %d :linespace %d :fixed #%c",
|
|
|
|
|
fmPtr->ascent, fmPtr->descent,
|
|
|
|
|
fmPtr->ascent + fmPtr->descent,
|
|
|
|
|
fmPtr->fixed? 't' : 'f');
|
|
|
|
|
Tcl_SetObjResult(interp,
|
|
|
|
|
STk_create_tcl_object(
|
|
|
|
|
STk_convert_Tcl_string2list(buf)));
|
|
|
|
|
#else
|
|
|
|
|
sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
|
|
|
|
|
fmPtr->ascent, fmPtr->descent,
|
|
|
|
|
fmPtr->ascent + fmPtr->descent,
|
|
|
|
|
fmPtr->fixed);
|
|
|
|
|
Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1);
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
1998-09-30 07:11:02 -04:00
|
|
|
|
if (Tcl_GetIndexFromObj(interp, objv[3], switches,
|
1998-04-10 06:59:06 -04:00
|
|
|
|
"metric", 0, &index) != TCL_OK) {
|
|
|
|
|
Tk_FreeFont(tkfont);
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
i = 0; /* Needed only to prevent compiler
|
|
|
|
|
* warning. */
|
|
|
|
|
switch (index) {
|
|
|
|
|
case 0: i = fmPtr->ascent; break;
|
|
|
|
|
case 1: i = fmPtr->descent; break;
|
|
|
|
|
case 2: i = fmPtr->ascent + fmPtr->descent; break;
|
|
|
|
|
case 3: i = fmPtr->fixed; break;
|
|
|
|
|
}
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (index == 3)
|
|
|
|
|
Tcl_SetBooleanObj(Tcl_GetObjResult(interp), i);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
Tcl_SetIntObj(Tcl_GetObjResult(interp), i);
|
|
|
|
|
}
|
|
|
|
|
Tk_FreeFont(tkfont);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FONT_NAMES: {
|
|
|
|
|
char *string;
|
|
|
|
|
Tcl_Obj *strPtr;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
Tcl_HashSearch search;
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;
|
|
|
|
|
|
|
|
|
|
if (objc != 2) {
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_WrongNumArgs(interp, 1, objv, "'names");
|
|
|
|
|
#else
|
|
|
|
|
Tcl_WrongNumArgs(interp, 1, objv, "names");
|
|
|
|
|
#endif
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
|
|
|
|
|
while (namedHashPtr != NULL) {
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
if (nfPtr->deletePending == 0) {
|
|
|
|
|
string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);
|
|
|
|
|
strPtr = Tcl_NewStringObj(string, -1);
|
|
|
|
|
Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr);
|
|
|
|
|
}
|
|
|
|
|
namedHashPtr = Tcl_NextHashEntry(&search);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TCL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
1996-09-27 06:29:02 -04:00
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* UpdateDependantFonts, TheWorldHasChanged, RecomputeWidgets --
|
|
|
|
|
*
|
|
|
|
|
* Called when the attributes of a named font changes. Updates all
|
|
|
|
|
* the instantiated fonts that depend on that named font and then
|
|
|
|
|
* uses the brute force approach and prepares every widget to
|
|
|
|
|
* recompute its geometry.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Things get queued for redisplay.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static void
|
|
|
|
|
UpdateDependantFonts(fiPtr, tkwin, namedHashPtr)
|
|
|
|
|
TkFontInfo *fiPtr; /* Info about application's fonts. */
|
|
|
|
|
Tk_Window tkwin; /* A window in the application. */
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */
|
|
|
|
|
{
|
|
|
|
|
Tcl_HashEntry *cacheHashPtr;
|
|
|
|
|
Tcl_HashSearch search;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
if (nfPtr->refCount == 0) {
|
|
|
|
|
/*
|
|
|
|
|
* Well nobody's using this named font, so don't have to tell
|
|
|
|
|
* any widgets to recompute themselves.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
|
|
|
|
|
while (cacheHashPtr != NULL) {
|
|
|
|
|
fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
|
|
|
|
|
if (fontPtr->namedHashPtr == namedHashPtr) {
|
|
|
|
|
TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);
|
|
|
|
|
if (fiPtr->updatePending == 0) {
|
|
|
|
|
fiPtr->updatePending = 1;
|
|
|
|
|
Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cacheHashPtr = Tcl_NextHashEntry(&search);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
TheWorldHasChanged(clientData)
|
|
|
|
|
ClientData clientData; /* Info about application's fonts. */
|
|
|
|
|
{
|
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
|
|
|
|
|
fiPtr = (TkFontInfo *) clientData;
|
|
|
|
|
fiPtr->updatePending = 0;
|
|
|
|
|
|
|
|
|
|
RecomputeWidgets(fiPtr->mainPtr->winPtr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
RecomputeWidgets(winPtr)
|
|
|
|
|
TkWindow *winPtr; /* Window to which command is sent. */
|
|
|
|
|
{
|
|
|
|
|
if ((winPtr->classProcsPtr != NULL)
|
|
|
|
|
&& (winPtr->classProcsPtr->geometryProc != NULL)) {
|
|
|
|
|
(*winPtr->classProcsPtr->geometryProc)(winPtr->instanceData);
|
|
|
|
|
}
|
|
|
|
|
for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
|
|
|
|
|
RecomputeWidgets(winPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* TkCreateNamedFont --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Create the specified named font with the given attributes in the
|
|
|
|
|
* named font table associated with the interp.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Returns TCL_OK if the font was successfully created, or TCL_ERROR
|
|
|
|
|
* if the named font already existed. If TCL_ERROR is returned, an
|
|
|
|
|
* error message is left in interp->result.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Assume there used to exist a named font by the specified name, and
|
|
|
|
|
* that the named font had been deleted, but there were still some
|
|
|
|
|
* widgets using the named font at the time it was deleted. If a
|
|
|
|
|
* new named font is created with the same name, all those widgets
|
|
|
|
|
* that were using the old named font will be redisplayed using
|
|
|
|
|
* the new named font's attributes.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
int
|
|
|
|
|
TkCreateNamedFont(interp, tkwin, name, faPtr)
|
|
|
|
|
Tcl_Interp *interp; /* Interp for error return. */
|
|
|
|
|
Tk_Window tkwin; /* A window associated with interp. */
|
|
|
|
|
CONST char *name; /* Name for the new named font. */
|
|
|
|
|
TkFontAttributes *faPtr; /* Attributes for the new named font. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
Tcl_HashEntry *namedHashPtr;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
int new;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
|
|
|
|
|
fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
|
|
|
|
|
|
|
|
|
|
name = Tk_GetUid(name);
|
|
|
|
|
namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
|
|
|
|
|
|
|
|
|
|
if (new == 0) {
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
if (nfPtr->deletePending == 0) {
|
|
|
|
|
interp->result[0] = '\0';
|
|
|
|
|
Tcl_AppendResult(interp, "font \"", name,
|
|
|
|
|
"\" already exists", (char *) NULL);
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Recreating a named font with the same name as a previous
|
|
|
|
|
* named font. Some widgets were still using that named
|
|
|
|
|
* font, so they need to get redisplayed.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nfPtr->fa = *faPtr;
|
|
|
|
|
nfPtr->deletePending = 0;
|
|
|
|
|
UpdateDependantFonts(fiPtr, tkwin, namedHashPtr);
|
|
|
|
|
return TCL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));
|
|
|
|
|
nfPtr->deletePending = 0;
|
|
|
|
|
Tcl_SetHashValue(namedHashPtr, nfPtr);
|
|
|
|
|
nfPtr->fa = *faPtr;
|
|
|
|
|
nfPtr->refCount = 0;
|
|
|
|
|
nfPtr->deletePending = 0;
|
|
|
|
|
return TCL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_GetFont --
|
|
|
|
|
*
|
|
|
|
|
* Given a string description of a font, map the description to a
|
|
|
|
|
* corresponding Tk_Font that represents the font.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is token for the font, or NULL if an error
|
|
|
|
|
* prevented the font from being created. If NULL is returned, an
|
|
|
|
|
* error message will be left in interp->result.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Calls Tk_GetFontFromObj(), which modifies interp's result object,
|
|
|
|
|
* then copies the string from the result object into interp->result.
|
|
|
|
|
* This procedure will go away when Tk_ConfigureWidget() is
|
|
|
|
|
* made into an object command.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Tk_Font
|
|
|
|
|
Tk_GetFont(interp, tkwin, string)
|
|
|
|
|
Tcl_Interp *interp; /* Interp for database and error return. */
|
|
|
|
|
Tk_Window tkwin; /* For display on which font will be used. */
|
|
|
|
|
CONST char *string; /* String describing font, as: named font,
|
|
|
|
|
* native format, or parseable string. */
|
|
|
|
|
{
|
|
|
|
|
Tcl_Obj *strPtr;
|
|
|
|
|
Tk_Font tkfont;
|
|
|
|
|
|
|
|
|
|
strPtr = Tcl_NewStringObj((char *) string, -1);
|
|
|
|
|
|
|
|
|
|
tkfont = Tk_GetFontFromObj(interp, tkwin, strPtr);
|
|
|
|
|
if (tkfont == NULL) {
|
|
|
|
|
Tcl_SetResult(interp,
|
|
|
|
|
Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL),
|
|
|
|
|
TCL_VOLATILE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Tcl_DecrRefCount(strPtr); /* done with object */
|
|
|
|
|
return tkfont;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_GetFontFromObj --
|
|
|
|
|
*
|
|
|
|
|
* Given a string description of a font, map the description to a
|
|
|
|
|
* corresponding Tk_Font that represents the font.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is token for the font, or NULL if an error
|
|
|
|
|
* prevented the font from being created. If NULL is returned, an
|
|
|
|
|
* error message will be left in interp's result object.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The font is added to an internal database with a reference
|
|
|
|
|
* count. For each call to this procedure, there should eventually
|
|
|
|
|
* be a call to Tk_FreeFont() so that the database is cleaned up when
|
|
|
|
|
* fonts aren't in use anymore.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Tk_Font
|
|
|
|
|
Tk_GetFontFromObj(interp, tkwin, objPtr)
|
|
|
|
|
Tcl_Interp *interp; /* Interp for database and error return. */
|
|
|
|
|
Tk_Window tkwin; /* For display on which font will be used. */
|
|
|
|
|
Tcl_Obj *objPtr; /* Object describing font, as: named font,
|
|
|
|
|
* native format, or parseable string. */
|
|
|
|
|
{
|
|
|
|
|
TkFontInfo *fiPtr;
|
|
|
|
|
CachedFontKey key;
|
|
|
|
|
Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
int new, descent;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
char *string;
|
|
|
|
|
|
|
|
|
|
fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
|
|
|
|
|
string = Tcl_GetStringFromObj(objPtr, NULL);
|
|
|
|
|
|
|
|
|
|
key.display = Tk_Display(tkwin);
|
|
|
|
|
key.string = Tk_GetUid(string);
|
|
|
|
|
cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, (char *) &key, &new);
|
|
|
|
|
|
|
|
|
|
if (new == 0) {
|
|
|
|
|
/*
|
|
|
|
|
* We have already constructed a font with this description for
|
|
|
|
|
* this display. Bump the reference count of the cached font.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
|
|
|
|
|
fontPtr->refCount++;
|
|
|
|
|
return (Tk_Font) fontPtr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, key.string);
|
|
|
|
|
if (namedHashPtr != NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* Construct a font based on a named font.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
|
|
|
|
|
nfPtr->refCount++;
|
|
|
|
|
|
|
|
|
|
fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* Native font?
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fontPtr = TkpGetNativeFont(tkwin, string);
|
|
|
|
|
if (fontPtr == NULL) {
|
|
|
|
|
TkFontAttributes fa;
|
|
|
|
|
|
|
|
|
|
TkInitFontAttributes(&fa);
|
|
|
|
|
if (ParseFontNameObj(interp, tkwin, objPtr, &fa) != TCL_OK) {
|
|
|
|
|
Tcl_DeleteHashEntry(cacheHashPtr);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* String contained the attributes inline.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Tcl_SetHashValue(cacheHashPtr, fontPtr);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
fontPtr->refCount = 1;
|
|
|
|
|
fontPtr->cacheHashPtr = cacheHashPtr;
|
|
|
|
|
fontPtr->namedHashPtr = namedHashPtr;
|
|
|
|
|
|
|
|
|
|
Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, 0, 0, &fontPtr->tabWidth);
|
|
|
|
|
if (fontPtr->tabWidth == 0) {
|
|
|
|
|
fontPtr->tabWidth = fontPtr->fm.maxWidth;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
fontPtr->tabWidth *= 8;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Make sure the tab width isn't zero (some fonts may not have enough
|
|
|
|
|
* information to set a reasonable tab width).
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (fontPtr->tabWidth == 0) {
|
|
|
|
|
fontPtr->tabWidth = 1;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Get information used for drawing underlines in generic code on a
|
|
|
|
|
* non-underlined font.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
1998-04-10 06:59:06 -04:00
|
|
|
|
|
|
|
|
|
descent = fontPtr->fm.descent;
|
|
|
|
|
fontPtr->underlinePos = descent / 2;
|
|
|
|
|
fontPtr->underlineHeight = fontPtr->fa.pointsize / 10;
|
|
|
|
|
if (fontPtr->underlineHeight == 0) {
|
|
|
|
|
fontPtr->underlineHeight = 1;
|
|
|
|
|
}
|
|
|
|
|
if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {
|
|
|
|
|
/*
|
|
|
|
|
* If this set of values would cause the bottom of the underline
|
|
|
|
|
* bar to stick below the descent of the font, jack the underline
|
|
|
|
|
* up a bit higher.
|
|
|
|
|
*/
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
fontPtr->underlineHeight = descent - fontPtr->underlinePos;
|
|
|
|
|
if (fontPtr->underlineHeight == 0) {
|
|
|
|
|
fontPtr->underlinePos--;
|
|
|
|
|
fontPtr->underlineHeight = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Tk_Font) fontPtr;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Tk_NameOfFont --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Given a font, return a textual string identifying it.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The return value is the description that was passed to
|
|
|
|
|
* Tk_GetFont() to create the font. The storage for the returned
|
|
|
|
|
* string is only guaranteed to persist until the font is deleted.
|
|
|
|
|
* The caller should not modify this string.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
Tk_NameOfFont(tkfont)
|
|
|
|
|
Tk_Font tkfont; /* Font whose name is desired. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
Tcl_HashEntry *hPtr;
|
|
|
|
|
CachedFontKey *keyPtr;
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
hPtr = fontPtr->cacheHashPtr;
|
|
|
|
|
|
|
|
|
|
keyPtr = (CachedFontKey *) Tcl_GetHashKey(hPtr->tablePtr, hPtr);
|
|
|
|
|
return (char *) keyPtr->string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_FreeFont --
|
|
|
|
|
*
|
|
|
|
|
* Called to release a font allocated by Tk_GetFont().
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The reference count associated with font is decremented, and
|
|
|
|
|
* only deallocated when no one is using it.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_FreeFont(tkfont)
|
|
|
|
|
Tk_Font tkfont; /* Font to be released. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
NamedFont *nfPtr;
|
|
|
|
|
|
|
|
|
|
if (tkfont == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
fontPtr->refCount--;
|
|
|
|
|
if (fontPtr->refCount == 0) {
|
|
|
|
|
if (fontPtr->namedHashPtr != NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* The font is being deleted. Determine if the associated named
|
|
|
|
|
* font definition should and/or can be deleted too.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
|
|
|
|
|
nfPtr->refCount--;
|
|
|
|
|
if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
|
|
|
|
|
Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
|
|
|
|
|
ckfree((char *) nfPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
|
|
|
|
|
TkpDeleteFont(fontPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_FontId --
|
|
|
|
|
*
|
|
|
|
|
* Given a font, return an opaque handle that should be selected
|
|
|
|
|
* into the XGCValues structure in order to get the constructed
|
|
|
|
|
* gc to use this font. This procedure would go away if the
|
|
|
|
|
* XGCValues structure were replaced with a TkGCValues structure.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* As above.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Font
|
|
|
|
|
Tk_FontId(tkfont)
|
|
|
|
|
Tk_Font tkfont; /* Font that is going to be selected into GC. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
return fontPtr->fid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_GetFontMetrics --
|
|
|
|
|
*
|
|
|
|
|
* Returns overall ascent and descent metrics for the given font.
|
|
|
|
|
* These values can be used to space multiple lines of text and
|
|
|
|
|
* to align the baselines of text in different fonts.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* If *heightPtr is non-NULL, it is filled with the overall height
|
|
|
|
|
* of the font, which is the sum of the ascent and descent.
|
|
|
|
|
* If *ascentPtr or *descentPtr is non-NULL, they are filled with
|
|
|
|
|
* the ascent and/or descent information for the font.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Tk_GetFontMetrics(tkfont, fmPtr)
|
|
|
|
|
Tk_Font tkfont; /* Font in which metrics are calculated. */
|
|
|
|
|
Tk_FontMetrics *fmPtr; /* Pointer to structure in which font
|
|
|
|
|
* metrics for tkfont will be stored. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
fmPtr->ascent = fontPtr->fm.ascent;
|
|
|
|
|
fmPtr->descent = fontPtr->fm.descent;
|
|
|
|
|
fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_PostscriptFontName --
|
|
|
|
|
*
|
|
|
|
|
* Given a Tk_Font, return the name of the corresponding Postscript
|
|
|
|
|
* font.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is the pointsize of the given Tk_Font.
|
|
|
|
|
* The name of the Postscript font is appended to dsPtr.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If the font does not exist on the printer, the print job will
|
|
|
|
|
* fail at print time. Given a "reasonable" Postscript printer,
|
|
|
|
|
* the following Tk_Font font families should print correctly:
|
|
|
|
|
*
|
|
|
|
|
* Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
|
|
|
|
|
* Helvetica, Monaco, New Century Schoolbook, New York,
|
|
|
|
|
* Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
|
|
|
|
|
* and Zapf Dingbats.
|
|
|
|
|
*
|
|
|
|
|
* Any other Tk_Font font families may not print correctly
|
|
|
|
|
* because the computed Postscript font name may be incorrect.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_PostscriptFontName(tkfont, dsPtr)
|
|
|
|
|
Tk_Font tkfont; /* Font in which text will be printed. */
|
|
|
|
|
Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to
|
|
|
|
|
* which the name of the Postscript font that
|
|
|
|
|
* corresponds to tkfont will be appended. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
char *family, *weightString, *slantString;
|
|
|
|
|
char *src, *dest;
|
|
|
|
|
int upper, len;
|
|
|
|
|
|
|
|
|
|
len = Tcl_DStringLength(dsPtr);
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert the case-insensitive Tk_Font family name to the
|
|
|
|
|
* case-sensitive Postscript family name. Take out any spaces and
|
|
|
|
|
* capitalize the first letter of each word.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
family = fontPtr->fa.family;
|
|
|
|
|
if (strncasecmp(family, "itc ", 4) == 0) {
|
|
|
|
|
family = family + 4;
|
|
|
|
|
}
|
|
|
|
|
if ((strcasecmp(family, "Arial") == 0)
|
|
|
|
|
|| (strcasecmp(family, "Geneva") == 0)) {
|
|
|
|
|
family = "Helvetica";
|
|
|
|
|
} else if ((strcasecmp(family, "Times New Roman") == 0)
|
|
|
|
|
|| (strcasecmp(family, "New York") == 0)) {
|
|
|
|
|
family = "Times";
|
|
|
|
|
} else if ((strcasecmp(family, "Courier New") == 0)
|
|
|
|
|
|| (strcasecmp(family, "Monaco") == 0)) {
|
|
|
|
|
family = "Courier";
|
|
|
|
|
} else if (strcasecmp(family, "AvantGarde") == 0) {
|
|
|
|
|
family = "AvantGarde";
|
|
|
|
|
} else if (strcasecmp(family, "ZapfChancery") == 0) {
|
|
|
|
|
family = "ZapfChancery";
|
|
|
|
|
} else if (strcasecmp(family, "ZapfDingbats") == 0) {
|
|
|
|
|
family = "ZapfDingbats";
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* Inline, capitalize the first letter of each word, lowercase the
|
|
|
|
|
* rest of the letters in each word, and then take out the spaces
|
|
|
|
|
* between the words. This may make the DString shorter, which is
|
|
|
|
|
* safe to do.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Tcl_DStringAppend(dsPtr, family, -1);
|
|
|
|
|
|
|
|
|
|
src = dest = Tcl_DStringValue(dsPtr) + len;
|
|
|
|
|
upper = 1;
|
|
|
|
|
for (; *src != '\0'; src++, dest++) {
|
|
|
|
|
while (isspace(UCHAR(*src))) {
|
|
|
|
|
src++;
|
|
|
|
|
upper = 1;
|
|
|
|
|
}
|
|
|
|
|
*dest = *src;
|
|
|
|
|
if ((upper != 0) && (islower(UCHAR(*src)))) {
|
|
|
|
|
*dest = toupper(UCHAR(*src));
|
|
|
|
|
}
|
|
|
|
|
upper = 0;
|
|
|
|
|
}
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
|
|
|
|
|
family = Tcl_DStringValue(dsPtr) + len;
|
|
|
|
|
}
|
|
|
|
|
if (family != Tcl_DStringValue(dsPtr) + len) {
|
|
|
|
|
Tcl_DStringAppend(dsPtr, family, -1);
|
|
|
|
|
family = Tcl_DStringValue(dsPtr) + len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
|
|
|
|
|
Tcl_DStringSetLength(dsPtr, len);
|
|
|
|
|
Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);
|
|
|
|
|
family = Tcl_DStringValue(dsPtr) + len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the string to use for the weight.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
weightString = NULL;
|
|
|
|
|
if (fontPtr->fa.weight == TK_FW_NORMAL) {
|
|
|
|
|
if (strcmp(family, "Bookman") == 0) {
|
|
|
|
|
weightString = "Light";
|
|
|
|
|
} else if (strcmp(family, "AvantGarde") == 0) {
|
|
|
|
|
weightString = "Book";
|
|
|
|
|
} else if (strcmp(family, "ZapfChancery") == 0) {
|
|
|
|
|
weightString = "Medium";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((strcmp(family, "Bookman") == 0)
|
|
|
|
|
|| (strcmp(family, "AvantGarde") == 0)) {
|
|
|
|
|
weightString = "Demi";
|
|
|
|
|
} else {
|
|
|
|
|
weightString = "Bold";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the string to use for the slant.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
slantString = NULL;
|
|
|
|
|
if (fontPtr->fa.slant == TK_FS_ROMAN) {
|
|
|
|
|
;
|
|
|
|
|
} else {
|
|
|
|
|
if ((strcmp(family, "Helvetica") == 0)
|
|
|
|
|
|| (strcmp(family, "Courier") == 0)
|
|
|
|
|
|| (strcmp(family, "AvantGarde") == 0)) {
|
|
|
|
|
slantString = "Oblique";
|
|
|
|
|
} else {
|
|
|
|
|
slantString = "Italic";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The string "Roman" needs to be added to some fonts that are not bold
|
|
|
|
|
* and not italic.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((slantString == NULL) && (weightString == NULL)) {
|
|
|
|
|
if ((strcmp(family, "Times") == 0)
|
|
|
|
|
|| (strcmp(family, "NewCenturySchlbk") == 0)
|
|
|
|
|
|| (strcmp(family, "Palatino") == 0)) {
|
|
|
|
|
Tcl_DStringAppend(dsPtr, "-Roman", -1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Tcl_DStringAppend(dsPtr, "-", -1);
|
|
|
|
|
if (weightString != NULL) {
|
|
|
|
|
Tcl_DStringAppend(dsPtr, weightString, -1);
|
|
|
|
|
}
|
|
|
|
|
if (slantString != NULL) {
|
|
|
|
|
Tcl_DStringAppend(dsPtr, slantString, -1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fontPtr->fa.pointsize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_TextWidth --
|
|
|
|
|
*
|
|
|
|
|
* A wrapper function for the more complicated interface of
|
|
|
|
|
* Tk_MeasureChars. Computes how much space the given
|
|
|
|
|
* simple string needs.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is the width (in pixels) of the given string.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_TextWidth(tkfont, string, numChars)
|
|
|
|
|
Tk_Font tkfont; /* Font in which text will be measured. */
|
|
|
|
|
CONST char *string; /* String whose width will be computed. */
|
|
|
|
|
int numChars; /* Number of characters to consider from
|
|
|
|
|
* string, or < 0 for strlen(). */
|
|
|
|
|
{
|
|
|
|
|
int width;
|
|
|
|
|
|
|
|
|
|
if (numChars < 0) {
|
|
|
|
|
numChars = strlen(string);
|
|
|
|
|
}
|
|
|
|
|
Tk_MeasureChars(tkfont, string, numChars, 0, 0, &width);
|
|
|
|
|
return width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_UnderlineChars --
|
|
|
|
|
*
|
|
|
|
|
* This procedure draws an underline for a given range of characters
|
|
|
|
|
* in a given string. It doesn't draw the characters (which are
|
|
|
|
|
* assumed to have been displayed previously); it just draws the
|
|
|
|
|
* underline. This procedure would mainly be used to quickly
|
|
|
|
|
* underline a few characters without having to construct an
|
|
|
|
|
* underlined font. To produce properly underlined text, the
|
|
|
|
|
* appropriate underlined font should be constructed and used.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Information gets displayed in "drawable".
|
|
|
|
|
*
|
|
|
|
|
*----------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar,
|
|
|
|
|
lastChar)
|
|
|
|
|
Display *display; /* Display on which to draw. */
|
|
|
|
|
Drawable drawable; /* Window or pixmap in which to draw. */
|
|
|
|
|
GC gc; /* Graphics context for actually drawing
|
|
|
|
|
* line. */
|
|
|
|
|
Tk_Font tkfont; /* Font used in GC; must have been allocated
|
|
|
|
|
* by Tk_GetFont(). Used for character
|
|
|
|
|
* dimensions, etc. */
|
|
|
|
|
CONST char *string; /* String containing characters to be
|
|
|
|
|
* underlined or overstruck. */
|
|
|
|
|
int x, y; /* Coordinates at which first character of
|
|
|
|
|
* string is drawn. */
|
|
|
|
|
int firstChar; /* Index of first character. */
|
|
|
|
|
int lastChar; /* Index of one after the last character. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
int startX, endX;
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
|
|
|
|
|
Tk_MeasureChars(tkfont, string, firstChar, 0, 0, &startX);
|
|
|
|
|
Tk_MeasureChars(tkfont, string, lastChar, 0, 0, &endX);
|
|
|
|
|
|
|
|
|
|
XFillRectangle(display, drawable, gc, x + startX,
|
|
|
|
|
y + fontPtr->underlinePos, (unsigned int) (endX - startX),
|
|
|
|
|
(unsigned int) fontPtr->underlineHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_ComputeTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* Computes the amount of screen space needed to display a
|
|
|
|
|
* multi-line, justified string of text. Records all the
|
|
|
|
|
* measurements that were done to determine to size and
|
|
|
|
|
* positioning of the individual lines of text; this information
|
|
|
|
|
* can be used by the Tk_DrawTextLayout() procedure to
|
|
|
|
|
* display the text quickly (without remeasuring it).
|
|
|
|
|
*
|
|
|
|
|
* This procedure is useful for simple widgets that want to
|
|
|
|
|
* display single-font, multi-line text and want Tk to handle the
|
|
|
|
|
* details.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is a Tk_TextLayout token that holds the
|
|
|
|
|
* measurement information for the given string. The token is
|
|
|
|
|
* only valid for the given string. If the string is freed,
|
|
|
|
|
* the token is no longer valid and must also be freed. To free
|
|
|
|
|
* the token, call Tk_FreeTextLayout().
|
|
|
|
|
*
|
|
|
|
|
* The dimensions of the screen area needed to display the text
|
|
|
|
|
* are stored in *widthPtr and *heightPtr.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Memory is allocated to hold the measurement information.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Tk_TextLayout
|
|
|
|
|
Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,
|
|
|
|
|
widthPtr, heightPtr)
|
|
|
|
|
Tk_Font tkfont; /* Font that will be used to display text. */
|
|
|
|
|
CONST char *string; /* String whose dimensions are to be
|
|
|
|
|
* computed. */
|
|
|
|
|
int numChars; /* Number of characters to consider from
|
|
|
|
|
* string, or < 0 for strlen(). */
|
|
|
|
|
int wrapLength; /* Longest permissible line length, in
|
|
|
|
|
* pixels. <= 0 means no automatic wrapping:
|
|
|
|
|
* just let lines get as long as needed. */
|
|
|
|
|
Tk_Justify justify; /* How to justify lines. */
|
|
|
|
|
int flags; /* Flag bits OR-ed together.
|
|
|
|
|
* TK_IGNORE_TABS means that tab characters
|
|
|
|
|
* should not be expanded. TK_IGNORE_NEWLINES
|
|
|
|
|
* means that newline characters should not
|
|
|
|
|
* cause a line break. */
|
|
|
|
|
int *widthPtr; /* Filled with width of string. */
|
|
|
|
|
int *heightPtr; /* Filled with height of string. */
|
|
|
|
|
{
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
CONST char *start, *end, *special;
|
|
|
|
|
int n, y, charsThisChunk, maxChunks;
|
|
|
|
|
int baseline, height, curX, newX, maxWidth;
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
CONST TkFontMetrics *fmPtr;
|
|
|
|
|
#define MAX_LINES 50
|
|
|
|
|
int staticLineLengths[MAX_LINES];
|
|
|
|
|
int *lineLengths;
|
|
|
|
|
int maxLines, curLine, layoutHeight;
|
|
|
|
|
|
|
|
|
|
lineLengths = staticLineLengths;
|
|
|
|
|
maxLines = MAX_LINES;
|
|
|
|
|
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
fmPtr = &fontPtr->fm;
|
|
|
|
|
|
|
|
|
|
height = fmPtr->ascent + fmPtr->descent;
|
|
|
|
|
|
|
|
|
|
if (numChars < 0) {
|
|
|
|
|
numChars = strlen(string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
maxChunks = 1;
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)
|
|
|
|
|
+ (maxChunks - 1) * sizeof(LayoutChunk));
|
|
|
|
|
layoutPtr->tkfont = tkfont;
|
|
|
|
|
layoutPtr->string = string;
|
|
|
|
|
layoutPtr->numChunks = 0;
|
|
|
|
|
|
|
|
|
|
baseline = fmPtr->ascent;
|
|
|
|
|
maxWidth = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Divide the string up into simple strings and measure each string.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
curX = 0;
|
|
|
|
|
|
|
|
|
|
end = string + numChars;
|
|
|
|
|
special = string;
|
|
|
|
|
|
|
|
|
|
flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
|
|
|
|
|
flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;
|
|
|
|
|
curLine = 0;
|
|
|
|
|
for (start = string; start < end; ) {
|
|
|
|
|
if (start >= special) {
|
|
|
|
|
/*
|
|
|
|
|
* Find the next special character in the string.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (special = start; special < end; special++) {
|
|
|
|
|
if (!(flags & TK_IGNORE_NEWLINES)) {
|
|
|
|
|
if ((*special == '\n') || (*special == '\r')) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!(flags & TK_IGNORE_TABS)) {
|
|
|
|
|
if (*special == '\t') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Special points at the next special character (or the end of the
|
|
|
|
|
* string). Process characters between start and special.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
chunkPtr = NULL;
|
|
|
|
|
if (start < special) {
|
|
|
|
|
charsThisChunk = Tk_MeasureChars(tkfont, start, special - start,
|
|
|
|
|
wrapLength - curX, flags, &newX);
|
|
|
|
|
newX += curX;
|
|
|
|
|
flags &= ~TK_AT_LEAST_ONE;
|
|
|
|
|
if (charsThisChunk > 0) {
|
|
|
|
|
chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
|
|
|
|
|
charsThisChunk, curX, newX, baseline);
|
|
|
|
|
|
|
|
|
|
start += charsThisChunk;
|
|
|
|
|
curX = newX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((start == special) && (special < end)) {
|
|
|
|
|
/*
|
|
|
|
|
* Handle the special character.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
chunkPtr = NULL;
|
|
|
|
|
if (*special == '\t') {
|
|
|
|
|
newX = curX + fontPtr->tabWidth;
|
|
|
|
|
newX -= newX % fontPtr->tabWidth;
|
|
|
|
|
NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
|
|
|
|
|
baseline)->numDisplayChars = -1;
|
|
|
|
|
start++;
|
|
|
|
|
if ((start < end) &&
|
|
|
|
|
((wrapLength <= 0) || (newX <= wrapLength))) {
|
|
|
|
|
/*
|
|
|
|
|
* More chars can still fit on this line.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
curX = newX;
|
|
|
|
|
flags &= ~TK_AT_LEAST_ONE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NewChunk(&layoutPtr, &maxChunks, start, 1, curX, 1000000000,
|
|
|
|
|
baseline)->numDisplayChars = -1;
|
|
|
|
|
start++;
|
|
|
|
|
goto wrapLine;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* No more characters are going to go on this line, either because
|
|
|
|
|
* no more characters can fit or there are no more characters left.
|
|
|
|
|
* Consume all extra spaces at end of line.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
while ((start < end) && isspace(UCHAR(*start))) {
|
|
|
|
|
if (!(flags & TK_IGNORE_NEWLINES)) {
|
|
|
|
|
if ((*start == '\n') || (*start == '\r')) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!(flags & TK_IGNORE_TABS)) {
|
|
|
|
|
if (*start == '\t') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
start++;
|
|
|
|
|
}
|
|
|
|
|
if (chunkPtr != NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* Append all the extra spaces on this line to the end of the
|
|
|
|
|
* last text chunk.
|
|
|
|
|
*/
|
|
|
|
|
charsThisChunk = start - (chunkPtr->start + chunkPtr->numChars);
|
|
|
|
|
if (charsThisChunk > 0) {
|
|
|
|
|
chunkPtr->numChars += Tk_MeasureChars(tkfont,
|
|
|
|
|
chunkPtr->start + chunkPtr->numChars, charsThisChunk,
|
|
|
|
|
0, 0, &chunkPtr->totalWidth);
|
|
|
|
|
chunkPtr->totalWidth += curX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wrapLine:
|
|
|
|
|
flags |= TK_AT_LEAST_ONE;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Save current line length, then move current position to start of
|
|
|
|
|
* next line.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (curX > maxWidth) {
|
|
|
|
|
maxWidth = curX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Remember width of this line, so that all chunks on this line
|
|
|
|
|
* can be centered or right justified, if necessary.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (curLine >= maxLines) {
|
|
|
|
|
int *newLengths;
|
|
|
|
|
|
|
|
|
|
newLengths = (int *) ckalloc(2 * maxLines * sizeof(int));
|
|
|
|
|
memcpy((void *) newLengths, lineLengths, maxLines * sizeof(int));
|
|
|
|
|
if (lineLengths != staticLineLengths) {
|
|
|
|
|
ckfree((char *) lineLengths);
|
|
|
|
|
}
|
|
|
|
|
lineLengths = newLengths;
|
|
|
|
|
maxLines *= 2;
|
|
|
|
|
}
|
|
|
|
|
lineLengths[curLine] = curX;
|
|
|
|
|
curLine++;
|
|
|
|
|
|
|
|
|
|
curX = 0;
|
|
|
|
|
baseline += height;
|
|
|
|
|
}
|
|
|
|
|
|
1998-09-30 07:11:02 -04:00
|
|
|
|
/*
|
|
|
|
|
* If last line ends with a newline, then we need to make a 0 width
|
|
|
|
|
* chunk on the next line. Otherwise "Hello" and "Hello\n" are the
|
|
|
|
|
* same height.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {
|
|
|
|
|
if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') {
|
|
|
|
|
chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,
|
|
|
|
|
1000000000, baseline);
|
|
|
|
|
chunkPtr->numDisplayChars = -1;
|
|
|
|
|
baseline += height;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/*
|
|
|
|
|
* Using maximum line length, shift all the chunks so that the lines are
|
|
|
|
|
* all justified correctly.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
curLine = 0;
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
y = chunkPtr->y;
|
|
|
|
|
for (n = 0; n < layoutPtr->numChunks; n++) {
|
|
|
|
|
int extra;
|
|
|
|
|
|
|
|
|
|
if (chunkPtr->y != y) {
|
|
|
|
|
curLine++;
|
|
|
|
|
y = chunkPtr->y;
|
|
|
|
|
}
|
|
|
|
|
extra = maxWidth - lineLengths[curLine];
|
|
|
|
|
if (justify == TK_JUSTIFY_CENTER) {
|
|
|
|
|
chunkPtr->x += extra / 2;
|
|
|
|
|
} else if (justify == TK_JUSTIFY_RIGHT) {
|
|
|
|
|
chunkPtr->x += extra;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutPtr->width = maxWidth;
|
|
|
|
|
layoutHeight = baseline - fmPtr->ascent;
|
|
|
|
|
if (layoutPtr->numChunks == 0) {
|
|
|
|
|
layoutHeight = height;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This fake chunk is used by the other procedures so that they can
|
|
|
|
|
* pretend that there is a chunk with no chars in it, which makes
|
|
|
|
|
* the coding simpler.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
layoutPtr->numChunks = 1;
|
|
|
|
|
layoutPtr->chunks[0].start = string;
|
|
|
|
|
layoutPtr->chunks[0].numChars = 0;
|
|
|
|
|
layoutPtr->chunks[0].numDisplayChars = -1;
|
|
|
|
|
layoutPtr->chunks[0].x = 0;
|
|
|
|
|
layoutPtr->chunks[0].y = fmPtr->ascent;
|
|
|
|
|
layoutPtr->chunks[0].totalWidth = 0;
|
|
|
|
|
layoutPtr->chunks[0].displayWidth = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (widthPtr != NULL) {
|
|
|
|
|
*widthPtr = layoutPtr->width;
|
|
|
|
|
}
|
|
|
|
|
if (heightPtr != NULL) {
|
|
|
|
|
*heightPtr = layoutHeight;
|
|
|
|
|
}
|
|
|
|
|
if (lineLengths != staticLineLengths) {
|
|
|
|
|
ckfree((char *) lineLengths);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Tk_TextLayout) layoutPtr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_FreeTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called to release the storage associated with
|
|
|
|
|
* a Tk_TextLayout when it is no longer needed.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Memory is freed.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_FreeTextLayout(textLayout)
|
|
|
|
|
Tk_TextLayout textLayout; /* The text layout to be released. */
|
|
|
|
|
{
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) textLayout;
|
|
|
|
|
if (layoutPtr != NULL) {
|
|
|
|
|
ckfree((char *) layoutPtr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_DrawTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* Use the information in the Tk_TextLayout token to display a
|
|
|
|
|
* multi-line, justified string of text.
|
|
|
|
|
*
|
|
|
|
|
* This procedure is useful for simple widgets that need to
|
|
|
|
|
* display single-font, multi-line text and want Tk to handle
|
|
|
|
|
* the details.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Text drawn on the screen.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)
|
|
|
|
|
Display *display; /* Display on which to draw. */
|
|
|
|
|
Drawable drawable; /* Window or pixmap in which to draw. */
|
|
|
|
|
GC gc; /* Graphics context to use for drawing text. */
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call
|
|
|
|
|
* to Tk_ComputeTextLayout(). */
|
|
|
|
|
int x, y; /* Upper-left hand corner of rectangle in
|
|
|
|
|
* which to draw (pixels). */
|
|
|
|
|
int firstChar; /* The index of the first character to draw
|
|
|
|
|
* from the given text item. 0 specfies the
|
|
|
|
|
* beginning. */
|
|
|
|
|
int lastChar; /* The index just after the last character
|
|
|
|
|
* to draw from the given text item. A number
|
|
|
|
|
* < 0 means to draw all characters. */
|
|
|
|
|
{
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
int i, numDisplayChars, drawX;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
if (layoutPtr == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastChar < 0) {
|
|
|
|
|
lastChar = 100000000;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
numDisplayChars = chunkPtr->numDisplayChars;
|
|
|
|
|
if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
|
|
|
|
|
if (firstChar <= 0) {
|
|
|
|
|
drawX = 0;
|
|
|
|
|
firstChar = 0;
|
|
|
|
|
} else {
|
|
|
|
|
Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, firstChar,
|
|
|
|
|
0, 0, &drawX);
|
|
|
|
|
}
|
|
|
|
|
if (lastChar < numDisplayChars) {
|
|
|
|
|
numDisplayChars = lastChar;
|
|
|
|
|
}
|
|
|
|
|
Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
|
|
|
|
|
chunkPtr->start + firstChar, numDisplayChars - firstChar,
|
|
|
|
|
x + chunkPtr->x + drawX, y + chunkPtr->y);
|
|
|
|
|
}
|
|
|
|
|
firstChar -= chunkPtr->numChars;
|
|
|
|
|
lastChar -= chunkPtr->numChars;
|
|
|
|
|
if (lastChar <= 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_UnderlineTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* Use the information in the Tk_TextLayout token to display an
|
|
|
|
|
* underline below an individual character. This procedure does
|
|
|
|
|
* not draw the text, just the underline.
|
|
|
|
|
*
|
|
|
|
|
* This procedure is useful for simple widgets that need to
|
|
|
|
|
* display single-font, multi-line text with an individual
|
|
|
|
|
* character underlined and want Tk to handle the details.
|
|
|
|
|
* To display larger amounts of underlined text, construct
|
|
|
|
|
* and use an underlined font.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Underline drawn on the screen.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)
|
|
|
|
|
Display *display; /* Display on which to draw. */
|
|
|
|
|
Drawable drawable; /* Window or pixmap in which to draw. */
|
|
|
|
|
GC gc; /* Graphics context to use for drawing text. */
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call
|
|
|
|
|
* to Tk_ComputeTextLayout(). */
|
|
|
|
|
int x, y; /* Upper-left hand corner of rectangle in
|
|
|
|
|
* which to draw (pixels). */
|
|
|
|
|
int underline; /* Index of the single character to
|
|
|
|
|
* underline, or -1 for no underline. */
|
|
|
|
|
{
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
int xx, yy, width, height;
|
|
|
|
|
|
|
|
|
|
if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)
|
|
|
|
|
&& (width != 0)) {
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
fontPtr = (TkFont *) layoutPtr->tkfont;
|
|
|
|
|
|
|
|
|
|
XFillRectangle(display, drawable, gc, x + xx,
|
|
|
|
|
y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,
|
|
|
|
|
(unsigned int) width, (unsigned int) fontPtr->underlineHeight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_PointToChar --
|
|
|
|
|
*
|
|
|
|
|
* Use the information in the Tk_TextLayout token to determine the
|
|
|
|
|
* character closest to the given point. The point must be
|
|
|
|
|
* specified with respect to the upper-left hand corner of the
|
|
|
|
|
* text layout, which is considered to be located at (0, 0).
|
|
|
|
|
*
|
|
|
|
|
* Any point whose y-value is less that 0 will be considered closest
|
|
|
|
|
* to the first character in the text layout; any point whose y-value
|
|
|
|
|
* is greater than the height of the text layout will be considered
|
|
|
|
|
* closest to the last character in the text layout.
|
|
|
|
|
*
|
|
|
|
|
* Any point whose x-value is less than 0 will be considered closest
|
|
|
|
|
* to the first character on that line; any point whose x-value is
|
|
|
|
|
* greater than the width of the text layout will be considered
|
|
|
|
|
* closest to the last character on that line.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is the index of the character that was
|
|
|
|
|
* closest to the point. Given a text layout with no characters,
|
|
|
|
|
* the value 0 will always be returned, referring to a hypothetical
|
|
|
|
|
* zero-width placeholder character.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_PointToChar(layout, x, y)
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call
|
|
|
|
|
* to Tk_ComputeTextLayout(). */
|
|
|
|
|
int x, y; /* Coordinates of point to check, with
|
|
|
|
|
* respect to the upper-left corner of the
|
|
|
|
|
* text layout. */
|
|
|
|
|
{
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
LayoutChunk *chunkPtr, *lastPtr;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
int i, n, dummy, baseline, pos;
|
|
|
|
|
|
|
|
|
|
if (y < 0) {
|
|
|
|
|
/*
|
|
|
|
|
* Point lies above any line in this layout. Return the index of
|
|
|
|
|
* the first char.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find which line contains the point.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
fontPtr = (TkFont *) layoutPtr->tkfont;
|
|
|
|
|
lastPtr = chunkPtr = layoutPtr->chunks;
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
baseline = chunkPtr->y;
|
|
|
|
|
if (y < baseline + fontPtr->fm.descent) {
|
|
|
|
|
if (x < chunkPtr->x) {
|
|
|
|
|
/*
|
|
|
|
|
* Point is to the left of all chunks on this line. Return
|
|
|
|
|
* the index of the first character on this line.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return chunkPtr->start - layoutPtr->string;
|
|
|
|
|
}
|
|
|
|
|
if (x >= layoutPtr->width) {
|
|
|
|
|
/*
|
|
|
|
|
* If point lies off right side of the text layout, return
|
|
|
|
|
* the last char in the last chunk on this line. Without
|
|
|
|
|
* this, it might return the index of the first char that
|
|
|
|
|
* was located outside of the text layout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
x = INT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Examine all chunks on this line to see which one contains
|
|
|
|
|
* the specified point.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
lastPtr = chunkPtr;
|
|
|
|
|
while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline)) {
|
|
|
|
|
if (x < chunkPtr->x + chunkPtr->totalWidth) {
|
|
|
|
|
/*
|
|
|
|
|
* Point falls on one of the characters in this chunk.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (chunkPtr->numDisplayChars < 0) {
|
|
|
|
|
/*
|
|
|
|
|
* This is a special chunk that encapsulates a single
|
|
|
|
|
* tab or newline char.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return chunkPtr->start - layoutPtr->string;
|
|
|
|
|
}
|
|
|
|
|
n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
|
|
|
|
|
chunkPtr->numChars, x + 1 - chunkPtr->x,
|
|
|
|
|
TK_PARTIAL_OK, &dummy);
|
|
|
|
|
return (chunkPtr->start + n - 1) - layoutPtr->string;
|
|
|
|
|
}
|
|
|
|
|
lastPtr = chunkPtr;
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Point is to the right of all chars in all the chunks on this
|
|
|
|
|
* line. Return the index just past the last char in the last
|
|
|
|
|
* chunk on this line.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pos = (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
|
|
|
|
|
if (i < layoutPtr->numChunks) {
|
|
|
|
|
pos--;
|
|
|
|
|
}
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
lastPtr = chunkPtr;
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Point lies below any line in this text layout. Return the index
|
|
|
|
|
* just past the last char.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_CharBbox --
|
|
|
|
|
*
|
|
|
|
|
* Use the information in the Tk_TextLayout token to return the
|
|
|
|
|
* bounding box for the character specified by index.
|
|
|
|
|
*
|
|
|
|
|
* The width of the bounding box is the advance width of the
|
|
|
|
|
* character, and does not include and left- or right-bearing.
|
|
|
|
|
* Any character that extends partially outside of the
|
|
|
|
|
* text layout is considered to be truncated at the edge. Any
|
|
|
|
|
* character which is located completely outside of the text
|
|
|
|
|
* layout is considered to be zero-width and pegged against
|
|
|
|
|
* the edge.
|
|
|
|
|
*
|
|
|
|
|
* The height of the bounding box is the line height for this font,
|
|
|
|
|
* extending from the top of the ascent to the bottom of the
|
|
|
|
|
* descent. Information about the actual height of the individual
|
|
|
|
|
* letter is not available.
|
|
|
|
|
*
|
|
|
|
|
* A text layout that contains no characters is considered to
|
|
|
|
|
* contain a single zero-width placeholder character.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is 0 if the index did not specify a character
|
|
|
|
|
* in the text layout, or non-zero otherwise. In that case,
|
|
|
|
|
* *bbox is filled with the bounding box of the character.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call to
|
|
|
|
|
* Tk_ComputeTextLayout(). */
|
|
|
|
|
int index; /* The index of the character whose bbox is
|
|
|
|
|
* desired. */
|
|
|
|
|
int *xPtr, *yPtr; /* Filled with the upper-left hand corner, in
|
|
|
|
|
* pixels, of the bounding box for the character
|
|
|
|
|
* specified by index, if non-NULL. */
|
|
|
|
|
int *widthPtr, *heightPtr;
|
|
|
|
|
/* Filled with the width and height of the
|
|
|
|
|
* bounding box for the character specified by
|
|
|
|
|
* index, if non-NULL. */
|
|
|
|
|
{
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
int i, x, w;
|
|
|
|
|
Tk_Font tkfont;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
tkfont = layoutPtr->tkfont;
|
|
|
|
|
fontPtr = (TkFont *) tkfont;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
if (chunkPtr->numDisplayChars < 0) {
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
x = chunkPtr->x;
|
|
|
|
|
w = chunkPtr->totalWidth;
|
|
|
|
|
goto check;
|
|
|
|
|
}
|
|
|
|
|
} else if (index < chunkPtr->numChars) {
|
|
|
|
|
if (xPtr != NULL) {
|
|
|
|
|
Tk_MeasureChars(tkfont, chunkPtr->start, index, 0, 0, &x);
|
|
|
|
|
x += chunkPtr->x;
|
|
|
|
|
}
|
|
|
|
|
if (widthPtr != NULL) {
|
|
|
|
|
Tk_MeasureChars(tkfont, chunkPtr->start + index, 1, 0, 0, &w);
|
|
|
|
|
}
|
|
|
|
|
goto check;
|
|
|
|
|
}
|
|
|
|
|
index -= chunkPtr->numChars;
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
/*
|
|
|
|
|
* Special case to get location just past last char in layout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
chunkPtr--;
|
|
|
|
|
x = chunkPtr->x + chunkPtr->totalWidth;
|
|
|
|
|
w = 0;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ensure that the bbox lies within the text layout. This forces all
|
|
|
|
|
* chars that extend off the right edge of the text layout to have
|
|
|
|
|
* truncated widths, and all chars that are completely off the right
|
|
|
|
|
* edge of the text layout to peg to the edge and have 0 width.
|
|
|
|
|
*/
|
|
|
|
|
check:
|
|
|
|
|
if (yPtr != NULL) {
|
|
|
|
|
*yPtr = chunkPtr->y - fontPtr->fm.ascent;
|
|
|
|
|
}
|
|
|
|
|
if (heightPtr != NULL) {
|
|
|
|
|
*heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x > layoutPtr->width) {
|
|
|
|
|
x = layoutPtr->width;
|
|
|
|
|
}
|
|
|
|
|
if (xPtr != NULL) {
|
|
|
|
|
*xPtr = x;
|
|
|
|
|
}
|
|
|
|
|
if (widthPtr != NULL) {
|
|
|
|
|
if (x + w > layoutPtr->width) {
|
|
|
|
|
w = layoutPtr->width - x;
|
|
|
|
|
}
|
|
|
|
|
*widthPtr = w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_DistanceToTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* Computes the distance in pixels from the given point to the
|
|
|
|
|
* given text layout. Non-displaying space characters that occur
|
|
|
|
|
* at the end of individual lines in the text layout are ignored
|
|
|
|
|
* for hit detection purposes.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is 0 if the point (x, y) is inside the text
|
|
|
|
|
* layout. If the point isn't inside the text layout then the
|
|
|
|
|
* return value is the distance in pixels from the point to the
|
|
|
|
|
* text item.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_DistanceToTextLayout(layout, x, y)
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call
|
|
|
|
|
* to Tk_ComputeTextLayout(). */
|
|
|
|
|
int x, y; /* Coordinates of point to check, with
|
|
|
|
|
* respect to the upper-left corner of the
|
|
|
|
|
* text layout (in pixels). */
|
|
|
|
|
{
|
|
|
|
|
int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
fontPtr = (TkFont *) layoutPtr->tkfont;
|
|
|
|
|
ascent = fontPtr->fm.ascent;
|
|
|
|
|
descent = fontPtr->fm.descent;
|
|
|
|
|
|
|
|
|
|
minDist = 0;
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
if (chunkPtr->start[0] == '\n') {
|
|
|
|
|
/*
|
|
|
|
|
* Newline characters are not counted when computing distance
|
|
|
|
|
* (but tab characters would still be considered).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x1 = chunkPtr->x;
|
|
|
|
|
y1 = chunkPtr->y - ascent;
|
|
|
|
|
x2 = chunkPtr->x + chunkPtr->displayWidth;
|
|
|
|
|
y2 = chunkPtr->y + descent;
|
|
|
|
|
|
|
|
|
|
if (x < x1) {
|
|
|
|
|
xDiff = x1 - x;
|
|
|
|
|
} else if (x >= x2) {
|
|
|
|
|
xDiff = x - x2 + 1;
|
|
|
|
|
} else {
|
|
|
|
|
xDiff = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (y < y1) {
|
|
|
|
|
yDiff = y1 - y;
|
|
|
|
|
} else if (y >= y2) {
|
|
|
|
|
yDiff = y - y2 + 1;
|
|
|
|
|
} else {
|
|
|
|
|
yDiff = 0;
|
|
|
|
|
}
|
|
|
|
|
if ((xDiff == 0) && (yDiff == 0)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
dist = (int) hypot((double) xDiff, (double) yDiff);
|
|
|
|
|
if ((dist < minDist) || (minDist == 0)) {
|
|
|
|
|
minDist = dist;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
return minDist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_IntersectTextLayout --
|
|
|
|
|
*
|
|
|
|
|
* Determines whether a text layout lies entirely inside,
|
|
|
|
|
* entirely outside, or overlaps a given rectangle. Non-displaying
|
|
|
|
|
* space characters that occur at the end of individual lines in
|
|
|
|
|
* the text layout are ignored for intersection calculations.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is -1 if the text layout is entirely outside of
|
|
|
|
|
* the rectangle, 0 if it overlaps, and 1 if it is entirely inside
|
|
|
|
|
* of the rectangle.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Tk_IntersectTextLayout(layout, x, y, width, height)
|
|
|
|
|
Tk_TextLayout layout; /* Layout information, from a previous call
|
|
|
|
|
* to Tk_ComputeTextLayout(). */
|
|
|
|
|
int x, y; /* Upper-left hand corner, in pixels, of
|
|
|
|
|
* rectangular area to compare with text
|
|
|
|
|
* layout. Coordinates are with respect to
|
|
|
|
|
* the upper-left hand corner of the text
|
|
|
|
|
* layout itself. */
|
|
|
|
|
int width, height; /* The width and height of the above
|
|
|
|
|
* rectangular area, in pixels. */
|
|
|
|
|
{
|
|
|
|
|
int result, i, x1, y1, x2, y2;
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
TkFont *fontPtr;
|
|
|
|
|
int left, top, right, bottom;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scan the chunks one at a time, seeing whether each is entirely in,
|
|
|
|
|
* entirely out, or overlapping the rectangle. If an overlap is
|
|
|
|
|
* detected, return immediately; otherwise wait until all chunks have
|
|
|
|
|
* been processed and see if they were all inside or all outside.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
fontPtr = (TkFont *) layoutPtr->tkfont;
|
|
|
|
|
|
|
|
|
|
left = x;
|
|
|
|
|
top = y;
|
|
|
|
|
right = x + width;
|
|
|
|
|
bottom = y + height;
|
|
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
if (chunkPtr->start[0] == '\n') {
|
|
|
|
|
/*
|
|
|
|
|
* Newline characters are not counted when computing area
|
|
|
|
|
* intersection (but tab characters would still be considered).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x1 = chunkPtr->x;
|
|
|
|
|
y1 = chunkPtr->y - fontPtr->fm.ascent;
|
|
|
|
|
x2 = chunkPtr->x + chunkPtr->displayWidth;
|
|
|
|
|
y2 = chunkPtr->y + fontPtr->fm.descent;
|
|
|
|
|
|
|
|
|
|
if ((right < x1) || (left >= x2)
|
|
|
|
|
|| (bottom < y1) || (top >= y2)) {
|
|
|
|
|
if (result == 1) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
result = -1;
|
|
|
|
|
} else if ((x1 < left) || (x2 >= right)
|
|
|
|
|
|| (y1 < top) || (y2 >= bottom)) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (result == -1) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
result = 1;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Tk_TextLayoutToPostscript --
|
|
|
|
|
*
|
|
|
|
|
* Outputs the contents of a text layout in Postscript format.
|
|
|
|
|
* The set of lines in the text layout will be rendered by the user
|
|
|
|
|
* supplied Postscript function. The function should be of the form:
|
|
|
|
|
*
|
|
|
|
|
* justify x y string function --
|
|
|
|
|
*
|
|
|
|
|
* Justify is -1, 0, or 1, depending on whether the following string
|
|
|
|
|
* should be left, center, or right justified, x and y is the
|
|
|
|
|
* location for the origin of the string, string is the sequence
|
|
|
|
|
* of characters to be printed, and function is the name of the
|
|
|
|
|
* caller-provided function; the function should leave nothing
|
|
|
|
|
* on the stack.
|
|
|
|
|
*
|
|
|
|
|
* The meaning of the origin of the string (x and y) depends on
|
|
|
|
|
* the justification. For left justification, x is where the
|
|
|
|
|
* left edge of the string should appear. For center justification,
|
|
|
|
|
* x is where the center of the string should appear. And for right
|
|
|
|
|
* justification, x is where the right edge of the string should
|
|
|
|
|
* appear. This behavior is necessary because, for example, right
|
|
|
|
|
* justified text on the screen is justified with screen metrics.
|
|
|
|
|
* The same string needs to be justified with printer metrics on
|
|
|
|
|
* the printer to appear in the correct place with respect to other
|
|
|
|
|
* similarly justified strings. In all circumstances, y is the
|
|
|
|
|
* location of the baseline for the string.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Interp->result is modified to hold the Postscript code that
|
|
|
|
|
* will render the text layout.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tk_TextLayoutToPostscript(interp, layout)
|
|
|
|
|
Tcl_Interp *interp; /* Filled with Postscript code. */
|
|
|
|
|
Tk_TextLayout layout; /* The layout to be rendered. */
|
|
|
|
|
{
|
|
|
|
|
#define MAXUSE 128
|
|
|
|
|
char buf[MAXUSE+10];
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
int i, j, used, c, baseline;
|
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
|
|
|
|
|
layoutPtr = (TextLayout *) layout;
|
|
|
|
|
chunkPtr = layoutPtr->chunks;
|
|
|
|
|
baseline = chunkPtr->y;
|
|
|
|
|
used = 0;
|
|
|
|
|
buf[used++] = '(';
|
|
|
|
|
for (i = 0; i < layoutPtr->numChunks; i++) {
|
|
|
|
|
if (baseline != chunkPtr->y) {
|
|
|
|
|
buf[used++] = ')';
|
|
|
|
|
buf[used++] = '\n';
|
|
|
|
|
buf[used++] = '(';
|
|
|
|
|
baseline = chunkPtr->y;
|
|
|
|
|
}
|
|
|
|
|
if (chunkPtr->numDisplayChars <= 0) {
|
|
|
|
|
if (chunkPtr->start[0] == '\t') {
|
|
|
|
|
buf[used++] = '\\';
|
|
|
|
|
buf[used++] = 't';
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (j = 0; j < chunkPtr->numDisplayChars; j++) {
|
|
|
|
|
c = UCHAR(chunkPtr->start[j]);
|
|
|
|
|
if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)
|
|
|
|
|
|| (c >= UCHAR(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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
sprintf(buf + used, "\\%03o", c);
|
|
|
|
|
used += 4;
|
|
|
|
|
} else {
|
|
|
|
|
buf[used++] = c;
|
|
|
|
|
}
|
|
|
|
|
if (used >= MAXUSE) {
|
|
|
|
|
buf[used] = '\0';
|
|
|
|
|
Tcl_AppendResult(interp, buf, (char *) NULL);
|
|
|
|
|
used = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (used >= MAXUSE) {
|
|
|
|
|
/*
|
|
|
|
|
* If there are a whole bunch of returns or tabs in a row,
|
|
|
|
|
* then buf[] could get filled up.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
buf[used] = '\0';
|
|
|
|
|
Tcl_AppendResult(interp, buf, (char *) NULL);
|
|
|
|
|
used = 0;
|
|
|
|
|
}
|
|
|
|
|
chunkPtr++;
|
|
|
|
|
}
|
|
|
|
|
buf[used++] = ')';
|
|
|
|
|
buf[used++] = '\n';
|
|
|
|
|
buf[used] = '\0';
|
|
|
|
|
Tcl_AppendResult(interp, buf, (char *) NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TkInitFontAttributes --
|
|
|
|
|
*
|
|
|
|
|
* Initialize the font attributes structure to contain sensible
|
|
|
|
|
* values. This must be called before using any other font
|
|
|
|
|
* attributes functions.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Side effects.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
* None.
|
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
void
|
|
|
|
|
TkInitFontAttributes(faPtr)
|
|
|
|
|
TkFontAttributes *faPtr; /* The attributes structure to initialize. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
faPtr->family = NULL;
|
|
|
|
|
faPtr->pointsize = 0;
|
|
|
|
|
faPtr->weight = TK_FW_NORMAL;
|
|
|
|
|
faPtr->slant = TK_FS_ROMAN;
|
|
|
|
|
faPtr->underline = 0;
|
|
|
|
|
faPtr->overstrike = 0;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* ConfigAttributesObj --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Process command line options to fill in fields of a properly
|
|
|
|
|
* initialized font attributes structure.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* A standard Tcl return value. If TCL_ERROR is returned, an
|
|
|
|
|
* error message will be left in interp's result object.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The fields of the font attributes structure get filled in with
|
|
|
|
|
* information from argc/argv. If an error occurs while parsing,
|
|
|
|
|
* the font attributes structure will contain all modifications
|
|
|
|
|
* specified in the command line options up to the point of the
|
|
|
|
|
* error.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static int
|
|
|
|
|
ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)
|
|
|
|
|
Tcl_Interp *interp; /* Interp for error return. */
|
|
|
|
|
Tk_Window tkwin; /* For display on which font will be used. */
|
|
|
|
|
int objc; /* Number of elements in argv. */
|
|
|
|
|
Tcl_Obj *CONST objv[]; /* Command line options. */
|
|
|
|
|
TkFontAttributes *faPtr; /* Font attributes structure whose fields
|
|
|
|
|
* are to be modified. Structure must already
|
|
|
|
|
* be properly initialized. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
int i, n, index;
|
|
|
|
|
Tcl_Obj *value;
|
|
|
|
|
char *option, *string;
|
|
|
|
|
|
|
|
|
|
if (objc & 1) {
|
|
|
|
|
string = Tcl_GetStringFromObj(objv[objc - 1], NULL);
|
|
|
|
|
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "missing value for \"",
|
|
|
|
|
string, "\" option", (char *) NULL);
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
for (i = 0; i < objc; i += 2) {
|
|
|
|
|
option = Tcl_GetStringFromObj(objv[i], NULL);
|
|
|
|
|
value = objv[i + 1];
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (Tcl_GetIndexFromObj(interp, objv[i], fontOpt, "option", 1,
|
|
|
|
|
&index) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
switch (index) {
|
|
|
|
|
case FONT_FAMILY:
|
|
|
|
|
string = Tcl_GetStringFromObj(value, NULL);
|
|
|
|
|
faPtr->family = Tk_GetUid(string);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_SIZE:
|
|
|
|
|
if (Tcl_GetIntFromObj(interp, value, &n) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->pointsize = n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_WEIGHT:
|
|
|
|
|
string = Tcl_GetStringFromObj(value, NULL);
|
|
|
|
|
n = TkFindStateNum(interp, option, weightMap, string);
|
|
|
|
|
if (n == TK_FW_UNKNOWN) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->weight = n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_SLANT:
|
|
|
|
|
string = Tcl_GetStringFromObj(value, NULL);
|
|
|
|
|
n = TkFindStateNum(interp, option, slantMap, string);
|
|
|
|
|
if (n == TK_FS_UNKNOWN) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->slant = n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_UNDERLINE:
|
|
|
|
|
if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->underline = n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_OVERSTRIKE:
|
|
|
|
|
if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->overstrike = n;
|
|
|
|
|
break;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
return TCL_OK;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* GetAttributeInfoObj --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Return information about the font attributes as a Tcl list.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-09-30 07:11:02 -04:00
|
|
|
|
* The return value is TCL_OK if the objPtr was non-NULL and
|
|
|
|
|
* specified a valid font attribute, TCL_ERROR otherwise. If TCL_OK
|
|
|
|
|
* is returned, the interp's result object is modified to hold a
|
|
|
|
|
* description of either the current value of a single option, or a
|
|
|
|
|
* list of all options and their current values for the given font
|
|
|
|
|
* attributes. If TCL_ERROR is returned, the interp's result is
|
|
|
|
|
* set to an error message describing that the objPtr did not refer
|
|
|
|
|
* to a valid option.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* None.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-09-30 07:11:02 -04:00
|
|
|
|
static int
|
1998-04-10 06:59:06 -04:00
|
|
|
|
GetAttributeInfoObj(interp, faPtr, objPtr)
|
|
|
|
|
Tcl_Interp *interp; /* Interp to hold result. */
|
|
|
|
|
CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */
|
|
|
|
|
Tcl_Obj *objPtr; /* If non-NULL, indicates the single
|
|
|
|
|
* option whose value is to be
|
|
|
|
|
* returned. Otherwise
|
|
|
|
|
* information is returned for
|
|
|
|
|
* all options. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
int i, index, start, end, num;
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
int bool;
|
|
|
|
|
#endif
|
|
|
|
|
char *str;
|
|
|
|
|
Tcl_Obj *newPtr;
|
|
|
|
|
|
|
|
|
|
start = 0;
|
|
|
|
|
end = FONT_NUMFIELDS;
|
|
|
|
|
if (objPtr != NULL) {
|
1998-09-30 07:11:02 -04:00
|
|
|
|
if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", 1,
|
1998-04-10 06:59:06 -04:00
|
|
|
|
&index) != TCL_OK) {
|
1998-09-30 07:11:02 -04:00
|
|
|
|
return TCL_ERROR;
|
1998-04-10 06:59:06 -04:00
|
|
|
|
}
|
|
|
|
|
start = index;
|
|
|
|
|
end = index + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = start; i < end; i++) {
|
|
|
|
|
str = NULL;
|
|
|
|
|
num = 0; /* Needed only to prevent compiler
|
|
|
|
|
* warning. */
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
bool =-1;
|
|
|
|
|
#endif
|
|
|
|
|
switch (i) {
|
|
|
|
|
case FONT_FAMILY:
|
|
|
|
|
str = faPtr->family;
|
|
|
|
|
if (str == NULL) {
|
|
|
|
|
str = "";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_SIZE:
|
|
|
|
|
num = faPtr->pointsize;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_WEIGHT:
|
|
|
|
|
str = TkFindStateString(weightMap, faPtr->weight);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_SLANT:
|
|
|
|
|
str = TkFindStateString(slantMap, faPtr->slant);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_UNDERLINE:
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
bool = faPtr->underline;
|
|
|
|
|
#else
|
|
|
|
|
num = faPtr->underline;
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FONT_OVERSTRIKE:
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
bool = faPtr->overstrike;
|
|
|
|
|
#else
|
|
|
|
|
num = faPtr->overstrike;
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (objPtr == NULL) {
|
|
|
|
|
Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp),
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-04-10 06:59:06 -04:00
|
|
|
|
STk_NewKeywordObj(fontOpt[i]));
|
|
|
|
|
#else
|
|
|
|
|
Tcl_NewStringObj(fontOpt[i], -1));
|
|
|
|
|
#endif
|
|
|
|
|
if (str != NULL) {
|
|
|
|
|
newPtr = Tcl_NewStringObj(str, -1);
|
|
|
|
|
} else {
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-09-30 07:11:02 -04:00
|
|
|
|
newPtr = (bool < 0) ? Tcl_NewIntObj(num) : Tcl_NewBooleanObj(bool);
|
1998-04-10 06:59:06 -04:00
|
|
|
|
#else
|
|
|
|
|
newPtr = Tcl_NewIntObj(num);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp),
|
|
|
|
|
newPtr);
|
|
|
|
|
} else {
|
|
|
|
|
if (str != NULL) {
|
|
|
|
|
Tcl_SetStringObj(Tcl_GetObjResult(interp), str, -1);
|
|
|
|
|
} else {
|
1999-09-05 07:16:41 -04:00
|
|
|
|
#ifdef SCM_CODE
|
1998-09-30 07:11:02 -04:00
|
|
|
|
if (bool >= 0)
|
|
|
|
|
Tcl_SetBooleanObj(Tcl_GetObjResult(interp), bool);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_SetIntObj(Tcl_GetObjResult(interp), num);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-09-30 07:11:02 -04:00
|
|
|
|
return TCL_OK;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* ParseFontNameObj --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Converts a object into a set of font attributes that can be used
|
|
|
|
|
* to construct a font.
|
|
|
|
|
*
|
|
|
|
|
* The string rep of the object can be one of the following forms:
|
|
|
|
|
* XLFD (see X documentation)
|
|
|
|
|
* "Family [size [style] [style ...]]"
|
|
|
|
|
* "-option value [-option value ...]"
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The return value is TCL_ERROR if the object was syntactically
|
|
|
|
|
* invalid. In that case an error message is left in interp's
|
|
|
|
|
* result object. Otherwise, fills the font attribute buffer with
|
|
|
|
|
* the values parsed from the string and returns TCL_OK;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* None.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static int
|
|
|
|
|
ParseFontNameObj(interp, tkwin, objPtr, faPtr)
|
|
|
|
|
Tcl_Interp *interp; /* Interp for error return. */
|
|
|
|
|
Tk_Window tkwin; /* For display on which font is used. */
|
|
|
|
|
Tcl_Obj *objPtr; /* Parseable font description object. */
|
|
|
|
|
TkFontAttributes *faPtr; /* Font attributes structure whose fields
|
|
|
|
|
* are to be modified. Structure must already
|
|
|
|
|
* be properly initialized. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
char *dash;
|
|
|
|
|
int objc, result, i, n;
|
|
|
|
|
Tcl_Obj **objv;
|
|
|
|
|
TkXLFDAttributes xa;
|
|
|
|
|
char *string;
|
|
|
|
|
|
|
|
|
|
string = Tcl_GetStringFromObj(objPtr, NULL);
|
|
|
|
|
if (*string == '-') {
|
|
|
|
|
/*
|
|
|
|
|
* This may be an XLFD or an "-option value" string.
|
|
|
|
|
*
|
|
|
|
|
* If the string begins with "-*" or a "-foundry-family-*" pattern,
|
|
|
|
|
* then consider it an XLFD.
|
|
|
|
|
*/
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (string[1] == '*') {
|
|
|
|
|
goto xlfd;
|
|
|
|
|
}
|
|
|
|
|
dash = strchr(string + 1, '-');
|
|
|
|
|
if ((dash != NULL) && (!isspace(UCHAR(dash[-1])))) {
|
|
|
|
|
goto xlfd;
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*string == '*') {
|
|
|
|
|
/*
|
|
|
|
|
* This appears to be an XLFD.
|
|
|
|
|
*/
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
xlfd:
|
|
|
|
|
xa.fa = *faPtr;
|
|
|
|
|
result = TkParseXLFD(string, &xa);
|
|
|
|
|
if (result == TCL_OK) {
|
|
|
|
|
*faPtr = xa.fa;
|
|
|
|
|
return result;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Wasn't an XLFD or "-option value" string. Try it as a
|
|
|
|
|
* "font size style" list.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (objc < 1) {
|
|
|
|
|
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "font \"", string,
|
|
|
|
|
"\" doesn't exist", (char *) NULL);
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
faPtr->family = Tk_GetUid(Tcl_GetStringFromObj(objv[0], NULL));
|
|
|
|
|
if (objc > 1) {
|
|
|
|
|
if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
faPtr->pointsize = n;
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
i = 2;
|
|
|
|
|
if (objc == 3) {
|
|
|
|
|
if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
i = 0;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
for ( ; i < objc; i++) {
|
|
|
|
|
string = Tcl_GetStringFromObj(objv[i], NULL);
|
|
|
|
|
n = TkFindStateNum(NULL, NULL, weightMap, string);
|
|
|
|
|
if (n != TK_FW_UNKNOWN) {
|
|
|
|
|
faPtr->weight = n;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
n = TkFindStateNum(NULL, NULL, slantMap, string);
|
|
|
|
|
if (n != TK_FS_UNKNOWN) {
|
|
|
|
|
faPtr->slant = n;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
n = TkFindStateNum(NULL, NULL, underlineMap, string);
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
faPtr->underline = n;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
n = TkFindStateNum(NULL, NULL, overstrikeMap, string);
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
faPtr->overstrike = n;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/*
|
|
|
|
|
* Unknown style.
|
|
|
|
|
*/
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
|
|
|
|
|
"unknown font style \"", string, "\"",
|
|
|
|
|
(char *) NULL);
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
return TCL_OK;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* TkParseXLFD --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Break up a fully specified XLFD into a set of font attributes.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Return value is TCL_ERROR if string was not a fully specified XLFD.
|
|
|
|
|
* Otherwise, fills font attribute buffer with the values parsed
|
|
|
|
|
* from the XLFD and returns TCL_OK.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
1998-04-10 06:59:06 -04:00
|
|
|
|
TkParseXLFD(string, xaPtr)
|
|
|
|
|
CONST char *string; /* Parseable font description string. */
|
|
|
|
|
TkXLFDAttributes *xaPtr; /* XLFD attributes structure whose fields
|
|
|
|
|
* are to be modified. Structure must already
|
|
|
|
|
* be properly initialized. */
|
|
|
|
|
{
|
|
|
|
|
char *src;
|
|
|
|
|
CONST char *str;
|
|
|
|
|
int i, j;
|
|
|
|
|
char *field[XLFD_NUMFIELDS + 2];
|
|
|
|
|
Tcl_DString ds;
|
|
|
|
|
|
|
|
|
|
memset(field, '\0', sizeof(field));
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
str = string;
|
|
|
|
|
if (*str == '-') {
|
|
|
|
|
str++;
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_DStringInit(&ds);
|
|
|
|
|
Tcl_DStringAppend(&ds, (char *) str, -1);
|
|
|
|
|
src = Tcl_DStringValue(&ds);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
field[0] = src;
|
|
|
|
|
for (i = 0; *src != '\0'; src++) {
|
|
|
|
|
if (isupper(UCHAR(*src))) {
|
|
|
|
|
*src = tolower(UCHAR(*src));
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (*src == '-') {
|
|
|
|
|
i++;
|
|
|
|
|
if (i > XLFD_NUMFIELDS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*src = '\0';
|
|
|
|
|
field[i] = src + 1;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
|
|
|
|
|
* but it is (strictly) malformed, because the first * is eliding both
|
|
|
|
|
* the Setwidth and the Addstyle fields. If the Addstyle field is a
|
|
|
|
|
* number, then assume the above incorrect form was used and shift all
|
|
|
|
|
* the rest of the fields up by one, so the number gets interpreted
|
|
|
|
|
* as a pixelsize. This fix is so that we don't get a million reports
|
|
|
|
|
* that "it works under X, but gives a syntax error under Windows".
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
|
|
|
|
|
if (atoi(field[XLFD_ADD_STYLE]) != 0) {
|
|
|
|
|
for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
|
|
|
|
|
field[j + 1] = field[j];
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
field[XLFD_ADD_STYLE] = NULL;
|
|
|
|
|
i++;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Bail if we don't have enough of the fields (up to pointsize).
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (i < XLFD_FAMILY) {
|
|
|
|
|
Tcl_DStringFree(&ds);
|
|
|
|
|
return TCL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FieldSpecified(field[XLFD_FOUNDRY])) {
|
|
|
|
|
xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FieldSpecified(field[XLFD_FAMILY])) {
|
|
|
|
|
xaPtr->fa.family = Tk_GetUid(field[XLFD_FAMILY]);
|
|
|
|
|
}
|
|
|
|
|
if (FieldSpecified(field[XLFD_WEIGHT])) {
|
|
|
|
|
xaPtr->fa.weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,
|
|
|
|
|
field[XLFD_WEIGHT]);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (FieldSpecified(field[XLFD_SLANT])) {
|
|
|
|
|
xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,
|
|
|
|
|
field[XLFD_SLANT]);
|
|
|
|
|
if (xaPtr->slant == TK_FS_ROMAN) {
|
|
|
|
|
xaPtr->fa.slant = TK_FS_ROMAN;
|
|
|
|
|
} else {
|
|
|
|
|
xaPtr->fa.slant = TK_FS_ITALIC;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (FieldSpecified(field[XLFD_SETWIDTH])) {
|
|
|
|
|
xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,
|
|
|
|
|
field[XLFD_SETWIDTH]);
|
|
|
|
|
}
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/* XLFD_ADD_STYLE ignored. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Pointsize in tenths of a point, but treat it as tenths of a pixel.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (FieldSpecified(field[XLFD_POINT_SIZE])) {
|
|
|
|
|
if (field[XLFD_POINT_SIZE][0] == '[') {
|
|
|
|
|
/*
|
|
|
|
|
* Some X fonts have the point size specified as follows:
|
|
|
|
|
*
|
|
|
|
|
* [ N1 N2 N3 N4 ]
|
|
|
|
|
*
|
|
|
|
|
* where N1 is the point size (in points, not decipoints!), and
|
|
|
|
|
* N2, N3, and N4 are some additional numbers that I don't know
|
|
|
|
|
* the purpose of, so I ignore them.
|
|
|
|
|
*/
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
xaPtr->fa.pointsize = atoi(field[XLFD_POINT_SIZE] + 1);
|
|
|
|
|
} else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],
|
|
|
|
|
&xaPtr->fa.pointsize) == TCL_OK) {
|
|
|
|
|
xaPtr->fa.pointsize /= 10;
|
|
|
|
|
} else {
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Pixel height of font. If specified, overrides pointsize.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
|
|
|
|
|
if (field[XLFD_PIXEL_SIZE][0] == '[') {
|
|
|
|
|
/*
|
|
|
|
|
* Some X fonts have the pixel size specified as follows:
|
|
|
|
|
*
|
|
|
|
|
* [ N1 N2 N3 N4 ]
|
|
|
|
|
*
|
|
|
|
|
* where N1 is the pixel size, and where N2, N3, and N4
|
|
|
|
|
* are some additional numbers that I don't know
|
|
|
|
|
* the purpose of, so I ignore them.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
xaPtr->fa.pointsize = atoi(field[XLFD_PIXEL_SIZE] + 1);
|
|
|
|
|
} else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],
|
|
|
|
|
&xaPtr->fa.pointsize) != TCL_OK) {
|
|
|
|
|
return TCL_ERROR;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
xaPtr->fa.pointsize = -xaPtr->fa.pointsize;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/* XLFD_RESOLUTION_X ignored. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/* XLFD_RESOLUTION_Y ignored. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/* XLFD_SPACING ignored. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
/* XLFD_AVERAGE_WIDTH ignored. */
|
|
|
|
|
|
|
|
|
|
if (FieldSpecified(field[XLFD_REGISTRY])) {
|
|
|
|
|
xaPtr->charset = TkFindStateNum(NULL, NULL, xlfdCharsetMap,
|
|
|
|
|
field[XLFD_REGISTRY]);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (FieldSpecified(field[XLFD_ENCODING])) {
|
|
|
|
|
xaPtr->encoding = atoi(field[XLFD_ENCODING]);
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
Tcl_DStringFree(&ds);
|
|
|
|
|
return TCL_OK;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* FieldSpecified --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Helper function for TkParseXLFD(). Determines if a field in the
|
|
|
|
|
* XLFD was set to a non-null, non-don't-care value.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The return value is 0 if the field in the XLFD was not set and
|
|
|
|
|
* should be ignored, non-zero otherwise.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static int
|
|
|
|
|
FieldSpecified(field)
|
|
|
|
|
CONST char *field; /* The field of the XLFD to check. Strictly
|
|
|
|
|
* speaking, only when the string is "*" does it mean
|
|
|
|
|
* don't-care. However, an unspecified or question
|
|
|
|
|
* mark is also interpreted as don't-care. */
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
char ch;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
|
1998-04-10 06:59:06 -04:00
|
|
|
|
if (field == NULL) {
|
|
|
|
|
return 0;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
ch = field[0];
|
|
|
|
|
return (ch != '*' && ch != '?');
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* NewChunk --
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Helper function for Tk_ComputeTextLayout(). Encapsulates a
|
|
|
|
|
* measured set of characters in a chunk that can be quickly
|
|
|
|
|
* drawn.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Results:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* A pointer to the new chunk in the text layout.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* The text layout is reallocated to hold more chunks as necessary.
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*
|
1998-04-10 06:59:06 -04:00
|
|
|
|
* Currently, Tk_ComputeTextLayout() stores contiguous ranges of
|
|
|
|
|
* "normal" characters in a chunk, along with individual tab
|
|
|
|
|
* and newline chars in their own chunks. All characters in the
|
|
|
|
|
* text layout are accounted for.
|
|
|
|
|
*
|
|
|
|
|
*---------------------------------------------------------------------------
|
1996-09-27 06:29:02 -04:00
|
|
|
|
*/
|
1998-04-10 06:59:06 -04:00
|
|
|
|
static LayoutChunk *
|
|
|
|
|
NewChunk(layoutPtrPtr, maxPtr, start, numChars, curX, newX, y)
|
|
|
|
|
TextLayout **layoutPtrPtr;
|
|
|
|
|
int *maxPtr;
|
|
|
|
|
CONST char *start;
|
|
|
|
|
int numChars;
|
|
|
|
|
int curX;
|
|
|
|
|
int newX;
|
|
|
|
|
int y;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
{
|
1998-04-10 06:59:06 -04:00
|
|
|
|
TextLayout *layoutPtr;
|
|
|
|
|
LayoutChunk *chunkPtr;
|
|
|
|
|
int maxChunks;
|
|
|
|
|
size_t s;
|
|
|
|
|
|
|
|
|
|
layoutPtr = *layoutPtrPtr;
|
|
|
|
|
maxChunks = *maxPtr;
|
|
|
|
|
if (layoutPtr->numChunks == maxChunks) {
|
|
|
|
|
maxChunks *= 2;
|
|
|
|
|
s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));
|
|
|
|
|
layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);
|
|
|
|
|
|
|
|
|
|
*layoutPtrPtr = layoutPtr;
|
|
|
|
|
*maxPtr = maxChunks;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|
1998-04-10 06:59:06 -04:00
|
|
|
|
chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];
|
|
|
|
|
chunkPtr->start = start;
|
|
|
|
|
chunkPtr->numChars = numChars;
|
|
|
|
|
chunkPtr->numDisplayChars = numChars;
|
|
|
|
|
chunkPtr->x = curX;
|
|
|
|
|
chunkPtr->y = y;
|
|
|
|
|
chunkPtr->totalWidth = newX - curX;
|
|
|
|
|
chunkPtr->displayWidth = newX - curX;
|
|
|
|
|
layoutPtr->numChunks++;
|
|
|
|
|
|
|
|
|
|
return chunkPtr;
|
1996-09-27 06:29:02 -04:00
|
|
|
|
}
|