aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/Group.c292
1 files changed, 192 insertions, 100 deletions
diff --git a/generic/Group.c b/generic/Group.c
index db9aecc..4eb356d 100644
--- a/generic/Group.c
+++ b/generic/Group.c
@@ -81,6 +81,9 @@ static ZnAttrConfig group_attrs[] = {
{ ZN_CONFIG_ITEM, "-clip", NULL,
Tk_Offset(GroupItemStruct, clip), 0,
ZN_COORDS_FLAG|ZN_ITEM_FLAG, False },
+ { ZN_CONFIG_BOOL, "-composealpha", NULL,
+ Tk_Offset(GroupItemStruct, header.flags), COMPOSE_ALPHA_BIT,
+ ZN_DRAW_FLAG, False },
{ ZN_CONFIG_BOOL, "-composerotation", NULL,
Tk_Offset(GroupItemStruct, header.flags), COMPOSE_ROTATION_BIT,
ZN_TRANSFO_FLAG, False },
@@ -93,7 +96,7 @@ static ZnAttrConfig group_attrs[] = {
{ ZN_CONFIG_BOOL, "-sensitive", NULL,
Tk_Offset(GroupItemStruct, header.flags), SENSITIVE_BIT,
ZN_REPICK_FLAG, False },
- { ZN_CONFIG_TAGS, "-tags", NULL,
+ { ZN_CONFIG_TAG_LIST, "-tags", NULL,
Tk_Offset(GroupItemStruct, header.tags), 0, 0, False },
{ ZN_CONFIG_BOOL, "-visible", NULL,
Tk_Offset(GroupItemStruct, header.flags), VISIBLE_BIT,
@@ -124,6 +127,7 @@ Init(Item item,
group->dependents = NULL;
SET(item->flags, VISIBLE_BIT);
SET(item->flags, SENSITIVE_BIT);
+ SET(item->flags, COMPOSE_ALPHA_BIT);
SET(item->flags, COMPOSE_ROTATION_BIT);
SET(item->flags, COMPOSE_SCALE_BIT);
CLEAR(item->flags, ATOMIC_BIT);
@@ -757,85 +761,135 @@ ComputeCoordinates(Item item,
*/
static int
ToArea(Item item,
- ZnBBox *area,
- Tk_Uid tag_uid,
- int enclosed,
- ZnBool report)
+ ZnToArea ta)
{
GroupItem group = (GroupItem) item;
Item current_item;
ZnBBox enclosing, inter;
- int result;
- ZnBool outside = True;
+ int result = -1;
+ ZnBool outside, inside;
ZnBool atomic = ISSET(item->flags, ATOMIC_BIT);
+ ZnBool report, empty = True;
+ /*
+ * If this group is ATOMIC, ask the child groups to report
+ * instead of adding their children to the result.
+ */
+ report = ta->report;
+ ta->report |= atomic;
+
PushTransform(item);
- enclosing.orig.x = area->orig.x - 1;
- enclosing.orig.y = area->orig.y - 1;
- enclosing.corner.x = area->corner.x + 1;
- enclosing.corner.y = area->corner.y + 1;
+ /*
+ * Is this group the target group ?
+ */
+ if ((ta->in_group != ZN_NO_ITEM) && (ta->in_group != item)) {
+ /* No, try the subgroups. */
+ for (current_item = group->head;
+ current_item != ZN_NO_ITEM;
+ current_item = current_item->next) {
+ if (current_item->class != ZnGroup) {
+ continue;
+ }
+ result = current_item->class->ToArea(current_item, ta);
+ if (ta->in_group == ZN_NO_ITEM) {
+ /* The target group has been found, return its result. */
+ goto out;
+ }
+ }
+ /* No group found in this subtree. */
+ goto out;
+ }
+ /*
+ * At this point we are either in the target group
+ * or one of its sub-groups. If in the target group,
+ * erase the target in the call struct to remember
+ * the fact.
+ */
+ if (ta->in_group == item) {
+ ta->in_group = ZN_NO_ITEM;
+ }
+ enclosing.orig.x = ta->area->orig.x - 1;
+ enclosing.orig.y = ta->area->orig.y - 1;
+ enclosing.corner.x = ta->area->corner.x + 1;
+ enclosing.corner.y = ta->area->corner.y + 1;
- current_item = group->head;
- while (current_item != ZN_NO_ITEM) {
+ outside = inside = True;
+ /*
+ * Process each item and proceed with subtrees if
+ * asked for by the recursive flag.
+ */
+ for (current_item = group->head;
+ current_item != ZN_NO_ITEM;
+ current_item = current_item->next) {
if (ISCLEAR(current_item->flags, VISIBLE_BIT) &&
ISCLEAR(current_item->flags, SENSITIVE_BIT)) {
- goto cont_ta;
+ continue;
}
IntersectBBox(&enclosing, &current_item->item_bounding_box, &inter);
if (IsEmptyBBox(&inter)) {
- goto cont_ta;
+ continue;
}
if (current_item->class != ZnGroup) {
PushTransform(current_item);
}
+ if ((current_item->class != ZnGroup) || atomic || ta->recursive) {
+ result = current_item->class->ToArea(current_item, ta);
+ outside &= (result == -1);
+ inside &= (result == 1);
+ empty = False;
- /*
- * If this group is ATOMIC, ask the child groups to report
- * instead of adding their children to the result.
- */
- result = current_item->class->ToArea(current_item, area, tag_uid,
- enclosed, atomic);
- outside &= (result == -1);
- /*
- * If this group is ATOMIC, it must report itself as matching
- * if a/ the request is 'enclosed' and all the children are
- * enclosed or b/ the request is 'overlapping' and at least one
- * child overlaps (or is enclosed). If not ATOMIC, the group
- * never match the area.
- * So here we can do early tests to shortcut the search when
- * the most stringent conditions are met.
- */
- if (atomic) {
- if (!enclosed && (result >= 0)) {
- result = 0;
- goto out;
- } else if (enclosed && (result == 0)) {
- goto out;
+ /*
+ * If this group is ATOMIC, it must report itself as matching
+ * if a/ the request is 'enclosed' and all the children are
+ * enclosed or b/ the request is 'overlapping' and at least one
+ * child overlaps (or is enclosed).
+ * So here we can do early tests to shortcut the search when
+ * the most stringent conditions are met.
+ */
+ if (atomic) {
+ if (!ta->enclosed && (result >= 0)) {
+ result = 0;
+ goto out;
+ } else if (ta->enclosed && (result == 0)) {
+ goto out;
+ }
+ }
+ if (!ta->report && (result >= ta->enclosed)) {
+ ZnDoItem(item->wi->interp, current_item, ZN_NO_PART, ta->tag_uid);
}
}
- if (!atomic && (result >= enclosed)) {
- ZnDoItem(item->wi->interp, current_item, ZN_NO_PART, tag_uid);
- }
-
if (current_item->class != ZnGroup) {
PopTransform(current_item);
}
- cont_ta:
- current_item = current_item->next;
}
- if (!atomic) {
- result = -1;
- }
- else if (outside) {
- result = -1;
+ /*
+ * If there are no items or only sub-groups in this group and
+ * the search is not recursive we must report outside.
+ */
+ if (empty) {
+ result = -1;
}
else {
- result = 1;
+ if (atomic) {
+ result = outside ? -1 : 1;
+ }
+ else if (ta->report) { /* Need to report matching children to ancestor */
+ if (outside && inside) {
+ result = 0;
+ }
+ else {
+ result = outside ? -1 : 1;
+ }
+ }
+ else {
+ result = -1;
+ }
}
-
- out:
+
+ out:
+ ta->report = report;
PopTransform(item);
return result;
}
@@ -926,9 +980,16 @@ Render(Item item)
ZnBBox bbox, old_damaged_area;
#endif
unsigned char save_alpha = wi->alpha;
+ unsigned char save_alpha2;
+
+ if (ISSET(item->flags, COMPOSE_ALPHA_BIT)) {
+ wi->alpha = wi->alpha * group->alpha / 100;
+ }
+ else {
+ wi->alpha = group->alpha;
+ }
+ save_alpha2 = wi->alpha;
- wi->alpha = wi->alpha * group->alpha / 100;
-
PushTransform(item);
PushClip(group, True);
#ifdef GLX_DAMAGE
@@ -949,10 +1010,14 @@ Render(Item item)
#endif
if (current_item->class != ZnGroup) {
PushTransform(current_item);
+ if (ISCLEAR(current_item->flags, COMPOSE_ALPHA_BIT)) {
+ wi->alpha = 100;
+ }
}
current_item->class->Render(current_item);
if (current_item->class != ZnGroup) {
PopTransform(current_item);
+ wi->alpha = save_alpha2;
}
#ifdef GLX_DAMAGE
}
@@ -1020,22 +1085,19 @@ IsSensitive(Item item,
*/
static double
Pick(Item item,
- ZnPoint *p,
- Item start_item,
- int aperture,
- Item *a_item,
- int *a_part)
+ ZnPick ps)
{
GroupItem group = (GroupItem) item;
Item p_item, current_item;
WidgetInfo *wi = item->wi;
- int p_part;
+ int p_part, aperture = ps->aperture;
double dist, best = 1e10;
ZnBBox bbox, inter, *clip_box;
- ZnBool in_depth;
-
- *a_item= ZN_NO_ITEM;
- *a_part = ZN_NO_PART;
+ ZnPoint *p = ps->point;
+ ZnBool atomic;
+
+ ps->a_item= ZN_NO_ITEM;
+ ps->a_part = ZN_NO_PART;
if (group->head == ZN_NO_ITEM) {
return best;
@@ -1044,6 +1106,37 @@ Pick(Item item,
PushTransform(item);
PushClip(group, False);
+ /*
+ * Is this group the target group ?
+ */
+ if ((ps->in_group != ZN_NO_ITEM) && (ps->in_group != item)) {
+ /* No, try the subgroups. */
+ for (current_item = group->head;
+ current_item != ZN_NO_ITEM;
+ current_item = current_item->next) {
+ if (current_item->class != ZnGroup) {
+ continue;
+ }
+ best = current_item->class->Pick(current_item, ps);
+ if (ps->in_group == ZN_NO_ITEM) {
+ /* The target group has been found, return its result. */
+ goto out;
+ }
+ }
+ /* No group found in this subtree. */
+ goto out;
+ }
+
+ /*
+ * At this point we are either in the target group
+ * or one of its sub-groups. If in the target group,
+ * erase the target in the call struct to remember
+ * the fact.
+ */
+ if (ps->in_group == item) {
+ ps->in_group = ZN_NO_ITEM;
+ }
+
bbox.orig.x = p->x - aperture;
bbox.orig.y = p->y - aperture;
bbox.corner.x = p->x + (aperture?aperture:1);
@@ -1056,20 +1149,10 @@ Pick(Item item,
}
}
- if ((start_item == ZN_NO_ITEM) || (start_item->parent == item)) {
- in_depth = False;
- }
- else {
- in_depth = True;
- }
- if ((start_item == ZN_NO_ITEM) || (start_item->parent != item)) {
- current_item = group->head;
- }
- else {
- current_item = start_item;
- }
-
- do {
+ current_item = (ps->start_item == ZN_NO_ITEM) ? group->head : ps->start_item;
+ atomic = ISSET(item->flags, ATOMIC_BIT);
+
+ for ( ; current_item != ZN_NO_ITEM; current_item = current_item->next) {
/*
* Sensitive item must be reported even if they are invisible.
* It is legal to fire bindings on invisible sensitive items.
@@ -1077,46 +1160,47 @@ Pick(Item item,
*/
if (ISCLEAR(current_item->flags, SENSITIVE_BIT) &&
ISCLEAR(current_item->flags, VISIBLE_BIT)) {
- goto cont;
+ continue;
}
if (current_item->class != ZnGroup) {
- if (in_depth) {
- goto cont;
- }
PushTransform(current_item);
- p_item = current_item;
- p_part = ZN_NO_PART;
- dist = current_item->class->Pick(current_item, p, NULL, 0,
- &p_item, &p_part);
+ p_item = ps->a_item;
+ p_part = ps->a_part;
+ ps->a_item = current_item;
+ ps->a_part = ZN_NO_PART;
+ dist = current_item->class->Pick(current_item, ps);
dist -= aperture;
PopTransform(current_item);
}
+ else if (!atomic && !ps->recursive) {
+ continue;
+ }
else {
- dist = current_item->class->Pick(current_item, p,
- in_depth ? start_item : NULL,
- aperture, &p_item, &p_part);
+ dist = current_item->class->Pick(current_item, ps);
}
if (dist < 0.0) {
dist = 0.0;
}
if (dist >= best) {
- goto cont;
- }
- if (ISSET(item->flags, ATOMIC_BIT)) {
- *a_item = item;
+ /* Not a good one, restore the previous best and try again. */
+ ps->a_item = p_item;
+ ps->a_part = p_part;
+ continue;
}
- else {
- *a_item = p_item;
- *a_part = p_part;
+ if (atomic) {
+ /* If ATOMIC, this group is the item to be reported. */
+ ps->a_item = item;
+ ps->a_part = ZN_NO_PART;
}
+
best = dist;
- /*printf("found %d:%d, at %g\n", (*a_item)->id, *a_part, dist);*/
+ /*printf("found %d:%d, at %g\n", (ps->a_item)->id, ps->a_part, dist);*/
if (dist == 0.0) {
+ /* No need to look further, the item found is the topmost
+ * closest. */
break;
}
- cont:
- current_item = current_item->next;
- } while (current_item != ZN_NO_ITEM);
+ }
out:
PopClip(group, False);
@@ -1215,6 +1299,15 @@ ZnGroupCallOm(Item group)
return ((GroupItem) group)->call_om;
}
+ZnBool
+ZnGroupAtomic(Item group)
+{
+ if (group->class != ZnGroup) {
+ return True;
+ }
+ return ISSET(group->flags, ATOMIC_BIT);
+}
+
void
ZnGroupSetCallOm(Item group,
ZnBool set)
@@ -1463,7 +1556,6 @@ ZnGroupInsertItem(Item group,
*/
static ItemClassStruct GROUP_ITEM_CLASS = {
sizeof(GroupItemStruct),
- False, /* has_fields */
0, /* num_parts */
False, /* has_anchors */
"group",