unsigned long gt_layout_get_height(const GtLayout *layout) { GtTracklineInfo lines; double tmp, head_track_space = HEAD_TRACK_SPACE_DEFAULT; bool show_track_captions; unsigned long height, line_height, i; gt_assert(layout); /* get dynamic heights from tracks */ lines.style = layout->style; lines.height = 0; (void) gt_hashmap_foreach(layout->tracks, add_tracklines, &lines, NULL); height = lines.height; /* obtain line height and spacer from style */ if (gt_style_get_num(layout->style, "format", "bar_height", &tmp, NULL)) line_height = tmp; else line_height = BAR_HEIGHT_DEFAULT; if (gt_style_get_num(layout->style, "format", "bar_vspace", &tmp, NULL)) line_height += tmp; else line_height += BAR_VSPACE_DEFAULT; if (!(gt_style_get_bool(layout->style, "format","show_track_captions", &show_track_captions, NULL))) show_track_captions = true; /* add custom track space allotment */ if (show_track_captions) { double theight = TOY_TEXT_HEIGHT, captionspace = CAPTION_BAR_SPACE_DEFAULT; (void) gt_style_get_num(layout->style, "format", "track_caption_font_size", &theight, NULL); (void) gt_style_get_num(layout->style, "format", "track_caption_space", &captionspace, NULL); height += gt_array_size(layout->custom_tracks) * (theight + captionspace); } for (i=0;i<gt_array_size(layout->custom_tracks);i++) { GtCustomTrack *ct = *(GtCustomTrack**) gt_array_get(layout->custom_tracks, i); height += gt_custom_track_get_height(ct); (void) gt_style_get_num(layout->style, "format", "track_vspace", &tmp, NULL); height += tmp; } /* add header space and footer */ (void) gt_style_get_num(layout->style, "format", "ruler_space", &head_track_space, NULL); height += HEADER_SPACE + head_track_space + FOOTER_SPACE; return height; }
static int layout_tracks(void *key, void *value, void *data, GT_UNUSED GtError *err) { unsigned long i, max; GtTrack *track; GtLayoutTraverseInfo *lti = (GtLayoutTraverseInfo*) data; GtArray *list = (GtArray*) value; GtStr *gt_track_key; const char *type = key; GtBlock *block; bool split; double tmp; gt_assert(type && list); /* to get a deterministic layout, we sort the GtBlocks for each type */ gt_array_sort_stable(list, blocklist_block_compare); block = *(GtBlock**) gt_array_get(list, 0); gt_track_key = gt_str_new_cstr((char*) key); if (!gt_style_get_bool(lti->layout->style, "format", "split_lines", &split, NULL)) split = true; if (split) if (!gt_style_get_bool(lti->layout->style, type, "split_lines", &split, NULL)) split = true; if (gt_style_get_num(lti->layout->style, type, "max_num_lines", &tmp, NULL)) max = tmp; else max = 50; track = gt_track_new(gt_track_key, max, split, gt_line_breaker_captions_new(lti->layout, lti->layout->width, lti->layout->style)); lti->layout->nof_tracks++; for (i = 0; i < gt_array_size(list); i++) { block = *(GtBlock**) gt_array_get(list, i); gt_track_insert_block(track, block); } gt_hashmap_add(lti->layout->tracks, gt_cstr_dup(gt_str_get(gt_track_key)), track); gt_str_delete(gt_track_key); return 0; }
static int get_caption_display_status(GtDiagram *d, const char *gft, bool *result, GtError *err) { bool *status; gt_assert(d && gft); status = (bool*) gt_hashmap_get(d->caption_display_status, gft); if (!status) { GtUword threshold = GT_UNDEF_UWORD; double tmp = GT_UNDEF_DOUBLE; status = gt_malloc(sizeof (bool)); *status = true; if (gt_style_get_bool(d->style, "format", "show_block_captions", status, NULL, err) == GT_STYLE_QUERY_ERROR) { gt_free(status); return -1; } if (*status) { GtStyleQueryStatus rval; rval = gt_style_get_num(d->style, gft, "max_capt_show_width", &tmp, NULL, err); switch (rval) { case GT_STYLE_QUERY_ERROR: gt_free(status); return -1; break; /* should never reach this */ case GT_STYLE_QUERY_NOT_SET: *status = true; break; default: gt_assert(tmp != GT_UNDEF_DOUBLE); threshold = tmp; gt_assert(tmp != GT_UNDEF_UWORD); *status = (gt_range_length(&d->range) <= threshold); break; } *status = (gt_range_length(&d->range) <= threshold); } gt_hashmap_add(d->caption_display_status, (void*) gft, status); } *result = *status; return 0; }
int gt_canvas_cairo_visit_line_pre(GtCanvas *canvas, GtLine *line, GtError *err) { int had_err = 0; double lheight, bar_vspace = BAR_VSPACE_DEFAULT, theight = gt_graphics_get_text_height(canvas->pvt->g), captionspace = CAPTION_BAR_SPACE_DEFAULT; bool show_block_captions = true; gt_assert(canvas && line); if (gt_style_get_num(canvas->pvt->sty, "format", "block_caption_space", &captionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_bool(canvas->pvt->sty, "format", "show_block_captions", &show_block_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } had_err = gt_line_get_height(line, &lheight, canvas->pvt->sty, err); if (!had_err) { if (gt_style_get_num(canvas->pvt->sty, "format", "bar_vspace", &bar_vspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "block_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_line_has_captions(line) && show_block_captions) canvas->pvt->y += theight + captionspace; canvas->pvt->bt = gt_bittab_new(canvas->pvt->width); gt_bittab_unset(canvas->pvt->bt); canvas->pvt->y += lheight/2; } return had_err; }
static int layout_tracks(void *key, void *value, void *data, GtError *err) { unsigned long i, max = 50; GtTrack *track = NULL; GtLayoutTraverseInfo *lti = (GtLayoutTraverseInfo*) data; GtArray *list = (GtArray*) value; GtStr *gt_track_key; GtBlock *block; int had_err = 0; bool split = true; double tmp = 50; gt_assert(list); /* to get a deterministic layout, we sort the GtBlocks for each type */ if (lti->layout->block_ordering_func) { gt_array_sort_stable_with_data(list, blocklist_block_compare, lti->layout); } /* XXX: get first block for track property lookups, this should be reworked to allow arbitrary track keys! */ block = *(GtBlock**) gt_array_get(list, 0); gt_track_key = gt_str_new_cstr((char*) key); /* obtain default settings*/ if (gt_style_get_bool(lti->layout->style, "format", "split_lines", &split, NULL, err) == GT_STYLE_QUERY_ERROR) { had_err = 1; } if (!had_err) { if (gt_style_get_num(lti->layout->style, "format", "max_num_lines", &tmp, NULL, err) == GT_STYLE_QUERY_ERROR) { had_err = 1; } } /* obtain track-specific settings, should be changed to query arbitrary track keys! */ if (!had_err) { if (gt_style_get_bool(lti->layout->style, gt_block_get_type(block), "split_lines", &split, NULL, err) == GT_STYLE_QUERY_ERROR) { had_err = 1; } } if (!had_err) { if (gt_style_get_num(lti->layout->style, gt_block_get_type(block), "max_num_lines", &tmp, NULL, err) == GT_STYLE_QUERY_ERROR) { had_err = 1; } } if (!had_err) { max = (unsigned long) tmp; track = gt_track_new(gt_track_key, max, split, gt_line_breaker_captions_new(lti->layout, lti->layout->width, lti->layout->style)); lti->layout->nof_tracks++; for (i = 0; !had_err && i < gt_array_size(list); i++) { block = *(GtBlock**) gt_array_get(list, i); had_err = gt_track_insert_block(track, block, err); } } if (!had_err) { gt_hashmap_add(lti->layout->tracks, gt_cstr_dup(gt_str_get(gt_track_key)), track); } else { gt_track_delete(track); } gt_str_delete(gt_track_key); return had_err; }
int gt_layout_get_height(GtLayout *layout, unsigned long *result, GtError *err) { int had_err = 0; GtTracklineInfo lines; double tmp, head_track_space = HEAD_TRACK_SPACE_DEFAULT; bool show_track_captions = true; unsigned long height, i; gt_assert(layout); had_err = layout_all_tracks(layout, err); if (!had_err) { /* get dynamic heights from tracks */ lines.style = layout->style; lines.height = 0; if (gt_hashmap_foreach(layout->tracks, add_tracklines, &lines, err) < 0) { return -1; } height = lines.height; if (gt_style_get_bool(layout->style, "format","show_track_captions", &show_track_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* add custom track space allotment */ if (show_track_captions) { double theight = TEXT_SIZE_DEFAULT, captionspace = CAPTION_BAR_SPACE_DEFAULT; if (gt_style_get_num(layout->style, "format", "track_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(layout->style, "format", "track_caption_space", &captionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } height += gt_array_size(layout->custom_tracks) * (theight + captionspace); } for (i=0;i<gt_array_size(layout->custom_tracks);i++) { GtCustomTrack *ct = *(GtCustomTrack**) gt_array_get(layout->custom_tracks, i); height += gt_custom_track_get_height(ct); if (gt_style_get_num(layout->style, "format", "track_vspace", &tmp, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } height += tmp; } /* add header space and footer */ if (gt_style_get_num(layout->style, "format", "ruler_space", &head_track_space, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } height += HEADER_SPACE + head_track_space + FOOTER_SPACE; *result = height; return 0; } return had_err; }
int gt_track_get_height(const GtTrack *track, double *height, const GtStyle *sty, GtError *err) { unsigned long i; double track_height = 0, bheight = TEXT_SIZE_DEFAULT, theight = TEXT_SIZE_DEFAULT, tcaptionspace = CAPTION_BAR_SPACE_DEFAULT, bcaptionspace = CAPTION_BAR_SPACE_DEFAULT, tmp = TRACK_VSPACE_DEFAULT; bool show_track_captions = true, show_block_captions = true; gt_assert(track && sty); if (gt_style_get_num(sty, "format", "block_caption_font_size", &bheight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(sty, "format", "track_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(sty, "format", "track_caption_space", &tcaptionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(sty, "format", "block_caption_space", &bcaptionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(sty, "format", "block_caption_font_size", &bheight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(sty, "format", "track_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } for (i = 0; i < gt_array_size(track->lines); i++) { double itmp = BAR_VSPACE_DEFAULT, tmp = 0.0; int rval; GtLine *line; line = *(GtLine**) gt_array_get(track->lines, i); rval = gt_line_get_height(line, &tmp, sty, err); if (rval < 0) return -1; track_height += tmp; show_block_captions = true; if (gt_style_get_bool(sty, "format","show_block_captions", &show_block_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* add caption space if necessary */ if (gt_line_has_captions(line) && show_block_captions) { track_height += bheight + bcaptionspace; } /* add vertical spacer */ if (gt_style_get_num(sty, "format", "bar_vspace", &itmp, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } track_height += itmp; } /* determine display of track captions */ if (gt_style_get_bool(sty, "format","show_track_captions", &show_track_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* add track caption height and spacer */ if (show_track_captions) track_height += theight + tcaptionspace; if (gt_style_get_num(sty, "format", "track_vspace", &tmp, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } track_height += tmp; *height = track_height; return 0; }
/* Renders a ruler with dynamic scale labeling and optional grid. */ int gt_canvas_cairo_draw_ruler(GtCanvas *canvas, GtRange viewrange, GtError *err) { double step, minorstep, vmajor, vminor, theight = gt_graphics_get_text_height(canvas->pvt->g); long base_length, tick; GtColor rulercol, gridcol; GtStr *left_str, *right_str, *unit; char str[BUFSIZ]; GtStyleQueryStatus rval; bool showgrid = true; gt_assert(canvas); if (gt_style_get_bool(canvas->pvt->sty, "format", "show_grid", &showgrid, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "ruler_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* get unit value from style, default: empty */ unit = gt_str_new(); if (gt_style_get_str(canvas->pvt->sty, "format", "unit", unit, NULL, err) == GT_STYLE_QUERY_ERROR) { gt_str_delete(unit); return -1; } /* get additional description texts from style */ left_str = gt_str_new(); rval = gt_style_get_str(canvas->pvt->sty, "format", "ruler_left_text", left_str, NULL, err); switch (rval) { case GT_STYLE_QUERY_NOT_SET: gt_str_append_cstr(left_str, FIVE_PRIME_STRING); break; case GT_STYLE_QUERY_ERROR: gt_str_delete(unit); gt_str_delete(left_str); return -1; break; /* shouldn't reach this */ default: break; } right_str = gt_str_new(); rval = gt_style_get_str(canvas->pvt->sty, "format", "ruler_right_text", right_str, NULL, err); switch (rval) { case GT_STYLE_QUERY_NOT_SET: gt_str_append_cstr(right_str, THREE_PRIME_STRING); break; case GT_STYLE_QUERY_ERROR: gt_str_delete(unit); gt_str_delete(left_str); gt_str_delete(right_str); return -1; break; /* shouldn't reach this */ default: break; } /* reset font to default */ gt_graphics_set_font(canvas->pvt->g, "Sans", SLANT_NORMAL, WEIGHT_NORMAL, theight); rulercol.red = rulercol.green = rulercol.blue = RULER_GREY; rulercol.alpha = 1.0; gridcol.red = gridcol.green = gridcol.blue = GRID_GREY; gridcol.alpha = 1.0; /* determine range and step of the scale */ base_length = gt_range_length(&viewrange); /* determine tick steps */ step = pow(10,ceil(log10(base_length))-1); minorstep = step/10.0; /* calculate starting positions */ vminor = (double) (floor(viewrange.start / minorstep))*minorstep; vmajor = (double) (floor(viewrange.start / step))*step; /* draw major ticks */ for (tick = vmajor; tick <= viewrange.end; tick += step) { double drawtick = (gt_coords_convert_point(viewrange, tick) * (canvas->pvt->width-2*canvas->pvt->margins)) + canvas->pvt->margins; if (tick < viewrange.start) continue; gt_graphics_draw_vertical_line(canvas->pvt->g, drawtick, canvas->pvt->y + 30, rulercol, 10, 1.0); gt_format_ruler_label(str, tick, gt_str_get(unit), BUFSIZ); gt_graphics_draw_text_centered(canvas->pvt->g, drawtick, canvas->pvt->y + 20, str); } /* draw minor ticks */ if (minorstep >= 1) { for (tick = vminor; tick <= viewrange.end; tick += minorstep) { double drawtick; if (tick < viewrange.start) continue; drawtick = (gt_coords_convert_point(viewrange, tick) * (canvas->pvt->width-2*canvas->pvt->margins)) + canvas->pvt->margins; if (showgrid) { gt_graphics_draw_vertical_line(canvas->pvt->g, drawtick, canvas->pvt->y + 40, gridcol, canvas->pvt->height - 40 - 15, 1.0); } gt_graphics_draw_vertical_line(canvas->pvt->g, drawtick, canvas->pvt->y + 35, rulercol, 5, 1.0); } } /* draw ruler line */ gt_graphics_draw_horizontal_line(canvas->pvt->g, canvas->pvt->margins, canvas->pvt->y + 40, rulercol, canvas->pvt->width - 2 * canvas->pvt->margins, 1.25); gt_graphics_draw_text_right(canvas->pvt->g, canvas->pvt->margins - 10, canvas->pvt->y + 39 + (theight/2), gt_str_get(left_str)); gt_graphics_draw_text(canvas->pvt->g, canvas->pvt->width - canvas->pvt->margins + 10, canvas->pvt->y + 39 + (theight/2), gt_str_get(right_str)); gt_str_delete(unit); gt_str_delete(left_str); gt_str_delete(right_str); return 0; }
int gt_canvas_cairo_visit_custom_track(GtCanvas *canvas, GtCustomTrack *ct, GtError *err) { bool show_track_captions = true; double space; int had_err = 0; GtColor color; gt_assert(canvas && ct); if (gt_style_get_bool(canvas->pvt->sty, "format", "show_track_captions", &show_track_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_color(canvas->pvt->sty, "format", "track_title_color", &color, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (show_track_captions) { double theight = gt_graphics_get_text_height(canvas->pvt->g), captionspace = CAPTION_BAR_SPACE_DEFAULT; if (gt_style_get_num(canvas->pvt->sty, "format", "track_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* draw track title */ gt_graphics_set_font(canvas->pvt->g, "Sans", SLANT_NORMAL, WEIGHT_NORMAL, theight); gt_graphics_draw_colored_text(canvas->pvt->g, canvas->pvt->margins, canvas->pvt->y, color, gt_custom_track_get_title(ct)); if (gt_style_get_num(canvas->pvt->sty, "format", "track_caption_space", &captionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } canvas->pvt->y += theight + captionspace; } /* call rendering function */ had_err = gt_custom_track_render(ct, canvas->pvt->g, canvas->pvt->y, canvas->pvt->viewrange, canvas->pvt->sty, err); canvas->pvt->y += gt_custom_track_get_height(ct); /* put spacers after track */ space = TRACK_VSPACE_DEFAULT; if (gt_style_get_num(canvas->pvt->sty, "format", "track_vspace", &space, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } canvas->pvt->y += space; return had_err; }
int gt_canvas_cairo_visit_track_pre(GtCanvas *canvas, GtTrack *track, GtError *err) { int had_err = 0; unsigned long exceeded; bool show_track_captions = true; GtColor color; gt_assert(canvas && track); if (gt_style_get_bool(canvas->pvt->sty, "format", "show_track_captions", &show_track_captions, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_color(canvas->pvt->sty, "format", "track_title_color", &color, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* debug */ gt_log_log("processing track %s", gt_str_get(gt_track_get_title(track))); if (show_track_captions) { double theight = gt_graphics_get_text_height(canvas->pvt->g), captionspace = CAPTION_BAR_SPACE_DEFAULT; if (gt_style_get_num(canvas->pvt->sty, "format", "track_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "track_caption_space", &captionspace, NULL, err ) == GT_STYLE_QUERY_ERROR) { return -1; } gt_graphics_set_font(canvas->pvt->g, "Sans", SLANT_NORMAL, WEIGHT_NORMAL, theight); canvas->pvt->y += theight; /* draw track title */ gt_graphics_draw_colored_text(canvas->pvt->g, canvas->pvt->margins, canvas->pvt->y, color, gt_str_get(gt_track_get_title(track))); /* draw 'line maximum exceeded' message */ if ((exceeded = gt_track_get_number_of_discarded_blocks(track)) > 0) { char buf[BUFSIZ]; const char *msg; double width; GtColor red; red.red = LINE_EXCEEDED_MSG_R; red.green = LINE_EXCEEDED_MSG_G; red.blue = LINE_EXCEEDED_MSG_B; red.alpha = 1.0; if (exceeded == 1) { msg = "(1 block not shown due to exceeded line limit)"; strncpy(buf, msg, BUFSIZ); } else { msg = "(%lu blocks not shown due to exceeded line limit)"; /*@ignore@*/ snprintf(buf, BUFSIZ, msg, exceeded); /*@end@*/ } width = gt_graphics_get_text_width(canvas->pvt->g, gt_str_get(gt_track_get_title(track))); gt_graphics_draw_colored_text(canvas->pvt->g, canvas->pvt->margins+width+10.0, canvas->pvt->y, red, buf); } canvas->pvt->y += captionspace; } return had_err; }
static int process_node(GtDiagram *d, GtFeatureNode *node, GtFeatureNode *parent, GtError *err) { GtRange elem_range; bool *collapse; GtShouldGroupByParent *group; const char *feature_type = NULL, *parent_gft = NULL; double tmp; GtStyleQueryStatus rval; GtUword max_show_width = GT_UNDEF_UWORD, par_max_show_width = GT_UNDEF_UWORD; gt_assert(d && node); gt_log_log(">> getting '%s'", gt_feature_node_get_type(node)); /* skip pseudonodes */ if (gt_feature_node_is_pseudo(node)) return 0; feature_type = gt_feature_node_get_type(node); gt_assert(feature_type); /* discard elements that do not overlap with visible range */ elem_range = gt_genome_node_get_range((GtGenomeNode*) node); if (!gt_range_overlap(&d->range, &elem_range)) return 0; /* get maximal view widths in nucleotides to show this type */ rval = gt_style_get_num(d->style, feature_type, "max_show_width", &tmp, NULL, err); switch (rval) { case GT_STYLE_QUERY_OK: max_show_width = tmp; break; case GT_STYLE_QUERY_ERROR: return -1; break; /* should never be reached */ default: /* do not change default value */ break; } /* for non-root nodes, get maximal view with to show parent */ if (parent) { if (!gt_feature_node_is_pseudo(parent)) { parent_gft = gt_feature_node_get_type(parent); rval = gt_style_get_num(d->style, parent_gft, "max_show_width", &tmp, NULL, err); switch (rval) { case GT_STYLE_QUERY_OK: par_max_show_width = tmp; break; case GT_STYLE_QUERY_ERROR: return -1; break; /* should never be reached */ default: /* do not change default value */ break; } } else par_max_show_width = GT_UNDEF_UWORD; } /* check if this type is to be displayed at all */ if (max_show_width != GT_UNDEF_UWORD && gt_range_length(&d->range) > max_show_width) { return 0; } /* disregard parent node if it is configured not to be shown */ if (parent && par_max_show_width != GT_UNDEF_UWORD && gt_range_length(&d->range) > par_max_show_width) { parent = NULL; } /* check if this is a collapsing type, cache result */ if ((collapse = (bool*) gt_hashmap_get(d->collapsingtypes, feature_type)) == NULL) { collapse = gt_malloc(sizeof (bool)); *collapse = false; if (gt_style_get_bool(d->style, feature_type, "collapse_to_parent", collapse, NULL, err) == GT_STYLE_QUERY_ERROR) { gt_free(collapse); return -1; } gt_hashmap_add(d->collapsingtypes, (void*) feature_type, collapse); } /* check if type should be grouped by parent, cache result */ if ((group = (GtShouldGroupByParent*) gt_hashmap_get(d->groupedtypes, feature_type)) == NULL) { bool tmp; group = gt_malloc(sizeof (GtShouldGroupByParent)); rval = gt_style_get_bool(d->style, feature_type, "group_by_parent", &tmp, NULL, err); switch (rval) { case GT_STYLE_QUERY_OK: if (tmp) *group = GT_GROUP_BY_PARENT; else *group = GT_DO_NOT_GROUP_BY_PARENT; break; case GT_STYLE_QUERY_NOT_SET: *group = GT_UNDEFINED_GROUPING; break; case GT_STYLE_QUERY_ERROR: gt_free(group); return -1; break; /* should never be reached */ } gt_hashmap_add(d->groupedtypes, (void*) feature_type, group); } /* decide where to place this feature: */ if (*collapse) { /* user has specified collapsing to parent for this type */ if (parent && !gt_feature_node_is_pseudo(parent)) { /* collapsing child nodes are added to upwards blocks, but never collapse into pseudo nodes */ add_recursive(d, node, parent, node); } else { /* if no parent or only pseudo-parent, do not collapse */ if (add_to_current(d, node, parent, err) < 0) { return -1; } } } else /* (!*collapse) */ { if (parent) { bool do_not_overlap = false; do_not_overlap = gt_feature_node_direct_children_do_not_overlap_st(parent, node); if (*group == GT_GROUP_BY_PARENT || (do_not_overlap && *group == GT_UNDEFINED_GROUPING)) { if (gt_feature_node_is_pseudo(parent) && gt_feature_node_is_multi(node)) { if (add_to_rep(d, node, parent, err) < 0) { return -1; } } else if (gt_feature_node_number_of_children(parent) > 1) { if (add_to_parent(d, node, parent, err) < 0) { return -1; } } else { if (add_to_current(d, node, parent, err) < 0) { return -1; } } } else { if (gt_feature_node_is_pseudo(parent) && gt_feature_node_is_multi(node)) { if (add_to_rep(d, node, parent, err) < 0) { return -1; } } else { if (add_to_current(d, node, parent, err) < 0) { return -1; } } } } else { /* root nodes always get their own block */ if (add_to_current(d, node, parent, err) < 0) { return -1; } } } /* we can now assume that this node (or its representative) has been processed into the reverse lookup structure */ #ifndef NDEBUG if (gt_feature_node_is_multi(node)) { GtFeatureNode *rep; rep = gt_feature_node_get_multi_representative((GtFeatureNode*) node); gt_assert(gt_hashmap_get(d->nodeinfo, rep)); } else gt_assert(gt_hashmap_get(d->nodeinfo, node)); #endif return 0; }