diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2019-03-11 09:43:35 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2019-03-11 09:43:35 (GMT) |
commit | aa019c08a152fc9d3fd124aa780af6c90f7c68ad (patch) | |
tree | 6026e6abac6e28df4064a3a1267ad13292c409f3 /generic | |
parent | 9febe3d031f0782f45894fd86868b6965ba101e1 (diff) | |
download | tk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.zip tk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.tar.gz tk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.tar.bz2 |
Basic implementation of TIP 164: [$canvas rotate]
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tk.h | 6 | ||||
-rw-r--r-- | generic/tkCanvas.c | 110 |
2 files changed, 104 insertions, 12 deletions
diff --git a/generic/tk.h b/generic/tk.h index f106f1c..b5be2ce 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -1034,6 +1034,8 @@ typedef int (Tk_ItemAreaProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); typedef int (Tk_ItemPostscriptProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); +typedef void (Tk_ItemRotateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + double originX, double originY, double angleRadians); typedef void (Tk_ItemScaleProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); @@ -1117,7 +1119,9 @@ typedef struct Tk_ItemType { /* Procedure to delete characters from an * item. */ struct Tk_ItemType *nextPtr;/* Used to link types together into a list. */ - char *reserved1; /* Reserved for future extension. */ + Tk_ItemRotateProc *rotateProc; + /* Procedure to rotate an item's coordinates + * about a point. */ int reserved2; /* Carefully compatible with */ char *reserved3; /* Jan Nijtmans dash patch */ char *reserved4; diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index f3778a6..8a05c86 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -560,6 +560,71 @@ ItemTranslate( itemPtr->typePtr->translateProc((Tk_Canvas) canvasPtr, itemPtr, xDelta, yDelta); } + +static inline void +ItemRotate( + TkCanvas *canvasPtr, + Tk_Item *itemPtr, + double x, + double y, + double angle) +{ + if (itemPtr->typePtr->rotateProc != NULL) { + itemPtr->typePtr->rotateProc((Tk_Canvas) canvasPtr, + itemPtr, x, y, angle); + } else { + int objc, i, ok = 1; + Tcl_Obj **objv; + double *coordv; + double s = sin(angle); + double c = cos(angle); + Tcl_Interp *interp = canvasPtr->interp; + + if (ItemCoords(canvasPtr, itemPtr, 0, NULL) == TCL_OK && + Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), + &objc, &objv) == TCL_OK) { + coordv = (double *) Tcl_Alloc(sizeof(double) * objc); + for (i=0 ; i<objc ; i++) { + if (Tcl_GetDoubleFromObj(NULL, objv[i], &coordv[i]) != TCL_OK) { + ok = 0; + break; + } + } + if (ok) { + /* + * Apply the rotation. + */ + + for (i=0 ; i<objc ; i+=2) { + double px = coordv[i+0] - x; + double py = coordv[i+1] - y; + double nx = px * c - py * s; + double ny = px * s + py * c; + + coordv[i+0] = nx + x; + coordv[i+1] = ny + y; + } + + /* + * Write the coordinates back into the item. + */ + + objv = (Tcl_Obj **) Tcl_Alloc(sizeof(Tcl_Obj *) * objc); + for (i=0 ; i<objc ; i++) { + objv[i] = Tcl_NewDoubleObj(coordv[i]); + Tcl_IncrRefCount(objv[i]); + } + ItemCoords(canvasPtr, itemPtr, objc, objv); + for (i=0 ; i<objc ; i++) { + Tcl_DecrRefCount(objv[i]); + } + Tcl_Free((char *) objv); + } + Tcl_Free((char *) coordv); + } + Tcl_ResetResult(interp); + } +} /* *-------------------------------------------------------------- @@ -746,25 +811,24 @@ CanvasWidgetCmd( "canvasy", "cget", "configure", "coords", "create", "dchars", "delete", "dtag", "find", "focus", "gettags", "icursor", - "image", - "imove", "index", "insert", "itemcget", - "itemconfigure", + "image", "imove", "index", "insert", + "itemcget", "itemconfigure", "lower", "move", "moveto", "postscript", - "raise", "rchars", "scale", "scan", - "select", "type", "xview", "yview", - NULL + "raise", "rchars", "rotate", "scale", + "scan", "select", "type", "xview", + "yview", NULL }; enum options { CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX, CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS, CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG, CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR, - CANV_IMAGE, - CANV_IMOVE, CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, - CANV_ITEMCONFIGURE, + CANV_IMAGE, CANV_IMOVE, CANV_INDEX, CANV_INSERT, + CANV_ITEMCGET, CANV_ITEMCONFIGURE, CANV_LOWER, CANV_MOVE, CANV_MOVETO, CANV_POSTSCRIPT, - CANV_RAISE, CANV_RCHARS, CANV_SCALE, CANV_SCAN, - CANV_SELECT, CANV_TYPE, CANV_XVIEW, CANV_YVIEW + CANV_RAISE, CANV_RCHARS, CANV_ROTATE, CANV_SCALE, + CANV_SCAN, CANV_SELECT, CANV_TYPE, CANV_XVIEW, + CANV_YVIEW }; if (objc < 2) { @@ -1760,6 +1824,30 @@ CanvasWidgetCmd( } break; } + case CANV_ROTATE: { + double x, y, angle; + Tk_Canvas canvas = (Tk_Canvas) canvasPtr; + + if (objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId x y angle"); + result = TCL_ERROR; + goto done; + } + if (Tk_CanvasGetCoordFromObj(interp, canvas, objv[3], &x) != TCL_OK || + Tk_CanvasGetCoordFromObj(interp, canvas, objv[4], &y) != TCL_OK || + Tcl_GetDoubleFromObj(interp, objv[5], &angle) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + angle = angle * 3.1415927 / 180.0; + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + EventuallyRedrawItem(canvasPtr, itemPtr); + ItemRotate(canvasPtr, itemPtr, x, y, angle); + EventuallyRedrawItem(canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } + break; + } case CANV_SCALE: { double xOrigin, yOrigin, xScale, yScale; |