aboutsummaryrefslogtreecommitdiff
path: root/generic/tkZinc.c
diff options
context:
space:
mode:
authorlecoanet2003-05-09 15:02:49 +0000
committerlecoanet2003-05-09 15:02:49 +0000
commit0bd438e81d1eee5db0cfe6316e1063cfc50fd86b (patch)
treebdf466599949e588bea44136dbcb068beba88567 /generic/tkZinc.c
parentbb7924e8fe10f9f28cb5d01dc687bc652ec33408 (diff)
downloadtkzinc-0bd438e81d1eee5db0cfe6316e1063cfc50fd86b.zip
tkzinc-0bd438e81d1eee5db0cfe6316e1063cfc50fd86b.tar.gz
tkzinc-0bd438e81d1eee5db0cfe6316e1063cfc50fd86b.tar.bz2
tkzinc-0bd438e81d1eee5db0cfe6316e1063cfc50fd86b.tar.xz
* (PickCurrentItem, DoEvent): Fixed a couple of problems in
Enter/Leave generation during grabs. * Fix a segfault occuring when asking for the ancestors of an unknown item. * In Contour, the contour reverting was done on the shared point array given by GetClipVertices/GetContours, not on the new unshared array. * It is now possible to add a polygonal (non simple) contour from an item that export only the GetClipVertices method. In the past it was only possible to add bounding boxes via this method. This is important for rotated rectangles for example.
Diffstat (limited to 'generic/tkZinc.c')
-rw-r--r--generic/tkZinc.c191
1 files changed, 103 insertions, 88 deletions
diff --git a/generic/tkZinc.c b/generic/tkZinc.c
index 23c4b47..0b4c53a 100644
--- a/generic/tkZinc.c
+++ b/generic/tkZinc.c
@@ -2531,15 +2531,17 @@ FindItems(ZnWInfo *wi,
if (result == TCL_ERROR) {
return TCL_ERROR;
}
- item = item->parent;
- if (argc == first+3) {
- uid = Tk_GetUid(Tcl_GetString(args[first+2]));
- }
- while (item != ZN_NO_ITEM) {
- if (!uid || ZnITEM.HasTag(item, uid)) {
- ZnDoItem(wi->interp, item, ZN_NO_PART, tag_uid);
- }
+ if (item) {
item = item->parent;
+ if (argc == first+3) {
+ uid = Tk_GetUid(Tcl_GetString(args[first+2]));
+ }
+ while (item != ZN_NO_ITEM) {
+ if (!uid || ZnITEM.HasTag(item, uid)) {
+ ZnDoItem(wi->interp, item, ZN_NO_PART, tag_uid);
+ }
+ item = item->parent;
+ }
}
}
break;
@@ -2994,6 +2996,9 @@ Contour(ZnWInfo *wi,
&controls, &num_points, NULL) == TCL_ERROR) {
return TCL_ERROR;
}
+ /*
+ * Processing contours from an explicit list.
+ */
ZnPolyContour1(&poly, NULL, num_points, False);
/*
* Allocate a fresh point array, ZnParseCoordList returns a shared
@@ -3024,6 +3029,9 @@ Contour(ZnWInfo *wi,
poly.contours[0].controls = controls;
}
else {
+ /*
+ * Processing contours from an item
+ */
if (winding_flag == 0) {
Tcl_AppendResult(wi->interp,
"Must supply an explicit winding direction (-1, 1)\nwhen adding a contour from an item",
@@ -3037,7 +3045,6 @@ Contour(ZnWInfo *wi,
Update(wi);
if (!shape->class->GetContours &&
!shape->class->GetClipVertices) {
- noshape:
Tcl_AppendResult(wi->interp, "class: \"", shape->class->name,
"\" can't give a polygonal shape", NULL);
return TCL_ERROR;
@@ -3050,11 +3057,15 @@ Contour(ZnWInfo *wi,
* shapes (i.e tose returning a bounding box).
*/
tristrip.num_strips = 0;
+ /*
+ * GetClipVertices _may_ return a tristrip describing a fan
+ * this would lead to strange results. For now, this case
+ * should not appear, the items candidates to such a behavior
+ * export a GetContours method which has higher precedence.
+ */
simple = shape->class->GetClipVertices(shape, &tristrip);
- if (!simple) {
- goto noshape;
- }
- ZnPolyContour1(&poly, tristrip.strip1.points, tristrip.strip1.num_points, False);
+ ZnPolyContour1(&poly, tristrip.strip1.points, tristrip.strip1.num_points,
+ False);
poly.contours[0].controls = NULL;
}
else {
@@ -3098,7 +3109,7 @@ Contour(ZnWInfo *wi,
poly.contours[0].controls = NULL;
}
else {
- /* Unshare the contour array */
+ /* Unshare the contour array or use the static storage */
contours = poly.contours;
if (poly.num_contours == 1) {
poly.contours = &poly.contour1;
@@ -3123,20 +3134,21 @@ Contour(ZnWInfo *wi,
* Unshare the point array.
*/
poly.contours[i].points = ZnMalloc(num_points*sizeof(ZnPoint));
-
- if (((poly.num_contours == 1) && ((winding_flag == -1) ^ cw)) ||
- ((poly.num_contours > 1) && (winding_flag == -1))) {
+ ZnTransformPoints(&inv, points, poly.contours[i].points, num_points);
+
+ if ((((poly.num_contours == 1) && ((winding_flag == -1) ^ cw)) ||
+ ((poly.num_contours > 1) && (winding_flag == -1)))) {
ZnPoint p;
-
- /* Revert and transform the coords */
+
+ revert = True;
+ /* Revert the points */
poly.contours[i].cw = ! cw;
for (j = 0, k = num_points-1; j < k; j++, k--) {
- p = points[j];
- points[j] = points[k];
- points[k] = p;
+ p = poly.contours[i].points[j];
+ poly.contours[i].points[j] = poly.contours[i].points[k];
+ poly.contours[i].points[k] = p;
}
- ZnTransformPoints(&inv, points, poly.contours[i].points, num_points);
-
+
/* Revert the controls */
if (contours[i].controls) {
for (j = 0; j < num_points; j++) {
@@ -3145,7 +3157,6 @@ Contour(ZnWInfo *wi,
}
}
else {
- ZnTransformPoints(&inv, points, poly.contours[i].points, num_points);
if (contours[i].controls) {
memcpy(poly.contours[i].controls, contours[i].controls, num_points);
}
@@ -5943,7 +5954,12 @@ Event(ClientData client_data, /* Information about widget. */
*/
static void
DoEvent(ZnWInfo *wi,
- XEvent *event)
+ XEvent *event,
+ ZnBool bind_item, /* Controls whether item bindings will trigger.
+ * Useful for Enter/Leaves between fields */
+ ZnBool bind_part) /* Controls whether part bindings will trigger.
+ * Useful for precise control of Enter/Leaves
+ * during grabs. */
{
#define NUM_STATIC 4
ClientData items[NUM_STATIC], *its;
@@ -5953,7 +5969,6 @@ DoEvent(ZnWInfo *wi,
ClientData *tag_list = NULL;
ZnItem item;
int part;
- ZnBool bind_part, bind_item;
#define BIND_ITEM(test) \
if (bind_item && (test)) { \
@@ -5992,19 +6007,12 @@ DoEvent(ZnWInfo *wi,
num = 0;
num_tags = 0;
its = items;
- bind_part = ((wi->current_part != ZN_NO_PART) &&
+ bind_part = (bind_part &&
+ (wi->current_part != ZN_NO_PART) &&
item->class->IsSensitive(item, part) &&
(wi->current_item->class->num_parts ||
wi->current_item->class->GetFieldSet));
- /*
- * This is needed to avoid generating enter and leave
- * event on items when crossing a field boundary inside
- * the item. If not bind_item we do not want to trigger
- * any binding related to the item only those pertaining
- * to the fields.
- */
- bind_item = (((event->type != EnterNotify) && (event->type != LeaveNotify)) ||
- (wi->current_item != wi->new_item));
+
/*printf("type=%s, current=%d, new=%d --> %s, currentp %d, newp %d\n",
event->type==EnterNotify?"<Enter>":
event->type==LeaveNotify?"<Leave>":
@@ -6103,10 +6111,16 @@ DoEvent(ZnWInfo *wi,
*/
static void
PickCurrentItem(ZnWInfo *wi,
- XEvent *event)
+ XEvent *event)
{
- int button_down;
+ int button_down;
+ ZnItem item;
+ ZnBool back_inside = False;
+ ZnBool grab_release = False;
+ /*printf("PickCurrent current=%d, new=%d\n",
+ wi->current_item?wi->current_item->id:0,
+ wi->new_item?wi->new_item->id:0);*/
/*
* Check whether or not a button is down. If so, we'll log entry
* and exit into and out of the current item, but not entry into
@@ -6116,7 +6130,8 @@ PickCurrentItem(ZnWInfo *wi,
button_down = wi->state
& (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
if (!button_down) {
- wi->flags &= ~ZN_LEFT_GRABBED_ITEM;
+ CLEAR(wi->flags, ZN_GRABBED_ITEM);
+ CLEAR(wi->flags, ZN_GRABBED_PART);
}
/*
@@ -6161,7 +6176,7 @@ PickCurrentItem(ZnWInfo *wi,
* Leave event handler for the old current item) then just return;
* the pending call will do everything that's needed.
*/
- if (wi->flags & ZN_REPICK_IN_PROGRESS) {
+ if (ISSET(wi->flags, ZN_REPICK_IN_PROGRESS)) {
fprintf(stderr, "PickCurrentItem recursive\n");
return;
}
@@ -6170,11 +6185,12 @@ PickCurrentItem(ZnWInfo *wi,
* A LeaveNotify event automatically means that there's no current
* object, so the check for closest item can be skipped.
*/
+ item = wi->new_item;
if (wi->pick_event.type != LeaveNotify) {
ZnPickStruct ps;
ZnReal dist;
ZnPoint p;
-
+
p.x = wi->pick_event.xcrossing.x;
p.y = wi->pick_event.xcrossing.y;
ps.point = &p;
@@ -6196,30 +6212,36 @@ PickCurrentItem(ZnWInfo *wi,
wi->new_item = ZN_NO_ITEM;
wi->new_part = ZN_NO_PART;
}
+ /*
+ * This state is needed to do a valid detection
+ * of Enter during a grab.
+ */
+ back_inside = (wi->new_item != item);
/*printf("------ PickCurrentItem current: %d %d, new %d %d\n",
wi->current_item==ZN_NO_ITEM?0:wi->current_item->id, wi->current_part,
wi->new_item==ZN_NO_ITEM?0:wi->new_item->id, wi->new_part);*/
- if ((wi->new_item == wi->current_item) && (wi->new_part == wi->current_part) &&
- !(wi->flags & ZN_LEFT_GRABBED_ITEM)) {
+ if ((wi->new_item == wi->current_item) &&
+ (wi->new_part == wi->current_part) &&
+ ISCLEAR(wi->flags, ZN_GRABBED_ITEM) &&
+ ISCLEAR(wi->flags, ZN_GRABBED_PART)) {
/*
- * Nothing to do: the current item/part hasn't changed.
+ * Nothing to do: the current item/part hasn't changed.
*/
return;
}
-
+
/*
- * Simulate a LeaveNotify event on the previous current item and
- * an EnterNotify event on the new current item. Remove the "current"
- * tag from the previous current item and place it on the new current
- * item.
+ * Simulate a LeaveNotify event on the previous current item.
+ * Remove the "current" tag from the previous current item.
*/
- if (((wi->new_item != wi->current_item) || (wi->new_part != wi->current_part)) &&
- (wi->current_item != ZN_NO_ITEM) && !(wi->flags & ZN_LEFT_GRABBED_ITEM)) {
+ if ((wi->current_item != ZN_NO_ITEM) &&
+ (((wi->new_item != wi->current_item) && ISCLEAR(wi->flags, ZN_GRABBED_ITEM)) ||
+ ((wi->new_part != wi->current_part) && ISCLEAR(wi->flags, ZN_GRABBED_PART)))) {
XEvent event;
- ZnItem item = wi->current_item;
-
+
+ item = wi->current_item;
event = wi->pick_event;
event.type = LeaveNotify;
@@ -6230,9 +6252,10 @@ PickCurrentItem(ZnWInfo *wi,
* always use NotifyAncestor.
*/
event.xcrossing.detail = NotifyAncestor;
- wi->flags |= ZN_REPICK_IN_PROGRESS;
- DoEvent(wi, &event);
- wi->flags &= ~ZN_REPICK_IN_PROGRESS;
+ SET(wi->flags, ZN_REPICK_IN_PROGRESS);
+ DoEvent(wi, &event,
+ wi->new_item != wi->current_item, ISCLEAR(wi->flags, ZN_GRABBED_PART));
+ CLEAR(wi->flags, ZN_REPICK_IN_PROGRESS);
/*
* The check on item below is needed because there could be an
@@ -6248,40 +6271,31 @@ PickCurrentItem(ZnWInfo *wi,
* item was deleted.
*/
}
- if (((wi->new_item != wi->current_item) ||
- (wi->new_part != wi->current_part)) && button_down) {
- wi->flags |= ZN_LEFT_GRABBED_ITEM;
- return;
- }
/*
* Special note: it's possible that wi->new_item == wi->current_item
- * here. This can happen, for example, if ZN_LEFT_GRABBED_ITEM was set or
+ * here. This can happen, for example, if a grab was set or
* if there is only a change in the part number.
*/
- wi->flags &= ~ZN_LEFT_GRABBED_ITEM;
-
- /*
- * Tentative pour éviter d'enlever puis de remettre
- * le tag current sur le même item en ces de changement
- * de partie. Ca marche pas pour l'instant.
- if (wi->current_item != wi->new_item) {
- if (wi->current_item != ZN_NO_ITEM) {
- printf("vvv Removing 'current' from %d\n", wi->current_item->id);
- ZnITEM.RemoveTag(wi->current_item, current_uid);
- }
- }*/
- {
- ZnItem it = wi->current_item;
-
+ if ((wi->new_item != wi->current_item) && button_down) {
+ SET(wi->flags, ZN_GRABBED_ITEM);
+ }
+ else {
+ grab_release = ISSET(wi->flags, ZN_GRABBED_ITEM);
+ CLEAR(wi->flags, ZN_GRABBED_ITEM);
wi->current_item = wi->new_item;
+ }
+ if ((wi->new_part != wi->current_part) && button_down) {
+ SET(wi->flags, ZN_GRABBED_PART);
+ }
+ else {
+ CLEAR(wi->flags, ZN_GRABBED_PART);
wi->current_part = wi->new_part;
- /*
- * Added to enable DoEvent to make a special case for enter/leaves
- * between fields in the same item. It may interact with
- * ZN_LEFT_GRABBED_ITEM.
- */
- wi->new_item = it;
+ }
+
+ if (!grab_release &&
+ (ISSET(wi->flags, ZN_GRABBED_PART) || ISSET(wi->flags, ZN_GRABBED_ITEM))) {
+ return;
}
if (wi->current_item != ZN_NO_ITEM) {
@@ -6298,7 +6312,8 @@ PickCurrentItem(ZnWInfo *wi,
event = wi->pick_event;
event.type = EnterNotify;
event.xcrossing.detail = NotifyAncestor;
- DoEvent(wi, &event);
+ DoEvent(wi, &event,
+ back_inside, !(grab_release && ISSET(wi->flags, ZN_GRABBED_PART)));
}
}
@@ -6380,7 +6395,7 @@ Bind(ClientData client_data, /* Information about widget. */
PickCurrentItem(wi, event);
wi->state ^= mask;
if (wi->current_item != ZN_NO_ITEM) {
- DoEvent(wi, event);
+ DoEvent(wi, event, True, True);
}
}
else {
@@ -6390,7 +6405,7 @@ Bind(ClientData client_data, /* Information about widget. */
* item under the assumption that the button is no longer down.
*/
wi->state = event->xbutton.state;
- DoEvent(wi, event);
+ DoEvent(wi, event, True, True);
event->xbutton.state ^= mask;
wi->state = event->xbutton.state;
PickCurrentItem(wi, event);
@@ -6428,7 +6443,7 @@ Bind(ClientData client_data, /* Information about widget. */
PickCurrentItem(wi, event);
}
- DoEvent(wi, event);
+ DoEvent(wi, event, True, True);
done:
Tcl_Release((ClientData) wi);