diff options
author | hobbs <hobbs> | 1999-12-14 06:52:24 (GMT) |
---|---|---|
committer | hobbs <hobbs> | 1999-12-14 06:52:24 (GMT) |
commit | b6b6ff8f0eee42e270a45b019789faa444ed4dad (patch) | |
tree | 5b5ddecf0f3677601c5511eaded466191ef3ba8a /generic | |
parent | 9b37fa05b11850066aed28ed447109e55708bce0 (diff) | |
download | tk-b6b6ff8f0eee42e270a45b019789faa444ed4dad.zip tk-b6b6ff8f0eee42e270a45b019789faa444ed4dad.tar.gz tk-b6b6ff8f0eee42e270a45b019789faa444ed4dad.tar.bz2 |
* generic/tkStubInit.c:
* generic/tkDecls.h:
* generic/tkIntXlibDecls.h:
* generic/tkInt.decls: added XSetDashes and XWarpPointer
* generic/tk.decls: added Tk_CreateSmoothMethod, and reserved
two spots
* generic/tk.h: added Tk_SmoothMethod struct,
state item to canvas record, #defines for item state,
support for using old char*-based canvas item C creation
procedures with -DUSE_OLD_CANVAS,
Tk_Dash, Tk_TSOffset (-offsets) & Tk_Outline structs and #defs,
decls for dash, outline and postscript routines
* generic/tkBind.c: added support for Quadruple clicks, and added
the -warp option to 'event' with pointer warping routines
* xlib/xgc.c:
* generic/tkRectOval.c:
* generic/tkCanvArc.c:
* generic/tkCanvBmap.c:
* generic/tkCanvImg.c:
* generic/tkCanvLine.c:
* generic/tkCanvPoly.c:
* generic/tkCanvPs.c:
* generic/tkCanvText.c:
* generic/tkCanvUtil.c:
* generic/tkCanvWind.c:
* generic/tkCanvas.c:
* generic/tkCanvas.h: Canvas and items received overhaul to with
the addition of the dash patch (Nijtmans, et al) This includes
objectification of the 'canvas' command, as well as support for
(where appropriate) dashes in items, extended stipple support,
state for all items, and postscript generation of images and
windows. See the new canvas man page for related docs.
* generic/tkEntry.c: added entry widget validation, see entry.n
* generic/tkEvent.c: on simulated events, ButtonPress should
be matched with ButtonRelease to be correct
* generic/tkFont.c: corrected possible null reference
* generic/tkFrame.c: made frame a Tcl_Obj based command
* generic/tkGet.c: added TkGetDoublePixels
* generic/tkImage.c: bug fixes from Img patch and new
Tk_PostscriptImage and Tk_SetTSOrigin functions
* generic/tkImgBmap.c: new ImgBmapPostscript function
* generic/tkImgPhoto.c: new Tk_CreatePhotoOption, Tk_DitherPhoto
* generic/tkInt.h: declarations for some new functions
* generic/tkMessage.c: reworked relief drawing
* generic/tkOldConfig.c: added TK_CONFIG_OBJS so old style
ConfigureWidget calls can pass in Tcl_Obj arrays
* generic/tkScrollbar.c:
* generic/tkScrollbar.h: made -orient use an option table
* generic/tkText.c:
* generic/tkText.h: made -wrap and -state use option tables
* generic/tkTextBTree.c:
* generic/tkTextDisp.c:
* generic/tkTextImage.c:
* generic/tkTextMark.c:
* generic/tkTextTag.c:
* generic/tkTextWind.c: added support for -elide and -state hidden
* generic/tkTrig.c: changed TkMakeBezierCurve to support returning
the upper limit of points needed for spline
* generic/tkUtil.c: new option table parsing routines
* generic/tkWindow.c: init'ing of warp stuff, mouseButtonState
Diffstat (limited to 'generic')
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; |