#include "tkInt.h"
#include "tkCanvas.h"
#include "tkDefault.h"
typedef struct TagSearch {
TkCanvas *canvasPtr;
Tk_Uid tag;
Tk_Item *prevPtr;
Tk_Item *currentPtr;
int searchOver;
} TagSearch;
static Tk_ConfigSpec configSpecs[] = {
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},
{TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},
{TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},
{TK_CONFIG_PIXELS, "-height", "height", "Height",
DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},
{TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
"HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
Tk_Offset(TkCanvas, highlightBgColorPtr), 0},
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},
{TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
"HighlightThickness",
DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},
{TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
DEF_CANVAS_INSERT_BD_COLOR,
Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
DEF_CANVAS_INSERT_BD_MONO,
Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},
{TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},
{TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
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_RELIEF, "-relief", "relief", "Relief",
DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},
{TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
TK_CONFIG_NULL_OK},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
DEF_CANVAS_SELECT_BD_COLOR,
Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
TK_CONFIG_NULL_OK},
{TK_CONFIG_PIXELS, "-width", "width", "Width",
DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},
{TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
TK_CONFIG_NULL_OK},
{TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
"ScrollIncrement",
DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
0},
{TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
TK_CONFIG_NULL_OK},
{TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
"ScrollIncrement",
DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
0},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
static Tk_ItemType *typeList = NULL;
extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;
extern Tk_ItemType tkOvalType, tkPolygonType;
extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
static Tk_Uid allUid = NULL;
static Tk_Uid currentUid = NULL;
static int numIdSearches;
static int numSlowSearches;
static void CanvasBindProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static void CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
static void CanvasCmdDeletedProc _ANSI_ARGS_((
ClientData clientData));
static void CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,
XEvent *eventPtr));
static void CanvasEventProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static int CanvasFetchSelection _ANSI_ARGS_((
ClientData clientData, int offset,
char *buffer, int maxBytes));
static Tk_Item * CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,
double coords[2]));
static void CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,
int gotFocus));
static void CanvasLostSelection _ANSI_ARGS_((
ClientData clientData));
static void CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,
Tk_Item *itemPtr, int index));
static void CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,
int xOrigin, int yOrigin));
static void CanvasUpdateScrollbars _ANSI_ARGS_((
TkCanvas *canvasPtr));
static int CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int argc, char **argv));
static int ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
TkCanvas *canvasPtr, int argc, char **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 int FindItems _ANSI_ARGS_((Tcl_Interp *interp,
TkCanvas *canvasPtr, int argc, char **argv,
char *newTag, char *cmdName, char *option));
static int FindArea _ANSI_ARGS_((Tcl_Interp *interp,
TkCanvas *canvasPtr, char **argv, Tk_Uid uid,
int enclosed));
static double GridAlign _ANSI_ARGS_((double coord, double spacing));
static void InitCanvas _ANSI_ARGS_((void));
static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr));
static void PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,
XEvent *eventPtr));
static void PrintScrollFractions _ANSI_ARGS_((int screen1,
int screen2, int object1, int object2,
char *string));
static void RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
char *tag, Tk_Item *prevPtr));
static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
char *tag, TagSearch *searchPtr));
int
Tk_CanvasCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
Tk_Window tkwin = (Tk_Window) clientData;
TkCanvas *canvasPtr;
Tk_Window new;
if (typeList == NULL) {
InitCanvas();
}
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " pathName ?options?\"", (char *) NULL);
return TCL_ERROR;
}
new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
if (new == NULL) {
return TCL_ERROR;
}
canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));
canvasPtr->tkwin = new;
canvasPtr->display = Tk_Display(new);
canvasPtr->interp = interp;
canvasPtr->widgetCmd = Tcl_CreateCommand(interp,
Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
(ClientData) canvasPtr, CanvasCmdDeletedProc);
canvasPtr->firstItemPtr = NULL;
canvasPtr->lastItemPtr = NULL;
canvasPtr->borderWidth = 0;
canvasPtr->bgBorder = NULL;
canvasPtr->relief = TK_RELIEF_FLAT;
canvasPtr->highlightWidth = 0;
canvasPtr->highlightBgColorPtr = NULL;
canvasPtr->highlightColorPtr = NULL;
canvasPtr->inset = 0;
canvasPtr->pixmapGC = None;
canvasPtr->width = None;
canvasPtr->height = None;
canvasPtr->confine = 0;
canvasPtr->textInfo.selBorder = NULL;
canvasPtr->textInfo.selBorderWidth = 0;
canvasPtr->textInfo.selFgColorPtr = NULL;
canvasPtr->textInfo.selItemPtr = NULL;
canvasPtr->textInfo.selectFirst = -1;
canvasPtr->textInfo.selectLast = -1;
canvasPtr->textInfo.anchorItemPtr = NULL;
canvasPtr->textInfo.selectAnchor = 0;
canvasPtr->textInfo.insertBorder = NULL;
canvasPtr->textInfo.insertWidth = 0;
canvasPtr->textInfo.insertBorderWidth = 0;
canvasPtr->textInfo.focusItemPtr = NULL;
canvasPtr->textInfo.gotFocus = 0;
canvasPtr->textInfo.cursorOn = 0;
canvasPtr->insertOnTime = 0;
canvasPtr->insertOffTime = 0;
canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
canvasPtr->bindingTable = NULL;
canvasPtr->currentItemPtr = NULL;
canvasPtr->newCurrentPtr = NULL;
canvasPtr->closeEnough = 0.0;
canvasPtr->pickEvent.type = LeaveNotify;
canvasPtr->pickEvent.xcrossing.x = 0;
canvasPtr->pickEvent.xcrossing.y = 0;
canvasPtr->state = 0;
canvasPtr->xScrollCmd = NULL;
canvasPtr->yScrollCmd = NULL;
canvasPtr->scrollX1 = 0;
canvasPtr->scrollY1 = 0;
canvasPtr->scrollX2 = 0;
canvasPtr->scrollY2 = 0;
canvasPtr->regionString = NULL;
canvasPtr->xScrollIncrement = 0;
canvasPtr->yScrollIncrement = 0;
canvasPtr->scanX = 0;
canvasPtr->scanXOrigin = 0;
canvasPtr->scanY = 0;
canvasPtr->scanYOrigin = 0;
canvasPtr->hotPtr = NULL;
canvasPtr->hotPrevPtr = NULL;
canvasPtr->cursor = None;
canvasPtr->takeFocus = NULL;
canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
canvasPtr->flags = 0;
canvasPtr->nextId = 1;
canvasPtr->psInfoPtr = NULL;
Tk_SetClass(canvasPtr->tkwin, "Canvas");
Tk_CreateEventHandler(canvasPtr->tkwin,
ExposureMask|StructureNotifyMask|FocusChangeMask,
CanvasEventProc, (ClientData) canvasPtr);
Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
|ButtonPressMask|ButtonReleaseMask|EnterWindowMask
|LeaveWindowMask|PointerMotionMask, CanvasBindProc,
(ClientData) canvasPtr);
Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
goto error;
}
interp->result = Tk_PathName(canvasPtr->tkwin);
return TCL_OK;
error:
Tk_DestroyWindow(canvasPtr->tkwin);
return TCL_ERROR;
}
static int
CanvasWidgetCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
size_t length;
int c, result;
Tk_Item *itemPtr = NULL;
TagSearch search;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " option ?arg arg ...?\"", (char *) NULL);
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)) {
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)) {
int i, gotAny;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " bbox tagOrId ?tagOrId ...?\"",
(char *) NULL);
goto error;
}
gotAny = 0;
for (i = 2; i < argc; i++) {
for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
if ((itemPtr->x1 >= itemPtr->x2)
|| (itemPtr->y1 >= itemPtr->y2)) {
continue;
}
if (!gotAny) {
x1 = itemPtr->x1;
y1 = itemPtr->y1;
x2 = itemPtr->x2;
y2 = itemPtr->y2;
gotAny = 1;
} else {
if (itemPtr->x1 < x1) {
x1 = itemPtr->x1;
}
if (itemPtr->y1 < y1) {
y1 = itemPtr->y1;
}
if (itemPtr->x2 > x2) {
x2 = itemPtr->x2;
}
if (itemPtr->y2 > y2) {
y2 = itemPtr->y2;
}
}
}
}
if (gotAny) {
sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2);
}
} else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)
&& (length >= 2)) {
ClientData object;
if ((argc < 3) || (argc > 5)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " bind tagOrId ?sequence? ?command?\"",
(char *) NULL);
goto error;
}
object = 0;
if (isdigit(UCHAR(argv[2][0]))) {
int id;
char *end;
id = strtoul(argv[2], &end, 0);
if (*end != 0) {
goto bindByTag;
}
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
if (itemPtr->id == id) {
object = (ClientData) itemPtr;
break;
}
}
if (object == 0) {
Tcl_AppendResult(interp, "item \"", argv[2],
"\" doesn't exist", (char *) NULL);
goto error;
}
} else {
bindByTag:
object = (ClientData) Tk_GetUid(argv[2]);
}
if (canvasPtr->bindingTable == NULL) {
canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
}
if (argc == 5) {
int append = 0;
unsigned long mask;
if (argv[4][0] == 0) {
result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
object, argv[3]);
goto done;
}
if (argv[4][0] == '+') {
argv[4]++;
append = 1;
}
mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
object, argv[3], argv[4], append);
if (mask == 0) {
goto error;
}
if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
|Button2MotionMask|Button3MotionMask|Button4MotionMask
|Button5MotionMask|ButtonPressMask|ButtonReleaseMask
|EnterWindowMask|LeaveWindowMask|KeyPressMask
|KeyReleaseMask|PointerMotionMask)) {
Tk_DeleteBinding(interp, canvasPtr->bindingTable,
object, argv[3]);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "requested illegal events; ",
"only key, button, motion, and enter/leave ",
"events may be used", (char *) NULL);
goto error;
}
} else if (argc == 4) {
char *command;
command = Tk_GetBinding(interp, canvasPtr->bindingTable,
object, argv[3]);
if (command == NULL) {
goto error;
}
interp->result = command;
} else {
Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
}
} else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) {
int x;
double grid;
if ((argc < 3) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " canvasx screenx ?gridspacing?\"",
(char *) NULL);
goto error;
}
if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {
goto error;
}
if (argc == 4) {
if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
&grid) != TCL_OK) {
goto error;
}
} else {
grid = 0.0;
}
x += canvasPtr->xOrigin;
Tcl_PrintDouble(interp, GridAlign((double) x, grid), interp->result);
} else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) {
int y;
double grid;
if ((argc < 3) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " canvasy screeny ?gridspacing?\"",
(char *) NULL);
goto error;
}
if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {
goto error;
}
if (argc == 4) {
if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
argv[3], &grid) != TCL_OK) {
goto error;
}
} else {
grid = 0.0;
}
y += canvasPtr->yOrigin;
Tcl_PrintDouble(interp, GridAlign((double) y, grid), interp->result);
} else 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);
goto error;
}
result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
(char *) canvasPtr, argv[2], 0);
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
&& (length >= 3)) {
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);
} else {
result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,
TK_CONFIG_ARGV_ONLY);
}
} else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)
&& (length >= 3)) {
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " coords tagOrId ?x y x y ...?\"",
(char *) NULL);
goto error;
}
itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
if (itemPtr != NULL) {
if (argc != 3) {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
if (itemPtr->typePtr->coordProc != NULL) {
result = (*itemPtr->typePtr->coordProc)(interp,
(Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
}
if (argc != 3) {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
}
} else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)
&& (length >= 2)) {
Tk_ItemType *typePtr;
Tk_ItemType *matchPtr = NULL;
Tk_Item *itemPtr;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " create type ?arg arg ...?\"", (char *) NULL);
goto error;
}
c = argv[2][0];
length = strlen(argv[2]);
for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
if ((c == typePtr->name[0])
&& (strncmp(argv[2], typePtr->name, length) == 0)) {
if (matchPtr != NULL) {
badType:
Tcl_AppendResult(interp,
"unknown or ambiguous item type \"",
argv[2], "\"", (char *) NULL);
goto error;
}
matchPtr = typePtr;
}
}
if (matchPtr == NULL) {
goto badType;
}
typePtr = matchPtr;
itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
itemPtr->id = canvasPtr->nextId;
canvasPtr->nextId++;
itemPtr->tagPtr = itemPtr->staticTagSpace;
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) {
ckfree((char *) itemPtr);
goto error;
}
itemPtr->nextPtr = NULL;
canvasPtr->hotPtr = itemPtr;
canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
if (canvasPtr->lastItemPtr == NULL) {
canvasPtr->firstItemPtr = itemPtr;
} else {
canvasPtr->lastItemPtr->nextPtr = itemPtr;
}
canvasPtr->lastItemPtr = itemPtr;
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
canvasPtr->flags |= REPICK_NEEDED;
sprintf(interp->result, "%d", itemPtr->id);
} else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0)
&& (length >= 2)) {
int first, last;
if ((argc != 4) && (argc != 5)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " dchars tagOrId first ?last?\"",
(char *) NULL);
goto error;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&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 (argc == 5) {
if ((*itemPtr->typePtr->indexProc)(interp,
(Tk_Canvas) canvasPtr, itemPtr, argv[4], &last)
!= TCL_OK) {
goto error;
}
} else {
last = first;
}
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
(*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
itemPtr, first, last);
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
} else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)
&& (length >= 2)) {
int i;
for (i = 2; i < argc; i++) {
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);
if (canvasPtr->bindingTable != NULL) {
Tk_DeleteAllBindings(canvasPtr->bindingTable,
(ClientData) itemPtr);
}
(*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
canvasPtr->display);
if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
ckfree((char *) itemPtr->tagPtr);
}
if (search.prevPtr == NULL) {
canvasPtr->firstItemPtr = itemPtr->nextPtr;
if (canvasPtr->firstItemPtr == NULL) {
canvasPtr->lastItemPtr = NULL;
}
} else {
search.prevPtr->nextPtr = itemPtr->nextPtr;
}
if (canvasPtr->lastItemPtr == itemPtr) {
canvasPtr->lastItemPtr = search.prevPtr;
}
ckfree((char *) itemPtr);
if (itemPtr == canvasPtr->currentItemPtr) {
canvasPtr->currentItemPtr = NULL;
canvasPtr->flags |= REPICK_NEEDED;
}
if (itemPtr == canvasPtr->newCurrentPtr) {
canvasPtr->newCurrentPtr = NULL;
canvasPtr->flags |= REPICK_NEEDED;
}
if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
canvasPtr->textInfo.focusItemPtr = NULL;
}
if (itemPtr == canvasPtr->textInfo.selItemPtr) {
canvasPtr->textInfo.selItemPtr = NULL;
}
if ((itemPtr == canvasPtr->hotPtr)
|| (itemPtr == canvasPtr->hotPrevPtr)) {
canvasPtr->hotPtr = NULL;
}
}
}
} else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0)
&& (length >= 2)) {
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;
}
if (argc == 4) {
tag = Tk_GetUid(argv[3]);
} else {
tag = Tk_GetUid(argv[2]);
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
for (i = itemPtr->numTags-1; i >= 0; i--) {
if (itemPtr->tagPtr[i] == tag) {
itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
itemPtr->numTags--;
}
}
}
} else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)
&& (length >= 2)) {
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)) {
if (argc > 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " focus ?tagOrId?\"",
(char *) NULL);
goto error;
}
itemPtr = canvasPtr->textInfo.focusItemPtr;
if (argc == 2) {
if (itemPtr != NULL) {
sprintf(interp->result, "%d", itemPtr->id);
}
goto done;
}
if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
if (argv[2][0] == 0) {
canvasPtr->textInfo.focusItemPtr = NULL;
goto done;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
if (itemPtr->typePtr->icursorProc != NULL) {
break;
}
}
if (itemPtr == NULL) {
goto done;
}
canvasPtr->textInfo.focusItemPtr = itemPtr;
if (canvasPtr->textInfo.gotFocus) {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
} else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " gettags tagOrId\"", (char *) NULL);
goto error;
}
itemPtr = StartTagSearch(canvasPtr, argv[2], &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)) {
int index;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " icursor tagOrId index\"",
(char *) NULL);
goto error;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&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;
}
(*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);
}
}
} else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
&& (length >= 3)) {
int index;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " index tagOrId string\"",
(char *) NULL);
goto error;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&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;
}
if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
itemPtr, argv[3], &index) != TCL_OK) {
goto error;
}
sprintf(interp->result, "%d", index);
} else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
&& (length >= 3)) {
int beforeThis;
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " insert tagOrId beforeThis string\"",
(char *) NULL);
goto error;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&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;
}
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);
}
} else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0)
&& (length >= 6)) {
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " itemcget tagOrId option\"",
(char *) NULL);
return TCL_ERROR;
}
itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
if (itemPtr != NULL) {
result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
itemPtr->typePtr->configSpecs, (char *) itemPtr,
argv[3], 0);
}
} else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0)
&& (length >= 6)) {
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " itemconfigure tagOrId ?option value ...?\"",
(char *) NULL);
goto error;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
if (argc == 3) {
result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
itemPtr->typePtr->configSpecs, (char *) itemPtr,
(char *) NULL, 0);
} else if (argc == 4) {
result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
itemPtr->typePtr->configSpecs, (char *) itemPtr,
argv[3], 0);
} else {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
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);
canvasPtr->flags |= REPICK_NEEDED;
}
if ((result != TCL_OK) || (argc < 5)) {
break;
}
}
} else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) {
Tk_Item *prevPtr;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " lower tagOrId ?belowThis?\"",
(char *) NULL);
goto error;
}
if (argc == 3) {
prevPtr = NULL;
} else {
prevPtr = StartTagSearch(canvasPtr, argv[3], &search);
if (prevPtr != NULL) {
prevPtr = search.prevPtr;
} else {
Tcl_AppendResult(interp, "tag \"", argv[3],
"\" doesn't match any items", (char *) NULL);
goto error;
}
}
RelinkItems(canvasPtr, argv[2], prevPtr);
} else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) {
double xAmount, yAmount;
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " move tagOrId xAmount yAmount\"",
(char *) NULL);
goto error;
}
if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
&xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp,
(Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) {
goto error;
}
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);
(void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
itemPtr, xAmount, yAmount);
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
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)) {
Tk_Item *prevPtr;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " raise tagOrId ?aboveThis?\"",
(char *) NULL);
goto error;
}
if (argc == 3) {
prevPtr = canvasPtr->lastItemPtr;
} else {
prevPtr = NULL;
for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
prevPtr = itemPtr;
}
if (prevPtr == NULL) {
Tcl_AppendResult(interp, "tagOrId \"", argv[3],
"\" doesn't match any items", (char *) NULL);
goto error;
}
}
RelinkItems(canvasPtr, argv[2], prevPtr);
} else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)
&& (length >= 3)) {
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;
}
if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
argv[3], &xOrigin) != TCL_OK)
|| (Tk_CanvasGetCoord(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;
}
if ((xScale == 0.0) || (yScale == 0.0)) {
interp->result = "scale factor cannot be zero";
goto error;
}
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);
(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);
canvasPtr->flags |= REPICK_NEEDED;
}
} else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0)
&& (length >= 3)) {
int x, y;
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " scan mark|dragto x y\"", (char *) NULL);
goto error;
}
if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
goto error;
}
if ((argv[2][0] == 'm')
&& (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
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)) {
int newXOrigin, newYOrigin, tmp;
tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX)
- canvasPtr->scrollX1;
newXOrigin = canvasPtr->scrollX1 + tmp;
tmp = canvasPtr->scanYOrigin - 10*(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;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL);
goto error;
}
if (argc >= 4) {
for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
if ((itemPtr->typePtr->indexProc != NULL)
&& (itemPtr->typePtr->selectionProc != NULL)){
break;
}
}
if (itemPtr == NULL) {
Tcl_AppendResult(interp,
"can't find an indexable and selectable item \"",
argv[3], "\"", (char *) NULL);
goto error;
}
}
if (argc == 5) {
if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
itemPtr, argv[4], &index) != TCL_OK) {
goto error;
}
}
length = strlen(argv[2]);
c = argv[2][0];
if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select adjust tagOrId index\"",
(char *) NULL);
goto error;
}
if (canvasPtr->textInfo.selItemPtr == itemPtr) {
if (index < (canvasPtr->textInfo.selectFirst
+ canvasPtr->textInfo.selectLast)/2) {
canvasPtr->textInfo.selectAnchor =
canvasPtr->textInfo.selectLast + 1;
} else {
canvasPtr->textInfo.selectAnchor =
canvasPtr->textInfo.selectFirst;
}
}
CanvasSelectTo(canvasPtr, itemPtr, index);
} else if ((c == 'c') && (argv[2] != NULL)
&& (strncmp(argv[2], "clear", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select clear\"", (char *) NULL);
goto error;
}
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);
canvasPtr->textInfo.selItemPtr = NULL;
}
goto done;
} else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select from tagOrId index\"",
(char *) NULL);
goto error;
}
canvasPtr->textInfo.anchorItemPtr = itemPtr;
canvasPtr->textInfo.selectAnchor = index;
} else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select item\"", (char *) NULL);
goto error;
}
if (canvasPtr->textInfo.selItemPtr != NULL) {
sprintf(interp->result, "%d",
canvasPtr->textInfo.selItemPtr->id);
}
} else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select to tagOrId index\"",
(char *) NULL);
goto error;
}
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;
}
} else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " type tag\"", (char *) NULL);
goto error;
}
itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
if (itemPtr != NULL) {
interp->result = itemPtr->typePtr->name;
}
} else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
int count, type;
int newX = 0;
double fraction;
if (argc == 2) {
PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset,
canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
- canvasPtr->inset, canvasPtr->scrollX1,
canvasPtr->scrollX2, interp->result);
} else {
type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
switch (type) {
case TK_SCROLL_ERROR:
goto error;
case TK_SCROLL_MOVETO:
newX = canvasPtr->scrollX1 - canvasPtr->inset
+ (int) (fraction * (canvasPtr->scrollX2
- canvasPtr->scrollX1) + 0.5);
break;
case TK_SCROLL_PAGES:
newX = canvasPtr->xOrigin + count * .9
* (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset);
break;
case TK_SCROLL_UNITS:
if (canvasPtr->xScrollIncrement > 0) {
newX = canvasPtr->xOrigin
+ count*canvasPtr->xScrollIncrement;
} else {
newX = canvasPtr->xOrigin + count * .1
* (Tk_Width(canvasPtr->tkwin)
- 2*canvasPtr->inset);
}
break;
}
CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
}
} else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) {
int count, type;
int newY = 0;
double fraction;
if (argc == 2) {
PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset,
canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
- canvasPtr->inset, canvasPtr->scrollY1,
canvasPtr->scrollY2, interp->result);
} else {
type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
switch (type) {
case TK_SCROLL_ERROR:
goto error;
case TK_SCROLL_MOVETO:
newY = canvasPtr->scrollY1 - canvasPtr->inset
+ (int) (fraction*(canvasPtr->scrollY2
- canvasPtr->scrollY1) + 0.5);
break;
case TK_SCROLL_PAGES:
newY = canvasPtr->yOrigin + count * .9
* (Tk_Height(canvasPtr->tkwin)
- 2*canvasPtr->inset);
break;
case TK_SCROLL_UNITS:
if (canvasPtr->yScrollIncrement > 0) {
newY = canvasPtr->yOrigin
+ count*canvasPtr->yScrollIncrement;
} else {
newY = canvasPtr->yOrigin + count * .1
* (Tk_Height(canvasPtr->tkwin)
- 2*canvasPtr->inset);
}
break;
}
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;
}
done:
Tcl_Release((ClientData) canvasPtr);
return result;
error:
Tcl_Release((ClientData) canvasPtr);
return TCL_ERROR;
}
static void
DestroyCanvas(memPtr)
char *memPtr;
{
TkCanvas *canvasPtr = (TkCanvas *) memPtr;
Tk_Item *itemPtr;
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = canvasPtr->firstItemPtr) {
canvasPtr->firstItemPtr = itemPtr->nextPtr;
(*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
canvasPtr->display);
if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
ckfree((char *) itemPtr->tagPtr);
}
ckfree((char *) itemPtr);
}
if (canvasPtr->pixmapGC != None) {
Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
}
Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
if (canvasPtr->bindingTable != NULL) {
Tk_DeleteBindingTable(canvasPtr->bindingTable);
}
Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
ckfree((char *) canvasPtr);
}
static int
ConfigureCanvas(interp, canvasPtr, argc, argv, flags)
Tcl_Interp *interp;
TkCanvas *canvasPtr;
int argc;
char **argv;
int flags;
{
XGCValues gcValues;
GC new;
if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
argc, argv, (char *) canvasPtr, flags) != TCL_OK) {
return TCL_ERROR;
}
Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
if (canvasPtr->highlightWidth < 0) {
canvasPtr->highlightWidth = 0;
}
canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
gcValues.function = GXcopy;
gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
gcValues.graphics_exposures = False;
new = Tk_GetGC(canvasPtr->tkwin,
GCFunction|GCForeground|GCGraphicsExposures, &gcValues);
if (canvasPtr->pixmapGC != None) {
Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
}
canvasPtr->pixmapGC = new;
Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
canvasPtr->height + 2*canvasPtr->inset);
if (canvasPtr->textInfo.gotFocus) {
CanvasFocusProc(canvasPtr, 1);
}
canvasPtr->scrollX1 = 0;
canvasPtr->scrollY1 = 0;
canvasPtr->scrollX2 = 0;
canvasPtr->scrollY2 = 0;
if (canvasPtr->regionString != NULL) {
int argc2;
char **argv2;
if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
&argc2, &argv2) != TCL_OK) {
return TCL_ERROR;
}
if (argc2 != 4) {
Tcl_AppendResult(interp, "bad scrollRegion \"",
canvasPtr->regionString, "\"", (char *) NULL);
badRegion:
ckfree(canvasPtr->regionString);
ckfree((char *) argv2);
canvasPtr->regionString = NULL;
return TCL_ERROR;
}
if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
argv2[0], &canvasPtr->scrollX1) != TCL_OK)
|| (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
argv2[1], &canvasPtr->scrollY1) != TCL_OK)
|| (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
argv2[2], &canvasPtr->scrollX2) != TCL_OK)
|| (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
goto badRegion;
}
ckfree((char *) argv2);
}
CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
canvasPtr->xOrigin, canvasPtr->yOrigin,
canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
return TCL_OK;
}
static void
DisplayCanvas(clientData)
ClientData clientData;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
Tk_Window tkwin = canvasPtr->tkwin;
Tk_Item *itemPtr;
Pixmap pixmap;
int screenX1, screenX2, screenY1, screenY2, width, height;
if (canvasPtr->tkwin == NULL) {
return;
}
if (!Tk_IsMapped(tkwin)) {
goto done;
}
while (canvasPtr->flags & REPICK_NEEDED) {
Tcl_Preserve((ClientData) canvasPtr);
canvasPtr->flags &= ~REPICK_NEEDED;
PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
tkwin = canvasPtr->tkwin;
Tcl_Release((ClientData) canvasPtr);
if (tkwin == NULL) {
return;
}
}
if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
&& (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
if (canvasPtr->redrawX1 > screenX1) {
screenX1 = canvasPtr->redrawX1;
}
if (canvasPtr->redrawY1 > screenY1) {
screenY1 = canvasPtr->redrawY1;
}
if (canvasPtr->redrawX2 < screenX2) {
screenX2 = canvasPtr->redrawX2;
}
if (canvasPtr->redrawY2 < screenY2) {
screenY2 = canvasPtr->redrawY2;
}
if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
goto borders;
}
canvasPtr->drawableXOrigin = screenX1 - 30;
canvasPtr->drawableYOrigin = screenY1 - 30;
pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
(screenX2 + 30 - canvasPtr->drawableXOrigin),
(screenY2 + 30 - canvasPtr->drawableYOrigin),
Tk_Depth(tkwin));
width = screenX2 - screenX1;
height = screenY2 - screenY1;
XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
screenX1 - canvasPtr->drawableXOrigin,
screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
(unsigned int) height);
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
if ((itemPtr->x1 >= screenX2)
|| (itemPtr->y1 >= screenY2)
|| (itemPtr->x2 < screenX1)
|| (itemPtr->y2 < screenY1)) {
if (!itemPtr->typePtr->alwaysRedraw
|| (itemPtr->x1 >= canvasPtr->redrawX2)
|| (itemPtr->y1 >= canvasPtr->redrawY2)
|| (itemPtr->x2 < canvasPtr->redrawX1)
|| (itemPtr->y2 < canvasPtr->redrawY1)) {
continue;
}
}
(*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
canvasPtr->display, pixmap, screenX1, screenY1, width,
height);
}
XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
canvasPtr->pixmapGC,
screenX1 - canvasPtr->drawableXOrigin,
screenY1 - canvasPtr->drawableYOrigin,
(unsigned) (screenX2 - screenX1),
(unsigned) (screenY2 - screenY1),
screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
Tk_FreePixmap(Tk_Display(tkwin), pixmap);
}
borders:
if (canvasPtr->flags & REDRAW_BORDERS) {
canvasPtr->flags &= ~REDRAW_BORDERS;
if (canvasPtr->borderWidth > 0) {
Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
canvasPtr->bgBorder, canvasPtr->highlightWidth,
canvasPtr->highlightWidth,
Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
canvasPtr->borderWidth, canvasPtr->relief);
}
if (canvasPtr->highlightWidth != 0) {
GC gc;
if (canvasPtr->textInfo.gotFocus) {
gc = Tk_GCForColor(canvasPtr->highlightColorPtr,
Tk_WindowId(tkwin));
} else {
gc = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
Tk_WindowId(tkwin));
}
Tk_DrawFocusHighlight(tkwin, gc, canvasPtr->highlightWidth,
Tk_WindowId(tkwin));
}
}
done:
canvasPtr->flags &= ~REDRAW_PENDING;
canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
if (canvasPtr->flags & UPDATE_SCROLLBARS) {
CanvasUpdateScrollbars(canvasPtr);
}
}
static void
CanvasEventProc(clientData, eventPtr)
ClientData clientData;
XEvent *eventPtr;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
if (eventPtr->type == Expose) {
int x, y;
x = eventPtr->xexpose.x + canvasPtr->xOrigin;
y = eventPtr->xexpose.y + canvasPtr->yOrigin;
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
x + eventPtr->xexpose.width,
y + eventPtr->xexpose.height);
if ((eventPtr->xexpose.x < canvasPtr->inset)
|| (eventPtr->xexpose.y < canvasPtr->inset)
|| ((eventPtr->xexpose.x + eventPtr->xexpose.width)
> (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
|| ((eventPtr->xexpose.y + eventPtr->xexpose.height)
> (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
canvasPtr->flags |= REDRAW_BORDERS;
}
} else if (eventPtr->type == DestroyNotify) {
if (canvasPtr->tkwin != NULL) {
canvasPtr->tkwin = NULL;
Tcl_DeleteCommand(canvasPtr->interp,
Tcl_GetCommandName(canvasPtr->interp,
canvasPtr->widgetCmd));
}
if (canvasPtr->flags & REDRAW_PENDING) {
Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
}
Tcl_EventuallyFree((ClientData) canvasPtr, DestroyCanvas);
} else if (eventPtr->type == ConfigureNotify) {
canvasPtr->flags |= UPDATE_SCROLLBARS;
CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
canvasPtr->yOrigin,
canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
canvasPtr->flags |= REDRAW_BORDERS;
} else if (eventPtr->type == FocusIn) {
if (eventPtr->xfocus.detail != NotifyInferior) {
CanvasFocusProc(canvasPtr, 1);
}
} else if (eventPtr->type == FocusOut) {
if (eventPtr->xfocus.detail != NotifyInferior) {
CanvasFocusProc(canvasPtr, 0);
}
} else if (eventPtr->type == UnmapNotify) {
Tk_Item *itemPtr;
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
if (itemPtr->typePtr->alwaysRedraw) {
(*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,
itemPtr, canvasPtr->display, None, 0, 0, 0, 0);
}
}
}
}
static void
CanvasCmdDeletedProc(clientData)
ClientData clientData;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
Tk_Window tkwin = canvasPtr->tkwin;
if (tkwin != NULL) {
canvasPtr->tkwin = NULL;
Tk_DestroyWindow(tkwin);
}
}
void
Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
Tk_Canvas canvas;
int x1, y1;
int x2, y2;
{
TkCanvas *canvasPtr = (TkCanvas *) canvas;
if ((x1 == x2) || (y1 == y2)) {
return;
}
if (canvasPtr->flags & REDRAW_PENDING) {
if (x1 <= canvasPtr->redrawX1) {
canvasPtr->redrawX1 = x1;
}
if (y1 <= canvasPtr->redrawY1) {
canvasPtr->redrawY1 = y1;
}
if (x2 >= canvasPtr->redrawX2) {
canvasPtr->redrawX2 = x2;
}
if (y2 >= canvasPtr->redrawY2) {
canvasPtr->redrawY2 = y2;
}
} else {
canvasPtr->redrawX1 = x1;
canvasPtr->redrawY1 = y1;
canvasPtr->redrawX2 = x2;
canvasPtr->redrawY2 = y2;
Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
canvasPtr->flags |= REDRAW_PENDING;
}
}
void
Tk_CreateItemType(typePtr)
Tk_ItemType *typePtr;
{
Tk_ItemType *typePtr2, *prevPtr;
if (typeList == NULL) {
InitCanvas();
}
for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
if (strcmp(typePtr2->name, typePtr->name) == 0) {
if (prevPtr == NULL) {
typeList = typePtr2->nextPtr;
} else {
prevPtr->nextPtr = typePtr2->nextPtr;
}
break;
}
}
typePtr->nextPtr = typeList;
typeList = typePtr;
}
Tk_ItemType *
Tk_GetItemTypes()
{
if (typeList == NULL) {
InitCanvas();
}
return typeList;
}
static void
InitCanvas()
{
if (typeList != NULL) {
return;
}
typeList = &tkRectangleType;
tkRectangleType.nextPtr = &tkTextType;
tkTextType.nextPtr = &tkLineType;
tkLineType.nextPtr = &tkPolygonType;
tkPolygonType.nextPtr = &tkImageType;
tkImageType.nextPtr = &tkOvalType;
tkOvalType.nextPtr = &tkBitmapType;
tkBitmapType.nextPtr = &tkArcType;
tkArcType.nextPtr = &tkWindowType;
tkWindowType.nextPtr = NULL;
allUid = Tk_GetUid("all");
currentUid = Tk_GetUid("current");
}
static Tk_Item *
StartTagSearch(canvasPtr, tag, searchPtr)
TkCanvas *canvasPtr;
char *tag;
TagSearch *searchPtr;
{
int id;
Tk_Item *itemPtr, *prevPtr;
Tk_Uid *tagPtr;
Tk_Uid uid;
int count;
searchPtr->canvasPtr = canvasPtr;
searchPtr->searchOver = 0;
if (isdigit(UCHAR(*tag))) {
char *end;
numIdSearches++;
id = strtoul(tag, &end, 0);
if (*end == 0) {
itemPtr = canvasPtr->hotPtr;
prevPtr = canvasPtr->hotPrevPtr;
if ((itemPtr == NULL) || (itemPtr->id != id) || (prevPtr == NULL)
|| (prevPtr->nextPtr != itemPtr)) {
numSlowSearches++;
for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr;
itemPtr != NULL;
prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
if (itemPtr->id == id) {
break;
}
}
}
searchPtr->prevPtr = prevPtr;
searchPtr->searchOver = 1;
canvasPtr->hotPtr = itemPtr;
canvasPtr->hotPrevPtr = prevPtr;
return itemPtr;
}
}
searchPtr->tag = uid = Tk_GetUid(tag);
if (uid == allUid) {
searchPtr->tag = NULL;
searchPtr->prevPtr = NULL;
searchPtr->currentPtr = canvasPtr->firstItemPtr;
return canvasPtr->firstItemPtr;
}
for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
count > 0; tagPtr++, count--) {
if (*tagPtr == uid) {
searchPtr->prevPtr = prevPtr;
searchPtr->currentPtr = itemPtr;
return itemPtr;
}
}
}
searchPtr->prevPtr = prevPtr;
searchPtr->searchOver = 1;
return NULL;
}
static Tk_Item *
NextItem(searchPtr)
TagSearch *searchPtr;
{
Tk_Item *itemPtr, *prevPtr;
int count;
Tk_Uid uid;
Tk_Uid *tagPtr;
prevPtr = searchPtr->prevPtr;
if (prevPtr == NULL) {
itemPtr = searchPtr->canvasPtr->firstItemPtr;
} else {
itemPtr = prevPtr->nextPtr;
}
if ((itemPtr == NULL) || (searchPtr->searchOver)) {
searchPtr->searchOver = 1;
return NULL;
}
if (itemPtr != searchPtr->currentPtr) {
} else {
prevPtr = itemPtr;
itemPtr = prevPtr->nextPtr;
}
uid = searchPtr->tag;
if (uid == NULL) {
searchPtr->prevPtr = prevPtr;
searchPtr->currentPtr = itemPtr;
return itemPtr;
}
for ( ; itemPtr != NULL; prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
count > 0; tagPtr++, count--) {
if (*tagPtr == uid) {
searchPtr->prevPtr = prevPtr;
searchPtr->currentPtr = itemPtr;
return itemPtr;
}
}
}
searchPtr->prevPtr = prevPtr;
searchPtr->searchOver = 1;
return NULL;
}
static void
DoItem(interp, itemPtr, tag)
Tcl_Interp *interp;
Tk_Item *itemPtr;
Tk_Uid tag;
{
Tk_Uid *tagPtr;
int count;
if (tag == NULL) {
char msg[30];
sprintf(msg, "%d", itemPtr->id);
Tcl_AppendElement(interp, msg);
return;
}
for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
count > 0; tagPtr++, count--) {
if (tag == *tagPtr) {
return;
}
}
if (itemPtr->tagSpace == itemPtr->numTags) {
Tk_Uid *newTagPtr;
itemPtr->tagSpace += 5;
newTagPtr = (Tk_Uid *) ckalloc((unsigned)
(itemPtr->tagSpace * sizeof(Tk_Uid)));
memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,
(itemPtr->numTags * sizeof(Tk_Uid)));
if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
ckfree((char *) itemPtr->tagPtr);
}
itemPtr->tagPtr = newTagPtr;
tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
}
*tagPtr = tag;
itemPtr->numTags++;
}
static int
FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option)
Tcl_Interp *interp;
TkCanvas *canvasPtr;
int argc;
char **argv;
char *newTag;
char *cmdName;
char *option;
{
int c;
size_t length;
TagSearch search;
Tk_Item *itemPtr;
Tk_Uid uid;
if (newTag != NULL) {
uid = Tk_GetUid(newTag);
} else {
uid = NULL;
}
c = argv[0][0];
length = strlen(argv[0]);
if ((c == 'a') && (strncmp(argv[0], "above", length) == 0)
&& (length >= 2)) {
Tk_Item *lastPtr = NULL;
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
cmdName, option, " above tagOrId", (char *) NULL);
return TCL_ERROR;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
itemPtr != NULL; itemPtr = NextItem(&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);
return TCL_ERROR;
}
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
DoItem(interp, itemPtr, uid);
}
} else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) {
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
cmdName, option, " below tagOrId", (char *) NULL);
return TCL_ERROR;
}
itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
if (search.prevPtr != NULL) {
DoItem(interp, search.prevPtr, uid);
}
} else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) {
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);
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)) {
return TCL_ERROR;
}
if (argc > 3) {
if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
&halo) != TCL_OK) {
return TCL_ERROR;
}
if (halo < 0.0) {
Tcl_AppendResult(interp, "can't have negative halo value \"",
argv[3], "\"", (char *) NULL);
return TCL_ERROR;
}
} else {
halo = 0.0;
}
startPtr = canvasPtr->firstItemPtr;
if (argc == 5) {
itemPtr = StartTagSearch(canvasPtr, argv[4], &search);
if (itemPtr != NULL) {
startPtr = itemPtr;
}
}
itemPtr = startPtr;
if (itemPtr == NULL) {
return TCL_OK;
}
closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
itemPtr, coords) - halo;
if (closestDist < 0.0) {
closestDist = 0.0;
}
while (1) {
double newDist;
x1 = (coords[0] - closestDist - halo - 1);
y1 = (coords[1] - closestDist - halo - 1);
x2 = (coords[0] + closestDist + halo + 1);
y2 = (coords[1] + closestDist + halo + 1);
closestPtr = itemPtr;
while (1) {
itemPtr = itemPtr->nextPtr;
if (itemPtr == NULL) {
itemPtr = canvasPtr->firstItemPtr;
}
if (itemPtr == startPtr) {
DoItem(interp, closestPtr, uid);
return TCL_OK;
}
if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
|| (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
continue;
}
newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
itemPtr, coords) - halo;
if (newDist < 0.0) {
newDist = 0.0;
}
if (newDist <= closestDist) {
closestDist = newDist;
break;
}
}
}
} 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);
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 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 TCL_ERROR;
}
for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
itemPtr != NULL; itemPtr = NextItem(&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;
}
static int
FindArea(interp, canvasPtr, argv, uid, enclosed)
Tcl_Interp *interp;
TkCanvas *canvasPtr;
char **argv;
Tk_Uid uid;
int enclosed;
{
double rect[4], tmp;
int x1, y1, x2, y2;
Tk_Item *itemPtr;
if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0],
&rect[0]) != TCL_OK)
|| (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1],
&rect[1]) != TCL_OK)
|| (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2],
&rect[2]) != TCL_OK)
|| (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
&rect[3]) != TCL_OK)) {
return TCL_ERROR;
}
if (rect[0] > rect[2]) {
tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
}
if (rect[1] > rect[3]) {
tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
}
x1 = (rect[0]-1.0);
y1 = (rect[1]-1.0);
x2 = (rect[2]+1.0);
y2 = (rect[3]+1.0);
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
|| (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
continue;
}
if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect)
>= enclosed) {
DoItem(interp, itemPtr, uid);
}
}
return TCL_OK;
}
static void
RelinkItems(canvasPtr, tag, prevPtr)
TkCanvas *canvasPtr;
char *tag;
Tk_Item *prevPtr;
{
Tk_Item *itemPtr;
TagSearch search;
Tk_Item *firstMovePtr, *lastMovePtr;
firstMovePtr = lastMovePtr = NULL;
for (itemPtr = StartTagSearch(canvasPtr, tag, &search);
itemPtr != NULL; itemPtr = NextItem(&search)) {
if (itemPtr == prevPtr) {
prevPtr = search.prevPtr;
}
if (search.prevPtr == NULL) {
canvasPtr->firstItemPtr = itemPtr->nextPtr;
} else {
search.prevPtr->nextPtr = itemPtr->nextPtr;
}
if (canvasPtr->lastItemPtr == itemPtr) {
canvasPtr->lastItemPtr = search.prevPtr;
}
if (firstMovePtr == NULL) {
firstMovePtr = itemPtr;
} else {
lastMovePtr->nextPtr = itemPtr;
}
lastMovePtr = itemPtr;
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1,
itemPtr->x2, itemPtr->y2);
canvasPtr->flags |= REPICK_NEEDED;
}
if (firstMovePtr == NULL) {
return;
}
if (prevPtr == NULL) {
lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
canvasPtr->firstItemPtr = firstMovePtr;
} else {
lastMovePtr->nextPtr = prevPtr->nextPtr;
prevPtr->nextPtr = firstMovePtr;
}
if (canvasPtr->lastItemPtr == prevPtr) {
canvasPtr->lastItemPtr = lastMovePtr;
}
}
static void
CanvasBindProc(clientData, eventPtr)
ClientData clientData;
XEvent *eventPtr;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
Tcl_Preserve((ClientData) canvasPtr);
if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
int mask;
switch (eventPtr->xbutton.button) {
case Button1:
mask = Button1Mask;
break;
case Button2:
mask = Button2Mask;
break;
case Button3:
mask = Button3Mask;
break;
case Button4:
mask = Button4Mask;
break;
case Button5:
mask = Button5Mask;
break;
default:
mask = 0;
break;
}
if (eventPtr->type == ButtonPress) {
canvasPtr->state = eventPtr->xbutton.state;
PickCurrentItem(canvasPtr, eventPtr);
canvasPtr->state ^= mask;
CanvasDoEvent(canvasPtr, eventPtr);
} else {
canvasPtr->state = eventPtr->xbutton.state;
CanvasDoEvent(canvasPtr, eventPtr);
eventPtr->xbutton.state ^= mask;
canvasPtr->state = eventPtr->xbutton.state;
PickCurrentItem(canvasPtr, eventPtr);
eventPtr->xbutton.state ^= mask;
}
goto done;
} else if ((eventPtr->type == EnterNotify)
|| (eventPtr->type == LeaveNotify)) {
canvasPtr->state = eventPtr->xcrossing.state;
PickCurrentItem(canvasPtr, eventPtr);
goto done;
} else if (eventPtr->type == MotionNotify) {
canvasPtr->state = eventPtr->xmotion.state;
PickCurrentItem(canvasPtr, eventPtr);
}
CanvasDoEvent(canvasPtr, eventPtr);
done:
Tcl_Release((ClientData) canvasPtr);
}
static void
PickCurrentItem(canvasPtr, eventPtr)
TkCanvas *canvasPtr;
XEvent *eventPtr;
{
double coords[2];
int buttonDown;
buttonDown = canvasPtr->state
& (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
if (!buttonDown) {
canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
}
if (eventPtr != &canvasPtr->pickEvent) {
if ((eventPtr->type == MotionNotify)
|| (eventPtr->type == ButtonRelease)) {
canvasPtr->pickEvent.xcrossing.type = EnterNotify;
canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
canvasPtr->pickEvent.xcrossing.send_event
= eventPtr->xmotion.send_event;
canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
canvasPtr->pickEvent.xcrossing.subwindow = None;
canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
canvasPtr->pickEvent.xcrossing.same_screen
= eventPtr->xmotion.same_screen;
canvasPtr->pickEvent.xcrossing.focus = False;
canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
} else {
canvasPtr->pickEvent = *eventPtr;
}
}
if (canvasPtr->flags & REPICK_IN_PROGRESS) {
return;
}
coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
if (canvasPtr->pickEvent.type != LeaveNotify) {
canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);
} else {
canvasPtr->newCurrentPtr = NULL;
}
if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)
&& !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
return;
}
if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)
&& (canvasPtr->currentItemPtr != NULL)
&& !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
XEvent event;
Tk_Item *itemPtr = canvasPtr->currentItemPtr;
int i;
event = canvasPtr->pickEvent;
event.type = LeaveNotify;
event.xcrossing.detail = NotifyAncestor;
canvasPtr->flags |= REPICK_IN_PROGRESS;
CanvasDoEvent(canvasPtr, &event);
canvasPtr->flags &= ~REPICK_IN_PROGRESS;
if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {
for (i = itemPtr->numTags-1; i >= 0; i--) {
if (itemPtr->tagPtr[i] == currentUid) {
itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
itemPtr->numTags--;
break;
}
}
}
}
if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) {
canvasPtr->flags |= LEFT_GRABBED_ITEM;
return;
}
canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;
if (canvasPtr->currentItemPtr != NULL) {
XEvent event;
DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid);
event = canvasPtr->pickEvent;
event.type = EnterNotify;
event.xcrossing.detail = NotifyAncestor;
CanvasDoEvent(canvasPtr, &event);
}
}
static Tk_Item *
CanvasFindClosest(canvasPtr, coords)
TkCanvas *canvasPtr;
double coords[2];
{
Tk_Item *itemPtr;
Tk_Item *bestPtr;
int x1, y1, x2, y2;
x1 = coords[0] - canvasPtr->closeEnough;
y1 = coords[1] - canvasPtr->closeEnough;
x2 = coords[0] + canvasPtr->closeEnough;
y2 = coords[1] + canvasPtr->closeEnough;
bestPtr = NULL;
for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
itemPtr = itemPtr->nextPtr) {
if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)
|| (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {
continue;
}
if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
itemPtr, coords) <= canvasPtr->closeEnough) {
bestPtr = itemPtr;
}
}
return bestPtr;
}
static void
CanvasDoEvent(canvasPtr, eventPtr)
TkCanvas *canvasPtr;
XEvent *eventPtr;
{
#define NUM_STATIC 3
ClientData staticObjects[NUM_STATIC];
ClientData *objectPtr;
int numObjects, i;
Tk_Item *itemPtr;
if (canvasPtr->bindingTable == NULL) {
return;
}
itemPtr = canvasPtr->currentItemPtr;
if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
itemPtr = canvasPtr->textInfo.focusItemPtr;
}
if (itemPtr == NULL) {
return;
}
numObjects = itemPtr->numTags + 2;
if (numObjects <= NUM_STATIC) {
objectPtr = staticObjects;
} else {
objectPtr = (ClientData *) ckalloc((unsigned)
(numObjects * sizeof(ClientData)));
}
objectPtr[0] = (ClientData) allUid;
for (i = itemPtr->numTags-1; i >= 0; i--) {
objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
}
objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr;
if (canvasPtr->tkwin != NULL) {
Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
numObjects, objectPtr);
}
if (objectPtr != staticObjects) {
ckfree((char *) objectPtr);
}
}
static void
CanvasBlinkProc(clientData)
ClientData clientData;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {
return;
}
if (canvasPtr->textInfo.cursorOn) {
canvasPtr->textInfo.cursorOn = 0;
canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
canvasPtr->insertOffTime, CanvasBlinkProc,
(ClientData) canvasPtr);
} else {
canvasPtr->textInfo.cursorOn = 1;
canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
canvasPtr->insertOnTime, CanvasBlinkProc,
(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);
}
}
static void
CanvasFocusProc(canvasPtr, gotFocus)
TkCanvas *canvasPtr;
int gotFocus;
{
Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
if (gotFocus) {
canvasPtr->textInfo.gotFocus = 1;
canvasPtr->textInfo.cursorOn = 1;
if (canvasPtr->insertOffTime != 0) {
canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
canvasPtr->insertOffTime, CanvasBlinkProc,
(ClientData) canvasPtr);
}
} else {
canvasPtr->textInfo.gotFocus = 0;
canvasPtr->textInfo.cursorOn = 0;
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);
}
if (canvasPtr->highlightWidth > 0) {
canvasPtr->flags |= REDRAW_BORDERS;
if (!(canvasPtr->flags & REDRAW_PENDING)) {
Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
canvasPtr->flags |= REDRAW_PENDING;
}
}
}
static void
CanvasSelectTo(canvasPtr, itemPtr, index)
TkCanvas *canvasPtr;
Tk_Item *itemPtr;
int index;
{
int oldFirst, oldLast;
Tk_Item *oldSelPtr;
oldFirst = canvasPtr->textInfo.selectFirst;
oldLast = canvasPtr->textInfo.selectLast;
oldSelPtr = canvasPtr->textInfo.selItemPtr;
if (canvasPtr->textInfo.selItemPtr == NULL) {
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);
}
canvasPtr->textInfo.selItemPtr = itemPtr;
if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {
canvasPtr->textInfo.anchorItemPtr = itemPtr;
canvasPtr->textInfo.selectAnchor = index;
}
if (canvasPtr->textInfo.selectAnchor <= index) {
canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;
canvasPtr->textInfo.selectLast = index;
} else {
canvasPtr->textInfo.selectFirst = index;
canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;
}
if ((canvasPtr->textInfo.selectFirst != oldFirst)
|| (canvasPtr->textInfo.selectLast != oldLast)
|| (itemPtr != oldSelPtr)) {
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
}
}
static int
CanvasFetchSelection(clientData, offset, buffer, maxBytes)
ClientData clientData;
int offset;
char *buffer;
int maxBytes;
{
TkCanvas *canvasPtr = (TkCanvas *) clientData;
if (canvasPtr->textInfo.selItemPtr == NULL) {
return -1;
}
if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) {
return -1;
}
return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)(
(Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset,
buffer, maxBytes);
}
static void
CanvasLostSelection(clientData)
ClientData 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);
}
canvasPtr->textInfo.selItemPtr = NULL;
}
static double
GridAlign(coord, spacing)
double coord;
double spacing;
{
if (spacing <= 0.0) {
return coord;
}
if (coord < 0) {
return -((int) ((-coord)/spacing + 0.5)) * spacing;
}
return ((int) (coord/spacing + 0.5)) * spacing;
}
static void
PrintScrollFractions(screen1, screen2, object1, object2, string)
int screen1;
int screen2;
int object1;
int object2;
char *string;
{
double range, f1, f2;
range = object2 - object1;
if (range <= 0) {
f1 = 0;
f2 = 1.0;
} else {
f1 = (screen1 - object1)/range;
if (f1 < 0) {
f1 = 0.0;
}
f2 = (screen2 - object1)/range;
if (f2 > 1.0) {
f2 = 1.0;
}
if (f2 < f1) {
f2 = f1;
}
}
sprintf(string, "%g %g", f1, f2);
}
static void
CanvasUpdateScrollbars(canvasPtr)
TkCanvas *canvasPtr;
{
int result;
char buffer[200];
Tcl_Interp *interp;
int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2,
scrollY1, scrollY2;
char *xScrollCmd, *yScrollCmd;
interp = canvasPtr->interp;
Tcl_Preserve((ClientData) interp);
xScrollCmd = canvasPtr->xScrollCmd;
if (xScrollCmd != (char *) NULL) {
Tcl_Preserve((ClientData) xScrollCmd);
}
yScrollCmd = canvasPtr->yScrollCmd;
if (yScrollCmd != (char *) NULL) {
Tcl_Preserve((ClientData) yScrollCmd);
}
xOrigin = canvasPtr->xOrigin;
yOrigin = canvasPtr->yOrigin;
inset = canvasPtr->inset;
width = Tk_Width(canvasPtr->tkwin);
height = Tk_Height(canvasPtr->tkwin);
scrollX1 = canvasPtr->scrollX1;
scrollX2 = canvasPtr->scrollX2;
scrollY1 = canvasPtr->scrollY1;
scrollY2 = canvasPtr->scrollY2;
canvasPtr->flags &= ~UPDATE_SCROLLBARS;
if (canvasPtr->xScrollCmd != NULL) {
PrintScrollFractions(xOrigin + inset, xOrigin + width - inset,
scrollX1, scrollX2, buffer);
result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);
if (result != TCL_OK) {
Tcl_BackgroundError(interp);
}
Tcl_ResetResult(interp);
Tcl_Release((ClientData) xScrollCmd);
}
if (yScrollCmd != NULL) {
PrintScrollFractions(yOrigin + inset, yOrigin + height - inset,
scrollY1, scrollY2, buffer);
result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);
if (result != TCL_OK) {
Tcl_BackgroundError(interp);
}
Tcl_ResetResult(interp);
Tcl_Release((ClientData) yScrollCmd);
}
Tcl_Release((ClientData) interp);
}
static void
CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)
TkCanvas *canvasPtr;
int xOrigin;
int yOrigin;
{
int left, right, top, bottom, delta;
if (canvasPtr->xScrollIncrement > 0) {
if (xOrigin >= 0) {
xOrigin += canvasPtr->xScrollIncrement/2;
xOrigin -= (xOrigin + canvasPtr->inset)
% canvasPtr->xScrollIncrement;
} else {
xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;
xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)
% canvasPtr->xScrollIncrement);
}
}
if (canvasPtr->yScrollIncrement > 0) {
if (yOrigin >= 0) {
yOrigin += canvasPtr->yScrollIncrement/2;
yOrigin -= (yOrigin + canvasPtr->inset)
% canvasPtr->yScrollIncrement;
} else {
yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;
yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)
% canvasPtr->yScrollIncrement);
}
}
if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;
right = canvasPtr->scrollX2
- (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);
top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;
bottom = canvasPtr->scrollY2
- (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);
if ((left < 0) && (right > 0)) {
delta = (right > -left) ? -left : right;
if (canvasPtr->xScrollIncrement > 0) {
delta -= delta % canvasPtr->xScrollIncrement;
}
xOrigin += delta;
} else if ((right < 0) && (left > 0)) {
delta = (left > -right) ? -right : left;
if (canvasPtr->xScrollIncrement > 0) {
delta -= delta % canvasPtr->xScrollIncrement;
}
xOrigin -= delta;
}
if ((top < 0) && (bottom > 0)) {
delta = (bottom > -top) ? -top : bottom;
if (canvasPtr->yScrollIncrement > 0) {
delta -= delta % canvasPtr->yScrollIncrement;
}
yOrigin += delta;
} else if ((bottom < 0) && (top > 0)) {
delta = (top > -bottom) ? -bottom : top;
if (canvasPtr->yScrollIncrement > 0) {
delta -= delta % canvasPtr->yScrollIncrement;
}
yOrigin -= delta;
}
}
if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
return;
}
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
canvasPtr->xOrigin, canvasPtr->yOrigin,
canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
canvasPtr->xOrigin = xOrigin;
canvasPtr->yOrigin = yOrigin;
canvasPtr->flags |= UPDATE_SCROLLBARS;
Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
canvasPtr->xOrigin, canvasPtr->yOrigin,
canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
}