summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2019-03-11 09:43:35 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2019-03-11 09:43:35 (GMT)
commitaa019c08a152fc9d3fd124aa780af6c90f7c68ad (patch)
tree6026e6abac6e28df4064a3a1267ad13292c409f3
parent9febe3d031f0782f45894fd86868b6965ba101e1 (diff)
downloadtk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.zip
tk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.tar.gz
tk-aa019c08a152fc9d3fd124aa780af6c90f7c68ad.tar.bz2
Basic implementation of TIP 164: [$canvas rotate]
-rw-r--r--generic/tk.h6
-rw-r--r--generic/tkCanvas.c110
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;