diff options
44 files changed, 10933 insertions, 1907 deletions
diff --git a/generic/tk.decls b/generic/tk.decls index 6f8eb13..db8314a 100644 --- a/generic/tk.decls +++ b/generic/tk.decls @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tk.decls,v 1.4 1999/04/28 18:18:06 redman Exp $ +# RCS: @(#) $Id: tk.decls,v 1.5 1999/12/14 06:52:24 hobbs Exp $ library tk @@ -1040,6 +1040,18 @@ declare 216 generic { int Tk_CreateConsoleWindow(Tcl_Interp *interp) } +declare 217 generic { + void Tk_CreateSmoothMethod(Tcl_Interp *interp, Tk_SmoothMethod *method) +} + +#declare 218 generic { +# void Tk_CreateCanvasVisitor(Tcl_Interp *interp, VOID *typePtr) +#} + +#declare 219 generic { +# VOID *Tk_GetCanvasVisitor(Tcl_Interp *interp, CONST char *name) +#} + # Define the platform specific public Tk interface. These functions are # only available on the designated platform. diff --git a/generic/tk.h b/generic/tk.h index 552611f..1217e26 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tk.h,v 1.33 1999/11/23 23:52:13 hobbs Exp $ + * RCS: @(#) $Id: tk.h,v 1.34 1999/12/14 06:52:25 hobbs Exp $ */ #ifndef _TK @@ -110,6 +110,7 @@ typedef struct Tk_Font_ *Tk_Font; typedef struct Tk_Image__ *Tk_Image; typedef struct Tk_ImageMaster_ *Tk_ImageMaster; typedef struct Tk_OptionTable_ *Tk_OptionTable; +typedef struct Tk_PostscriptInfo_ *Tk_PostscriptInfo; typedef struct Tk_TextLayout_ *Tk_TextLayout; typedef struct Tk_Window_ *Tk_Window; typedef struct Tk_3DBorder_ *Tk_3DBorder; @@ -348,6 +349,7 @@ typedef enum { */ #define TK_CONFIG_ARGV_ONLY 1 +#define TK_CONFIG_OBJS 0x80 /* * Possible flag values for Tk_ConfigSpec structures. Any bits at @@ -771,6 +773,21 @@ typedef struct Tk_FakeWin { *-------------------------------------------------------------- */ +typedef enum { + TK_STATE_NULL = -1, TK_STATE_ACTIVE, TK_STATE_DISABLED, + TK_STATE_NORMAL, TK_STATE_HIDDEN +} Tk_State; + +typedef struct Tk_SmoothMethod { + char *name; + int (*coordProc) _ANSI_ARGS_((Tk_Canvas canvas, + double *pointPtr, int numPoints, int numSteps, + XPoint xPoints[], double dblPoints[])); + void (*postscriptProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, double *coordPtr, + int numPoints, int numSteps)); +} Tk_SmoothMethod; + /* * For each item in a canvas widget there exists one record with * the following structure. Each actual item is represented by @@ -810,9 +827,9 @@ typedef struct Tk_Item { * items in this canvas. Later items * in list are drawn just below earlier * ones. */ - int reserved1; /* This padding is for compatibility */ - char *reserved2; /* with Jan Nijtmans dash patch */ - int reserved3; + Tk_State state; /* state of item */ + char *reserved1; /* reserved for future use */ + int redraw_flags; /* some flags used in the canvas */ /* *------------------------------------------------------------------ @@ -825,11 +842,25 @@ typedef struct Tk_Item { } Tk_Item; /* + * Flag bits for canvases (redraw_flags): + * + * TK_ITEM_STATE_DEPENDANT - 1 means that object needs to be + * redrawn if the canvas state changes. + * TK_ITEM_DONT_REDRAW - 1 means that the object redraw is already + * been prepared, so the general canvas code + * doesn't need to do that any more. + */ + +#define TK_ITEM_STATE_DEPENDANT 1 +#define TK_ITEM_DONT_REDRAW 2 + +/* * Records of the following type are used to describe a type of * item (e.g. lines, circles, etc.) that can form part of a * canvas widget. */ +#ifdef USE_OLD_CANVAS typedef int Tk_ItemCreateProc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv)); @@ -839,6 +870,17 @@ typedef int Tk_ItemConfigureProc _ANSI_ARGS_((Tcl_Interp *interp, typedef int Tk_ItemCoordProc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv)); +#else +typedef int Tk_ItemCreateProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST objv[])); +typedef int Tk_ItemConfigureProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST objv[], int flags)); +typedef int Tk_ItemCoordProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST argv[])); +#endif typedef void Tk_ItemDeleteProc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); typedef void Tk_ItemDisplayProc _ANSI_ARGS_((Tk_Canvas canvas, @@ -890,7 +932,7 @@ typedef struct Tk_ItemType { * this type. */ int alwaysRedraw; /* Non-zero means displayProc should * be called even when the item has - * been moved off-screen. */ + * been moved off-screen. */ Tk_ItemPointProc *pointProc; /* Computes distance from item to * a given point. */ Tk_ItemAreaProc *areaProc; /* Computes whether item is inside, @@ -971,6 +1013,80 @@ typedef struct Tk_CanvasTextInfo { } Tk_CanvasTextInfo; /* + * Structures used for Dashing and Outline. + */ + +typedef struct Tk_Dash { + int number; + union { + char *pt; + char array[sizeof(char *)]; + } pattern; +} Tk_Dash; + +typedef struct Tk_TSOffset { + int flags; /* flags; see below for possible values */ + int xoffset; /* x offset */ + int yoffset; /* y offset */ +} Tk_TSOffset; + +/* + * Bit fields in Tk_Offset->flags: + */ + +#define TK_OFFSET_INDEX 1 +#define TK_OFFSET_RELATIVE 2 +#define TK_OFFSET_LEFT 4 +#define TK_OFFSET_CENTER 8 +#define TK_OFFSET_RIGHT 16 +#define TK_OFFSET_TOP 32 +#define TK_OFFSET_MIDDLE 64 +#define TK_OFFSET_BOTTOM 128 + +typedef struct Tk_Outline { + GC gc; /* Graphics context. */ + double width; /* Width of outline. */ + double activeWidth; /* Width of outline. */ + double disabledWidth; /* Width of outline. */ + int offset; /* Dash offset */ + Tk_Dash dash; /* Dash pattern */ + Tk_Dash activeDash; /* Dash pattern if state is active*/ + Tk_Dash disabledDash; /* Dash pattern if state is disabled*/ + VOID *reserved1; /* reserved for future expansion */ + VOID *reserved2; + VOID *reserved3; + Tk_TSOffset tsoffset; /* stipple offset for outline*/ + XColor *color; /* Outline color. */ + XColor *activeColor; /* Outline color if state is active. */ + XColor *disabledColor; /* Outline color if state is disabled. */ + Pixmap stipple; /* Outline Stipple pattern. */ + Pixmap activeStipple; /* Outline Stipple pattern if state is active. */ + Pixmap disabledStipple; /* Outline Stipple pattern if state is disabled. */ +} Tk_Outline; + +/* + * Some functions handy for Dashing and Outlines (in tkCanvUtil.c). + */ + +EXTERN int Tk_GetDash _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *value, Tk_Dash *dash)); +EXTERN void Tk_CreateOutline _ANSI_ARGS_((Tk_Outline *outline)); +EXTERN void Tk_DeleteOutline _ANSI_ARGS_((Display *display, + Tk_Outline *outline)); +EXTERN int Tk_ConfigOutlineGC _ANSI_ARGS_((XGCValues *gcValues, + Tk_Canvas canvas ,Tk_Item *item, + Tk_Outline *outline)); +EXTERN int Tk_ChangeOutlineGC _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *item, Tk_Outline *outline)); +EXTERN int Tk_ResetOutlineGC _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *item, Tk_Outline *outline)); +EXTERN int Tk_CanvasPsOutline _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *item, Tk_Outline *outline)); +EXTERN void Tk_SetTSOrigin _ANSI_ARGS_((Tk_Window tkwin, GC gc, int x, + int y)); + + +/* *-------------------------------------------------------------- * * Procedure prototypes and structures used for managing images: @@ -999,6 +1115,9 @@ typedef void (Tk_ImageDeleteProc) _ANSI_ARGS_((ClientData masterData)); typedef void (Tk_ImageChangedProc) _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, int imageWidth, int imageHeight)); +typedef int (Tk_ImagePostscriptProc) _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psinfo, + int x, int y, int width, int height, int prepass)); /* * The following structure represents a particular type of image @@ -1028,6 +1147,9 @@ struct Tk_ImageType { * will not be called until after freeProc * has been called for each instance of the * image. */ + Tk_ImagePostscriptProc *postscriptProc; + /* Procedure to call to produce postscript + * output for the image. */ struct Tk_ImageType *nextPtr; /* Next in list of all image types currently * known. Filled in by Tk, not by image @@ -1240,6 +1362,44 @@ typedef int (Tk_SelectionProc) _ANSI_ARGS_((ClientData clientData, /* *-------------------------------------------------------------- * + * Exported procedures introduced by dash-patch. + * + *-------------------------------------------------------------- + */ + +EXTERN int Tk_CanvasGetCoordFromObj _ANSI_ARGS_(( + Tcl_Interp *interp, Tk_Canvas canvas, Tcl_Obj *obj, + double *doublePtr)); +EXTERN void Tk_CanvasSetOffset _ANSI_ARGS_(( + Tk_Canvas canvas, GC gc, Tk_TSOffset *offset)); +EXTERN void Tk_CreatePhotoOption _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *name, Tcl_ObjCmdProc *proc)); +EXTERN void Tk_DitherPhoto _ANSI_ARGS_((Tk_PhotoHandle handle, + int x, int y, int width, int height)); +EXTERN int Tk_PostscriptBitmap _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + Pixmap bitmap, int startX, int startY, + int width, int height)); +EXTERN int Tk_PostscriptColor _ANSI_ARGS_((Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, XColor *colorPtr)); +EXTERN int Tk_PostscriptFont _ANSI_ARGS_((Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, Tk_Font font)); +EXTERN int Tk_PostscriptImage _ANSI_ARGS_((Tk_Image image, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass)); +EXTERN void Tk_PostscriptPath _ANSI_ARGS_((Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, double *coordPtr, + int numPoints)); +EXTERN int Tk_PostscriptStipple _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + Pixmap bitmap)); +EXTERN double Tk_PostscriptY _ANSI_ARGS_((double y, + Tk_PostscriptInfo psInfo)); + +/* + *-------------------------------------------------------------- + * * Exported procedures and variables. * *-------------------------------------------------------------- diff --git a/generic/tkBind.c b/generic/tkBind.c index 192ea69..031ded7 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkBind.c,v 1.8 1999/04/21 21:53:23 rjohnson Exp $ + * RCS: @(#) $Id: tkBind.c,v 1.9 1999/12/14 06:52:25 hobbs Exp $ */ #include "tkPort.h" @@ -403,10 +403,15 @@ typedef struct { * e.g. for double-clicks. * TRIPLE - Non-zero means triplicate this event, * e.g. for triple-clicks. + * QUADRUPLE - Non-zero means quadruple this event, + * e.g. for 4-fold-clicks. + * MULT_CLICKS - Combination of all of above. */ #define DOUBLE 1 #define TRIPLE 2 +#define QUADRUPLE 4 +#define MULT_CLICKS 7 /* * The following special modifier mask bits are defined, to indicate @@ -448,6 +453,7 @@ static ModInfo modArray[] = { {"M5", Mod5Mask, 0}, {"Double", 0, DOUBLE}, {"Triple", 0, TRIPLE}, + {"Quadruple", 0, QUADRUPLE}, {"Any", 0, 0}, /* Ignored: historical relic. */ {NULL, 0, 0} }; @@ -685,6 +691,7 @@ static int ParseEventDescription _ANSI_ARGS_((Tcl_Interp *interp, unsigned long *eventMaskPtr)); static void SetKeycodeAndState _ANSI_ARGS_((Tk_Window tkwin, KeySym keySym, XEvent *eventPtr)); +static void DoWarp _ANSI_ARGS_((ClientData clientData)); /* * The following define is used as a short circuit for the callback @@ -3170,8 +3177,8 @@ HandleEventGenerate(interp, mainWin, objc, objv) Tcl_Obj *CONST objv[]; /* Argument objects. */ { XEvent event; - char *name, *p; - int count, flags, synch, i, number; + char *name, *p, *windowName; + int count, flags, synch, i, number, warp; Tcl_QueuePosition pos; Pattern pat; Tk_Window tkwin, tkwin2; @@ -3184,8 +3191,8 @@ HandleEventGenerate(interp, mainWin, objc, objv) "-keycode", "-keysym", "-mode", "-override", "-place", "-root", "-rootx", "-rooty", "-sendevent", "-serial", "-state", "-subwindow", - "-time", "-width", "-window", "-x", - "-y", NULL + "-time", "-warp", "-width", "-window", + "-x", "-y", NULL }; enum field { EVENT_WHEN, EVENT_ABOVE, EVENT_BORDER, EVENT_BUTTON, @@ -3194,11 +3201,14 @@ HandleEventGenerate(interp, mainWin, objc, objv) EVENT_KEYCODE, EVENT_KEYSYM, EVENT_MODE, EVENT_OVERRIDE, EVENT_PLACE, EVENT_ROOT, EVENT_ROOTX, EVENT_ROOTY, EVENT_SEND, EVENT_SERIAL, EVENT_STATE, EVENT_SUBWINDOW, - EVENT_TIME, EVENT_WIDTH, EVENT_WINDOW, EVENT_X, - EVENT_Y + EVENT_TIME, EVENT_WARP, EVENT_WIDTH, EVENT_WINDOW, + EVENT_X, EVENT_Y }; - if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) { + windowName = Tcl_GetStringFromObj(objv[0], NULL); + if (!windowName[0]) { + tkwin = mainWin; + } else if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) { return TCL_ERROR; } @@ -3236,7 +3246,11 @@ HandleEventGenerate(interp, mainWin, objc, objv) event.xany.type = pat.eventType; event.xany.serial = NextRequest(Tk_Display(tkwin)); event.xany.send_event = False; - event.xany.window = Tk_WindowId(tkwin); + if (windowName[0]) { + event.xany.window = Tk_WindowId(tkwin); + } else { + event.xany.window = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); + } event.xany.display = Tk_Display(tkwin); flags = flagArray[event.xany.type]; @@ -3260,6 +3274,7 @@ HandleEventGenerate(interp, mainWin, objc, objv) */ synch = 1; + warp = 0; pos = TCL_QUEUE_TAIL; for (i = 2; i < objc; i += 2) { Tcl_Obj *optionPtr, *valuePtr; @@ -3287,6 +3302,15 @@ HandleEventGenerate(interp, mainWin, objc, objv) } switch ((enum field) index) { + case EVENT_WARP: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) { + return TCL_ERROR; + } + if (!(flags & (KEY_BUTTON_MOTION_VIRTUAL))) { + goto badopt; + } + break; + } case EVENT_WHEN: { pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, queuePosition, valuePtr); @@ -3667,6 +3691,17 @@ HandleEventGenerate(interp, mainWin, objc, objv) } else { Tk_QueueWindowEvent(&event, pos); } + if (warp != 0) { + TkDisplay *dispPtr; + dispPtr = TkGetDisplay(event.xmotion.display); + if (!dispPtr->warpInProgress) { + Tcl_DoWhenIdle(DoWarp, (ClientData) dispPtr); + dispPtr->warpInProgress = 1; + } + dispPtr->warpWindow = event.xany.window; + dispPtr->warpX = event.xkey.x; + dispPtr->warpY = event.xkey.y; + } Tcl_ResetResult(interp); return TCL_OK; @@ -3747,6 +3782,33 @@ SetKeycodeAndState(tkwin, keySym, eventPtr) /* *------------------------------------------------------------------------- * + * DoWarp -- + * + * Perform Warping of X pointer. Executed as an idle handler only. + * + * Results: + * None + * + * Side effects: + * X Pointer will move to a new location. + * + *------------------------------------------------------------------------- + */ +static void +DoWarp(clientData) + ClientData clientData; +{ + TkDisplay *dispPtr = (TkDisplay *) clientData; + + XWarpPointer(dispPtr->display, (Window) None, (Window) dispPtr->warpWindow, + 0, 0, 0, 0, (int) dispPtr->warpX, (int) dispPtr->warpY); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + dispPtr->warpInProgress = 0; +} + +/* + *------------------------------------------------------------------------- + * * GetVirtualEventUid -- * * Determine if the given string is in the proper format for a @@ -3886,19 +3948,14 @@ FindSequence(interp, patternTablePtr, object, eventString, create, } /* - * Replicate events for DOUBLE and TRIPLE. + * Replicate events for DOUBLE, TRIPLE, QUADRUPLE. */ - if ((count > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { + while ((count-- > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { flags |= PAT_NEARBY; patPtr[-1] = patPtr[0]; patPtr--; numPats++; - if ((count == 3) && (numPats < EVENT_BUFFER_SIZE-1)) { - patPtr[-1] = patPtr[0]; - patPtr--; - numPats++; - } } } @@ -4117,12 +4174,10 @@ ParseEventDescription(interp, eventStringPtr, patPtr, } modPtr = (ModInfo *) Tcl_GetHashValue(hPtr); patPtr->needMods |= modPtr->mask; - if (modPtr->flags & (DOUBLE|TRIPLE)) { - if (modPtr->flags & DOUBLE) { - count = 2; - } else { - count = 3; - } + if (modPtr->flags & (MULT_CLICKS)) { + int i = modPtr->flags & MULT_CLICKS; + count = 2; + while (i >>= 1) count++; } while ((*p == '-') || isspace(UCHAR(*p))) { p++; @@ -4310,8 +4365,8 @@ GetPatternString(psPtr, dsPtr) /* * It's a more general event specification. First check - * for "Double" or "Triple", then modifiers, then event type, - * then keysym or button detail. + * for "Double", "Triple", "Quadruple", then modifiers, + * then event type, then keysym or button detail. */ Tcl_DStringAppend(dsPtr, "<", 1); @@ -4324,7 +4379,14 @@ GetPatternString(psPtr, dsPtr) (char *) (patPtr-1), sizeof(Pattern)) == 0)) { patsLeft--; patPtr--; - Tcl_DStringAppend(dsPtr, "Triple-", 7); + if ((patsLeft > 1) && (memcmp((char *) patPtr, + (char *) (patPtr-1), sizeof(Pattern)) == 0)) { + patsLeft--; + patPtr--; + Tcl_DStringAppend(dsPtr, "Quadruple-", 10); + } else { + Tcl_DStringAppend(dsPtr, "Triple-", 7); + } } else { Tcl_DStringAppend(dsPtr, "Double-", 7); } diff --git a/generic/tkCanvArc.c b/generic/tkCanvArc.c index 1848c88..1d0934e 100644 --- a/generic/tkCanvArc.c +++ b/generic/tkCanvArc.c @@ -9,20 +9,25 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvArc.c,v 1.6 1999/04/21 21:53:24 rjohnson Exp $ + * RCS: @(#) $Id: tkCanvArc.c,v 1.7 1999/12/14 06:52:25 hobbs Exp $ */ #include <stdio.h> #include "tkPort.h" #include "tkInt.h" - +#include "tkCanvas.h" /* * The structure below defines the record for each arc item. */ +typedef enum { + PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE +} Style; + typedef struct ArcItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ double bbox[4]; /* Coordinates (x1, y1, x2, y2) of bounding * box for oval of which arc is a piece. */ double start; /* Angle at which arc begins, in degrees @@ -38,16 +43,22 @@ typedef struct ArcItem { * for a chord). Malloc'ed. */ int numOutlinePoints; /* Number of points at outlinePtr. Zero * means no space allocated. */ - int width; /* Width of outline (in pixels). */ - XColor *outlineColor; /* Color for outline. NULL means don't - * draw outline. */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Color for filling arc (used for drawing * outline too when style is "arc"). NULL * means don't fill arc. */ + XColor *activeFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "active"). NULL means use fillColor. */ + XColor *disabledFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "disabled". NULL means use fillColor */ Pixmap fillStipple; /* Stipple bitmap for filling item. */ - Pixmap outlineStipple; /* Stipple bitmap for outline. */ - Tk_Uid style; /* How to draw arc: arc, chord, or pieslice. */ - GC outlineGC; /* Graphics context for outline. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state + * is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state + * is disabled. */ + Style style; /* How to draw arc: arc, chord, or pieslice. */ GC fillGC; /* Graphics context for filling item. */ double center1[2]; /* Coordinates of center of arc outline at * start (see ComputeArcOutline). */ @@ -68,29 +79,112 @@ typedef struct ArcItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static int StyleParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +static char * StylePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption styleOption = { + (Tk_OptionParseProc *) StyleParseProc, + StylePrintProc, (ClientData) NULL +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(ArcItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(ArcItem, outline.offset), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(ArcItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL, "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(ArcItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(ArcItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(ArcItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ArcItem, outlineStipple), TK_CONFIG_NULL_OK}, + (char *) NULL, Tk_Offset(ArcItem, outline.stipple), + TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL, "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL, - "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-style", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT, + &styleOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(ArcItem, outline.width), TK_CONFIG_DONT_SET_DEFAULT, + &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -103,10 +197,10 @@ static void ComputeArcBbox _ANSI_ARGS_((Tk_Canvas canvas, ArcItem *arcPtr)); static int ConfigureArc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateArc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteArc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayArc _ANSI_ARGS_((Tk_Canvas canvas, @@ -114,7 +208,7 @@ static void DisplayArc _ANSI_ARGS_((Tk_Canvas canvas, int x, int y, int width, int height)); static int ArcCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int ArcToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double ArcToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -128,7 +222,8 @@ static void TranslateArc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY)); static int AngleInRange _ANSI_ARGS_((double x, double y, double start, double extent)); -static void ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr)); +static void ComputeArcOutline _ANSI_ARGS_((Tk_Canvas canvas, + ArcItem *arcPtr)); static int HorizLineToArc _ANSI_ARGS_((double x1, double x2, double y, double rx, double ry, double start, double extent)); @@ -150,7 +245,7 @@ Tk_ItemType tkArcType = { ArcCoords, /* coordProc */ DeleteArc, /* deleteProc */ DisplayArc, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ ArcToPoint, /* pointProc */ ArcToArea, /* areaProc */ ArcToPostscript, /* postscriptProc */ @@ -161,7 +256,7 @@ Tk_ItemType tkArcType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; #ifndef PI @@ -197,11 +292,23 @@ CreateArc(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing arc. */ + Tcl_Obj *CONST argv[]; /* Arguments describing arc. */ { ArcItem *arcPtr = (ArcItem *) itemPtr; + int i; - if (argc < 4) { + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 4; + } + } + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", @@ -214,38 +321,36 @@ CreateArc(interp, canvas, itemPtr, argc, argv) * up after errors during the the remainder of this procedure. */ + Tk_CreateOutline(&(arcPtr->outline)); arcPtr->start = 0; arcPtr->extent = 90; arcPtr->outlinePtr = NULL; arcPtr->numOutlinePoints = 0; - arcPtr->width = 1; - arcPtr->outlineColor = NULL; + arcPtr->tsoffset.flags = 0; + arcPtr->tsoffset.xoffset = 0; + arcPtr->tsoffset.yoffset = 0; arcPtr->fillColor = NULL; + arcPtr->activeFillColor = NULL; + arcPtr->disabledFillColor = NULL; arcPtr->fillStipple = None; - arcPtr->outlineStipple = None; - arcPtr->style = Tk_GetUid("pieslice"); - arcPtr->outlineGC = None; + arcPtr->activeFillStipple = None; + arcPtr->disabledFillStipple = None; + arcPtr->style = PIESLICE_STYLE; arcPtr->fillGC = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &arcPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; + if ((ArcCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) != TCL_OK) { - DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + error: + DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -274,28 +379,42 @@ ArcCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { ArcItem *arcPtr = (ArcItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, arcPtr->bbox[0], c0); - Tcl_PrintDouble(interp, arcPtr->bbox[1], c1); - Tcl_PrintDouble(interp, arcPtr->bbox[2], c2); - Tcl_PrintDouble(interp, arcPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(arcPtr->bbox[0]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[2]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[3]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((argc == 1)||(argc == 4)) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], + &arcPtr->bbox[0]) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[2], &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[3], &arcPtr->bbox[3]) != TCL_OK)) { return TCL_ERROR; } @@ -335,7 +454,7 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Arc item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { ArcItem *arcPtr = (ArcItem *) itemPtr; @@ -344,18 +463,52 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) unsigned long mask; int i; Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) arcPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) arcPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } + state = itemPtr->state; + /* * A few of the options require additional processing, such as * style and graphics contexts. */ + if (arcPtr->outline.activeWidth > arcPtr->outline.width || + arcPtr->outline.activeDash.number > 0 || + arcPtr->outline.activeColor != NULL || + arcPtr->outline.activeStipple != None || + arcPtr->activeFillColor != NULL || + arcPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = &arcPtr->outline.tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[2] + 0.5); + } + i = (int) (arcPtr->start/360.0); arcPtr->start -= i*360.0; if (arcPtr->start < 0) { @@ -364,50 +517,60 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) i = (int) (arcPtr->extent/360.0); arcPtr->extent -= i*360.0; - if ((arcPtr->style != Tk_GetUid("arc")) - && (arcPtr->style != Tk_GetUid("chord")) - && (arcPtr->style != Tk_GetUid("pieslice"))) { - Tcl_AppendResult(interp, "bad -style option \"", - arcPtr->style, "\": must be arc, chord, or pieslice", - (char *) NULL); - arcPtr->style = Tk_GetUid("pieslice"); - return TCL_ERROR; - } - - if (arcPtr->width < 0) { - arcPtr->width = 1; - } - if (arcPtr->outlineColor == NULL) { - newGC = None; - } else { - gcValues.foreground = arcPtr->outlineColor->pixel; + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(arcPtr->outline)); + if (mask) { gcValues.cap_style = CapButt; - gcValues.line_width = arcPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; - if (arcPtr->outlineStipple != None) { - gcValues.stipple = arcPtr->outlineStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } + mask |= GCCapStyle; newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (arcPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), arcPtr->outline.gc); + } + arcPtr->outline.gc = newGC; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), arcPtr->outlineGC); + if (state==TK_STATE_HIDDEN) { + ComputeArcBbox(canvas, arcPtr); + return TCL_OK; } - arcPtr->outlineGC = newGC; - if ((arcPtr->fillColor == NULL) || (arcPtr->style == Tk_GetUid("arc"))) { + color = arcPtr->fillColor; + stipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->activeFillColor!=NULL) { + color = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->disabledFillColor!=NULL) { + color = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + stipple = arcPtr->disabledFillStipple; + } + } + + if (arcPtr->style == ARC_STYLE) { + newGC = None; + } else if (color == NULL) { newGC = None; } else { - gcValues.foreground = arcPtr->fillColor->pixel; - if (arcPtr->style == Tk_GetUid("chord")) { + gcValues.foreground = color->pixel; + if (arcPtr->style == CHORD_STYLE) { gcValues.arc_mode = ArcChord; } else { gcValues.arc_mode = ArcPieSlice; } mask = GCForeground|GCArcMode; - if (arcPtr->fillStipple != None) { - gcValues.stipple = arcPtr->fillStipple; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } @@ -418,6 +581,23 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) } arcPtr->fillGC = newGC; + tsoffset = &arcPtr->tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[3] + 0.5); + } + ComputeArcBbox(canvas, arcPtr); return TCL_OK; } @@ -448,23 +628,27 @@ DeleteArc(canvas, itemPtr, display) { ArcItem *arcPtr = (ArcItem *) itemPtr; + Tk_DeleteOutline(display, &(arcPtr->outline)); if (arcPtr->numOutlinePoints != 0) { ckfree((char *) arcPtr->outlinePtr); } - if (arcPtr->outlineColor != NULL) { - Tk_FreeColor(arcPtr->outlineColor); - } if (arcPtr->fillColor != NULL) { Tk_FreeColor(arcPtr->fillColor); } + if (arcPtr->activeFillColor != NULL) { + Tk_FreeColor(arcPtr->activeFillColor); + } + if (arcPtr->disabledFillColor != NULL) { + Tk_FreeColor(arcPtr->disabledFillColor); + } if (arcPtr->fillStipple != None) { Tk_FreeBitmap(display, arcPtr->fillStipple); } - if (arcPtr->outlineStipple != None) { - Tk_FreeBitmap(display, arcPtr->outlineStipple); + if (arcPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, arcPtr->activeFillStipple); } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(display, arcPtr->outlineGC); + if (arcPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, arcPtr->disabledFillStipple); } if (arcPtr->fillGC != None) { Tk_FreeGC(display, arcPtr->fillGC); @@ -497,6 +681,30 @@ ComputeArcBbox(canvas, arcPtr) * recomputed. */ { double tmp, center[2], point[2]; + double width; + Tk_State state = arcPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = arcPtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (state==TK_STATE_HIDDEN) { + arcPtr->header.x1 = arcPtr->header.x2 = + arcPtr->header.y1 = arcPtr->header.y2 = -1; + return; + } else if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { + if (arcPtr->outline.activeWidth>width) { + width = arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = arcPtr->outline.disabledWidth; + } + } /* * Make sure that the first coordinates are the lowest ones. @@ -515,7 +723,7 @@ ComputeArcBbox(canvas, arcPtr) arcPtr->bbox[0] = tmp; } - ComputeArcOutline(arcPtr); + ComputeArcOutline(canvas,arcPtr); /* * To compute the bounding box, start with the the bbox formed @@ -529,7 +737,7 @@ ComputeArcBbox(canvas, arcPtr) TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2); center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2; center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2; - if (arcPtr->style == Tk_GetUid("pieslice")) { + if (arcPtr->style == PIESLICE_STYLE) { TkIncludePoint((Tk_Item *) arcPtr, center); } @@ -575,10 +783,10 @@ ComputeArcBbox(canvas, arcPtr) * being drawn) and add one extra pixel just for safety. */ - if (arcPtr->outlineColor == NULL) { + if (arcPtr->outline.gc == None) { tmp = 1; } else { - tmp = (arcPtr->width + 1)/2 + 1; + tmp = (int) ((width + 1.0)/2.0 + 1); } arcPtr->header.x1 -= (int) tmp; arcPtr->header.y1 -= (int) tmp; @@ -616,7 +824,41 @@ DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height) { ArcItem *arcPtr = (ArcItem *) itemPtr; short x1, y1, x2, y2; - int start, extent; + int start, extent, dashnumber; + double lineWidth; + Tk_State state = itemPtr->state; + Pixmap stipple; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + lineWidth = arcPtr->outline.width; + if (lineWidth < 1.0) { + lineWidth = 1.0; + } + dashnumber = arcPtr->outline.dash.number; + stipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>lineWidth) { + lineWidth = arcPtr->outline.activeWidth; + } + if (arcPtr->outline.activeDash.number>0) { + dashnumber = arcPtr->outline.activeDash.number; + } + if (arcPtr->activeFillStipple != None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + lineWidth = arcPtr->outline.disabledWidth; + } + if (arcPtr->outline.disabledDash.number>0) { + dashnumber = arcPtr->outline.disabledDash.number; + } + if (arcPtr->disabledFillStipple != None) { + stipple = arcPtr->disabledFillStipple; + } + } /* * Compute the screen coordinates of the bounding box for the item, @@ -643,65 +885,86 @@ DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height) */ if ((arcPtr->fillGC != None) && (extent != 0)) { - if (arcPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->fillGC); + if (stipple != None) { + int w=0; int h=0; + Tk_TSOffset *tsoffset = &arcPtr->tsoffset; + int flags = tsoffset->flags; + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, arcPtr->fillGC, tsoffset); + if (tsoffset) { + tsoffset->xoffset += w; + tsoffset->yoffset += h; + } } XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); - if (arcPtr->fillStipple != None) { + if (stipple != None) { XSetTSOrigin(display, arcPtr->fillGC, 0, 0); } } - if (arcPtr->outlineGC != None) { - if (arcPtr->outlineStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->outlineGC); - } + if (arcPtr->outline.gc != None) { + Tk_ChangeOutlineGC(canvas, itemPtr, &(arcPtr->outline)); + if (extent != 0) { - XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, + XDrawArc(display, drawable, arcPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); } /* * If the outline width is very thin, don't use polygons to draw * the linear parts of the outline (this often results in nothing - * being displayed); just draw lines instead. + * being displayed); just draw lines instead. The same is done if + * the outline is dashed, because then polygons don't work. */ - if (arcPtr->width <= 2) { + if (lineWidth < 1.5 || dashnumber > 0) { Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0], arcPtr->center1[1], &x1, &y1); Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0], arcPtr->center2[1], &x2, &y2); - if (arcPtr->style == Tk_GetUid("chord")) { - XDrawLine(display, drawable, arcPtr->outlineGC, + if (arcPtr->style == CHORD_STYLE) { + XDrawLine(display, drawable, arcPtr->outline.gc, x1, y1, x2, y2); - } else if (arcPtr->style == Tk_GetUid("pieslice")) { + } else if (arcPtr->style == PIESLICE_STYLE) { short cx, cy; Tk_CanvasDrawableCoords(canvas, (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0, (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy); - XDrawLine(display, drawable, arcPtr->outlineGC, + XDrawLine(display, drawable, arcPtr->outline.gc, cx, cy, x1, y1); - XDrawLine(display, drawable, arcPtr->outlineGC, + XDrawLine(display, drawable, arcPtr->outline.gc, cx, cy, x2, y2); } } else { - if (arcPtr->style == Tk_GetUid("chord")) { + if (arcPtr->style == CHORD_STYLE) { TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS, - display, drawable, arcPtr->outlineGC, None); - } else if (arcPtr->style == Tk_GetUid("pieslice")) { + display, drawable, arcPtr->outline.gc, None); + } else if (arcPtr->style == PIESLICE_STYLE) { TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS, - display, drawable, arcPtr->outlineGC, None); + display, drawable, arcPtr->outline.gc, None); TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS, display, drawable, arcPtr->outlineGC, + PIE_OUTLINE2_PTS, display, drawable, arcPtr->outline.gc, None); } } - if (arcPtr->outlineStipple != None) { - XSetTSOrigin(display, arcPtr->outlineGC, 0, 0); - } + + Tk_ResetOutlineGC(canvas, itemPtr, &(arcPtr->outline)); } } @@ -739,6 +1002,22 @@ ArcToPoint(canvas, itemPtr, pointPtr) double vertex[2], pointAngle, diff, dist, newDist; double poly[8], polyDist, width, t1, t2; int filled, angleInRange; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = (double) arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state == TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } /* * See if the point is within the angular range of the arc. @@ -775,9 +1054,9 @@ ArcToPoint(canvas, itemPtr, pointPtr) * we're dealing with. */ - if (arcPtr->style == Tk_GetUid("arc")) { + if (arcPtr->style == ARC_STYLE) { if (angleInRange) { - return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width, + return TkOvalToPoint(arcPtr->bbox, width, 0, pointPtr); } dist = hypot(pointPtr[0] - arcPtr->center1[0], @@ -790,18 +1069,16 @@ ArcToPoint(canvas, itemPtr, pointPtr) return dist; } - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { filled = 1; } else { filled = 0; } - if (arcPtr->outlineGC == None) { + if (arcPtr->outline.gc == None) { width = 0.0; - } else { - width = arcPtr->width; } - if (arcPtr->style == Tk_GetUid("pieslice")) { + if (arcPtr->style == PIESLICE_STYLE) { if (width > 1.0) { dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, pointPtr); @@ -906,16 +1183,29 @@ ArcToArea(canvas, itemPtr, rectPtr) * every test so far shows arc to be outside * of rectangle. */ int newInside; + Tk_State state = itemPtr->state; - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = (double) arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } + + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { filled = 1; } else { filled = 0; } - if (arcPtr->outlineGC == None) { + if (arcPtr->outline.gc == None) { width = 0.0; - } else { - width = arcPtr->width; } /* @@ -956,7 +1246,7 @@ ArcToArea(canvas, itemPtr, rectPtr) numPoints = 2; pointPtr += 4; - if ((arcPtr->style == Tk_GetUid("pieslice")) && (arcPtr->extent < 180.0)) { + if ((arcPtr->style == PIESLICE_STYLE) && (arcPtr->extent < 180.0)) { pointPtr[0] = 0.0; pointPtr[1] = 0.0; numPoints++; @@ -1030,7 +1320,7 @@ ArcToArea(canvas, itemPtr, rectPtr) * polygon(s) forming the sides of a chord or pie-slice. */ - if (arcPtr->style == Tk_GetUid("pieslice")) { + if (arcPtr->style == PIESLICE_STYLE) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, rectPtr) != -1) { @@ -1046,7 +1336,7 @@ ArcToArea(canvas, itemPtr, rectPtr) return 0; } } - } else if (arcPtr->style == Tk_GetUid("chord")) { + } else if (arcPtr->style == CHORD_STYLE) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, rectPtr) != -1) { @@ -1198,13 +1488,16 @@ TranslateArc(canvas, itemPtr, deltaX, deltaY) */ static void -ComputeArcOutline(arcPtr) +ComputeArcOutline(canvas,arcPtr) + Tk_Canvas canvas; /* Information about overall canvas. */ ArcItem *arcPtr; /* Information about arc. */ { - double sin1, cos1, sin2, cos2, angle, halfWidth; + double sin1, cos1, sin2, cos2, angle, width, halfWidth; double boxWidth, boxHeight; double vertex[2], corner1[2], corner2[2]; double *outlinePtr; + Tk_State state = arcPtr->header.state; + /* * Make sure that the outlinePtr array is large enough to hold @@ -1218,6 +1511,10 @@ ComputeArcOutline(arcPtr) } outlinePtr = arcPtr->outlinePtr; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + /* * First compute the two points that lie at the centers of * the ends of the curved arc segment, which are marked with @@ -1274,7 +1571,18 @@ ComputeArcOutline(arcPtr) * the oval. */ - halfWidth = arcPtr->width/2.0; + width = arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { + if (arcPtr->outline.activeWidth>arcPtr->outline.width) { + width = arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>arcPtr->outline.width) { + width = arcPtr->outline.disabledWidth; + } + } + halfWidth = width/2.0; + if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { angle = 0.0; } else { @@ -1297,11 +1605,11 @@ ComputeArcOutline(arcPtr) * center point. The second point is the corner point. */ - if (arcPtr->style == Tk_GetUid("chord")) { + if (arcPtr->style == CHORD_STYLE) { outlinePtr[0] = outlinePtr[12] = corner1[0]; outlinePtr[1] = outlinePtr[13] = corner1[1]; TkGetButtPoints(arcPtr->center2, arcPtr->center1, - (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2); + width, 0, outlinePtr+10, outlinePtr+2); outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2] - arcPtr->center1[0]; outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3] @@ -1312,7 +1620,7 @@ ComputeArcOutline(arcPtr) - arcPtr->center1[0]; outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11] - arcPtr->center1[1]; - } else if (arcPtr->style == Tk_GetUid("pieslice")) { + } else if (arcPtr->style == PIESLICE_STYLE) { /* * For pie slices, generate two polygons, one for each side * of the pie slice. The first arm has a shape like this, @@ -1328,7 +1636,7 @@ ComputeArcOutline(arcPtr) * */ - TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0, + TkGetButtPoints(arcPtr->center1, vertex, width, 0, outlinePtr, outlinePtr+2); outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0]; outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1]; @@ -1357,7 +1665,7 @@ ComputeArcOutline(arcPtr) * first two points of the first arm, depending on extent. */ - TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0, + TkGetButtPoints(arcPtr->center2, vertex, width, 0, outlinePtr+12, outlinePtr+16); if ((arcPtr->extent > 180) || ((arcPtr->extent < 0) && (arcPtr->extent > -180))) { @@ -1588,6 +1896,11 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ArcItem *arcPtr = (ArcItem *) itemPtr; char buffer[400]; double y1, y2, ang1, ang2; + XColor *color; + Pixmap stipple; + XColor *fillColor; + Pixmap fillStipple; + Tk_State state = itemPtr->state; y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]); y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]); @@ -1598,6 +1911,41 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ang2 = arcPtr->start; } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = arcPtr->outline.color; + stipple = arcPtr->outline.stipple; + fillColor = arcPtr->fillColor; + fillStipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeColor!=NULL) { + color = arcPtr->outline.activeColor; + } + if (arcPtr->outline.activeStipple!=None) { + stipple = arcPtr->outline.activeStipple; + } + if (arcPtr->activeFillColor!=NULL) { + fillColor = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + fillStipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledColor!=NULL) { + color = arcPtr->outline.disabledColor; + } + if (arcPtr->outline.disabledStipple!=None) { + stipple = arcPtr->outline.disabledStipple; + } + if (arcPtr->disabledFillColor!=NULL) { + fillColor = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + fillStipple = arcPtr->disabledFillStipple; + } + } + /* * If the arc is filled, output Postscript for the interior region * of the arc. @@ -1608,7 +1956,7 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); Tcl_AppendResult(interp, buffer, (char *) NULL); - if (arcPtr->style == Tk_GetUid("chord")) { + if (arcPtr->style == CHORD_STYLE) { sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", ang1, ang2); } else { @@ -1617,16 +1965,16 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ang1, ang2); } Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->fillColor) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; }; - if (arcPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, arcPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineGC != None) { + if (arcPtr->outline.gc != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -1638,44 +1986,34 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) * If there's an outline for the arc, draw it. */ - if (arcPtr->outlineGC != None) { + if (arcPtr->outline.gc != None) { sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "0 0 1 %.15g %.15g arc\nsetmatrix\n", ang1, ang2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "%d setlinewidth\n0 setlinecap\n", arcPtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) - != TCL_OK) { + sprintf(buffer, "0 0 1 %.15g %.15g", ang1, ang2); + Tcl_AppendResult(interp, buffer, + " arc\nsetmatrix\n0 setlinecap\n", (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(arcPtr->outline)) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - if (arcPtr->style != Tk_GetUid("arc")) { + if (arcPtr->style != ARC_STYLE) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - if (arcPtr->style == Tk_GetUid("chord")) { + if (arcPtr->style == CHORD_STYLE) { Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS); } else { Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { + stipple) != TCL_OK) { return TCL_ERROR; } } else { @@ -1686,14 +2024,14 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, PIE_OUTLINE2_PTS); } - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { + stipple) != TCL_OK) { return TCL_ERROR; } } else { @@ -1704,3 +2042,106 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * StyleParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-style" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The state for a given item gets replaced by the state + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +StyleParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register Style *stylePtr = (Style *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *stylePtr = PIESLICE_STYLE; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'a') && (strncmp(value, "arc", length) == 0)) { + *stylePtr = ARC_STYLE; + return TCL_OK; + } + if ((c == 'c') && (strncmp(value, "chord", length) == 0)) { + *stylePtr = CHORD_STYLE; + return TCL_OK; + } + if ((c == 'p') && (strncmp(value, "pieslice", length) == 0)) { + *stylePtr = PIESLICE_STYLE; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad -style option \"", + value, "\": must be arc, chord, or pieslice", + (char *) NULL); + *stylePtr = PIESLICE_STYLE; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * StylePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-style" + * configuration option. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +StylePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Ignored. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Style *stylePtr = (Style *) (widgRec + offset); + + if (*stylePtr==ARC_STYLE) { + return "arc"; + } else if (*stylePtr==CHORD_STYLE) { + return "chord"; + } else { + return "pieslice"; + } +} diff --git a/generic/tkCanvBmap.c b/generic/tkCanvBmap.c index dedc4e7..bcef7f3 100644 --- a/generic/tkCanvBmap.c +++ b/generic/tkCanvBmap.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvBmap.c,v 1.3 1999/04/16 01:51:11 stanton Exp $ + * RCS: @(#) $Id: tkCanvBmap.c,v 1.4 1999/12/14 06:52:25 hobbs Exp $ */ #include <stdio.h> @@ -29,8 +29,14 @@ typedef struct BitmapItem { Tk_Anchor anchor; /* Where to anchor bitmap relative to * (x,y). */ Pixmap bitmap; /* Bitmap to display in window. */ + Pixmap activeBitmap; /* Bitmap to display in window. */ + Pixmap disabledBitmap; /* Bitmap to display in window. */ XColor *fgColor; /* Foreground color to use for bitmap. */ + XColor *activeFgColor; /* Foreground color to use for bitmap. */ + XColor *disabledFgColor; /* Foreground color to use for bitmap. */ XColor *bgColor; /* Background color to use for bitmap. */ + XColor *activeBgColor; /* Background color to use for bitmap. */ + XColor *disabledBgColor; /* Background color to use for bitmap. */ GC gc; /* Graphics context to use for drawing * bitmap on screen. */ } BitmapItem; @@ -39,19 +45,42 @@ typedef struct BitmapItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_COLOR, "-activebackground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeBgColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activebitmap", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeBitmap), TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeFgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledbackground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledBgColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledbitmap", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledBitmap), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledforeground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledFgColor), + TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, "black", Tk_Offset(BitmapItem, fgColor), 0}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, @@ -64,7 +93,7 @@ static Tk_ConfigSpec configSpecs[] = { static int BitmapCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int BitmapToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double BitmapToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -75,10 +104,10 @@ static void ComputeBitmapBbox _ANSI_ARGS_((Tk_Canvas canvas, BitmapItem *bmapPtr)); static int ConfigureBitmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateBitmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteBitmap _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayBitmap _ANSI_ARGS_((Tk_Canvas canvas, @@ -104,7 +133,7 @@ Tk_ItemType tkBitmapType = { BitmapCoords, /* coordProc */ DeleteBitmap, /* deleteProc */ DisplayBitmap, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ BitmapToPoint, /* pointProc */ BitmapToArea, /* areaProc */ BitmapToPostscript, /* postscriptProc */ @@ -115,7 +144,7 @@ Tk_ItemType tkBitmapType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -145,11 +174,24 @@ CreateBitmap(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -163,25 +205,30 @@ CreateBitmap(interp, canvas, itemPtr, argc, argv) bmapPtr->anchor = TK_ANCHOR_CENTER; bmapPtr->bitmap = None; + bmapPtr->activeBitmap = None; + bmapPtr->disabledBitmap = None; bmapPtr->fgColor = NULL; + bmapPtr->activeFgColor = NULL; + bmapPtr->disabledFgColor = NULL; bmapPtr->bgColor = NULL; + bmapPtr->activeBgColor = NULL; + bmapPtr->disabledBgColor = NULL; bmapPtr->gc = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((BitmapCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureBitmap(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureBitmap(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -210,20 +257,34 @@ BitmapCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, bmapPtr->x, x); - Tcl_PrintDouble(interp, bmapPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(bmapPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(bmapPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc <3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &bmapPtr->y) + != TCL_OK)) { return TCL_ERROR; } ComputeBitmapBbox(canvas, bmapPtr); @@ -261,7 +322,7 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Bitmap item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; @@ -269,10 +330,14 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) GC newGC; Tk_Window tkwin; unsigned long mask; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) bmapPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) bmapPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -281,16 +346,67 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) * that determine the graphics context. */ - gcValues.foreground = bmapPtr->fgColor->pixel; + state = itemPtr->state; + + if (bmapPtr->activeFgColor!=NULL || + bmapPtr->activeBgColor!=NULL || + bmapPtr->activeBitmap!=None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (state==TK_STATE_DISABLED || bitmap == None) { + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; + } + + gcValues.foreground = fgColor->pixel; mask = GCForeground; - if (bmapPtr->bgColor != NULL) { - gcValues.background = bmapPtr->bgColor->pixel; + if (bgColor != NULL) { + gcValues.background = bgColor->pixel; mask |= GCBackground; } else { - gcValues.clip_mask = bmapPtr->bitmap; + gcValues.clip_mask = bitmap; mask |= GCClipMask; } - newGC = Tk_GetGC(tkwin, mask, &gcValues); + if (bitmap == None) { + newGC = None; + } else { + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } if (bmapPtr->gc != None) { Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc); } @@ -330,12 +446,30 @@ DeleteBitmap(canvas, itemPtr, display) if (bmapPtr->bitmap != None) { Tk_FreeBitmap(display, bmapPtr->bitmap); } + if (bmapPtr->activeBitmap != None) { + Tk_FreeBitmap(display, bmapPtr->activeBitmap); + } + if (bmapPtr->disabledBitmap != None) { + Tk_FreeBitmap(display, bmapPtr->disabledBitmap); + } if (bmapPtr->fgColor != NULL) { Tk_FreeColor(bmapPtr->fgColor); } + if (bmapPtr->activeFgColor != NULL) { + Tk_FreeColor(bmapPtr->activeFgColor); + } + if (bmapPtr->disabledFgColor != NULL) { + Tk_FreeColor(bmapPtr->disabledFgColor); + } if (bmapPtr->bgColor != NULL) { Tk_FreeColor(bmapPtr->bgColor); } + if (bmapPtr->activeBgColor != NULL) { + Tk_FreeColor(bmapPtr->activeBgColor); + } + if (bmapPtr->disabledBgColor != NULL) { + Tk_FreeColor(bmapPtr->disabledBgColor); + } if (bmapPtr->gc != NULL) { Tk_FreeGC(display, bmapPtr->gc); } @@ -370,11 +504,27 @@ ComputeBitmapBbox(canvas, bmapPtr) { int width, height; int x, y; + Pixmap bitmap; + Tk_State state = bmapPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)bmapPtr) { + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5)); - if (bmapPtr->bitmap == None) { + if (state==TK_STATE_HIDDEN || bitmap == None) { bmapPtr->header.x1 = bmapPtr->header.x2 = x; bmapPtr->header.y1 = bmapPtr->header.y2 = y; return; @@ -460,6 +610,10 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) BitmapItem *bmapPtr = (BitmapItem *) itemPtr; int bmapX, bmapY, bmapWidth, bmapHeight; short drawableX, drawableY; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_State state = itemPtr->state; /* * If the area being displayed doesn't cover the whole bitmap, @@ -467,7 +621,35 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) * redisplay. */ - if (bmapPtr->bitmap != None) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (bitmap != None) { if (x > bmapPtr->header.x1) { bmapX = x - bmapPtr->header.x1; bmapWidth = bmapPtr->header.x2 - x; @@ -503,9 +685,10 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX, drawableY - bmapY); - XCopyPlane(display, bmapPtr->bitmap, drawable, + XCopyPlane(display, bitmap, drawable, bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth, (unsigned int) bmapHeight, drawableX, drawableY, 1); + XSetClipOrigin(display, bmapPtr->gc, 0, 0); } } diff --git a/generic/tkCanvImg.c b/generic/tkCanvImg.c index cf1106d..144b755 100644 --- a/generic/tkCanvImg.c +++ b/generic/tkCanvImg.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvImg.c,v 1.3 1999/04/16 01:51:11 stanton Exp $ + * RCS: @(#) $Id: tkCanvImg.c,v 1.4 1999/12/14 06:52:25 hobbs Exp $ */ #include <stdio.h> @@ -31,23 +31,45 @@ typedef struct ImageItem { * (x,y). */ char *imageString; /* String describing -image option (malloc-ed). * NULL means no image right now. */ + char *activeImageString; /* String describing -activeimage option. + * NULL means no image right now. */ + char *disabledImageString; /* String describing -disabledimage option. + * NULL means no image right now. */ Tk_Image image; /* Image to display in window, or NULL if * no image at present. */ + Tk_Image activeImage; /* Image to display in window, or NULL if + * no image at present. */ + Tk_Image disabledImage; /* Image to display in window, or NULL if + * no image at present. */ } ImageItem; /* * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_STRING, "-activeimage", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ImageItem, activeImageString), + TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(ImageItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_STRING, "-disabledimage", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ImageItem, disabledImageString), + TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ImageItem, imageString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, @@ -63,19 +85,21 @@ static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, int imgHeight)); static int ImageCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int ImageToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double ImageToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *coordPtr)); +static int ImageToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static void ComputeImageBbox _ANSI_ARGS_((Tk_Canvas canvas, ImageItem *imgPtr)); static int ConfigureImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteImage _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayImage _ANSI_ARGS_((Tk_Canvas canvas, @@ -101,10 +125,10 @@ Tk_ItemType tkImageType = { ImageCoords, /* coordProc */ DeleteImage, /* deleteProc */ DisplayImage, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ ImageToPoint, /* pointProc */ ImageToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ + ImageToPostscript, /* postscriptProc */ ScaleImage, /* scaleProc */ TranslateImage, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ @@ -112,7 +136,7 @@ Tk_ItemType tkImageType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -142,11 +166,24 @@ CreateImage(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { ImageItem *imgPtr = (ImageItem *) itemPtr; + int i; - if (argc < 2) { + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj((Tcl_Obj *) argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } + + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -161,23 +198,26 @@ CreateImage(interp, canvas, itemPtr, argc, argv) imgPtr->canvas = canvas; imgPtr->anchor = TK_ANCHOR_CENTER; imgPtr->imageString = NULL; + imgPtr->activeImageString = NULL; + imgPtr->disabledImageString = NULL; imgPtr->image = NULL; + imgPtr->activeImage = NULL; + imgPtr->disabledImage = NULL; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &imgPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((ImageCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureImage(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureImage(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -206,20 +246,34 @@ ImageCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { ImageItem *imgPtr = (ImageItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, imgPtr->x, x); - Tcl_PrintDouble(interp, imgPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &imgPtr->y) != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(imgPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(imgPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], + &imgPtr->y) != TCL_OK)) { return TCL_ERROR; } ComputeImageBbox(canvas, imgPtr); @@ -257,7 +311,7 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Image item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { ImageItem *imgPtr = (ImageItem *) itemPtr; @@ -265,8 +319,8 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_Image image; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, - argv, (char *) imgPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) imgPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -277,6 +331,11 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) * if it hasn't changed. */ + if (imgPtr->activeImageString != NULL) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } if (imgPtr->imageString != NULL) { image = Tk_GetImage(interp, tkwin, imgPtr->imageString, ImageChangedProc, (ClientData) imgPtr); @@ -290,6 +349,32 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_FreeImage(imgPtr->image); } imgPtr->image = image; + if (imgPtr->activeImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + return TCL_ERROR; + } + } else { + image = NULL; + } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + imgPtr->activeImage = image; + if (imgPtr->disabledImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + return TCL_ERROR; + } + } else { + image = NULL; + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } + imgPtr->disabledImage = image; ComputeImageBbox(canvas, imgPtr); return TCL_OK; } @@ -323,9 +408,21 @@ DeleteImage(canvas, itemPtr, display) if (imgPtr->imageString != NULL) { ckfree(imgPtr->imageString); } + if (imgPtr->activeImageString != NULL) { + ckfree(imgPtr->activeImageString); + } + if (imgPtr->disabledImageString != NULL) { + ckfree(imgPtr->disabledImageString); + } if (imgPtr->image != NULL) { Tk_FreeImage(imgPtr->image); } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } } /* @@ -357,11 +454,27 @@ ComputeImageBbox(canvas, imgPtr) { int width, height; int x, y; + Tk_Image image; + Tk_State state = imgPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)imgPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5)); - if (imgPtr->image == None) { + if ((state == TK_STATE_HIDDEN) || (image == None)) { imgPtr->header.x1 = imgPtr->header.x2 = x; imgPtr->header.y1 = imgPtr->header.y2 = y; return; @@ -371,7 +484,7 @@ ComputeImageBbox(canvas, imgPtr) * Compute location and size of image, using anchor information. */ - Tk_SizeOfImage(imgPtr->image, &width, &height); + Tk_SizeOfImage(image, &width, &height); switch (imgPtr->anchor) { case TK_ANCHOR_N: x -= width/2; @@ -445,8 +558,25 @@ DisplayImage(canvas, itemPtr, display, drawable, x, y, width, height) { ImageItem *imgPtr = (ImageItem *) itemPtr; short drawableX, drawableY; + Tk_Image image; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } - if (imgPtr->image == NULL) { + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + + if (image == NULL) { return; } @@ -456,7 +586,7 @@ DisplayImage(canvas, itemPtr, display, drawable, x, y, width, height) Tk_CanvasDrawableCoords(canvas, (double) x, (double) y, &drawableX, &drawableY); - Tk_RedrawImage(imgPtr->image, x - imgPtr->header.x1, y - imgPtr->header.y1, + Tk_RedrawImage(image, x - imgPtr->header.x1, y - imgPtr->header.y1, width, height, drawable, drawableX, drawableY); } @@ -565,6 +695,96 @@ ImageToArea(canvas, itemPtr, rectPtr) /* *-------------------------------------------------------------- * + * ImageToPostscript -- + * + * This procedure is called to generate Postscript for + * image items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in interp->result, replacing whatever used to be there. + * If no error occurs, then Postscript for the item is appended + * to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +ImageToPostscript(interp, canvas, itemPtr, prepass) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is + * wanted. */ + int prepass; /* 1 means this is a prepass to + * collect font information; 0 means + * final Postscript is being created.*/ +{ + ImageItem *imgPtr = (ImageItem *)itemPtr; + Tk_Window canvasWin = Tk_CanvasTkwin(canvas); + + char buffer[256]; + double x, y; + int width, height; + Tk_Image image; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + Tk_SizeOfImage(image, &width, &height); + + /* + * Compute the coordinates of the lower-left corner of the image, + * taking into account the anchor position for the image. + */ + + x = imgPtr->x; + y = Tk_CanvasPsY(canvas, imgPtr->y); + + switch (imgPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + if (image == NULL) { + return TCL_OK; + } + + if (!prepass) { + sprintf(buffer, "%.15g %.15g", x, y); + Tcl_AppendResult(interp, buffer, " translate\n", (char *) NULL); + } + + return Tk_PostscriptImage(image, interp, canvasWin, + ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); +} + +/* + *-------------------------------------------------------------- + * * ScaleImage -- * * This procedure is invoked to rescale an item. diff --git a/generic/tkCanvLine.c b/generic/tkCanvLine.c index 131b73d..328d184 100644 --- a/generic/tkCanvLine.c +++ b/generic/tkCanvLine.c @@ -10,23 +10,29 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvLine.c,v 1.4 1999/04/16 01:51:11 stanton Exp $ + * RCS: @(#) $Id: tkCanvLine.c,v 1.5 1999/12/14 06:52:26 hobbs Exp $ */ #include <stdio.h> #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each line item. */ +typedef enum { + ARROWS_NONE, ARROWS_FIRST, ARROWS_LAST, ARROWS_BOTH +} Arrows; + typedef struct LineItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ Tk_Canvas canvas; /* Canvas containing item. Needed for * parsing arrow shapes. */ - int numPoints; /* Number of points in line (always >= 2). */ + int numPoints; /* Number of points in line (always >= 0). */ double *coordPtr; /* Pointer to malloc-ed array containing * x- and y-coords of all points in line. * X-coords are even-valued indices, y-coords @@ -37,14 +43,10 @@ typedef struct LineItem { * their tips. The actual endpoints are * stored in the *firstArrowPtr and * *lastArrowPtr, if they exist. */ - int width; /* Width of line. */ - XColor *fg; /* Foreground color for line. */ - Pixmap fillStipple; /* Stipple bitmap for filling line. */ int capStyle; /* Cap style for line. */ int joinStyle; /* Join style for line. */ - GC gc; /* Graphics context for filling line. */ GC arrowGC; /* Graphics context for drawing arrowheads. */ - Tk_Uid arrow; /* Indicates whether or not to draw arrowheads: + Arrows arrow; /* Indicates whether or not to draw arrowheads: * "none", "first", "last", or "both". */ float arrowShapeA; /* Distance from tip of arrowhead to center. */ float arrowShapeB; /* Distance from tip of arrowhead to trailing @@ -60,7 +62,7 @@ typedef struct LineItem { * point in line (PTS_IN_ARROW points, first * of which is tip). Malloc'ed. NULL means * no arrowhead at last point. */ - int smooth; /* Non-zero means draw line smoothed (i.e. + Tk_SmoothMethod *smooth; /* Non-zero means draw line smoothed (i.e. * with Bezier splines). */ int splineSteps; /* Number of steps in each spline segment. */ } LineItem; @@ -82,29 +84,42 @@ static void ComputeLineBbox _ANSI_ARGS_((Tk_Canvas canvas, LineItem *linePtr)); static int ConfigureLine _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas canvas, LineItem *linePtr)); static int CreateLine _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteLine _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayLine _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height)); +static int GetLineIndex _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, + Tcl_Obj *obj, int *indexPtr)); static int LineCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); +static void LineDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int first, int last)); +static void LineInsert _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj)); static int LineToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double LineToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *coordPtr)); static int LineToPostscript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); +static int ArrowParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); +static char * ArrowPrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *recordPtr, int offset, + Tcl_FreeProc **freeProcPtr)); static int ParseArrowShape _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, - char *recordPtr, int offset)); + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *recordPtr, int offset, Tcl_FreeProc **freeProcPtr)); @@ -120,34 +135,101 @@ static void TranslateLine _ANSI_ARGS_((Tk_Canvas canvas, * values in CreateLine. */ -static Tk_CustomOption arrowShapeOption = {ParseArrowShape, - PrintArrowShape, (ClientData) NULL}; -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption arrowShapeOption = { + (Tk_OptionParseProc *) ParseArrowShape, + PrintArrowShape, (ClientData) NULL +}; +static Tk_CustomOption arrowOption = { + (Tk_OptionParseProc *) ArrowParseProc, + ArrowPrintProc, (ClientData) NULL +}; +static Tk_CustomOption smoothOption = { + (Tk_OptionParseProc *) TkSmoothParseProc, + TkSmoothPrintProc, (ClientData) NULL +}; +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, - "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(LineItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-arrow", (char *) NULL, (char *) NULL, + "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT, &arrowOption}, {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL, "8 10 3", Tk_Offset(LineItem, arrowShapeA), TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption}, {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL, "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - "black", Tk_Offset(LineItem, fg), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(LineItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(LineItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(LineItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(LineItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(LineItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(LineItem, smooth), + TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(LineItem, fillStipple), TK_CONFIG_NULL_OK}, + (char *) NULL, Tk_Offset(LineItem, outline.stipple), + TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(LineItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(LineItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -166,18 +248,18 @@ Tk_ItemType tkLineType = { LineCoords, /* coordProc */ DeleteLine, /* deleteProc */ DisplayLine, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ LineToPoint, /* pointProc */ LineToArea, /* areaProc */ LineToPostscript, /* postscriptProc */ ScaleLine, /* scaleProc */ TranslateLine, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ + (Tk_ItemIndexProc *) GetLineIndex, /* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemInsertProc *) LineInsert, /* insertProc */ + LineDeleteCoords, /* dTextProc */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -215,42 +297,31 @@ CreateLine(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing line. */ + Tcl_Obj *CONST argv[]; /* Arguments describing line. */ { LineItem *linePtr = (LineItem *) itemPtr; int i; - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x1 y1 x2 y2 ?x3 y3 ...? ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - /* * Carry out initialization that is needed to set defaults and to * allow proper cleanup after errors during the the remainder of * this procedure. */ + Tk_CreateOutline(&(linePtr->outline)); linePtr->canvas = canvas; linePtr->numPoints = 0; linePtr->coordPtr = NULL; - linePtr->width = 1; - linePtr->fg = None; - linePtr->fillStipple = None; linePtr->capStyle = CapButt; linePtr->joinStyle = JoinRound; - linePtr->gc = None; linePtr->arrowGC = None; - linePtr->arrow = Tk_GetUid("none"); + linePtr->arrow = ARROWS_NONE; linePtr->arrowShapeA = (float)8.0; linePtr->arrowShapeB = (float)10.0; linePtr->arrowShapeC = (float)3.0; linePtr->firstArrowPtr = NULL; linePtr->lastArrowPtr = NULL; - linePtr->smooth = 0; + linePtr->smooth = (Tk_SmoothMethod *) NULL; linePtr->splineSteps = 12; /* @@ -259,14 +330,14 @@ CreateLine(interp, canvas, itemPtr, argc, argv) * start with a digit or a minus sign followed by a digit. */ - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') - || ((argv[i][1] != '.') && !isdigit(UCHAR(argv[i][1]))))) { + for (i = 0; i < argc; i++) { + char *arg = Tcl_GetStringFromObj(argv[i], NULL); + if ((arg[0] == '-') && (arg[1] >= 'a') + && (arg[1] <= 'z')) { break; } } - if (LineCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { + if (i && (LineCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { goto error; } if (ConfigureLine(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { @@ -304,16 +375,16 @@ LineCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { LineItem *linePtr = (LineItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; int i, numPoints; + double *coordPtr; if (argc == 0) { - double *coordPtr; int numCoords; + Tcl_Obj *subobj, *obj = Tcl_NewObj(); numCoords = 2*linePtr->numPoints; if (linePtr->firstArrowPtr != NULL) { @@ -328,15 +399,19 @@ LineCoords(interp, canvas, itemPtr, argc, argv) if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { coordPtr = linePtr->lastArrowPtr; } - Tcl_PrintDouble(interp, *coordPtr, buffer); - Tcl_AppendElement(interp, buffer); + subobj = Tcl_NewDoubleObj(*coordPtr); + Tcl_ListObjAppendElement(interp, obj, subobj); } - } else if (argc < 4) { - Tcl_AppendResult(interp, - "too few coordinates for line: must have at least 4", - (char *) NULL); - return TCL_ERROR; - } else if (argc & 1) { + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (argc == 1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } + } + if (argc & 1) { Tcl_AppendResult(interp, "odd number of coordinates specified for line", (char *) NULL); @@ -344,19 +419,21 @@ LineCoords(interp, canvas, itemPtr, argc, argv) } else { numPoints = argc/2; if (linePtr->numPoints != numPoints) { + coordPtr = (double *) ckalloc((unsigned) + (sizeof(double) * argc)); if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } - linePtr->coordPtr = (double *) ckalloc((unsigned) - (sizeof(double) * argc)); + linePtr->coordPtr = coordPtr; linePtr->numPoints = numPoints; } - for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], - &linePtr->coordPtr[i]) != TCL_OK) { - return TCL_ERROR; - } - } + coordPtr = linePtr->coordPtr; + for (i = 0; i <argc; i++) { + if (Tk_CanvasGetCoordFromObj(interp, canvas, argv[i], + coordPtr++) != TCL_OK) { + return TCL_ERROR; + } + } /* * Update arrowheads by throwing away any existing arrow-head @@ -371,7 +448,7 @@ LineCoords(interp, canvas, itemPtr, argc, argv) ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } - if (linePtr->arrow != Tk_GetUid("none")) { + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } ComputeLineBbox(canvas, linePtr); @@ -404,7 +481,7 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Line item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { LineItem *linePtr = (LineItem *) itemPtr; @@ -412,14 +489,11 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) GC newGC, arrowGC; unsigned long mask; Tk_Window tkwin; - Tk_Uid noneUid = Tk_GetUid("none"); - Tk_Uid bothUid = Tk_GetUid("both"); - Tk_Uid firstUid = Tk_GetUid("first"); - Tk_Uid lastUid = Tk_GetUid("last"); + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) linePtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) linePtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -428,36 +502,42 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ - if (linePtr->fg == NULL) { - newGC = arrowGC = None; + state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (linePtr->outline.activeWidth > linePtr->outline.width || + linePtr->outline.activeDash.number > 0 || + linePtr->outline.activeColor != NULL || + linePtr->outline.activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = linePtr->fg->pixel; - gcValues.join_style = linePtr->joinStyle; - if (linePtr->width < 0) { - linePtr->width = 1; - } - gcValues.line_width = linePtr->width; - mask = GCForeground|GCJoinStyle|GCLineWidth; - if (linePtr->fillStipple != None) { - gcValues.stipple = linePtr->fillStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - if (linePtr->arrow == noneUid) { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(linePtr->outline)); + if (mask) { + if (linePtr->arrow == ARROWS_NONE) { gcValues.cap_style = linePtr->capStyle; mask |= GCCapStyle; } + gcValues.join_style = linePtr->joinStyle; + mask |= GCJoinStyle; newGC = Tk_GetGC(tkwin, mask, &gcValues); gcValues.line_width = 0; arrowGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = arrowGC = None; } - if (linePtr->gc != None) { - Tk_FreeGC(Tk_Display(tkwin), linePtr->gc); + if (linePtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), linePtr->outline.gc); } if (linePtr->arrowGC != None) { Tk_FreeGC(Tk_Display(tkwin), linePtr->arrowGC); } - linePtr->gc = newGC; + linePtr->outline.gc = newGC; linePtr->arrowGC = arrowGC; /* @@ -470,21 +550,26 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) linePtr->splineSteps = 100; } + if ((!linePtr->numPoints) || (state==TK_STATE_HIDDEN)) { + ComputeLineBbox(canvas, linePtr); + return TCL_OK; + } + /* * Setup arrowheads, if needed. If arrowheads are turned off, * restore the line's endpoints (they were shortened when the * arrowheads were added). */ - if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != firstUid) - && (linePtr->arrow != bothUid)) { + if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != ARROWS_FIRST) + && (linePtr->arrow != ARROWS_BOTH)) { linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; ckfree((char *) linePtr->firstArrowPtr); linePtr->firstArrowPtr = NULL; } - if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { + if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != ARROWS_LAST) + && (linePtr->arrow != ARROWS_BOTH)) { int i; i = 2*(linePtr->numPoints-1); @@ -493,15 +578,7 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } - if (linePtr->arrow != noneUid) { - if ((linePtr->arrow != firstUid) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { - Tcl_AppendResult(interp, "bad arrow spec \"", - linePtr->arrow, "\": must be none, first, last, or both", - (char *) NULL); - linePtr->arrow = noneUid; - return TCL_ERROR; - } + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } @@ -540,18 +617,10 @@ DeleteLine(canvas, itemPtr, display) { LineItem *linePtr = (LineItem *) itemPtr; + Tk_DeleteOutline(display, &(linePtr->outline)); if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } - if (linePtr->fg != NULL) { - Tk_FreeColor(linePtr->fg); - } - if (linePtr->fillStipple != None) { - Tk_FreeBitmap(display, linePtr->fillStipple); - } - if (linePtr->gc != None) { - Tk_FreeGC(display, linePtr->gc); - } if (linePtr->arrowGC != None) { Tk_FreeGC(display, linePtr->arrowGC); } @@ -588,7 +657,33 @@ ComputeLineBbox(canvas, linePtr) * recomputed. */ { double *coordPtr; - int i, width; + int i, intWidth; + double width; + Tk_State state = linePtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!(linePtr->numPoints) || (state==TK_STATE_HIDDEN)) { + linePtr->header.x1 = -1; + linePtr->header.x2 = -1; + linePtr->header.y1 = -1; + linePtr->header.y2 = -1; + return; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } coordPtr = linePtr->coordPtr; linePtr->header.x1 = linePtr->header.x2 = (int) *coordPtr; @@ -608,14 +703,66 @@ ComputeLineBbox(canvas, linePtr) i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); } - width = linePtr->width; - if (width < 1) { - width = 1; + width = linePtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + TkIncludePoint((Tk_Item *) linePtr, linePtr->firstArrowPtr); + } + if (linePtr->arrow != ARROWS_FIRST) { + TkIncludePoint((Tk_Item *) linePtr, linePtr->lastArrowPtr); + } + } + + tsoffset = &linePtr->outline.tsoffset; + if (tsoffset->flags & TK_OFFSET_INDEX) { + double *coordPtr = linePtr->coordPtr + (tsoffset->flags & ~TK_OFFSET_INDEX); + if (tsoffset->flags <= 0) { + coordPtr = linePtr->coordPtr; + if ((linePtr->arrow == ARROWS_FIRST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->firstArrowPtr; + } + } + if (tsoffset->flags > (linePtr->numPoints * 2)) { + coordPtr = linePtr->coordPtr + (linePtr->numPoints * 2); + if ((linePtr->arrow == ARROWS_LAST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->lastArrowPtr; + } + } + tsoffset->xoffset = (int) (coordPtr[0] + 0.5); + tsoffset->yoffset = (int) (coordPtr[1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = linePtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (linePtr->header.x1 + linePtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = linePtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = linePtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (linePtr->header.y1 + linePtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = linePtr->header.y2; + } + } + + intWidth = (int) (width + 0.5); + linePtr->header.x1 -= intWidth; + linePtr->header.x2 += intWidth; + linePtr->header.y1 -= intWidth; + linePtr->header.y2 += intWidth; + + if (linePtr->numPoints==1) { + linePtr->header.x1 -= 1; + linePtr->header.x2 += 1; + linePtr->header.y1 -= 1; + linePtr->header.y2 += 1; + return; } - linePtr->header.x1 -= width; - linePtr->header.x2 += width; - linePtr->header.y1 -= width; - linePtr->header.y2 += width; /* * For mitered lines, make a second pass through all the points. @@ -630,7 +777,7 @@ ComputeLineBbox(canvas, linePtr) int j; if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) width, miter, miter+2)) { + width, miter, miter+2)) { for (j = 0; j < 4; j += 2) { TkIncludePoint((Tk_Item *) linePtr, miter+j); } @@ -642,14 +789,14 @@ ComputeLineBbox(canvas, linePtr) * Add in the sizes of arrowheads, if any. */ - if (linePtr->arrow != Tk_GetUid("none")) { - if (linePtr->arrow != Tk_GetUid("last")) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); } } - if (linePtr->arrow != Tk_GetUid("first")) { + if (linePtr->arrow != ARROWS_FIRST) { for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); @@ -700,13 +847,34 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) XPoint staticPoints[MAX_STATIC_POINTS]; XPoint *pointPtr; XPoint *pPtr; - double *coordPtr; + double *coordPtr, linewidth; int i, numPoints; + Tk_State state = itemPtr->state; + Pixmap stipple = linePtr->outline.stipple; - if (linePtr->gc == None) { + if ((!linePtr->numPoints)||(linePtr->outline.gc==None)) { return; } + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + linewidth = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + if (linePtr->outline.activeWidth>linewidth) { + linewidth = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + if (linePtr->outline.disabledWidth>linewidth) { + linewidth = linePtr->outline.activeWidth; + } + } /* * Build up an array of points in screen coordinates. Use a * static array unless the line has an enormous number of points; @@ -715,7 +883,9 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); } else { numPoints = linePtr->numPoints; } @@ -727,7 +897,7 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) } if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, pointPtr, (double *) NULL); } else { @@ -745,12 +915,21 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) * GC is supposed to be read-only. */ - if (linePtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, linePtr->gc); - Tk_CanvasSetStippleOrigin(canvas, linePtr->arrowGC); + if (Tk_ChangeOutlineGC(canvas, itemPtr, &(linePtr->outline))) { + Tk_CanvasSetOffset(canvas, linePtr->arrowGC, &linePtr->outline.tsoffset); } - XDrawLines(display, drawable, linePtr->gc, pointPtr, numPoints, + if (numPoints>1) { + XDrawLines(display, drawable, linePtr->outline.gc, pointPtr, numPoints, CoordModeOrigin); + } else { + int intwidth = (int) (linewidth + 0.5); + if (intwidth<1) { + intwidth=1; + } + XFillArc(display, drawable, linePtr->outline.gc, + pointPtr->x - intwidth/2, pointPtr->y - intwidth/2, + (unsigned int)intwidth+1, (unsigned int)intwidth+1, 0, 64*360); + } if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } @@ -761,14 +940,13 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) if (linePtr->firstArrowPtr != NULL) { TkFillPolygon(canvas, linePtr->firstArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); + display, drawable, linePtr->arrowGC, NULL); } if (linePtr->lastArrowPtr != NULL) { TkFillPolygon(canvas, linePtr->lastArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); + display, drawable, linePtr->arrowGC, NULL); } - if (linePtr->fillStipple != None) { - XSetTSOrigin(display, linePtr->gc, 0, 0); + if (Tk_ResetOutlineGC(canvas, itemPtr, &(linePtr->outline))) { XSetTSOrigin(display, linePtr->arrowGC, 0, 0); } } @@ -776,6 +954,325 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) /* *-------------------------------------------------------------- * + * LineInsert -- + * + * Insert coords into a line item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +LineInsert(canvas, itemPtr, beforeThis, obj) + Tk_Canvas canvas; /* Canvas containing text item. */ + Tk_Item *itemPtr; /* Line item to be modified. */ + int beforeThis; /* Index before which new coordinates + * are to be inserted. */ + Tcl_Obj *obj; /* New coordinates to be inserted. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int length, argc, i; + double *new, *coordPtr; + Tk_State state = itemPtr->state; + Tcl_Obj **objv; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &argc, &objv) != TCL_OK) + || !argc || argc&1) { + return; + } + length = 2*linePtr->numPoints; + if (beforeThis < 0) { + beforeThis = 0; + } + if (beforeThis > length) { + beforeThis = length; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + new = (double *) ckalloc((unsigned)(sizeof(double) * (length + argc))); + for(i=0; i<beforeThis; i++) { + new[i] = linePtr->coordPtr[i]; + } + for(i=0; i<argc; i++) { + if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i], + new+(i+beforeThis))!=TCL_OK) { + Tcl_ResetResult(((TkCanvas *)canvas)->interp); + ckfree((char *) new); + return; + } + } + + for(i=beforeThis; i<length; i++) { + new[i+argc] = linePtr->coordPtr[i]; + } + if(linePtr->coordPtr) ckfree((char *)linePtr->coordPtr); + linePtr->coordPtr = new; + linePtr->numPoints = (length + argc)/2; + + if ((length>3) && (state != TK_STATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part + * of the polygon that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is not set, the canvas will do the redrawing, + * otherwise I have to do it here. + */ + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + if (beforeThis>0) {beforeThis -= 2; argc+=2; } + if ((beforeThis+argc)<length) argc+=2; + if (linePtr->smooth) { + if(beforeThis>0) { + beforeThis-=2; argc+=2; + } + if((beforeThis+argc+2)<length) { + argc+=2; + } + } + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[beforeThis+1]; + if ((linePtr->firstArrowPtr != NULL) && (beforeThis<1)) { + /* include old first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+argc)>=length)) { + /* include old last arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+beforeThis+2; + for(i=2; i<argc; i+=2) { + TkIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + + if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + if ((linePtr->firstArrowPtr != NULL) && (beforeThis>2)) { + /* include new first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+argc)<(length-2))) { + /* include new right arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * LineDeleteCoords -- + * + * Delete one or more coordinates from a line item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get + * deleted from itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +LineDeleteCoords(canvas, itemPtr, first, last) + Tk_Canvas canvas; /* Canvas containing itemPtr. */ + Tk_Item *itemPtr; /* Item in which to delete characters. */ + int first; /* Index of first character to delete. */ + int last; /* Index of last character to delete. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int count, i, first1, last1; + int length = 2*linePtr->numPoints; + double *coordPtr; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + first &= -2; + last &= -2; + + if (first < 0) { + first = 0; + } + if (last >= length) { + last = length-2; + } + if (first > last) { + return; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + first1 = first; last1 = last; + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + if (linePtr->smooth) { + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + } + + if((first1<2) && (last1 >= length-2)) { + /* + * This is some optimizing code that will result that only the part + * of the line that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is set, the redrawing has to be done here, + * otherwise the general Canvas code will take care of it. + */ + + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[first1]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[first1+1]; + if ((linePtr->firstArrowPtr != NULL) && (first1<2)) { + /* include old first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>=length-2)) { + /* include old last arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+first1+2; + for (i=first1+2; i<=last1; i+=2) { + TkIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + + count = last + 2 - first; + for (i=last+2; i<length; i++) { + linePtr->coordPtr[i-count] = linePtr->coordPtr[i]; + } + linePtr->numPoints -= count/2; + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + if ((linePtr->firstArrowPtr != NULL) && (first1<4)) { + /* include new first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>(length-4))) { + /* include new right arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * * LineToPoint -- * * Computes the distance from a given point to a given @@ -800,6 +1297,7 @@ LineToPoint(canvas, itemPtr, pointPtr) Tk_Item *itemPtr; /* Item to check against point. */ double *pointPtr; /* Pointer to x and y coordinates. */ { + Tk_State state = itemPtr->state; LineItem *linePtr = (LineItem *) itemPtr; double *coordPtr, *linePoints; double staticSpace[2*MAX_STATIC_POINTS]; @@ -817,15 +1315,32 @@ LineToPoint(canvas, itemPtr, pointPtr) * against which to do the check. */ + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { linePoints = staticSpace; } else { linePoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, linePoints); } else { @@ -833,11 +1348,19 @@ LineToPoint(canvas, itemPtr, pointPtr) linePoints = linePtr->coordPtr; } - width = (double) linePtr->width; if (width < 1.0) { width = 1.0; } + if (!numPoints || itemPtr->state==TK_STATE_HIDDEN) { + return bestDist; + } else if (numPoints == 1) { + bestDist = hypot(linePoints[0] - pointPtr[0], linePoints[1] - pointPtr[1]) + - width/2.0; + if (bestDist < 0) bestDist = 0; + return bestDist; + } + /* * The overall idea is to iterate through all of the edges of * the line, computing a polygon for each edge and testing the @@ -950,8 +1473,8 @@ LineToPoint(canvas, itemPtr, pointPtr) * If there are arrowheads, check the distance to the arrowheads. */ - if (linePtr->arrow != Tk_GetUid("none")) { - if (linePtr->arrow != Tk_GetUid("last")) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { @@ -961,7 +1484,7 @@ LineToPoint(canvas, itemPtr, pointPtr) bestDist = dist; } } - if (linePtr->arrow != Tk_GetUid("first")) { + if (linePtr->arrow != ARROWS_FIRST) { dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { @@ -1010,8 +1533,36 @@ LineToArea(canvas, itemPtr, rectPtr) LineItem *linePtr = (LineItem *) itemPtr; double staticSpace[2*MAX_STATIC_POINTS]; double *linePoints; - double width; int numPoints, result; + double radius, width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + radius = (width+1.0)/2.0; + + if ((state==TK_STATE_HIDDEN) || !linePtr->numPoints) { + return -1; + } else if (linePtr->numPoints == 1) { + double oval[4]; + oval[0] = linePtr->coordPtr[0]-radius; + oval[1] = linePtr->coordPtr[1]-radius; + oval[2] = linePtr->coordPtr[0]+radius; + oval[3] = linePtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } /* * Handle smoothed lines by generating an expanded set of points @@ -1019,14 +1570,16 @@ LineToArea(canvas, itemPtr, rectPtr) */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { linePoints = staticSpace; } else { linePoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, linePoints); } else { @@ -1038,8 +1591,7 @@ LineToArea(canvas, itemPtr, rectPtr) * Check the segments of the line. */ - width = (double) linePtr->width; - if (width < 1.0) { + if (width < 1.0) { width = 1.0; } @@ -1054,15 +1606,15 @@ LineToArea(canvas, itemPtr, rectPtr) * Check arrowheads, if any. */ - if (linePtr->arrow != Tk_GetUid("none")) { - if (linePtr->arrow != Tk_GetUid("last")) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW, rectPtr) != result) { result = 0; goto done; } } - if (linePtr->arrow != Tk_GetUid("first")) { + if (linePtr->arrow != ARROWS_FIRST) { if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW, rectPtr) != result) { result = 0; @@ -1135,7 +1687,7 @@ ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY) coordPtr[0] = originX + scaleX*(*coordPtr - originX); coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); } - if (linePtr->arrow != Tk_GetUid("none")) { + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } ComputeLineBbox(canvas, linePtr); @@ -1144,6 +1696,96 @@ ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY) /* *-------------------------------------------------------------- * + * GetLineIndex -- + * + * Parse an index into a line item and return either its value + * or an error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is + * filled in with the index (into itemPtr) corresponding to + * string. Otherwise an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetLineIndex(interp, canvas, itemPtr, obj, indexPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item for which the index is being + * specified. */ + Tcl_Obj *obj; /* Specification of a particular coord + * in itemPtr's line. */ + int *indexPtr; /* Where to store converted index. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + size_t length; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", length) == 0) { + *indexPtr = 2*linePtr->numPoints; + } else { + badIndex: + + /* + * Some of the paths here leave messages in interp->result, + * so we have to clear it out before storing our own message. + */ + + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", + (char *) NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = linePtr->coordPtr; + *indexPtr = 0; + for(i=0; i<linePtr->numPoints; i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if index is odd, make it even */ + if (*indexPtr < 0){ + *indexPtr = 0; + } else if (*indexPtr > (2*linePtr->numPoints)) { + *indexPtr = (2*linePtr->numPoints); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * * TranslateLine -- * * This procedure is called to move a line by a given amount. @@ -1217,7 +1859,7 @@ ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Used for error reporting. */ Tk_Window tkwin; /* Not used. */ - char *value; /* Textual specification of arrow shape. */ + CONST char *value; /* Textual specification of arrow shape. */ char *recordPtr; /* Pointer to item record in which to * store arrow information. */ int offset; /* Offset of shape information in widget @@ -1232,7 +1874,7 @@ ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) panic("ParseArrowShape received bogus offset"); } - if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { + if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) { syntaxError: Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad arrow shape \"", value, @@ -1297,6 +1939,117 @@ PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr) return buffer; } + +/* + *-------------------------------------------------------------- + * + * ArrowParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-arrow" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The arrow for a given item gets replaced by the arrow + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +ArrowParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register Arrows *arrowPtr = (Arrows *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *arrowPtr = ARROWS_NONE; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'n') && (strncmp(value, "none", length) == 0)) { + *arrowPtr = ARROWS_NONE; + return TCL_OK; + } + if ((c == 'f') && (strncmp(value, "first", length) == 0)) { + *arrowPtr = ARROWS_FIRST; + return TCL_OK; + } + if ((c == 'l') && (strncmp(value, "last", length) == 0)) { + *arrowPtr = ARROWS_LAST; + return TCL_OK; + } + if ((c == 'b') && (strncmp(value, "both", length) == 0)) { + *arrowPtr = ARROWS_BOTH; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad arrow spec \"", value, + "\": must be none, first, last, or both", + (char *) NULL); + *arrowPtr = ARROWS_NONE; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * ArrowPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-arrow" + * configuration option. + * + * Results: + * The return value is a string describing the arrows for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +ArrowPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Arrows *arrowPtr = (Arrows *) (widgRec + offset); + + switch (*arrowPtr) { + case ARROWS_FIRST: + return "first"; + case ARROWS_LAST: + return "last"; + case ARROWS_BOTH: + return "both"; + default: + return "none"; + } +} + /* *-------------------------------------------------------------- * @@ -1336,6 +2089,27 @@ ConfigureArrows(canvas, linePtr) double vertX, vertY; /* Position of arrowhead vertex. */ double shapeA, shapeB, shapeC; /* Adjusted coordinates (see * explanation below). */ + double width; + Tk_State state = linePtr->header.state; + + if (linePtr->numPoints <2) { + return TCL_OK; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } /* * The code below makes a tiny increase in the shape parameters @@ -1346,7 +2120,7 @@ ConfigureArrows(canvas, linePtr) shapeA = linePtr->arrowShapeA + 0.001; shapeB = linePtr->arrowShapeB + 0.001; - shapeC = linePtr->arrowShapeC + linePtr->width/2.0 + 0.001; + shapeC = linePtr->arrowShapeC + width/2.0 + 0.001; /* * If there's an arrowhead on the first point of the line, compute @@ -1354,9 +2128,9 @@ ConfigureArrows(canvas, linePtr) * line doesn't stick out past the leading edge of the arrowhead. */ - fracHeight = (linePtr->width/2.0)/shapeC; + fracHeight = (width/2.0)/shapeC; backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0; - if (linePtr->arrow != Tk_GetUid("last")) { + if (linePtr->arrow != ARROWS_LAST) { poly = linePtr->firstArrowPtr; if (poly == NULL) { poly = (double *) ckalloc((unsigned) @@ -1401,7 +2175,7 @@ ConfigureArrows(canvas, linePtr) * Similar arrowhead calculation for the last point of the line. */ - if (linePtr->arrow != Tk_GetUid("first")) { + if (linePtr->arrow != ARROWS_FIRST) { coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2); poly = linePtr->lastArrowPtr; if (poly == NULL) { @@ -1475,21 +2249,75 @@ LineToPostscript(interp, canvas, itemPtr, prepass) char buffer[64 + TCL_INTEGER_SPACE]; char *style; - if (linePtr->fg == NULL) { + double width; + XColor *color; + Pixmap stipple; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + color = linePtr->outline.color; + stipple = linePtr->outline.stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + if (linePtr->outline.activeColor!=NULL) { + color = linePtr->outline.activeColor; + } + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + if (linePtr->outline.disabledColor!=NULL) { + color = linePtr->outline.disabledColor; + } + if (linePtr->outline.disabledStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + + if (color == NULL || linePtr->numPoints<1 || linePtr->coordPtr==NULL) { return TCL_OK; } + if (linePtr->numPoints==1) { + sprintf(buffer, "%.15g %.15g translate %.15g %.15g", + linePtr->coordPtr[0], Tk_CanvasPsY(canvas, linePtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",buffer, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", (char *) NULL); + if (Tk_CanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + return TCL_OK; + } /* * Generate a path for the line's center-line (do this differently * for straight lines and smoothed lines). */ - if ((!linePtr->smooth) || (linePtr->numPoints <= 2)) { + if ((!linePtr->smooth) || (linePtr->numPoints < 3)) { Tk_CanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints); } else { - if (linePtr->fillStipple == None) { - TkMakeBezierPostscript(interp, canvas, linePtr->coordPtr, - linePtr->numPoints); + if ((stipple == None) && linePtr->smooth->postscriptProc) { + linePtr->smooth->postscriptProc(interp, canvas, + linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps); } else { /* * Special hack: Postscript printers don't appear to be able @@ -1504,13 +2332,15 @@ LineToPostscript(interp, canvas, itemPtr, prepass) double *pointPtr; int numPoints; - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); pointPtr = staticPoints; if (numPoints > MAX_STATIC_POINTS) { pointPtr = (double *) ckalloc((unsigned) (numPoints * 2 * sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, pointPtr); Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints); @@ -1524,8 +2354,6 @@ LineToPostscript(interp, canvas, itemPtr, prepass) * Set other line-drawing parameters and stroke out the line. */ - sprintf(buffer, "%d setlinewidth\n", linePtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); style = "0 setlinecap\n"; if (linePtr->capStyle == CapRound) { style = "1 setlinecap\n"; @@ -1540,17 +2368,10 @@ LineToPostscript(interp, canvas, itemPtr, prepass) style = "2 setlinejoin\n"; } Tcl_AppendResult(interp, style, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, linePtr->fg) != TCL_OK) { + + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(linePtr->outline)) != TCL_OK) { return TCL_ERROR; - }; - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } /* @@ -1558,7 +2379,7 @@ LineToPostscript(interp, canvas, itemPtr, prepass) */ if (linePtr->firstArrowPtr != NULL) { - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } @@ -1568,7 +2389,7 @@ LineToPostscript(interp, canvas, itemPtr, prepass) } } if (linePtr->lastArrowPtr != NULL) { - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } if (ArrowheadPostscript(interp, canvas, linePtr, @@ -1610,10 +2431,28 @@ ArrowheadPostscript(interp, canvas, linePtr, arrowPtr) double *arrowPtr; /* Pointer to first of five points * describing arrowhead polygon. */ { + Pixmap stipple; + Tk_State state = linePtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + stipple = linePtr->outline.stipple; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { return TCL_ERROR; } diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c index ad5eb80..f64ccd6 100644 --- a/generic/tkCanvPoly.c +++ b/generic/tkCanvPoly.c @@ -9,12 +9,13 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvPoly.c,v 1.3 1999/04/16 01:51:11 stanton Exp $ + * RCS: @(#) $Id: tkCanvPoly.c,v 1.4 1999/12/14 06:52:26 hobbs Exp $ */ #include <stdio.h> #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each polygon item. @@ -23,7 +24,8 @@ typedef struct PolygonItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ - int numPoints; /* Number of points in polygon (always >= 3). + Tk_Outline outline; /* Outline structure */ + int numPoints; /* Number of points in polygon. * Polygon is always closed. */ int pointsAllocated; /* Number of points for which space is * allocated at *coordPtr. */ @@ -31,13 +33,16 @@ typedef struct PolygonItem { * x- and y-coords of all points in polygon. * X-coords are even-valued indices, y-coords * are corresponding odd-valued indices. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ - GC outlineGC; /* Graphics context for drawing outline. */ + int joinStyle; /* Join style for outline */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Foreground color for polygon. */ + XColor *activeFillColor; /* Foreground color for polygon if state is active. */ + XColor *disabledFillColor; /* Foreground color for polygon if state is disabled. */ Pixmap fillStipple; /* Stipple bitmap for filling polygon. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling polygon if state is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling polygon if state is disabled. */ GC fillGC; /* Graphics context for filling polygon. */ - int smooth; /* Non-zero means draw shape smoothed (i.e. + Tk_SmoothMethod *smooth; /* Non-zero means draw shape smoothed (i.e. * with Bezier splines). */ int splineSteps; /* Number of steps in each spline segment. */ int autoClosed; /* Zero means the given polygon was closed, @@ -48,25 +53,106 @@ typedef struct PolygonItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption smoothOption = { + (Tk_OptionParseProc *) TkSmoothParseProc, + TkSmoothPrintProc, (ClientData) NULL +}; +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(PolygonItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(PolygonItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(PolygonItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, + "round", Tk_Offset(PolygonItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(PolygonItem, tsoffset), + TK_CONFIG_NULL_OK, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, + (char *) NULL, Tk_Offset(PolygonItem, outline.color), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(PolygonItem, outline.tsoffset), + TK_CONFIG_NULL_OK, &offsetOption}, + {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.stipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(PolygonItem, smooth), + TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(PolygonItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -79,18 +165,25 @@ static void ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas, PolygonItem *polyPtr)); static int ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height)); +static int GetPolygonIndex _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, + Tcl_Obj *obj, int *indexPtr)); static int PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); +static void PolygonDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int first, int last)); +static void PolygonInsert _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj)); static int PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -117,18 +210,18 @@ Tk_ItemType tkPolygonType = { PolygonCoords, /* coordProc */ DeletePolygon, /* deleteProc */ DisplayPolygon, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ PolygonToPoint, /* pointProc */ PolygonToArea, /* areaProc */ PolygonToPostscript, /* postscriptProc */ ScalePolygon, /* scaleProc */ TranslatePolygon, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ + (Tk_ItemIndexProc *) GetPolygonIndex,/* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemInsertProc *) PolygonInsert,/* insertProc */ + PolygonDeleteCoords, /* dTextProc */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -167,34 +260,32 @@ CreatePolygon(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing polygon. */ + Tcl_Obj *CONST argv[]; /* Arguments describing polygon. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; int i; - if (argc < 6) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, - " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?\"", (char *) NULL); - return TCL_ERROR; - } - /* * Carry out initialization that is needed in order to clean * up after errors during the the remainder of this procedure. */ + Tk_CreateOutline(&(polyPtr->outline)); polyPtr->numPoints = 0; polyPtr->pointsAllocated = 0; polyPtr->coordPtr = NULL; - polyPtr->width = 1; - polyPtr->outlineColor = NULL; - polyPtr->outlineGC = None; + polyPtr->joinStyle = JoinRound; + polyPtr->tsoffset.flags = 0; + polyPtr->tsoffset.xoffset = 0; + polyPtr->tsoffset.yoffset = 0; polyPtr->fillColor = NULL; + polyPtr->activeFillColor = NULL; + polyPtr->disabledFillColor = NULL; polyPtr->fillStipple = None; + polyPtr->activeFillStipple = None; + polyPtr->disabledFillStipple = None; polyPtr->fillGC = None; - polyPtr->smooth = 0; + polyPtr->smooth = (Tk_SmoothMethod *) NULL; polyPtr->splineSteps = 12; polyPtr->autoClosed = 0; @@ -204,13 +295,14 @@ CreatePolygon(interp, canvas, itemPtr, argc, argv) * start with a digit or a minus sign followed by a digit. */ - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) { + for (i = 0; i < argc; i++) { + char *arg = Tcl_GetStringFromObj((Tcl_Obj *) argv[i], NULL); + if ((arg[0] == '-') && (arg[1] >= 'a') + && (arg[1] <= 'z')) { break; } } - if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { + if (i && PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { goto error; } @@ -250,11 +342,10 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; int i, numPoints; if (argc == 0) { @@ -262,16 +353,21 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) * Print the coords used to create the polygon. If we auto * closed the polygon then we don't report the last point. */ + Tcl_Obj *subobj, *obj = Tcl_NewObj(); for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) { - Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer); - Tcl_AppendElement(interp, buffer); + subobj = Tcl_NewDoubleObj(polyPtr->coordPtr[i]); + Tcl_ListObjAppendElement(interp, obj, subobj); } - } else if (argc < 6) { - Tcl_AppendResult(interp, - "too few coordinates for polygon: must have at least 6", - (char *) NULL); - return TCL_ERROR; - } else if (argc & 1) { + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (argc == 1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } + } + if (argc & 1) { Tcl_AppendResult(interp, "odd number of coordinates specified for polygon", (char *) NULL); @@ -284,8 +380,8 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) } /* - * One extra point gets allocated here, just in case we have - * to add another point to close the polygon. + * One extra point gets allocated here, because we always + * add another point to close the polygon. */ polyPtr->coordPtr = (double *) ckalloc((unsigned) @@ -293,20 +389,20 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) polyPtr->pointsAllocated = numPoints+1; } for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], + if (Tk_CanvasGetCoordFromObj(interp, canvas, argv[i], &polyPtr->coordPtr[i]) != TCL_OK) { return TCL_ERROR; } } polyPtr->numPoints = numPoints; polyPtr->autoClosed = 0; - + /* * Close the polygon if it isn't already closed. */ - if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0]) - || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) { + if (argc>2 && ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0]) + || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1]))) { polyPtr->autoClosed = 1; polyPtr->numPoints++; polyPtr->coordPtr[argc] = polyPtr->coordPtr[0]; @@ -342,7 +438,7 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Polygon item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; @@ -350,10 +446,13 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) GC newGC; unsigned long mask; Tk_Window tkwin; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) polyPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) polyPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -362,31 +461,66 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ - if (polyPtr->width < 1) { - polyPtr->width = 1; - } - if (polyPtr->outlineColor == NULL) { - newGC = None; + state = itemPtr->state; + + if (polyPtr->outline.activeWidth > polyPtr->outline.width || + polyPtr->outline.activeDash.number > 0 || + polyPtr->outline.activeColor != NULL || + polyPtr->outline.activeStipple != None || + polyPtr->activeFillColor != NULL || + polyPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = polyPtr->outlineColor->pixel; - gcValues.line_width = polyPtr->width; + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputePolygonBbox(canvas, polyPtr); + return TCL_OK; + } + + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, &(polyPtr->outline)); + if (mask) { gcValues.cap_style = CapRound; - gcValues.join_style = JoinRound; - mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle; + gcValues.join_style = polyPtr->joinStyle; + mask |= GCCapStyle|GCJoinStyle; newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (polyPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), polyPtr->outline.gc); } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC); + polyPtr->outline.gc = newGC; + + color = polyPtr->fillColor; + stipple = polyPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->activeFillColor!=NULL) { + color = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->disabledFillColor!=NULL) { + color = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + stipple = polyPtr->disabledFillStipple; + } } - polyPtr->outlineGC = newGC; - if (polyPtr->fillColor == NULL) { + if (color == NULL) { newGC = None; } else { - gcValues.foreground = polyPtr->fillColor->pixel; + gcValues.foreground = color->pixel; mask = GCForeground; - if (polyPtr->fillStipple != None) { - gcValues.stipple = polyPtr->fillStipple; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } @@ -437,20 +571,27 @@ DeletePolygon(canvas, itemPtr, display) { PolygonItem *polyPtr = (PolygonItem *) itemPtr; + Tk_DeleteOutline(display,&(polyPtr->outline)); if (polyPtr->coordPtr != NULL) { ckfree((char *) polyPtr->coordPtr); } if (polyPtr->fillColor != NULL) { Tk_FreeColor(polyPtr->fillColor); } + if (polyPtr->activeFillColor != NULL) { + Tk_FreeColor(polyPtr->activeFillColor); + } + if (polyPtr->disabledFillColor != NULL) { + Tk_FreeColor(polyPtr->disabledFillColor); + } if (polyPtr->fillStipple != None) { Tk_FreeBitmap(display, polyPtr->fillStipple); } - if (polyPtr->outlineColor != NULL) { - Tk_FreeColor(polyPtr->outlineColor); + if (polyPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, polyPtr->activeFillStipple); } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(display, polyPtr->outlineGC); + if (polyPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, polyPtr->disabledFillStipple); } if (polyPtr->fillGC != None) { Tk_FreeGC(display, polyPtr->fillGC); @@ -483,27 +624,159 @@ ComputePolygonBbox(canvas, polyPtr) { double *coordPtr; int i; + double width; + Tk_State state = polyPtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (polyPtr->coordPtr == NULL || (polyPtr->numPoints < 1) || (state==TK_STATE_HIDDEN)) { + polyPtr->header.x1 = polyPtr->header.x2 = + polyPtr->header.y1 = polyPtr->header.y2 = -1; + return; + } + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)polyPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } coordPtr = polyPtr->coordPtr; polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr; polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1]; - for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints; + /* + * Compute the bounding box of all the points in the polygon, + * then expand in all directions by the outline's width to take + * care of butting or rounded corners and projecting or + * rounded caps. This expansion is an overestimate (worst-case + * is square root of two over two) but it's simple. Don't do + * anything special for curves. This causes an additional + * overestimate in the bounding box, but is faster. + */ + + for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints-1; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) polyPtr, coordPtr); } + tsoffset = &polyPtr->tsoffset; + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index < 0) { + index = 0; + } + } + index %= (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index <0) { + index += (polyPtr->numPoints - polyPtr->autoClosed) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + + if (polyPtr->outline.gc != None) { + tsoffset = &polyPtr->outline.tsoffset; + if (tsoffset) { + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - 1) * 2; + } + index %= (polyPtr->numPoints - 1) * 2; + if (index <0) { + index += (polyPtr->numPoints - 1) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + } + + i = (int) ((width+1.5)/2.0); + polyPtr->header.x1 -= i; + polyPtr->header.x2 += i; + polyPtr->header.y1 -= i; + polyPtr->header.y2 += i; + + /* + * For mitered lines, make a second pass through all the points. + * Compute the locations of the two miter vertex points and add + * those into the bounding box. + */ + + if (polyPtr->joinStyle == JoinMiter) { + double miter[4]; + int j; + coordPtr = polyPtr->coordPtr; + if (polyPtr->numPoints>3) { + if (TkGetMiterPoints(coordPtr+2*(polyPtr->numPoints-2), + coordPtr, coordPtr+2, width, + miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkIncludePoint((Tk_Item *) polyPtr, miter+j); + } + } + } + for (i = polyPtr->numPoints ; i >= 3; + i--, coordPtr += 2) { + + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkIncludePoint((Tk_Item *) polyPtr, miter+j); + } + } + } + } + } + /* - * Expand bounding box in all directions to account for the outline, - * which can stick out beyond the polygon. Add one extra pixel of - * fudge, just in case X rounds differently than we do. + * Add one more pixel of fudge factor just to be safe (e.g. + * X may round differently than we do). */ - i = (polyPtr->width+1)/2 + 1; - polyPtr->header.x1 -= i; - polyPtr->header.x2 += i; - polyPtr->header.y1 -= i; - polyPtr->header.y2 += i; + polyPtr->header.x1 -= 1; + polyPtr->header.x2 += 1; + polyPtr->header.y1 -= 1; + polyPtr->header.y2 += 1; } /* @@ -567,7 +840,7 @@ TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC) * allocated. */ - if (gc != None) { + if (gc != None && numPoints>3) { XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex, CoordModeOrigin); } @@ -609,24 +882,80 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) * must be redisplayed (not used). */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; + Tk_State state = itemPtr->state; + Pixmap stipple = polyPtr->fillStipple; + double linewidth = polyPtr->outline.width; - if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) { + if (((polyPtr->fillGC == None) && (polyPtr->outline.gc == None)) || + (polyPtr->numPoints < 1) || + (polyPtr->numPoints < 3 && polyPtr->outline.gc == None)) { return; } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>linewidth) { + linewidth = polyPtr->outline.activeWidth; + } + if (polyPtr->activeFillStipple != None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + linewidth = polyPtr->outline.disabledWidth; + } + if (polyPtr->disabledFillStipple != None) { + stipple = polyPtr->disabledFillStipple; + } + } /* * If we're stippling then modify the stipple offset in the GC. Be * sure to reset the offset when done, since the GC is supposed to be * read-only. */ - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { - Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC); + if (stipple != None) { + Tk_TSOffset *tsoffset = &polyPtr->tsoffset; + int w=0; int h=0; + int flags = tsoffset->flags; + if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, polyPtr->fillGC, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; } + Tk_ChangeOutlineGC(canvas, itemPtr, &(polyPtr->outline)); - if (!polyPtr->smooth) { + if(polyPtr->numPoints < 3) { + short x,y; + int intLineWidth = (int) (linewidth + 0.5); + if (intLineWidth < 1) { + intLineWidth = 1; + } + Tk_CanvasDrawableCoords(canvas, polyPtr->coordPtr[0], + polyPtr->coordPtr[1], &x,&y); + XFillArc(display, drawable, polyPtr->outline.gc, + x - intLineWidth/2, y - intLineWidth/2, + (unsigned int)intLineWidth+1, (unsigned int)intLineWidth+1, + 0, 64*360); + } else if (!polyPtr->smooth || polyPtr->numPoints < 4) { TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints, - display, drawable, polyPtr->fillGC, polyPtr->outlineGC); + display, drawable, polyPtr->fillGC, polyPtr->outline.gc); } else { int numPoints; XPoint staticPoints[MAX_STATIC_POINTS]; @@ -637,29 +966,32 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) * spline points rather than the original points. */ - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { pointPtr = staticPoints; } else { pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, pointPtr, (double *) NULL); if (polyPtr->fillGC != None) { XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr, numPoints, Complex, CoordModeOrigin); } - if (polyPtr->outlineGC != None) { - XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr, + if (polyPtr->outline.gc != None) { + XDrawLines(display, drawable, polyPtr->outline.gc, pointPtr, numPoints, CoordModeOrigin); } if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } } - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { + Tk_ResetOutlineGC(canvas, itemPtr, &(polyPtr->outline)); + if (stipple != None) { XSetTSOrigin(display, polyPtr->fillGC, 0, 0); } } @@ -667,6 +999,203 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) /* *-------------------------------------------------------------- * + * PolygonInsert -- + * + * Insert coords into a polugon item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +PolygonInsert(canvas, itemPtr, beforeThis, obj) + Tk_Canvas canvas; /* Canvas containing text item. */ + Tk_Item *itemPtr; /* Line item to be modified. */ + int beforeThis; /* Index before which new coordinates + * are to be inserted. */ + Tcl_Obj *obj; /* New coordinates to be inserted. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int length, argc, i; + Tcl_Obj **objv; + double *new; + Tk_State state = itemPtr->state; + + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &argc, &objv) != TCL_OK) + || !argc || argc&1) { + return; + } + length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + while(beforeThis>length) beforeThis-=length; + while(beforeThis<0) beforeThis+=length; + new = (double *) ckalloc((unsigned)(sizeof(double) * (length + 2 + argc))); + for (i=0; i<beforeThis; i++) { + new[i] = polyPtr->coordPtr[i]; + } + for (i=0; i<argc; i++) { + if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i], + new+(i+beforeThis))!=TCL_OK) { + ckfree((char *) new); + return; + } + } + + for(i=beforeThis; i<length; i++) { + new[i+argc] = polyPtr->coordPtr[i]; + } + if(polyPtr->coordPtr) ckfree((char *) polyPtr->coordPtr); + length+=argc; + polyPtr->coordPtr = new; + polyPtr->numPoints = (length/2) + polyPtr->autoClosed; + + /* + * Close the polygon if it isn't already closed, or remove autoclosing + * if the user's coordinates are now closed. + */ + + if (polyPtr->autoClosed) { + if ((new[length-2] == new[0]) && (new[length-1] == new[1])) { + polyPtr->autoClosed = 0; + polyPtr->numPoints--; + } + } + else { + if ((new[length-2] != new[0]) || (new[length-1] != new[1])) { + polyPtr->autoClosed = 1; + polyPtr->numPoints++; + } + } + + new[length] = new[0]; + new[length+1] = new[1]; + if (((length-argc)>3) && (state != TK_STATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part + * of the polygon that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is not set, the canvas will do the redrawing, + * otherwise I have to do it here. + */ + double width; + int j; + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + /* + * The header elements that normally are used for the + * bounding box, are now used to calculate the bounding + * box for only the part that has to be redrawn. That + * doesn't matter, because afterwards the bounding + * box has to be re-calculated anyway. + */ + + itemPtr->x1 = itemPtr->x2 = (int) polyPtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) polyPtr->coordPtr[beforeThis+1]; + beforeThis-=2; argc+=4; + if(polyPtr->smooth) { + beforeThis-=2; argc+=4; + } /* be carefull; beforeThis could now be negative */ + for(i=beforeThis; i<beforeThis+argc; i+=2) { + j=i; + if(j<0) j+=length; + if(j>=length) j-=length; + TkIncludePoint(itemPtr, polyPtr->coordPtr+j); + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + itemPtr->x1 -= (int) width; itemPtr->y1 -= (int) width; + itemPtr->x2 += (int) width; itemPtr->y2 += (int) width; + Tk_CanvasEventuallyRedraw(canvas, + itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * PolygonDeleteCoords -- + * + * Delete one or more coordinates from a polygon item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get + * deleted from itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +PolygonDeleteCoords(canvas, itemPtr, first, last) + Tk_Canvas canvas; /* Canvas containing itemPtr. */ + Tk_Item *itemPtr; /* Item in which to delete characters. */ + int first; /* Index of first character to delete. */ + int last; /* Index of last character to delete. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int count, i; + int length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + + while(first>=length) first-=length; + while(first<0) first+=length; + while(last>=length) last-=length; + while(last<0) last+=length; + + first &= -2; + last &= -2; + + count = last + 2 - first; + if(count<=0) count +=length; + + if(count >= length) { + polyPtr->numPoints = 0; + if(polyPtr->coordPtr != NULL) { + ckfree((char *) polyPtr->coordPtr); + } + ComputePolygonBbox(canvas, polyPtr); + return; + } + + if(last>=first) { + for(i=last+2; i<length; i++) { + polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i]; + } + } else { + for(i=last; i<=first; i++) { + polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i]; + } + } + polyPtr->coordPtr[length-count] = polyPtr->coordPtr[0]; + polyPtr->coordPtr[length-count+1] = polyPtr->coordPtr[1]; + polyPtr->numPoints -= count/2; + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * * PolygonToPoint -- * * Computes the distance from a given point to a given @@ -692,41 +1221,169 @@ PolygonToPoint(canvas, itemPtr, pointPtr) double *pointPtr; /* Pointer to x and y coordinates. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, distance; + double *coordPtr, *polyPoints; double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints; + double poly[10]; + double radius; + double bestDist, dist; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + double width; + Tk_State state = itemPtr->state; + + bestDist = 1.0e36; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + radius = width/2.0; - if (!polyPtr->smooth) { - distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints, - pointPtr); - } else { - /* - * Smoothed polygon. Generate a new set of points and use them - * for comparison. - */ - - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + /* + * Handle smoothed polygons by generating an expanded set of points + * against which to do the check. + */ + + if ((polyPtr->smooth) && (polyPtr->numPoints>2)) { + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; + polyPoints = staticSpace; } else { - coordPtr = (double *) ckalloc((unsigned) + polyPoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); - distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr); - if (coordPtr != staticSpace) { - ckfree((char *) coordPtr); + polyPoints); + } else { + numPoints = polyPtr->numPoints; + polyPoints = polyPtr->coordPtr; + } + + bestDist = TkPolygonToPoint(polyPoints, numPoints, pointPtr); + if (bestDist<=0.0) { + goto donepoint; + } + if ((polyPtr->outline.gc != None) && (polyPtr->joinStyle == JoinRound)) { + dist = bestDist - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else { + bestDist = dist; } } - if (polyPtr->outlineColor != NULL) { - distance -= polyPtr->width/2.0; - if (distance < 0) { - distance = 0; + + if ((polyPtr->outline.gc == None) || (width <= 1)) goto donepoint; + + /* + * The overall idea is to iterate through all of the edges of + * the line, computing a polygon for each edge and testing the + * point against that polygon. In addition, there are additional + * tests to deal with rounded joints and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints, coordPtr = polyPoints; count >= 2; + count--, coordPtr += 2) { + + /* + * If rounding is done around the first point then compute + * the distance between the point and the point. + */ + + if (polyPtr->joinStyle == JoinRound) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } } + + /* + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. + */ + + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, (double) width, + 0, poly, poly+2); + } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, (double) width, 0, + poly, poly+2); + + /* + * If this line uses beveled joints, then check the distance + * to a polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the mitered joint. + */ + + if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + donepoint: + if ((polyPoints != staticSpace) && polyPoints != polyPtr->coordPtr) { + ckfree((char *) polyPoints); } - return distance; + return bestDist; } /* @@ -759,75 +1416,179 @@ PolygonToArea(canvas, itemPtr, rectPtr) * area. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, rect2[4], halfWidth; + double *coordPtr; double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints, result; + double *polyPoints, poly[10]; + double radius; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + int inside; /* Tentative guess about what to return, + * based on all points seen so far: one + * means everything seen so far was + * inside the area; -1 means everything + * was outside the area. 0 means overlap + * has been found. */ + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + + radius = width/2.0; + inside = -1; + + if ((state==TK_STATE_HIDDEN) || polyPtr->numPoints<2) { + return -1; + } else if (polyPtr->numPoints <3) { + double oval[4]; + oval[0] = polyPtr->coordPtr[0]-radius; + oval[1] = polyPtr->coordPtr[1]-radius; + oval[2] = polyPtr->coordPtr[0]+radius; + oval[3] = polyPtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } /* * Handle smoothed polygons by generating an expanded set of points * against which to do the check. */ if (polyPtr->smooth) { - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; + polyPoints = staticSpace; } else { - coordPtr = (double *) ckalloc((unsigned) + polyPoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); + polyPoints); } else { numPoints = polyPtr->numPoints; - coordPtr = polyPtr->coordPtr; + polyPoints = polyPtr->coordPtr; } - if (polyPtr->width <= 1) { - /* - * The outline of the polygon doesn't stick out, so we can - * do a simple check. - */ - - result = TkPolygonToArea(coordPtr, numPoints, rectPtr); + if (polyPtr->fillGC != None) { + inside = TkPolygonToArea(polyPoints, numPoints, rectPtr); + if (inside==0) goto donearea; } else { + if ((polyPoints[0] >= rectPtr[0]) + && (polyPoints[0] <= rectPtr[2]) + && (polyPoints[1] >= rectPtr[1]) + && (polyPoints[1] <= rectPtr[3])) { + inside = 1; + } + } + + if (polyPtr->outline.gc == None) goto donearea ; + + + /* + * Iterate through all of the edges of the line, computing a polygon + * for each edge and testing the area against that polygon. In + * addition, there are additional tests to deal with rounded joints + * and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints, coordPtr = polyPoints; count >= 2; + count--, coordPtr += 2) { + /* - * The polygon has a wide outline, so the check is more complicated. - * First, check the line segments to see if they overlap the area. + * If rounding is done around the first point of the edge + * then test a circular region around the point with the + * area. */ - result = TkThickPolyLineToArea(coordPtr, numPoints, - (double) polyPtr->width, CapRound, JoinRound, rectPtr); - if (result >= 0) { - goto done; + if (polyPtr->joinStyle == JoinRound) { + poly[0] = coordPtr[0] - radius; + poly[1] = coordPtr[1] - radius; + poly[2] = coordPtr[0] + radius; + poly[3] = coordPtr[1] + radius; + if (TkOvalToArea(poly, rectPtr) != inside) { + inside = 0; + goto donearea; + } } /* - * There is no overlap between the polygon's outline and the - * rectangle. This means either the rectangle is entirely outside - * the polygon or entirely inside. To tell the difference, - * see whether the polygon (with 0 outline width) overlaps the - * rectangle bloated by half the outline width. + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. */ - halfWidth = polyPtr->width/2.0; - rect2[0] = rectPtr[0] - halfWidth; - rect2[1] = rectPtr[1] - halfWidth; - rect2[2] = rectPtr[2] + halfWidth; - rect2[3] = rectPtr[3] + halfWidth; - if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) { - result = -1; + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, width, + 0, poly, poly+2); + } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; } else { - result = 0; + TkGetButtPoints(coordPtr+2, coordPtr, width, 0, + poly, poly+2); + + /* + * If the last joint was beveled, then also check a + * polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the beveled joint. + */ + + if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, width, + 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; } } - done: - if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) { - ckfree((char *) coordPtr); + donearea: + if ((polyPoints != staticSpace) && (polyPoints != polyPtr->coordPtr)) { + ckfree((char *) polyPoints); } - return result; + return inside; } /* @@ -873,6 +1634,101 @@ ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY) /* *-------------------------------------------------------------- * + * GetPolygonIndex -- + * + * Parse an index into a polygon item and return either its value + * or an error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is + * filled in with the index (into itemPtr) corresponding to + * string. Otherwise an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPolygonIndex(interp, canvas, itemPtr, obj, indexPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item for which the index is being + * specified. */ + Tcl_Obj *obj; /* Specification of a particular coord + * in itemPtr's line. */ + int *indexPtr; /* Where to store converted index. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + size_t length; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", length) == 0) { + *indexPtr = 2*(polyPtr->numPoints - polyPtr->autoClosed); + } else { + badIndex: + + /* + * Some of the paths here leave messages in interp->result, + * so we have to clear it out before storing our own message. + */ + + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", + (char *) NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = polyPtr->coordPtr; + *indexPtr = 0; + for(i=0; i<(polyPtr->numPoints-1); i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + int count = 2*(polyPtr->numPoints - polyPtr->autoClosed); + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if odd, make it even */ + if (count) { + if (*indexPtr > 0) { + *indexPtr = ((*indexPtr - 2) % count) + 2; + } else { + *indexPtr = -((-(*indexPtr)) % count); + } + } else { + *indexPtr = 0; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * * TranslatePolygon -- * * This procedure is called to move a polygon by a given @@ -941,29 +1797,103 @@ PolygonToPostscript(interp, canvas, itemPtr, prepass) * final Postscript is being created. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; + char *style; + XColor *color; + XColor *fillColor; + Pixmap stipple; + Pixmap fillStipple; + Tk_State state = itemPtr->state; + double width; + + if (polyPtr->numPoints<2 || polyPtr->coordPtr==NULL) { + return TCL_OK; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + color = polyPtr->outline.color; + stipple = polyPtr->fillStipple; + fillColor = polyPtr->fillColor; + fillStipple = polyPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + if (polyPtr->outline.activeColor!=NULL) { + color = polyPtr->outline.activeColor; + } + if (polyPtr->outline.activeStipple!=None) { + stipple = polyPtr->outline.activeStipple; + } + if (polyPtr->activeFillColor!=NULL) { + fillColor = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + fillStipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + if (polyPtr->outline.disabledColor!=NULL) { + color = polyPtr->outline.disabledColor; + } + if (polyPtr->outline.disabledStipple!=None) { + stipple = polyPtr->outline.disabledStipple; + } + if (polyPtr->disabledFillColor!=NULL) { + fillColor = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + fillStipple = polyPtr->disabledFillStipple; + } + } + if (polyPtr->numPoints==2) { + char string[128]; + sprintf(string, "%.15g %.15g translate %.15g %.15g", + polyPtr->coordPtr[0], Tk_CanvasPsY(canvas, polyPtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",string, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", (char *) NULL); + if (Tk_CanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + return TCL_OK; + } /* * Fill the area of the polygon. */ - if (polyPtr->fillColor != NULL) { - if (!polyPtr->smooth) { + if (fillColor != NULL && polyPtr->numPoints>3) { + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, polyPtr->numPoints); } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); } - if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; } - if (polyPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "eoclip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (polyPtr->outlineColor != NULL) { + if (color != NULL) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -975,25 +1905,29 @@ PolygonToPostscript(interp, canvas, itemPtr, prepass) * Now draw the outline, if there is one. */ - if (polyPtr->outlineColor != NULL) { - char string[32 + TCL_INTEGER_SPACE]; + if (color != NULL) { - if (!polyPtr->smooth) { + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, polyPtr->numPoints); } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); } - sprintf(string, "%d setlinewidth\n", polyPtr->width); - Tcl_AppendResult(interp, string, - "1 setlinecap\n1 setlinejoin\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor) - != TCL_OK) { + if (polyPtr->joinStyle == JoinRound) { + style = "1"; + } else if (polyPtr->joinStyle == JoinBevel) { + style = "2"; + } else { + style = "0"; + } + Tcl_AppendResult(interp, style," setlinejoin 1 setlinecap\n", + (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(polyPtr->outline)) != TCL_OK) { return TCL_ERROR; } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } return TCL_OK; } diff --git a/generic/tkCanvPs.c b/generic/tkCanvPs.c index 4c99b15..c234320 100644 --- a/generic/tkCanvPs.c +++ b/generic/tkCanvPs.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvPs.c,v 1.5 1999/04/16 01:51:11 stanton Exp $ + * RCS: @(#) $Id: tkCanvPs.c,v 1.6 1999/12/14 06:52:26 hobbs Exp $ */ #include "tkInt.h" @@ -68,6 +68,8 @@ typedef struct TkPostscriptInfo { * the pre-pass that collects font information, * so the Postscript generated isn't * relevant. */ + int prolog; /* Non-zero means output should contain + the file prolog.ps in the header. */ } TkPostscriptInfo; /* @@ -99,6 +101,8 @@ static Tk_ConfigSpec configSpecs[] = { "", Tk_Offset(TkPostscriptInfo, pageXString), 0}, {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, "", Tk_Offset(TkPostscriptInfo, pageYString), 0}, + {TK_CONFIG_BOOLEAN, "-prolog", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, prolog), 0}, {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, "", Tk_Offset(TkPostscriptInfo, rotate), 0}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, @@ -124,7 +128,7 @@ static CONST char * CONST prolog[]= { \n\ % This is a standard prolog for Postscript generated by Tk's canvas\n\ % widget.\n\ -% RCS: @(#) $Id: tkCanvPs.c,v 1.5 1999/04/16 01:51:11 stanton Exp $\n\ +% RCS: @(#) $Id: tkCanvPs.c,v 1.6 1999/12/14 06:52:26 hobbs Exp $\n\ \n\ % The definitions below just define all of the variables used in\n\ % any of the procedures here. This is needed for obscure reasons\n\ @@ -461,13 +465,15 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * to know that argv[1] is * "postscript". */ { - TkPostscriptInfo psInfo, *oldInfoPtr; + TkPostscriptInfo psInfo; + Tk_PostscriptInfo oldInfoPtr; int result; Tk_Item *itemPtr; #define STRING_LENGTH 400 char string[STRING_LENGTH+1], *p; time_t now; size_t length; + Tk_Window tkwin = canvasPtr->tkwin; int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of * area to be marked up, measured * in canvas units from the positioning @@ -487,8 +493,8 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *---------------------------------------------------------------- */ - oldInfoPtr = canvasPtr->psInfoPtr; - canvasPtr->psInfoPtr = &psInfo; + oldInfoPtr = canvasPtr->psInfo; + canvasPtr->psInfo = (Tk_PostscriptInfo) &psInfo; psInfo.x = canvasPtr->xOrigin; psInfo.y = canvasPtr->yOrigin; psInfo.width = -1; @@ -510,8 +516,9 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) psInfo.channelName = NULL; psInfo.chan = NULL; psInfo.prepass = 0; + psInfo.prolog = 1; Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); - result = Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, + result = Tk_ConfigureWidget(interp, tkwin, configSpecs, argc-2, argv+2, (char *) &psInfo, TK_CONFIG_ARGV_ONLY); if (result != TCL_OK) { @@ -519,41 +526,41 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } if (psInfo.width == -1) { - psInfo.width = Tk_Width(canvasPtr->tkwin); + psInfo.width = Tk_Width(tkwin); } if (psInfo.height == -1) { - psInfo.height = Tk_Height(canvasPtr->tkwin); + psInfo.height = Tk_Height(tkwin); } psInfo.x2 = psInfo.x + psInfo.width; psInfo.y2 = psInfo.y + psInfo.height; if (psInfo.pageXString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageXString, + if (GetPostscriptPoints(interp, psInfo.pageXString, &psInfo.pageX) != TCL_OK) { goto cleanup; } } if (psInfo.pageYString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageYString, + if (GetPostscriptPoints(interp, psInfo.pageYString, &psInfo.pageY) != TCL_OK) { goto cleanup; } } if (psInfo.pageWidthString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageWidthString, + if (GetPostscriptPoints(interp, psInfo.pageWidthString, &psInfo.scale) != TCL_OK) { goto cleanup; } psInfo.scale /= psInfo.width; } else if (psInfo.pageHeightString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageHeightString, + if (GetPostscriptPoints(interp, psInfo.pageHeightString, &psInfo.scale) != TCL_OK) { goto cleanup; } psInfo.scale /= psInfo.height; } else { - psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(canvasPtr->tkwin)); - psInfo.scale /= WidthOfScreen(Tk_Screen(canvasPtr->tkwin)); + psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tkwin)); + psInfo.scale /= WidthOfScreen(Tk_Screen(tkwin)); } switch (psInfo.pageAnchor) { case TK_ANCHOR_NW: @@ -601,7 +608,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } else if (strncmp(psInfo.colorMode, "color", length) == 0) { psInfo.colorLevel = 2; } else { - Tcl_AppendResult(canvasPtr->interp, "bad color mode \"", + Tcl_AppendResult(interp, "bad color mode \"", psInfo.colorMode, "\": must be monochrome, ", "gray, or color", (char *) NULL); goto cleanup; @@ -615,7 +622,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ if (psInfo.channelName != NULL) { - Tcl_AppendResult(canvasPtr->interp, "can't specify both -file", + Tcl_AppendResult(interp, "can't specify both -file", " and -channel", (char *) NULL); result = TCL_ERROR; goto cleanup; @@ -626,18 +633,18 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * the -file specification. */ - if (Tcl_IsSafe(canvasPtr->interp)) { - Tcl_AppendResult(canvasPtr->interp, "can't specify -file in a", + if (Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't specify -file in a", " safe interpreter", (char *) NULL); result = TCL_ERROR; goto cleanup; } - p = Tcl_TranslateFileName(canvasPtr->interp, psInfo.fileName, &buffer); + p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer); if (p == NULL) { goto cleanup; } - psInfo.chan = Tcl_OpenFileChannel(canvasPtr->interp, p, "w", 0666); + psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666); Tcl_DStringFree(&buffer); if (psInfo.chan == NULL) { goto cleanup; @@ -652,14 +659,14 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * is open for writing. */ - psInfo.chan = Tcl_GetChannel(canvasPtr->interp, psInfo.channelName, + psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName, &mode); if (psInfo.chan == (Tcl_Channel) NULL) { result = TCL_ERROR; goto cleanup; } if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(canvasPtr->interp, "channel \"", + Tcl_AppendResult(interp, "channel \"", psInfo.channelName, "\" wasn't opened for writing", (char *) NULL); result = TCL_ERROR; @@ -687,9 +694,9 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) if (itemPtr->typePtr->postscriptProc == NULL) { continue; } - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, + result = (*itemPtr->typePtr->postscriptProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, 1); - Tcl_ResetResult(canvasPtr->interp); + Tcl_ResetResult(interp); if (result != TCL_OK) { /* * An error just occurred. Just skip out of this loop. @@ -709,21 +716,22 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *-------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "%!PS-Adobe-3.0 EPSF-3.0\n", + if (psInfo.prolog) { + Tcl_AppendResult(interp, "%!PS-Adobe-3.0 EPSF-3.0\n", "%%Creator: Tk Canvas Widget\n", (char *) NULL); #ifdef HAVE_PW_GECOS if (!Tcl_IsSafe(interp)) { struct passwd *pwPtr = getpwuid(getuid()); /* INTL: Native. */ - Tcl_AppendResult(canvasPtr->interp, "%%For: ", + Tcl_AppendResult(interp, "%%For: ", (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "\n", (char *) NULL); endpwent(); } #endif /* HAVE_PW_GECOS */ - Tcl_AppendResult(canvasPtr->interp, "%%Title: Window ", - Tk_PathName(canvasPtr->tkwin), "\n", (char *) NULL); + Tcl_AppendResult(interp, "%%Title: Window ", + Tk_PathName(tkwin), "\n", (char *) NULL); time(&now); - Tcl_AppendResult(canvasPtr->interp, "%%CreationDate: ", + Tcl_AppendResult(interp, "%%CreationDate: ", ctime(&now), (char *) NULL); /* INTL: Native. */ if (!psInfo.rotate) { sprintf(string, "%d %d %d %d", @@ -741,21 +749,21 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) + 1.0)); } - Tcl_AppendResult(canvasPtr->interp, "%%BoundingBox: ", string, + Tcl_AppendResult(interp, "%%BoundingBox: ", string, "\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Pages: 1\n", + Tcl_AppendResult(interp, "%%Pages: 1\n", "%%DocumentData: Clean7Bit\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Orientation: ", + Tcl_AppendResult(interp, "%%Orientation: ", psInfo.rotate ? "Landscape\n" : "Portrait\n", (char *) NULL); p = "%%DocumentNeededResources: font "; for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, p, + Tcl_AppendResult(interp, p, Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", (char *) NULL); p = "%%+ font "; } - Tcl_AppendResult(canvasPtr->interp, "%%EndComments\n\n", (char *) NULL); + Tcl_AppendResult(interp, "%%EndComments\n\n", (char *) NULL); /* * Insert the prolog @@ -765,7 +773,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, Tcl_GetStringResult(canvasPtr->interp), -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -776,14 +784,14 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ sprintf(string, "/CL %d def\n", psInfo.colorLevel); - Tcl_AppendResult(canvasPtr->interp, "%%BeginSetup\n", string, + Tcl_AppendResult(interp, "%%BeginSetup\n", string, (char *) NULL); for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, "%%IncludeResource: font ", + Tcl_AppendResult(interp, "%%IncludeResource: font ", Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", (char *) NULL); } - Tcl_AppendResult(canvasPtr->interp, "%%EndSetup\n\n", (char *) NULL); + Tcl_AppendResult(interp, "%%EndSetup\n\n", (char *) NULL); /* *----------------------------------------------------------- @@ -793,26 +801,31 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *----------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "%%Page: 1 1\n", "save\n", + Tcl_AppendResult(interp, "%%Page: 1 1\n", "save\n", (char *) NULL); sprintf(string, "%.1f %.1f translate\n", psInfo.pageX, psInfo.pageY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); if (psInfo.rotate) { - Tcl_AppendResult(canvasPtr->interp, "90 rotate\n", (char *) NULL); + Tcl_AppendResult(interp, "90 rotate\n", (char *) NULL); } sprintf(string, "%.4g %.4g scale\n", psInfo.scale, psInfo.scale); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); sprintf(string, "%d %d translate\n", deltaX - psInfo.x, deltaY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2), - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2)); - Tcl_AppendResult(canvasPtr->interp, string, + psInfo.x, + Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo), + psInfo.x2, + Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo), + psInfo.x2, + Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo), + psInfo.x, + Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo)); + Tcl_AppendResult(interp, string, " lineto closepath clip newpath\n", (char *) NULL); + } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, Tcl_GetStringResult(canvasPtr->interp), -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -833,21 +846,24 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) if (itemPtr->typePtr->postscriptProc == NULL) { continue; } - Tcl_AppendResult(canvasPtr->interp, "gsave\n", (char *) NULL); - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, + if (itemPtr->state == TK_STATE_HIDDEN) { + continue; + } + Tcl_AppendResult(interp, "gsave\n", (char *) NULL); + result = (*itemPtr->typePtr->postscriptProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, 0); if (result != TCL_OK) { char msg[64 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (generating Postscript for item %d)", itemPtr->id); - Tcl_AddErrorInfo(canvasPtr->interp, msg); + Tcl_AddErrorInfo(interp, msg); goto cleanup; } - Tcl_AppendResult(canvasPtr->interp, "grestore\n", (char *) NULL); + Tcl_AppendResult(interp, "grestore\n", (char *) NULL); if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, Tcl_GetStringResult(canvasPtr->interp), -1); - Tcl_ResetResult(canvasPtr->interp); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(interp); } } @@ -858,10 +874,12 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *--------------------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "restore showpage\n\n", + if (psInfo.prolog) { + Tcl_AppendResult(interp, "restore showpage\n\n", "%%Trailer\nend\n%%EOF\n", (char *) NULL); + } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, Tcl_GetStringResult(canvasPtr->interp), -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -895,20 +913,20 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) ckfree(psInfo.fileName); } if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { - Tcl_Close(canvasPtr->interp, psInfo.chan); + Tcl_Close(interp, psInfo.chan); } if (psInfo.channelName != NULL) { ckfree(psInfo.channelName); } Tcl_DeleteHashTable(&psInfo.fontTable); - canvasPtr->psInfoPtr = oldInfoPtr; + canvasPtr->psInfo = (Tk_PostscriptInfo) oldInfoPtr; return result; } /* *-------------------------------------------------------------- * - * Tk_CanvasPsColor -- + * Tk_PostscriptColor -- * * This procedure is called by individual canvas items when * they want to set a color value for output. Given information @@ -928,14 +946,12 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ int -Tk_CanvasPsColor(interp, canvas, colorPtr) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptColor(interp, psInfo, colorPtr) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Postscript info. */ XColor *colorPtr; /* Information about color. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; int tmp; double red, green, blue; char string[200]; @@ -989,7 +1005,7 @@ Tk_CanvasPsColor(interp, canvas, colorPtr) /* *-------------------------------------------------------------- * - * Tk_CanvasPsFont -- + * Tk_PostscriptFont -- * * This procedure is called by individual canvas items when * they want to output text. Given information about an X @@ -1010,15 +1026,13 @@ Tk_CanvasPsColor(interp, canvas, colorPtr) */ int -Tk_CanvasPsFont(interp, canvas, tkfont) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptFont(interp, psInfo, tkfont) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Postscript Info. */ Tk_Font tkfont; /* Information about font in which text * is to be printed. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; char *end; char pointString[TCL_INTEGER_SPACE]; Tcl_DString ds; @@ -1083,7 +1097,7 @@ Tk_CanvasPsFont(interp, canvas, tkfont) /* *-------------------------------------------------------------- * - * Tk_CanvasPsBitmap -- + * Tk_PostscriptBitmap -- * * This procedure is called to output the contents of a * sub-region of a bitmap in proper image data format for @@ -1103,18 +1117,18 @@ Tk_CanvasPsFont(interp, canvas, tkfont) */ int -Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, startX, startY, width, + height) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* Postscript info. */ Pixmap bitmap; /* Bitmap for which to generate * Postscript. */ int startX, startY; /* Coordinates of upper-left corner * of rectangular region to output. */ int width, height; /* Height of rectangular region. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; XImage *imagePtr; int charsInLine, x, y, lastX, lastY, value, mask; unsigned int totalWidth, totalHeight; @@ -1135,10 +1149,10 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) * it shouldn't matter here. */ - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, + XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot, (int *) &dummyX, (int *) &dummyY, (unsigned int *) &totalWidth, (unsigned int *) &totalHeight, &dummyBorderwidth, &dummyDepth); - imagePtr = XGetImage(Tk_Display(canvasPtr->tkwin), bitmap, 0, 0, + imagePtr = XGetImage(Tk_Display(tkwin), bitmap, 0, 0, totalWidth, totalHeight, 1, XYPixmap); Tcl_AppendResult(interp, "<", (char *) NULL); mask = 0x80; @@ -1180,7 +1194,7 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) /* *-------------------------------------------------------------- * - * Tk_CanvasPsStipple -- + * Tk_PostscriptStipple -- * * This procedure is called by individual canvas items when * they have created a path that they'd like to be filled with @@ -1202,14 +1216,14 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) */ int -Tk_CanvasPsStipple(interp, canvas, bitmap) - Tcl_Interp *interp; /* Interpreter for returning Postscript +Tk_PostscriptStipple(interp, tkwin, psInfo, bitmap) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* Interpreter for returning Postscript * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ Pixmap bitmap; /* Bitmap to use for stippling. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; int width, height; char string[TCL_INTEGER_SPACE * 2]; Window dummyRoot; @@ -1228,12 +1242,12 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) * it shouldn't matter here. */ - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, + XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot, (int *) &dummyX, (int *) &dummyY, (unsigned *) &width, (unsigned *) &height, &dummyBorderwidth, &dummyDepth); sprintf(string, "%d %d ", width, height); Tcl_AppendResult(interp, string, (char *) NULL); - if (Tk_CanvasPsBitmap(interp, (Tk_Canvas) canvasPtr, bitmap, 0, 0, + if (Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, 0, 0, width, height) != TCL_OK) { return TCL_ERROR; } @@ -1244,9 +1258,9 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) /* *-------------------------------------------------------------- * - * Tk_CanvasPsY -- + * Tk_PostscriptY -- * - * Given a y-coordinate in canvas coordinates, this procedure + * Given a y-coordinate in local coordinates, this procedure * returns a y-coordinate to use for Postscript output. * * Results: @@ -1260,12 +1274,11 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) */ double -Tk_CanvasPsY(canvas, y) - Tk_Canvas canvas; /* Token for canvas on whose behalf - * Postscript is being generated. */ +Tk_PostscriptY(y, psInfo) double y; /* Y-coordinate in canvas coords. */ + Tk_PostscriptInfo psInfo; /* Postscript info */ { - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; return psInfoPtr->y2 - y; } @@ -1273,7 +1286,7 @@ Tk_CanvasPsY(canvas, y) /* *-------------------------------------------------------------- * - * Tk_CanvasPsPath -- + * Tk_PostscriptPath -- * * Given an array of points for a path, generate Postscript * commands to create the path. @@ -1288,29 +1301,28 @@ Tk_CanvasPsY(canvas, y) */ void -Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) - Tcl_Interp *interp; /* Put generated Postscript in this - * interpreter's result field. */ - Tk_Canvas canvas; /* Canvas on whose behalf Postscript +Tk_PostscriptPath(interp, psInfo, coordPtr, numPoints) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Canvas on whose behalf Postscript * is being generated. */ double *coordPtr; /* Pointer to first in array of * 2*numPoints coordinates giving * points for path. */ int numPoints; /* Number of points at *coordPtr. */ { - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; char buffer[200]; if (psInfoPtr->prepass) { return; } sprintf(buffer, "%.15g %.15g moveto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); + Tk_PostscriptY(coordPtr[1], psInfo)); Tcl_AppendResult(interp, buffer, (char *) NULL); for (numPoints--, coordPtr += 2; numPoints > 0; numPoints--, coordPtr += 2) { sprintf(buffer, "%.15g %.15g lineto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); + Tk_PostscriptY(coordPtr[1], psInfo)); Tcl_AppendResult(interp, buffer, (char *) NULL); } } @@ -1385,3 +1397,287 @@ GetPostscriptPoints(interp, string, doublePtr) *doublePtr = d; return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * TkImageGetColor -- + * + * This procedure converts a pixel value to three floating + * point numbers, representing the amount of red, green, and + * blue in that pixel on the screen. It makes use of colormap + * data passed as an argument, and should work for all Visual + * types. + * + * Results: + * Returns red, green, and blue color values in the range + * 0 to 1. There are no error returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +TkImageGetColor(cdata, pixel, red, green, blue) + TkColormapData *cdata; /* Colormap data */ + unsigned long pixel; /* Pixel value to look up */ + double *red, *green, *blue; /* Color data to return */ +{ + if (cdata->separated) { + int r = (pixel & cdata->red_mask) >> cdata->red_shift; + int g = (pixel & cdata->green_mask) >> cdata->green_shift; + int b = (pixel & cdata->blue_mask) >> cdata->blue_shift; + *red = cdata->colors[r].red / 65535.0; + *green = cdata->colors[g].green / 65535.0; + *blue = cdata->colors[b].blue / 65535.0; + } else { + *red = cdata->colors[pixel].red / 65535.0; + *green = cdata->colors[pixel].green / 65535.0; + *blue = cdata->colors[pixel].blue / 65535.0; + } +} + +/* + *-------------------------------------------------------------- + * + * TkPostscriptImage -- + * + * This procedure is called to output the contents of an + * image in Postscript, using a format appropriate for the + * current color mode (i.e. one bit per pixel in monochrome, + * one byte per pixel in gray, and three bytes per pixel in + * color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* postscript info */ + XImage *ximage; /* Image to draw */ + int x, y; /* First pixel to output */ + int width, height; /* Width and height of area */ +{ + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; + char buffer[256]; + int xx, yy, band, maxRows; + double red, green, blue; + int bytesPerLine=0, maxWidth=0; + int level = psInfoPtr->colorLevel; + Colormap cmap; + int i, depth, ncolors; + Visual *visual; + TkColormapData cdata; + + if (psInfoPtr->prepass) { + return TCL_OK; + } + + cmap = Tk_Colormap(tkwin); + depth = Tk_Depth(tkwin); + visual = Tk_Visual(tkwin); + + /* + * Obtain information about the colormap, ie the mapping between + * pixel values and RGB values. The code below should work + * for all Visual types. + */ + + ncolors = visual->map_entries; + cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors); + cdata.ncolors = ncolors; + + if (visual->class == DirectColor || visual->class == TrueColor) { + cdata.separated = 1; + cdata.red_mask = visual->red_mask; + cdata.green_mask = visual->green_mask; + cdata.blue_mask = visual->blue_mask; + cdata.red_shift = 0; + cdata.green_shift = 0; + cdata.blue_shift = 0; + while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0) + cdata.red_shift ++; + while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0) + cdata.green_shift ++; + while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0) + cdata.blue_shift ++; + for (i = 0; i < ncolors; i ++) + cdata.colors[i].pixel = + ((i << cdata.red_shift) & cdata.red_mask) | + ((i << cdata.green_shift) & cdata.green_mask) | + ((i << cdata.blue_shift) & cdata.blue_mask); + } else { + cdata.separated=0; + for (i = 0; i < ncolors; i ++) + cdata.colors[i].pixel = i; + } + if (visual->class == StaticGray || visual->class == GrayScale) + cdata.color = 0; + else + cdata.color = 1; + + + XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors); + + /* + * Figure out which color level to use (possibly lower than the + * one specified by the user). For example, if the user specifies + * color with monochrome screen, use gray or monochrome mode instead. + */ + + if (!cdata.color && level == 2) { + level = 1; + } + + if (!cdata.color && cdata.ncolors == 2) { + level = 0; + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + + switch (level) + { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, + "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + ckfree((char *) cdata.colors); + return TCL_ERROR; + } + + maxRows = 60000 / bytesPerLine; + + for (band = height-1; band >= 0; band -= maxRows) { + int rows = (band >= maxRows) ? maxRows : band + 1; + int lineLen = 0; + switch (level) { + case 0: + sprintf(buffer, "%d %d 1 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 1: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 2: + sprintf(buffer, "%d %d 8 matrix {\n<", + width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + } + for (yy = band; yy > band - rows; yy--) { + switch (level) { + case 0: { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + */ + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = x; xx< x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + if (0.30 * red + 0.59 * green + 0.11 * blue > 0.5) + data |= mask; + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: { + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + for (xx = x; xx < x+width; xx ++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 * + (0.30 * red + + 0.59 * green + + 0.11 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + case 2: { + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + for (xx = x; xx < x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X%02X%02X", + (int) floor(0.5 + 255.0 * red), + (int) floor(0.5 + 255.0 * green), + (int) floor(0.5 + 255.0 * blue)); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + switch (level) { + case 0: sprintf(buffer, ">\n} image\n"); break; + case 1: sprintf(buffer, ">\n} image\n"); break; + case 2: sprintf(buffer, ">\n} false 3 colorimage\n"); break; + } + Tcl_AppendResult(interp, buffer, (char *) NULL); + sprintf(buffer, "0 %d translate\n", rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + ckfree((char *) cdata.colors); + return TCL_OK; +} diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c index b9b3e2d..4e826e9 100644 --- a/generic/tkCanvText.c +++ b/generic/tkCanvText.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvText.c,v 1.6 1999/04/21 21:53:24 rjohnson Exp $ + * RCS: @(#) $Id: tkCanvText.c,v 1.7 1999/12/14 06:52:26 hobbs Exp $ */ #include <stdio.h> @@ -44,10 +44,15 @@ typedef struct TextItem { */ Tk_Anchor anchor; /* Where to anchor text relative to (x,y). */ + Tk_TSOffset tsoffset; XColor *color; /* Color for text. */ + XColor *activeColor; /* Color for text. */ + XColor *disabledColor; /* Color for text. */ Tk_Font tkfont; /* Font for drawing text. */ Tk_Justify justify; /* Justification mode for text. */ Pixmap stipple; /* Stipple bitmap for text, or None. */ + Pixmap activeStipple; /* Stipple bitmap for text, or None. */ + Pixmap disabledStipple; /* Stipple bitmap for text, or None. */ char *text; /* Text for item (malloc-ed). */ int width; /* Width of lines for word-wrap, pixels. * Zero means no word-wrap. */ @@ -78,14 +83,31 @@ typedef struct TextItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE) +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, activeColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, activeStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(TextItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, disabledColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, disabledStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, "black", Tk_Offset(TextItem, color), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, @@ -93,6 +115,12 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, "left", Tk_Offset(TextItem, justify), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(TextItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, @@ -113,10 +141,10 @@ static void ComputeTextBbox _ANSI_ARGS_((Tk_Canvas canvas, TextItem *textPtr)); static int ConfigureText _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateText _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteText _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayCanvText _ANSI_ARGS_((Tk_Canvas canvas, @@ -127,7 +155,7 @@ static int GetSelText _ANSI_ARGS_((Tk_Canvas canvas, int maxBytes)); static int GetTextIndex _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - char *indexString, int *indexPtr)); + Tcl_Obj *obj, int *indexPtr)); static void ScaleText _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY)); @@ -135,7 +163,7 @@ static void SetTextCursor _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, int index)); static int TextCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void TextDeleteChars _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, int first, int last)); static void TextInsert _ANSI_ARGS_((Tk_Canvas canvas, @@ -163,18 +191,18 @@ Tk_ItemType tkTextType = { TextCoords, /* coordProc */ DeleteText, /* deleteProc */ DisplayCanvText, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ TextToPoint, /* pointProc */ TextToArea, /* areaProc */ TextToPostscript, /* postscriptProc */ ScaleText, /* scaleProc */ TranslateText, /* translateProc */ - GetTextIndex, /* indexProc */ + (Tk_ItemIndexProc *) GetTextIndex,/* indexProc */ SetTextCursor, /* icursorProc */ GetSelText, /* selectionProc */ TextInsert, /* insertProc */ TextDeleteChars, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -204,11 +232,24 @@ CreateText(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header has been * initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { TextItem *textPtr = (TextItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL); @@ -225,10 +266,17 @@ CreateText(interp, canvas, itemPtr, argc, argv) textPtr->insertPos = 0; textPtr->anchor = TK_ANCHOR_CENTER; + textPtr->tsoffset.flags = 0; + textPtr->tsoffset.xoffset = 0; + textPtr->tsoffset.yoffset = 0; textPtr->color = NULL; + textPtr->activeColor = NULL; + textPtr->disabledColor = NULL; textPtr->tkfont = NULL; textPtr->justify = TK_JUSTIFY_LEFT; textPtr->stipple = None; + textPtr->activeStipple = None; + textPtr->disabledStipple = None; textPtr->text = NULL; textPtr->width = 0; @@ -245,17 +293,16 @@ CreateText(interp, canvas, itemPtr, argc, argv) * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &textPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((TextCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureText(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureText(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -283,19 +330,33 @@ TextCoords(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Item whose coordinates are to be read or * modified. */ int argc; /* Number of coordinates supplied in argv. */ - char **argv; /* Array of coordinates: x1, y1, x2, y2, ... */ + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, x2, y2, ... */ { TextItem *textPtr = (TextItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, textPtr->x, x); - Tcl_PrintDouble(interp, textPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &textPtr->y) != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(textPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &textPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], + &textPtr->y) != TCL_OK)) { return TCL_ERROR; } ComputeTextBbox(canvas, textPtr); @@ -334,7 +395,7 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -344,10 +405,13 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) Tk_Window tkwin; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; XColor *selBgColorPtr; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) textPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) textPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -356,19 +420,59 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ + state = itemPtr->state; + + if (textPtr->activeColor != NULL || + textPtr->activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + color = textPtr->color; + stipple = textPtr->stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + newGC = newSelGC = None; - if ((textPtr->color != NULL) && (textPtr->tkfont != NULL)) { - gcValues.foreground = textPtr->color->pixel; + if (textPtr->tkfont != NULL) { gcValues.font = Tk_FontId(textPtr->tkfont); - mask = GCForeground|GCFont; - if (textPtr->stipple != None) { - gcValues.stipple = textPtr->stipple; + mask = GCFont; + if (color != NULL) { + gcValues.foreground = color->pixel; + mask |= GCForeground; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + mask &= ~(GCTile|GCFillStyle|GCStipple); + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; - mask |= GCForeground|GCStipple|GCFillStyle; + mask |= GCStipple|GCFillStyle; } - newGC = Tk_GetGC(tkwin, mask, &gcValues); gcValues.foreground = textInfoPtr->selFgColorPtr->pixel; - newSelGC = Tk_GetGC(tkwin, mask, &gcValues); + newSelGC = Tk_GetGC(tkwin, mask|GCForeground, &gcValues); } if (textPtr->gc != None) { Tk_FreeGC(Tk_Display(tkwin), textPtr->gc); @@ -454,10 +558,22 @@ DeleteText(canvas, itemPtr, display) if (textPtr->color != NULL) { Tk_FreeColor(textPtr->color); } + if (textPtr->activeColor != NULL) { + Tk_FreeColor(textPtr->activeColor); + } + if (textPtr->disabledColor != NULL) { + Tk_FreeColor(textPtr->disabledColor); + } Tk_FreeFont(textPtr->tkfont); if (textPtr->stipple != None) { Tk_FreeBitmap(display, textPtr->stipple); } + if (textPtr->activeStipple != None) { + Tk_FreeBitmap(display, textPtr->activeStipple); + } + if (textPtr->disabledStipple != None) { + Tk_FreeBitmap(display, textPtr->disabledStipple); + } if (textPtr->text != NULL) { ckfree(textPtr->text); } @@ -502,12 +618,21 @@ ComputeTextBbox(canvas, textPtr) { Tk_CanvasTextInfo *textInfoPtr; int leftX, topY, width, height, fudge; + Tk_State state = textPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } Tk_FreeTextLayout(textPtr->textLayout); textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont, textPtr->text, textPtr->numChars, textPtr->width, textPtr->justify, 0, &width, &height); + if (state == TK_STATE_HIDDEN || textPtr->color == NULL) { + width = height = 0; + } + /* * Use overall geometry information to compute the top-left corner * of the bounding box for the text item. @@ -604,10 +729,26 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) Tk_CanvasTextInfo *textInfoPtr; int selFirstChar, selLastChar; short drawableX, drawableY; + Pixmap stipple; + Tk_State state = itemPtr->state; textPtr = (TextItem *) itemPtr; textInfoPtr = textPtr->textInfoPtr; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + stipple = textPtr->stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + if (textPtr->gc == None) { return; } @@ -618,8 +759,8 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) * read-only. */ - if (textPtr->stipple != None) { - Tk_CanvasSetStippleOrigin(canvas, textPtr->gc); + if (stipple != None) { + Tk_CanvasSetOffset(canvas, textPtr->gc, &textPtr->tsoffset); } selFirstChar = -1; @@ -735,7 +876,7 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) selLastChar + 1); } - if (textPtr->stipple != None) { + if (stipple != None) { XSetTSOrigin(display, textPtr->gc, 0, 0); } } @@ -771,6 +912,8 @@ TextInsert(canvas, itemPtr, index, string) char *new, *text; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + string = Tcl_GetStringFromObj((Tcl_Obj *) string, &byteCount); + text = textPtr->text; if (index < 0) { @@ -942,11 +1085,22 @@ TextToPoint(canvas, itemPtr, pointPtr) double *pointPtr; /* Pointer to x and y coordinates. */ { TextItem *textPtr; + Tk_State state = itemPtr->state; + double value; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } textPtr = (TextItem *) itemPtr; - return (double) Tk_DistanceToTextLayout(textPtr->textLayout, + value = (double) Tk_DistanceToTextLayout(textPtr->textLayout, (int) pointPtr[0] - textPtr->leftEdge, (int) pointPtr[1] - textPtr->header.y1); + + if ((state == TK_STATE_HIDDEN) || (textPtr->color == NULL) || + (textPtr->text == NULL) || (*textPtr->text == 0)) { + value = 1.0e36; + } + return value; } /* @@ -978,6 +1132,11 @@ TextToArea(canvas, itemPtr, rectPtr) * area. */ { TextItem *textPtr; + Tk_State state = itemPtr->state; + + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } textPtr = (TextItem *) itemPtr; return Tk_IntersectTextLayout(textPtr->textLayout, @@ -1074,12 +1233,12 @@ TranslateText(canvas, itemPtr, deltaX, deltaY) */ static int -GetTextIndex(interp, canvas, itemPtr, string, indexPtr) +GetTextIndex(interp, canvas, itemPtr, obj, indexPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item for which the index is being * specified. */ - char *string; /* Specification of a particular character + Tcl_Obj *obj; /* Specification of a particular character * in itemPtr's text. */ int *indexPtr; /* Where to store converted character * index. */ @@ -1089,6 +1248,7 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) int c; TkCanvas *canvasPtr = (TkCanvas *) canvas; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); c = string[0]; length = strlen(string); @@ -1131,7 +1291,7 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) *indexPtr = Tk_PointToChar(textPtr->textLayout, x + canvasPtr->scrollX1 - textPtr->leftEdge, y + canvasPtr->scrollY1 - textPtr->header.y1); - } else if (Tcl_GetInt(interp, string, indexPtr) == TCL_OK) { + } else if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, obj, indexPtr) == TCL_OK) { if (*indexPtr < 0){ *indexPtr = 0; } else if (*indexPtr > textPtr->numChars) { @@ -1280,9 +1440,32 @@ TextToPostscript(interp, canvas, itemPtr, prepass) Tk_FontMetrics fm; char *justify; char buffer[500]; + XColor *color; + Pixmap stipple; + Tk_State state = itemPtr->state; - if (textPtr->color == NULL) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = textPtr->color; + stipple = textPtr->stipple; + if (state == TK_STATE_HIDDEN || textPtr->color == NULL || + textPtr->text == NULL || *textPtr->text == 0) { return TCL_OK; + } else if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } } if (Tk_CanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) { @@ -1291,13 +1474,13 @@ TextToPostscript(interp, canvas, itemPtr, prepass) if (prepass != 0) { return TCL_OK; } - if (Tk_CanvasPsColor(interp, canvas, textPtr->color) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (textPtr->stipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "/StippleText {\n ", (char *) NULL); - Tk_CanvasPsStipple(interp, canvas, textPtr->stipple); + Tk_CanvasPsStipple(interp, canvas, stipple); Tcl_AppendResult(interp, "} bind def\n", (char *) NULL); } @@ -1328,7 +1511,7 @@ TextToPostscript(interp, canvas, itemPtr, prepass) Tk_GetFontMetrics(textPtr->tkfont, &fm); sprintf(buffer, "] %d %g %g %s %s DrawText\n", fm.linespace, x / -2.0, y / 2.0, justify, - ((textPtr->stipple == None) ? "false" : "true")); + ((stipple == None) ? "false" : "true")); Tcl_AppendResult(interp, buffer, (char *) NULL); return TCL_OK; diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c index 7d203ec..3c79861 100644 --- a/generic/tkCanvUtil.c +++ b/generic/tkCanvUtil.c @@ -10,10 +10,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvUtil.c,v 1.3 1999/04/16 01:51:12 stanton Exp $ + * RCS: @(#) $Id: tkCanvUtil.c,v 1.4 1999/12/14 06:52:26 hobbs Exp $ */ -#include "tk.h" +#include "tkInt.h" #include "tkCanvas.h" #include "tkPort.h" @@ -201,6 +201,44 @@ Tk_CanvasGetCoord(interp, canvas, string, doublePtr) *doublePtr *= canvasPtr->pixelsPerMM; return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasGetCoordFromObj -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * canvas coordinate is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasGetCoordFromObj(interp, canvas, obj, doublePtr) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Canvas canvas; /* Canvas to which coordinate applies. */ + Tcl_Obj *obj; /* Describes coordinate (any screen + * coordinate form may be used here). */ + double *doublePtr; /* Place to store converted coordinate. */ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj, + doublePtr) != TCL_OK) { + return TCL_ERROR; + } + *doublePtr *= canvasPtr->pixelsPerMM; + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -237,6 +275,50 @@ Tk_CanvasSetStippleOrigin(canvas, gc) /* *---------------------------------------------------------------------- * + * Tk_CanvasSetOffset-- + * + * This procedure sets the stipple offset in a graphics + * context so that stipples drawn with the GC will + * line up with other stipples with the same offset. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasSetOffset(canvas, gc, offset) + Tk_Canvas canvas; /* Token for a canvas. */ + GC gc; /* Graphics context that is about to be + * used to draw a stippled pattern as + * part of redisplaying the canvas. */ + Tk_TSOffset *offset; /* offset (may be NULL pointer)*/ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + int flags = 0; + int x = - canvasPtr->drawableXOrigin; + int y = - canvasPtr->drawableYOrigin; + + if (offset != NULL) { + flags = offset->flags; + x += offset->xoffset; + y += offset->yoffset; + } + if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) { + Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin, + y - canvasPtr->yOrigin); + } else { + XSetTSOrigin(canvasPtr->display, gc, x, y); + } +} + +/* + *---------------------------------------------------------------------- + * * Tk_CanvasGetTextInfo -- * * This procedure returns a pointer to a structure containing @@ -374,3 +456,1016 @@ Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) *freeProcPtr = TCL_DYNAMIC; return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr); } + + +static int DashConvert _ANSI_ARGS_((char *l, CONST char *p, + int n, double width)); +#define ABS(a) ((a>=0)?(a):(-(a))) + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashParseProc -- + * + * This procedure is invoked during option processing to handle + * "-dash", "-activedash" and "-disableddash" options for canvas + * objects. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The dash list for a given canvas object gets replaced by + * those indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkCanvasDashParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* Not used.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + return Tk_GetDash(interp, value, (Tk_Dash *)(widgRec+offset)); +} + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-dash", "-activedash" + * and "-disableddash" configuration options for canvas items. + * + * Results: + * The return value is a string describing all the dash list for + * the item referred to by "widgRec"and "offset". In addition, + * *freeProcPtr is filled in with the address of a procedure to + * call to free the result string when it's no longer needed (or + * NULL to indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset in record for item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + Tk_Dash *dash = (Tk_Dash *) (widgRec+offset); + char *buffer; + char *p; + int i = dash->number; + + if (i < 0) { + i = -i; + *freeProcPtr = TCL_DYNAMIC; + buffer = (char *) ckalloc((unsigned int) (i+1)); + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + memcpy(buffer, p, (unsigned int) i); + buffer[i] = 0; + return buffer; + } else if (!i) { + *freeProcPtr = (Tcl_FreeProc *) NULL; + return ""; + } + buffer = (char *)ckalloc((unsigned int) (4*i)); + *freeProcPtr = TCL_DYNAMIC; + + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + sprintf(buffer, "%d", *p++ & 0xff); + while(--i) { + sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff); + } + return buffer; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateSmoothMethod -- + * + * This procedure is invoked to add additional values + * for the "-smooth" option to the list. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * In the future "-smooth <name>" will be accepted as + * smooth method for the line and polygon. + * + *-------------------------------------------------------------- + */ + +Tk_SmoothMethod tkBezierSmoothMethod = { + "bezier", + TkMakeBezierCurve, + (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, + double *coordPtr, int numPoints, int numSteps))) + TkMakeBezierPostscript, +}; + +static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp)); + +typedef struct SmoothAssocData { + struct SmoothAssocData *nextPtr; /* pointer to next SmoothAssocData */ + Tk_SmoothMethod smooth; /* name and functions associated with this + * option */ +} SmoothAssocData; + +void +Tk_CreateSmoothMethod(interp, smooth) + Tcl_Interp *interp; + Tk_SmoothMethod *smooth; +{ + SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr; + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod", + (Tcl_InterpDeleteProc **) NULL); + + /* + * If there's already a smooth method with the given name, remove it. + */ + + for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (!strcmp(typePtr2->smooth.name, smooth->name)) { + if (prevPtr == NULL) { + methods = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree((char *) typePtr2); + break; + } + } + ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData)); + ptr->smooth.name = smooth->name; + ptr->smooth.coordProc = smooth->coordProc; + ptr->smooth.postscriptProc = smooth->postscriptProc; + ptr->nextPtr = methods; + Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc, + (ClientData) ptr); +} +/* + *---------------------------------------------------------------------- + * + * SmoothMethodCleanupProc -- + * + * This procedure is invoked whenever an interpreter is deleted + * to cleanup the smooth methods. + * + * Results: + * None. + * + * Side effects: + * Smooth methods are removed. + * + *---------------------------------------------------------------------- + */ + +static void +SmoothMethodCleanupProc(clientData, interp) + ClientData clientData; /* Points to "smoothMethod" AssocData + * for the interpreter. */ + Tcl_Interp *interp; /* Interpreter that is being deleted. */ +{ + SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData; + + while (methods != NULL) { + methods = (ptr = methods)->nextPtr; + ckfree((char *) ptr); + } +} +/* + *-------------------------------------------------------------- + * + * TkSmoothParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-smooth" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The smooth option for a given item gets replaced by the value + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + register Tk_SmoothMethod **smoothPtr = + (Tk_SmoothMethod **) (widgRec + offset); + Tk_SmoothMethod *smooth = NULL; + int b; + size_t length; + SmoothAssocData *methods; + + if(value == NULL || *value == 0) { + *smoothPtr = (Tk_SmoothMethod *) NULL; + return TCL_OK; + } + length = strlen(value); + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod", + (Tcl_InterpDeleteProc **) NULL); + while (methods != (SmoothAssocData *) NULL) { + if (strncmp(value, methods->smooth.name, length) == 0) { + if (smooth != (Tk_SmoothMethod *) NULL) { + Tcl_AppendResult(interp, "ambigeous smooth method \"", value, + "\"", (char *) NULL); + return TCL_ERROR; + } + smooth = &methods->smooth; + } + methods = methods->nextPtr; + } + if (smooth) { + *smoothPtr = smooth; + return TCL_OK; + } + + if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) { + return TCL_ERROR; + } + *smoothPtr = b ? &tkBezierSmoothMethod : (Tk_SmoothMethod*) NULL; + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * TkSmoothPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-smooth" + * configuration option. + * + * Results: + * The return value is a string describing the smooth option for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkSmoothPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Tk_SmoothMethod **smoothPtr = (Tk_SmoothMethod **) (widgRec + offset); + + return (*smoothPtr) ? (*smoothPtr)->name : "0"; +} +/* + *-------------------------------------------------------------- + * + * Tk_GetDash + * + * This procedure is used to parse a string, assuming + * it is dash information. + * + * Results: + * The return value is a standard Tcl result: TCL_OK means + * that the dash information was parsed ok, and + * TCL_ERROR means it couldn't be parsed. + * + * Side effects: + * Dash information in the dash structure is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_GetDash(interp, value, dash) + Tcl_Interp *interp; /* Used for error reporting. */ + CONST char *value; /* Textual specification of dash list. */ + Tk_Dash *dash; /* Pointer to record in which to + * store dash information. */ +{ + int argc, i; + char **largv, **argv = NULL; + char *pt; + + if ((value==(char *) NULL) || (*value==0) ) { + dash->number = 0; + return TCL_OK; + } + if ((*value == '.') || (*value == ',') || + (*value == '-') || (*value == '_')) { + i = DashConvert((char *) NULL, value, -1, 0.0); + if (i>0) { + i = strlen(value); + } else { + goto badDashList; + } + if (i > sizeof(char *)) { + dash->pattern.pt = pt = (char *) ckalloc(strlen(value)); + } else { + pt = dash->pattern.array; + } + memcpy(pt,value, (unsigned int) i); + dash->number = -i; + return TCL_OK; + } + if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) { + Tcl_ResetResult(interp); + badDashList: + Tcl_AppendResult(interp, "bad dash list \"", value, + "\": must be a list of integers or a format like \"-..\"", + (char *) NULL); + syntaxError: + if (argv != NULL) { + ckfree((char *) argv); + } + if (ABS(dash->number) > sizeof(char *)) + ckfree((char *) dash->pattern.pt); + dash->number = 0; + return TCL_ERROR; + } + + if (ABS(dash->number) > sizeof(char *)) { + ckfree((char *) dash->pattern.pt); + } + if (argc > sizeof(char *)) { + dash->pattern.pt = pt = (char *) ckalloc((unsigned int) argc); + } else { + pt = dash->pattern.array; + } + dash->number = argc; + + largv = argv; + while(argc>0) { + if (Tcl_GetInt(interp, *largv, &i) != TCL_OK || + i < 1 || i>255) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "expected integer in the range 1..255 but got \"", + *largv, "\"", (char *) NULL); + goto syntaxError; + } + *pt++ = i; + argc--; largv++; + } + + if (argv != NULL) { + ckfree((char *) argv); + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateOutline + * + * This procedure initializes the Tk_Outline structure + * with default values. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void Tk_CreateOutline(outline) + Tk_Outline *outline; +{ + outline->gc = None; + outline->width = 1.0; + outline->activeWidth = 0.0; + outline->disabledWidth = 0.0; + outline->offset = 0; + outline->dash.number = 0; + outline->activeDash.number = 0; + outline->disabledDash.number = 0; + outline->tsoffset.flags = 0; + outline->tsoffset.xoffset = 0; + outline->tsoffset.yoffset = 0; + outline->color = NULL; + outline->activeColor = NULL; + outline->disabledColor = NULL; + outline->stipple = None; + outline->activeStipple = None; + outline->disabledStipple = None; +} + +/* + *-------------------------------------------------------------- + * + * Tk_DeleteOutline + * + * This procedure frees all memory that might be + * allocated and referenced in the Tk_Outline structure. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void Tk_DeleteOutline(display, outline) + Display *display; /* Display containing window */ + Tk_Outline *outline; +{ + if (outline->gc != None) { + Tk_FreeGC(display, outline->gc); + } + if (ABS(outline->dash.number) > sizeof(char *)) { + ckfree((char *) outline->dash.pattern.pt); + } + if (ABS(outline->activeDash.number) > sizeof(char *)) { + ckfree((char *) outline->activeDash.pattern.pt); + } + if (ABS(outline->disabledDash.number) > sizeof(char *)) { + ckfree((char *) outline->disabledDash.pattern.pt); + } + if (outline->color != NULL) { + Tk_FreeColor(outline->color); + } + if (outline->activeColor != NULL) { + Tk_FreeColor(outline->activeColor); + } + if (outline->disabledColor != NULL) { + Tk_FreeColor(outline->disabledColor); + } + if (outline->stipple != None) { + Tk_FreeBitmap(display, outline->stipple); + } + if (outline->activeStipple != None) { + Tk_FreeBitmap(display, outline->activeStipple); + } + if (outline->disabledStipple != None) { + Tk_FreeBitmap(display, outline->disabledStipple); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_ConfigOutlineGC + * + * This procedure should be called in the canvas object + * during the configure command. The graphics context + * description in gcValues is updated according to the + * information in the dash structure, as far as possible. + * + * Results: + * The return-value is a mask, indicating which + * elements of gcValues have been updated. + * 0 means there is no outline. + * + * Side effects: + * GC information in gcValues is updated. + * + *-------------------------------------------------------------- + */ + +int Tk_ConfigOutlineGC(gcValues, canvas, item, outline) + XGCValues *gcValues; + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + int mask = 0; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + if (outline->width < 0.0) { + outline->width = 0.0; + } + if (outline->activeWidth < 0.0) { + outline->activeWidth = 0.0; + } + if (outline->disabledWidth < 0) { + outline->disabledWidth = 0.0; + } + if (state==TK_STATE_HIDDEN) { + return 0; + } + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + + if (color==NULL) { + return 0; + } + + gcValues->line_width = (int) (width + 0.5); + if (color != NULL) { + gcValues->foreground = color->pixel; + mask = GCForeground|GCLineWidth; + if (stipple != None) { + gcValues->stipple = stipple; + gcValues->fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + } + if (mask && (dash->number != 0)) { + gcValues->line_style = LineOnOffDash; + gcValues->dash_offset = outline->offset; + if (dash->number >= 2) { + gcValues->dashes = 4; + } else if (dash->number > 0) { + gcValues->dashes = dash->pattern.array[0]; + } else { + gcValues->dashes = (char) (4 * width); + } + mask |= GCLineStyle|GCDashList|GCDashOffset; + } + return mask; +} + +/* + *-------------------------------------------------------------- + * + * Tk_ChangeOutlineGC + * + * Updates the GC to represent the full information of + * the dash structure. Partly this is already done in + * Tk_ConfigOutlineGC(). + * This function should be called just before drawing + * the dashed item. + * + * Results: + * 1 if there is a stipple pattern. + * 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_ChangeOutlineGC(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + CONST char *p; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number<-1) || ((dash->number == -1) && (dash->pattern.array[1]!=','))) { + char *q; + int i = -dash->number; + + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + q = (char *) ckalloc(2*(unsigned int)i); + i = DashConvert(q, p, i, width); + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, q, i); + ckfree(q); + } else if ( dash->number>2 || (dash->number==2 && + (dash->pattern.array[0]!=dash->pattern.array[1]))) { + p = (char *) (dash->number > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, p, dash->number); + } + if (stipple!=None) { + int w=0; int h=0; + Tk_TSOffset *tsoffset = &outline->tsoffset; + int flags = tsoffset->flags; + if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(((TkCanvas *)canvas)->display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, outline->gc, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_ResetOutlineGC + * + * Restores the GC to the situation before + * Tk_ChangeDashGC() was called. + * This function should be called just after the dashed + * item is drawn, because the GC is supposed to be + * read-only. + * + * Results: + * 1 if there is a stipple pattern. + * 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ +int +Tk_ResetOutlineGC(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + char dashList; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 && + (dash->pattern.array[0] != dash->pattern.array[1])) || + ((dash->number == -1) && (dash->pattern.array[1] != ','))) { + if (dash->number < 0) { + dashList = (int) (4 * width + 0.5); + } else if (dash->number<3) { + dashList = dash->pattern.array[0]; + } else { + dashList = 4; + } + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, &dashList , 1); + } + if (stipple!=None) { + XSetTSOrigin(((TkCanvas *)canvas)->display, outline->gc, 0, 0); + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsOutline + * + * Creates the postscript command for the correct + * Outline-information (width, dash, color and stipple). + * + * Results: + * TCL_OK if succeeded, otherwise TCL_ERROR. + * + * Side effects: + * canvas->interp->result contains the postscript string, + * or an error message if the result was TCL_ERROR. + * + *-------------------------------------------------------------- + */ +int +Tk_CanvasPsOutline(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + char string[41]; + char pattern[11]; + int i; + char *p; + char *s = string; + char *l = pattern; + Tcl_Interp *interp = ((TkCanvas *)canvas)->interp; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number>0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number>0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + sprintf(string, "%.15g setlinewidth\n", width); + Tcl_AppendResult(interp, string, (char *) NULL); + + if (dash->number > 10) { + s = (char *)ckalloc(1 + 4*(unsigned int)dash->number); + } else if (dash->number<-5) { + s = (char *)ckalloc(1 - 8*(unsigned int)dash->number); + l = (char *)ckalloc(1 - 2*(unsigned int)dash->number); + } + p = (char *) ((ABS(dash->number) > sizeof(char *)) ) ? + dash->pattern.pt : dash->pattern.array; + if (dash->number > 0) { + sprintf(s,"[%d",*p++ & 0xff); + i=dash->number-1; + while(i--) { + sprintf(s+strlen(s)," %d",*p++ & 0xff); + } + Tcl_AppendResult(interp,s,(char *)NULL); + if (dash->number&1) { + Tcl_AppendResult(interp," ",s+1,(char *)NULL); + } + sprintf(s,"] %d setdash\n",outline->offset); + Tcl_AppendResult(interp,s,(char *)NULL); + } else if (dash->number < 0) { + if ((i = DashConvert(l ,p, -dash->number, width)) != 0) { + sprintf(s,"[%d",*l++ & 0xff); + while(--i) { + sprintf(s+strlen(s)," %d",*l++ & 0xff); + } + Tcl_AppendResult(interp,s,(char *)NULL); + sprintf(s,"] %d setdash\n",outline->offset); + Tcl_AppendResult(interp,s,(char *)NULL); + } else { + Tcl_AppendResult(interp,"[] 0 setdash\n",(char *)NULL); + } + } else { + Tcl_AppendResult(interp,"[] 0 setdash\n",(char *)NULL); + } + if (s!=string) { + ckfree(s); + } + if (l!=pattern) { + ckfree(l); + } + if (Tk_CanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, + stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "stroke\n", (char *) NULL); + } + + return TCL_OK; +} + + +/* + *-------------------------------------------------------------- + * + * DashConvert + * + * Converts a character-like dash-list (e.g. "-..") + * into an X11-style. l must point to a string that + * holds room to at least 2*n characters. if + * l == NULL, this function can be used for + * syntax checking only. + * + * Results: + * The length of the resulting X11 compatible + * dash-list. -1 if failed. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +static int +DashConvert (l, p, n, width) + char *l; + CONST char *p; + int n; + double width; +{ + int result = 0; + int size, intWidth; + + if (n<0) { + n = strlen(p); + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + while (n-- && *p) { + switch (*p++) { + case ' ': + if (result) { + if (l) { + l[-1] += intWidth + 1; + } + continue; + } else { + return 0; + } + break; + case '_': + size = 8; + break; + case '-': + size = 6; + break; + case ',': + size = 4; + break; + case '.': + size = 2; + break; + default: + return -1; + } + if (l) { + *l++ = size * intWidth; + *l++ = 4 * intWidth; + } + result += 2; + } + return result; +} diff --git a/generic/tkCanvWind.c b/generic/tkCanvWind.c index 4dd8ee3..fab0015 100644 --- a/generic/tkCanvWind.c +++ b/generic/tkCanvWind.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvWind.c,v 1.3 1999/04/16 01:51:12 stanton Exp $ + * RCS: @(#) $Id: tkCanvWind.c,v 1.4 1999/12/14 06:52:26 hobbs Exp $ */ #include <stdio.h> @@ -41,7 +41,12 @@ typedef struct WindowItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; @@ -50,6 +55,9 @@ static Tk_ConfigSpec configSpecs[] = { "center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, "0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, @@ -68,10 +76,10 @@ static void ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas, WindowItem *winItemPtr)); static int ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas, @@ -84,7 +92,7 @@ static void TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY)); static int WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static void WinItemLostSlaveProc _ANSI_ARGS_(( ClientData clientData, Tk_Window tkwin)); static void WinItemRequestProc _ANSI_ARGS_((ClientData clientData, @@ -93,8 +101,17 @@ static void WinItemStructureProc _ANSI_ARGS_(( ClientData clientData, XEvent *eventPtr)); static int WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); +static int WinItemToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static double WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)); +#ifdef X_GetImage +static int xerrorhandler _ANSI_ARGS_((ClientData clientData, + XErrorEvent *e)); +#endif +static int CanvasPsWindow _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_Canvas canvas, double x, + double y, int width, int height)); /* * The structure below defines the window item type by means of procedures @@ -110,10 +127,10 @@ Tk_ItemType tkWindowType = { WinItemCoords, /* coordProc */ DeleteWinItem, /* deleteProc */ DisplayWinItem, /* displayProc */ - 1, /* alwaysRedraw */ + 1|TK_CONFIG_OBJS, /* flags */ WinItemToPoint, /* pointProc */ WinItemToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ + WinItemToPostscript, /* postscriptProc */ ScaleWinItem, /* scaleProc */ TranslateWinItem, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ @@ -121,7 +138,7 @@ Tk_ItemType tkWindowType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; @@ -164,11 +181,24 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing window. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -190,18 +220,16 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &winItemPtr->y) != TCL_OK)) { - return TCL_ERROR; + if ((WinItemCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureWinItem(interp, canvas, itemPtr, argc-2, argv+2, 0) - != TCL_OK) { - DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureWinItem(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -230,19 +258,33 @@ WinItemCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, winItemPtr->x, x); - Tcl_PrintDouble(interp, winItemPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) - != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(winItemPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(winItemPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &winItemPtr->x) + != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &winItemPtr->y) != TCL_OK)) { return TCL_ERROR; } @@ -281,7 +323,7 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Window item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; @@ -290,8 +332,8 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) oldWindow = winItemPtr->tkwin; canvasTkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, argv, - (char *) winItemPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, (char **) argv, + (char *) winItemPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -417,11 +459,15 @@ ComputeWindowBbox(canvas, winItemPtr) * recomputed. */ { int width, height, x, y; + Tk_State state = winItemPtr->header.state; x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); - if (winItemPtr->tkwin == NULL) { + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if ((winItemPtr->tkwin == NULL) || (state == TK_STATE_HIDDEN)) { /* * There is no window for this item yet. Just give it a 1x1 * bounding box. Don't give it a 0x0 bounding box; there are @@ -542,11 +588,18 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, int width, height; short x, y; Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); + Tk_State state = itemPtr->state; if (winItemPtr->tkwin == NULL) { return; } - + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state == TK_STATE_HIDDEN) { + Tk_UnmapWindow(winItemPtr->tkwin); + return; + } Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, (double) winItemPtr->header.y1, &x, &y); width = winItemPtr->header.x2 - winItemPtr->header.x1; @@ -593,7 +646,7 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, * WinItemToPoint -- * * Computes the distance from a given point to a given - * rectangle, in canvas units. + * window, in canvas units. * * Results: * The return value is 0 if the point whose x and y coordinates @@ -622,7 +675,7 @@ WinItemToPoint(canvas, itemPtr, pointPtr) y2 = winItemPtr->header.y2; /* - * Point is outside rectangle. + * Point is outside window. */ if (pointPtr[0] < x1) { @@ -692,16 +745,203 @@ WinItemToArea(canvas, itemPtr, rectPtr) /* *-------------------------------------------------------------- * + * xerrorhandler -- + * + * This is a dummy function to catch X11 errors during an + * attempt to print a canvas window. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#ifdef X_GetImage +static int +xerrorhandler(clientData, e) + ClientData clientData; + XErrorEvent *e; +{ + return 0; +} +#endif + + +/* + *-------------------------------------------------------------- + * + * WinItemToPostscript -- + * + * This procedure is called to generate Postscript for + * window items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in interp->result, replacing whatever used to be there. + * If no error occurs, then Postscript for the item is appended + * to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +WinItemToPostscript(interp, canvas, itemPtr, prepass) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is + * wanted. */ + int prepass; /* 1 means this is a prepass to + * collect font information; 0 means + * final Postscript is being created.*/ +{ + WindowItem *winItemPtr = (WindowItem *)itemPtr; + + double x, y; + int width, height; + Tk_Window tkwin = winItemPtr->tkwin; + + if (prepass || winItemPtr->tkwin == NULL) { + return TCL_OK; + } + + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + + /* + * Compute the coordinates of the lower-left corner of the window, + * taking into account the anchor position for the window. + */ + + x = winItemPtr->x; + y = Tk_CanvasPsY(canvas, winItemPtr->y); + + switch (winItemPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + return CanvasPsWindow(interp, tkwin, canvas, x, y, width, height); +} + +static int +CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Window tkwin; /* window to be printed */ + Tk_Canvas canvas; /* Information about overall canvas. */ + double x, y; /* origin of window. */ + int width, height; /* width/height of window. */ +{ + char buffer[256]; + TkWindow *winPtr; + XImage *ximage; + int result; + Tcl_DString buffer1, buffer2; +#ifdef X_GetImage + Tk_ErrorHandler handle; +#endif + + sprintf(buffer, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", + Tk_Class(tkwin), Tk_PathName(tkwin), width, height, x, y); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + /* first try if the widget has its own "postscript" command. If it + * exists, this will produce much better postscript than + * when a pixmap is used. + */ + + Tcl_DStringInit(&buffer1); + Tcl_DStringInit(&buffer2); + Tcl_DStringGetResult(interp, &buffer2); + sprintf (buffer, "%s postscript -prolog 0\n", Tk_PathName(tkwin)); + result = Tcl_Eval(interp, buffer); + Tcl_DStringGetResult(interp, &buffer1); + Tcl_DStringResult(interp, &buffer2); + Tcl_DStringFree(&buffer2); + + if (result == TCL_OK) { + Tcl_AppendResult(interp, + "50 dict begin\nsave\ngsave\n", + (char *) NULL); + sprintf (buffer, + "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", + height, width, height, width); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " 0 rlineto closepath\n", + "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", + Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", + (char *) NULL); + Tcl_DStringFree(&buffer1); + + for (winPtr = ((TkWindow *) tkwin)->childList; winPtr != NULL; + winPtr = winPtr->nextPtr) { + if (Tk_IsMapped(winPtr)) { +/* printf("child window: %s\n", winPtr->pathName);*/ + } + } + return result; + } + Tcl_DStringFree(&buffer1); + + /* + * If the window is off the screen it will generate an BadMatch/XError + * We catch any BadMatch errors here + */ +#ifdef X_GetImage + handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, + X_GetImage, -1, xerrorhandler, (ClientData) tkwin); +#endif + + /* + * Generate an XImage from the window. We can then read pixel + * values out of the XImage. + */ + + ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + +#ifdef X_GetImage + Tk_DeleteErrorHandler(handle); +#endif + + if (ximage == (XImage*) NULL) { + return TCL_OK; + } + + result = TkPostscriptImage(interp, tkwin, + ((TkCanvas *)canvas)->psInfo, ximage, 0, 0, width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *-------------------------------------------------------------- + * * ScaleWinItem -- * - * This procedure is invoked to rescale a rectangle or oval - * item. + * This procedure is invoked to rescale a window item. * * Results: * None. * * Side effects: - * The rectangle or oval referred to by itemPtr is rescaled + * The window referred to by itemPtr is rescaled * so that the following transformation is applied to all * point coordinates: * x' = originX + scaleX*(x-originX) @@ -712,9 +952,9 @@ WinItemToArea(canvas, itemPtr, rectPtr) static void ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ + Tk_Canvas canvas; /* Canvas containing window. */ + Tk_Item *itemPtr; /* Window to be scaled. */ + double originX, originY; /* Origin about which to scale window. */ double scaleX; /* Amount to scale in X direction. */ double scaleY; /* Amount to scale in Y direction. */ { @@ -736,16 +976,15 @@ ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) * * TranslateWinItem -- * - * This procedure is called to move a rectangle or oval by a - * given amount. + * This procedure is called to move a window by a given amount. * * Results: * None. * * Side effects: - * The position of the rectangle or oval is offset by - * (xDelta, yDelta), and the bounding box is updated in the - * generic part of the item structure. + * The position of the window is offset by (xDelta, yDelta), + * and the bounding box is updated in the generic part of the + * item structure. * *-------------------------------------------------------------- */ diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8183c2b..0446d0c 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -12,9 +12,11 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvas.c,v 1.8 1999/09/02 17:02:27 hobbs Exp $ + * RCS: @(#) $Id: tkCanvas.c,v 1.9 1999/12/14 06:52:26 hobbs Exp $ */ +/* #define USE_OLD_TAG_SEARCH 1 */ + #include "default.h" #include "tkInt.h" #include "tkPort.h" @@ -24,6 +26,7 @@ * See tkCanvas.h for key data structures used to implement canvases. */ +#ifdef USE_OLD_TAG_SEARCH /* * The structure defined below is used to keep track of a tag search * in progress. No field should be accessed by anyone other than @@ -43,6 +46,65 @@ typedef struct TagSearch { * return NULL. */ } TagSearch; +#else /* USE_OLD_TAG_SEARCH */ +/* + * The structure defined below is used to keep track of a tag search + * in progress. No field should be accessed by anyone other than + * TagSearchScan, TagSearchFirst, TagSearchNext, + * TagSearchScanExpr, TagSearchEvalExpr, + * TagSearchExprInit, TagSearchExprDestroy, + * TagSearchDestroy. + * ( + * Not quite accurate: the TagSearch structure is also accessed from: + * CanvasWidgetCmd, FindItems, RelinkItems + * The only instances of the structure are owned by: + * CanvasWidgetCmd + * CanvasWidgetCmd is the only function that calls: + * FindItems, RelinkItems + * CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call + * TagSearch* + * ) + */ + +typedef struct TagSearch { + TkCanvas *canvasPtr; /* Canvas widget being searched. */ + Tk_Item *currentPtr; /* Pointer to last item returned. */ + Tk_Item *lastPtr; /* The item right before the currentPtr + * is tracked so if the currentPtr is + * deleted we don't have to start from the + * beginning. */ + int searchOver; /* Non-zero means NextItem should always + * return NULL. */ + int type; /* search type */ + int id; /* item id for searches by id */ + + char *string; /* tag expression string */ + int stringIndex; /* current position in string scan */ + int stringLength; /* length of tag expression string */ + + char *rewritebuffer; /* tag string (after removing escapes) */ + unsigned int rewritebufferAllocated; /* available space for rewrites */ + + TagSearchExpr *expr; /* compiled tag expression */ +} TagSearch; +#endif /* USE_OLD_TAG_SEARCH */ + +/* + * Custom option for handling "-state" and "-offset" + */ + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, + (ClientData) NULL /* only "normal" and "disabled" */ +}; + +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) TK_OFFSET_RELATIVE +}; + /* * Information used for argv parsing. */ @@ -90,6 +152,9 @@ static Tk_ConfigSpec configSpecs[] = { DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0}, {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0}, + {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0", + Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT, + &offsetOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0}, {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion", @@ -113,6 +178,9 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr), TK_CONFIG_MONO_ONLY}, + {TK_CONFIG_CUSTOM, "-state", "state", "State", + "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT, + &stateOption}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus), TK_CONFIG_NULL_OK}, @@ -143,6 +211,23 @@ static Tk_ConfigSpec configSpecs[] = { static Tk_ItemType *typeList = NULL; /* NULL means initialization hasn't * been done yet. */ +#ifndef USE_OLD_TAG_SEARCH +/* + * Uids for operands in compiled advanced tag search expressions + * Initialization is done by InitCanvas() + */ +static Tk_Uid allUid = NULL; +static Tk_Uid currentUid = NULL; +static Tk_Uid andUid = NULL; +static Tk_Uid orUid = NULL; +static Tk_Uid xorUid = NULL; +static Tk_Uid parenUid = NULL; +static Tk_Uid negparenUid = NULL; +static Tk_Uid endparenUid = NULL; +static Tk_Uid tagvalUid = NULL; +static Tk_Uid negtagvalUid = NULL; +#endif /* USE_OLD_TAG_SEARCH */ + /* * Standard item types provided by Tk: */ @@ -180,34 +265,65 @@ static void CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr, static void CanvasUpdateScrollbars _ANSI_ARGS_(( TkCanvas *canvasPtr)); static int CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); + Tcl_Interp *interp, int argc, Tcl_Obj *CONST *argv)); static void CanvasWorldChanged _ANSI_ARGS_(( ClientData instanceData)); static int ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, int flags)); static void DestroyCanvas _ANSI_ARGS_((char *memPtr)); static void DisplayCanvas _ANSI_ARGS_((ClientData clientData)); static void DoItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Item *itemPtr, Tk_Uid tag)); +static void EventuallyRedrawItem _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr)); +#ifdef USE_OLD_TAG_SEARCH static int FindItems _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, - char *newTag, char *cmdName, char *option)); + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first)); +#else /* USE_OLD_TAG_SEARCH */ +static int FindItems _ANSI_ARGS_((Tcl_Interp *interp, + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first, + TagSearch **searchPtrPtr)); +#endif /* USE_OLD_TAG_SEARCH */ static int FindArea _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, char **argv, Tk_Uid uid, + TkCanvas *canvasPtr, Tcl_Obj *CONST *argv, Tk_Uid uid, int enclosed)); static double GridAlign _ANSI_ARGS_((double coord, double spacing)); +static char** GetStringsFromObjs _ANSI_ARGS_((int argc, + Tcl_Obj *CONST *objv)); static void InitCanvas _ANSI_ARGS_((void)); +#ifdef USE_OLD_TAG_SEARCH static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr)); +#endif /* USE_OLD_TAG_SEARCH */ static void PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr, XEvent *eventPtr)); static void PrintScrollFractions _ANSI_ARGS_((int screen1, int screen2, int object1, int object2, char *string)); +#ifdef USE_OLD_TAG_SEARCH static void RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, Tk_Item *prevPtr)); + Tcl_Obj *tag, Tk_Item *prevPtr)); static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, TagSearch *searchPtr)); + Tcl_Obj *tag, TagSearch *searchPtr)); +#else /* USE_OLD_TAG_SEARCH */ +static int RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr, + Tcl_Obj *tag, Tk_Item *prevPtr, + TagSearch **searchPtrPtr)); +static void TagSearchExprInit _ANSI_ARGS_ ((TagSearchExpr **exprPtrPtr, + Tk_Uid uid)); +static void TagSearchExprDestroy _ANSI_ARGS_((TagSearchExpr *expr)); +static void TagSearchDestroy _ANSI_ARGS_((TagSearch *searchPtr)); +static int TagSearchScan _ANSI_ARGS_((TkCanvas *canvasPtr, + Tcl_Obj *tag, TagSearch **searchPtrPtr)); +static int TagSearchScanExpr _ANSI_ARGS_((Tcl_Interp *interp, + TagSearch *searchPtr, TagSearchExpr *expr)); +static int TagSearchEvalExpr _ANSI_ARGS_((TagSearchExpr *expr, + Tk_Item *itemPtr)); +static Tk_Item * TagSearchFirst _ANSI_ARGS_((TagSearch *searchPtr)); +static Tk_Item * TagSearchNext _ANSI_ARGS_((TagSearch *searchPtr)); +#endif /* USE_OLD_TAG_SEARCH */ /* * The structure below defines canvas class behavior by means of procedures @@ -224,7 +340,7 @@ static TkClassProcs canvasClass = { /* *-------------------------------------------------------------- * - * Tk_CanvasCmd -- + * Tk_CanvasObjCmd -- * * This procedure is invoked to process the "canvas" Tcl * command. See the user documentation for details on what @@ -240,12 +356,12 @@ static TkClassProcs canvasClass = { */ int -Tk_CanvasCmd(clientData, interp, argc, argv) +Tk_CanvasObjCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData; TkCanvas *canvasPtr; @@ -256,12 +372,12 @@ Tk_CanvasCmd(clientData, interp, argc, argv) } if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?"); return TCL_ERROR; } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); + new = Tk_CreateWindowFromPath(interp, tkwin, + Tcl_GetString(argv[1]), (char *) NULL); if (new == NULL) { return TCL_ERROR; } @@ -276,7 +392,7 @@ Tk_CanvasCmd(clientData, interp, argc, argv) canvasPtr->tkwin = new; canvasPtr->display = Tk_Display(new); canvasPtr->interp = interp; - canvasPtr->widgetCmd = Tcl_CreateCommand(interp, + canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd, (ClientData) canvasPtr, CanvasCmdDeletedProc); canvasPtr->firstItemPtr = NULL; @@ -340,7 +456,14 @@ Tk_CanvasCmd(clientData, interp, argc, argv) canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new)); canvasPtr->flags = 0; canvasPtr->nextId = 1; - canvasPtr->psInfoPtr = NULL; + canvasPtr->psInfo = NULL; + canvasPtr->canvas_state = TK_STATE_NORMAL; + canvasPtr->tsoffset.flags = 0; + canvasPtr->tsoffset.xoffset = 0; + canvasPtr->tsoffset.yoffset = 0; +#ifndef USE_OLD_TAG_SEARCH + canvasPtr->bindTagExprs = NULL; +#endif Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS); Tk_SetClass(canvasPtr->tkwin, "Canvas"); @@ -390,50 +513,93 @@ CanvasWidgetCmd(clientData, interp, argc, argv) * widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ { TkCanvas *canvasPtr = (TkCanvas *) clientData; - size_t length; + unsigned int length; int c, result; Tk_Item *itemPtr = NULL; /* Initialization needed only to * prevent compiler warning. */ +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#else /* USE_OLD_TAG_SEARCH */ + TagSearch *searchPtr = NULL; /* Allocated by first TagSearchScan + * Freed by TagSearchDestroy */ +#endif /* USE_OLD_TAG_SEARCH */ + + int index; + static char *optionStrings[] = { + "addtag", "bbox", "bind", "canvasx", + "canvasy", "cget", "configure", "coords", + "create", "dchars", "delete", "dtag", + "find", "focus", "gettags", "icursor", + "index", "insert", "itemcget", "itemconfigure", + "lower", "move", "postscript", "raise", + "scale", "scan", "select", "type", + "xview", "yview", + NULL + }; + enum options { + CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX, + CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS, + CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG, + CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR, + CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, CANV_ITEMCONFIGURE, + CANV_LOWER, CANV_MOVE, CANV_POSTSCRIPT,CANV_RAISE, + CANV_SCALE, CANV_SCAN, CANV_SELECT, CANV_TYPE, + CANV_XVIEW, CANV_YVIEW + }; if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, argv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, argv[1], optionStrings, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) canvasPtr); + result = TCL_OK; - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) { + switch ((enum options) index) { + case CANV_ADDTAG: { if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " addtags tag searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0], - " addtag tag"); - } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0) - && (length >= 2)) { + Tcl_WrongNumArgs(interp, 2, argv, "tag searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + + case CANV_BBOX: { int i, gotAny; int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed * only to prevent compiler * warnings. */ if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox tagOrId ?tagOrId ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagOrId ...?"); + result = TCL_ERROR; + goto done; } gotAny = 0; for (i = 2; i < argc; i++) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2)) { continue; @@ -466,15 +632,15 @@ CanvasWidgetCmd(clientData, interp, argc, argv) sprintf(buf, "%d %d %d %d", x1, y1, x2, y2); Tcl_SetResult(interp, buf, TCL_VOLATILE); } - } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0) - && (length >= 2)) { + break; + } + case CANV_BIND: { ClientData object; if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bind tagOrId ?sequence? ?command?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?sequence? ?command?"); + result = TCL_ERROR; + goto done; } /* @@ -483,12 +649,13 @@ CanvasWidgetCmd(clientData, interp, argc, argv) */ object = 0; - if (isdigit(UCHAR(argv[2][0]))) { +#ifdef USE_OLD_TAG_SEARCH + if (isdigit(UCHAR(Tcl_GetString(argv[2])[0]))) { int id; char *end; Tcl_HashEntry *entryPtr; - id = strtoul(argv[2], &end, 0); + id = strtoul(Tcl_GetString(argv[2]), &end, 0); if (*end != 0) { goto bindByTag; } @@ -499,14 +666,38 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } if (object == 0) { - Tcl_AppendResult(interp, "item \"", argv[2], + Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]), "\" doesn't exist", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } else { bindByTag: - object = (ClientData) Tk_GetUid(argv[2]); + object = (ClientData) Tk_GetUid(Tcl_GetString(argv[2])); + } +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + if (searchPtr->type == 1) { + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) searchPtr->id); + if (entryPtr != NULL) { + itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr); + object = (ClientData) itemPtr; + } + + if (object == 0) { + Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]), + "\" doesn't exist", (char *) NULL); + result = TCL_ERROR; + goto done; + } + } else { + object = (ClientData) searchPtr->expr->uid; } +#endif /* USE_OLD_TAG_SEARCH */ /* * Make a binding table if the canvas doesn't already have @@ -520,20 +711,50 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (argc == 5) { int append = 0; unsigned long mask; + char* argv4 = Tcl_GetStringFromObj(argv[4],NULL); - if (argv[4][0] == 0) { + if (argv4[0] == 0) { result = Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); goto done; } - if (argv[4][0] == '+') { - argv[4]++; +#ifndef USE_OLD_TAG_SEARCH + if (searchPtr->type == 4) { + /* + * if new tag expression, then insert in linked list + */ + TagSearchExpr *expr, **lastPtr; + + lastPtr = &(canvasPtr->bindTagExprs); + while ((expr = *lastPtr)) { + if (expr->uid == searchPtr->expr->uid) + break; + lastPtr = &(expr->next); + } + if (!expr) { + /* + * transfer ownership of expr to bindTagExprs list + */ + *lastPtr = searchPtr->expr; + searchPtr->expr->next = NULL; + + /* + * flag in TagSearch that expr has changed ownership + * so that TagSearchDestroy doesn't try to free it + */ + searchPtr->expr = NULL; + } + } +#endif /* not USE_OLD_TAG_SEARCH */ + if (argv4[0] == '+') { + argv4++; append = 1; } mask = Tk_CreateBinding(interp, canvasPtr->bindingTable, - object, argv[3], argv[4], append); + object, Tcl_GetStringFromObj(argv[3],NULL), argv4, append); if (mask == 0) { - goto error; + result = TCL_ERROR; + goto done; } if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask |Button2MotionMask|Button3MotionMask|Button4MotionMask @@ -541,18 +762,19 @@ CanvasWidgetCmd(clientData, interp, argc, argv) |EnterWindowMask|LeaveWindowMask|KeyPressMask |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "requested illegal events; ", "only key, button, motion, enter, leave, and virtual ", "events may be used", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } else if (argc == 4) { char *command; command = Tk_GetBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); if (command == NULL) { char *string; @@ -564,7 +786,8 @@ CanvasWidgetCmd(clientData, interp, argc, argv) */ if (string[0] != '\0') { - goto error; + result = TCL_ERROR; + goto done; } else { Tcl_ResetResult(interp); } @@ -574,24 +797,27 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } else { Tk_GetAllBindings(interp, canvasPtr->bindingTable, object); } - } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) { + break; + } + case CANV_CANVASX: { int x; double grid; char buf[TCL_DOUBLE_SPACE]; if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasx screenx ?gridspacing?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "screenx ?gridspacing?"); + result = TCL_ERROR; + goto done; } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) { - goto error; + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) { + result = TCL_ERROR; + goto done; } if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &grid) != TCL_OK) { - goto error; + result = TCL_ERROR; + goto done; } } else { grid = 0.0; @@ -599,24 +825,27 @@ CanvasWidgetCmd(clientData, interp, argc, argv) x += canvasPtr->xOrigin; Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf); Tcl_SetResult(interp, buf, TCL_VOLATILE); - } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) { + break; + } + case CANV_CANVASY: { int y; double grid; char buf[TCL_DOUBLE_SPACE]; if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasy screeny ?gridspacing?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "screeny ?gridspacing?"); + result = TCL_ERROR; + goto done; } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) { - goto error; + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) { + result = TCL_ERROR; + goto done; } if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &grid) != TCL_OK) { - goto error; + result = TCL_ERROR; + goto done; } } else { grid = 0.0; @@ -624,76 +853,104 @@ CanvasWidgetCmd(clientData, interp, argc, argv) y += canvasPtr->yOrigin; Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf); Tcl_SetResult(interp, buf, TCL_VOLATILE); - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { + break; + } + case CANV_CGET: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "option"); + result = TCL_ERROR; + goto done; } result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { + (char *) canvasPtr, Tcl_GetString(argv[2]), 0); + break; + } + case CANV_CONFIGURE: { if (argc == 2) { result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, (char *) canvasPtr, (char *) NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); + (char *) canvasPtr, Tcl_GetString(argv[2]), 0); } else { result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, TK_CONFIG_ARGV_ONLY); + for (itemPtr = canvasPtr->firstItemPtr; + itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (itemPtr->state != TK_STATE_NULL) { + continue; + } + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + result = (*itemPtr->typePtr->configProc)(interp, + (Tk_Canvas) canvasPtr, itemPtr, 0, (Tcl_Obj **) NULL, + TK_CONFIG_ARGV_ONLY); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } } - } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0) - && (length >= 3)) { + break; + } + case CANV_COORDS: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " coords tagOrId ?x y x y ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?x y x y ...?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } if (itemPtr->typePtr->coordProc != NULL) { + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { result = (*itemPtr->typePtr->coordProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*itemPtr->typePtr->coordProc)(interp, + (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args); + if (args) ckfree((char *) args); + } } if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } - } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0) - && (length >= 2)) { + break; + } + case CANV_CREATE: { Tk_ItemType *typePtr; Tk_ItemType *matchPtr = NULL; Tk_Item *itemPtr; char buf[TCL_INTEGER_SPACE]; int isNew = 0; Tcl_HashEntry *entryPtr; + char *arg; if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " create type ?arg arg ...?\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "type ?arg arg ...?"); + result = TCL_ERROR; + goto done; } - c = argv[2][0]; - length = strlen(argv[2]); + arg = Tcl_GetStringFromObj(argv[2], (int *) &length); + c = arg[0]; for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) { if ((c == typePtr->name[0]) - && (strncmp(argv[2], typePtr->name, length) == 0)) { + && (strncmp(arg, typePtr->name, length) == 0)) { if (matchPtr != NULL) { badType: Tcl_AppendResult(interp, "unknown or ambiguous item type \"", - argv[2], "\"", (char *) NULL); - goto error; + arg, "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } matchPtr = typePtr; } @@ -709,10 +966,21 @@ CanvasWidgetCmd(clientData, interp, argc, argv) itemPtr->tagSpace = TK_TAG_SPACE; itemPtr->numTags = 0; itemPtr->typePtr = typePtr; - if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argc-3, argv+3) != TCL_OK) { + itemPtr->state = TK_STATE_NULL; + itemPtr->redraw_flags = 0; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, + itemPtr, argc-3, argv+3); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, + itemPtr, argc-3, (Tcl_Obj **) args); + if (args) ckfree((char *) args); + } + if (result != TCL_OK) { ckfree((char *) itemPtr); - goto error; + result = TCL_ERROR; + goto done; } itemPtr->nextPtr = NULL; entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable, @@ -727,36 +995,56 @@ CanvasWidgetCmd(clientData, interp, argc, argv) canvasPtr->lastItemPtr->nextPtr = itemPtr; } canvasPtr->lastItemPtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + itemPtr->redraw_flags |= FORCE_REDRAW; + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; sprintf(buf, "%d", itemPtr->id); Tcl_SetResult(interp, buf, TCL_VOLATILE); - } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0) - && (length >= 2)) { + break; + } + case CANV_DCHARS: { int first, last; + int x1,x2,y1,y2; if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dchars tagOrId first ?last?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId first ?last?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->dCharsProc == NULL)) { continue; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &first) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &first); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &first); + } + if (result != TCL_OK) { + goto done; } if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, - (Tk_Canvas) canvasPtr, itemPtr, argv[4], &last) - != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[4], &last); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &last); + } + if (result != TCL_OK) { + goto done; } } else { last = first; @@ -765,26 +1053,40 @@ CanvasWidgetCmd(clientData, interp, argc, argv) /* * Redraw both item's old and new areas: it's possible * that a delete could result in a new area larger than - * the old area. + * the old area. Except if the insertProc sets the + * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done. */ - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr, itemPtr, first, last); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0) - && (length >= 2)) { + break; + } + case CANV_DELETE: { int i; Tcl_HashEntry *entryPtr; for (i = 2; i < argc; i++) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); if (canvasPtr->bindingTable != NULL) { Tk_DeleteAllBindings(canvasPtr->bindingTable, (ClientData) itemPtr); @@ -833,24 +1135,32 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } } - } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0) - && (length >= 2)) { + break; + } + case CANV_DTAG: { Tk_Uid tag; int i; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dtag tagOrId ?tagToDelete?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagToDelete?"); + result = TCL_ERROR; + goto done; } if (argc == 4) { - tag = Tk_GetUid(argv[3]); + tag = Tk_GetUid(Tcl_GetStringFromObj(argv[3], NULL)); } else { - tag = Tk_GetUid(argv[2]); + tag = Tk_GetUid(Tcl_GetStringFromObj(argv[2], NULL)); } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ for (i = itemPtr->numTags-1; i >= 0; i--) { if (itemPtr->tagPtr[i] == tag) { itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; @@ -858,23 +1168,27 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } } - } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0) - && (length >= 2)) { + break; + } + case CANV_FIND: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " find searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL, - argv[0]," find"); - } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0) - && (length >= 2)) { + Tcl_WrongNumArgs(interp, 2, argv, "searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, argc, argv, (Tcl_Obj *) NULL, 2); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, argc, argv, + (Tcl_Obj *) NULL, 2, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_FOCUS: { if (argc > 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " focus ?tagOrId?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "?tagOrId?"); + result = TCL_ERROR; + goto done; } itemPtr = canvasPtr->textInfo.focusItemPtr; if (argc == 2) { @@ -887,15 +1201,22 @@ CanvasWidgetCmd(clientData, interp, argc, argv) goto done; } if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } - if (argv[2][0] == 0) { + if (Tcl_GetStringFromObj(argv[2], NULL)[0] == 0) { canvasPtr->textInfo.focusItemPtr = NULL; goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr->typePtr->icursorProc != NULL) { break; } @@ -905,136 +1226,214 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } canvasPtr->textInfo.focusItemPtr = itemPtr; if (canvasPtr->textInfo.gotFocus) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } - } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) { + break; + } + case CANV_GETTAGS: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " gettags tagOrId\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { int i; for (i = 0; i < itemPtr->numTags; i++) { Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]); } } - } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0) - && (length >= 2)) { + break; + } + case CANV_ICURSOR: { int index; if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " icursor tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->icursorProc == NULL)) { goto done; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index); + } + if (result != TCL_OK) { + goto done; } (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr, index); if ((itemPtr == canvasPtr->textInfo.focusItemPtr) && (canvasPtr->textInfo.cursorOn)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { + break; + } + case CANV_INDEX: { + int index; char buf[TCL_INTEGER_SPACE]; if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index tagOrId string\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId string"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr->typePtr->indexProc != NULL) { break; } } if (itemPtr == NULL) { Tcl_AppendResult(interp, "can't find an indexable item \"", - argv[2], "\"", (char *) NULL); - goto error; + Tcl_GetStringFromObj(argv[2], NULL), "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index); + } + if (result != TCL_OK) { + goto done; } sprintf(buf, "%d", index); Tcl_SetResult(interp, buf, TCL_VOLATILE); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { + break; + } + case CANV_INSERT: { int beforeThis; + int x1,x2,y1,y2; if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert tagOrId beforeThis string\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId beforeThis string"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->insertProc == NULL)) { continue; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &beforeThis) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &beforeThis); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &beforeThis); + } + if (result != TCL_OK) { + goto done; } /* * Redraw both item's old and new areas: it's possible * that an insertion could result in a new area either - * larger or smaller than the old area. + * larger or smaller than the old area. Except if the + * insertProc sets the TK_ITEM_DONT_REDRAW flag, nothing + * more needs to be done. */ - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, - itemPtr, beforeThis, argv[4]); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, - itemPtr->y1, itemPtr->x2, itemPtr->y2); + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, + itemPtr, beforeThis, (char *) argv[4]); + } else { + (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, + itemPtr, beforeThis, Tcl_GetStringFromObj(argv[4], NULL)); + } + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } - } else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0) - && (length >= 6)) { + break; + } + case CANV_ITEMCGET: { if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemcget tagOrId option\"", - (char *) NULL); + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId option"); return TCL_ERROR; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); + Tcl_GetStringFromObj(argv[3], NULL), 0); } - } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0) - && (length >= 6)) { + break; + } + case CANV_ITEMCONFIGURE: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemconfigure tagOrId ?option value ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?option value ...?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (argc == 3) { result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, @@ -1042,29 +1441,36 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } else if (argc == 4) { result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); + Tcl_GetString(argv[3]), 0); } else { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { result = (*itemPtr->typePtr->configProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3, TK_CONFIG_ARGV_ONLY); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*itemPtr->typePtr->configProc)(interp, + (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args, + TK_CONFIG_ARGV_ONLY); + if (args) ckfree((char *) args); + } + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } if ((result != TCL_OK) || (argc < 5)) { break; } } - } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) { + break; + } + case CANV_LOWER: { Tk_Item *itemPtr; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " lower tagOrId ?belowThis?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?belowThis?"); + result = TCL_ERROR; + goto done; } /* @@ -1075,49 +1481,75 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (argc == 3) { itemPtr = NULL; } else { +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[3], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr == NULL) { - Tcl_AppendResult(interp, "tag \"", argv[3], + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(argv[3]), "\" doesn't match any items", (char *) NULL); - goto error; + goto done; } itemPtr = itemPtr->prevPtr; } +#ifdef USE_OLD_TAG_SEARCH RelinkItems(canvasPtr, argv[2], itemPtr); - } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = RelinkItems(canvasPtr, argv[2], itemPtr, &searchPtr)) != TCL_OK) { + goto done; + } +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_MOVE: { double xAmount, yAmount; if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " move tagOrId xAmount yAmount\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xAmount yAmount"); + result = TCL_ERROR; + goto done; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp, + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], + &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) { - goto error; + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr, itemPtr, xAmount, yAmount); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } - } else if ((c == 'p') && (strncmp(argv[1], "postscript", length) == 0)) { - result = TkCanvPostscriptCmd(canvasPtr, interp, argc, argv); - } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) { + break; + } + case CANV_POSTSCRIPT: { + char **args = GetStringsFromObjs(argc, argv); + result = TkCanvPostscriptCmd(canvasPtr, interp, argc, args); + if (args) ckfree((char *) args); + break; + } + case CANV_RAISE: { Tk_Item *prevPtr; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " raise tagOrId ?aboveThis?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?aboveThis?"); + result = TCL_ERROR; + goto done; } /* @@ -1129,70 +1561,106 @@ CanvasWidgetCmd(clientData, interp, argc, argv) prevPtr = canvasPtr->lastItemPtr; } else { prevPtr = NULL; +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ prevPtr = itemPtr; } if (prevPtr == NULL) { - Tcl_AppendResult(interp, "tagOrId \"", argv[3], + Tcl_AppendResult(interp, "tagOrId \"", Tcl_GetStringFromObj(argv[3], NULL), "\" doesn't match any items", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } +#ifdef USE_OLD_TAG_SEARCH RelinkItems(canvasPtr, argv[2], prevPtr); - } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0) - && (length >= 3)) { +#else /* USE_OLD_TAG_SEARCH */ + result = RelinkItems(canvasPtr, argv[2], prevPtr, &searchPtr); + if (result != TCL_OK) { + goto done; + } +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_SCALE: { double xOrigin, yOrigin, xScale, yScale; if (argc != 7) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xOrigin yOrigin xScale yScale"); + result = TCL_ERROR; + goto done; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &xOrigin) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[4], &yOrigin) != TCL_OK) - || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK) - || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) { - goto error; + || (Tcl_GetDoubleFromObj(interp, argv[5], &xScale) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, argv[6], &yScale) != TCL_OK)) { + result = TCL_ERROR; + goto done; } if ((xScale == 0.0) || (yScale == 0.0)) { Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC); - goto error; + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr, itemPtr, xOrigin, yOrigin, xScale, yScale); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } - } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0) - && (length >= 3)) { - int x, y; + break; + } + case CANV_SCAN: { + int x, y, gain=10; + static char *optionStrings[] = { + "mark", "dragto", NULL + }; - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - goto error; + if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "scan option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + if ((argc != 5) && (argc != 5+index)) { + Tcl_WrongNumArgs(interp, 3, argv, index?"x y ?gain?":"x y"); + result = TCL_ERROR; + goto done; + } + if ((Tcl_GetIntFromObj(interp, argv[3], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, argv[4], &y) != TCL_OK)){ + result = TCL_ERROR; + goto done; } - if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){ - goto error; + if ((argc == 6) && (Tcl_GetIntFromObj(interp, argv[5], &gain) != TCL_OK)) { + result = TCL_ERROR; + goto done; } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { + if (!index) { canvasPtr->scanX = x; canvasPtr->scanXOrigin = canvasPtr->xOrigin; canvasPtr->scanY = y; canvasPtr->scanYOrigin = canvasPtr->yOrigin; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { + } else { int newXOrigin, newYOrigin, tmp; /* @@ -1200,30 +1668,41 @@ CanvasWidgetCmd(clientData, interp, argc, argv) * mouse motion. */ - tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX) + tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX) - canvasPtr->scrollX1; newXOrigin = canvasPtr->scrollX1 + tmp; - tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY) + tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY) - canvasPtr->scrollY1; newYOrigin = canvasPtr->scrollY1 + tmp; CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; } - } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) - && (length >= 2)) { - int index; + break; + } + case CANV_SELECT: { + int index, optionindex; + static char *optionStrings[] = { + "adjust", "clear", "from", "item", "to", NULL + }; + enum options { + CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO + }; if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "option ?tagOrId? ?arg?"); + result = TCL_ERROR; + goto done; } if (argc >= 4) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc != NULL) && (itemPtr->typePtr->selectionProc != NULL)){ break; @@ -1232,24 +1711,33 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (itemPtr == NULL) { Tcl_AppendResult(interp, "can't find an indexable and selectable item \"", - argv[3], "\"", (char *) NULL); - goto error; + Tcl_GetStringFromObj(argv[3], NULL), "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } } if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[4], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[4], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &index); + } + if (result != TCL_OK) { + goto done; } } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { + if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "select option", 0, + &optionindex) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum options) optionindex) { + case CANV_ADJUST: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select adjust tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr == itemPtr) { if (index < (canvasPtr->textInfo.selectFirst @@ -1262,36 +1750,37 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } CanvasSelectTo(canvasPtr, itemPtr, index); - } else if ((c == 'c') && (argv[2] != NULL) - && (strncmp(argv[2], "clear", length) == 0)) { + break; + } + case CANV_CLEAR: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select clear\"", (char *) NULL); - goto error; + Tcl_AppendResult(interp, 3, argv, (char *) NULL); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); canvasPtr->textInfo.selItemPtr = NULL; } goto done; - } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { + break; + } + case CANV_FROM: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select from tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } canvasPtr->textInfo.anchorItemPtr = itemPtr; canvasPtr->textInfo.selectAnchor = index; - } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) { + break; + } + case CANV_ITEM: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select item\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, (char *) NULL); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr != NULL) { char buf[TCL_INTEGER_SPACE]; @@ -1299,31 +1788,40 @@ CanvasWidgetCmd(clientData, interp, argc, argv) sprintf(buf, "%d", canvasPtr->textInfo.selItemPtr->id); Tcl_SetResult(interp, buf, TCL_VOLATILE); } - } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { + break; + } + case CANV_TO: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select to tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } CanvasSelectTo(canvasPtr, itemPtr, index); - } else { - Tcl_AppendResult(interp, "bad select option \"", argv[2], - "\": must be adjust, clear, from, item, or to", - (char *) NULL); - goto error; + break; + } } - } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) { + break; + } + case CANV_TYPE: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " type tag\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tag"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC); } - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { + break; + } + case CANV_XVIEW: { int count, type; int newX = 0; /* Initialization needed only to prevent * gcc warnings. */ @@ -1335,10 +1833,13 @@ CanvasWidgetCmd(clientData, interp, argc, argv) - canvasPtr->inset, canvasPtr->scrollX1, canvasPtr->scrollX2, Tcl_GetStringResult(interp)); } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); + char **args = GetStringsFromObjs(argc, argv); + type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count); + if (args) ckfree((char *) args); switch (type) { case TK_SCROLL_ERROR: - goto error; + result = TCL_ERROR; + goto done; case TK_SCROLL_MOVETO: newX = canvasPtr->scrollX1 - canvasPtr->inset + (int) (fraction * (canvasPtr->scrollX2 @@ -1361,7 +1862,9 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin); } - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) { + break; + } + case CANV_YVIEW: { int count, type; int newY = 0; /* Initialization needed only to prevent * gcc warnings. */ @@ -1373,10 +1876,13 @@ CanvasWidgetCmd(clientData, interp, argc, argv) - canvasPtr->inset, canvasPtr->scrollY1, canvasPtr->scrollY2, Tcl_GetStringResult(interp)); } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); + char **args = GetStringsFromObjs(argc, argv); + type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count); + if (args) ckfree((char *) args); switch (type) { case TK_SCROLL_ERROR: - goto error; + result = TCL_ERROR; + goto done; case TK_SCROLL_MOVETO: newY = canvasPtr->scrollY1 - canvasPtr->inset + (int) (fraction*(canvasPtr->scrollY2 @@ -1400,24 +1906,15 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY); } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be addtag, bbox, bind, ", - "canvasx, canvasy, cget, configure, coords, create, ", - "dchars, delete, dtag, find, focus, ", - "gettags, icursor, index, insert, itemcget, itemconfigure, ", - "lower, move, postscript, raise, scale, scan, ", - "select, type, xview, or yview", - (char *) NULL); - goto error; + break; + } } done: +#ifndef USE_OLD_TAG_SEARCH + TagSearchDestroy(searchPtr); +#endif /* not USE_OLD_TAG_SEARCH */ Tcl_Release((ClientData) canvasPtr); return result; - - error: - Tcl_Release((ClientData) canvasPtr); - return TCL_ERROR; } /* @@ -1470,6 +1967,18 @@ DestroyCanvas(memPtr) if (canvasPtr->pixmapGC != None) { Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); } +#ifndef USE_OLD_TAG_SEARCH + { + TagSearchExpr *expr, *next; + + expr = canvasPtr->bindTagExprs; + while (expr) { + next = expr->next; + TagSearchExprDestroy(expr); + expr = next; + } + } +#endif Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); if (canvasPtr->bindingTable != NULL) { Tk_DeleteBindingTable(canvasPtr->bindingTable); @@ -1505,14 +2014,14 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) TkCanvas *canvasPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { XGCValues gcValues; GC new; if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs, - argc, argv, (char *) canvasPtr, flags) != TCL_OK) { + argc, (char **) argv, (char *) canvasPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -1530,10 +2039,10 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth; gcValues.function = GXcopy; - gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; gcValues.graphics_exposures = False; + gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; new = Tk_GetGC(canvasPtr->tkwin, - GCFunction|GCForeground|GCGraphicsExposures, &gcValues); + GCFunction|GCGraphicsExposures|GCForeground, &gcValues); if (canvasPtr->pixmapGC != None) { Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); } @@ -1593,6 +2102,22 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) ckfree((char *) argv2); } + flags = canvasPtr->tsoffset.flags; + if (flags & TK_OFFSET_LEFT) { + canvasPtr->tsoffset.xoffset = 0; + } else if (flags & TK_OFFSET_CENTER) { + canvasPtr->tsoffset.xoffset = canvasPtr->width/2; + } else if (flags & TK_OFFSET_RIGHT) { + canvasPtr->tsoffset.xoffset = canvasPtr->width; + } + if (flags & TK_OFFSET_TOP) { + canvasPtr->tsoffset.yoffset = 0; + } else if (flags & TK_OFFSET_MIDDLE) { + canvasPtr->tsoffset.yoffset = canvasPtr->height/2; + } else if (flags & TK_OFFSET_BOTTOM) { + canvasPtr->tsoffset.yoffset = canvasPtr->height; + } + /* * Reset the canvas's origin (this is a no-op unless confine * mode has just been turned on or the scroll region has changed). @@ -1683,6 +2208,7 @@ DisplayCanvas(clientData) if (canvasPtr->tkwin == NULL) { return; } + if (!Tk_IsMapped(tkwin)) { goto done; } @@ -1704,6 +2230,20 @@ DisplayCanvas(clientData) } /* + * Scan through the item list, registering the bounding box + * for all items that didn't do that for the final coordinates + * yet. This can be determined by the FORCE_REDRAW flag. + */ + + for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; + itemPtr = itemPtr->nextPtr) { + if (itemPtr->redraw_flags & FORCE_REDRAW) { + itemPtr->redraw_flags &= ~FORCE_REDRAW; + EventuallyRedrawItem((Tk_Canvas)canvasPtr, itemPtr); + itemPtr->redraw_flags &= ~FORCE_REDRAW; + } + } + /* * Compute the intersection between the area that needs redrawing * and the area that's visible on the screen. */ @@ -1795,7 +2335,7 @@ DisplayCanvas(clientData) || (itemPtr->y1 >= screenY2) || (itemPtr->x2 < screenX1) || (itemPtr->y2 < screenY1)) { - if (!itemPtr->typePtr->alwaysRedraw + if (!(itemPtr->typePtr->alwaysRedraw & 1) || (itemPtr->x1 >= canvasPtr->redrawX2) || (itemPtr->y1 >= canvasPtr->redrawY2) || (itemPtr->x2 < canvasPtr->redrawX1) @@ -1803,6 +2343,11 @@ DisplayCanvas(clientData) continue; } } + if (itemPtr->state == TK_STATE_HIDDEN || + (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, canvasPtr->display, pixmap, screenX1, screenY1, width, height); @@ -1856,7 +2401,7 @@ DisplayCanvas(clientData) } done: - canvasPtr->flags &= ~REDRAW_PENDING; + canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY); canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0; canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0; if (canvasPtr->flags & UPDATE_SCROLLBARS) { @@ -1948,7 +2493,7 @@ CanvasEventProc(clientData, eventPtr) for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { - if (itemPtr->typePtr->alwaysRedraw) { + if (itemPtr->typePtr->alwaysRedraw & 1) { (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, canvasPtr->display, None, 0, 0, 0, 0); } @@ -2020,10 +2565,13 @@ Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2) * Pixels on edge are not redrawn. */ { TkCanvas *canvasPtr = (TkCanvas *) canvas; - if ((x1 == x2) || (y1 == y2)) { + if ((x1 >= x2) || (y1 >= y2) || + (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) || + (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { return; } - if (canvasPtr->flags & REDRAW_PENDING) { + if (canvasPtr->flags & BBOX_NOT_EMPTY) { if (x1 <= canvasPtr->redrawX1) { canvasPtr->redrawX1 = x1; } @@ -2041,6 +2589,70 @@ Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2) canvasPtr->redrawY1 = y1; canvasPtr->redrawX2 = x2; canvasPtr->redrawY2 = y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + if (!(canvasPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); + canvasPtr->flags |= REDRAW_PENDING; + } +} + +/* + *-------------------------------------------------------------- + * + * EventuallyRedrawItem -- + * + * Arrange for part or all of a canvas widget to redrawn at + * some convenient time in the future. + * + * Results: + * None. + * + * Side effects: + * The screen will eventually be refreshed. + * + *-------------------------------------------------------------- + */ + +static void +EventuallyRedrawItem(canvas, itemPtr) + Tk_Canvas canvas; /* Information about widget. */ + Tk_Item *itemPtr; /* item to be redrawn. */ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) || + (itemPtr->x2 < canvasPtr->xOrigin) || + (itemPtr->y2 < canvasPtr->yOrigin) || + (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { + if (!(itemPtr->typePtr->alwaysRedraw & 1)) { + return; + } + } + if (!(itemPtr->redraw_flags & FORCE_REDRAW)) { + if (canvasPtr->flags & BBOX_NOT_EMPTY) { + if (itemPtr->x1 <= canvasPtr->redrawX1) { + canvasPtr->redrawX1 = itemPtr->x1; + } + if (itemPtr->y1 <= canvasPtr->redrawY1) { + canvasPtr->redrawY1 = itemPtr->y1; + } + if (itemPtr->x2 >= canvasPtr->redrawX2) { + canvasPtr->redrawX2 = itemPtr->x2; + } + if (itemPtr->y2 >= canvasPtr->redrawY2) { + canvasPtr->redrawY2 = itemPtr->y2; + } + } else { + canvasPtr->redrawX1 = itemPtr->x1; + canvasPtr->redrawY1 = itemPtr->y1; + canvasPtr->redrawX2 = itemPtr->x2; + canvasPtr->redrawY2 = itemPtr->y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + itemPtr->redraw_flags |= FORCE_REDRAW; + } + if (!(canvasPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); canvasPtr->flags |= REDRAW_PENDING; } @@ -2159,8 +2771,21 @@ InitCanvas() tkBitmapType.nextPtr = &tkArcType; tkArcType.nextPtr = &tkWindowType; tkWindowType.nextPtr = NULL; +#ifndef USE_OLD_TAG_SEARCH + allUid = Tk_GetUid("all"); + currentUid = Tk_GetUid("current"); + andUid = Tk_GetUid("&&"); + orUid = Tk_GetUid("||"); + xorUid = Tk_GetUid("^"); + parenUid = Tk_GetUid("("); + endparenUid = Tk_GetUid(")"); + negparenUid = Tk_GetUid("!("); + tagvalUid = Tk_GetUid("!!"); + negtagvalUid = Tk_GetUid("!"); +#endif /* USE_OLD_TAG_SEARCH */ } +#ifdef USE_OLD_TAG_SEARCH /* *-------------------------------------------------------------- * @@ -2187,10 +2812,10 @@ InitCanvas() */ static Tk_Item * -StartTagSearch(canvasPtr, tag, searchPtr) +StartTagSearch(canvasPtr, tagObj, searchPtr) TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ - char *tag; /* String giving tag value. */ + Tcl_Obj *tagObj; /* Object giving tag value. */ TagSearch *searchPtr; /* Record describing tag search; * will be initialized here. */ { @@ -2198,6 +2823,7 @@ StartTagSearch(canvasPtr, tag, searchPtr) Tk_Item *itemPtr, *lastPtr; Tk_Uid *tagPtr; Tk_Uid uid; + char *tag = Tcl_GetString(tagObj); int count; TkWindow *tkwin; TkDisplay *dispPtr; @@ -2249,7 +2875,6 @@ StartTagSearch(canvasPtr, tag, searchPtr) searchPtr->tag = uid = Tk_GetUid(tag); if (uid == Tk_GetUid("all")) { - /* * All items match. */ @@ -2368,6 +2993,865 @@ NextItem(searchPtr) return NULL; } +#else /* USE_OLD_TAG_SEARCH */ +/* + *-------------------------------------------------------------- + * + * TagSearchExprInit -- + * + * This procedure allocates and initializes one TagSearchExpr struct. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprInit(exprPtrPtr, uid) +TagSearchExpr **exprPtrPtr; +Tk_Uid uid; +{ + TagSearchExpr* expr = *exprPtrPtr; + + if (! expr) { + expr = (TagSearchExpr *) ckalloc(sizeof(TagSearchExpr)); + expr->allocated = 0; + expr->uids = NULL; + expr->next = NULL; + } + expr->uid = uid; + expr->index = 0; + expr->length = 0; + *exprPtrPtr = expr; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchExprDestroy -- + * + * This procedure destroys one TagSearchExpr structure. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprDestroy(expr) + TagSearchExpr *expr; +{ + if (expr) { + if (expr->uids) { + ckfree((char *)expr->uids); + } + ckfree((char *)expr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScan -- + * + * This procedure is called to initiate an enumeration of + * all items in a given canvas that contain a tag that matches + * the tagOrId expression. + * + * Results: + * The return value indicates if the tagOrId expression + * was successfully scanned (syntax). + * The information at *searchPtr is initialized + * such that a call to TagSearchFirst, followed by + * successive calls to NextItem will return items + * that match tag. + * + * Side effects: + * SearchPtr is linked into a list of searches in progress + * on canvasPtr, so that elements can safely be deleted + * while the search is in progress. + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScan(canvasPtr, tagObj, searchPtrPtr) + TkCanvas *canvasPtr; /* Canvas whose items are to be + * searched. */ + Tcl_Obj *tagObj; /* Object giving tag value. */ + TagSearch **searchPtrPtr; /* Record describing tag search; + * will be initialized here. */ +{ + char *tag = Tcl_GetStringFromObj(tagObj,NULL); + int i; + TagSearch *searchPtr; + + /* + * Initialize the search. + */ + + if (*searchPtrPtr) { + searchPtr = *searchPtrPtr; + } else { + /* Allocate primary search struct on first call */ + *searchPtrPtr = searchPtr = (TagSearch *) ckalloc(sizeof(TagSearch)); + searchPtr->expr = NULL; + + /* Allocate buffer for rewritten tags (after de-escaping) */ + searchPtr->rewritebufferAllocated = 100; + searchPtr->rewritebuffer = + ckalloc(searchPtr->rewritebufferAllocated); + } + TagSearchExprInit(&(searchPtr->expr),Tk_GetUid(tag)); + + /* short circuit impossible searches for null tags */ + if ((searchPtr->stringLength = strlen(tag)) == 0) { + return TCL_OK; + } + + /* Make sure there is enough buffer to hold rewritten tags */ + if ((unsigned int)searchPtr->stringLength >= + searchPtr->rewritebufferAllocated) { + searchPtr->rewritebufferAllocated += 100; + searchPtr->rewritebuffer = + ckrealloc(searchPtr->rewritebuffer, + searchPtr->rewritebufferAllocated); + } + + /* Initialize search */ + searchPtr->canvasPtr = canvasPtr; + searchPtr->searchOver = 0; + searchPtr->type = 0; + + /* + * Find the first matching item in one of several ways. If the tag + * is a number then it selects the single item with the matching + * identifier. In this case see if the item being requested is the + * hot item, in which case the search can be skipped. + */ + + if (isdigit(UCHAR(*tag))) { + char *end; + + searchPtr->id = strtoul(tag, &end, 0); + if (*end == 0) { + searchPtr->type = 1; + return TCL_OK; + } + } + + /* + * Pre-scan tag for at least one unquoted "&&" "||" "^" "!" + * if not found then use string as simple tag + */ + for (i = 0; i < searchPtr->stringLength ; i++) { + if (tag[i] == '"') { + i++; + for ( ; i < searchPtr->stringLength; i++) { + if (tag[i] == '\\') { + i++; + continue; + } + if (tag[i] == '"') { + break; + } + } + } else { + if ((tag[i] == '&' && tag[i+1] == '&') + || (tag[i] == '|' && tag[i+1] == '|') + || (tag[i] == '^') + || (tag[i] == '!')) { + searchPtr->type = 4; + break; + } + } + } + + searchPtr->string = tag; + searchPtr->stringIndex = 0; + if (searchPtr->type == 4) { + /* + * an operator was found in the prescan, so + * now compile the tag expression into array of Tk_Uid + * flagging any syntax errors found + */ + if (TagSearchScanExpr(canvasPtr->interp, searchPtr, searchPtr->expr) != TCL_OK) { + /* Syntax error in tag expression */ + /* Result message set by TagSearchScanExpr */ + return TCL_ERROR; + } + searchPtr->expr->length = searchPtr->expr->index; + } else { + if (searchPtr->expr->uid == allUid) { + /* + * All items match. + */ + searchPtr->type = 2; + } else { + /* + * Optimized single-tag search + */ + searchPtr->type = 3; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchDestroy -- + * + * This procedure destroys any dynamic structures that + * may have been allocated by TagSearchScan. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchDestroy(searchPtr) + TagSearch *searchPtr; /* Record describing tag search */ +{ + if (searchPtr) { + TagSearchExprDestroy(searchPtr->expr); + ckfree((char *)searchPtr->rewritebuffer); + ckfree((char *)searchPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScanExpr -- + * + * This recursive procedure is called to scan a tag expression + * and compile it into an array of Tk_Uids. + * + * Results: + * The return value indicates if the tagOrId expression + * was successfully scanned (syntax). + * The information at *searchPtr is initialized + * such that a call to TagSearchFirst, followed by + * successive calls to TagSearchNext will return items + * that match tag. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScanExpr(interp, searchPtr, expr) + Tcl_Interp *interp; /* Current interpreter. */ + TagSearch *searchPtr; /* Search data */ + TagSearchExpr *expr; /* compiled expression result */ +{ + int looking_for_tag; /* When true, scanner expects + * next char(s) to be a tag, + * else operand expected */ + int found_tag; /* One or more tags found */ + int found_endquote; /* For quoted tag string parsing */ + int negate_result; /* Pending negation of next tag value */ + char *tag; /* tag from tag expression string */ + char c; + + negate_result = 0; + found_tag = 0; + looking_for_tag = 1; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + + if (expr->allocated == expr->index) { + expr->allocated += 15; + if (expr->uids) { + expr->uids = + (Tk_Uid *) ckrealloc((char *)(expr->uids), + (expr->allocated)*sizeof(Tk_Uid)); + } else { + expr->uids = + (Tk_Uid *) ckalloc((expr->allocated)*sizeof(Tk_Uid)); + } + } + + if (looking_for_tag) { + + switch (c) { + + /* ignore unquoted whitespace */ + case ' ' : + case '\t' : + case '\n' : + case '\r' : + break; + + /* negate next tag or subexpr */ + case '!' : + if (looking_for_tag > 1) { + Tcl_AppendResult(interp, + "Too many '!' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + looking_for_tag++; + negate_result = 1; + break; + + /* scan subexpr (or negated subexpr) recursively */ + case '(' : + if (negate_result) { + expr->uids[expr->index++] = negparenUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = parenUid; + } + if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) { + /* Result string should be already set + * by nested call to tag_expr_scan() */ + return TCL_ERROR; + } + looking_for_tag = 0; + found_tag = 1; + break; + + /* quoted tag string */ + case '"' : + if (negate_result) { + expr->uids[expr->index++] = negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = tagvalUid; + } + tag = searchPtr->rewritebuffer; + found_endquote = 0; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + if (c == '\\') { + c = searchPtr->string[searchPtr->stringIndex++]; + } + if (c == '"') { + found_endquote = 1; + break; + } + *tag++ = c; + } + if (! found_endquote) { + Tcl_AppendResult(interp, + "Missing endquote in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + if (! (tag - searchPtr->rewritebuffer)) { + Tcl_AppendResult(interp, + "Null quoted tag string in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + *tag++ = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + break; + + /* illegal chars when looking for tag */ + case '&' : + case '|' : + case '^' : + case ')' : + Tcl_AppendResult(interp, + "Unexpected operator in tag search expression", + (char *) NULL); + return TCL_ERROR; + + /* unquoted tag string */ + default : + if (negate_result) { + expr->uids[expr->index++] = negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = tagvalUid; + } + tag = searchPtr->rewritebuffer; + *tag++ = c; + /* copy rest of tag, including any embedded whitespace */ + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex]; + if (c == '!' + || c == '&' + || c == '|' + || c == '^' + || c == '(' + || c == ')' + || c == '"') { + break; + } + *tag++ = c; + searchPtr->stringIndex++; + } + /* remove trailing whitespace */ + while (1) { + c = *--tag; + /* there must have been one non-whitespace char, + * so this will terminate */ + if (c != ' ' + && c != '\t' + && c != '\n' + && c != '\r') + break; + } + *++tag = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + } + + } else { /* ! looking_for_tag */ + + switch (c) { + + /* ignore whitespace */ + case ' ' : + case '\t' : + case '\n' : + case '\r' : + break; + + /* AND operator */ + case '&' : + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '&') { + Tcl_AppendResult(interp, + "Singleton '&' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = andUid; + looking_for_tag = 1; + break; + + /* OR operator */ + case '|' : + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '|') { + Tcl_AppendResult(interp, + "Singleton '|' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = orUid; + looking_for_tag = 1; + break; + + /* XOR operator */ + case '^' : + expr->uids[expr->index++] = xorUid; + looking_for_tag = 1; + break; + + /* end subexpression */ + case ')' : + expr->uids[expr->index++] = endparenUid; + goto breakwhile; + + /* syntax error */ + default : + Tcl_AppendResult(interp, + "Invalid boolean operator in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + } + } + breakwhile: + if (found_tag && ! looking_for_tag) { + return TCL_OK; + } + Tcl_AppendResult(interp, + "Missing tag in tag search expression", (char *) NULL); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchEvalExpr -- + * + * This recursive procedure is called to eval a tag expression. + * + * Results: + * The return value indicates if the tagOrId expression + * successfully matched the tags of the current item. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchEvalExpr(expr, itemPtr) + TagSearchExpr *expr; /* Search expression */ + Tk_Item *itemPtr; /* Item being test for match */ +{ + int looking_for_tag; /* When true, scanner expects + * next char(s) to be a tag, + * else operand expected */ + int negate_result; /* Pending negation of next tag value */ + Tk_Uid uid; + Tk_Uid *tagPtr; + int count; + int result; /* Value of expr so far */ + int parendepth; + + result = 0; /* just to keep the compiler quiet */ + + negate_result = 0; + looking_for_tag = 1; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (looking_for_tag) { + if (uid == tagvalUid) { +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + /* + * set result 1 if tag is found in item's tags + */ + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + + } else if (uid == negtagvalUid) { + negate_result = ! negate_result; +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + /* + * set result 1 if tag is found in item's tags + */ + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + + } else if (uid == parenUid) { + /* + * evaluate subexpressions with recursion + */ + result = TagSearchEvalExpr(expr, itemPtr); + + } else if (uid == negparenUid) { + negate_result = ! negate_result; + /* + * evaluate subexpressions with recursion + */ + result = TagSearchEvalExpr(expr, itemPtr); +/* + * } else { + * assert(0); + */ + } + if (negate_result) { + result = ! result; + negate_result = 0; + } + looking_for_tag = 0; + } else { /* ! looking_for_tag */ + if (((uid == andUid) && (!result)) || ((uid == orUid) && result)) { + /* + * short circuit expression evaluation + * + * if result before && is 0, or result before || is 1, + * then the expression is decided and no further + * evaluation is needed. + */ + + parendepth = 0; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (uid == tagvalUid || uid == negtagvalUid) { + expr->index++; + continue; + } + if (uid == parenUid || uid == negparenUid) { + parendepth++; + continue; + } + if (uid == endparenUid) { + parendepth--; + if (parendepth < 0) { + break; + } + } + } + return result; + + } else if (uid == xorUid) { + /* + * if the previous result was 1 + * then negate the next result + */ + negate_result = result; + + } else if (uid == endparenUid) { + return result; +/* + * } else { + * assert(0); + */ + } + looking_for_tag = 1; + } + } +/* + * assert(! looking_for_tag); + */ + return result; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchFirst -- + * + * This procedure is called to get the first item + * item that matches a preestablished search predicate + * that was set by TagSearchScan. + * + * Results: + * The return value is a pointer to the first item, or NULL + * if there is no such item. The information at *searchPtr + * is updated such that successive calls to TagSearchNext + * will return successive items. + * + * Side effects: + * SearchPtr is linked into a list of searches in progress + * on canvasPtr, so that elements can safely be deleted + * while the search is in progress. + * + *-------------------------------------------------------------- + */ + +static Tk_Item * +TagSearchFirst(searchPtr) + TagSearch *searchPtr; /* Record describing tag search */ +{ + Tk_Item *itemPtr, *lastPtr; + Tk_Uid uid, *tagPtr; + int count; + + /* short circuit impossible searches for null tags */ + if (searchPtr->stringLength == 0) { + return NULL; + } + + /* + * Find the first matching item in one of several ways. If the tag + * is a number then it selects the single item with the matching + * identifier. In this case see if the item being requested is the + * hot item, in which case the search can be skipped. + */ + + if (searchPtr->type == 1) { + Tcl_HashEntry *entryPtr; + + itemPtr = searchPtr->canvasPtr->hotPtr; + lastPtr = searchPtr->canvasPtr->hotPrevPtr; + if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id) || (lastPtr == NULL) + || (lastPtr->nextPtr != itemPtr)) { + entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable, + (char *) searchPtr->id); + if (entryPtr != NULL) { + itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr); + lastPtr = itemPtr->prevPtr; + } else { + lastPtr = itemPtr = NULL; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + searchPtr->canvasPtr->hotPtr = itemPtr; + searchPtr->canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + + if (searchPtr->type == 2) { + + /* + * All items match. + */ + + searchPtr->lastPtr = NULL; + searchPtr->currentPtr = searchPtr->canvasPtr->firstItemPtr; + return searchPtr->canvasPtr->firstItemPtr; + } + + if (searchPtr->type == 3) { + + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } else { + + /* + * None of the above. Search for an item matching the tag expression. + */ + + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchNext -- + * + * This procedure returns successive items that match a given + * tag; it should be called only after TagSearchFirst has been + * used to begin a search. + * + * Results: + * The return value is a pointer to the next item that matches + * the tag expr specified to TagSearchScan, or NULL if no such + * item exists. *SearchPtr is updated so that the next call + * to this procedure will return the next item. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_Item * +TagSearchNext(searchPtr) + TagSearch *searchPtr; /* Record describing search in + * progress. */ +{ + Tk_Item *itemPtr, *lastPtr; + Tk_Uid uid, *tagPtr; + int count; + + /* + * Find next item in list (this may not actually be a suitable + * one to return), and return if there are no items left. + */ + + lastPtr = searchPtr->lastPtr; + if (lastPtr == NULL) { + itemPtr = searchPtr->canvasPtr->firstItemPtr; + } else { + itemPtr = lastPtr->nextPtr; + } + if ((itemPtr == NULL) || (searchPtr->searchOver)) { + searchPtr->searchOver = 1; + return NULL; + } + if (itemPtr != searchPtr->currentPtr) { + /* + * The structure of the list has changed. Probably the + * previously-returned item was removed from the list. + * In this case, don't advance lastPtr; just return + * its new successor (i.e. do nothing here). + */ + } else { + lastPtr = itemPtr; + itemPtr = lastPtr->nextPtr; + } + + if (searchPtr->type == 2) { + + /* + * All items match. + */ + + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + + if (searchPtr->type == 3) { + + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; + } + + /* + * Else.... evaluate tag expression + */ + + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} +#endif /* USE_OLD_TAG_SEARCH */ + /* *-------------------------------------------------------------- * @@ -2473,58 +3957,81 @@ DoItem(interp, itemPtr, tag) */ static int -FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) +#ifdef USE_OLD_TAG_SEARCH +FindItems(interp, canvasPtr, argc, argv, newTag, first) +#else /* USE_OLD_TAG_SEARCH */ +FindItems(interp, canvasPtr, argc, argv, newTag, first, searchPtrPtr) +#endif /* USE_OLD_TAG_SEARCH */ Tcl_Interp *interp; /* Interpreter for error reporting. */ TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ int argc; /* Number of entries in argv. Must be * greater than zero. */ - char **argv; /* Arguments that describe what items + Tcl_Obj *CONST *argv; /* Arguments that describe what items * to search for (see user doc on * "find" and "addtag" options). */ - char *newTag; /* If non-NULL, gives new tag to set + Tcl_Obj *newTag; /* If non-NULL, gives new tag to set * on all found items; if NULL, then * ids of found items are returned * in the interp's result. */ - char *cmdName; /* Name of original Tcl command, for - * use in error messages. */ - char *option; /* For error messages: gives option - * from Tcl command and other stuff - * up to what's in argc/argv. */ + int first; /* For error messages: gives number + * of elements of argv which are already + * handled. */ +#ifndef USE_OLD_TAG_SEARCH + TagSearch **searchPtrPtr; /* From CanvasWidgetCmd local vars*/ +#endif /* not USE_OLD_TAG_SEARCH */ { - int c; - size_t length; +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ Tk_Item *itemPtr; Tk_Uid uid; + int index; + static char *optionStrings[] = { + "above", "all", "below", "closest", + "enclosed", "overlapping", "withtag", NULL + }; + enum options { + CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST, + CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG + }; if (newTag != NULL) { - uid = Tk_GetUid(newTag); + uid = Tk_GetUid(Tcl_GetStringFromObj(newTag, NULL)); } else { uid = NULL; } - c = argv[0][0]; - length = strlen(argv[0]); - if ((c == 'a') && (strncmp(argv[0], "above", length) == 0) - && (length >= 2)) { + if (Tcl_GetIndexFromObj(interp, argv[first], optionStrings, "search command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum options) index) { + case CANV_ABOVE: { Tk_Item *lastPtr = NULL; - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " above tagOrId", (char *) NULL); + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); +#ifdef USE_OLD_TAG_SEARCH + for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ lastPtr = itemPtr; } if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) { DoItem(interp, lastPtr->nextPtr, uid); } - } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0) - && (length >= 2)) { - if (argc != 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " all", (char *) NULL); + break; + } + case CANV_ALL: { + if (argc != first+1) { + Tcl_WrongNumArgs(interp, first+1, argv, (char *) NULL); return TCL_ERROR; } @@ -2532,45 +4039,53 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) itemPtr = itemPtr->nextPtr) { DoItem(interp, itemPtr, uid); } - } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) { + break; + } + case CANV_BELOW: { Tk_Item *itemPtr; - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " below tagOrId", (char *) NULL); + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - itemPtr = StartTagSearch(canvasPtr, argv[1], &search); +#ifdef USE_OLD_TAG_SEARCH + itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + itemPtr = TagSearchFirst(*searchPtrPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { if (itemPtr->prevPtr != NULL) { DoItem(interp, itemPtr->prevPtr, uid); } } - } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) { + break; + } + case CANV_CLOSEST: { double closestDist; Tk_Item *startPtr, *closestPtr; double coords[2], halo; int x1, y1, x2, y2; - if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " closest x y ?halo? ?start?", - (char *) NULL); + if ((argc < first+3) || (argc > first+5)) { + Tcl_WrongNumArgs(interp, first+1, argv, "x y ?halo? ?start?"); return TCL_ERROR; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], - &coords[0]) != TCL_OK) || (Tk_CanvasGetCoord(interp, - (Tk_Canvas) canvasPtr, argv[2], &coords[1]) != TCL_OK)) { + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+1], + &coords[0]) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, + (Tk_Canvas) canvasPtr, argv[first+2], &coords[1]) != TCL_OK)) { return TCL_ERROR; } - if (argc > 3) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + if (argc > first+3) { + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+3], &halo) != TCL_OK) { return TCL_ERROR; } if (halo < 0.0) { Tcl_AppendResult(interp, "can't have negative halo value \"", - argv[3], "\"", (char *) NULL); + Tcl_GetString(argv[3]), "\"", (char *) NULL); return TCL_ERROR; } } else { @@ -2582,8 +4097,15 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) */ startPtr = canvasPtr->firstItemPtr; - if (argc == 5) { - itemPtr = StartTagSearch(canvasPtr, argv[4], &search); + if (argc == first+5) { +#ifdef USE_OLD_TAG_SEARCH + itemPtr = StartTagSearch(canvasPtr, argv[first+4], &search); +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+4], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + itemPtr = TagSearchFirst(*searchPtrPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { startPtr = itemPtr; } @@ -2598,6 +4120,10 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) */ itemPtr = startPtr; + while(itemPtr && (itemPtr->state == TK_STATE_HIDDEN || + (itemPtr->state == TK_STATE_NULL && canvasPtr->canvas_state == TK_STATE_HIDDEN))) { + itemPtr = itemPtr->nextPtr; + } if (itemPtr == NULL) { return TCL_OK; } @@ -2635,6 +4161,10 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) DoItem(interp, closestPtr, uid); return TCL_OK; } + if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { continue; @@ -2650,36 +4180,40 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) } } } - } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL); + break; + } + case CANV_ENCLOSED: { + if (argc != first+5) { + Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2"); return TCL_ERROR; } - return FindArea(interp, canvasPtr, argv+1, uid, 1); - } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " overlapping x1 y1 x2 y2", - (char *) NULL); + return FindArea(interp, canvasPtr, argv+first+1, uid, 1); + } + case CANV_OVERLAPPING: { + if (argc != first+5) { + Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2"); return TCL_ERROR; } - return FindArea(interp, canvasPtr, argv+1, uid, 0); - } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " withtag tagOrId", (char *) NULL); + return FindArea(interp, canvasPtr, argv+first+1, uid, 0); + } + case CANV_WITHTAG: { + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); +#ifdef USE_OLD_TAG_SEARCH + for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ DoItem(interp, itemPtr, uid); } - } else { - Tcl_AppendResult(interp, "bad search command \"", argv[0], - "\": must be above, all, below, closest, enclosed, ", - "overlapping, or withtag", (char *) NULL); - return TCL_ERROR; + } } return TCL_OK; } @@ -2714,7 +4248,7 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) * and result storing. */ TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ - char **argv; /* Array of four arguments that + Tcl_Obj *CONST *argv; /* Array of four arguments that * give the coordinates of the * rectangular area to search. */ Tk_Uid uid; /* If non-NULL, gives new tag to set @@ -2729,13 +4263,13 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) int x1, y1, x2, y2; Tk_Item *itemPtr; - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0], + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[0], &rect[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[1], &rect[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[2], &rect[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &rect[3]) != TCL_OK)) { return TCL_ERROR; } @@ -2757,6 +4291,10 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) y2 = (int) (rect[3]+1.0); for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { continue; @@ -2789,17 +4327,27 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) *-------------------------------------------------------------- */ +#ifdef USE_OLD_TAG_SEARCH static void RelinkItems(canvasPtr, tag, prevPtr) +#else /* USE_OLD_TAG_SEARCH */ +static int +RelinkItems(canvasPtr, tag, prevPtr, searchPtrPtr) +#endif /* USE_OLD_TAG_SEARCH */ TkCanvas *canvasPtr; /* Canvas to be modified. */ - char *tag; /* Tag identifying items to be moved + Tcl_Obj *tag; /* Tag identifying items to be moved * in the redisplay list. */ Tk_Item *prevPtr; /* Reposition the items so that they * go just after this item (NULL means * put at beginning of list). */ +#ifndef USE_OLD_TAG_SEARCH + TagSearch **searchPtrPtr; /* From CanvasWidgetCmd local vars */ +#endif /* not USE_OLD_TAG_SEARCH */ { Tk_Item *itemPtr; +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ Tk_Item *firstMovePtr, *lastMovePtr; /* @@ -2809,8 +4357,16 @@ RelinkItems(canvasPtr, tag, prevPtr) */ firstMovePtr = lastMovePtr = NULL; +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, tag, &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, tag, searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr == prevPtr) { /* * Item after which insertion is to occur is being @@ -2841,8 +4397,7 @@ RelinkItems(canvasPtr, tag, prevPtr) lastMovePtr->nextPtr = itemPtr; } lastMovePtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1, - itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } @@ -2852,7 +4407,11 @@ RelinkItems(canvasPtr, tag, prevPtr) */ if (firstMovePtr == NULL) { +#ifdef USE_OLD_TAG_SEARCH return; +#else /* USE_OLD_TAG_SEARCH */ + return TCL_OK; +#endif /* USE_OLD_TAG_SEARCH */ } if (prevPtr == NULL) { if (canvasPtr->firstItemPtr != NULL) { @@ -2873,6 +4432,9 @@ RelinkItems(canvasPtr, tag, prevPtr) if (canvasPtr->lastItemPtr == prevPtr) { canvasPtr->lastItemPtr = lastMovePtr; } +#ifndef USE_OLD_TAG_SEARCH + return TCL_OK; +#endif /* not USE_OLD_TAG_SEARCH */ } /* @@ -2990,8 +4552,9 @@ CanvasBindProc(clientData, eventPtr) * Find the topmost item in a canvas that contains a given * location and mark the the current item. If the current * item has changed, generate a fake exit event on the old - * current item and a fake enter event on the new current - * item. + * current item, a fake enter event on the new current item + * item and force a redraw of the two items. Canvas items + * that are hidden or disabled are ignored. * * Results: * None. @@ -3017,6 +4580,7 @@ PickCurrentItem(canvasPtr, eventPtr) { double coords[2]; int buttonDown; + Tk_Item *prevItemPtr; /* * Check whether or not a button is down. If so, we'll log entry @@ -3138,7 +4702,11 @@ PickCurrentItem(canvasPtr, eventPtr) if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) { for (i = itemPtr->numTags-1; i >= 0; i--) { +#ifdef USE_OLD_TAG_SEARCH if (itemPtr->tagPtr[i] == Tk_GetUid("current")) { +#else /* USE_OLD_TAG_SEARCH */ + if (itemPtr->tagPtr[i] == currentUid) { +#endif /* USE_OLD_TAG_SEARCH */ itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; itemPtr->numTags--; break; @@ -3163,13 +4731,33 @@ PickCurrentItem(canvasPtr, eventPtr) * if LEFT_GRABBED_ITEM was set. */ + prevItemPtr = canvasPtr->currentItemPtr; canvasPtr->flags &= ~LEFT_GRABBED_ITEM; canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr; + if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr && + (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) { + EventuallyRedrawItem((Tk_Canvas) canvasPtr, prevItemPtr); + (*prevItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_Canvas) canvasPtr, prevItemPtr, 0, (Tcl_Obj **) NULL, + TK_CONFIG_ARGV_ONLY); + } if (canvasPtr->currentItemPtr != NULL) { XEvent event; +#ifdef USE_OLD_TAG_SEARCH DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, Tk_GetUid("current")); +#else /* USE_OLD_TAG_SEARCH */ + DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid); +#endif /* USE_OLD_TAG_SEA */ + if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT && + prevItemPtr != canvasPtr->currentItemPtr)) { + (*canvasPtr->currentItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_Canvas) canvasPtr, canvasPtr->currentItemPtr, 0, (Tcl_Obj **) NULL, + TK_CONFIG_ARGV_ONLY); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->currentItemPtr); + } event = canvasPtr->pickEvent; event.type = EnterNotify; event.xcrossing.detail = NotifyAncestor; @@ -3183,7 +4771,8 @@ PickCurrentItem(canvasPtr, eventPtr) * CanvasFindClosest -- * * Given x and y coordinates, find the topmost canvas item that - * is "close" to the coordinates. + * is "close" to the coordinates. Canvas items that are hidden + * or disabled are ignored. * * Results: * The return value is a pointer to the topmost item that is @@ -3213,6 +4802,11 @@ CanvasFindClosest(canvasPtr, coords) bestPtr = NULL; for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (itemPtr->state == TK_STATE_HIDDEN || itemPtr->state==TK_STATE_DISABLED || + (itemPtr->state == TK_STATE_NULL && (canvasPtr->canvas_state == TK_STATE_HIDDEN || + canvasPtr->canvas_state == TK_STATE_DISABLED))) { + continue; + } if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1) || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) { continue; @@ -3257,6 +4851,10 @@ CanvasDoEvent(canvasPtr, eventPtr) ClientData *objectPtr; int numObjects, i; Tk_Item *itemPtr; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *expr; + int numExprs; +#endif /* not USE_OLD_TAG_SEARCH */ if (canvasPtr->bindingTable == NULL) { return; @@ -3270,6 +4868,7 @@ CanvasDoEvent(canvasPtr, eventPtr) return; } +#ifdef USE_OLD_TAG_SEARCH /* * Set up an array with all the relevant objects for processing * this event. The relevant objects are (a) the event's item, @@ -3279,17 +4878,62 @@ CanvasDoEvent(canvasPtr, eventPtr) */ numObjects = itemPtr->numTags + 2; +#else /* USE_OLD_TAG_SEARCH */ + /* + * Set up an array with all the relevant objects for processing + * this event. The relevant objects are: + * (a) the event's item, + * (b) the tags associated with the event's item, + * (c) the expressions that are true for the event's item's tags, and + * (d) the tag "all". + * + * If there are a lot of tags then malloc an array to hold all of + * the objects. + */ + + /* + * flag and count all expressions that match item's tags + */ + numExprs = 0; + expr = canvasPtr->bindTagExprs; + while (expr) { + expr->index = 0; + if ((expr->match = TagSearchEvalExpr(expr, itemPtr))) { + numExprs++; + } + expr = expr->next; + } + + numObjects = itemPtr->numTags + numExprs + 2; +#endif /* not USE_OLD_TAG_SEARCH */ if (numObjects <= NUM_STATIC) { objectPtr = staticObjects; } else { objectPtr = (ClientData *) ckalloc((unsigned) (numObjects * sizeof(ClientData))); } +#ifdef USE_OLD_TAG_SEARCH objectPtr[0] = (ClientData) Tk_GetUid("all"); +#else /* USE_OLD_TAG_SEARCH */ + objectPtr[0] = (ClientData) allUid; +#endif /* USE_OLD_TAG_SEARCH */ for (i = itemPtr->numTags-1; i >= 0; i--) { objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i]; } objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr; +#ifndef USE_OLD_TAG_SEARCH + /* + * copy uids of matching expressions into object array + */ + i = itemPtr->numTags+2; + expr = canvasPtr->bindTagExprs; + while (expr) { + if (expr->match) { + objectPtr[i++] = (int *) expr->uid; + } + expr = expr->next; + } +#endif /* not USE_OLD_TAG_SEARCH */ /* * Invoke the binding system, then free up the object array if @@ -3344,11 +4988,8 @@ CanvasBlinkProc(clientData) (ClientData) canvasPtr); } if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); } } @@ -3391,11 +5032,8 @@ CanvasFocusProc(canvasPtr, gotFocus) canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; } if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); } if (canvasPtr->highlightWidth > 0) { canvasPtr->flags |= REDRAW_BORDERS; @@ -3445,11 +5083,8 @@ CanvasSelectTo(canvasPtr, itemPtr, index) Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection, (ClientData) canvasPtr); } else if (canvasPtr->textInfo.selItemPtr != itemPtr) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); } canvasPtr->textInfo.selItemPtr = itemPtr; @@ -3467,8 +5102,7 @@ CanvasSelectTo(canvasPtr, itemPtr, index) if ((canvasPtr->textInfo.selectFirst != oldFirst) || (canvasPtr->textInfo.selectLast != oldLast) || (itemPtr != oldSelPtr)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } @@ -3542,11 +5176,8 @@ CanvasLostSelection(clientData) TkCanvas *canvasPtr = (TkCanvas *) clientData; if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); } canvasPtr->textInfo.selItemPtr = NULL; } @@ -3851,3 +5482,235 @@ CanvasSetOrigin(canvasPtr, xOrigin, yOrigin) canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); } + +/* + *---------------------------------------------------------------------- + * + * GetStringsFromObjs + * + * Results: + * Converts object list into string list. + * + * Side effects: + * Memory is allocated for the argv array, which must + * be freed using ckfree() when no longer needed. + * + *---------------------------------------------------------------------- + */ +/* ARGSUSED */ +static char ** +GetStringsFromObjs(argc, objv) + int argc; + Tcl_Obj *CONST objv[]; +{ + register int i; + char **argv; + if (argc <= 0) { + return NULL; + } + argv = (char **) ckalloc((argc+1) * sizeof(char *)); + for (i = 0; i < argc; i++) { + argv[i]=Tcl_GetStringFromObj(objv[i], (int *) NULL); + } + argv[argc] = 0; + return argv; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsColor -- + * + * This procedure is called by individual canvas items when + * they want to set a color value for output. Given information + * about an X color, this procedure will generate Postscript + * commands to set up an appropriate color in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsColor(interp, canvas, colorPtr) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + XColor *colorPtr; /* Information about color. */ +{ + return Tk_PostscriptColor(interp, ((TkCanvas *) canvas)->psInfo, + colorPtr); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsFont -- + * + * This procedure is called by individual canvas items when + * they want to output text. Given information about an X + * font, this procedure will generate Postscript commands + * to set up an appropriate font in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to the interp->result. + * + * Side effects: + * The Postscript font name is entered into psInfoPtr->fontTable + * if it wasn't already there. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsFont(interp, canvas, tkfont) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Tk_Font tkfont; /* Information about font in which text + * is to be printed. */ +{ + return Tk_PostscriptFont(interp, ((TkCanvas *) canvas)->psInfo, tkfont); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsBitmap -- + * + * This procedure is called to output the contents of a + * sub-region of a bitmap in proper image data format for + * Postscript (i.e. data between angle brackets, one bit + * per pixel). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Pixmap bitmap; /* Bitmap for which to generate + * Postscript. */ + int startX, startY; /* Coordinates of upper-left corner + * of rectangular region to output. */ + int width, height; /* Height of rectangular region. */ +{ + return Tk_PostscriptBitmap(interp, ((TkCanvas *) canvas)->tkwin, + ((TkCanvas *) canvas)->psInfo, bitmap, startX, startY, + width, height); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsStipple -- + * + * This procedure is called by individual canvas items when + * they have created a path that they'd like to be filled with + * a stipple pattern. Given information about an X bitmap, + * this procedure will generate Postscript commands to fill + * the current clip region using a stipple pattern defined by the + * bitmap. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsStipple(interp, canvas, bitmap) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Pixmap bitmap; /* Bitmap to use for stippling. */ +{ + return Tk_PostscriptStipple(interp, ((TkCanvas *) canvas)->tkwin, + ((TkCanvas *) canvas)->psInfo, bitmap); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsY -- + * + * Given a y-coordinate in canvas coordinates, this procedure + * returns a y-coordinate to use for Postscript output. + * + * Results: + * Returns the Postscript coordinate that corresponds to + * "y". + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +Tk_CanvasPsY(canvas, y) + Tk_Canvas canvas; /* Token for canvas on whose behalf + * Postscript is being generated. */ + double y; /* Y-coordinate in canvas coords. */ +{ + return Tk_PostscriptY(y, ((TkCanvas *) canvas)->psInfo); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsPath -- + * + * Given an array of points for a path, generate Postscript + * commands to create the path. + * + * Results: + * Postscript commands get appended to what's in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) + Tcl_Interp *interp; /* Put generated Postscript in this + * interpreter's result field. */ + Tk_Canvas canvas; /* Canvas on whose behalf Postscript + * is being generated. */ + double *coordPtr; /* Pointer to first in array of + * 2*numPoints coordinates giving + * points for path. */ + int numPoints; /* Number of points at *coordPtr. */ +{ + Tk_PostscriptPath(interp, ((TkCanvas *) canvas)->psInfo, + coordPtr, numPoints); +} diff --git a/generic/tkCanvas.h b/generic/tkCanvas.h index 9dbcd0f..9d2c392 100644 --- a/generic/tkCanvas.h +++ b/generic/tkCanvas.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvas.h,v 1.3 1998/10/13 18:13:06 rjohnson Exp $ + * RCS: @(#) $Id: tkCanvas.h,v 1.4 1999/12/14 06:52:27 hobbs Exp $ */ #ifndef _TKCANVAS @@ -21,6 +21,20 @@ #include "tk.h" #endif +#ifndef USE_OLD_TAG_SEARCH +typedef struct TagSearchExpr_s TagSearchExpr; + +struct TagSearchExpr_s { + TagSearchExpr *next; /* for linked lists of expressions - used in bindings */ + Tk_Uid uid; /* the uid of the whole expression */ + Tk_Uid *uids; /* expresion compiled to an array of uids */ + int allocated; /* available space for array of uids */ + int length; /* length of expression */ + int index; /* current position in expression evaluation */ + int match; /* this expression matches event's item's tags*/ +}; +#endif /* not USE_OLD_TAG_SEARCH */ + /* * The record below describes a canvas widget. It is made available * to the item procedures so they can access certain shared fields such @@ -204,12 +218,23 @@ typedef struct TkCanvas { * definitions. */ int nextId; /* Number to use as id for next item * created in widget. */ - struct TkPostscriptInfo *psInfoPtr; + Tk_PostscriptInfo psInfo; /* Pointer to information used for generating * Postscript for the canvas. NULL means * no Postscript is currently being * generated. */ Tcl_HashTable idTable; /* Table of integer indices. */ + /* + * Additional information, added by the 'dash'-patch + */ + VOID *reserved1; + Tk_State canvas_state; /* state of canvas */ + VOID *reserved2; + VOID *reserved3; + Tk_TSOffset tsoffset; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *bindTagExprs; /* linked list of tag expressions used in bindings */ +#endif } TkCanvas; /* @@ -237,6 +262,8 @@ typedef struct TkCanvas { * REPICK_IN_PROGRESS - 1 means PickCurrentItem is currently * executing. If it should be called recursively, * it should simply return immediately. + * BBOX_NOT_EMPTY - 1 means that the bounding box of the area + * that should be redrawn is not empty. */ #define REDRAW_PENDING 1 @@ -247,6 +274,18 @@ typedef struct TkCanvas { #define UPDATE_SCROLLBARS 0x20 #define LEFT_GRABBED_ITEM 0x40 #define REPICK_IN_PROGRESS 0x100 +#define BBOX_NOT_EMPTY 0x200 + +/* + * Flag bits for canvas items (redraw_flags): + * + * FORCE_REDRAW - 1 means that the new coordinates of some + * item are not yet registered using + * Tk_CanvasEventuallyRedraw(). It should still + * be done by the general canvas code. + */ + +#define FORCE_REDRAW 8 /* * Canvas-related procedures that are shared among Tk modules but not @@ -256,4 +295,18 @@ typedef struct TkCanvas { extern int TkCanvPostscriptCmd _ANSI_ARGS_((TkCanvas *canvasPtr, Tcl_Interp *interp, int argc, char **argv)); +/* + * The following definition is shared between tkCanvPs.c and tkCanvImg.c, + * and is used in generating postscript for images and windows. + */ + +typedef struct TkColormapData { /* Hold color information for a window */ + int separated; /* Whether to use separate color bands */ + int color; /* Whether window is color or black/white */ + int ncolors; /* Number of color values stored */ + XColor *colors; /* Pixel value -> RGB mappings */ + int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ + int red_shift, green_shift, blue_shift; /* color band */ +} TkColormapData; + #endif /* _TKCANVAS */ diff --git a/generic/tkDecls.h b/generic/tkDecls.h index c017771..7293542 100644 --- a/generic/tkDecls.h +++ b/generic/tkDecls.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkDecls.h,v 1.5 1999/04/30 22:49:54 stanton Exp $ + * RCS: @(#) $Id: tkDecls.h,v 1.6 1999/12/14 06:52:27 hobbs Exp $ */ #ifndef _TKDECLS @@ -748,6 +748,16 @@ EXTERN void Tk_InitConsoleChannels _ANSI_ARGS_(( /* 216 */ EXTERN int Tk_CreateConsoleWindow _ANSI_ARGS_(( Tcl_Interp * interp)); +/* 217 */ +EXTERN void Tk_CreateSmoothMethod _ANSI_ARGS_(( + Tcl_Interp * interp, + Tk_SmoothMethod * method)); +/* 218 */ +EXTERN void Tk_CreateCanvasVisitor _ANSI_ARGS_(( + Tcl_Interp * interp, VOID * typePtr)); +/* 219 */ +EXTERN VOID * Tk_GetCanvasVisitor _ANSI_ARGS_((Tcl_Interp * interp, + CONST char * name)); typedef struct TkStubHooks { struct TkPlatStubs *tkPlatStubs; @@ -977,6 +987,9 @@ typedef struct TkStubs { int (*tk_SetOptions) _ANSI_ARGS_((Tcl_Interp * interp, char * recordPtr, Tk_OptionTable optionTable, int objc, Tcl_Obj *CONST objv[], Tk_Window tkwin, Tk_SavedOptions * savePtr, int * maskPtr)); /* 214 */ void (*tk_InitConsoleChannels) _ANSI_ARGS_((Tcl_Interp * interp)); /* 215 */ int (*tk_CreateConsoleWindow) _ANSI_ARGS_((Tcl_Interp * interp)); /* 216 */ + void (*tk_CreateSmoothMethod) _ANSI_ARGS_((Tcl_Interp * interp, Tk_SmoothMethod * method)); /* 217 */ + void (*tk_CreateCanvasVisitor) _ANSI_ARGS_((Tcl_Interp * interp, VOID * typePtr)); /* 218 */ + VOID * (*tk_GetCanvasVisitor) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * name)); /* 219 */ } TkStubs; #ifdef __cplusplus @@ -1861,6 +1874,18 @@ extern TkStubs *tkStubsPtr; #define Tk_CreateConsoleWindow \ (tkStubsPtr->tk_CreateConsoleWindow) /* 216 */ #endif +#ifndef Tk_CreateSmoothMethod +#define Tk_CreateSmoothMethod \ + (tkStubsPtr->tk_CreateSmoothMethod) /* 217 */ +#endif +#ifndef Tk_CreateCanvasVisitor +#define Tk_CreateCanvasVisitor \ + (tkStubsPtr->tk_CreateCanvasVisitor) /* 218 */ +#endif +#ifndef Tk_GetCanvasVisitor +#define Tk_GetCanvasVisitor \ + (tkStubsPtr->tk_GetCanvasVisitor) /* 219 */ +#endif #endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ diff --git a/generic/tkEntry.c b/generic/tkEntry.c index 8ae1b06..ac0f288 100644 --- a/generic/tkEntry.c +++ b/generic/tkEntry.c @@ -11,12 +11,14 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkEntry.c,v 1.6 1999/11/10 02:56:24 hobbs Exp $ + * RCS: @(#) $Id: tkEntry.c,v 1.7 1999/12/14 06:52:27 hobbs Exp $ */ #include "tkInt.h" #include "default.h" +#define ENTRY_VALIDATE + /* * A data structure of the following type is kept for each entry * widget managed by this file: @@ -151,6 +153,16 @@ typedef struct { int avgWidth; /* Width of average character. */ int flags; /* Miscellaneous flags; see below for * definitions. */ + Tk_TSOffset tsoffset; + +#ifdef ENTRY_VALIDATE + char *validateCmd; /* Command prefix to use when invoking + * validate command. NULL means don't + * invoke commands. Malloc'ed. */ + int validate; /* Non-zero means try to validate */ + char *invalidCmd; /* Command called when a validation returns 0 + * (successfully fails), defaults to {}. */ +#endif /* ENTRY_VALIDATE */ } Entry; /* @@ -169,6 +181,11 @@ typedef struct { * UPDATE_SCROLLBAR: Non-zero means scrollbar should be updated * during next redisplay operation. * GOT_SELECTION: Non-zero means we've claimed the selection. + * VALIDATING: Non-zero means we are in a validateCmd + * VALIDATE_VAR: Non-zero means we are attempting to validate + * the entry's textvariable with validateCmd + * VALIDATE_ABORT: Non-zero if validatecommand signals an abort + * for current procedure and make no changes */ #define REDRAW_PENDING 1 @@ -178,6 +195,11 @@ typedef struct { #define UPDATE_SCROLLBAR 0x10 #define GOT_SELECTION 0x20 #define ENTRY_DELETED 0x40 +#ifdef ENTRY_VALIDATE +#define VALIDATING 0x80 +#define VALIDATE_VAR 0x100 +#define VALIDATE_ABORT 0x200 +#endif /* ENTRY_VALIDATE */ /* * The following macro defines how many extra pixels to leave on each @@ -201,6 +223,27 @@ static char *stateStrings[] = { "disabled", "normal", (char *) NULL }; +#ifdef ENTRY_VALIDATE +/* + * Definitions for -validate option values: + */ + +static char *validateStrings[] = { + "all", "key", "focus", "focusin", "focusout", "none", (char *) NULL +}; +enum validateType { + VALIDATE_ALL, VALIDATE_KEY, VALIDATE_FOCUS, + VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT, VALIDATE_NONE, + /* + * These extra enums are for use with EntryValidateChange + */ + VALIDATE_FORCED, VALIDATE_DELETE, VALIDATE_INSERT +}; +#define DEF_ENTRY_VALIDATE "none" +#define DEF_ENTRY_INVALIDCMD "" + +#endif /* ENTRY_VALIDATE */ + /* * Information used for argv parsing. */ @@ -256,6 +299,13 @@ static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth), 0, 0, 0}, +#ifdef ENTRY_VALIDATE + {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand", + DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd), + 0, 0, 0}, + {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0}, +#endif /* ENTRY_VALIDATE */ {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", @@ -283,6 +333,16 @@ static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName), TK_CONFIG_NULL_OK, 0, 0}, +#ifdef ENTRY_VALIDATE + {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate", + DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate), + 0, (ClientData) validateStrings, 0}, + {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand", + (char *) NULL, -1, Tk_Offset(Entry, validateCmd), + TK_CONFIG_NULL_OK, 0, 0}, + {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0}, +#endif /* ENTRY_VALIDATE */ {TK_OPTION_INT, "-width", "width", "Width", DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0}, {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", @@ -307,13 +367,21 @@ static Tk_OptionSpec optionSpecs[] = { static char *commandNames[] = { "bbox", "cget", "configure", "delete", "get", "icursor", "index", - "insert", "scan", "selection", "xview", (char *) NULL + "insert", "scan", "selection", +#ifdef ENTRY_VALIDATE + "validate", +#endif + "xview", (char *) NULL }; enum command { COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE, COMMAND_GET, COMMAND_ICURSOR, COMMAND_INDEX, COMMAND_INSERT, - COMMAND_SCAN, COMMAND_SELECTION, COMMAND_XVIEW + COMMAND_SCAN, COMMAND_SELECTION, +#ifdef ENTRY_VALIDATE + COMMAND_VALIDATE, +#endif + COMMAND_XVIEW }; static char *selCommandNames[] = { @@ -358,6 +426,15 @@ static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr)); +#ifdef ENTRY_VALIDATE +static int EntryValidate _ANSI_ARGS_((Entry *entryPtr, + char *cmd)); +static int EntryValidateChange _ANSI_ARGS_((Entry *entryPtr, + char *change, char *new, int index, int type)); +static void ExpandPercents _ANSI_ARGS_((Entry *entryPtr, + char *before, char *change, char *new, int index, + int type, Tcl_DString *dsPtr)); +#endif /* ENTRY_VALIDATE */ static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr)); static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr, double *firstPtr, double *lastPtr)); @@ -506,6 +583,11 @@ Tk_EntryObjCmd(clientData, interp, objc, objv) entryPtr->highlightGC = None; entryPtr->avgWidth = 1; entryPtr->flags = 0; +#ifdef ENTRY_VALIDATE + entryPtr->validateCmd = NULL; + entryPtr->validate = VALIDATE_NONE; + entryPtr->invalidCmd = NULL; +#endif /* ENTRY_VALIDATE */ Tk_SetClass(entryPtr->tkwin, "Entry"); TkSetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr); @@ -888,6 +970,26 @@ EntryWidgetObjCmd(clientData, interp, objc, objv) break; } +#ifdef ENTRY_VALIDATE + case COMMAND_VALIDATE: { + int code; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "validate"); + goto error; + } + selIndex = entryPtr->validate; + entryPtr->validate = VALIDATE_ALL; + code = EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FORCED); + if (entryPtr->validate != VALIDATE_NONE) { + entryPtr->validate = selIndex; + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK))); + break; + } +#endif + case COMMAND_XVIEW: { int index; @@ -1192,7 +1294,7 @@ EntryWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */ { XGCValues gcValues; - GC gc; + GC gc = None; unsigned long mask; Entry *entryPtr; @@ -1203,6 +1305,10 @@ EntryWorldChanged(instanceData) entryPtr->avgWidth = 1; } + if (entryPtr->normalBorder != NULL) { + Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); + } + gcValues.foreground = entryPtr->fgColorPtr->pixel; gcValues.font = Tk_FontId(entryPtr->tkfont); gcValues.graphics_exposures = False; @@ -1313,7 +1419,7 @@ DisplayEntry(clientData) */ Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); string = entryPtr->displayString; if (showSelection @@ -1599,6 +1705,16 @@ InsertChars(entryPtr, index, value) strcpy(new + byteIndex, value); strcpy(new + byteIndex + byteCount, string + byteIndex); +#ifdef ENTRY_VALIDATE + if ((entryPtr->validate == VALIDATE_KEY || + entryPtr->validate == VALIDATE_ALL) && + EntryValidateChange(entryPtr, value, new, index, + VALIDATE_INSERT) != TCL_OK) { + ckfree(new); + return; + } +#endif /* ENTRY_VALIDATE */ + ckfree(string); entryPtr->string = new; @@ -1674,6 +1790,9 @@ DeleteChars(entryPtr, index, count) { int byteIndex, byteCount, newByteCount; char *new, *string; +#ifdef ENTRY_VALIDATE + char *todelete; +#endif if ((index + count) > entryPtr->numChars) { count = entryPtr->numChars - index; @@ -1691,6 +1810,23 @@ DeleteChars(entryPtr, index, count) memcpy(new, string, (size_t) byteIndex); strcpy(new + byteIndex, string + byteIndex + byteCount); +#ifdef ENTRY_VALIDATE + todelete = (char *) ckalloc((unsigned) (byteCount + 1)); + memcpy(todelete, string + byteIndex, (size_t) byteCount); + todelete[byteCount] = '\0'; + + if ((entryPtr->validate == VALIDATE_KEY || + entryPtr->validate == VALIDATE_ALL) && + EntryValidateChange(entryPtr, todelete, new, index, + VALIDATE_DELETE) != TCL_OK) { + ckfree(new); + ckfree(todelete); + return; + } + + ckfree(todelete); +#endif /* ENTRY_VALIDATE */ + ckfree(entryPtr->string); entryPtr->string = new; entryPtr->numChars -= count; @@ -1830,6 +1966,30 @@ EntrySetValue(entryPtr, value) char *value; /* New text to display in entry. */ { char *oldSource; +#ifdef ENTRY_VALIDATE + int code; + + if (strcmp(value, entryPtr->string) == 0) { + return; + } + + if (entryPtr->flags & VALIDATE_VAR) { + entryPtr->flags |= VALIDATE_ABORT; + } else { + entryPtr->flags |= VALIDATE_VAR; + code = EntryValidateChange(entryPtr, (char *) NULL, value, -1, + VALIDATE_FORCED); + entryPtr->flags &= ~VALIDATE_VAR; + /* + * If VALIDATE_ABORT has been set, then this operation should be + * aborted because the validatecommand did something else instead + */ + if (entryPtr->flags & VALIDATE_ABORT) { + entryPtr->flags &= ~VALIDATE_ABORT; + return; + } + } +#endif /* ENTRY_VALIDATE */ oldSource = entryPtr->string; @@ -2489,9 +2649,25 @@ EntryFocusProc(entryPtr, gotFocus) entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr); } +#ifdef ENTRY_VALIDATE + if (entryPtr->validate == VALIDATE_ALL || + entryPtr->validate == VALIDATE_FOCUS || + entryPtr->validate == VALIDATE_FOCUSIN) { + EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FOCUSIN); + } +#endif /* ENTRY_VALIDATE */ } else { entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON); entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; +#ifdef ENTRY_VALIDATE + if (entryPtr->validate == VALIDATE_ALL || + entryPtr->validate == VALIDATE_FOCUS || + entryPtr->validate == VALIDATE_FOCUSOUT) { + EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FOCUSOUT); + } +#endif /* ENTRY_VALIDATE */ } EventuallyRedraw(entryPtr); } @@ -2553,8 +2729,289 @@ EntryTextVarProc(clientData, interp, name1, name2, flags) if (value == NULL) { value = ""; } +#ifdef ENTRY_VALIDATE + EntrySetValue(entryPtr, value); +#else if (strcmp(value, entryPtr->string) != 0) { EntrySetValue(entryPtr, value); } +#endif /* ENTRY_VALIDATE */ return (char *) NULL; } +#ifdef ENTRY_VALIDATE + +/* + *-------------------------------------------------------------- + * + * EntryValidate -- + * + * This procedure is invoked when any character is added or + * removed from the entry widget, or a focus has trigerred validation. + * + * Results: + * TCL_OK if the validatecommand passes the new string. + * TCL_BREAK if the vcmd executed OK, but rejects the string. + * TCL_ERROR if an error occurred while executing the vcmd + * or a valid Tcl_Bool is not returned. + * + * Side effects: + * An error condition may arise + * + *-------------------------------------------------------------- + */ + +static int +EntryValidate(entryPtr, cmd) + register Entry *entryPtr; /* Entry that needs validation. */ + register char *cmd; /* Validation command (NULL-terminated + * string). */ +{ + register Tcl_Interp *interp = entryPtr->interp; + int code, bool; + + code = Tcl_GlobalEval(interp, cmd); + + if (code != TCL_OK && code != TCL_RETURN) { + Tcl_AddErrorInfo(interp, + "\n\t(in validation command executed by entry)"); + Tcl_BackgroundError(interp); + return TCL_ERROR; + } + + if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp), + &bool) != TCL_OK) { + Tcl_AddErrorInfo(interp, + "\nValid Tcl Boolean not returned by validation command"); + Tcl_BackgroundError(interp); + Tcl_SetObjLength(Tcl_GetObjResult(interp), 0); + return TCL_ERROR; + } + + Tcl_SetObjLength(Tcl_GetObjResult(interp), 0); + return (bool ? TCL_OK : TCL_BREAK); +} + +/* + *-------------------------------------------------------------- + * + * EntryValidateChange -- + * + * This procedure is invoked when any character is added or + * removed from the entry widget, or a focus has trigerred validation. + * + * Results: + * TCL_OK if the validatecommand accepts the new string, + * TCL_ERROR if any problems occured with validatecommand. + * + * Side effects: + * The insertion/deletion may be aborted, and the + * validatecommand might turn itself off (if an error + * or loop condition arises). + * + *-------------------------------------------------------------- + */ + +static int +EntryValidateChange(entryPtr, change, new, index, type) + register Entry *entryPtr; /* Entry that needs validation. */ + char *change; /* Characters to be added/deleted + * (NULL-terminated string). */ + char *new; /* Potential new value of entry string */ + int index; /* index of insert/delete, -1 otherwise */ + int type; /* forced, delete, insert, + * focusin or focusout */ +{ + int code; + char *p; + Tcl_DString script; + + if (entryPtr->validateCmd == NULL || + entryPtr->validate == VALIDATE_NONE) { + return (entryPtr->flags & VALIDATE_VAR) ? TCL_ERROR : TCL_OK; + } + + /* + * If we're already validating, then we're hitting a loop condition + * Return and set validate to 0 to disallow further validations + * and prevent current validation from finishing + */ + if (entryPtr->flags & VALIDATING) { + entryPtr->validate = VALIDATE_NONE; + return (entryPtr->flags & VALIDATE_VAR) ? TCL_ERROR : TCL_OK; + } + + entryPtr->flags |= VALIDATING; + + /* + * Now form command string and run through the -validatecommand + */ + + Tcl_DStringInit(&script); + ExpandPercents(entryPtr, entryPtr->validateCmd, + change, new, index, type, &script); + Tcl_DStringAppend(&script, "", 1); + + p = Tcl_DStringValue(&script); + code = EntryValidate(entryPtr, p); + Tcl_DStringFree(&script); + + /* + * If e->validate has become VALIDATE_NONE during the validation, + * it means that a loop condition almost occured. Do not allow + * this validation result to finish. + */ + if (entryPtr->validate == VALIDATE_NONE || + (entryPtr->flags & VALIDATE_VAR)) { + code = TCL_ERROR; + } + /* + * If validate will return ERROR, then disallow further validations + * Otherwise, if it didn't accept the new string (returned TCL_BREAK) + * then eval the invalidCmd (if it's set) + */ + if (code == TCL_ERROR) { + entryPtr->validate = VALIDATE_NONE; + } else if (code == TCL_BREAK) { + if (entryPtr->invalidCmd != NULL) { + Tcl_DStringInit(&script); + ExpandPercents(entryPtr, entryPtr->invalidCmd, + change, new, index, type, &script); + Tcl_DStringAppend(&script, "", 1); + p = Tcl_DStringValue(&script); + if (Tcl_GlobalEval(entryPtr->interp, p) != TCL_OK) { + Tcl_AddErrorInfo(entryPtr->interp, + "\n\t(in invalidcommand executed by entry)"); + Tcl_BackgroundError(entryPtr->interp); + code = TCL_ERROR; + entryPtr->validate = VALIDATE_NONE; + } + Tcl_DStringFree(&script); + } + } + + entryPtr->flags &= ~VALIDATING; + + return code; +} + +/* + *-------------------------------------------------------------- + * + * ExpandPercents -- + * + * Given a command and an event, produce a new command + * by replacing % constructs in the original command + * with information from the X event. + * + * Results: + * The new expanded command is appended to the dynamic string + * given by dsPtr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +ExpandPercents(entryPtr, before, change, new, index, type, dsPtr) + register Entry *entryPtr; /* Entry that needs validation. */ + register char *before; /* Command containing percent + * expressions to be replaced. */ + char *change; /* Characters to added/deleted + * (NULL-terminated string). */ + char *new; /* Potential new value of entry string */ + int index; /* index of insert/delete */ + int type; /* INSERT or DELETE */ + Tcl_DString *dsPtr; /* Dynamic string in which to append + * new command. */ +{ + int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl + * list element. */ + int number, length; + register char *string; + Tcl_UniChar ch; + char numStorage[2*TCL_INTEGER_SPACE]; + + while (1) { + if (*before == '\0') { + break; + } + /* + * Find everything up to the next % character and append it + * to the result string. + */ + + string = before; + /* No need to convert '%', as it is in ascii range */ + string = Tcl_UtfFindFirst(before, '%'); + if (string == (char *) NULL) { + Tcl_DStringAppend(dsPtr, before, -1); + break; + } else if (string != before) { + Tcl_DStringAppend(dsPtr, before, string-before); + before = string; + } + + /* + * There's a percent sequence here. Process it. + */ + + before++; /* skip over % */ + if (*before != '\0') { + before += Tcl_UtfToUniChar(before, &ch); + } else { + ch = '%'; + } + switch (ch) { + case 'd': /* Type of call that caused validation */ + switch (type) { + case VALIDATE_INSERT: + number = 1; + break; + case VALIDATE_DELETE: + number = 0; + break; + default: + number = -1; + break; + } + sprintf(numStorage, "%d", number); + string = numStorage; + break; + case 'i': /* index of insert/delete */ + sprintf(numStorage, "%d", index); + string = numStorage; + break; + case 'P': /* 'Peeked' new value of the string */ + string = new; + break; + case 's': /* Current string value of entry */ + string = entryPtr->string; + break; + case 'S': /* string to be inserted/deleted, if any */ + string = change; + break; + case 'v': /* type of validation */ + string = validateStrings[entryPtr->validate]; + break; + case 'W': /* widget name */ + string = Tk_PathName(entryPtr->tkwin); + break; + default: + length = Tcl_UniCharToUtf(ch, numStorage); + numStorage[length] = '\0'; + string = numStorage; + break; + } + + spaceNeeded = Tcl_ScanElement(string, &cvtFlags); + length = Tcl_DStringLength(dsPtr); + Tcl_DStringSetLength(dsPtr, length + spaceNeeded); + spaceNeeded = Tcl_ConvertElement(string, + Tcl_DStringValue(dsPtr) + length, + cvtFlags | TCL_DONT_USE_BRACES); + Tcl_DStringSetLength(dsPtr, length + spaceNeeded); + } +} +#endif /* ENTRY_VALIDATE */ diff --git a/generic/tkEvent.c b/generic/tkEvent.c index 91d4b55..cd3615f 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkEvent.c,v 1.5 1999/08/13 17:52:12 redman Exp $ + * RCS: @(#) $Id: tkEvent.c,v 1.6 1999/12/14 06:52:27 hobbs Exp $ */ #include "tkPort.h" @@ -467,6 +467,33 @@ Tk_HandleEvent(eventPtr) ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + /* + * Hack for simulated X-events: Correct the state field + * of the event record to match with the ButtonPress + * and ButtonRelease events. + */ + + if (eventPtr->type==ButtonPress) { + dispPtr = TkGetDisplay(eventPtr->xbutton.display); + eventPtr->xbutton.state |= dispPtr->mouseButtonState; + switch (eventPtr->xbutton.button) { + case 1: dispPtr->mouseButtonState |= Button1Mask; break; + case 2: dispPtr->mouseButtonState |= Button2Mask; break; + case 3: dispPtr->mouseButtonState |= Button3Mask; break; + } + } else if (eventPtr->type==ButtonRelease) { + dispPtr = TkGetDisplay(eventPtr->xbutton.display); + switch (eventPtr->xbutton.button) { + case 1: dispPtr->mouseButtonState &= ~Button1Mask; break; + case 2: dispPtr->mouseButtonState &= ~Button2Mask; break; + case 3: dispPtr->mouseButtonState &= ~Button3Mask; break; + } + eventPtr->xbutton.state |= dispPtr->mouseButtonState; + } else if (eventPtr->type==MotionNotify) { + dispPtr = TkGetDisplay(eventPtr->xmotion.display); + eventPtr->xmotion.state |= dispPtr->mouseButtonState; + } + /* * Next, invoke all the generic event handlers (those that are * invoked for all events). If a generic event handler reports that diff --git a/generic/tkFont.c b/generic/tkFont.c index d63e58d..8fdbcc9 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkFont.c,v 1.6 1999/09/21 06:42:30 hobbs Exp $ + * RCS: @(#) $Id: tkFont.c,v 1.7 1999/12/14 06:52:28 hobbs Exp $ */ #include "tkPort.h" @@ -1818,6 +1818,16 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, Tcl_DStringInit(&lineBuffer); fontPtr = (TkFont *) tkfont; + if ((fontPtr == NULL) || (string == NULL)) { + if (widthPtr != NULL) { + *widthPtr = 0; + } + if (heightPtr != NULL) { + *heightPtr = 0; + } + return NULL; + } + fmPtr = &fontPtr->fm; height = fmPtr->ascent + fmPtr->descent; diff --git a/generic/tkFrame.c b/generic/tkFrame.c index 9284deb..4af8d7e 100644 --- a/generic/tkFrame.c +++ b/generic/tkFrame.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkFrame.c,v 1.4 1999/08/10 05:06:01 jingham Exp $ + * RCS: @(#) $Id: tkFrame.c,v 1.5 1999/12/14 06:52:28 hobbs Exp $ */ #include "default.h" @@ -167,22 +167,25 @@ static Tk_ConfigSpec configSpecs[] = { */ static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp, - Frame *framePtr, int argc, char **argv, + Frame *framePtr, int objc, Tcl_Obj *CONST objv[], int flags)); +static int CreateFrame _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST argv[], + int toplevel, char *appName)); static void DestroyFrame _ANSI_ARGS_((char *memPtr)); static void DisplayFrame _ANSI_ARGS_((ClientData clientData)); static void FrameCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void FrameEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); -static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int FrameWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void MapFrame _ANSI_ARGS_((ClientData clientData)); /* *-------------------------------------------------------------- * - * Tk_FrameCmd, Tk_ToplevelCmd -- + * Tk_FrameObjCmd, Tk_ToplevelObjCmd -- * * These procedures are invoked to process the "frame" and * "toplevel" Tcl commands. See the user documentation for @@ -199,31 +202,31 @@ static void MapFrame _ANSI_ARGS_((ClientData clientData)); */ int -Tk_FrameCmd(clientData, interp, argc, argv) +Tk_FrameObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - return TkCreateFrame(clientData, interp, argc, argv, 0, (char *) NULL); + return CreateFrame(clientData, interp, objc, objv, 0, (char *) NULL); } int -Tk_ToplevelCmd(clientData, interp, argc, argv) +Tk_ToplevelObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - return TkCreateFrame(clientData, interp, argc, argv, 1, (char *) NULL); + return CreateFrame(clientData, interp, objc, objv, 1, (char *) NULL); } /* *-------------------------------------------------------------- * - * TkFrameCreate -- + * TkCreateFrame -- * * This procedure is invoked to process the "frame" and "toplevel" * Tcl commands; it is also invoked directly by Tk_Init to create @@ -253,18 +256,47 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) * NULL: gives the base name to use for the * new application. */ { + int result, i; + Tcl_Obj **objv = (Tcl_Obj **) ckalloc((argc+1) * sizeof(Tcl_Obj **)); + for (i=0; i<argc; i++) { + objv[i] = Tcl_NewStringObj(argv[i], -1); + Tcl_IncrRefCount(objv[i]); + } + objv[argc] = NULL; + result = CreateFrame(clientData, interp, argc, objv, toplevel, appName); + for (i=0; i<argc; i++) { + Tcl_DecrRefCount(objv[i]); + } + ckfree((char *) objv); + return result; +} + +static int +CreateFrame(clientData, interp, objc, objv, toplevel, appName) + ClientData clientData; /* Main window associated with interpreter. + * If we're called by Tk_Init to create a + * new application, then this is NULL. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ + int toplevel; /* Non-zero means create a toplevel window, + * zero means create a frame. */ + char *appName; /* Should only be non-NULL if clientData is + * NULL: gives the base name to use for the + * new application. */ +{ Tk_Window tkwin = (Tk_Window) clientData; Frame *framePtr; Tk_Window new; char *className, *screenName, *visualName, *colormapName, *arg, *useOption; - int i, c, length, depth; + int i, c, depth; + size_t length; unsigned int mask; Colormap colormap; Visual *visual; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } @@ -277,28 +309,27 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) className = colormapName = screenName = visualName = useOption = NULL; colormap = None; - for (i = 2; i < argc; i += 2) { - arg = argv[i]; - length = strlen(arg); + for (i = 2; i < objc; i += 2) { + arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; - if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0) + if ((c == 'c') && (strncmp(arg, "-class", length) == 0) && (length >= 3)) { - className = argv[i+1]; + className = Tcl_GetString(objv[i+1]); } else if ((c == 'c') - && (strncmp(arg, "-colormap", strlen(arg)) == 0)) { - colormapName = argv[i+1]; + && (strncmp(arg, "-colormap", length) == 0)) { + colormapName = Tcl_GetString(objv[i+1]); } else if ((c == 's') && toplevel - && (strncmp(arg, "-screen", strlen(arg)) == 0)) { - screenName = argv[i+1]; + && (strncmp(arg, "-screen", length) == 0)) { + screenName = Tcl_GetString(objv[i+1]); } else if ((c == 'u') && toplevel - && (strncmp(arg, "-use", strlen(arg)) == 0)) { - useOption = argv[i+1]; + && (strncmp(arg, "-use", length) == 0)) { + useOption = Tcl_GetString(objv[i+1]); } else if ((c == 'v') - && (strncmp(arg, "-visual", strlen(arg)) == 0)) { - visualName = argv[i+1]; + && (strncmp(arg, "-visual", length) == 0)) { + visualName = Tcl_GetString(objv[i+1]); } } @@ -321,7 +352,8 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) screenName = (toplevel) ? "" : NULL; } if (tkwin != NULL) { - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName); + new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), + screenName); } else { /* * We were called from Tk_Init; create a new application. @@ -392,8 +424,8 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) framePtr->tkwin = new; framePtr->display = Tk_Display(new); framePtr->interp = interp; - framePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(new), FrameWidgetCmd, + framePtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(new), FrameWidgetObjCmd, (ClientData) framePtr, FrameCmdDeletedProc); framePtr->className = NULL; framePtr->mask = (toplevel) ? TOPLEVEL : FRAME; @@ -426,7 +458,7 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) mask |= ActivateMask; } Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData) framePtr); - if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) { + if (ConfigureFrame(interp, framePtr, objc-2, objv+2, 0) != TCL_OK) { goto error; } if ((framePtr->isContainer)) { @@ -454,7 +486,7 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) /* *-------------------------------------------------------------- * - * FrameWidgetCmd -- + * FrameWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a frame widget. See the user @@ -470,83 +502,87 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) */ static int -FrameWidgetCmd(clientData, interp, argc, argv) +FrameWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about frame widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { + static char *frameOptions[] = { + "cget", "configure", (char *) NULL + }; + enum options { + FRAME_CGET, FRAME_CONFIGURE + }; register Frame *framePtr = (Frame *) clientData; - int result; + int result = TCL_OK, index; size_t length; int c, i; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], frameOptions, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) framePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); + switch ((enum options) index) { + case FRAME_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); result = TCL_ERROR; goto done; } result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { + (char *) framePtr, Tcl_GetString(objv[2]), framePtr->mask); + break; + } + case FRAME_CONFIGURE: { + if (objc == 2) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, (char *) framePtr, (char *) NULL, framePtr->mask); - } else if (argc == 3) { + } else if (objc == 3) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); + (char *) framePtr, Tcl_GetString(objv[2]), framePtr->mask); } else { /* * Don't allow the options -class, -colormap, -container, * -newcmap, -screen, -use, or -visual to be changed. */ - for (i = 2; i < argc; i++) { - length = strlen(argv[i]); + for (i = 2; i < objc; i++) { + char *arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } - c = argv[i][1]; - if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0) + c = arg[1]; + if (((c == 'c') && (strncmp(arg, "-class", length) == 0) && (length >= 2)) || ((c == 'c') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-colormap", length) == 0) + && (strncmp(arg, "-colormap", length) == 0) && (length >= 3)) || ((c == 'c') - && (strncmp(argv[i], "-container", length) == 0) + && (strncmp(arg, "-container", length) == 0) && (length >= 3)) || ((c == 's') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-screen", length) == 0)) + && (strncmp(arg, "-screen", length) == 0)) || ((c == 'u') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-use", length) == 0)) + && (strncmp(arg, "-use", length) == 0)) || ((c == 'v') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-visual", length) == 0))) { - Tcl_AppendResult(interp, "can't modify ", argv[i], + && (strncmp(arg, "-visual", length) == 0))) { + Tcl_AppendResult(interp, "can't modify ", arg, " option after widget is created", (char *) NULL); result = TCL_ERROR; goto done; } } - result = ConfigureFrame(interp, framePtr, argc-2, argv+2, + result = ConfigureFrame(interp, framePtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - result = TCL_ERROR; + break; + } } done: @@ -591,7 +627,7 @@ DestroyFrame(memPtr) * * ConfigureFrame -- * - * This procedure is called to process an argv/argc list, plus + * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or * reconfigure) a frame widget. * @@ -608,12 +644,12 @@ DestroyFrame(memPtr) */ static int -ConfigureFrame(interp, framePtr, argc, argv, flags) +ConfigureFrame(interp, framePtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Frame *framePtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + int objc; /* Number of valid entries in objv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { char *oldMenuName; @@ -630,7 +666,8 @@ ConfigureFrame(interp, framePtr, argc, argv, flags) } if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs, - argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) { + objc, (char **) objv, (char *) framePtr, + flags | framePtr->mask | TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -694,6 +731,8 @@ DisplayFrame(clientData) { register Frame *framePtr = (Frame *) clientData; register Tk_Window tkwin = framePtr->tkwin; + void (* drawFunction) _ANSI_ARGS_((Tk_Window, Drawable, Tk_3DBorder, + int, int, int, int, int, int)) = Tk_Fill3DRectangle; framePtr->flags &= ~REDRAW_PENDING; if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin) @@ -702,7 +741,7 @@ DisplayFrame(clientData) } if (framePtr->border != NULL) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), + drawFunction(tkwin, Tk_WindowId(tkwin), framePtr->border, framePtr->highlightWidth, framePtr->highlightWidth, Tk_Width(tkwin) - 2*framePtr->highlightWidth, diff --git a/generic/tkGet.c b/generic/tkGet.c index b05be71..dd920be 100644 --- a/generic/tkGet.c +++ b/generic/tkGet.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkGet.c,v 1.5 1999/04/21 21:53:26 rjohnson Exp $ + * RCS: @(#) $Id: tkGet.c,v 1.6 1999/12/14 06:52:28 hobbs Exp $ */ #include "tkInt.h" @@ -621,13 +621,56 @@ Tk_GetPixels(interp, tkwin, string, intPtr) Tk_Window tkwin; /* Window whose screen determines conversion * from centimeters and other absolute * units. */ - char *string; /* String describing a justification style. */ + char *string; /* String describing a number of pixels. */ int *intPtr; /* Place to store converted result. */ { + double d; + + if (TkGetDoublePixels(interp, tkwin, string, &d) != TCL_OK) { + return TCL_ERROR; + } + + if (d < 0) { + *intPtr = (int) (d - 0.5); + } else { + *intPtr = (int) (d + 0.5); + } + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * TkGetDoublePixels -- + * + * Given a string, returns the number of pixels corresponding + * to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * pixel distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkGetDoublePixels(interp, tkwin, string, doublePtr) + Tcl_Interp *interp; /* Use this for error reporting. */ + Tk_Window tkwin; /* Window whose screen determines conversion + * from centimeters and other absolute + * units. */ + CONST char *string; /* String describing a number of pixels. */ + double *doublePtr; /* Place to store converted result. */ +{ char *end; double d; - d = strtod(string, &end); + d = strtod((char *) string, &end); if (end == string) { error: Tcl_AppendResult(interp, "bad screen distance \"", string, @@ -669,11 +712,7 @@ Tk_GetPixels(interp, tkwin, string, intPtr) if (*end != 0) { goto error; } - if (d < 0) { - *intPtr = (int) (d - 0.5); - } else { - *intPtr = (int) (d + 0.5); - } + *doublePtr = d; return TCL_OK; } diff --git a/generic/tkImage.c b/generic/tkImage.c index a867594..e54a189 100644 --- a/generic/tkImage.c +++ b/generic/tkImage.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkImage.c,v 1.4 1999/10/29 03:57:56 hobbs Exp $ + * RCS: @(#) $Id: tkImage.c,v 1.5 1999/12/14 06:52:28 hobbs Exp $ */ #include "tkInt.h" @@ -186,227 +186,227 @@ Tk_ImageObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } switch ((enum options) index) { - case IMAGE_CREATE: { - char *arg; - Tcl_Obj **args; - int oldimage = 0; - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "type ?name? ?options?"); - return TCL_ERROR; - } + case IMAGE_CREATE: { + char *arg; + Tcl_Obj **args; + int oldimage = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "type ?name? ?options?"); + return TCL_ERROR; + } - /* - * Look up the image type. - */ + /* + * Look up the image type. + */ - arg = Tcl_GetString(objv[2]); - for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - if ((*arg == typePtr->name[0]) - && (strcmp(arg, typePtr->name) == 0)) { - break; - } - } - if (typePtr == NULL) { - oldimage = 1; - for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { + arg = Tcl_GetString(objv[2]); + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { if ((*arg == typePtr->name[0]) && (strcmp(arg, typePtr->name) == 0)) { break; } } - } - if (typePtr == NULL) { - Tcl_AppendResult(interp, "image type \"", arg, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - - /* - * Figure out a name to use for the new image. - */ + if (typePtr == NULL) { + oldimage = 1; + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + if ((*arg == typePtr->name[0]) + && (strcmp(arg, typePtr->name) == 0)) { + break; + } + } + } + if (typePtr == NULL) { + Tcl_AppendResult(interp, "image type \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } - arg = Tcl_GetString(objv[3]); - if ((objc == 3) || (arg[0] == '-')) { - dispPtr->imageId++; - sprintf(idString, "image%d", dispPtr->imageId); - name = idString; - firstOption = 3; - } else { - name = arg; - firstOption = 4; - } + /* + * Figure out a name to use for the new image. + */ - /* - * Create the data structure for the new image. - */ + if ((objc == 3) || (*(arg = Tcl_GetString(objv[3])) == '-')) { + dispPtr->imageId++; + sprintf(idString, "image%d", dispPtr->imageId); + name = idString; + firstOption = 3; + } else { + name = arg; + firstOption = 4; + } - hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, name, &new); - if (new) { - masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); - masterPtr->typePtr = NULL; - masterPtr->masterData = NULL; - masterPtr->width = masterPtr->height = 1; - masterPtr->tablePtr = &winPtr->mainPtr->imageTable; - masterPtr->hPtr = hPtr; - masterPtr->instancePtr = NULL; - Tcl_SetHashValue(hPtr, masterPtr); - } else { /* - * An image already exists by this name. Disconnect the - * instances from the master. + * Create the data structure for the new image. */ - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - (*masterPtr->typePtr->freeProc)( - imagePtr->instanceData, imagePtr->display); - (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0, - masterPtr->width, masterPtr->height, masterPtr->width, - masterPtr->height); - } - (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); + hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, + name, &new); + if (new) { + masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); masterPtr->typePtr = NULL; + masterPtr->masterData = NULL; + masterPtr->width = masterPtr->height = 1; + masterPtr->tablePtr = &winPtr->mainPtr->imageTable; + masterPtr->hPtr = hPtr; + masterPtr->instancePtr = NULL; + Tcl_SetHashValue(hPtr, masterPtr); + } else { + /* + * An image already exists by this name. Disconnect the + * instances from the master. + */ + + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr != NULL) { + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + (*masterPtr->typePtr->freeProc)( + imagePtr->instanceData, imagePtr->display); + (*imagePtr->changeProc)(imagePtr->widgetClientData, + 0, 0, masterPtr->width, masterPtr->height, + masterPtr->width, masterPtr->height); + } + (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); + masterPtr->typePtr = NULL; + } } - } - /* - * Call the image type manager so that it can perform its own - * initialization, then re-"get" for any existing instances of - * the image. - */ + /* + * Call the image type manager so that it can perform its own + * initialization, then re-"get" for any existing instances of + * the image. + */ - objv += firstOption; - objc -= firstOption; - args = (Tcl_Obj **) objv; - if (oldimage) { - int i; - args = (Tcl_Obj **) ckalloc((objc+1) * sizeof(char *)); - for (i = 0; i < objc; i++) { - args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]); + objv += firstOption; + objc -= firstOption; + args = (Tcl_Obj **) objv; + if (oldimage) { + int i; + args = (Tcl_Obj **) ckalloc((objc+1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]); + } + args[objc] = NULL; + } + if ((*typePtr->createProc)(interp, name, objc, + args, typePtr, (Tk_ImageMaster) masterPtr, + &masterPtr->masterData) != TCL_OK) { + DeleteImage(masterPtr); + if (oldimage) { + ckfree((char *) args); + } + return TCL_ERROR; } - args[objc] = NULL; - } - if ((*typePtr->createProc)(interp, name, objc, - args, typePtr, (Tk_ImageMaster) masterPtr, - &masterPtr->masterData) != TCL_OK) { - DeleteImage(masterPtr); if (oldimage) { ckfree((char *) args); } - return TCL_ERROR; - } - if (oldimage) { - ckfree((char *) args); + masterPtr->typePtr = typePtr; + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + imagePtr->instanceData = (*typePtr->getProc)( + imagePtr->tkwin, masterPtr->masterData); + } + Tcl_SetResult(interp, + Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), + TCL_STATIC); + break; } - masterPtr->typePtr = typePtr; - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - imagePtr->instanceData = (*typePtr->getProc)( - imagePtr->tkwin, masterPtr->masterData); + case IMAGE_DELETE: { + for (i = 2; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + DeleteImage(masterPtr); + } + break; } - Tcl_SetResult(interp, - Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), - TCL_STATIC); - break; - } - case IMAGE_DELETE: { - for (i = 2; i < objc; i++) { - char *arg = Tcl_GetString(objv[i]); + case IMAGE_HEIGHT: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", arg, - "\" doesn't exist", (char *) NULL); + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); return TCL_ERROR; } masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - DeleteImage(masterPtr); - } - break; - } - case IMAGE_HEIGHT: { - char *arg; - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "name"); - return TCL_ERROR; - } - arg = Tcl_GetString(objv[2]); - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", arg, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height); - break; - } - case IMAGE_NAMES: { - if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, NULL); - return TCL_ERROR; + Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height); + break; } - for (hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, Tcl_GetHashKey( + case IMAGE_NAMES: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendElement(interp, Tcl_GetHashKey( &winPtr->mainPtr->imageTable, hPtr)); + } + break; } - break; - } - case IMAGE_TYPE: { - char *arg; - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "name"); - return TCL_ERROR; - } - arg = Tcl_GetString(objv[2]); - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", arg, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - Tcl_SetResult(interp, masterPtr->typePtr->name, TCL_STATIC); - } - break; - } - case IMAGE_TYPES: { - if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, NULL); - return TCL_ERROR; - } - for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - Tcl_AppendElement(interp, typePtr->name); - } - for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - Tcl_AppendElement(interp, typePtr->name); + case IMAGE_TYPE: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr != NULL) { + Tcl_SetResult(interp, masterPtr->typePtr->name, TCL_STATIC); + } + break; } - break; - } - case IMAGE_WIDTH: { - char *arg; - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "name"); - return TCL_ERROR; + case IMAGE_TYPES: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_AppendElement(interp, typePtr->name); + } + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_AppendElement(interp, typePtr->name); + } + break; } - arg = Tcl_GetString(objv[2]); - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", arg, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; + case IMAGE_WIDTH: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width); + break; } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width); - break; - } } return TCL_OK; } @@ -450,9 +450,9 @@ Tk_ImageChanged(imageMaster, x, y, width, height, imageWidth, masterPtr->width = imageWidth; masterPtr->height = imageHeight; for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { + imagePtr = imagePtr->nextPtr) { (*imagePtr->changeProc)(imagePtr->widgetClientData, x, y, - width, height, imageWidth, imageHeight); + width, height, imageWidth, imageHeight); } } @@ -608,6 +608,81 @@ Tk_FreeImage(image) /* *---------------------------------------------------------------------- * + * Tk_PostscriptImage -- + * + * This procedure is called by widgets that contain images in order + * to redisplay an image on the screen or an off-screen pixmap. + * + * Results: + * None. + * + * Side effects: + * The image's manager is notified, and it redraws the desired + * portion of the image before returning. + * + *---------------------------------------------------------------------- + */ + +int +Tk_PostscriptImage(image, interp, tkwin, psinfo, x, y, width, height, prepass) + Tk_Image image; /* Token for image to redisplay. */ + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psinfo; /* postscript info */ + int x, y; /* Upper-left pixel of region in image that + * needs to be redisplayed. */ + int width, height; /* Dimensions of region to redraw. */ + int prepass; +{ + int result; + XImage *ximage; + Pixmap pmap; + GC newGC; + XGCValues gcValues; + if (prepass) { + return TCL_OK; + } + + /* + * Create a Pixmap, tell the image to redraw itself there, and then + * generate an XImage from the Pixmap. We can then read pixel + * values out of the XImage. + */ + + pmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), + width, height, Tk_Depth(tkwin)); + + gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); + newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); + if (newGC != None) { + XFillRectangle(Tk_Display(tkwin), pmap, newGC, + 0, 0, (unsigned int)width, (unsigned int)height); + Tk_FreeGC(Tk_Display(tkwin), newGC); + } + + Tk_RedrawImage(image, x, y, width, height, pmap, 0, 0); + + ximage = XGetImage(Tk_Display(tkwin), pmap, 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + + Tk_FreePixmap(Tk_Display(tkwin), pmap); + + if (ximage == NULL) { + /* The XGetImage() function is apparently not + * implemented on this system. Just ignore it. + */ + return TCL_OK; + } + result = TkPostscriptImage(interp, tkwin, psinfo, ximage, x, y, + width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *---------------------------------------------------------------------- + * * Tk_RedrawImage -- * * This procedure is called by widgets that contain images in order @@ -864,3 +939,39 @@ Tk_GetImageMasterData(interp, name, typePtrPtr) *typePtrPtr = masterPtr->typePtr; return masterPtr->masterData; } + +/* + *---------------------------------------------------------------------- + * + * Tk_SetTSOrigin -- + * + * Set the pattern origin of the tile to a common point (i.e. the + * origin (0,0) of the top level window) so that tiles from two + * different widgets will match up. This done by setting the + * GCTileStipOrigin field is set to the translated origin of the + * toplevel window in the hierarchy. + * + * Results: + * None. + * + * Side Effects: + * The GCTileStipOrigin is reset in the GC. This will cause the + * tile origin to change when the GC is used for drawing. + * + *---------------------------------------------------------------------- + */ +/*ARGSUSED*/ +void +Tk_SetTSOrigin(tkwin, gc, x, y) + Tk_Window tkwin; + GC gc; + int x, y; +{ + while (!Tk_IsTopLevel(tkwin)) { + x -= Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; + y -= Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; + tkwin = Tk_Parent(tkwin); + } + XSetTSOrigin(Tk_Display(tkwin), gc, x, y); +} + diff --git a/generic/tkImgBmap.c b/generic/tkImgBmap.c index 60b9f39..6c49129 100644 --- a/generic/tkImgBmap.c +++ b/generic/tkImgBmap.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkImgBmap.c,v 1.10 1999/10/29 03:57:56 hobbs Exp $ + * RCS: @(#) $Id: tkImgBmap.c,v 1.11 1999/12/14 06:52:28 hobbs Exp $ */ #include "tkInt.h" @@ -92,6 +92,10 @@ static void ImgBmapDisplay _ANSI_ARGS_((ClientData clientData, static void ImgBmapFree _ANSI_ARGS_((ClientData clientData, Display *display)); static void ImgBmapDelete _ANSI_ARGS_((ClientData clientData)); +static int ImgBmapPostscript _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass)); Tk_ImageType tkBitmapImageType = { "bitmap", /* name */ @@ -100,6 +104,7 @@ Tk_ImageType tkBitmapImageType = { ImgBmapDisplay, /* displayProc */ ImgBmapFree, /* freeProc */ ImgBmapDelete, /* deleteProc */ + ImgBmapPostscript, /* postscriptProc */ (Tk_ImageType *) NULL /* nextPtr */ }; @@ -1095,3 +1100,103 @@ GetByte(chan) return buffer; } } + + +/* + *---------------------------------------------------------------------- + * + * ImgBmapPostscript -- + * + * This procedure is called by the image code to create + * postscript output for an image. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ImgBmapPostscript(clientData, interp, tkwin, psinfo, x, y, width, height, + prepass) + ClientData clientData; + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psinfo; + int x, y, width, height, prepass; +{ + BitmapMaster *masterPtr = (BitmapMaster *) clientData; + int rowsAtOnce, rowsThisTime; + int curRow, yy; + char buffer[200]; + + if (prepass) { + return TCL_OK; + } + /* + * Color the background, if there is one. + */ + + if (masterPtr->bgUid != NULL) { + XColor color; + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid, + &color); + sprintf(buffer, + "%d %d moveto %d 0 rlineto 0 %d rlineto %d %s\n", + x, y, width, height, -width,"0 rlineto closepath"); + Tcl_AppendResult(interp, buffer, (char *) NULL); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + + /* + * Draw the bitmap, if there is a foreground color. If the bitmap + * is very large, then chop it up into multiple bitmaps, each + * consisting of one or more rows. This is needed because Postscript + * can't handle single strings longer than 64 KBytes long. + */ + + if (masterPtr->fgUid != NULL) { + XColor color; + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid, + &color); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + if (width > 60000) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't generate Postscript", + " for bitmaps more than 60000 pixels wide", + (char *) NULL); + return TCL_ERROR; + } + rowsAtOnce = 60000/width; + if (rowsAtOnce < 1) { + rowsAtOnce = 1; + } + sprintf(buffer, "%d %d translate\n", x, y); + Tcl_AppendResult(interp, buffer, (char *) NULL); + for (curRow = y+height-1; curRow >= y; curRow -= rowsAtOnce) { + rowsThisTime = rowsAtOnce; + if (rowsThisTime > (curRow + 1 - y)) { + rowsThisTime = curRow + 1 - y; + } + sprintf(buffer, "%d %d", width, rowsThisTime); + Tcl_AppendResult(interp, buffer, " true matrix {\n<", + (char *) NULL); + for (yy = curRow; yy >= (curRow - rowsThisTime + 1); yy--) { + sprintf(buffer, "row %d\n", yy); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + sprintf(buffer, "0 %.15g", (double) rowsThisTime); + Tcl_AppendResult(interp, ">\n} imagemask\n", buffer, + " translate\n", (char *) NULL); + } + } + return TCL_OK; +} diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 7e3b804..75694c0 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -15,7 +15,7 @@ * Department of Computer Science, * Australian National University. * - * RCS: @(#) $Id: tkImgPhoto.c,v 1.10 1999/10/29 03:57:56 hobbs Exp $ + * RCS: @(#) $Id: tkImgPhoto.c,v 1.11 1999/12/14 06:52:28 hobbs Exp $ */ #include "tkInt.h" @@ -301,6 +301,7 @@ Tk_ImageType tkPhotoImageType = { ImgPhotoDisplay, /* displayProc */ ImgPhotoFree, /* freeProc */ ImgPhotoDelete, /* deleteProc */ + (Tk_ImagePostscriptProc *) NULL, /* postscriptProc */ (Tk_ImageType *) NULL /* nextPtr */ }; @@ -394,8 +395,8 @@ static int MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *data, Tcl_Obj *formatString, Tk_PhotoImageFormat **imageFormatPtr, int *widthPtr, int *heightPtr, int *oldformat)); -static void Dither _ANSI_ARGS_((PhotoMaster *masterPtr, - int x, int y, int width, int height)); +static Tcl_ObjCmdProc * PhotoOptionFind _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_Obj *obj)); static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr, int x, int y, int width, int height)); @@ -588,7 +589,12 @@ ImgPhotoCmd(clientData, interp, objc, objv) if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0, &index) != TCL_OK) { - return TCL_ERROR; + Tcl_ObjCmdProc *proc; + proc = PhotoOptionFind(interp, objv[1]); + if (proc == (Tcl_ObjCmdProc *) NULL) { + return TCL_ERROR; + } + return proc(clientData, interp, objc, objv); } switch ((enum options) index) { case PHOTO_BLANK: { @@ -610,7 +616,7 @@ ImgPhotoCmd(clientData, interp, objc, objv) Tcl_WrongNumArgs(interp, 2, objv, "option"); return TCL_ERROR; } - arg = Tcl_GetStringFromObj(objv[2],&length); + arg = Tcl_GetStringFromObj(objv[2], (int *) &length); if (strncmp(arg,"-data", length) == 0) { if (masterPtr->dataString) { Tcl_SetObjResult(interp, masterPtr->dataString); @@ -659,7 +665,7 @@ ImgPhotoCmd(clientData, interp, objc, objv) return TCL_OK; } if (objc == 3) { - char *arg = Tcl_GetStringFromObj(objv[2], &length); + char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length); if (!strncmp(arg, "-data", length)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "-data {} {} {}", (char *) NULL); @@ -1172,11 +1178,11 @@ ImgPhotoCmd(clientData, interp, objc, objv) x = masterPtr->ditherX; y = masterPtr->ditherY; if (masterPtr->ditherX != 0) { - Dither(masterPtr, x, y, masterPtr->width - x, 1); + Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, masterPtr->width - x, 1); } if (masterPtr->ditherY < masterPtr->height) { x = 0; - Dither(masterPtr, 0, masterPtr->ditherY, masterPtr->width, + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0, masterPtr->ditherY, masterPtr->width, masterPtr->height - masterPtr->ditherY); } @@ -1454,10 +1460,14 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv) return TCL_ERROR; } } else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) { + char *val; maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2; argIndex = index + 1; for (numValues = 0; numValues < maxValues; ++numValues) { - char *val = Tcl_GetString(objv[argIndex]); + if (argIndex >= objc) { + break; + } + val = Tcl_GetString(objv[argIndex]); if ((argIndex < objc) && (isdigit(UCHAR(val[0])) || ((val[0] == '-') && isdigit(UCHAR(val[1]))))) { if (Tcl_GetInt(interp, val, &values[numValues]) @@ -3835,7 +3845,7 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) * Update each instance. */ - Dither(masterPtr, x, y, width, height); + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height); /* * Tell the core image code that this image has changed. @@ -4072,7 +4082,7 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, * Update each instance. */ - Dither(masterPtr, x, y, width, height); + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height); /* * Tell the core image code that this image has changed. @@ -4085,7 +4095,7 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, /* *---------------------------------------------------------------------- * - * Dither -- + * Tk_DitherPhoto -- * * This procedure is called to update an area of each instance's * pixmap by dithering the corresponding area of the image master. @@ -4101,14 +4111,15 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, *---------------------------------------------------------------------- */ -static void -Dither(masterPtr, x, y, width, height) - PhotoMaster *masterPtr; /* Image master whose instances are +void +Tk_DitherPhoto(photo, x, y, width, height) + Tk_PhotoHandle photo; /* Image master whose instances are * to be updated. */ int x, y; /* Coordinates of the top-left pixel * in the area to be dithered. */ int width, height; /* Dimensions of the area to be dithered. */ { + PhotoMaster *masterPtr = (PhotoMaster *) photo; PhotoInstance *instancePtr; if ((width <= 0) || (height <= 0)) { @@ -4944,3 +4955,149 @@ Tk_PhotoGetImage(handle, blockPtr) blockPtr->offset[3] = 3; return 1; } + +/* + *---------------------------------------------------------------------- + * + * PhotoOptionFind -- + * + * Finds a specific Photo option. + * + * Results: + * None. + * + * Side effects: + * After commands are removed. + * + *---------------------------------------------------------------------- + */ + +typedef struct OptionAssocData { + struct OptionAssocData *nextPtr; /* pointer to next OptionAssocData */ + Tcl_ObjCmdProc *command; /* command associated with this + * option */ + char name[1]; /* name of option (remaining chars) */ +} OptionAssocData; + +static Tcl_ObjCmdProc * +PhotoOptionFind(interp, obj) + Tcl_Interp *interp; /* Interpreter that is being deleted. */ + Tcl_Obj *obj; /* Name of option to be found. */ +{ + size_t length; + char *name = Tcl_GetStringFromObj(obj, (int *) &length); + OptionAssocData *list; + char *prevname = NULL; + Tcl_ObjCmdProc *proc = (Tcl_ObjCmdProc *) NULL; + list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption", + (Tcl_InterpDeleteProc **) NULL); + while (list != (OptionAssocData *) NULL) { + if (strncmp(name, list->name, length) == 0) { + if (proc != (Tcl_ObjCmdProc *) NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ambiguous option \"", name, + "\": must be ", prevname, (char *) NULL); + while (list->nextPtr != (OptionAssocData *) NULL) { + Tcl_AppendResult(interp, prevname, ", ",(char *) NULL); + list = list->nextPtr; + prevname = list->name; + } + Tcl_AppendResult(interp, ", or", prevname, (char *) NULL); + return (Tcl_ObjCmdProc *) NULL; + } + proc = list->command; + prevname = list->name; + } + list = list->nextPtr; + } + if (proc != (Tcl_ObjCmdProc *) NULL) { + Tcl_ResetResult(interp); + } + return proc; +} + +/* + *---------------------------------------------------------------------- + * + * PhotoOptionCleanupProc -- + * + * This procedure is invoked whenever an interpreter is deleted + * to cleanup the AssocData for "photoVisitor". + * + * Results: + * None. + * + * Side effects: + * Photo Visitor options are removed. + * + *---------------------------------------------------------------------- + */ + +static void +PhotoOptionCleanupProc(clientData, interp) + ClientData clientData; /* Points to "photoVisitor" AssocData + * for the interpreter. */ + Tcl_Interp *interp; /* Interpreter that is being deleted. */ +{ + OptionAssocData *list = (OptionAssocData *) clientData; + OptionAssocData *ptr; + + while (list != NULL) { + list = (ptr = list)->nextPtr; + ckfree((char *) ptr); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreatePhotoOption -- + * + * This procedure may be invoked to add a new kind of photo + * option to the core photo command supported by Tk. + * + * Results: + * None. + * + * Side effects: + * From now on, the new option will be useable by the + * photo command. + * + *-------------------------------------------------------------- + */ + +void +Tk_CreatePhotoOption(interp, name, proc) + Tcl_Interp *interp; /* interpreter */ + CONST char *name; /* option name */ + Tcl_ObjCmdProc *proc; /* proc to execute command */ +{ + OptionAssocData *typePtr2, *prevPtr, *ptr; + OptionAssocData *list; + + list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption", + (Tcl_InterpDeleteProc **) NULL); + + /* + * If there's already a photo option with the given name, remove it. + */ + + for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (strcmp(typePtr2->name, name) == 0) { + if (prevPtr == NULL) { + list = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree((char *) typePtr2); + break; + } + } + ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name)); + strcpy(&(ptr->name[0]), name); + ptr->command = proc; + ptr->nextPtr = list; + Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc, + (ClientData) ptr); +} diff --git a/generic/tkInt.decls b/generic/tkInt.decls index 244798f..c45134b 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -9,7 +9,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tkInt.decls,v 1.12 1999/12/07 03:51:05 hobbs Exp $ +# RCS: @(#) $Id: tkInt.decls,v 1.13 1999/12/14 06:52:29 hobbs Exp $ library tk @@ -1046,10 +1046,11 @@ interface tkIntXlib # X functions for Windows -# This slot is reserved for use by the dash patch: -# declare 0 win { -# XSetDashes -# } +declare 0 win { + void XSetDashes (Display* display, GC gc, int dash_offset, + _Xconst char* dash_list, int n) +} + declare 1 win { XModifierKeymap* XGetModifierMapping (Display* d) } @@ -1520,13 +1521,17 @@ declare 106 win { void XFillRectangle (Display* display, Drawable d, GC gc, \ int x, int y, unsigned int width, unsigned int height) } +declare 105 win { + void XWarpPointer (Display* d, Window s, Window dw, int sx, int sy, \ + unsigned int sw, unsigned int sh, int dx, int dy) +} # X functions for Mac -# This slot is reserved for use by the dash patch: -# declare 0 win { -# XSetDashes -# } +declare 0 mac { + void XSetDashes (Display* display, GC gc, int dash_offset, + _Xconst char* dash_list, int n) +} declare 1 mac { XModifierKeymap* XGetModifierMapping (Display* d) diff --git a/generic/tkInt.h b/generic/tkInt.h index c79c55c..6da5416 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: $Id: tkInt.h,v 1.18 1999/12/03 07:14:39 hobbs Exp $ + * RCS: $Id: tkInt.h,v 1.19 1999/12/14 06:52:29 hobbs Exp $ */ #ifndef _TKINT @@ -33,7 +33,6 @@ typedef struct TkColormap TkColormap; typedef struct TkGrabEvent TkGrabEvent; -typedef struct Tk_PostscriptInfo Tk_PostscriptInfo; typedef struct TkpCursor_ *TkpCursor; typedef struct TkRegion_ *TkRegion; typedef struct TkStressedCmap TkStressedCmap; @@ -490,6 +489,12 @@ typedef struct TkDisplay { * the display when we no longer have any * Tk applications using it. */ + int mouseButtonState; /* current mouse button state for this + * display */ + int warpInProgress; + Window warpWindow; + int warpX; + int warpY; } TkDisplay; /* @@ -846,15 +851,13 @@ extern TkDisplay *tkDisplayList; * to the outside world: */ -extern Tk_Uid tkActiveUid; +extern Tk_SmoothMethod tkBezierSmoothMethod; extern Tk_ImageType tkBitmapImageType; -extern Tk_Uid tkDisabledUid; extern Tk_PhotoImageFormat tkImgFmtGIF; extern void (*tkHandleEventProc) _ANSI_ARGS_(( XEvent* eventPtr)); extern Tk_PhotoImageFormat tkImgFmtPPM; extern TkMainInfo *tkMainWindowList; -extern Tk_Uid tkNormalUid; extern Tk_ImageType tkPhotoImageType; extern Tcl_HashTable tkPredefBitmapTable; extern int tkSendSerial; @@ -883,8 +886,8 @@ EXTERN int Tk_BindtagsCmd _ANSI_ARGS_((ClientData clientData, EXTERN int Tk_ButtonObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); -EXTERN int Tk_CanvasCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_CanvasObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); EXTERN int Tk_CheckbuttonObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); @@ -910,8 +913,9 @@ EXTERN int Tk_EventObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Obj *CONST objv[])); EXTERN int Tk_FileeventCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FrameCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_FrameObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); EXTERN int Tk_FocusObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); @@ -979,8 +983,9 @@ EXTERN int Tk_TkObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Obj *CONST objv[])); EXTERN int Tk_TkwaitCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ToplevelCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_ToplevelObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); EXTERN int Tk_UpdateObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); @@ -1001,6 +1006,70 @@ EXTERN int TkDeadAppCmd _ANSI_ARGS_((ClientData clientData, EXTERN int TkpTestembedCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); +EXTERN int TkCanvasGetCoordObj _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tcl_Obj *obj, + double *doublePtr)); +EXTERN int TkCanvasDashParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkCanvasDashPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkGetDoublePixels _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, CONST char *string, + double *doublePtr)); +EXTERN int TkOffsetParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkOffsetPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkOrientParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +EXTERN char * TkOrientPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkPixelParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkPixelPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkPostscriptImage _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + XImage *ximage, int x, int y, int width, + int height)); +EXTERN int TkSmoothParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); +EXTERN char * TkSmoothPrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *recordPtr, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkStateParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +EXTERN char * TkStatePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkTileParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkTilePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); /* * Unsupported commands. diff --git a/generic/tkIntXlibDecls.h b/generic/tkIntXlibDecls.h index d76165f..5f22fd8 100644 --- a/generic/tkIntXlibDecls.h +++ b/generic/tkIntXlibDecls.h @@ -9,7 +9,7 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tkIntXlibDecls.h,v 1.11 1999/07/31 03:36:49 hobbs Exp $ + * RCS: @(#) $Id: tkIntXlibDecls.h,v 1.12 1999/12/14 06:52:29 hobbs Exp $ */ #ifndef _TKINTXLIBDECLS @@ -39,7 +39,10 @@ */ #ifdef __WIN32__ -/* Slot 0 is reserved */ +/* 0 */ +EXTERN void XSetDashes _ANSI_ARGS_((Display* display, GC gc, + int dash_offset, _Xconst char* dash_list, + int n)); /* 1 */ EXTERN XModifierKeymap* XGetModifierMapping _ANSI_ARGS_((Display* d)); /* 2 */ @@ -354,14 +357,20 @@ EXTERN Status XStringListToTextProperty _ANSI_ARGS_((char** list, /* 104 */ EXTERN void XDrawLine _ANSI_ARGS_((Display* d, Drawable dr, GC g, int x1, int y1, int x2, int y2)); -/* Slot 105 is reserved */ +/* 105 */ +EXTERN void XWarpPointer _ANSI_ARGS_((Display* d, Window s, + Window dw, int sx, int sy, unsigned int sw, + unsigned int sh, int dx, int dy)); /* 106 */ EXTERN void XFillRectangle _ANSI_ARGS_((Display* display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height)); #endif /* __WIN32__ */ #ifdef MAC_TCL -/* Slot 0 is reserved */ +/* 0 */ +EXTERN void XSetDashes _ANSI_ARGS_((Display* display, GC gc, + int dash_offset, _Xconst char* dash_list, + int n)); /* 1 */ EXTERN XModifierKeymap* XGetModifierMapping _ANSI_ARGS_((Display* d)); /* 2 */ @@ -627,7 +636,7 @@ typedef struct TkIntXlibStubs { struct TkIntXlibStubHooks *hooks; #ifdef __WIN32__ - void *reserved0; + void (*xSetDashes) _ANSI_ARGS_((Display* display, GC gc, int dash_offset, _Xconst char* dash_list, int n)); /* 0 */ XModifierKeymap* (*xGetModifierMapping) _ANSI_ARGS_((Display* d)); /* 1 */ XImage * (*xCreateImage) _ANSI_ARGS_((Display* d, Visual* v, unsigned int ui1, int i1, int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, int i4)); /* 2 */ XImage * (*xGetImage) _ANSI_ARGS_((Display* d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3)); /* 3 */ @@ -732,11 +741,11 @@ typedef struct TkIntXlibStubs { void (*xSetWMClientMachine) _ANSI_ARGS_((Display* display, Window w, XTextProperty* text_prop)); /* 102 */ Status (*xStringListToTextProperty) _ANSI_ARGS_((char** list, int count, XTextProperty* text_prop_return)); /* 103 */ void (*xDrawLine) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int x1, int y1, int x2, int y2)); /* 104 */ - void *reserved105; + void (*xWarpPointer) _ANSI_ARGS_((Display* d, Window s, Window dw, int sx, int sy, unsigned int sw, unsigned int sh, int dx, int dy)); /* 105 */ void (*xFillRectangle) _ANSI_ARGS_((Display* display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height)); /* 106 */ #endif /* __WIN32__ */ #ifdef MAC_TCL - void *reserved0; + void (*xSetDashes) _ANSI_ARGS_((Display* display, GC gc, int dash_offset, _Xconst char* dash_list, int n)); /* 0 */ XModifierKeymap* (*xGetModifierMapping) _ANSI_ARGS_((Display* d)); /* 1 */ XImage * (*xCreateImage) _ANSI_ARGS_((Display* d, Visual* v, unsigned int ui1, int i1, int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, int i4)); /* 2 */ XImage * (*xGetImage) _ANSI_ARGS_((Display* d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3)); /* 3 */ @@ -838,7 +847,10 @@ extern TkIntXlibStubs *tkIntXlibStubsPtr; */ #ifdef __WIN32__ -/* Slot 0 is reserved */ +#ifndef XSetDashes +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#endif #ifndef XGetModifierMapping #define XGetModifierMapping \ (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ @@ -1252,14 +1264,20 @@ extern TkIntXlibStubs *tkIntXlibStubsPtr; #define XDrawLine \ (tkIntXlibStubsPtr->xDrawLine) /* 104 */ #endif -/* Slot 105 is reserved */ +#ifndef XWarpPointer +#define XWarpPointer \ + (tkIntXlibStubsPtr->xWarpPointer) /* 105 */ +#endif #ifndef XFillRectangle #define XFillRectangle \ (tkIntXlibStubsPtr->xFillRectangle) /* 106 */ #endif #endif /* __WIN32__ */ #ifdef MAC_TCL -/* Slot 0 is reserved */ +#ifndef XSetDashes +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#endif #ifndef XGetModifierMapping #define XGetModifierMapping \ (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ diff --git a/generic/tkMessage.c b/generic/tkMessage.c index 4001ac2..bb3cb00 100644 --- a/generic/tkMessage.c +++ b/generic/tkMessage.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMessage.c,v 1.4 1999/08/10 05:06:59 jingham Exp $ + * RCS: @(#) $Id: tkMessage.c,v 1.5 1999/12/14 06:52:30 hobbs Exp $ */ #include "tkPort.h" @@ -467,8 +467,6 @@ ConfigureMessage(interp, msgPtr, argc, argv, flags) msgPtr->numChars = Tcl_NumUtfChars(msgPtr->string, -1); - Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border); - if (msgPtr->highlightWidth < 0) { msgPtr->highlightWidth = 0; } @@ -500,12 +498,16 @@ MessageWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */ { XGCValues gcValues; - GC gc; + GC gc = None; Tk_FontMetrics fm; Message *msgPtr; msgPtr = (Message *) instanceData; + if (msgPtr->border != NULL) { + Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border); + } + gcValues.font = Tk_FontId(msgPtr->tkfont); gcValues.foreground = msgPtr->fgColorPtr->pixel; gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues); @@ -644,13 +646,23 @@ DisplayMessage(clientData) register Message *msgPtr = (Message *) clientData; register Tk_Window tkwin = msgPtr->tkwin; int x, y; + int borderWidth = msgPtr->highlightWidth; msgPtr->flags &= ~REDRAW_PENDING; if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + if (msgPtr->border != NULL) { + borderWidth += msgPtr->borderWidth; + } + if (msgPtr->relief == TK_RELIEF_FLAT) { + borderWidth = msgPtr->highlightWidth; + } + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, + borderWidth, borderWidth, + Tk_Width(tkwin) - 2 * borderWidth, + Tk_Height(tkwin) - 2 * borderWidth, + 0, TK_RELIEF_FLAT); /* * Compute starting y-location for message based on message size @@ -662,7 +674,7 @@ DisplayMessage(clientData) Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC, msgPtr->textLayout, x, y, 0, -1); - if (msgPtr->relief != TK_RELIEF_FLAT) { + if (borderWidth > msgPtr->highlightWidth) { Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, msgPtr->highlightWidth, msgPtr->highlightWidth, Tk_Width(tkwin) - 2*msgPtr->highlightWidth, diff --git a/generic/tkOldConfig.c b/generic/tkOldConfig.c index 0edf798..70e0152 100644 --- a/generic/tkOldConfig.c +++ b/generic/tkOldConfig.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkOldConfig.c,v 1.4 1999/04/21 21:53:27 rjohnson Exp $ + * RCS: @(#) $Id: tkOldConfig.c,v 1.5 1999/12/14 06:52:30 hobbs Exp $ */ #include "tkPort.h" @@ -125,7 +125,14 @@ Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) */ for ( ; argc > 0; argc -= 2, argv += 2) { - specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags); + char *arg; + + if (flags & TK_CONFIG_OBJS) { + arg = Tcl_GetStringFromObj((Tcl_Obj *) *argv, NULL); + } else { + arg = *argv; + } + specPtr = FindConfigSpec(interp, specs, arg, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } @@ -135,11 +142,16 @@ Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) */ if (argc < 2) { - Tcl_AppendResult(interp, "value for \"", *argv, + Tcl_AppendResult(interp, "value for \"", arg, "\" missing", (char *) NULL); return TCL_ERROR; } - if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) { + if (flags & TK_CONFIG_OBJS) { + arg = Tcl_GetString((Tcl_Obj *) argv[1]); + } else { + arg = argv[1]; + } + if (DoConfig(interp, tkwin, specPtr, arg, 0, widgRec) != TCL_OK) { char msg[100]; sprintf(msg, "\n (processing \"%.40s\" option)", diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c index 70556b4..b509c04 100644 --- a/generic/tkRectOval.c +++ b/generic/tkRectOval.c @@ -10,13 +10,14 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkRectOval.c,v 1.3 1999/04/16 01:51:21 stanton Exp $ + * RCS: @(#) $Id: tkRectOval.c,v 1.4 1999/12/14 06:52:30 hobbs Exp $ */ #include <stdio.h> #include "tk.h" #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each rectangle/oval item. @@ -25,14 +26,17 @@ typedef struct RectOvalItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ double bbox[4]; /* Coordinates of bounding box for rectangle * or oval (x1, y1, x2, y2). Item includes * x1 and x2 but not y1 and y2. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Color for filling rectangle/oval. */ + XColor *activeFillColor; /* Color for filling rectangle/oval if state is active. */ + XColor *disabledFillColor; /* Color for filling rectangle/oval if state is disabled. */ Pixmap fillStipple; /* Stipple bitmap for filling item. */ - GC outlineGC; /* Graphics context for outline. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is disabled. */ GC fillGC; /* Graphics context for filling item. */ } RectOvalItem; @@ -40,21 +44,93 @@ typedef struct RectOvalItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) TK_OFFSET_RELATIVE +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(RectOvalItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(RectOvalItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_PIXELS, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(RectOvalItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(RectOvalItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(RectOvalItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(RectOvalItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.stipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state),TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(RectOvalItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -67,10 +143,10 @@ static void ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas canvas, RectOvalItem *rectOvalPtr)); static int ConfigureRectOval _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateRectOval _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteRectOval _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayRectOval _ANSI_ARGS_((Tk_Canvas canvas, @@ -82,7 +158,7 @@ static double OvalToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)); static int RectOvalCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int RectOvalToPostscript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static int RectToArea _ANSI_ARGS_((Tk_Canvas canvas, @@ -109,7 +185,7 @@ Tk_ItemType tkRectangleType = { RectOvalCoords, /* coordProc */ DeleteRectOval, /* deleteProc */ DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ RectToPoint, /* pointProc */ RectToArea, /* areaProc */ RectOvalToPostscript, /* postscriptProc */ @@ -120,7 +196,7 @@ Tk_ItemType tkRectangleType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; Tk_ItemType tkOvalType = { @@ -132,7 +208,7 @@ Tk_ItemType tkOvalType = { RectOvalCoords, /* coordProc */ DeleteRectOval, /* deleteProc */ DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ OvalToPoint, /* pointProc */ OvalToArea, /* areaProc */ RectOvalToPostscript, /* postscriptProc */ @@ -143,7 +219,7 @@ Tk_ItemType tkOvalType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -173,11 +249,25 @@ CreateRectOval(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + int i; + + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 4; + } + } - if (argc < 4) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", @@ -190,34 +280,33 @@ CreateRectOval(interp, canvas, itemPtr, argc, argv) * up after errors during the the remainder of this procedure. */ - rectOvalPtr->width = 1; - rectOvalPtr->outlineColor = NULL; + Tk_CreateOutline(&(rectOvalPtr->outline)); + rectOvalPtr->tsoffset.flags = 0; + rectOvalPtr->tsoffset.xoffset = 0; + rectOvalPtr->tsoffset.yoffset = 0; rectOvalPtr->fillColor = NULL; + rectOvalPtr->activeFillColor = NULL; + rectOvalPtr->disabledFillColor = NULL; rectOvalPtr->fillStipple = None; - rectOvalPtr->outlineGC = None; + rectOvalPtr->activeFillStipple = None; + rectOvalPtr->disabledFillStipple = None; rectOvalPtr->fillGC = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &rectOvalPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; + if ((RectOvalCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureRectOval(interp, canvas, itemPtr, argc-4, argv+4, 0) - != TCL_OK) { - DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureRectOval(interp, canvas, itemPtr, argc-i, argv+i, 0) + == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -246,28 +335,42 @@ RectOvalCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, rectOvalPtr->bbox[0], c0); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[1], c1); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[2], c2); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[0]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[2]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[3]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((argc == 1)||(argc == 4)) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], + &rectOvalPtr->bbox[0]) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[2], &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[3], &rectOvalPtr->bbox[3]) != TCL_OK)) { return TCL_ERROR; } @@ -308,7 +411,7 @@ ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; @@ -316,41 +419,99 @@ ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) GC newGC; unsigned long mask; Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) rectOvalPtr, flags) != TCL_OK) { + + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) rectOvalPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } + state = itemPtr->state; + /* * A few of the options require additional processing, such as * graphics contexts. */ - if (rectOvalPtr->width < 1) { - rectOvalPtr->width = 1; - } - if (rectOvalPtr->outlineColor == NULL) { - newGC = None; + if (rectOvalPtr->outline.activeWidth > rectOvalPtr->outline.width || + rectOvalPtr->outline.activeDash.number > 0 || + rectOvalPtr->outline.activeColor != NULL || + rectOvalPtr->outline.activeStipple != None || + rectOvalPtr->activeFillColor != NULL || + rectOvalPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = rectOvalPtr->outlineColor->pixel; + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = &rectOvalPtr->outline.tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(rectOvalPtr->outline)); + if (mask) { gcValues.cap_style = CapProjecting; - gcValues.line_width = rectOvalPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; + mask |= GCCapStyle; newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (rectOvalPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outline.gc); } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outlineGC); + rectOvalPtr->outline.gc = newGC; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputeRectOvalBbox(canvas, rectOvalPtr); + return TCL_OK; + } + + color = rectOvalPtr->fillColor; + stipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->activeFillColor!=NULL) { + color = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + stipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->disabledFillColor!=NULL) { + color = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + stipple = rectOvalPtr->disabledFillStipple; + } } - rectOvalPtr->outlineGC = newGC; - if (rectOvalPtr->fillColor == NULL) { + if (color == NULL) { newGC = None; } else { - gcValues.foreground = rectOvalPtr->fillColor->pixel; - if (rectOvalPtr->fillStipple != None) { - gcValues.stipple = rectOvalPtr->fillStipple; + gcValues.foreground = color->pixel; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask = GCForeground|GCStipple|GCFillStyle; } else { @@ -362,6 +523,24 @@ ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC); } rectOvalPtr->fillGC = newGC; + + tsoffset = &rectOvalPtr->tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[3] + 0.5); + } + ComputeRectOvalBbox(canvas, rectOvalPtr); return TCL_OK; @@ -393,17 +572,24 @@ DeleteRectOval(canvas, itemPtr, display) { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - if (rectOvalPtr->outlineColor != NULL) { - Tk_FreeColor(rectOvalPtr->outlineColor); - } + Tk_DeleteOutline(display, &(rectOvalPtr->outline)); if (rectOvalPtr->fillColor != NULL) { Tk_FreeColor(rectOvalPtr->fillColor); } + if (rectOvalPtr->activeFillColor != NULL) { + Tk_FreeColor(rectOvalPtr->activeFillColor); + } + if (rectOvalPtr->disabledFillColor != NULL) { + Tk_FreeColor(rectOvalPtr->disabledFillColor); + } if (rectOvalPtr->fillStipple != None) { Tk_FreeBitmap(display, rectOvalPtr->fillStipple); } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(display, rectOvalPtr->outlineGC); + if (rectOvalPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, rectOvalPtr->activeFillStipple); + } + if (rectOvalPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, rectOvalPtr->disabledFillStipple); } if (rectOvalPtr->fillGC != None) { Tk_FreeGC(display, rectOvalPtr->fillGC); @@ -437,7 +623,28 @@ ComputeRectOvalBbox(canvas, rectOvalPtr) * recomputed. */ { int bloat, tmp; - double dtmp; + double dtmp, width; + Tk_State state = rectOvalPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = rectOvalPtr->outline.width; + if (state==TK_STATE_HIDDEN) { + rectOvalPtr->header.x1 = rectOvalPtr->header.y1 = + rectOvalPtr->header.x2 = rectOvalPtr->header.y2 = -1; + return; + } + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { + if (rectOvalPtr->outline.activeWidth>width) { + width = rectOvalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->outline.disabledWidth>0) { + width = rectOvalPtr->outline.disabledWidth; + } + } /* * Make sure that the first coordinates are the lowest ones. @@ -456,10 +663,10 @@ ComputeRectOvalBbox(canvas, rectOvalPtr) rectOvalPtr->bbox[0] = tmp; } - if (rectOvalPtr->outlineColor == NULL) { - bloat = 0; + if (rectOvalPtr->outline.gc == None) { + bloat = 1; } else { - bloat = (rectOvalPtr->width+1)/2; + bloat = (int) (width+1)/2; } /* @@ -518,6 +725,8 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; short x1, y1, x2, y2; + Pixmap fillStipple; + Tk_State state = itemPtr->state; /* * Compute the screen coordinates of the bounding box for the item. @@ -543,9 +752,48 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) * read-only. */ + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + fillStipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { + if (rectOvalPtr->activeFillStipple!=None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->disabledFillStipple!=None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + if (rectOvalPtr->fillGC != None) { - if (rectOvalPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, rectOvalPtr->fillGC); + if (fillStipple != None) { + Tk_TSOffset *tsoffset; + int w=0; int h=0; + tsoffset = &rectOvalPtr->tsoffset; + if (tsoffset) { + int flags = tsoffset->flags; + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, fillStipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + } + Tk_CanvasSetOffset(canvas, rectOvalPtr->fillGC, tsoffset); + if (tsoffset) { + tsoffset->xoffset += w; + tsoffset->yoffset += h; + } } if (rectOvalPtr->header.typePtr == &tkRectangleType) { XFillRectangle(display, drawable, rectOvalPtr->fillGC, @@ -555,18 +803,20 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); } - if (rectOvalPtr->fillStipple != None) { + if (fillStipple != None) { XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0); } } - if (rectOvalPtr->outlineGC != None) { + if (rectOvalPtr->outline.gc != None) { + Tk_ChangeOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); if (rectOvalPtr->header.typePtr == &tkRectangleType) { - XDrawRectangle(display, drawable, rectOvalPtr->outlineGC, + XDrawRectangle(display, drawable, rectOvalPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1)); } else { - XDrawArc(display, drawable, rectOvalPtr->outlineGC, + XDrawArc(display, drawable, rectOvalPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); } + Tk_ResetOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); } } @@ -602,6 +852,23 @@ RectToPoint(canvas, itemPtr, pointPtr) { RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = rectPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } /* * Generate a new larger rectangle that includes the border @@ -612,8 +879,8 @@ RectToPoint(canvas, itemPtr, pointPtr) y1 = rectPtr->bbox[1]; x2 = rectPtr->bbox[2]; y2 = rectPtr->bbox[3]; - if (rectPtr->outlineGC != None) { - inc = rectPtr->width/2.0; + if (rectPtr->outline.gc != None) { + inc = width/2.0; x1 -= inc; y1 -= inc; x2 += inc; @@ -629,7 +896,7 @@ RectToPoint(canvas, itemPtr, pointPtr) if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { - if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) { + if ((rectPtr->fillGC != None) || (rectPtr->outline.gc == None)) { return 0.0; } xDiff = pointPtr[0] - x1; @@ -645,7 +912,7 @@ RectToPoint(canvas, itemPtr, pointPtr) if (yDiff < xDiff) { xDiff = yDiff; } - xDiff -= rectPtr->width; + xDiff -= width; if (xDiff < 0.0) { return 0.0; } @@ -708,10 +975,26 @@ OvalToPoint(canvas, itemPtr, pointPtr) RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; double width; int filled; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = (double) ovalPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = (double) ovalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = (double) ovalPtr->outline.disabledWidth; + } + } + - width = ovalPtr->width; filled = ovalPtr->fillGC != None; - if (ovalPtr->outlineGC == None) { + if (ovalPtr->outline.gc == None) { width = 0.0; filled = 1; } @@ -749,9 +1032,26 @@ RectToArea(canvas, itemPtr, areaPtr) { RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; double halfWidth; + double width; + Tk_State state = itemPtr->state; - halfWidth = rectPtr->width/2.0; - if (rectPtr->outlineGC == None) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = rectPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } + + halfWidth = width/2.0; + if (rectPtr->outline.gc == None) { halfWidth = 0.0; } @@ -761,7 +1061,7 @@ RectToArea(canvas, itemPtr, areaPtr) || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { return -1; } - if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None) + if ((rectPtr->fillGC == None) && (rectPtr->outline.gc != None) && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) @@ -809,13 +1109,30 @@ OvalToArea(canvas, itemPtr, areaPtr) RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; double oval[4], halfWidth; int result; + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = ovalPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = ovalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = ovalPtr->outline.disabledWidth; + } + } /* * Expand the oval to include the width of the outline, if any. */ - halfWidth = ovalPtr->width/2.0; - if (ovalPtr->outlineGC == None) { + halfWidth = width/2.0; + if (ovalPtr->outline.gc == None) { halfWidth = 0.0; } oval[0] = ovalPtr->bbox[0] - halfWidth; @@ -832,9 +1149,9 @@ OvalToArea(canvas, itemPtr, areaPtr) * unfilled center, in which case we should return "outside". */ - if ((result == 0) && (ovalPtr->outlineGC != None) + if ((result == 0) && (ovalPtr->outline.gc != None) && (ovalPtr->fillGC == None)) { - double centerX, centerY, width, height; + double centerX, centerY, height; double xDelta1, yDelta1, xDelta2, yDelta2; centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; @@ -966,6 +1283,10 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) char pathCmd[500]; RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; double y1, y2; + XColor *color; + XColor *fillColor; + Pixmap fillStipple; + Tk_State state = itemPtr->state; y1 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[1]); y2 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[3]); @@ -988,23 +1309,51 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2); } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = rectOvalPtr->outline.color; + fillColor = rectOvalPtr->fillColor; + fillStipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->outline.activeColor!=NULL) { + color = rectOvalPtr->outline.activeColor; + } + if (rectOvalPtr->activeFillColor!=NULL) { + fillColor = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->outline.disabledColor!=NULL) { + color = rectOvalPtr->outline.disabledColor; + } + if (rectOvalPtr->disabledFillColor!=NULL) { + fillColor = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + /* * First draw the filled area of the rectangle. */ - if (rectOvalPtr->fillColor != NULL) { + if (fillColor != NULL) { Tcl_AppendResult(interp, pathCmd, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->fillColor) + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; } - if (rectOvalPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, rectOvalPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (rectOvalPtr->outlineColor != NULL) { + if (color != NULL) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -1016,18 +1365,13 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) * Now draw the outline, if there is one. */ - if (rectOvalPtr->outlineColor != NULL) { - char string[32 + TCL_INTEGER_SPACE]; - - Tcl_AppendResult(interp, pathCmd, (char *) NULL); - sprintf(string, "%d setlinewidth", rectOvalPtr->width); - Tcl_AppendResult(interp, string, - " 0 setlinejoin 2 setlinecap\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->outlineColor) - != TCL_OK) { + if (color != NULL) { + Tcl_AppendResult(interp, pathCmd, "0 setlinejoin 2 setlinecap\n", + (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(rectOvalPtr->outline))!= TCL_OK) { return TCL_ERROR; } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } return TCL_OK; } diff --git a/generic/tkScrollbar.c b/generic/tkScrollbar.c index e00581a..eec060e 100644 --- a/generic/tkScrollbar.c +++ b/generic/tkScrollbar.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkScrollbar.c,v 1.3 1999/04/16 01:51:21 stanton Exp $ + * RCS: @(#) $Id: tkScrollbar.c,v 1.4 1999/12/14 06:52:30 hobbs Exp $ */ #include "tkPort.h" @@ -20,6 +20,16 @@ #include "default.h" /* + * Custom option for handling "-orient" + */ + +static Tk_CustomOption orientOption = { + (Tk_OptionParseProc *) TkOrientParseProc, + TkOrientPrintProc, + (ClientData) NULL +}; + +/* * Information used for argv parsing. */ @@ -63,8 +73,9 @@ Tk_ConfigSpec tkpScrollbarConfigSpecs[] = { DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(TkScrollbar, highlightWidth), 0}, {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", DEF_SCROLLBAR_JUMP, Tk_Offset(TkScrollbar, jump), 0}, - {TK_CONFIG_UID, "-orient", "orient", "Orient", - DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, orientUid), 0}, + {TK_CONFIG_CUSTOM, "-orient", "orient", "Orient", + DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, vertical), 0, + &orientOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_SCROLLBAR_RELIEF, Tk_Offset(TkScrollbar, relief), 0}, {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", @@ -156,7 +167,6 @@ Tk_ScrollbarCmd(clientData, interp, argc, argv) scrollPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, (ClientData) scrollPtr, ScrollbarCmdDeletedProc); - scrollPtr->orientUid = NULL; scrollPtr->vertical = 0; scrollPtr->width = 0; scrollPtr->command = NULL; @@ -532,29 +542,16 @@ ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) int flags; /* Flags to pass to * Tk_ConfigureWidget. */ { - size_t length; - if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, tkpScrollbarConfigSpecs, argc, argv, (char *) scrollPtr, flags) != TCL_OK) { return TCL_ERROR; } /* - * A few options need special processing, such as parsing the - * orientation or setting the background from a 3-D border. + * A few options need special processing, such as setting the + * background from a 3-D border. */ - length = strlen(scrollPtr->orientUid); - if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { - scrollPtr->vertical = 1; - } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { - scrollPtr->vertical = 0; - } else { - Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, - "\": must be vertical or horizontal", (char *) NULL); - return TCL_ERROR; - } - if (scrollPtr->command != NULL) { scrollPtr->commandSize = strlen(scrollPtr->command); } else { diff --git a/generic/tkScrollbar.h b/generic/tkScrollbar.h index a1f3d4a..4e119e1 100644 --- a/generic/tkScrollbar.h +++ b/generic/tkScrollbar.h @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkScrollbar.h,v 1.4 1998/09/14 18:23:17 stanton Exp $ + * RCS: @(#) $Id: tkScrollbar.h,v 1.5 1999/12/14 06:52:30 hobbs Exp $ */ #ifndef _TKSCROLLBAR @@ -39,8 +39,6 @@ typedef struct TkScrollbar { * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */ - Tk_Uid orientUid; /* Orientation for window ("vertical" or - * "horizontal"). */ int vertical; /* Non-zero means vertical orientation * requested, zero means horizontal. */ int width; /* Desired narrow dimension of scrollbar, diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index 06f9e9a..bf2a37d 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkStubInit.c,v 1.13 1999/12/07 03:51:05 hobbs Exp $ + * RCS: @(#) $Id: tkStubInit.c,v 1.14 1999/12/14 06:52:31 hobbs Exp $ */ #include "tkInt.h" @@ -31,6 +31,11 @@ * Remove macros that will interfere with the definitions below. */ +#define Tk_CreateCanvasVisitor ((void (*) _ANSI_ARGS_((Tcl_Interp * interp, \ + VOID * typePtr))) NULL) +#define Tk_GetCanvasVisitor ((VOID * (*) _ANSI_ARGS_((Tcl_Interp * interp, \ + CONST char * name))) NULL) + /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations @@ -464,7 +469,7 @@ TkIntXlibStubs tkIntXlibStubs = { TCL_STUB_MAGIC, NULL, #ifdef __WIN32__ - NULL, /* 0 */ + XSetDashes, /* 0 */ XGetModifierMapping, /* 1 */ XCreateImage, /* 2 */ XGetImage, /* 3 */ @@ -569,11 +574,11 @@ TkIntXlibStubs tkIntXlibStubs = { XSetWMClientMachine, /* 102 */ XStringListToTextProperty, /* 103 */ XDrawLine, /* 104 */ - NULL, /* 105 */ + XWarpPointer, /* 105 */ XFillRectangle, /* 106 */ #endif /* __WIN32__ */ #ifdef MAC_TCL - NULL, /* 0 */ + XSetDashes, /* 0 */ XGetModifierMapping, /* 1 */ XCreateImage, /* 2 */ XGetImage, /* 3 */ @@ -913,6 +918,9 @@ TkStubs tkStubs = { Tk_SetOptions, /* 214 */ Tk_InitConsoleChannels, /* 215 */ Tk_CreateConsoleWindow, /* 216 */ + Tk_CreateSmoothMethod, /* 217 */ + Tk_CreateCanvasVisitor, /* 218 */ + Tk_GetCanvasVisitor, /* 219 */ }; /* !END!: Do not edit above this line. */ diff --git a/generic/tkTest.c b/generic/tkTest.c index fd68a32..d1c23bf 100644 --- a/generic/tkTest.c +++ b/generic/tkTest.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTest.c,v 1.8 1999/12/06 01:54:24 hobbs Exp $ + * RCS: @(#) $Id: tkTest.c,v 1.9 1999/12/14 06:52:31 hobbs Exp $ */ #include "tkInt.h" @@ -83,6 +83,7 @@ static Tk_ImageType imageType = { ImageDisplay, /* displayProc */ ImageFree, /* freeProc */ ImageDelete, /* deleteProc */ + (Tk_ImagePostscriptProc *) NULL,/* postscriptPtr */ (Tk_ImageType *) NULL /* nextPtr */ }; diff --git a/generic/tkText.c b/generic/tkText.c index 65ff1d1..16fb043 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkText.c,v 1.8 1999/12/12 22:51:22 hobbs Exp $ + * RCS: @(#) $Id: tkText.c,v 1.9 1999/12/14 06:52:31 hobbs Exp $ */ #include "default.h" @@ -29,6 +29,16 @@ #include "tkText.h" /* + * Custom options for handling "-state" + */ + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, + (ClientData) NULL /* only "normal" and "disabled" */ +}; + +/* * Information used to parse text configuration options: */ @@ -113,8 +123,8 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_PIXELS, "-spacing3", "spacing3", "Spacing", DEF_TEXT_SPACING3, Tk_Offset(TkText, spacing3), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_TEXT_STATE, Tk_Offset(TkText, state), 0}, + {TK_CONFIG_CUSTOM, "-state", "state", "State", + DEF_TEXT_STATE, Tk_Offset(TkText, state), 0, &stateOption}, {TK_CONFIG_STRING, "-tabs", "tabs", "Tabs", DEF_TEXT_TABS, Tk_Offset(TkText, tabOptionString), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", @@ -122,8 +132,8 @@ static Tk_ConfigSpec configSpecs[] = { TK_CONFIG_NULL_OK}, {TK_CONFIG_INT, "-width", "width", "Width", DEF_TEXT_WIDTH, Tk_Offset(TkText, width), 0}, - {TK_CONFIG_UID, "-wrap", "wrap", "Wrap", - DEF_TEXT_WRAP, Tk_Offset(TkText, wrapMode), 0}, + {TK_CONFIG_CUSTOM, "-wrap", "wrap", "Wrap", + DEF_TEXT_WRAP, Tk_Offset(TkText, wrapMode), 0, &textWrapModeOption}, {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", DEF_TEXT_XSCROLL_COMMAND, Tk_Offset(TkText, xScrollCmd), TK_CONFIG_NULL_OK}, @@ -142,6 +152,128 @@ static Tk_ConfigSpec configSpecs[] = { int tkTextDebug = 0; /* + * Custom options for handling "-wrap": + */ + +static int WrapModeParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, char *value, + char *widgRec, int offset)); +static char * WrapModePrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +Tk_CustomOption textWrapModeOption = { + WrapModeParseProc, + WrapModePrintProc, + (ClientData) NULL +}; + +/* + *-------------------------------------------------------------- + * + * WrapModeParseProc -- + * + * This procedure is invoked during option processing to handle + * "-wrap" options for text widgets. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The wrap mode for a given item gets replaced by the wrap mode + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +WrapModeParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *value; /* Value of option (list of tag + * names). */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register TkWrapMode *wrapPtr = (TkWrapMode *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *wrapPtr = TEXT_WRAPMODE_NULL; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'c') && (strncmp(value, "char", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_CHAR; + return TCL_OK; + } + if ((c == 'n') && (strncmp(value, "none", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_NONE; + return TCL_OK; + } + if ((c == 'w') && (strncmp(value, "word", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_WORD; + return TCL_OK; + } + Tcl_AppendResult(interp, "bad wrap mode \"", value, + "\": must be char, none, or word", + (char *) NULL); + *wrapPtr = TEXT_WRAPMODE_CHAR; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * WrapModePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-wrap" configuration + * option for canvas items. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +WrapModePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Ignored. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register TkWrapMode *wrapPtr = (TkWrapMode *) (widgRec + offset); + + if (*wrapPtr==TEXT_WRAPMODE_CHAR) { + return "char"; + } else if (*wrapPtr==TEXT_WRAPMODE_NONE) { + return "none"; + } else if (*wrapPtr==TEXT_WRAPMODE_WORD) { + return "word"; + } else { + return ""; + } +} + +/* * Forward declarations for procedures defined later in this file: */ @@ -244,7 +376,7 @@ Tk_TextCmd(clientData, interp, argc, argv) Tcl_InitHashTable(&textPtr->markTable, TCL_STRING_KEYS); Tcl_InitHashTable(&textPtr->windowTable, TCL_STRING_KEYS); Tcl_InitHashTable(&textPtr->imageTable, TCL_STRING_KEYS); - textPtr->state = Tk_GetUid("normal"); + textPtr->state = TK_STATE_NORMAL; textPtr->border = NULL; textPtr->borderWidth = 0; textPtr->padX = 0; @@ -262,7 +394,7 @@ Tk_TextCmd(clientData, interp, argc, argv) textPtr->spacing3 = 0; textPtr->tabOptionString = NULL; textPtr->tabArrayPtr = NULL; - textPtr->wrapMode = Tk_GetUid("char"); + textPtr->wrapMode = TEXT_WRAPMODE_CHAR; textPtr->width = 0; textPtr->height = 0; textPtr->setGrid = 0; @@ -480,7 +612,7 @@ TextWidgetCmd(clientData, interp, argc, argv) result = TCL_ERROR; goto done; } - if (textPtr->state == Tk_GetUid("normal")) { + if (textPtr->state == TK_STATE_NORMAL) { result = DeleteChars(textPtr, argv[2], (argc == 4) ? argv[3] : (char *) NULL); } @@ -588,7 +720,7 @@ TextWidgetCmd(clientData, interp, argc, argv) result = TCL_ERROR; goto done; } - if (textPtr->state == Tk_GetUid("normal")) { + if (textPtr->state == TK_STATE_NORMAL) { for (j = 3; j < argc; j += 2) { InsertChars(textPtr, &index1, argv[j]); if (argc > (j+1)) { @@ -764,23 +896,6 @@ ConfigureText(interp, textPtr, argc, argv, flags) * the geometry and setting the background from a 3-D border. */ - if ((textPtr->state != Tk_GetUid("normal")) - && (textPtr->state != Tk_GetUid("disabled"))) { - Tcl_AppendResult(interp, "bad state value \"", textPtr->state, - "\": must be normal or disabled", (char *) NULL); - textPtr->state = Tk_GetUid("normal"); - return TCL_ERROR; - } - - if ((textPtr->wrapMode != Tk_GetUid("char")) - && (textPtr->wrapMode != Tk_GetUid("none")) - && (textPtr->wrapMode != Tk_GetUid("word"))) { - Tcl_AppendResult(interp, "bad wrap mode \"", textPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - textPtr->wrapMode = Tk_GetUid("char"); - return TCL_ERROR; - } - Tk_SetBackgroundFromBorder(textPtr->tkwin, textPtr->border); /* @@ -854,8 +969,9 @@ ConfigureText(interp, textPtr, argc, argv, flags) || (textPtr->selTagPtr->spacing2String != NULL) || (textPtr->selTagPtr->spacing3String != NULL) || (textPtr->selTagPtr->tabString != NULL) + || (textPtr->selTagPtr->state != TK_STATE_NULL) || (textPtr->selTagPtr->underlineString != NULL) - || (textPtr->selTagPtr->wrapMode != NULL)) { + || (textPtr->selTagPtr->wrapMode != TEXT_WRAPMODE_NULL)) { textPtr->selTagPtr->affectsDisplay = 1; } TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, @@ -1403,7 +1519,7 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) } } } - if (segPtr->typePtr == &tkTextCharType) { + if (segPtr->typePtr == &tkTextCharType && !TkTextIsElided(textPtr, &textPtr->selIndex)) { memcpy((VOID *) buffer, (VOID *) (segPtr->body.chars + offsetInSeg), (size_t) chunkSize); buffer += chunkSize; @@ -1544,7 +1660,7 @@ TextSearchCmd(textPtr, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { - int backwards, exact, c, i, argsLeft, noCase, leftToScan; + int backwards, exact, searchElide, c, i, argsLeft, noCase, leftToScan; size_t length; int numLines, startingLine, startingByte, lineNum, firstByte, lastByte; int code, matchLength, matchByte, passes, stopLine, searchWholeText; @@ -1555,6 +1671,7 @@ TextSearchCmd(textPtr, interp, argc, argv) Tcl_DString line, patDString; TkTextSegment *segPtr; TkTextLine *linePtr; + TkTextIndex curIndex; Tcl_RegExp regexp = NULL; /* Initialization needed only to * prevent compiler warning. */ @@ -1563,6 +1680,8 @@ TextSearchCmd(textPtr, interp, argc, argv) */ exact = 1; + searchElide = 0; + curIndex.tree = textPtr->tree; backwards = 0; noCase = 0; varName = NULL; @@ -1576,7 +1695,7 @@ TextSearchCmd(textPtr, interp, argc, argv) badSwitch: Tcl_AppendResult(interp, "bad switch \"", arg, "\": must be -forward, -backward, -exact, -regexp, ", - "-nocase, -count, or --", (char *) NULL); + "-nocase, -count, -hidden, or --", (char *) NULL); return TCL_ERROR; } c = arg[1]; @@ -1592,12 +1711,16 @@ TextSearchCmd(textPtr, interp, argc, argv) varName = argv[i]; } else if ((c == 'e') && (strncmp(argv[i], "-exact", length) == 0)) { exact = 1; + } else if ((c == 'e') && (strncmp(argv[i], "-elide", length) == 0)) { + searchElide = 1; } else if ((c == 'f') && (strncmp(argv[i], "-forwards", length) == 0)) { backwards = 0; } else if ((c == 'n') && (strncmp(argv[i], "-nocase", length) == 0)) { noCase = 1; } else if ((c == 'r') && (strncmp(argv[i], "-regexp", length) == 0)) { exact = 0; + } else if ((c == 'h') && (strncmp(argv[i], "-hidden", length) == 0)) { + searchElide = 1; } else if ((c == '-') && (strncmp(argv[i], "--", length) == 0)) { i++; break; @@ -1692,9 +1815,10 @@ TextSearchCmd(textPtr, interp, argc, argv) */ linePtr = TkBTreeFindLine(textPtr->tree, lineNum); + curIndex.linePtr = linePtr; curIndex.byteIndex = 0; for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { + curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { + if (segPtr->typePtr != &tkTextCharType || (!searchElide && TkTextIsElided(textPtr, &curIndex))) { continue; } Tcl_DStringAppend(&line, segPtr->body.chars, segPtr->size); diff --git a/generic/tkText.h b/generic/tkText.h index 807295b..bec8ef7 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkText.h,v 1.5 1999/06/17 19:58:00 surles Exp $ + * RCS: @(#) $Id: tkText.h,v 1.6 1999/12/14 06:52:32 hobbs Exp $ */ #ifndef _TKTEXT @@ -274,6 +274,12 @@ struct TkTextDispChunk { * referred to in other structures. */ +typedef enum { TEXT_WRAPMODE_NULL, TEXT_WRAPMODE_NONE, + TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_WORD +} TkWrapMode; + +EXTERN Tk_CustomOption textWrapModeOption; + typedef struct TkTextTag { char *name; /* Name of this tag. This field is actually * a pointer to the key from the entry in @@ -371,13 +377,16 @@ typedef struct TkTextTag { int underline; /* Non-zero means draw underline underneath * text. Only valid if underlineString is * non-NULL. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * Must be tkTextCharUid, tkTextNoneUid, - * tkTextWordUid, or NULL to use wrapMode - * for whole widget. */ + TkWrapMode wrapMode; /* How to handle wrap-around for this tag. + * Must be TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, TEXT_WRAPMODE_WORD, + * or TEXT_WRAPMODE_NULL to use wrapmode for + * whole widget. */ int affectsDisplay; /* Non-zero means that this tag affects the * way information is displayed on the screen * (so need to redisplay if tag changes). */ + int state; /* Must be STATE_NULL, STATE_NORMAL, + * STATE_HIDDEN or STATE_DISABLED. */ } TkTextTag; #define TK_TAG_AFFECTS_DISPLAY 0x1 @@ -475,7 +484,7 @@ typedef struct TkText { * image segment doesn't yet have an * associated image, there is no entry for * it here. */ - Tk_Uid state; /* Either normal or disabled. A text + int state; /* Either STATE_NORMAL or STATE_DISABLED. A text * widget is read-only when disabled. */ /* @@ -518,9 +527,9 @@ typedef struct TkText { * Additional information used for displaying: */ - Tk_Uid wrapMode; /* How to handle wrap-around. Must be - * tkTextCharUid, tkTextNoneUid, or - * tkTextWordUid. */ + TkWrapMode wrapMode; /* How to handle wrap-around. Must be + * TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_NONE, or + * TEXT_WRAPMODE_WORD. */ int width, height; /* Desired dimensions for window, measured * in characters. */ int setGrid; /* Non-zero means pass gridding information @@ -657,7 +666,7 @@ typedef void Tk_SegLineChangeProc _ANSI_ARGS_(( typedef int Tk_SegLayoutProc _ANSI_ARGS_((struct TkText *textPtr, struct TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, struct TkTextDispChunk *chunkPtr)); typedef void Tk_SegCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, TkTextLine *linePtr)); @@ -716,15 +725,10 @@ typedef struct Tk_SegType { EXTERN int tkBTreeDebug; EXTERN int tkTextDebug; EXTERN Tk_SegType tkTextCharType; -EXTERN Tk_Uid tkTextCharUid; -EXTERN Tk_Uid tkTextDisabledUid; EXTERN Tk_SegType tkTextLeftMarkType; -EXTERN Tk_Uid tkTextNoneUid; -EXTERN Tk_Uid tkTextNormalUid; EXTERN Tk_SegType tkTextRightMarkType; EXTERN Tk_SegType tkTextToggleOnType; EXTERN Tk_SegType tkTextToggleOffType; -EXTERN Tk_Uid tkTextWordUid; /* * Declarations for procedures that are used by the text-related files @@ -775,7 +779,7 @@ EXTERN int TkTextCharBbox _ANSI_ARGS_((TkText *textPtr, EXTERN int TkTextCharLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, int noBreakYet, - Tk_Uid wrapMode, TkTextDispChunk *chunkPtr)); + TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); EXTERN void TkTextCreateDInfo _ANSI_ARGS_((TkText *textPtr)); EXTERN int TkTextDLineInfo _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, int *xPtr, int *yPtr, @@ -816,6 +820,8 @@ EXTERN void TkTextLostSelection _ANSI_ARGS_(( EXTERN TkTextIndex * TkTextMakeCharIndex _ANSI_ARGS_((TkTextBTree tree, int lineIndex, int charIndex, TkTextIndex *indexPtr)); +extern int TkTextIsElided _ANSI_ARGS_((TkText *textPtr, + TkTextIndex *indexPtr)); EXTERN TkTextIndex * TkTextMakeByteIndex _ANSI_ARGS_((TkTextBTree tree, int lineIndex, int byteIndex, TkTextIndex *indexPtr)); diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index 6f7beb6..c20a0db 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextBTree.c,v 1.3 1999/04/16 01:51:23 stanton Exp $ + * RCS: @(#) $Id: tkTextBTree.c,v 1.4 1999/12/14 06:52:32 hobbs Exp $ */ #include "tkInt.h" @@ -2427,6 +2427,132 @@ TkBTreeGetTags(indexPtr, numTagsPtr) } return tagInfo.tagPtrs; } + + +/* + special case to just return information about elided attribute + specialized from TkBTreeGetTags(indexPtr, numTagsPtr) and GetStyle(textPtr, indexPtr) + just need to keep track of invisibility settings for each priority, pick highest one active at end +*/ +int +TkTextIsElided(textPtr, indexPtr) + TkText *textPtr; /* Overall information about text widget. */ + TkTextIndex *indexPtr; /* The character in the text for which + * display information is wanted. */ +{ +#define LOTSA_TAGS 1000 + int elide = 0; /* if nobody says otherwise, it's visible */ + + int deftagCnts[LOTSA_TAGS]; + int *tagCnts = deftagCnts; + TkTextTag *deftagPtrs[LOTSA_TAGS]; + TkTextTag **tagPtrs = deftagPtrs; + int numTags = textPtr->numTags; + register Node *nodePtr; + register TkTextLine *siblingLinePtr; + register TkTextSegment *segPtr; + register TkTextTag *tagPtr; + register int i, index; + + /* almost always avoid malloc, so stay out of system calls */ + if (LOTSA_TAGS < numTags) { + tagCnts = (int *)ckalloc((unsigned)sizeof(int) * numTags); + tagPtrs = (TkTextTag **)ckalloc((unsigned)sizeof(TkTextTag *) * numTags); + } + + for (i=0; i<numTags; i++) tagCnts[i]=0; + + + /* + * Record tag toggles within the line of indexPtr but preceding + * indexPtr. + */ + + for (index = 0, segPtr = indexPtr->linePtr->segPtr; + (index + segPtr->size) <= indexPtr->byteIndex; + index += segPtr->size, segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr == &tkTextToggleOnType) + || (segPtr->typePtr == &tkTextToggleOffType)) { + tagPtr = segPtr->body.toggle.tagPtr; + if (tagPtr->state != TK_STATE_NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority]++; + } + } + } + + /* + * Record toggles for tags in lines that are predecessors of + * indexPtr->linePtr but under the same level-0 node. + */ + + for (siblingLinePtr = indexPtr->linePtr->parentPtr->children.linePtr; + siblingLinePtr != indexPtr->linePtr; + siblingLinePtr = siblingLinePtr->nextPtr) { + for (segPtr = siblingLinePtr->segPtr; segPtr != NULL; + segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr == &tkTextToggleOnType) + || (segPtr->typePtr == &tkTextToggleOffType)) { + tagPtr = segPtr->body.toggle.tagPtr; + if (tagPtr->state != TK_STATE_NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority]++; + } + } + } + } + + /* + * For each node in the ancestry of this line, record tag toggles + * for all siblings that precede that node. + */ + + for (nodePtr = indexPtr->linePtr->parentPtr; nodePtr->parentPtr != NULL; + nodePtr = nodePtr->parentPtr) { + register Node *siblingPtr; + register Summary *summaryPtr; + + for (siblingPtr = nodePtr->parentPtr->children.nodePtr; + siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) { + for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL; + summaryPtr = summaryPtr->nextPtr) { + if (summaryPtr->toggleCount & 1) { + tagPtr = summaryPtr->tagPtr; + if (tagPtr->state != TK_STATE_NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority] += summaryPtr->toggleCount; + } + } + } + } + } + + + /* + * Now traverse from highest priority to lowest, + * take elided value from first odd count (= on) + */ + + for (i = numTags-1; i >=0; i--) { + if (tagCnts[i] & 1) { +#ifndef ALWAYS_SHOW_SELECTION + /* who would make the selection elided? */ + if ((tagPtr == textPtr->selTagPtr) && !(textPtr->flags & GOT_FOCUS)) { + continue; + } +#endif + elide = (tagPtrs[i]->state == TK_STATE_HIDDEN); + break; + } + } + + if (LOTSA_TAGS < numTags) { + ckfree((char *) tagCnts); + ckfree((char *) tagPtrs); + } + + return elide; +} /* *---------------------------------------------------------------------- diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 90b1bd2..f9cef40 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextDisp.c,v 1.7 1999/08/10 05:07:36 jingham Exp $ + * RCS: @(#) $Id: tkTextDisp.c,v 1.8 1999/12/14 06:52:32 hobbs Exp $ */ #include "tkPort.h" @@ -59,8 +59,10 @@ typedef struct StyleValues { * be NULL). */ int underline; /* Non-zero means draw underline underneath * text. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * One of char, none, or text. */ + int elide; /* Non-zero means draw text */ + TkWrapMode wrapMode; /* How to handle wrap-around for this tag. + * One of TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE or TEXT_WRAPMODE_WORD.*/ } StyleValues; /* @@ -159,12 +161,14 @@ typedef struct DLine { * BOTTOM_LINE - Non-zero means that this was the bottom line * in the window the last time that the window * was laid out. + * IS_DISABLED - This Dline cannot be edited. */ #define HAS_3D_BORDER 1 #define NEW_LAYOUT 2 #define TOP_LINE 4 #define BOTTOM_LINE 8 +#define IS_DISABLED 16 /* * Overall display information for a text widget: @@ -315,6 +319,21 @@ static int CharMeasureProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, int x)); static void CharUndisplayProc _ANSI_ARGS_((TkText *textPtr, TkTextDispChunk *chunkPtr)); + +/* + Definitions of elided procs. + Compiler can't inline these since we use pointers to these functions. + ElideDisplayProc, ElideUndisplayProc special-cased for speed, + as potentially many elided DLine chunks if large, tag toggle-filled + elided region. +*/ +static void ElideBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, + int index, int y, int lineHeight, int baseline, + int *xPtr, int *yPtr, int *widthPtr, + int *heightPtr)); +static int ElideMeasureProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, + int x)); + static void DisplayDLine _ANSI_ARGS_((TkText *textPtr, DLine *dlPtr, DLine *prevPtr, Pixmap pixmap)); static void DisplayLineBackground _ANSI_ARGS_((TkText *textPtr, @@ -483,7 +502,7 @@ GetStyle(textPtr, indexPtr) int borderPrio, borderWidthPrio, reliefPrio, bgStipplePrio; int fgPrio, fontPrio, fgStipplePrio; - int underlinePrio, justifyPrio, offsetPrio; + int underlinePrio, statePrio, justifyPrio, offsetPrio; int lMargin1Prio, lMargin2Prio, rMarginPrio; int spacing1Prio, spacing2Prio, spacing3Prio; int overstrikePrio, tabPrio, wrapPrio; @@ -498,7 +517,7 @@ GetStyle(textPtr, indexPtr) tagPtrs = TkBTreeGetTags(indexPtr, &numTags); borderPrio = borderWidthPrio = reliefPrio = bgStipplePrio = -1; fgPrio = fontPrio = fgStipplePrio = -1; - underlinePrio = justifyPrio = offsetPrio = -1; + underlinePrio = statePrio = justifyPrio = offsetPrio = -1; lMargin1Prio = lMargin2Prio = rMarginPrio = -1; spacing1Prio = spacing2Prio = spacing3Prio = -1; overstrikePrio = tabPrio = wrapPrio = -1; @@ -512,6 +531,7 @@ GetStyle(textPtr, indexPtr) styleValues.spacing3 = textPtr->spacing3; styleValues.tabArrayPtr = textPtr->tabArrayPtr; styleValues.wrapMode = textPtr->wrapMode; + styleValues.elide = (textPtr->state == TK_STATE_HIDDEN); for (i = 0 ; i < numTags; i++) { tagPtr = tagPtrs[i]; @@ -616,7 +636,12 @@ GetStyle(textPtr, indexPtr) styleValues.underline = tagPtr->underline; underlinePrio = tagPtr->priority; } - if ((tagPtr->wrapMode != NULL) + if ((tagPtr->state != TK_STATE_NULL) + && (tagPtr->priority > statePrio)) { + styleValues.elide = (tagPtr->state == TK_STATE_HIDDEN); + statePrio = tagPtr->priority; + } + if ((tagPtr->wrapMode != TEXT_WRAPMODE_NULL) && (tagPtr->priority > wrapPrio)) { styleValues.wrapMode = tagPtr->wrapMode; wrapPrio = tagPtr->priority; @@ -656,9 +681,10 @@ GetStyle(textPtr, indexPtr) } else { stylePtr->bgGC = None; } - mask = GCForeground|GCFont; - gcValues.foreground = styleValues.fgColor->pixel; + mask = GCFont; gcValues.font = Tk_FontId(styleValues.tkfont); + mask |= GCForeground; + gcValues.foreground = styleValues.fgColor->pixel; if (styleValues.fgStipple != None) { gcValues.stipple = styleValues.fgStipple; gcValues.fill_style = FillStippled; @@ -702,7 +728,9 @@ FreeStyle(textPtr, stylePtr) if (stylePtr->bgGC != None) { Tk_FreeGC(textPtr->display, stylePtr->bgGC); } - Tk_FreeGC(textPtr->display, stylePtr->fgGC); + if (stylePtr->fgGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->fgGC); + } Tcl_DeleteHashEntry(stylePtr->hPtr); ckfree((char *) stylePtr); } @@ -754,7 +782,7 @@ LayoutDLine(textPtr, indexPtr) int jIndent; /* Additional indentation (beyond * margins) due to justification. */ int rMargin; /* Right margin width for line. */ - Tk_Uid wrapMode; /* Wrap mode to use for this line. */ + TkWrapMode wrapMode; /* Wrap mode to use for this line. */ int x = 0, maxX = 0; /* Initializations needed only to * stop compiler warnings. */ int wholeLine; /* Non-zero means this display line @@ -775,7 +803,7 @@ LayoutDLine(textPtr, indexPtr) * lines with numBytes > 0. Used to * drop 0-sized chunks from the end * of the line. */ - int byteOffset, ascent, descent, code; + int byteOffset, ascent, descent, code, elide, elidesize; StyleValues *sValuePtr; /* @@ -793,6 +821,34 @@ LayoutDLine(textPtr, indexPtr) dlPtr->nextPtr = NULL; dlPtr->flags = NEW_LAYOUT; + + /* + * special case entirely elide line as there may be 1000s or more + */ + elide = TkTextIsElided(textPtr, indexPtr); /* save a malloc */ + if (elide && indexPtr->byteIndex==0) { + maxBytes = 0; + for (segPtr = indexPtr->linePtr->segPtr; elide && segPtr!=NULL; segPtr = segPtr->nextPtr) { + if ((elidesize = segPtr->size) > 0) { + maxBytes += elidesize; + + /* if have tag toggle, chance that invisibility state changed, so bail out */ + } else if (segPtr->typePtr == &tkTextToggleOffType || segPtr->typePtr == &tkTextToggleOnType) { + if (segPtr->body.toggle.tagPtr->state!=TK_STATE_NULL) { + elide = (segPtr->typePtr == &tkTextToggleOffType) ^ (segPtr->body.toggle.tagPtr->state==TK_STATE_HIDDEN); + } + } + } + + if (elide) { + dlPtr->byteCount = maxBytes; + dlPtr->spaceAbove = dlPtr->spaceBelow = dlPtr->length = 0; + return dlPtr; + } + } + + + /* * Each iteration of the loop below creates one TkTextDispChunk for * the new display line. The line will always have at least one @@ -804,6 +860,7 @@ LayoutDLine(textPtr, indexPtr) lastChunkPtr = NULL; chunkPtr = NULL; noCharsYet = 1; + elide = 0; breakChunkPtr = NULL; breakByteOffset = 0; justify = TK_JUSTIFY_LEFT; @@ -811,7 +868,7 @@ LayoutDLine(textPtr, indexPtr) tabChunkPtr = NULL; tabArrayPtr = NULL; rMargin = 0; - wrapMode = Tk_GetUid("char"); + wrapMode = TEXT_WRAPMODE_CHAR; tabSize = 0; lastCharChunkPtr = NULL; @@ -828,6 +885,32 @@ LayoutDLine(textPtr, indexPtr) } while (segPtr != NULL) { + + /* every line still gets at least one chunk due to expectations in rest of code, + but able to skip elided portions of line quickly */ + /* if current chunk elided and last chunk was too, coalese */ + if (elide && lastChunkPtr!=NULL && lastChunkPtr->displayProc == NULL/*ElideDisplayProc*/) { + if ((elidesize = segPtr->size - byteOffset) > 0) { + curIndex.byteIndex += elidesize; + lastChunkPtr->numBytes += elidesize; + breakByteOffset = lastChunkPtr->breakIndex = lastChunkPtr->numBytes; + + /* if have tag toggle, chance that invisibility state changed */ + } else if (segPtr->typePtr == &tkTextToggleOffType || segPtr->typePtr == &tkTextToggleOnType) { + if (segPtr->body.toggle.tagPtr->state!=TK_STATE_NULL) { + elide = (segPtr->typePtr == &tkTextToggleOffType) ^ + (segPtr->body.toggle.tagPtr->state==TK_STATE_HIDDEN); + } + } + + byteOffset = 0; + segPtr = segPtr->nextPtr; + if (segPtr == NULL && chunkPtr != NULL) ckfree((char *) chunkPtr); + + continue; + } + + if (segPtr->typePtr->layoutProc == NULL) { segPtr = segPtr->nextPtr; byteOffset = 0; @@ -838,6 +921,7 @@ LayoutDLine(textPtr, indexPtr) chunkPtr->nextPtr = NULL; } chunkPtr->stylePtr = GetStyle(textPtr, &curIndex); + elide = chunkPtr->stylePtr->sValuePtr->elide; /* * Save style information such as justification and indentation, @@ -853,7 +937,7 @@ LayoutDLine(textPtr, indexPtr) x = ((curIndex.byteIndex == 0) ? chunkPtr->stylePtr->sValuePtr->lMargin1 : chunkPtr->stylePtr->sValuePtr->lMargin2); - if (wrapMode == Tk_GetUid("none")) { + if (wrapMode == TEXT_WRAPMODE_NONE) { maxX = -1; } else { maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x @@ -871,7 +955,7 @@ LayoutDLine(textPtr, indexPtr) gotTab = 0; maxBytes = segPtr->size - byteOffset; - if (justify == TK_JUSTIFY_LEFT) { + if (!elide && justify == TK_JUSTIFY_LEFT) { if (segPtr->typePtr == &tkTextCharType) { char *p; @@ -884,8 +968,21 @@ LayoutDLine(textPtr, indexPtr) } } } - chunkPtr->x = x; + if (elide && maxBytes) { + /* don't free style here, as other code expects to be able to do that */ + /*breakByteOffset =*/ chunkPtr->breakIndex = chunkPtr->numBytes = maxBytes; + chunkPtr->width = 0; + chunkPtr->minAscent = chunkPtr->minDescent = chunkPtr->minHeight = 0; + + /* would just like to point to canonical empty chunk */ + chunkPtr->displayProc = (Tk_ChunkDisplayProc *) NULL; + chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL; + chunkPtr->measureProc = ElideMeasureProc; + chunkPtr->bboxProc = ElideBboxProc; + + code = 1; + } else code = (*segPtr->typePtr->layoutProc)(textPtr, &curIndex, segPtr, byteOffset, maxX-tabSize, maxBytes, noCharsYet, wrapMode, chunkPtr); @@ -957,6 +1054,7 @@ LayoutDLine(textPtr, indexPtr) byteOffset = 0; segPtr = segPtr->nextPtr; } + chunkPtr = NULL; } if (noCharsYet) { @@ -1005,6 +1103,7 @@ LayoutDLine(textPtr, indexPtr) wholeLine = 0; } + /* * Make tab adjustments for the last tab stop, if there is one. */ @@ -1026,7 +1125,7 @@ LayoutDLine(textPtr, indexPtr) * what is implemented below. */ - if (wrapMode == Tk_GetUid("none")) { + if (wrapMode == TEXT_WRAPMODE_NONE) { maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - rMargin; } dlPtr->length = lastChunkPtr->x + lastChunkPtr->width; @@ -1328,10 +1427,12 @@ UpdateDisplayInfo(textPtr) index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); index.byteIndex = 0; lowestPtr = NULL; + do { dlPtr = LayoutDLine(textPtr, &index); dlPtr->nextPtr = lowestPtr; lowestPtr = dlPtr; + if (dlPtr->length == 0 && dlPtr->height == 0) { bytesToCount--; break; } /* elide */ TkTextIndexForwBytes(&index, dlPtr->byteCount, &index); bytesToCount -= dlPtr->byteCount; } while ((bytesToCount > 0) @@ -1561,6 +1662,8 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) Display *display; int height, x; + if (dlPtr->chunkPtr == NULL) return; + /* * First, clear the area of the line to the background color for the * text widget. @@ -1584,7 +1687,7 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) * to its left. */ - if (textPtr->state == Tk_GetUid("normal")) { + if (textPtr->state == TK_STATE_NORMAL) { for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); chunkPtr = chunkPtr->nextPtr) { x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; @@ -1627,12 +1730,16 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) * something is off to the right). */ + if (chunkPtr->displayProc != NULL) (*chunkPtr->displayProc)(chunkPtr, -chunkPtr->width, dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, dlPtr->y + dlPtr->spaceAbove); } else { + /* don't call if elide. This tax ok since not very many visible DLine's in + an area, but potentially many elide ones */ + if (chunkPtr->displayProc != NULL) (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, @@ -1721,6 +1828,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) StyleValues *sValuePtr; Display *display; + /* * Pass 1: scan through dlPtr from left to right. For each range of * chunks with the same style, draw the main background for the style @@ -1794,7 +1902,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) rightX = maxX; } chunkPtr2 = NULL; - if (prevPtr != NULL) { + if (prevPtr != NULL && prevPtr->chunkPtr != NULL) { /* * Find the chunk in the previous line that covers leftX. */ @@ -1915,7 +2023,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) rightX = maxX; } chunkPtr2 = NULL; - if (dlPtr->nextPtr != NULL) { + if (dlPtr->nextPtr != NULL && dlPtr->nextPtr->chunkPtr != NULL) { /* * Find the chunk in the previous line that covers leftX. */ @@ -2308,6 +2416,7 @@ DisplayText(clientData) for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr; (dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY); prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) { + if (dlPtr->chunkPtr == NULL) continue; if (dlPtr->oldY != dlPtr->y) { if (tkTextDebug) { char string[TK_POS_CHARS]; @@ -2324,6 +2433,7 @@ DisplayText(clientData) dlPtr->oldY = dlPtr->y; dlPtr->flags &= ~NEW_LAYOUT; } + /*prevPtr = dlPtr;*/ } Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap); } @@ -3203,7 +3313,7 @@ TkTextSeeCmd(textPtr, interp, argc, argv) dlPtr = FindDLine(dInfoPtr->dLinePtr, &index); byteCount = index.byteIndex - dlPtr->index.byteIndex; - for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { + for (chunkPtr = dlPtr->chunkPtr; chunkPtr!=NULL ; chunkPtr = chunkPtr->nextPtr) { if (byteCount < chunkPtr->numBytes) { break; } @@ -3215,6 +3325,7 @@ TkTextSeeCmd(textPtr, interp, argc, argv) * the character within the chunk. */ + if (chunkPtr!=NULL) { /* chunkPtr==NULL iff trying to see in elided region */ (*chunkPtr->bboxProc)(chunkPtr, byteCount, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width, @@ -3240,7 +3351,7 @@ TkTextSeeCmd(textPtr, interp, argc, argv) } else { return TCL_OK; } - } + }} dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; @@ -3390,7 +3501,7 @@ ScrollByLines(textPtr, offset) break; } } - + /* * Discard the display lines, then either return or prepare * for the next display line to lay out. @@ -3419,6 +3530,7 @@ ScrollByLines(textPtr, offset) TkBTreeNumLines(textPtr->tree)); for (i = 0; i < offset; i++) { dlPtr = LayoutDLine(textPtr, &textPtr->topIndex); + if (dlPtr->length == 0 && dlPtr->height == 0) offset++; dlPtr->nextPtr = NULL; TkTextIndexForwBytes(&textPtr->topIndex, dlPtr->byteCount, &new); FreeDLines(textPtr, dlPtr, (DLine *) NULL, 0); @@ -3631,13 +3743,14 @@ TkTextScanCmd(textPtr, interp, argc, argv) { TextDInfo *dInfoPtr = textPtr->dInfoPtr; TkTextIndex index; - int c, x, y, totalScroll, newByte, maxByte; + int c, x, y, totalScroll, newByte, maxByte, gain=10; Tk_FontMetrics fm; size_t length; - if (argc != 5) { + if ((argc != 5) && (argc != 6)) { Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); + argv[0], " scan mark x y\" or \"", + argv[0], " scan dragto x y ?gain?\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) { @@ -3646,6 +3759,8 @@ TkTextScanCmd(textPtr, interp, argc, argv) if (Tcl_GetInt(interp, argv[4], &y) != TCL_OK) { return TCL_ERROR; } + if ((argc == 6) && (Tcl_GetInt(interp, argv[5], &gain) != TCL_OK)) + return TCL_ERROR; c = argv[2][0]; length = strlen(argv[2]); if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { @@ -3661,7 +3776,7 @@ TkTextScanCmd(textPtr, interp, argc, argv) * moving again). */ - newByte = dInfoPtr->scanMarkIndex + (10*(dInfoPtr->scanMarkX - x)) + newByte = dInfoPtr->scanMarkIndex + (gain*(dInfoPtr->scanMarkX - x)) / (textPtr->charWidth); maxByte = 1 + (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) + textPtr->charWidth - 1)/textPtr->charWidth; @@ -3677,7 +3792,7 @@ TkTextScanCmd(textPtr, interp, argc, argv) dInfoPtr->newByteOffset = newByte; Tk_GetFontMetrics(textPtr->tkfont, &fm); - totalScroll = (10*(dInfoPtr->scanMarkY - y)) / fm.linespace; + totalScroll = (gain*(dInfoPtr->scanMarkY - y)) / fm.linespace; if (totalScroll != dInfoPtr->scanTotalScroll) { index = textPtr->topIndex; ScrollByLines(textPtr, totalScroll-dInfoPtr->scanTotalScroll); @@ -3961,7 +4076,7 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) * index of the character nearest to (x,y). */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - register DLine *dlPtr; + register DLine *dlPtr, *validdlPtr; register TkTextDispChunk *chunkPtr; /* @@ -3994,8 +4109,9 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) * Find the display line containing the desired y-coordinate. */ - for (dlPtr = dInfoPtr->dLinePtr; y >= (dlPtr->y + dlPtr->height); + for (dlPtr = validdlPtr = dInfoPtr->dLinePtr; y >= (dlPtr->y + dlPtr->height); dlPtr = dlPtr->nextPtr) { + if (dlPtr->chunkPtr !=NULL) validdlPtr = dlPtr; if (dlPtr->nextPtr == NULL) { /* * Y-coordinate is off the bottom of the displayed text. @@ -4006,6 +4122,8 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) break; } } + if (dlPtr->chunkPtr == NULL) dlPtr = validdlPtr; + /* * Scan through the line's chunks to find the one that contains @@ -4179,6 +4297,7 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) { TextDInfo *dInfoPtr = textPtr->dInfoPtr; DLine *dlPtr; + int dlx; /* * Make sure that all of the screen layout information is up to date. @@ -4197,8 +4316,9 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) return -1; } - *xPtr = dInfoPtr->x - dInfoPtr->curPixelOffset + dlPtr->chunkPtr->x; - *widthPtr = dlPtr->length - dlPtr->chunkPtr->x; + dlx = (dlPtr->chunkPtr != NULL? dlPtr->chunkPtr->x: 0); + *xPtr = dInfoPtr->x - dInfoPtr->curPixelOffset + dlx; + *widthPtr = dlPtr->length - dlx; *yPtr = dlPtr->y; if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { *heightPtr = dInfoPtr->maxY - dlPtr->y; @@ -4209,6 +4329,41 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) return 0; } +static void +ElideBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, + widthPtr, heightPtr) + TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ + int index; /* Index of desired character within + * the chunk. */ + int y; /* Topmost pixel in area allocated + * for this line. */ + int lineHeight; /* Height of line, in pixels. */ + int baseline; /* Location of line's baseline, in + * pixels measured down from y. */ + int *xPtr, *yPtr; /* Gets filled in with coords of + * character's upper-left pixel. + * X-coord is in same coordinate + * system as chunkPtr->x. */ + int *widthPtr; /* Gets filled in with width of + * character, in pixels. */ + int *heightPtr; /* Gets filled in with height of + * character, in pixels. */ +{ + *xPtr = chunkPtr->x; + *yPtr = y; + *widthPtr = *heightPtr = 0; +} + + +static int +ElideMeasureProc(chunkPtr, x) + TkTextDispChunk *chunkPtr; /* Chunk containing desired coord. */ + int x; /* X-coordinate, in same coordinate + * system as chunkPtr->x. */ +{ + return 0 /*chunkPtr->numBytes - 1*/; +} + /* *-------------------------------------------------------------- * @@ -4247,8 +4402,8 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, byteOffset, maxX, maxBytes, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this display line yet. */ - Tk_Uid wrapMode; /* How to handle line wrapping: char, - * none, or text. */ + TkWrapMode wrapMode; /* How to handle line wrapping: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -4342,7 +4497,7 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, byteOffset, maxX, maxBytes, * is not a character segment. */ - if (wrapMode != Tk_GetUid("word")) { + if (wrapMode != TEXT_WRAPMODE_WORD) { chunkPtr->breakIndex = chunkPtr->numBytes; } else { for (count = bytesThatFit, p += bytesThatFit - 1; count > 0; @@ -4436,7 +4591,7 @@ CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) * Draw the text, underline, and overstrike for this chunk. */ - if (ciPtr->numBytes > offsetBytes) { + if (!sValuePtr->elide && (ciPtr->numBytes > offsetBytes) && (stylePtr->fgGC != None)) { int numBytes = ciPtr->numBytes - offsetBytes; char *string = ciPtr->chars + offsetBytes; diff --git a/generic/tkTextImage.c b/generic/tkTextImage.c index b2d1923..0708a94 100644 --- a/generic/tkTextImage.c +++ b/generic/tkTextImage.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextImage.c,v 1.3 1999/04/16 01:51:23 stanton Exp $ + * RCS: @(#) $Id: tkTextImage.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $ */ #include "tk.h" @@ -62,7 +62,7 @@ static void EmbImageDisplayProc _ANSI_ARGS_(( static int EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static void EmbImageProc _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, @@ -604,8 +604,8 @@ EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: char, - * text, or word. */ + TkWrapMode wrapMode; /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -630,7 +630,7 @@ EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, height += 2*eiPtr->body.ei.padY; } if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != Tk_GetUid("none"))) { + && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) { return 0; } diff --git a/generic/tkTextMark.c b/generic/tkTextMark.c index 209a33b..ff3ef44 100644 --- a/generic/tkTextMark.c +++ b/generic/tkTextMark.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextMark.c,v 1.3 1999/04/16 01:51:24 stanton Exp $ + * RCS: @(#) $Id: tkTextMark.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $ */ #include "tkInt.h" @@ -39,7 +39,7 @@ static void MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, static int MarkLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static int MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp, TkText *textPtr, char *markName)); @@ -454,7 +454,7 @@ MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Not used. */ + TkWrapMode wrapMode; /* Not used. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c index 9827f92..00723ab 100644 --- a/generic/tkTextTag.c +++ b/generic/tkTextTag.c @@ -11,18 +11,40 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextTag.c,v 1.3 1999/04/16 01:51:24 stanton Exp $ + * RCS: @(#) $Id: tkTextTag.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $ */ #include "default.h" #include "tkPort.h" -#include "tk.h" +#include "tkInt.h" #include "tkText.h" /* * Information used for parsing tag configuration information: */ +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; + +/* The "-elide" is only provided for compatibility with TkMan 2.0, + * but might be removed in the future. The option "-state" provides + * the same functionality and is preferred. + */ + +static int ElideParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *widgRec, int offset)); +static char * ElidePrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +static Tk_CustomOption elideOption = { + (Tk_OptionParseProc *) ElideParseProc, + ElidePrintProc, (ClientData) 0 +}; + static Tk_ConfigSpec tagConfigSpecs[] = { {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, border), TK_CONFIG_NULL_OK}, @@ -31,6 +53,9 @@ static Tk_ConfigSpec tagConfigSpecs[] = { {TK_CONFIG_STRING, "-borderwidth", (char *) NULL, (char *) NULL, "0", Tk_Offset(TkTextTag, bdString), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-elide", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TkTextTag, state), + TK_CONFIG_NULL_OK, &elideOption}, {TK_CONFIG_BITMAP, "-fgstipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, fgStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, @@ -58,14 +83,17 @@ static Tk_ConfigSpec tagConfigSpecs[] = { (char *) NULL, Tk_Offset(TkTextTag, spacing2String), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-spacing3", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, spacing3String), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TkTextTag, state), + TK_CONFIG_NULL_OK, &stateOption}, {TK_CONFIG_STRING, "-tabs", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, tabString), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-underline", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, underlineString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-wrap", (char *) NULL, (char *) NULL, + {TK_CONFIG_CUSTOM, "-wrap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, wrapMode), - TK_CONFIG_NULL_OK}, + TK_CONFIG_NULL_OK, &textWrapModeOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -391,15 +419,6 @@ TkTextTagCmd(textPtr, interp, argc, argv) return TCL_ERROR; } } - if ((tagPtr->wrapMode != NULL) - && (tagPtr->wrapMode != Tk_GetUid("char")) - && (tagPtr->wrapMode != Tk_GetUid("none")) - && (tagPtr->wrapMode != Tk_GetUid("word"))) { - Tcl_AppendResult(interp, "bad wrap mode \"", tagPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - tagPtr->wrapMode = NULL; - return TCL_ERROR; - } /* * If the "sel" tag was changed, be sure to mirror information @@ -432,7 +451,8 @@ TkTextTagCmd(textPtr, interp, argc, argv) || (tagPtr->spacing3String != NULL) || (tagPtr->tabString != NULL) || (tagPtr->underlineString != NULL) - || (tagPtr->wrapMode != NULL)) { + || (tagPtr->state != TK_STATE_NULL) + || (tagPtr->wrapMode != TEXT_WRAPMODE_NULL)) { tagPtr->affectsDisplay = 1; } TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, @@ -824,7 +844,8 @@ TkTextCreateTag(textPtr, tagName) tagPtr->tabArrayPtr = NULL; tagPtr->underlineString = NULL; tagPtr->underline = 0; - tagPtr->wrapMode = NULL; + tagPtr->state = TK_STATE_NULL; + tagPtr->wrapMode = TEXT_WRAPMODE_NULL; tagPtr->affectsDisplay = 0; textPtr->numTags++; Tcl_SetHashValue(hPtr, tagPtr); @@ -1387,3 +1408,89 @@ TkTextPickCurrent(textPtr, eventPtr) ckfree((char *) copyArrayPtr); } } + +/* + *-------------------------------------------------------------- + * + * ElideParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-elide" option. This option is an obsolete equivalent + * of the "-state" option. It is only added for compatibility + * with TkMan 2.0, but will be removed in the future. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The state for a given item gets replaced by the state + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +ElideParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int b; + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *statePtr = TK_STATE_NULL; + return TCL_OK; + } + if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) { + *statePtr = TK_STATE_NULL; + return TCL_ERROR; + } + *statePtr = b?TK_STATE_HIDDEN:TK_STATE_NORMAL; + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * ElidePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-elide" + * configuration option. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +ElidePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing text widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if (*statePtr==TK_STATE_HIDDEN) { + return "1"; + } else if (*statePtr==TK_STATE_NULL) { + return ""; + } else { + return "0"; + } +} diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c index ef28b44..c43b8e8 100644 --- a/generic/tkTextWind.c +++ b/generic/tkTextWind.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextWind.c,v 1.3 1999/04/16 01:51:24 stanton Exp $ + * RCS: @(#) $Id: tkTextWind.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $ */ #include "tk.h" @@ -81,7 +81,7 @@ static void EmbWinDisplayProc _ANSI_ARGS_(( static int EmbWinLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); @@ -744,8 +744,8 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ + TkWrapMode wrapMode; /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -835,7 +835,7 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, height = Tk_ReqHeight(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padY; } if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != Tk_GetUid("none"))) { + && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) { return 0; } diff --git a/generic/tkTrig.c b/generic/tkTrig.c index d0afe90..b8a88e7 100644 --- a/generic/tkTrig.c +++ b/generic/tkTrig.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTrig.c,v 1.3 1999/04/16 01:51:24 stanton Exp $ + * RCS: @(#) $Id: tkTrig.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $ */ #include <stdio.h> @@ -1066,6 +1066,14 @@ TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints) * just put the first point into the output. */ + if (!pointPtr) { + /* Of pointPtr == NULL, this function returns an upper limit. + * of the array size to store the coordinates. This can be + * used to allocate storage, before the actual coordinates + * are calculated. */ + return 1 + numPoints * numSteps; + } + outputPoints = 0; if ((pointPtr[0] == pointPtr[numCoords-2]) && (pointPtr[1] == pointPtr[numCoords-1])) { diff --git a/generic/tkUtil.c b/generic/tkUtil.c index 226fd86..0ba1f96 100644 --- a/generic/tkUtil.c +++ b/generic/tkUtil.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUtil.c,v 1.6 1999/08/10 05:10:52 jingham Exp $ + * RCS: @(#) $Id: tkUtil.c,v 1.7 1999/12/14 06:52:34 hobbs Exp $ */ #include "tkInt.h" @@ -32,6 +32,487 @@ static Tcl_ObjType stateKeyType = { /* + *-------------------------------------------------------------- + * + * TkStateParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-state" and "-default" options. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The state for a given item gets replaced by the state + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkStateParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + int flags = (int)clientData; + size_t length; + + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *statePtr = TK_STATE_NULL; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'n') && (strncmp(value, "normal", length) == 0)) { + *statePtr = TK_STATE_NORMAL; + return TCL_OK; + } + if ((c == 'd') && (strncmp(value, "disabled", length) == 0)) { + *statePtr = TK_STATE_DISABLED; + return TCL_OK; + } + if ((c == 'a') && (flags&1) && (strncmp(value, "active", length) == 0)) { + *statePtr = TK_STATE_ACTIVE; + return TCL_OK; + } + if ((c == 'h') && (flags&2) && (strncmp(value, "hidden", length) == 0)) { + *statePtr = TK_STATE_HIDDEN; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad ", (flags&4)?"-default" : "state", + " value \"", value, "\": must be normal", + (char *) NULL); + if (flags&1) { + Tcl_AppendResult(interp, ", active",(char *) NULL); + } + if (flags&2) { + Tcl_AppendResult(interp, ", hidden",(char *) NULL); + } + if (flags&3) { + Tcl_AppendResult(interp, ",",(char *) NULL); + } + Tcl_AppendResult(interp, " or disabled",(char *) NULL); + *statePtr = TK_STATE_NORMAL; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkStatePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-state" + * configuration option. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkStatePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if (*statePtr==TK_STATE_NORMAL) { + return "normal"; + } else if (*statePtr==TK_STATE_DISABLED) { + return "disabled"; + } else if (*statePtr==TK_STATE_HIDDEN) { + return "hidden"; + } else if (*statePtr==TK_STATE_ACTIVE) { + return "active"; + } else { + return ""; + } +} + +/* + *-------------------------------------------------------------- + * + * TkOrientParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-orient" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The orientation for a given item gets replaced by the orientation + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkOrientParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register int *orientPtr = (int *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *orientPtr = 0; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'h') && (strncmp(value, "horizontal", length) == 0)) { + *orientPtr = 0; + return TCL_OK; + } + if ((c == 'v') && (strncmp(value, "vertical", length) == 0)) { + *orientPtr = 1; + return TCL_OK; + } + Tcl_AppendResult(interp, "bad orientation \"", value, + "\": must be vertical or horizontal", + (char *) NULL); + *orientPtr = 0; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkOrientPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-orient" + * configuration option. + * + * Results: + * The return value is a string describing the orientation for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkOrientPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register int *statePtr = (int *) (widgRec + offset); + + if (*statePtr) { + return "vertical"; + } else { + return "horizontal"; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkOffsetParseProc -- + * + * Converts the offset of a stipple or tile into the Tk_TSOffset structure. + * + *---------------------------------------------------------------------- + */ + +int +TkOffsetParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* not used */ + Tcl_Interp *interp; /* Interpreter to send results back to */ + Tk_Window tkwin; /* Window on same display as tile */ + CONST char *value; /* Name of image */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ +{ + Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset); + Tk_TSOffset tsoffset; + CONST char *q, *p; + int result; + + if ((value == NULL) || (*value == 0)) { + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + tsoffset.flags = 0; + p = value; + + switch(value[0]) { + case '#': + if (((int)clientData) & TK_OFFSET_RELATIVE) { + tsoffset.flags = TK_OFFSET_RELATIVE; + p++; break; + } + goto badTSOffset; + case 'e': + switch(value[1]) { + case '\0': + tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if (value[2]!='d' || value[3]!='\0') {goto badTSOffset;} + tsoffset.flags = INT_MAX; + goto goodTSOffset; + } + case 'w': + if (value[1] != '\0') {goto badTSOffset;} + tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_TOP; + goto goodTSOffset; + case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_TOP; + goto goodTSOffset; + case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_TOP; + goto goodTSOffset; + } + goto badTSOffset; + case 's': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + } + goto badTSOffset; + case 'c': + if (strncmp(value, "center", strlen(value)) != 0) { + goto badTSOffset; + } + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + if ((q = strchr(p,',')) == NULL) { + if (((int)clientData) & TK_OFFSET_INDEX) { + if (Tcl_GetInt(interp, (char *) p, &tsoffset.flags) != TCL_OK) { + Tcl_ResetResult(interp); + goto badTSOffset; + } + tsoffset.flags |= TK_OFFSET_INDEX; + goto goodTSOffset; + } + goto badTSOffset; + } + *((char *) q) = 0; + result = Tk_GetPixels(interp, tkwin, (char *) p, &tsoffset.xoffset); + *((char *) q) = ','; + if (result != TCL_OK) { + return TCL_ERROR; + } + if (Tk_GetPixels(interp, tkwin, (char *) q+1, &tsoffset.yoffset) != TCL_OK) { + return TCL_ERROR; + } + + +goodTSOffset: + /* below is a hack to allow the stipple/tile offset to be stored + * in the internal tile structure. Most of the times, offsetPtr + * is a pointer to an already existing tile structure. However + * if this structure is not already created, we must do it + * with Tk_GetTile()!!!!; + */ + + memcpy(offsetPtr,&tsoffset, sizeof(Tk_TSOffset)); + return TCL_OK; + +badTSOffset: + Tcl_AppendResult(interp, "bad offset \"", value, + "\": expected \"x,y\"", (char *) NULL); + if (((int) clientData) & TK_OFFSET_RELATIVE) { + Tcl_AppendResult(interp, ", \"#x,y\"", (char *) NULL); + } + if (((int) clientData) & TK_OFFSET_INDEX) { + Tcl_AppendResult(interp, ", <index>", (char *) NULL); + } + Tcl_AppendResult(interp, ", n, ne, e, se, s, sw, w, nw, or center", + (char *) NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TkOffsetPrintProc -- + * + * Returns the offset of the tile. + * + * Results: + * The offset of the tile is returned. + * + *---------------------------------------------------------------------- + */ + +char * +TkOffsetPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* not used */ + Tk_Window tkwin; /* not used */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ + Tcl_FreeProc **freeProcPtr; /* not used */ +{ + Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset); + char *p, *q; + + if ((offsetPtr->flags) & TK_OFFSET_INDEX) { + if ((offsetPtr->flags) >= INT_MAX) { + return "end"; + } + p = (char *) ckalloc(32); + sprintf(p, "%d",(offsetPtr->flags & (~TK_OFFSET_INDEX))); + *freeProcPtr = TCL_DYNAMIC; + return p; + } + if ((offsetPtr->flags) & TK_OFFSET_TOP) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "nw"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "n"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "ne"; + } + } else if ((offsetPtr->flags) & TK_OFFSET_MIDDLE) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "w"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "center"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "e"; + } + } else if ((offsetPtr->flags) & TK_OFFSET_BOTTOM) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "sw"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "s"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "se"; + } + } + q = p = (char *) ckalloc(32); + if ((offsetPtr->flags) & TK_OFFSET_RELATIVE) { + *q++ = '#'; + } + sprintf(q, "%d,%d",offsetPtr->xoffset, offsetPtr->yoffset); + *freeProcPtr = TCL_DYNAMIC; + return p; +} + + +/* + *---------------------------------------------------------------------- + * + * TkPixelParseProc -- + * + * Converts the name of an image into a tile. + * + *---------------------------------------------------------------------- + */ + +int +TkPixelParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* if non-NULL, negative values are + * allowed as well */ + Tcl_Interp *interp; /* Interpreter to send results back to */ + Tk_Window tkwin; /* Window on same display as tile */ + CONST char *value; /* Name of image */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ +{ + double *doublePtr = (double *)(widgRec + offset); + int result; + + result = TkGetDoublePixels(interp, tkwin, value, doublePtr); + + if ((result == TCL_OK) && (clientData == NULL) && (*doublePtr < 0.0)) { + Tcl_AppendResult(interp, "bad screen distance \"", value, + "\"", (char *) NULL); + return TCL_ERROR; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkPixelPrintProc -- + * + * Returns the name of the tile. + * + * Results: + * The name of the tile is returned. + * + *---------------------------------------------------------------------- + */ + +char * +TkPixelPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* not used */ + Tk_Window tkwin; /* not used */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ + Tcl_FreeProc **freeProcPtr; /* not used */ +{ + double *doublePtr = (double *)(widgRec + offset); + char *p; + + p = (char *) ckalloc(24); + Tcl_PrintDouble((Tcl_Interp *) NULL, *doublePtr, p); + *freeProcPtr = TCL_DYNAMIC; + return p; +} + +/* *---------------------------------------------------------------------- * * TkDrawInsetFocusHighlight -- diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 7e4d5fc..4686cb3 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWindow.c,v 1.12 1999/12/03 07:14:39 hobbs Exp $ + * RCS: @(#) $Id: tkWindow.c,v 1.13 1999/12/14 06:52:34 hobbs Exp $ */ #include "tkPort.h" @@ -134,10 +134,10 @@ static TkCmd commands[] = { */ {"button", NULL, Tk_ButtonObjCmd, 1, 0}, - {"canvas", Tk_CanvasCmd, NULL, 1, 1}, + {"canvas", NULL, Tk_CanvasObjCmd, 1, 1}, {"checkbutton", NULL, Tk_CheckbuttonObjCmd, 1, 0}, {"entry", NULL, Tk_EntryObjCmd, 1, 0}, - {"frame", Tk_FrameCmd, NULL, 1, 1}, + {"frame", NULL, Tk_FrameObjCmd, 1, 1}, {"label", NULL, Tk_LabelObjCmd, 1, 0}, {"listbox", NULL, Tk_ListboxObjCmd, 1, 0}, {"menubutton", NULL, Tk_MenubuttonObjCmd, 1, 0}, @@ -146,7 +146,7 @@ static TkCmd commands[] = { {"scale", NULL, Tk_ScaleObjCmd, 1, 0}, {"scrollbar", Tk_ScrollbarCmd, NULL, 1, 1}, {"text", Tk_TextCmd, NULL, 1, 1}, - {"toplevel", Tk_ToplevelCmd, NULL, 0, 1}, + {"toplevel", NULL, Tk_ToplevelObjCmd, 0, 1}, /* * Misc. @@ -431,6 +431,11 @@ GetScreen(interp, screenName, screenPtr) dispPtr->firstGrabEventPtr = NULL; dispPtr->lastGrabEventPtr = NULL; dispPtr->grabFlags = 0; + dispPtr->mouseButtonState = 0; + dispPtr->warpInProgress = 0; + dispPtr->warpWindow = None; + dispPtr->warpX = 0; + dispPtr->warpY = 0; dispPtr->gridInit = 0; dispPtr->imageId = 0; dispPtr->packInit = 0; |