/* File: zmapWindowContainerGroup.c * Author: Roy Storey (rds@sanger.ac.uk) * Copyright (c) 2008: Genome Research Ltd. *------------------------------------------------------------------- * ZMap is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt *------------------------------------------------------------------- * This file is part of the ZMap genome database package * originally written by: * * Ed Griffiths (Sanger Institute, UK) edgrif@sanger.ac.uk, * Roy Storey (Sanger Institute, UK) rds@sanger.ac.uk * * Description: * * Exported functions: See XXXXXXXXXXXXX.h * HISTORY: * Last edited: Jun 3 22:00 2009 (rds) * Created: Wed Dec 3 10:02:22 2008 (rds) * CVS info: $Id: zmapWindowContainerGroup.c,v 1.2 2009-06-03 22:29:08 rds Exp $ *------------------------------------------------------------------- */ #include <zmapWindowCanvas.h> #include <zmapWindowContainerGroup_I.h> #include <zmapWindowContainerChildren_I.h> #include <zmapWindowContainerUtils.h> #include <zmapWindow_P.h> /* ITEM_FEATURE_DATA, ITEM_FEATURE_TYPE */ #include <math.h> enum { CONTAINER_PROP_0, /* zero is invalid */ CONTAINER_PROP_VISIBLE, CONTAINER_PROP_COLUMN_REDRAW, }; typedef struct { ZMapWindowContainerUpdateHook hook_func; gpointer hook_data; } ContainerUpdateHookStruct, *ContainerUpdateHook; static void zmap_window_container_group_class_init (ZMapWindowContainerGroupClass container_class); static void zmap_window_container_group_init (ZMapWindowContainerGroup group); static void zmap_window_container_group_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void zmap_window_container_group_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void zmap_window_container_group_destroy (GObject *object); static void zmap_window_container_group_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose); static void zmap_window_container_group_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags); static void zmap_window_container_group_reposition(ZMapWindowContainerGroup container_group, double rect_x1, double rect_y1, double rect_x2, double rect_y2, double *dx_repos, double *dy_repos); static void maximise_background_rectangle(ZMapWindowContainerGroup this_container, FooCanvasItem *container_item, FooCanvasRE *rect); static void crop_rectangle_to_scroll_region(gpointer rectangle_data, gpointer points_data); static void zmap_window_container_scroll_region_get_item_bounds(FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2); static void zmap_window_container_update_with_crop(FooCanvasItem *item, double i2w_dx, double i2w_dy, FooCanvasPoints *itemised_scroll_region, int flags); static void zmap_window_container_invoke_update_hooks(ZMapWindowContainerGroup container, double x1, double y1, double x2, double y2); static gint find_update_hook_cb(gconstpointer list_data, gconstpointer query_data); #ifdef NO_NEED static FooCanvasGroupClass *group_parent_class_G = NULL; #endif static FooCanvasItemClass *item_parent_class_G = NULL; GType zmapWindowContainerGroupGetType(void) { static GType group_type = 0; if (!group_type) { static const GTypeInfo group_info = { sizeof (zmapWindowContainerGroupClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) zmap_window_container_group_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (zmapWindowContainerGroup), 0, /* n_preallocs */ (GInstanceInitFunc) zmap_window_container_group_init }; group_type = g_type_register_static (FOO_TYPE_CANVAS_GROUP, ZMAP_WINDOW_CONTAINER_GROUP_NAME, &group_info, 0); } return group_type; } ZMapWindowContainerGroup zmapWindowContainerGroupCreate(FooCanvasGroup *parent, ZMapContainerLevelType level, double child_spacing, GdkColor *background_fill_colour, GdkColor *background_border_colour) { ZMapWindowContainerGroup container = NULL; ZMapWindowContainerGroup parent_container = NULL; FooCanvasItem *features = NULL; FooCanvasItem *overlay = NULL; FooCanvasItem *underlay = NULL; FooCanvasItem *background = NULL; FooCanvasItem *item; FooCanvasGroup *group; GType container_type; double this_spacing = 200.0; if(ZMAP_IS_CONTAINER_GROUP(parent)) { zMapAssertNotReached(); parent = (FooCanvasGroup *)zmapWindowContainerGetFeatures((ZMapWindowContainerGroup)parent); } else { if((parent_container = (ZMapWindowContainerGroup)(((FooCanvasItem *)parent)->parent))) { this_spacing = parent_container->child_spacing; level = parent_container->level + 1; } } container_type = ZMAP_TYPE_CONTAINER_GROUP; switch(level) { case ZMAPCONTAINER_LEVEL_ROOT: container_type = ZMAP_TYPE_CONTAINER_CONTEXT; break; case ZMAPCONTAINER_LEVEL_ALIGN: container_type = ZMAP_TYPE_CONTAINER_ALIGNMENT; break; case ZMAPCONTAINER_LEVEL_BLOCK: container_type = ZMAP_TYPE_CONTAINER_BLOCK; break; case ZMAPCONTAINER_LEVEL_STRAND: container_type = ZMAP_TYPE_CONTAINER_STRAND; break; case ZMAPCONTAINER_LEVEL_FEATURESET: container_type = ZMAP_TYPE_CONTAINER_FEATURESET; break; default: container_type = ZMAP_TYPE_CONTAINER_GROUP; break; } item = foo_canvas_item_new(parent, container_type, "x", 0.0, "y", 0.0, NULL); if(item && ZMAP_IS_CONTAINER_GROUP(item)) { group = FOO_CANVAS_GROUP(item); container = ZMAP_CONTAINER_GROUP(item); container->level = level; /* level */ container->child_spacing = child_spacing; container->this_spacing = this_spacing; container->flags.column_redraw = FALSE; background = foo_canvas_item_new(group, ZMAP_TYPE_CONTAINER_BACKGROUND, "original-background", background_fill_colour, NULL); underlay = foo_canvas_item_new(group, ZMAP_TYPE_CONTAINER_UNDERLAY, NULL); features = foo_canvas_item_new(group, ZMAP_TYPE_CONTAINER_FEATURES, NULL); overlay = foo_canvas_item_new(group, ZMAP_TYPE_CONTAINER_OVERLAY, NULL); } return container; } /* Currently this function only works with columns, but the intention * is that it could work with blocks and aligns too at some later * point in time... */ gboolean zmapWindowContainerSetVisibility(FooCanvasGroup *container_parent, gboolean visible) { gboolean setable = FALSE; /* Most columns aren't */ /* We make sure that the container_parent is * - A parent * - Is a featureset... This is probably a limit too far. */ if(ZMAP_IS_CONTAINER_GROUP(container_parent)) { if(visible) foo_canvas_item_show((FooCanvasItem *)container_parent); else foo_canvas_item_hide((FooCanvasItem *)container_parent); setable = TRUE; } return setable ; } void zmapWindowContainerRequestReposition(ZMapWindowContainerGroup container) { ZMapWindowContainerGroup context_container; context_container = zmapWindowContainerUtilsGetParentLevel(container, ZMAPCONTAINER_LEVEL_ROOT); if(context_container) { g_object_set(G_OBJECT(context_container), "need-reposition", TRUE, NULL); } return ; } void zmapWindowContainerGroupBackgroundSize(ZMapWindowContainerGroup container, double height) { container->height = height; return ; } void zmapWindowContainerGroupChildRedrawRequired(ZMapWindowContainerGroup container, gboolean redraw_required) { container->flags.column_redraw = redraw_required; return ; } void zmapWindowContainerGroupSetBackgroundColour(ZMapWindowContainerGroup container, GdkColor *new_colour) { ZMapWindowContainerBackground background; if((background = zmapWindowContainerGetBackground(container))) zmapWindowContainerBackgroundSetColour(background, new_colour); return ; } void zmapWindowContainerGroupResetBackgroundColour(ZMapWindowContainerGroup container) { ZMapWindowContainerBackground background; if((background = zmapWindowContainerGetBackground(container))) zmapWindowContainerBackgroundResetColour(background); return ; } void zmapWindowContainerGroupAddUpdateHook(ZMapWindowContainerGroup container, ZMapWindowContainerUpdateHook hook, gpointer user_data) { ContainerUpdateHook update_hook = NULL; if((update_hook = g_new0(ContainerUpdateHookStruct, 1))) { update_hook->hook_func = hook; update_hook->hook_data = user_data; container->update_hooks = g_slist_append(container->update_hooks, update_hook); } return ; } void zmapWindowContainerGroupRemoveUpdateHook(ZMapWindowContainerGroup container, ZMapWindowContainerUpdateHook hook, gpointer user_data) { ContainerUpdateHookStruct update_hook = {NULL}; GSList *slist = NULL; update_hook.hook_func = hook; update_hook.hook_data = user_data; if((slist = g_slist_find_custom(container->update_hooks, &update_hook, find_update_hook_cb))) { g_free(slist->data); container->update_hooks = g_slist_remove(container->update_hooks, slist->data); } } ZMapWindowContainerGroup zmapWindowContainerGroupDestroy(ZMapWindowContainerGroup container) { g_object_unref(G_OBJECT(container)); container = NULL; return container; } /* object impl */ static void zmap_window_container_group_class_init (ZMapWindowContainerGroupClass container_class) { ZMapWindowContainerGroupClass canvas_class; FooCanvasItemClass *item_class; GObjectClass *gobject_class; GParamSpec *param_spec; gobject_class = (GObjectClass *) container_class; canvas_class = (ZMapWindowContainerGroupClass)container_class; item_class = (FooCanvasItemClass *)container_class; gobject_class->set_property = zmap_window_container_group_set_property; gobject_class->get_property = zmap_window_container_group_get_property; if((param_spec = g_object_class_find_property(gobject_class, "visible"))) { g_object_class_override_property(gobject_class, CONTAINER_PROP_VISIBLE, g_param_spec_get_name(param_spec)); } g_object_class_install_property(gobject_class, CONTAINER_PROP_COLUMN_REDRAW, g_param_spec_boolean("column-redraw", "column redraw", "Column needs redrawing when zoom changes", FALSE, ZMAP_PARAM_STATIC_RW)); item_parent_class_G = (FooCanvasItemClass *)(g_type_class_peek_parent(container_class)); zMapAssert(item_parent_class_G); zMapAssert(item_parent_class_G->update); item_class->draw = zmap_window_container_group_draw; item_class->update = zmap_window_container_group_update; container_class->reposition_group = zmap_window_container_group_reposition; gobject_class->dispose = zmap_window_container_group_destroy; return ; } static void zmap_window_container_group_init (ZMapWindowContainerGroup container) { g_object_set_data(G_OBJECT(container), CONTAINER_TYPE_KEY, GINT_TO_POINTER(CONTAINER_GROUP_PARENT)); return ; } static void zmap_window_container_group_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { ZMapWindowContainerGroup container; g_return_if_fail(ZMAP_IS_CONTAINER_GROUP(object)); container = ZMAP_CONTAINER_GROUP(object); switch(param_id) { case CONTAINER_PROP_VISIBLE: { gboolean visible = FALSE; visible = g_value_get_boolean(value); switch(container->level) { case ZMAPCONTAINER_LEVEL_FEATURESET: if(visible) { foo_canvas_item_show(FOO_CANVAS_ITEM(object)); } else { foo_canvas_item_hide(FOO_CANVAS_ITEM(object)); } break; default: break; } /* switch(container->level) */ } break; case CONTAINER_PROP_COLUMN_REDRAW: { switch(container->level) { case ZMAPCONTAINER_LEVEL_FEATURESET: container->flags.column_redraw = g_value_get_boolean(value); break; default: break; } /* switch(container->level) */ } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } /* switch(param_id) */ return ; } static void zmap_window_container_group_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { switch(param_id) { case CONTAINER_PROP_VISIBLE: { FooCanvasItem *item; item = FOO_CANVAS_ITEM(object); g_value_set_boolean (value, item->object.flags & FOO_CANVAS_ITEM_VISIBLE); } break; case CONTAINER_PROP_COLUMN_REDRAW: { ZMapWindowContainerGroup container; container = ZMAP_CONTAINER_GROUP(object); switch(container->level) { case ZMAPCONTAINER_LEVEL_FEATURESET: g_value_set_boolean(value, container->flags.column_redraw); break; default: break; } /* switch(container->level) */ } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } /* switch(param_id) */ return ; } #ifdef POINT_REQUIRED static double window_container_group_invoke_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item) { /* Calculate x & y in item local coordinates */ if (FOO_CANVAS_ITEM_GET_CLASS (item)->point) return FOO_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item); return 1e18; } /* Point handler for canvas groups */ static double zmap_window_container_group_item_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item) { FooCanvasGroup *group; FooCanvasItem *child, *point_item; GList *list = NULL; int x1, y1, x2, y2; double gx, gy; double dist, best; group = FOO_CANVAS_GROUP (item); x1 = cx - item->canvas->close_enough; y1 = cy - item->canvas->close_enough; x2 = cx + item->canvas->close_enough; y2 = cy + item->canvas->close_enough; best = 0.0; *actual_item = NULL; gx = x - group->xpos; gy = y - group->ypos; dist = 0.0; /* keep gcc happy */ list = group->item_list; while(list) { child = list->data; if ((child->object.flags & FOO_CANVAS_ITEM_MAPPED) && FOO_CANVAS_ITEM_GET_CLASS (child)->point) { dist = window_container_group_invoke_point (child, gx, gy, cx, cy, &point_item); if(point_item && ((int)(dist * item->canvas->pixels_per_unit_x + 0.5) <= item->canvas->close_enough) && (dist <= best)) { best = dist; *actual_item = point_item; } } list = list->next; } if(actual_item == NULL && item_parent_class_G->point) best = (item_parent_class_G->point)(item, x, y, cx, cy, actual_item); return best; } #endif static void zmap_window_container_group_destroy (GObject *object) { ZMapWindowContainerGroup container; GObjectClass *object_class; object_class = (GObjectClass *)item_parent_class_G; container = (ZMapWindowContainerGroup)object; g_slist_foreach(container->update_hooks, (GFunc)g_free, NULL); g_slist_free(container->update_hooks); container->update_hooks = NULL; if(object_class->dispose) (object_class->dispose)(object); return ; } static void zmap_window_container_group_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose) { if(item_parent_class_G->draw) (item_parent_class_G->draw)(item, drawable, expose); return ; } static void maximise_background_rectangle(ZMapWindowContainerGroup this_container, FooCanvasItem *container_item, FooCanvasRE *rect) { FooCanvasItem *rect_item; double irx1, irx2, iry1, iry2; int container_x2, container_y2; /* container canvas coords, calculated from group->update above. */ irx1 = iry1 = 0.0; /* placed @ 0,0 */ /* We can't trust item->x1 and item->y1 as empty child * groups return 0,0->0,0 hence extend all parents to * 0,0! */ container_x2 = (int)(container_item->x2); container_y2 = (int)(container_item->y2); rect_item = (FooCanvasItem *)rect; /* */ foo_canvas_item_i2w(rect_item, &irx1, &iry1); foo_canvas_c2w(rect_item->canvas, container_x2, container_y2, &irx2, &iry2); if((iry2 - iry1 + 1) < this_container->height) iry2 = this_container->height + iry1; rect->x1 = irx1; rect->y1 = iry1; rect->x2 = irx2; rect->y2 = iry2; if(rect->x1 == rect->x2) rect->x2 = rect->x1 + this_container->this_spacing; foo_canvas_item_w2i(rect_item, &(rect->x1), &(rect->y1)); foo_canvas_item_w2i(rect_item, &(rect->x2), &(rect->y2)); /* rect->x1 & rect->y1 should == 0.0 */ return ; } static void crop_rectangle_to_scroll_region(gpointer rectangle_data, gpointer points_data) { FooCanvasRE *rect; FooCanvas *foo_canvas; FooCanvasItem *crop_item; FooCanvasPoints *scroll_region = (FooCanvasPoints *)points_data; double scroll_x1, scroll_y1, scroll_x2, scroll_y2; double iwx1, iwy1, iwx2, iwy2; rect = (FooCanvasRE *)rectangle_data; crop_item = (FooCanvasItem *)rect; foo_canvas = crop_item->canvas; iwx1 = rect->x1; iwy1 = rect->y1; iwx2 = rect->x2; iwy2 = rect->y2; if((scroll_region == NULL)) { /* x unused ATM */ scroll_x1 = foo_canvas->scroll_x1; scroll_x2 = foo_canvas->scroll_x2; scroll_y1 = foo_canvas->scroll_y1; scroll_y2 = foo_canvas->scroll_y2; foo_canvas_item_w2i(crop_item, &scroll_x1, &scroll_y1); foo_canvas_item_w2i(crop_item, &scroll_x2, &scroll_y2); } else { scroll_x1 = scroll_region->coords[0]; scroll_y1 = scroll_region->coords[1]; scroll_x2 = scroll_region->coords[2]; scroll_y2 = scroll_region->coords[3]; } if (!(iwy2 < scroll_y1) && !(iwy1 > scroll_y2) && ((iwy1 < scroll_y1) || (iwy2 > scroll_y2))) { if(iwy1 < scroll_y1) { rect->y1 = scroll_y1 - 1.0; } if(iwy2 > scroll_y2) { rect->y2 = scroll_y2 + 1.0; } } return ; } static void zmap_window_container_scroll_region_get_item_bounds(FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { FooCanvas *foo_canvas; double scroll_x1, scroll_y1, scroll_x2, scroll_y2; foo_canvas = item->canvas; scroll_x1 = foo_canvas->scroll_x1; scroll_x2 = foo_canvas->scroll_x2; scroll_y1 = foo_canvas->scroll_y1; scroll_y2 = foo_canvas->scroll_y2; foo_canvas_item_w2i(item, &scroll_x1, &scroll_y1); foo_canvas_item_w2i(item, &scroll_x2, &scroll_y2); if(x1) *x1 = scroll_x1; if(y1) *y1 = scroll_y1; if(x2) *x2 = scroll_x2; if(y2) *y2 = scroll_y2; return ; } /* container update flags */ enum { CONTAINER_UPDATE_CROP_REQUIRED = 1 << 3, }; static void zmap_window_container_update_with_crop(FooCanvasItem *item, double i2w_dx, double i2w_dy, FooCanvasPoints *itemised_scroll_region, int flags) { if(FOO_IS_CANVAS_GROUP(item)) { FooCanvasGroup *group; GList *list; group = (FooCanvasGroup *)item; if((list = group->item_list)) { double sub_i2w_dx, sub_i2w_dy; sub_i2w_dx = i2w_dx + group->xpos; sub_i2w_dy = i2w_dx + group->ypos; itemised_scroll_region->coords[0] -= group->xpos; itemised_scroll_region->coords[1] -= group->ypos; itemised_scroll_region->coords[2] -= group->xpos; itemised_scroll_region->coords[3] -= group->ypos; do { zmap_window_container_update_with_crop((FooCanvasItem *)(list->data), sub_i2w_dx, sub_i2w_dy, itemised_scroll_region, flags); } while((list = list->next)); itemised_scroll_region->coords[0] += group->xpos; itemised_scroll_region->coords[1] += group->ypos; itemised_scroll_region->coords[2] += group->xpos; itemised_scroll_region->coords[3] += group->ypos; } } else if(flags & CONTAINER_UPDATE_CROP_REQUIRED) { if(FOO_IS_CANVAS_RE(item)) crop_rectangle_to_scroll_region((FooCanvasRE *)item, NULL); } if(FOO_CANVAS_ITEM_GET_CLASS(item)->update) (FOO_CANVAS_ITEM_GET_CLASS(item)->update)(item, i2w_dx, i2w_dy, flags); return ; } static void zmap_window_container_invoke_update_hooks(ZMapWindowContainerGroup container, double x1, double y1, double x2, double y2) { if(container->update_hooks) { FooCanvasPoints bounds; double coords[4] = {0.0}; GSList *hooks; hooks = container->update_hooks; coords[0] = x1; coords[1] = y1; coords[2] = x2; coords[3] = y2; bounds.coords = &coords[0]; bounds.ref_count = 1; bounds.num_points = 2; do { ContainerUpdateHook update_hook; update_hook = (ContainerUpdateHook)(hooks->data); if(update_hook->hook_func) (update_hook->hook_func)(container, &bounds, container->level, update_hook->hook_data); } while((hooks = hooks->next)); } return ; } /* This takes care of the x positioning of the containers as well as the maximising in the y coords. */ static void zmap_window_container_group_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags) { ZMapWindowContainerGroup this_container = NULL; ZMapWindowContainerGroup parent_container = NULL; ZMapWindowContainerOverlay overlay = NULL; ZMapWindowContainerUnderlay underlay = NULL; FooCanvasRE *rect = NULL; FooCanvasItem *parent_parent = NULL; FooCanvasGroup *canvas_group; GList *item_list; double current_x = 0.0; double current_y = 0.0; gboolean item_visible; gboolean doing_reposition; gboolean need_cropping; gboolean add_strand_border = FALSE; canvas_group = (FooCanvasGroup *)item; item_visible = ((item->object.flags & FOO_CANVAS_ITEM_VISIBLE) == FOO_CANVAS_ITEM_VISIBLE); this_container = (ZMapWindowContainerGroup)item; this_container->reposition_x = current_x; this_container->reposition_y = current_y; /* This was in the previous version of the code, copying across... */ if(add_strand_border && this_container->level == ZMAPCONTAINER_LEVEL_STRAND) this_container->reposition_x += this_container->child_spacing; if(item->parent && (parent_parent = item->parent->parent)) { parent_container = (ZMapWindowContainerGroup)parent_parent; #ifdef ACTUALLY_FLAGS_SUBVERSION_IS_BETTER /* we could subvert flags parameter, but this is slightly * better. Needs to be propgated through the tree. */ if(!this_container->flags.need_reposition) this_container->flags.need_reposition = parent_container->flags.need_reposition; this_container->flags.need_cropping = parent_container->flags.need_cropping; #endif current_x = parent_container->reposition_x; current_y = parent_container->reposition_y; } doing_reposition = ((flags & ZMAP_CANVAS_UPDATE_NEED_REPOSITION) == ZMAP_CANVAS_UPDATE_NEED_REPOSITION); need_cropping = ((flags & ZMAP_CANVAS_UPDATE_CROP_REQUIRED) == ZMAP_CANVAS_UPDATE_CROP_REQUIRED); if(doing_reposition) { GList *list, *list_end, tmp_features = {NULL}, tmp_background = {NULL}; gboolean print_debug = FALSE; if((item_list = canvas_group->item_list)) { /* reposition immediate descendants (features, background overlay, underlay) */ do { if(FOO_IS_CANVAS_GROUP(item_list->data)) { FooCanvasGroup *group = (FooCanvasGroup *)(item_list->data); if(group->xpos != 0.0) group->xpos = 0.0; if(group->ypos != 0.0) group->ypos = 0.0; if(ZMAP_IS_CONTAINER_OVERLAY(item_list->data)) overlay = (ZMapWindowContainerOverlay)(item_list->data); else if(ZMAP_IS_CONTAINER_UNDERLAY(item_list->data)) underlay = (ZMapWindowContainerUnderlay)(item_list->data); } else if(ZMAP_IS_CONTAINER_BACKGROUND(item_list->data)) { rect = FOO_CANVAS_RE(item_list->data); if(rect->x1 != 0.0) rect->x1 = 0.0; if(rect->y1 != 0.0) rect->y1 = 0.0; rect->x2 = 1.0; /* There's no way to know width */ rect->y2 = this_container->height; /* We know height though. */ } /* no recursion here... */ } while((item_list = item_list->next)); } if(print_debug) { switch(this_container->level) { case ZMAPCONTAINER_LEVEL_ROOT: printf("context: "); break; case ZMAPCONTAINER_LEVEL_ALIGN: printf("align: "); break; case ZMAPCONTAINER_LEVEL_BLOCK: printf("block: "); break; case ZMAPCONTAINER_LEVEL_STRAND: printf("strand: "); break; case ZMAPCONTAINER_LEVEL_FEATURESET: printf("featureset: "); break; default: break; } printf("current_x=%f, current_y=%f\n", current_x, current_y); } if(item_visible) { FooCanvasGroup *real_group; real_group = (FooCanvasGroup *)this_container; /* There's _no_ need to use group->translate, nor move by dx,dy. Just set the positions */ real_group->xpos = current_x; /* We don't do y at the moment. no real idea what should happen here. */ /* real_group->ypos = current_y; */ } /* We _only_ update the background and features at this time. Underlays and overlays will get done later */ tmp_background.next = &tmp_features; tmp_background.data = zmapWindowContainerGetBackground(this_container); tmp_background.prev = NULL; tmp_features.next = NULL; tmp_features.data = zmapWindowContainerGetFeatures(this_container); tmp_features.prev = &tmp_background; list = canvas_group->item_list; list_end = canvas_group->item_list_end; canvas_group->item_list = &tmp_background; canvas_group->item_list_end = &tmp_features; (item_parent_class_G->update)(item, i2w_dx, i2w_dy, flags); canvas_group->item_list = list; canvas_group->item_list_end = list_end; } else { (item_parent_class_G->update)(item, i2w_dx, i2w_dy, flags); } if(rect && item_visible) { gboolean need_2nd_update = TRUE; if(doing_reposition) { maximise_background_rectangle(this_container, item, rect); /* Update the current reposition_x, and reposition_y coords */ if(parent_container) { double dx, dy; if(ZMAP_CONTAINER_GROUP_GET_CLASS(this_container)->reposition_group) (ZMAP_CONTAINER_GROUP_GET_CLASS(this_container)->reposition_group)(this_container, rect->x1, rect->y1, rect->x2, rect->y2, &dx, &dy); parent_container->reposition_x += dx; parent_container->reposition_y += dy; } zmap_window_container_invoke_update_hooks(this_container, rect->x1, rect->y1, rect->x2, rect->y2); } /* The background needs updating now so that the canvas knows * where it is (canvas coords) for events. We are only setting * the points to match the containers bounds or within so no * need to re-update the whole tree...phew... */ if(need_2nd_update || need_cropping) { FooCanvasItem *update_items[3] = {NULL}; FooCanvasPoints scroll_region; double coords[4]; int i = 0, update_flags = flags; i2w_dx += canvas_group->xpos; i2w_dy += canvas_group->ypos; update_items[i++] = (FooCanvasItem *)rect; update_items[i++] = (FooCanvasItem *)overlay; update_items[i++] = (FooCanvasItem *)underlay; if(need_cropping) update_flags |= CONTAINER_UPDATE_CROP_REQUIRED; zmap_window_container_scroll_region_get_item_bounds(update_items[0], &coords[0], &coords[1], &coords[2], &coords[3]); scroll_region.coords = &coords[0]; scroll_region.num_points = 2; scroll_region.ref_count = 1; /* We need to maximise overlays and underlays if required too. */ if(overlay) zmapWindowContainerOverlayMaximiseItems(overlay, rect->x1, rect->y1, rect->x2, rect->y2); if(underlay) zmapWindowContainerUnderlayMaximiseItems(underlay, rect->x1, rect->y1, rect->x2, rect->y2); for(i = 0; i < 3; i++) { zmap_window_container_update_with_crop(update_items[i], i2w_dx, i2w_dy, &scroll_region, update_flags); } } } /* Always do these, whatever else went on. No question! */ this_container->reposition_x = 0.0; this_container->reposition_y = 0.0; this_container->flags.need_reposition = FALSE; return ; } static void zmap_window_container_group_reposition(ZMapWindowContainerGroup container_group, double rect_x1, double rect_y1, double rect_x2, double rect_y2, double *dx_repos, double *dy_repos) { double dx, dy; dx = dy = 0.0; dx = (rect_x2 - rect_x1 + 1) + container_group->this_spacing; if(dx_repos) *dx_repos = dx; if(dy_repos) *dy_repos = dy; return ; } static gint find_update_hook_cb(gconstpointer list_data, gconstpointer query_data) { ContainerUpdateHook current, query; gint zero_when_matched = -1; current = (ContainerUpdateHook)list_data; query = (ContainerUpdateHook)query_data; if(current->hook_func == query->hook_func && current->hook_data == query->hook_data) zero_when_matched = 0; return zero_when_matched; }