Index: generic/tk.h ================================================================== --- generic/tk.h +++ generic/tk.h @@ -975,14 +975,17 @@ * 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. + * TK_ITEM_SMALL_ITEM - 1 means that the object should not be drawn if + * the option "suppress small items" is in effect. */ #define TK_ITEM_STATE_DEPENDANT 1 #define TK_ITEM_DONT_REDRAW 2 +#define TK_ITEM_SMALL_ITEM 4 /* * 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. */ Index: generic/tkCanvas.c ================================================================== --- generic/tkCanvas.c +++ generic/tkCanvas.c @@ -95,21 +95,31 @@ #define SEARCH_TYPE_EXPR 4 /* Compound search */ #endif /* USE_OLD_TAG_SEARCH */ /* - * Custom option for handling "-state" and "-offset" + * Custom option for handling "-state", "-offset" and "-suppresssmallitems" */ +static int SuppressSmallItemsParseProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, const char *value, char *widgRec, + int offset); + +static const char * SuppressSmallItemsPrintProc(ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr); static const Tk_CustomOption stateOption = { TkStateParseProc, TkStatePrintProc, NULL /* Only "normal" and "disabled". */ }; static const Tk_CustomOption offsetOption = { TkOffsetParseProc, TkOffsetPrintProc, INT2PTR(TK_OFFSET_RELATIVE) }; + +static const Tk_CustomOption suppressSmallItemsOption = { + SuppressSmallItemsParseProc, SuppressSmallItemsPrintProc, NULL +}; /* * Information used for argv parsing. */ @@ -181,10 +191,13 @@ DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr), TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK, NULL}, {TK_CONFIG_CUSTOM, "-state", "state", "State", "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT, &stateOption}, + {TK_CONFIG_CUSTOM, "-suppresssmallitems", "SuppressSmallItems", + "SuppressSmallItems", "0", 0, TK_CONFIG_DONT_SET_DEFAULT, + &suppressSmallItemsOption}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus), TK_CONFIG_NULL_OK, NULL}, {TK_CONFIG_PIXELS, "-width", "width", "Width", DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0, NULL}, @@ -309,12 +322,12 @@ Tcl_Obj *tag, TagSearch **searchPtrPtr); static int TagSearchScanExpr(Tcl_Interp *interp, TagSearch *searchPtr, TagSearchExpr *expr); static int TagSearchEvalExpr(TagSearchExpr *expr, Tk_Item *itemPtr); -static Tk_Item * TagSearchFirst(TagSearch *searchPtr); -static Tk_Item * TagSearchNext(TagSearch *searchPtr); +static Tk_Item * TagSearchFirst(TagSearch *searchPtr, int suppressSmallItems); +static Tk_Item * TagSearchNext(TagSearch *searchPtr, int suppressSmallItems); #endif /* USE_OLD_TAG_SEARCH */ /* * The structure below defines canvas class behavior by means of functions * that can be invoked from generic window code. @@ -340,21 +353,21 @@ #define FIND_ITEMS(objPtr, n) \ FindItems(interp, canvasPtr, objc, objv, (objPtr), (n)) #define RELINK_ITEMS(objPtr, itemPtr) \ RelinkItems(canvasPtr, (objPtr), (itemPtr)) #else /* USE_OLD_TAG_SEARCH */ -#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ +#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,suppressSmallItems,errorExitClause) \ if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \ errorExitClause; \ } \ - itemPtr = TagSearchFirst(*(searchPtrPtr)); -#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ + itemPtr = TagSearchFirst(*(searchPtrPtr),suppressSmallItems); +#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,suppressSmallIitems,errorExitClause) \ if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \ errorExitClause; \ } \ - for (itemPtr = TagSearchFirst(*(searchPtrPtr)); \ - itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr))) + for (itemPtr = TagSearchFirst(*(searchPtrPtr),suppressSmallItems); \ + itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr),suppressSmallItems)) #define FIND_ITEMS(objPtr, n) \ FindItems(interp, canvasPtr, objc, objv, (objPtr), (n), &searchPtr) #define RELINK_ITEMS(objPtr, itemPtr) \ result = RelinkItems(canvasPtr, (objPtr), (itemPtr), &searchPtr) #endif /* USE_OLD_TAG_SEARCH */ @@ -797,10 +810,11 @@ #else /* USE_OLD_TAG_SEARCH */ TagSearch *searchPtr = NULL;/* Allocated by first TagSearchScan, freed by * TagSearchDestroy */ #endif /* USE_OLD_TAG_SEARCH */ + int suppressSmallItems; int index; static const char *const optionStrings[] = { "addtag", "bbox", "bind", "canvasx", "canvasy", "cget", "configure", "coords", "create", "dchars", "delete", "dtag", @@ -832,10 +846,12 @@ &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve(canvasPtr); + suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0); + result = TCL_OK; switch ((enum options) index) { case CANV_ADDTAG: if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "tag searchCommand ?arg ...?"); @@ -856,11 +872,11 @@ result = TCL_ERROR; goto done; } gotAny = 0; for (i = 2; i < objc; i++) { - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2)) { continue; } if (!gotAny) { @@ -1147,11 +1163,11 @@ if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?x y x y ...?"); result = TCL_ERROR; goto done; } - FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done); if (itemPtr != NULL) { if (objc != 3) { EventuallyRedrawItem(canvasPtr, itemPtr); } result = ItemCoords(canvasPtr, itemPtr, objc-3, objv+3); @@ -1182,11 +1198,11 @@ * modifications in the loop. */ tmpObj = Tcl_NewListObj(2, objv+4); - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto doneImove) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto doneImove) { int index; int x1,x2,y1,y2; int dontRedraw1,dontRedraw2; /* @@ -1339,11 +1355,11 @@ if ((objc != 4) && (objc != 5)) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->dCharsProc == NULL)) { continue; } result = ItemIndex(canvasPtr, itemPtr, objv[3], &first); @@ -1382,11 +1398,11 @@ case CANV_DELETE: { int i; Tcl_HashEntry *entryPtr; for (i = 2; i < objc; i++) { - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, suppressSmallItems, goto done) { EventuallyRedrawItem(canvasPtr, itemPtr); if (canvasPtr->bindingTable != NULL) { Tk_DeleteAllBindings(canvasPtr->bindingTable, itemPtr); } ItemDelete(canvasPtr, itemPtr); @@ -1446,11 +1462,11 @@ if (objc == 4) { tag = Tk_GetUid(Tcl_GetString(objv[3])); } else { tag = Tk_GetUid(Tcl_GetString(objv[2])); } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { for (i = itemPtr->numTags-1; i >= 0; i--) { if (itemPtr->tagPtr[i] == tag) { itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; itemPtr->numTags--; } @@ -1484,11 +1500,11 @@ } if (Tcl_GetString(objv[2])[0] == 0) { canvasPtr->textInfo.focusItemPtr = NULL; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if (itemPtr->typePtr->icursorProc != NULL) { break; } } if (itemPtr == NULL) { @@ -1503,11 +1519,11 @@ if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); result = TCL_ERROR; goto done; } - FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done); if (itemPtr != NULL) { int i; Tcl_Obj *resultObj = Tcl_NewObj(); for (i = 0; i < itemPtr->numTags; i++) { @@ -1523,11 +1539,11 @@ if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->icursorProc == NULL)) { goto done; } result = ItemIndex(canvasPtr, itemPtr, objv[3], &index); @@ -1548,11 +1564,11 @@ if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId string"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if (itemPtr->typePtr->indexProc != NULL) { break; } } if (itemPtr == NULL) { @@ -1577,11 +1593,11 @@ if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->insertProc == NULL)) { continue; } result = ItemIndex(canvasPtr, itemPtr, objv[3], &beforeThis); @@ -1613,11 +1629,11 @@ if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId option"); result = TCL_ERROR; goto done; } - FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done); if (itemPtr != NULL) { result = ItemConfigValue(canvasPtr, itemPtr, objv[3]); } break; case CANV_ITEMCONFIGURE: @@ -1624,11 +1640,11 @@ if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?-option value ...?"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if (objc == 3) { result = ItemConfigInfo(canvasPtr, itemPtr, NULL); } else if (objc == 4) { result = ItemConfigInfo(canvasPtr, itemPtr, objv[3]); } else { @@ -1656,11 +1672,11 @@ */ if (objc == 3) { itemPtr = NULL; } else { - FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr,suppressSmallItems, goto done); if (itemPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "tagOrId \"%s\" doesn't match any items", Tcl_GetString(objv[3]))); Tcl_SetErrorCode(interp, "TK", "CANVAS", "ITEM", NULL); @@ -1684,11 +1700,11 @@ &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, objv[4], &yAmount) != TCL_OK)) { result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { EventuallyRedrawItem(canvasPtr, itemPtr); ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount); EventuallyRedrawItem(canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } @@ -1721,11 +1737,11 @@ objv[4], &newY) != TCL_OK) { result = TCL_ERROR; goto done; } - FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done); if (itemPtr != NULL) { oldX = itemPtr->x1; oldY = itemPtr->y1; /* @@ -1746,11 +1762,11 @@ /* * Move the object(s). */ - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { EventuallyRedrawItem(canvasPtr, itemPtr); ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount); EventuallyRedrawItem(canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } @@ -1781,11 +1797,11 @@ if (objc == 3) { prevPtr = canvasPtr->lastItemPtr; } else { prevPtr = NULL; - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, suppressSmallItems, goto done) { prevPtr = itemPtr; } if (prevPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "tagOrId \"%s\" doesn't match any items", @@ -1805,11 +1821,11 @@ if (objc != 6) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first last string"); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->dCharsProc == NULL) || (itemPtr->typePtr->insertProc == NULL)) { continue; } @@ -1868,11 +1884,12 @@ "scale factor cannot be zero", -1)); Tcl_SetErrorCode(interp, "TK", "CANVAS", "BAD_SCALE", NULL); result = TCL_ERROR; goto done; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + suppressSmallItems = 0; /* All items must be considered when scaling */ + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) { EventuallyRedrawItem(canvasPtr, itemPtr); ItemScale(canvasPtr, itemPtr, xOrigin, yOrigin, xScale, yScale); EventuallyRedrawItem(canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } @@ -1935,11 +1952,11 @@ Tcl_WrongNumArgs(interp, 2, objv, "option ?tagOrId? ?arg?"); result = TCL_ERROR; goto done; } if (objc >= 4) { - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, suppressSmallItems, goto done) { if ((itemPtr->typePtr->indexProc != NULL) && (itemPtr->typePtr->selectionProc != NULL)){ break; } } @@ -2027,11 +2044,11 @@ if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "tag"); result = TCL_ERROR; goto done; } - FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done); if (itemPtr != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(itemPtr->typePtr->name, -1)); } break; @@ -2435,11 +2452,11 @@ { TkCanvas *canvasPtr = clientData; Tk_Window tkwin = canvasPtr->tkwin; Tk_Item *itemPtr; Pixmap pixmap; - int screenX1, screenX2, screenY1, screenY2, width, height; + int screenX1, screenX2, screenY1, screenY2, width, height, suppressSmallItems; if (canvasPtr->tkwin == NULL) { return; } @@ -2567,12 +2584,17 @@ * on-screen area or (b) it intersects the full canvas area and its * type requests that it be redrawn always (e.g. so subwindows can be * unmapped when they move off-screen). */ + suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0); + for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (suppressSmallItems && ((itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + continue; + } if ((itemPtr->x1 >= screenX2) || (itemPtr->y1 >= screenY2) || (itemPtr->x2 < screenX1) || (itemPtr->y2 < screenY1)) { if (!AlwaysRedraw(itemPtr) @@ -3069,10 +3091,11 @@ Tk_Uid uid; char *tag = Tcl_GetString(tagObj); int count; TkWindow *tkwin = (TkWindow *) canvasPtr->tkwin; TkDisplay *dispPtr = tkwin->dispPtr; + int suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0); /* * Initialize the search. */ @@ -3082,10 +3105,12 @@ /* * 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. + * + * TODO: should we accept a numerical ID/tag even if the item is too small? */ if (isdigit(UCHAR(*tag))) { char *end; Tcl_HashEntry *entryPtr; @@ -3116,10 +3141,11 @@ searchPtr->tag = uid = Tk_GetUid(tag); if (uid == Tk_GetUid("all")) { /* * All items match. + * TODO: how to implement the suppression? */ searchPtr->tag = NULL; searchPtr->lastPtr = NULL; searchPtr->currentPtr = canvasPtr->firstItemPtr; @@ -3130,18 +3156,20 @@ * None of the above. Search for an item with a matching tag. */ for (lastPtr = NULL, itemPtr = 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; - } - } + if (!(suppressSmallItems && ((itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0))) { + 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; } @@ -3203,10 +3231,11 @@ itemPtr = lastPtr->nextPtr; } /* * Handle special case of "all" search by returning next item. + * TODO: how to implement the suppression? */ uid = searchPtr->tag; if (uid == NULL) { searchPtr->lastPtr = lastPtr; @@ -3217,16 +3246,18 @@ /* * Look for an item with a particular tag. */ 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; + if (!(suppressSmallItems && (entryPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + 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; @@ -3966,11 +3997,12 @@ *-------------------------------------------------------------- */ static Tk_Item * TagSearchFirst( - TagSearch *searchPtr) /* Record describing tag search */ + TagSearch *searchPtr, /* Record describing tag search */ + int suppressSmallItems) /* Suppress items tagged as small? */ { Tk_Item *itemPtr, *lastPtr; Tk_Uid uid, *tagPtr; int count; @@ -3985,10 +4017,12 @@ /* * 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. + * + * TODO: Accept an item given by its numerical ID, even if it is too small? */ if (searchPtr->type == SEARCH_TYPE_ID) { Tcl_HashEntry *entryPtr; @@ -4028,16 +4062,18 @@ */ 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; + if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; count > 0; tagPtr++, count--) { - if (*tagPtr == uid) { - searchPtr->lastPtr = lastPtr; - searchPtr->currentPtr = itemPtr; - return itemPtr; + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } } } } } else { /* @@ -4044,15 +4080,17 @@ * 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; + if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } } } } searchPtr->lastPtr = lastPtr; searchPtr->searchOver = 1; @@ -4080,11 +4118,12 @@ *-------------------------------------------------------------- */ static Tk_Item * TagSearchNext( - TagSearch *searchPtr) /* Record describing search in progress. */ + TagSearch *searchPtr, /* Record describing search in progress. */ + int suppressSmallItems) /* Suppress items tagged as small? */ { Tk_Item *itemPtr, *lastPtr; Tk_Uid uid, *tagPtr; int count; @@ -4130,16 +4169,18 @@ * 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; + if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + 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; @@ -4150,14 +4191,16 @@ * 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; + if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) { + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } } } searchPtr->lastPtr = lastPtr; searchPtr->searchOver = 1; return NULL; @@ -4283,11 +4326,11 @@ #ifdef USE_OLD_TAG_SEARCH TagSearch search; #endif /* USE_OLD_TAG_SEARCH */ Tk_Item *itemPtr; Tk_Uid uid; - int index, result; + int index, result, suppressSmallItems; Tcl_Obj *resultObj; static const char *const optionStrings[] = { "above", "all", "below", "closest", "enclosed", "overlapping", "withtag", NULL }; @@ -4303,19 +4346,22 @@ } if (Tcl_GetIndexFromObj(interp, objv[first], optionStrings, "search command", 0, &index) != TCL_OK) { return TCL_ERROR; } + + suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0); + switch ((enum options) index) { case CANV_ABOVE: { Tk_Item *lastPtr = NULL; if (objc != first+2) { Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); return TCL_ERROR; } - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems, return TCL_ERROR) { lastPtr = itemPtr; } if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) { resultObj = Tcl_NewObj(); @@ -4341,11 +4387,11 @@ case CANV_BELOW: if (objc != first+2) { Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); return TCL_ERROR; } - FIRST_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + FIRST_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems, return TCL_ERROR); if ((itemPtr != NULL) && (itemPtr->prevPtr != NULL)) { resultObj = Tcl_NewObj(); DoItem(resultObj, itemPtr->prevPtr, uid); Tcl_SetObjResult(interp, resultObj); @@ -4385,11 +4431,11 @@ * Find the item at which to start the search. */ startPtr = canvasPtr->firstItemPtr; if (objc == first+5) { - FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr, + FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr, suppressSmallItems, return TCL_ERROR); if (itemPtr != NULL) { startPtr = itemPtr; } } @@ -4477,11 +4523,11 @@ if (objc != first+2) { Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); return TCL_ERROR; } resultObj = Tcl_NewObj(); - FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems, goto badWithTagSearch) { DoItem(resultObj, itemPtr, uid); } Tcl_SetObjResult(interp, resultObj); return TCL_OK; @@ -4624,19 +4670,21 @@ #ifdef USE_OLD_TAG_SEARCH TagSearch search; #endif /* USE_OLD_TAG_SEARCH */ Tk_Item *firstMovePtr, *lastMovePtr; int result; + int suppressSmallItems; /* * Find all of the items to be moved and remove them from the list, making * an auxiliary list running from firstMovePtr to lastMovePtr. Record * their areas for redisplay. */ + suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0); firstMovePtr = lastMovePtr = NULL; - FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, return TCL_ERROR) { + FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, suppressSmallItems, return TCL_ERROR) { if (itemPtr == prevPtr) { /* * Item after which insertion is to occur is being moved! Switch * to insert after its predecessor. */ @@ -5954,13 +6002,97 @@ * coordinates giving points for path. */ int numPoints) /* Number of points at *coordPtr. */ { Tk_PostscriptPath(interp, Canvas(canvas)->psInfo, coordPtr, numPoints); } + +/* + *-------------------------------------------------------------- + * + * SuppressSmallItemsParseProc -- + * + * Parse the -suppresssmallitems option + * + * Results: + * A standard Tcl return value + * + * Side effects: + * The flag for suppressing the drawing of small items is set + * or cleared + * + *-------------------------------------------------------------- + */ + +static int +SuppressSmallItemsParseProc( + ClientData clientData, /* Not used.*/ + Tcl_Interp *interp, /* Used for reporting errors. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + const char *value, /* Value of option (boolean value). */ + char *widgRec, /* Pointer to record in canvas. */ + int offset) /* Not used */ +{ + int optionValue; + TkCanvas *canvasPtr = (TkCanvas *) widgRec; + + /* + * Parse the given string as a boolean value and store the + * result as a bit flag + */ + + if (Tcl_GetBoolean(interp, value, &optionValue) != TCL_OK) { + return TCL_ERROR; + } + + if (optionValue) { + canvasPtr->flags |= SUPPRESS_SMALL_ITEMS; + } else { + canvasPtr->flags &= ~SUPPRESS_SMALL_ITEMS; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * SuppressSmallItemsPrintProc -- + * + * This function is invoked by the Tk configuration code to produce a + * printable string for the "-suppresssmallitems" configuration option + * for the canvas itself. + * + * Results: + * The return value is a string "1" or "0", depending on the value. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static const char * +SuppressSmallItemsPrintProc( + ClientData clientData, /* Ignored. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + char *widgRec, /* Pointer to record for item. */ + int offset, /* Not used */ + Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with + * information about how to reclaim storage + * for return string. */ +{ + TkCanvas *canvasPtr = (TkCanvas *) widgRec; + *freeProcPtr = TCL_STATIC; + + if (canvasPtr->flags & SUPPRESS_SMALL_ITEMS) { + return "1"; + } else { + return "0"; + } +} /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ Index: generic/tkCanvas.h ================================================================== --- generic/tkCanvas.h +++ generic/tkCanvas.h @@ -260,10 +260,12 @@ * 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. + * SUPPRESS_SMALL_ITEMS - 1 means that items smaller than 2 pixels are + * not drawn (performance improvement). */ #define REDRAW_PENDING 1 #define REDRAW_BORDERS 2 #define REPICK_NEEDED 4 @@ -271,10 +273,11 @@ #define CURSOR_ON 0x10 #define UPDATE_SCROLLBARS 0x20 #define LEFT_GRABBED_ITEM 0x40 #define REPICK_IN_PROGRESS 0x100 #define BBOX_NOT_EMPTY 0x200 +#define SUPPRESS_SMALL_ITEMS 0x400 /* * Flag bits for canvas items (redraw_flags): * * FORCE_REDRAW - 1 means that the new coordinates of some item Index: generic/tkRectOval.c ================================================================== --- generic/tkRectOval.c +++ generic/tkRectOval.c @@ -624,10 +624,16 @@ RectOvalItem *rectOvalPtr) /* Item whose bbox is to be recomputed. */ { int bloat, tmp; double dtmp, width; Tk_State state = rectOvalPtr->header.state; + + if ( (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0] ) < 2 || (rectOvalPtr->bbox[3] - rectOvalPtr->bbox[1] ) < 2 ) { + rectOvalPtr->header.redraw_flags |= TK_ITEM_SMALL_ITEM; + } else { + rectOvalPtr->header.redraw_flags &= ~TK_ITEM_SMALL_ITEM; + } if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; }