diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/Group.c | 292 |
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, ¤t_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", |