Attachment "smallitems.patch" to
ticket [e9a842a3]
added by
arjenmarkus
2013-12-28 14:42:20.
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", Tk_Offset(TkCanvas, flags),
+ 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,103 @@
* 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) /* Offset into the widget structure. */
+{
+ int optionValue;
+ int *canvasFlags = (int *)(widgRec+offset);
+
+ /*
+ * 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) {
+ (*canvasFlags) |= SUPPRESS_SMALL_ITEMS;
+ } else {
+ (*canvasFlags) &= ~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, /* Offset into the widget structure. */
+ Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
+ * information about how to reclaim storage
+ * for return string. */
+{
+ int *canvasFlags = (int *)(widgRec+offset);
+
+ FILE *outf;
+ outf = fopen( "arjen.out", "w" );
+ fprintf( outf, "Flags: %p\n", canvasFlags );
+ fclose( outf );
+
+ *freeProcPtr = TCL_STATIC;
+
+ if ((*canvasFlags) & 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.
+ * HIDE_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;
}
@@ -1223,10 +1229,11 @@
rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX);
rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY);
rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX);
rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY);
+
ComputeRectOvalBbox(canvas, rectOvalPtr);
}
/*
*--------------------------------------------------------------