From 960cdf29197bc3f5922110cf26627aa9709ac79b Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Fri, 10 Jun 2005 10:29:11 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'bogue40'. --- generic/Group.c | 1781 ------------------------------------------------------- 1 file changed, 1781 deletions(-) delete mode 100644 generic/Group.c (limited to 'generic/Group.c') diff --git a/generic/Group.c b/generic/Group.c deleted file mode 100644 index 1f6a183..0000000 --- a/generic/Group.c +++ /dev/null @@ -1,1781 +0,0 @@ -/* - * Group.c -- Implementation of Group item. - * - * Authors : Patrick Lecoanet. - * Creation date : Wed Jun 23 10:09:20 1999 - * - * $Id$ - */ - -/* - * Copyright (c) 1999 - 2005 CENA, Patrick Lecoanet -- - * - * See the file "Copyright" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - */ - - -#include "Types.h" -#include "WidgetInfo.h" -#include "Item.h" -#include "Group.h" -#include "Geo.h" -#include "tkZinc.h" - -#ifndef _WIN32 -#include -#endif - - -static const char rcsid[] = "$Id$"; -static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; - - -/* - * Group item special record. - */ -typedef struct _GroupItemStruct { - ZnItemStruct header; - - /* Public data */ - ZnItem clip; - unsigned char alpha; - - /* Private data */ - ZnItem head; /* Doubly linked list of all items. */ - ZnItem tail; - ZnList dependents; /* List of dependent items. */ -#ifdef ATC - /* Overlap manager variables. - * These variables are valid *only* if the overlap - * manager is active. */ - ZnBool call_om; /* Tell if there is a need to call the */ - /* overlap manager. */ -#endif -} GroupItemStruct, *GroupItem; - - -#define ATOMIC_BIT (1<head = ZN_NO_ITEM; - group->tail = ZN_NO_ITEM; - group->clip = ZN_NO_ITEM; - group->alpha = 100; - group->dependents = NULL; - SET(item->flags, ZN_VISIBLE_BIT); - SET(item->flags, ZN_SENSITIVE_BIT); - SET(item->flags, ZN_COMPOSE_ALPHA_BIT); - SET(item->flags, ZN_COMPOSE_ROTATION_BIT); - SET(item->flags, ZN_COMPOSE_SCALE_BIT); - CLEAR(item->flags, ATOMIC_BIT); - item->priority = 1; -#ifdef ATC - group->call_om = False; -#endif - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * Clone -- - * - ********************************************************************************** - */ -static void -Clone(ZnItem item) -{ - GroupItem group = (GroupItem) item; - ZnList dependents; - ZnItem connected, current_item, new_item; - ZnItem *items; - Tcl_HashTable mapping; - Tcl_HashEntry *entry; - int new, num_items, i; - - if (item == item->wi->top_group) { - /* Do not try to clone the top group */ - return; - } - - current_item = group->tail; - group->head = group->tail = ZN_NO_ITEM; -#ifdef ATC - group->call_om = False; -#endif - dependents = group->dependents; - if (dependents) { - Tcl_InitHashTable(&mapping, TCL_ONE_WORD_KEYS); - } - - /* - * First clone all the children, and build a mapping - * table if there is some attachments to relink. - */ - while (current_item != ZN_NO_ITEM) { - connected = current_item->connected_item; - new_item = ZnITEM.CloneItem(current_item); - new_item->connected_item = connected; - ZnITEM.InsertItem(new_item, item, ZN_NO_ITEM, True); - - if (dependents) { - entry = Tcl_CreateHashEntry(&mapping, (char *) current_item, &new); - Tcl_SetHashValue(entry, (ClientData) new_item); - } - if (current_item == group->clip) { - group->clip = new_item; - } - current_item = current_item->previous; - } - - /* - * Then rebuild the dependency list with - * the new items. - */ - if (dependents) { - /*printf("rebuilding dependents\n");*/ - group->dependents = NULL; - items = (ZnItem *) ZnListArray(dependents); - num_items = ZnListSize(dependents); - for (i = 0; i < num_items; i++, items++) { - entry = Tcl_FindHashEntry(&mapping, (char *) *items); - if (entry == NULL) { - ZnWarning("Can't find item correspondance in Group Clone\n"); - abort(); - } - else { - current_item = (ZnItem) Tcl_GetHashValue(entry); - } - entry = Tcl_FindHashEntry(&mapping, (char *) current_item->connected_item); - if (entry == NULL) { - ZnWarning("Can't found item correspondance in Group Clone\n"); - abort(); - } - else { - /*printf("item %d correspond to ", current_item->connected_item->id);*/ - current_item->connected_item = (ZnItem) Tcl_GetHashValue(entry); - /*printf("%d\n", current_item->connected_item->id);*/ - ZnInsertDependentItem(current_item); - } - } - Tcl_DeleteHashTable(&mapping); - } -} - - -/* - ********************************************************************************** - * - * Destroy -- - * - ********************************************************************************** - */ -static void -Destroy(ZnItem item) -{ - GroupItem group = (GroupItem) item; - ZnItem current_item, next_item; - - current_item = group->head; - while (current_item != ZN_NO_ITEM) { - next_item = current_item->next; - ZnITEM.DestroyItem(current_item); - current_item = next_item; - } - if (group->dependents) { - ZnListFree(group->dependents); - } -} - - -/* - ********************************************************************************** - * - * SetXShape -- - * - ********************************************************************************** - */ -#if defined(SHAPE) && !defined(_WIN32) -static void -SetXShape(ZnItem grp) -{ - ZnWInfo *wi = grp->wi; - ZnItem clip = ((GroupItem) grp)->clip; - unsigned int i, j, num_pts, max_num_pts; - ZnPos min_x, min_y, max_x, max_y; - ZnTriStrip tristrip; - ZnPoint *p; - ZnBool simple; - ZnDim width, height; - XPoint xpts[3], *xp2, *xpts2; - TkRegion reg, reg_op, reg_to; - - if (ISCLEAR(wi->flags, ZN_HAS_X_SHAPE)) { - return; - } - - if ((clip == ZN_NO_ITEM) || !wi->reshape) { - /* - * Reset both clip just to be sure (the application can have - * changed wi->full_reshape while resetting wi->reshape). - */ - XShapeCombineMask(wi->dpy, Tk_WindowId(wi->win), ShapeBounding, - 0, 0, None, ShapeSet); - XShapeCombineMask(wi->dpy, wi->real_top, ShapeBounding, - 0, 0, None, ShapeSet); - } - else { - /* - * Get the clip shape. - */ - tristrip.num_strips = 0; - simple = clip->class->GetClipVertices(clip, &tristrip); - if (simple || (tristrip.num_strips == 0)) { - /* - * Nothing to do: after normalisation the rectangular shape will - * fit exactly the window. We may test here if a shape is currently - * active and reset the mask only in this case (need a flag in wi). - */ - XShapeCombineMask(wi->dpy, Tk_WindowId(wi->win), ShapeBounding, - 0, 0, None, ShapeSet); - XShapeCombineMask(wi->dpy, wi->real_top, ShapeBounding, - 0, 0, None, ShapeSet); - } - else { - /* - * First make the vertices start at zero. - * In case of a fan we benefit from the fact that - * ALL the contour vertices are included in - * the tristrip, so we dont need to consider the - * center (arc in pie slice mode). - */ - max_x = min_x = tristrip.strips[0].points[0].x; - max_y = min_y = tristrip.strips[0].points[0].y; - max_num_pts = tristrip.strips[0].num_points; - for (j = 0; j < tristrip.num_strips; j++) { - p = tristrip.strips[j].points; - num_pts = tristrip.strips[j].num_points; - if (num_pts > max_num_pts) { - max_num_pts = num_pts; - } - for (i = 0; i < num_pts; p++, i++) { - if (p->x < min_x) { - min_x = p->x; - } - if (p->y < min_y) { - min_y = p->y; - } - if (p->x > max_x) { - max_x = p->x; - } - if (p->y > max_y) { - max_y = p->y; - } - } - } - max_x -= min_x; - max_y -= min_y; - XShapeCombineMask(wi->dpy, wi->full_reshape?Tk_WindowId(wi->win):wi->real_top, - ShapeBounding, 0, 0, None, ShapeSet); - reg = TkCreateRegion(); - - /* - * Now normalize the shape and map it to the window size, - * then Translate it in a region and apply this region to - * the window. - */ - width = wi->width; - height = wi->height; - for (j = 0; j < tristrip.num_strips; j++) { - p = tristrip.strips[j].points; - num_pts = tristrip.strips[j].num_points; - - /* - * In case of a fan we benefit from the fact that - * ALL the contour vertices are included in - * the tristrip, so we can use the corresponding - * polygon instead of going through all the triangles. - */ - if (tristrip.strips[j].fan) { - /* Skip the center */ - p++; - num_pts--; - xp2 = xpts2 = ZnMalloc(num_pts*sizeof(XPoint)); - for (i = 0 ; i < num_pts; i++, p++, xp2++) { - xp2->x = (short) ((p->x - min_x) * width / max_x); - xp2->y = (short) ((p->y - min_y) * height / max_y); - } - reg_op = ZnPolygonRegion(xpts2, num_pts, EvenOddRule); - reg_to = TkCreateRegion(); - ZnUnionRegion(reg, reg_op, reg_to); - TkDestroyRegion(reg); - TkDestroyRegion(reg_op); - reg = reg_to; - ZnFree(xpts2); - } - else { - xpts[0].x = (short) ((p->x - min_x) * width / max_x); - xpts[0].y = (short) ((p->y - min_y) * height / max_y); - p++; - xpts[1].x = (short) ((p->x - min_x) * width / max_x); - xpts[1].y = (short) ((p->y - min_y) * height / max_y); - p++; - for (i = 2 ; i < num_pts; i++, p++) { - xpts[2].x = (short) ((p->x - min_x) * width / max_x); - xpts[2].y = (short) ((p->y - min_y) * height / max_y); - reg_op = ZnPolygonRegion(xpts, 3, EvenOddRule); - reg_to = TkCreateRegion(); - ZnUnionRegion(reg, reg_op, reg_to); - TkDestroyRegion(reg); - TkDestroyRegion(reg_op); - reg = reg_to; - xpts[0] = xpts[1]; - xpts[1] = xpts[2]; - } - } - } - XShapeCombineRegion(wi->dpy, wi->full_reshape?wi->real_top:Tk_WindowId(wi->win), - ShapeBounding, 0, 0, (Region) reg, ShapeSet); - TkDestroyRegion(reg); - } - } -} -#else -static void -SetXShape(ZnItem grp) -{ -} -#endif - - -/* - ********************************************************************************** - * - * Configure -- - * - ********************************************************************************** - */ -static int -Configure(ZnItem item, - int argc, - Tcl_Obj *CONST argv[], - int *flags) -{ - GroupItem group = (GroupItem) item; - ZnWInfo *wi = item->wi; - - if (ZnConfigureAttributes(wi, item, item, group_attrs, argc, argv, flags) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * If the clip item changed, check if it is a legal - * item type that is inside this group. - */ - if (ISSET(*flags, ZN_ITEM_FLAG)) { - if (group->clip && - (!group->clip->class->GetClipVertices || (group->clip->parent != item))) { - group->clip = ZN_NO_ITEM; - Tcl_AppendResult(wi->interp, - " clip item must be a child of the group", NULL); - return TCL_ERROR; - } - if (!group->clip && (item == wi->top_group)) { - SetXShape(item); - } - } - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * Query -- - * - ********************************************************************************** - */ -static int -Query(ZnItem item, - int argc, - Tcl_Obj *CONST argv[]) -{ - if (ZnQueryAttribute(item->wi->interp, item, group_attrs, argv[0]) == TCL_ERROR) { - return TCL_ERROR; - } - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * PushClip -- - * Save the current clip shape and current clipbox if needed. - * Intersect the previous shape and the local to obtain the - * new current shape. Use this shape to compute the current - * clipbox and if set_gc is True compute the current region. - * - ********************************************************************************** - */ -static void -PushClip(GroupItem group, - ZnBool set_gc) -{ - ZnWInfo *wi = ((ZnItem) group)->wi; - ZnTriStrip tristrip; - ZnBool simple; - - if ((group->clip != ZN_NO_ITEM) && - ((((ZnItem) group) != wi->top_group) -#if defined(SHAPE) && ! defined (_WIN32) - || !wi->reshape -#endif - )) { - simple = group->clip->class->GetClipVertices(group->clip, &tristrip); - /*printf("Group: PushClip group %d\n", ((ZnItem) group)->id);*/ - if (tristrip.num_strips) { - ZnPushClip(wi, &tristrip, simple, set_gc); - } - } -} - - -/* - ********************************************************************************** - * - * PopClip -- - * Re-install the previous clip shape if any (stack can be empty). - * - ********************************************************************************** - */ -static void -PopClip(GroupItem group, - ZnBool set_gc) -{ - ZnWInfo *wi = ((ZnItem) group)->wi; - - if ((group->clip != ZN_NO_ITEM) && - ((((ZnItem) group) != wi->top_group) -#if defined(SHAPE) && !defined(_WIN32) - || !wi->reshape -#endif - )) { - /*printf("Group: PopClip group %d\n", ((ZnItem) group)->id);*/ - ZnPopClip(wi, set_gc); - } -} - - -/* - ********************************************************************************** - * - * PushTransform -- - * Save the current transform then concatenate the item transform to - * form the new current transform. - * - ********************************************************************************** - */ -static void -PushTransform(ZnItem item) -{ - ZnPoint *pos; - - pos = NULL; - if (item->class->pos_offset >= 0) { - pos = (ZnPoint *) (((char *) item) + item->class->pos_offset); - if (pos->x == 0 && pos->y == 0) { - pos = NULL; - } - } - if (!item->transfo && - !pos && - ISSET(item->flags, ZN_COMPOSE_SCALE_BIT) && - ISSET(item->flags, ZN_COMPOSE_ROTATION_BIT)) { - return; - } - - ZnPushTransform(item->wi, item->transfo, pos, - ISSET(item->flags, ZN_COMPOSE_SCALE_BIT), - ISSET(item->flags, ZN_COMPOSE_ROTATION_BIT)); - /*printf("Pushing transfo for item: %d\n;", item->id); - ZnPrintTransfo(wi->current_transfo);*/ -} - - -/* - ********************************************************************************** - * - * PopTransform -- - * Restore the previously saved transform from the stack. - * - ********************************************************************************** - */ -static void -PopTransform(ZnItem item) -{ - ZnPoint *pos; - - pos = NULL; - if (item->class->pos_offset >= 0) { - pos = (ZnPoint *) (((char *) item) + item->class->pos_offset); - if (pos->x == 0 && pos->y == 0) { - pos = NULL; - } - } - if (!item->transfo && - !pos && - ISSET(item->flags, ZN_COMPOSE_SCALE_BIT) && - ISSET(item->flags, ZN_COMPOSE_ROTATION_BIT)) { - return; - } - - ZnPopTransform(item->wi); - /*printf("Popping transfo for item: %d\n", item->id); - ZnPrintTransfo(wi->current_transfo);*/ -} - - -/* - ********************************************************************************** - * - * ComputeCoordinates -- - * Compute the geometrical elements of a group. First of all save the current - * transform and combine it with the item transform. Then call the item - * ComputeCoordinates method. - * For regular child items (not groups) some of the code of the item - * itself is factored out in CallRegularCC. - * - ********************************************************************************** - */ -static void -CallRegularCC(ZnItem item) -{ - ZnWInfo *wi = item->wi; - /*ZnBBox *clip_box;*/ - - /* - * Do some generic pre-work in behalf of the (regular) children. - */ - if (ISSET(item->flags, ZN_VISIBLE_BIT)) { - ZnDamage(wi, &item->item_bounding_box); - } - PushTransform(item); - - /*printf("calling cc on regular item %d\n", item->id);*/ - /*ZnPrintTransfo(wi->current_transfo);*/ - item->class->ComputeCoordinates(item, False); - /* - * If a current clipbox exists adjust the item - * bounding box accordingly. When computing coordinates - * the damaged area is not pushed onto the clipstack, - * the following predicate is thus valid for testing - * a clipbox. - */ - /* Tue Nov 14 15:21:05 2000 Suppressed to have a real - bbox to align tiles (i.e if an object is larger than - its enclosing clipping, the bbox is equal to the clip - area and the tiling will not move with the object until - it partially uncovered the clip area. - Have to watch any possible breakage. - - if (ZnCurrentClip(wi, NULL, &clip_box, NULL)) { - ZnBBox inter; - - ZnIntersectBBox(&item->item_bounding_box, clip_box, &inter); - item->item_bounding_box = inter; - }*/ - /* - * Do some generic post-work in behalf of the (regular) children. - */ -#ifdef GL -#ifdef GL_LIST - /* - * Remove the item display list so that it will be recreated - * to reflect the changes. - */ - if (item->gl_list) { - glDeleteLists(item->gl_list, 1); - item->gl_list = 0; - } -#endif -#endif - if (ISSET(item->inv_flags, ZN_REPICK_FLAG)) { - SET(wi->flags, ZN_INTERNAL_NEED_REPICK); - } - if (ISSET(item->inv_flags, ZN_COORDS_FLAG) && - (ISSET(item->flags, ZN_SENSITIVE_BIT) || - ISSET(item->flags, ZN_VISIBLE_BIT))) { - SET(wi->flags, ZN_INTERNAL_NEED_REPICK); - } - /* - * Damage if the item is visible or if it is - * a group clipper. - */ - if (ISSET(item->flags, ZN_VISIBLE_BIT) || - (item == ((GroupItem) item->parent)->clip)) { - ZnDamage(wi, &item->item_bounding_box); - } - PopTransform(item); - item->inv_flags = 0; - /*printf("Done cc on regular item %d\n", item->id);*/ -} - -static void -ComputeCoordinates(ZnItem item, - ZnBool force) -{ - GroupItem group = (GroupItem) item; - ZnItem current_item; - ZnItem *deps; - int num_deps, i; - ZnBBox *clip_box; - - PushTransform(item); - /* printf("Group.c\n"); - ZnPrintTransfo(item->wi->current_transfo); - printf("\n");*/ - - force |= ISSET(item->inv_flags, ZN_TRANSFO_FLAG); - - /* - * If the clip item changed or there is no clip anymore - * force an update. - */ - force |= ISSET(item->inv_flags, ZN_ITEM_FLAG); - - /* - * Clip shape is computed in the group's local - * coordinates. - */ - if (group->clip != ZN_NO_ITEM) { - /* - * Update the geometry of the clip item if needed. - * Its bounding box will be clipped by the current - * clipbox (i.e the clipbox of the group's parent). - */ - if (force || - ISSET(group->clip->inv_flags, ZN_COORDS_FLAG) || - ISSET(group->clip->inv_flags, ZN_TRANSFO_FLAG)) { - /*printf("calling cc on clip item %d for group %d\n", - group->clip->id, item->id);*/ - CallRegularCC(group->clip); - if (item == item->wi->top_group) { - SetXShape(item); - } - /* - * If the clip item has changed we need to compute - * new clipped bounding boxes for all the children. - */ - force = True; - } - } - - PushClip(group, False); - - for (current_item = group->head; current_item != ZN_NO_ITEM; - current_item = current_item->next) { - /* - * Skip the clip item, it has been already updated. - * Skip as well items with a dependency, they will - * be updated later. - */ - if ((current_item == group->clip) || - (current_item->connected_item != ZN_NO_ITEM)) { - continue; - } - if (force || - ISSET(current_item->inv_flags, ZN_COORDS_FLAG) || - ISSET(current_item->inv_flags, ZN_TRANSFO_FLAG)) { - if (current_item->class != ZnGroup) { - /*printf("calling cc on item %d\n", current_item->id);*/ - CallRegularCC(current_item); - } - else { - /*printf("calling cc on group %d\n", current_item->id);*/ - current_item->class->ComputeCoordinates(current_item, force); - } - } - } - /* - * Update coordinates and bounding boxes following - * a possible change in connected items. Only regular - * items can be concerned. - */ - if (group->dependents) { - num_deps = ZnListSize(group->dependents); - deps = (ZnItem *) ZnListArray(group->dependents); - for (i = 0; i < num_deps; i++) { - current_item = deps[i]; - if (force || - ISSET(current_item->inv_flags, ZN_COORDS_FLAG) || - ISSET(current_item->inv_flags, ZN_TRANSFO_FLAG) || - ISSET(current_item->connected_item->flags, ZN_UPDATE_DEPENDENT_BIT)) { - /*printf("Updating dependent: %d\n", current_item->id);*/ - CallRegularCC(current_item); - } - } - /* - * Now, we must reset the update_dependent flag - */ - for (i = 0; i < num_deps; i++) { - CLEAR(deps[i]->connected_item->flags, ZN_UPDATE_DEPENDENT_BIT); - } - /*printf("... done\n");*/ - } - /* - * Compute the bounding box. - */ - ZnResetBBox(&item->item_bounding_box); - current_item = group->head; - while (current_item != ZN_NO_ITEM) { - ZnAddBBoxToBBox(&item->item_bounding_box, ¤t_item->item_bounding_box); - current_item = current_item->next; - } - /* - * Limit the group actual bounding box to - * the clip shape boundary. - */ - if (group->clip) { - clip_box = &group->clip->item_bounding_box; - ZnIntersectBBox(&item->item_bounding_box, clip_box, &item->item_bounding_box); - } - item->inv_flags = 0; - - PopClip(group, False); - PopTransform(item); -} - - -/* - ********************************************************************************** - * - * ToArea -- - * Tell if the object is entirely outside (-1), - * entirely inside (1) or in between (0). - * - ********************************************************************************** - */ -static int -ToArea(ZnItem item, - ZnToArea ta) -{ - GroupItem group = (GroupItem) item; - ZnItem current_item; - ZnBBox enclosing, inter; - int result = -1; - ZnBool outside, inside; - ZnBool atomic, report, empty = True; - - - PushTransform(item); - report = ta->report; - - /* - * 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) { - /* - * We are in the target group, mark the fact and bypass the group - * atomicity. - */ - ta->in_group = ZN_NO_ITEM; - atomic = False; - } - else { - /* - * We are below the start group, If this group is ATOMIC, - * ask the child groups to report instead of adding their - * children to the result. - */ - atomic = ISSET(item->flags, ATOMIC_BIT) && !ta->override_atomic; - ta->report |= atomic; - } - - 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; - outside = inside = True; - /* - * Process each item and proceed with subtrees if - * asked for by the recursive flag. - */ - /* printf("searching in group %d\n", item?item->id:0);*/ - for (current_item = group->head; - current_item != ZN_NO_ITEM; - current_item = current_item->next) { - if (ISCLEAR(current_item->flags, ZN_VISIBLE_BIT) && - ISCLEAR(current_item->flags, ZN_SENSITIVE_BIT)) { - continue; - } - /*printf("visible&sensitive %d\n", current_item?current_item->id:0);*/ - ZnIntersectBBox(&enclosing, ¤t_item->item_bounding_box, &inter); - if (ZnIsEmptyBBox(&inter)) { - continue; - } - /*printf("bbox test passed %d\n", current_item?current_item->id:0);*/ - if ((current_item->class != ZnGroup) || atomic || ta->recursive || ISSET(current_item->flags, ATOMIC_BIT)) { - if (current_item->class != ZnGroup) { - /*printf("testing %d\n", current_item?current_item->id:0);*/ - PushTransform(current_item); - result = current_item->class->ToArea(current_item, ta); - PopTransform(current_item); - } - else { - result = current_item->class->ToArea(current_item, ta); - } - outside &= (result == -1); - inside &= (result == 1); - empty = False; - - /* - * 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)) { - /*printf("Doing %d\n", current_item?current_item->id:0);*/ - ZnDoItem(item->wi->interp, current_item, ZN_NO_PART, ta->tag_uid); - } - } - } - - /* - * 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 { - 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: - ta->report = report; - PopTransform(item); - return result; -} - - -/* - ********************************************************************************** - * - * Draw -- - * - ********************************************************************************** - */ -static void -Draw(ZnItem item) -{ - GroupItem group = (GroupItem) item; - ZnWInfo *wi = item->wi; - ZnItem current_item; - ZnBBox bbox, old_damaged_area, *clip_box; - - PushTransform(item); - PushClip(group, True); - if (group->clip != ZN_NO_ITEM) { - old_damaged_area = wi->damaged_area; - if (ZnCurrentClip(wi, NULL, &clip_box, NULL)) { - ZnIntersectBBox(&wi->damaged_area, clip_box, &bbox); - wi->damaged_area = bbox; - } - } - - current_item = group->tail; - while (current_item != ZN_NO_ITEM) { - if (ISSET(current_item->flags, ZN_VISIBLE_BIT)) { - ZnIntersectBBox(&wi->damaged_area, ¤t_item->item_bounding_box, &bbox); - if (!ZnIsEmptyBBox(&bbox)) { - if (current_item->class != ZnGroup) { - PushTransform(current_item); - } - current_item->class->Draw(current_item); - if (wi->draw_bboxes) { - XGCValues values; - values.foreground = ZnGetGradientPixel(wi->bbox_color, 0.0); - values.fill_style = FillSolid; - values.line_width = 1; - values.line_style = (current_item->class==ZnGroup)?LineOnOffDash:LineSolid; - XChangeGC(wi->dpy, wi->gc, GCForeground|GCLineStyle|GCLineWidth|GCFillStyle, - &values); - XDrawRectangle(wi->dpy, wi->draw_buffer, wi->gc, - (int) current_item->item_bounding_box.orig.x, - (int) current_item->item_bounding_box.orig.y, - (unsigned int) (current_item->item_bounding_box.corner.x - - current_item->item_bounding_box.orig.x), - (unsigned int) (current_item->item_bounding_box.corner.y - - current_item->item_bounding_box.orig.y)); - } - if (current_item->class != ZnGroup) { - PopTransform(current_item); - } - } - } - current_item = current_item->previous; - } - - if (group->clip != ZN_NO_ITEM) { - wi->damaged_area = old_damaged_area; - } - PopClip(group, True); - PopTransform(item); -} - - -/* - ********************************************************************************** - * - * Render -- - * - ********************************************************************************** - */ -#ifdef GL -static void -Render(ZnItem item) -{ - GroupItem group = (GroupItem) item; - ZnItem current_item; - ZnWInfo *wi = item->wi; -#ifdef GL_DAMAGE - ZnBBox *clip_box; - ZnBBox bbox, old_damaged_area; -#endif - unsigned char save_alpha = wi->alpha; - unsigned char save_alpha2; - - if (ISSET(item->flags, ZN_COMPOSE_ALPHA_BIT)) { - wi->alpha = wi->alpha * group->alpha / 100; - } - else { - wi->alpha = group->alpha; - } - save_alpha2 = wi->alpha; - - PushTransform(item); - PushClip(group, True); -#ifdef GL_DAMAGE - if (ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT) && (group->clip != ZN_NO_ITEM)) { - old_damaged_area = wi->damaged_area; - if (ZnCurrentClip(wi, NULL, &clip_box, NULL)) { - ZnIntersectBBox(&wi->damaged_area, clip_box, &bbox); - wi->damaged_area = bbox; - } - } -#endif - - current_item = group->tail; - while (current_item != ZN_NO_ITEM) { - if (ISSET(current_item->flags, ZN_VISIBLE_BIT)) { -#ifdef GL_DAMAGE - ZnIntersectBBox(&wi->damaged_area, ¤t_item->item_bounding_box, &bbox); - if (!ZnIsEmptyBBox(&bbox) || ISSET(wi->flags, ZN_CONFIGURE_EVENT)) { -#endif - if (current_item->class != ZnGroup) { - PushTransform(current_item); - if (ISCLEAR(current_item->flags, ZN_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 GL_DAMAGE - } -#endif - } - current_item = current_item->previous; - } - -#ifdef GL_DAMAGE - if (ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT) && (group->clip != ZN_NO_ITEM)) { - wi->damaged_area = old_damaged_area; - } -#endif - - PopClip(group, True); - PopTransform(item); - - wi->alpha = save_alpha; -} -#else -static void -Render(ZnItem item) -{ -} -#endif - - -/* - ********************************************************************************** - * - * IsSensitive -- - * - ********************************************************************************** - */ -static ZnBool -IsSensitive(ZnItem item, - int item_part) -{ - ZnBool sensitive = ISSET(item->flags, ZN_SENSITIVE_BIT); - ZnItem parent = item->parent; - - while (sensitive && (parent != ZN_NO_ITEM)) { - sensitive &= ISSET(parent->flags, ZN_SENSITIVE_BIT); - parent = parent->parent; - } - return sensitive; -} - - -/* - ********************************************************************************** - * - * Pick -- - * Given a point an an aperture, find the topmost group item/part - * that is (a) within the pick_aperture - * (b) the top most - * (c) has either its sensibility or its visibility set. - * - * Results: - * The return value is the distance of the picked item/part if one - * has been found or a really big distance if not. a_item and a_part - * are set to point the picked item/part or to ZN_NO_ITEM/ZN_NO_PART. - * If the group is ATOMIC, a_item points the group instead of the - * actual item. - * - * Side effects: - * None. - * - ********************************************************************************** - */ -static double -Pick(ZnItem item, - ZnPick ps) -{ - GroupItem group = (GroupItem) item; - ZnItem p_item=ZN_NO_ITEM, current_item; - ZnWInfo *wi = item->wi; - int p_part=0, aperture = ps->aperture; - double dist, best = 1e10; - ZnBBox bbox, inter, *clip_box; - ZnPoint *p = ps->point; - ZnBool atomic; - TkRegion reg; - - ps->a_item= ZN_NO_ITEM; - ps->a_part = ZN_NO_PART; - - if (group->head == ZN_NO_ITEM) { - return best; - } - - 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); - bbox.corner.y = p->y + (aperture?aperture:1); - - if (ZnCurrentClip(wi, ®, &clip_box, NULL)) { - ZnIntersectBBox(&bbox, clip_box, &inter); - if (ZnIsEmptyBBox(&inter)) { - goto out; - } - if (reg && !ZnPointInRegion(reg, (int) p->x, (int) p->y)) { - goto out; - } - } - - current_item = (ps->start_item == ZN_NO_ITEM) ? group->head : ps->start_item; - atomic = ISSET(item->flags, ATOMIC_BIT) && !ps->override_atomic; - - 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. - * This is _not_ a bug do _not_ modify the test below. - */ - if (ISCLEAR(current_item->flags, ZN_SENSITIVE_BIT) && - ISCLEAR(current_item->flags, ZN_VISIBLE_BIT)) { - continue; - } - ZnIntersectBBox(&bbox, ¤t_item->item_bounding_box, &inter); - if (ZnIsEmptyBBox(&inter)) { - continue; - } - if (current_item->class != ZnGroup) { - PushTransform(current_item); - 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, ps); - } - if (dist < 0.0) { - dist = 0.0; - } - if (dist >= best) { - /* Not a good one, restore the previous best and try again. */ - ps->a_item = p_item; - ps->a_part = p_part; - continue; - } - 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", (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; - } - } - - out: - PopClip(group, False); - PopTransform(item); - - return best; -} - - -/* - ********************************************************************************** - * - * Coords -- - * Return or edit the group translation (can be also interpreted as the - * position of the group origin in the group's parent). - * - ********************************************************************************** - */ -static int -Coords(ZnItem item, - int contour, - int index, - int cmd, - ZnPoint **pts, - char **controls, - unsigned int *num_pts) -{ - if ((cmd == ZN_COORDS_ADD) || (cmd == ZN_COORDS_ADD_LAST) || (cmd == ZN_COORDS_REMOVE)) { - Tcl_AppendResult(item->wi->interp, - " can't add or remove vertices in groups", NULL); - return TCL_ERROR; - } - else if ((cmd == ZN_COORDS_REPLACE) || (cmd == ZN_COORDS_REPLACE_ALL)) { - if (*num_pts == 0) { - Tcl_AppendResult(item->wi->interp, - " coords command need 1 point on groups", NULL); - return TCL_ERROR; - } - if (!item->transfo && ((*pts)[0].x == 0.0) && ((*pts)[0].y == 0.0)) { - return TCL_OK; - } - if (!item->transfo) { - item->transfo = ZnTransfoNew(); - } - ZnTranslate(item->transfo, (*pts)[0].x, (*pts)[0].y, True); - ZnITEM.Invalidate(item, ZN_TRANSFO_FLAG); - } - else if ((cmd == ZN_COORDS_READ) || (cmd == ZN_COORDS_READ_ALL)) { - ZnPoint *p; - - ZnListAssertSize(ZnWorkPoints, 1); - p = (ZnPoint *) ZnListArray(ZnWorkPoints); - ZnTransfoDecompose(item->transfo, NULL, p, NULL, NULL); - *num_pts = 1; - *pts = p; - } - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * PostScript -- - * - ********************************************************************************** - */ -static int -PostScript(ZnItem item, - ZnBool prepass, - ZnBBox *area) -{ - GroupItem group = (GroupItem) item; - ZnWInfo *wi = item->wi; - ZnItem current_item; - ZnBBox bbox; - int result = TCL_OK; - char msg[500]; - - PushTransform(item); - PushClip(group, True); - - for (current_item = group->tail; current_item != ZN_NO_ITEM; - current_item = current_item->previous) { - if (ISCLEAR(current_item->flags, ZN_VISIBLE_BIT)) { - continue; - } - //printf("area %g %g %g %g\n", area->orig.x, area->orig.y, - // area->corner.x, area->corner.y); - ZnIntersectBBox(area, ¤t_item->item_bounding_box, &bbox); - if (ZnIsEmptyBBox(&bbox)) { - continue; - } - if (current_item->class->PostScript == NULL) { - continue; - } - - if (current_item->class != ZnGroup) { - PushTransform(current_item); - if (!prepass) { - Tcl_AppendResult(wi->interp, "gsave\n", NULL); - } - ZnPostscriptTrace(current_item, 1); - } - result = current_item->class->PostScript(current_item, prepass, area); - if (current_item->class != ZnGroup) { - ZnPostscriptTrace(current_item, 0); - if (!prepass && (result == TCL_OK)) { - Tcl_AppendResult(wi->interp, "grestore\n", NULL); - } - PopTransform(current_item); - } - if (result == TCL_ERROR) { - if (!prepass) { - /* - * Add some trace to ease the error lookup. - */ - sprintf(msg, "\n (generating Postscript for item %d)", current_item->id); - Tcl_AddErrorInfo(wi->interp, msg); - break; - } - } - } - - PopClip(group, True); - PopTransform(item); - - if (!prepass && (result == TCL_OK)) { - ZnFlushPsChan(wi->interp, wi->ps_info); - } - return result; -} - - - -ZnItem -ZnGroupHead(ZnItem group) -{ - if (group->class != ZnGroup) { - return ZN_NO_ITEM; - } - return ((GroupItem) group)->head; -} - -ZnItem -ZnGroupTail(ZnItem group) -{ - if (group->class != ZnGroup) { - return ZN_NO_ITEM; - } - return ((GroupItem) group)->tail; -} - -#ifdef ATC -ZnBool -ZnGroupCallOm(ZnItem group) -{ - if (group->class != ZnGroup) { - return False; - } - return ((GroupItem) group)->call_om; -} - -void -ZnGroupSetCallOm(ZnItem group, - ZnBool set) -{ - if (group->class != ZnGroup) { - return; - } - ((GroupItem) group)->call_om = set; -} -#else -ZnBool -ZnGroupCallOm(ZnItem group) -{ - return False; -} - -void -ZnGroupSetCallOm(ZnItem group, - ZnBool set) -{ - return; -} -#endif - -ZnBool -ZnGroupAtomic(ZnItem group) -{ - if (group->class != ZnGroup) { - return True; - } - return ISSET(group->flags, ATOMIC_BIT); -} - -void -ZnGroupRemoveClip(ZnItem group, - ZnItem clip) -{ - GroupItem grp = (GroupItem) group; - - if (grp->clip == clip) { - grp->clip = ZN_NO_ITEM; - ZnITEM.Invalidate(group, ZN_COORDS_FLAG); - } -} - - -/* - ********************************************************************************** - * - * ZnInsertDependentItem -- - * - ********************************************************************************** - */ -void -ZnInsertDependentItem(ZnItem item) -{ - GroupItem group = (GroupItem) item->parent; - - if (!group) { - return; - } - if (!group->dependents) { - group->dependents = ZnListNew(2, sizeof(ZnItem)); - } - ZnListAdd(group->dependents, &item, ZnListTail); -} - - -/* - ********************************************************************************** - * - * ZnExtractDependentItem -- - * - ********************************************************************************** - */ -void -ZnExtractDependentItem(ZnItem item) -{ - GroupItem group = (GroupItem) item->parent; - unsigned int index, num_items; - ZnItem *deps; - - if (!group || !group->dependents) { - return; - } - num_items = ZnListSize(group->dependents); - deps = (ZnItem *) ZnListArray(group->dependents); - for (index = 0; index < num_items; index++) { - if (deps[index]->id == item->id) { - ZnListDelete(group->dependents, index); - if (ZnListSize(group->dependents) == 0) { - ZnListFree(group->dependents); - group->dependents = NULL; - break; - } - } - } -} - - -/* - ********************************************************************************** - * - * ZnDisconnectDependentItems -- - * - * - ********************************************************************************** - */ -void -ZnDisconnectDependentItems(ZnItem item) -{ - ZnItem current_item; - GroupItem group = (GroupItem) item->parent; - ZnItem *deps; - unsigned int num_deps; - int i; - - if (!group || !group->dependents) { - return; - } - deps = (ZnItem *) ZnListArray(group->dependents); - num_deps = ZnListSize(group->dependents); - - for (i = num_deps-1; i >= 0; i--) { - current_item = deps[i]; - if (current_item->connected_item == item) { - current_item->connected_item = ZN_NO_ITEM; - ZnListDelete(group->dependents, i); - ZnITEM.Invalidate(current_item, ZN_COORDS_FLAG); - } - } - if (ZnListSize(group->dependents) == 0) { - ZnListFree(group->dependents); - group->dependents = NULL; - } -} - - -/* - ********************************************************************************** - * - * ZnGroupExtractItem -- - * - ********************************************************************************** - */ -void -ZnGroupExtractItem(ZnItem item) -{ - GroupItem group; - - if (!item->parent) { - return; - } - group = (GroupItem) item->parent; - - if (item->previous != ZN_NO_ITEM) { - item->previous->next = item->next; - } - else { - group->head = item->next; - } - - if (item->next != ZN_NO_ITEM) { - item->next->previous = item->previous; - } - else { - group->tail = item->previous; - } - - ZnITEM.Invalidate((ZnItem) group, ZN_COORDS_FLAG); - - item->previous = ZN_NO_ITEM; - item->next = ZN_NO_ITEM; - item->parent = NULL; -} - - -/* - ********************************************************************************** - * - * ZnGroupInsertItem -- - * - ********************************************************************************** - */ -void -ZnGroupInsertItem(ZnItem group, - ZnItem item, - ZnItem mark_item, - ZnBool before) -{ - GroupItem grp = (GroupItem) group; - - /* - * Empty list, add the first item. - */ - if (grp->head == ZN_NO_ITEM) { - grp->head = grp->tail = item; - item->previous = item->next = ZN_NO_ITEM; - return; - } - - if (mark_item != ZN_NO_ITEM) { - /* - * Better leave here, mark_item will not - * have the links set right. - */ - if (mark_item == item) { - return; - } - /* - * Force the priority to be the same as the reference - * item; - */ - item->priority = mark_item->priority; - } - else { - mark_item = grp->head; - while ((mark_item != ZN_NO_ITEM) && - (mark_item->priority > item->priority)) { - mark_item = mark_item->next; - } - before = True; - } - - if (before && (mark_item != ZN_NO_ITEM)) { - /* - * Insert before mark. - */ - item->next = mark_item; - item->previous = mark_item->previous; - if (mark_item->previous == ZN_NO_ITEM) { - grp->head = item; - } - else { - mark_item->previous->next = item; - } - mark_item->previous = item; - } - else { - /* - * Insert after mark either because 'before' is False - * and mark_item valid or because the right place is at - * the end of the list and mark_item is ZN_NO_ITEM. - */ - if (mark_item == ZN_NO_ITEM) { - grp->tail->next = item; - item->previous = grp->tail; - grp->tail = item; - } - else { - item->previous = mark_item; - item->next = mark_item->next; - if (item->next == ZN_NO_ITEM) { - grp->tail = item; - } - else { - item->next->previous = item; - } - mark_item->next = item; - } - } - - ZnITEM.Invalidate(group, ZN_COORDS_FLAG); -} - -/* - ********************************************************************************** - * - * GetAnchor -- - * - ********************************************************************************** - */ -static void -GetAnchor(ZnItem item, - Tk_Anchor anchor, - ZnPoint *p) -{ - ZnBBox *bbox = &item->item_bounding_box; - - ZnOrigin2Anchor(&bbox->orig, - bbox->corner.x - bbox->orig.x, - bbox->corner.y - bbox->orig.y, - anchor, p); -} - - -/* - ********************************************************************************** - * - * Exported functions struct -- - * - ********************************************************************************** - */ -static ZnItemClassStruct GROUP_ITEM_CLASS = { - "group", - sizeof(GroupItemStruct), - group_attrs, - 0, /* num_parts */ - ZN_CLASS_ONE_COORD, /* flags */ - -1, - Init, - Clone, - Destroy, - Configure, - Query, - NULL, /* GetFieldSet */ - GetAnchor, - NULL, /* GetClipVertices */ - NULL, /* GetContours */ - Coords, - NULL, /* InsertChars */ - NULL, /* DeleteChars */ - NULL, /* Cursor */ - NULL, /* Index */ - NULL, /* Part */ - NULL, /* Selection */ - NULL, /* Contour */ - ComputeCoordinates, - ToArea, - Draw, - Render, - IsSensitive, - Pick, - NULL, /* PickVertex */ - PostScript -}; - -ZnItemClassId ZnGroup = (ZnItemClassId) &GROUP_ITEM_CLASS; -- cgit v1.1