Пример #1
0
void gt_graphics_cairo_draw_caret(GtGraphics *gg, double x, double y,
                                  double width,double height,
                                  ArrowStatus arrow_status, double arrow_width,
                                  double stroke_width, GtColor stroke_color)
{
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  gt_assert(g);

  /* save cairo context */
  cairo_save(g->cr);
  cairo_rectangle(g->cr, g->margin_x, g->margin_y,
                  g->width-2*g->margin_x, g->height-2*g->margin_y);
  cairo_clip(g->cr);
  /* create caret path */
  switch (arrow_status)
  {
    case ARROW_RIGHT:
      if (gt_double_smaller_double(0, width - arrow_width))
      {
        width -= arrow_width;
        cairo_move_to(g->cr, x, y + (height/2));
        cairo_line_to(g->cr, x + (width/2), y);
        cairo_line_to(g->cr, x + width, y + (height/2));
        cairo_line_to(g->cr, x + width + arrow_width, y + (height/2));
        /* add arrowhead */
        cairo_move_to(g->cr, x + width, y);
        cairo_line_to(g->cr, x + width + arrow_width, y + height / 2);
        cairo_line_to(g->cr, x + width, y + height);
      }
      break;
    case ARROW_LEFT:
      if (gt_double_smaller_double(0, width - arrow_width))
      {
        width -= arrow_width;
        /* draw arrowhead */
        cairo_move_to(g->cr, x + arrow_width , y);
        cairo_line_to(g->cr, x, y + (height/2));
        cairo_line_to(g->cr, x + arrow_width, y + height);
        cairo_move_to(g->cr, x, y + (height/2));
        cairo_line_to(g->cr, x + arrow_width, y + (height/2));
        cairo_line_to(g->cr, x + arrow_width + (width/2), y);
        cairo_line_to(g->cr, x + arrow_width + width, y + (height/2));
      }
      break;
    case ARROW_BOTH: /* XXX */
    case ARROW_NONE:
     cairo_move_to(g->cr, x, y + (height/2));
     cairo_line_to(g->cr, x + (width/2), y);
     cairo_line_to(g->cr, x + width, y + (height/2));
   }
   /* draw caret */
   cairo_set_line_width(g->cr, stroke_width);
   cairo_set_source_rgba(g->cr, stroke_color.red,
                                stroke_color.green,
                                stroke_color.blue,
                                stroke_color.alpha);
   cairo_stroke(g->cr);
   /* restore cairo context */
   cairo_restore(g->cr);
}
int calculate_drawing_range(GtLineBreakerCaptions *lbc, GtDrawingRange *rng,
                            GtBlock* block, GtError *err)
{
  double textwidth = 0.0;
  GtDrawingRange drange;
  gt_assert(block && lbc);
  drange = gt_coords_calc_generic_range(gt_block_get_range(block),
                                        gt_layout_get_range(lbc->layout));
  drange.start *= lbc->width-2*lbc->margins;
  drange.end *= lbc->width-2*lbc->margins;
  if (gt_block_get_caption(block))
  {
    textwidth = gt_text_width_calculator_get_text_width(
                                      gt_layout_get_twc(lbc->layout),
                                      gt_str_get(gt_block_get_caption(block)),
                                      err);
    if (gt_double_smaller_double(textwidth, 0))
      return -1;
    if (gt_double_smaller_double(gt_drawing_range_length(drange), textwidth))
      drange.end = drange.start + textwidth;
  }
  rng->start = drange.start;
  rng->end = drange.end;
  return 0;
}
Пример #3
0
int gt_drawing_range_compare(GtDrawingRange range_a, GtDrawingRange range_b)
{
  gt_assert(range_a.start <= range_a.end && range_b.start <= range_b.end);

  if (gt_double_equals_double(range_a.start, range_b.start) &&
      gt_double_equals_double(range_a.end, range_b.end))
    return 0; /* range_a == range_b */

  if (gt_double_smaller_double(range_a.start, range_b.start) ||
      (gt_double_equals_double(range_a.start, range_b.start)
       && gt_double_smaller_double(range_a.end, range_b.end)))
    return -1; /* range_a < range_b */

  return 1; /* range_a > range_b */
}
Пример #4
0
void gt_graphics_cairo_draw_dashes(GtGraphics *gg, double x, double y,
                                   double width, double height,
                                   ArrowStatus arrow_status, double arrow_width,
                                   double stroke_width, GtColor stroke_color)
{
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  double dashes[] = {2.0};
  gt_assert(g);
  /* save cairo context */
  cairo_save(g->cr);
  cairo_rectangle(g->cr, g->margin_x, g->margin_y,
                  g->width-2*g->margin_x, g->height-2*g->margin_y);
  cairo_clip(g->cr);
  cairo_set_line_width(g->cr, stroke_width);
  cairo_set_source_rgba(g->cr, stroke_color.red,
                               stroke_color.green,
                               stroke_color.blue,
                               stroke_color.alpha);
  /* create arrowhead path */
  if (gt_double_smaller_double(0, width - arrow_width))
  {
    switch (arrow_status)
    {
      case ARROW_RIGHT:
        cairo_move_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y);
        cairo_line_to(g->cr, rnd_to_nhalf(x + width), y + height / 2);
        cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y + height);
        /* draw arrowhead */
        cairo_stroke(g->cr);
        break;
      case ARROW_LEFT:
        cairo_move_to(g->cr, rnd_to_nhalf(x + arrow_width), y);
        cairo_line_to(g->cr, rnd_to_nhalf(x), y + height / 2);
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height);
        /* draw arrowhead */
        cairo_stroke(g->cr);
        break;
      case ARROW_BOTH:
        cairo_move_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y);
        cairo_line_to(g->cr, rnd_to_nhalf(x + width), y + height / 2);
        cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y + height);
        cairo_move_to(g->cr, rnd_to_nhalf(x + arrow_width), y);
        cairo_line_to(g->cr, rnd_to_nhalf(x), y + height / 2);
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height);
        cairo_stroke(g->cr);
        break;
      case ARROW_NONE: break;
    }
  }
  /* draw dashes */
  cairo_set_dash(g->cr, dashes, 1, (double) 0);
  cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y+(height/2)));
  cairo_rel_line_to(g->cr, rnd_to_nhalf(width), 0);
  cairo_stroke(g->cr);
  /* restore cairo context */
  cairo_restore(g->cr);
}
Пример #5
0
int gt_mathsupport_unit_test(GtError *err)
{
  int had_err = 0;
  double less_than_epsilon = 0.0000000000000001;
  gt_error_check(err);

  gt_ensure(had_err, !gt_double_equals_one(1.1));
  gt_ensure(had_err, gt_double_equals_one(1));
  gt_ensure(had_err, gt_double_equals_one(1+less_than_epsilon));
  gt_ensure(had_err, !gt_double_equals_one(-1-less_than_epsilon));

  gt_ensure(had_err, !gt_double_equals_double(1.0, 2.0));
  gt_ensure(had_err, !gt_double_equals_double(-1.0, 1.0));
  gt_ensure(had_err, !gt_double_equals_double(1.0, -1.0));
  gt_ensure(had_err, !gt_double_equals_double(-1.0, 1+less_than_epsilon));
  gt_ensure(had_err, !gt_double_equals_double(1.0, 1.1));
  gt_ensure(had_err, gt_double_equals_double(1.0, 1+less_than_epsilon));
  gt_ensure(had_err, gt_double_equals_double(1.0, 1.0));
  gt_ensure(had_err, gt_double_equals_double(0.0, 0.0));
  gt_ensure(had_err, gt_double_equals_double(-1.0, -1.0));
  gt_ensure(had_err, gt_double_equals_double(-1.0+less_than_epsilon, -1.0));
  gt_ensure(had_err, gt_double_equals_double(-1.0, -1.0+less_than_epsilon));
  gt_ensure(had_err, gt_double_equals_double(1.0+less_than_epsilon, 1.0));
  gt_ensure(had_err, gt_double_equals_double(1.0, 1.0+less_than_epsilon));

  gt_ensure(had_err, gt_double_compare(1.0, 1.0) == 0);
  gt_ensure(had_err, gt_double_compare(1.0, 1.1) < 0);
  gt_ensure(had_err, gt_double_compare(1.1, 1.0) > 0);
  gt_ensure(had_err, gt_double_compare(1.1, -1.0) > 0);
  gt_ensure(had_err, gt_double_compare(-1.1, -1.0) < 0);
  gt_ensure(had_err, gt_double_compare(1+less_than_epsilon, 1.0) == 0);
  gt_ensure(had_err, gt_double_compare(1+less_than_epsilon, -1.0) > 0);
  gt_ensure(had_err, gt_double_compare(-1+less_than_epsilon, -1.0) == 0);
  gt_ensure(had_err, gt_double_compare(-1+less_than_epsilon, 1.0) < 0);

  gt_ensure(had_err, gt_double_smaller_double(1.0, 1.1));
  gt_ensure(had_err, gt_double_smaller_double(-1.0, 1.1));
  gt_ensure(had_err, gt_double_smaller_double(-1.1, -1.0));
  gt_ensure(had_err, !gt_double_smaller_double(-1.0, -1.1));
  gt_ensure(had_err, !gt_double_smaller_double(1.0-less_than_epsilon, 1.0));

  return had_err;
}
Пример #6
0
void gt_graphics_cairo_draw_curve_data(GtGraphics *gg, double x, double y,
                                       GtColor color, double data[],
                                       unsigned long ndata, GtRange valrange,
                                       unsigned long height)
{
  unsigned long i, rnglen;
  double xpos;
  GtGraphicsCairo *g;
  g = gt_graphics_cairo_cast(gg);

  xpos = (((double)g->width-2*g->margin_x)/((double)ndata-1));
  rnglen = valrange.end - valrange.start;
  cairo_save(g->cr);
  cairo_move_to(g->cr,
                x,
                y+(1-(data[0]-valrange.start)/(double) rnglen)*height);
  for (i=1;i<ndata;i++)
  {
    double val, pval;
    if (gt_double_smaller_double(data[i], valrange.start)
          || gt_double_smaller_double(valrange.end, data[i]))
      break;
    val  = (double) (data[i]-valrange.start)/(double) rnglen;
    pval = (double) (data[i-1]-valrange.start)/(double) rnglen;
    gt_assert(val <= 1 && val >= 0 && pval >= 0 && pval <= 1);
    cairo_curve_to(g->cr,
                   x + ((i-0.5) * xpos),
                   y + (1-pval)   * height,
                   x + ((i-0.5) * xpos),
                   y + (1-val)    * height,
                   x + (i       * xpos),
                   y + (1-val)    * height);
  }
  cairo_set_source_rgba(g->cr, color.red,
                               color.green,
                               color.blue,
                               color.alpha);
  cairo_stroke(g->cr);
  cairo_restore(g->cr);
}
Пример #7
0
void gt_graphics_cairo_draw_text(GtGraphics *gg, double x, double y,
                                 const char *text)
{
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  cairo_text_extents_t ext;
  gt_assert(g && text);
  cairo_text_extents(g->cr, text, &ext);
  if (gt_double_smaller_double(g->width, x+ext.width))
    return;
  cairo_set_source_rgb(g->cr, 0, 0, 0);
  cairo_move_to(g->cr, x, y);
  cairo_show_text(g->cr, text);
}
Пример #8
0
double gt_graphics_cairo_get_text_width(GtGraphics *gg, const char* text)
{
  PangoRectangle rect;
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  gt_assert(g && text && g->layout);

  pango_layout_set_text(g->layout, text, -1);
  /* get text extents */

  pango_layout_get_pixel_extents(g->layout, &rect, NULL);

  gt_assert(gt_double_smaller_double(0, rect.width));
  return rect.width;
}
Пример #9
0
/* calculate divergence */
double gt_divergence(double E, /* relative error for divergence calculation */
                   double T, /* absolute error for exp shulen*/
                   double M, /* minimum for logarithm */
                   double threshold, /* abs error for divergence */
                   double shulen,
                   GtUword subjectLength,
                   double gc,
                   double *ln_n_fac,
                   GtUword n_s)
{
  double p, q,
         du, dl, dm, d, exp_shulen;
  double *s1;
  s1 = gt_calloc((size_t) n_s + 1, sizeof (double));

  p = gc / 2;
  q = (1.0 - gc) / 2.0;
  du = 0.0;
  dl = 1.0 - (2 * p * p + 2 * q * q);  /* dl < 0.75 */

  while (gt_double_smaller_double(threshold, (dl - du) / 2.0)) {
    dm = (du + dl) / 2.0;
    exp_shulen = expShulen(T, M, dm, p, subjectLength, ln_n_fac, s1, n_s);
    if (gt_double_smaller_double(shulen, exp_shulen))
      du = dm;
    else
      dl = dm;
    /* test the relative error between du and dl; if it is smaller than some
     * threshold, then break !! */
    if (fabs (dl - du) / dl <= E)
      break;
  }
  d = (du + dl) / 2.0;
  gt_free(s1);
  return d;
}
Пример #10
0
static int check_width(unsigned int width,
                       GtStyle *style,
                       GtError *err)
{
  int had_err = 0;
  double margins = MARGINS_DEFAULT;
  (void) gt_style_get_num(style, "format", "margins", &margins, NULL);
  if (gt_double_smaller_double(width - 2*margins, 0))
  {
    gt_error_set(err, "layout width must at least be twice the x-margin size "
                      "(2*%.1f=%.1f) but was %u",
                      margins,
                      2*margins,
                      width);
    had_err = -1;
  }
  return had_err;
}
Пример #11
0
void gt_graphics_cairo_draw_text(GtGraphics *gg, double x, double y,
                                 const char *text)
{
  PangoRectangle ink;
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  gt_assert(g && text && g->layout);

  pango_layout_set_text(g->layout, text, -1);

  /* get text extents */
  pango_layout_get_pixel_extents(g->layout, &ink, NULL);

  if (gt_double_smaller_double(g->width, x+ink.width))
    return;

  cairo_set_source_rgb(g->cr, 0, 0, 0);
  cairo_move_to(g->cr, x, y-g->font_height);
  pango_cairo_show_layout(g->cr, g->layout);
}
double gt_text_width_calculator_cairo_get_text_width(GtTextWidthCalculator *twc,
                                                     const char *text,
                                                     GT_UNUSED GtError *err)
{
  GtTextWidthCalculatorCairo *twcc;
  PangoRectangle rect;
  gt_assert(twc && text);
  twcc = gt_text_width_calculator_cairo_cast(twc);

  /* redo layout */
  pango_layout_set_text(twcc->layout, text, -1);

  /* get extents */
  pango_layout_get_pixel_extents(twcc->layout, &rect, NULL);

  if (twcc->style)
    cairo_restore(twcc->context);
  gt_assert(gt_double_smaller_double(0, rect.width));
  return rect.width;
}
Пример #13
0
/* This function orders GtElements by z-index or type. This enables the sketch
   function to paint elements in a specific order based on their type
   (painter's algorithm-like) */
static int elemcmp(const void *a, const void *b, void *data)
{
  const char *type_a, *type_b;
  double zindex_a = GT_UNDEF_DOUBLE, zindex_b= GT_UNDEF_DOUBLE;
  GtStyle *sty = (GtStyle*) data;
  GtElement *elem_a = *(GtElement**) a;
  GtElement *elem_b = *(GtElement**) b;

  type_a = gt_element_get_type(elem_a);
  type_b = gt_element_get_type(elem_b);

  /* same types are equal, no further action needed */
  if (type_a == type_b)
    return 0;
  /* if not, then get z-index from style */
  if (sty)
  {
    (void) gt_style_get_num(sty, type_a, "z_index", &zindex_a, NULL, NULL);
    (void) gt_style_get_num(sty, type_b, "z_index", &zindex_b, NULL, NULL);
  }
  /* only one is set -> put types with set z-indices always on top of others*/
  if (zindex_a == GT_UNDEF_DOUBLE && zindex_b != GT_UNDEF_DOUBLE)
    return -1;
  if (zindex_b == GT_UNDEF_DOUBLE && zindex_a != GT_UNDEF_DOUBLE)
    return 1;
  /* none is set, fall back to default alphabetic ordering */
  if (zindex_a == GT_UNDEF_DOUBLE && zindex_b == GT_UNDEF_DOUBLE)
  {
    if (strcmp(type_a, type_b) < 0)
      return 1;
    return -1;
  }
  /* both z-indices are set */
  if (gt_double_equals_double(zindex_a, zindex_b))
    return 0;
  if (gt_double_smaller_double(zindex_a, zindex_b))
    return -1;
  return 1;
}
Пример #14
0
int gt_block_get_max_height(const GtBlock *block, double *result,
                            const GtStyle *sty, GtError *err)
{
  GtUword max_height = 0;
  GtStyleQueryStatus rval = GT_STYLE_QUERY_OK;
  GtUword i;
  gt_assert(block && sty);
  for (i=0;i<gt_array_size(block->elements);i++) {
    GtElement *elem;
    double height = 0;
    elem = *(GtElement**) gt_array_get(block->elements, i);
    /* get default or image-wide bar height */
    rval = gt_style_get_num(sty, "format", "bar_height", &height, NULL, err);
    switch (rval) {
    case GT_STYLE_QUERY_ERROR:
      return -1;
      break; /* should never reach this */
    case GT_STYLE_QUERY_NOT_SET:
      height = BAR_HEIGHT_DEFAULT;
      break;
    default:
      /* do nothing */
      break;
    }
    /* try to get type-specific bar height */
    rval = gt_style_get_num(sty, gt_element_get_type(elem), "bar_height",
                            &height, gt_element_get_node_ref(elem),
                            err);
    if (rval == GT_STYLE_QUERY_ERROR) {
      return -1;
    }
    if (gt_double_smaller_double(max_height, height))
      max_height = height;
  }
  *result = max_height;
  return 0;
}
Пример #15
0
void gt_firstcodes_spacelog_add(GtFirstcodesspacelog *fcsl,
                                int line,
                                const char *filename,
                                bool add,
                                const char *title,
                                bool work,
                                size_t size)
{
  GtFirstcodespacelogentry *entry;
  size_t logspace;

  if (add)
  {
    entry = gt_spacelog_find(fcsl,title);
    if (entry != NULL)
    {
      if (entry->size != 0)
      {
        fprintf(stderr,"existing entry for title \"%s\""
                       "(from file %s, line %d) "
                       "in spacelog entries must have size 0\n",
                       title,filename,line);
        exit(GT_EXIT_PROGRAMMING_ERROR);
      }
      gt_spacelog_updateaddentry(entry,filename,line,title,size,work);
    } else
    {
      gt_spacelog_addentry(fcsl,filename,line,title,size,work);
    }
    if (work)
    {
      fcsl->workspace += size;
    } else
    {
      fcsl->splitspace += size;
    }
    gt_firstcodes_updatemax(fcsl);
  } else
  {
    entry = gt_spacelog_find(fcsl,title);
    if (entry == NULL)
    {
      fprintf(stderr,"cannot find title \"%s\" (from file %s, line %d) "
                     "in spacelog entries\n",title,filename,line);
      (void) gt_firstcodes_spacelog_showentries(stderr,fcsl);
      exit(GT_EXIT_PROGRAMMING_ERROR);
    }
    if ((entry->work && !work) || (!entry->work && work))
    {
      fprintf(stderr,"for title \"%s\" (from file %s, line %d) "
                     "in spacelog entries: inconsistent work/splitassignment\n",
               title,filename,line);
      exit(GT_EXIT_PROGRAMMING_ERROR);
    }
    if (work)
    {
      if (entry->size > fcsl->workspace)
      {
        gt_firstcodes_subtract_error(title, filename, line, entry->size, true,
                                     fcsl->workspace);
        (void) gt_firstcodes_spacelog_showentries(stderr,fcsl);
        exit(GT_EXIT_PROGRAMMING_ERROR);
      }
      fcsl->workspace -= entry->size;
    } else
    {
      if (entry->size > fcsl->splitspace)
      {
        gt_firstcodes_subtract_error(title, filename, line, entry->size, false,
                                     fcsl->splitspace);
        (void) gt_firstcodes_spacelog_showentries(stderr,fcsl);
        exit(GT_EXIT_PROGRAMMING_ERROR);
      }
      fcsl->splitspace -= entry->size;
    }
    if (size > 0)
    {
      gt_spacelog_updateaddentry(entry,filename,line,title,size,work);
      if (work)
      {
        fcsl->workspace += size;
      } else
      {
        fcsl->splitspace += size;
      }
      gt_firstcodes_updatemax(fcsl);
      if (size > entry->size)
      {
        add = true;
        size -= entry->size;
      } else
      {
        size = entry->size - size;
      }
    } else
    {
      size = entry->size;
      entry->size = 0;
    }
  }
  logspace = fcsl->workspace+fcsl->splitspace;
  gt_log_log(
#ifdef SKDEBUG
             "file %s, line %d: "
#endif
             "%s %s= %.2f, %s, w=%.2f, s=%.2f, sum=%.2f MB",
#ifdef SKDEBUG
             filename,
             line,
#endif
             work ? "w" : "s",
             add ? "+" : "-",
             GT_MEGABYTES(size),
             title,
             GT_MEGABYTES(fcsl->workspace),
             GT_MEGABYTES(fcsl->splitspace),
             GT_MEGABYTES(logspace));
#ifdef SKDEBUG
  if (gt_ma_bookkeeping_enabled())
  {
    unsigned long realspace = gt_ma_get_space_current() +
                              gt_fa_get_space_current();
    gt_log_log("current space usage %.2f MB (%.2f+%.2f)",
                                GT_MEGABYTES(realspace),
                                GT_MEGABYTES(gt_ma_get_space_current()),
                                GT_MEGABYTES(gt_fa_get_space_current()));
    if (fcsl->calc_difference)
    {
      double percent_difference;

      if ((unsigned long) logspace > realspace)
      {
        fprintf(stderr,"overestimating logspace\n");
        exit(GT_EXIT_PROGRAMMING_ERROR);
      }
      if (realspace >= 1000000UL)
      {
        /*
        printf("realspace=%lu,logspace=%lu\n",realspace,
                                              (unsigned long) logspace);
        */
        percent_difference = 100.0 * (double) (realspace - logspace)/realspace;
        if (gt_double_larger_double(percent_difference,3.0))
        {
          fprintf(stderr,"space difference of %.2f%% is too large\n",
                       percent_difference);
          exit(GT_EXIT_PROGRAMMING_ERROR);
        }
        if (gt_double_smaller_double(fcsl->max_percent_difference,
                                     percent_difference))
        {
          fcsl->max_percent_difference = percent_difference;
        }
      }
    }
  }
#endif
}
Пример #16
0
int gt_canvas_cairo_visit_block(GtCanvas *canvas, GtBlock *block,
                                GtError *err)
{
  int had_err = 0, arrow_status = ARROW_NONE;
  GtRange block_range;
  GtDrawingRange draw_range;
  GtColor grey, fillcolor, strokecolor;
  double block_start,
         block_width,
         bar_height = BAR_HEIGHT_DEFAULT,
         min_len_block = MIN_LEN_BLOCK_DEFAULT,
         arrow_width = ARROW_WIDTH_DEFAULT,
         stroke_width = STROKE_WIDTH_DEFAULT;
  const char *caption, *btype;
  GtStrand strand;
  double maxbarheight;
  btype = gt_block_get_type(block);

  gt_assert(canvas && block);

  grey.red = grey.green = grey.blue = DEFAULT_GREY_TONE;
  grey.alpha = 0.5;
  strand = gt_block_get_strand(block);
  block_range = gt_block_get_range(block);
  if (gt_block_get_max_height(block, &maxbarheight, canvas->pvt->sty, err)) {
    return -1;
  }
  if (gt_style_get_num(canvas->pvt->sty, "format", "bar_height", &bar_height,
                       NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  if (gt_style_get_num(canvas->pvt->sty, "format", "min_len_block",
                       &min_len_block,NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  if (gt_style_get_num(canvas->pvt->sty, "format", "arrow_width", &arrow_width,
                       NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  if (gt_style_get_num(canvas->pvt->sty, "format", "stroke_width",
                       &stroke_width, NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  if (gt_style_get_color_with_track(canvas->pvt->sty,
                                 btype, "stroke", &strokecolor,
                                 gt_block_get_top_level_feature(block),
                                 gt_track_get_title(canvas->pvt->current_track),
                                 err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }

  if (strand == GT_STRAND_REVERSE || strand == GT_STRAND_BOTH)
    arrow_status = ARROW_LEFT;
  if (strand == GT_STRAND_FORWARD || strand == GT_STRAND_BOTH)
    arrow_status = (arrow_status == ARROW_LEFT ? ARROW_BOTH : ARROW_RIGHT);

  /* calculate scaled drawing coordinates for this canvas */
  draw_range = gt_coords_calc_generic_range(block_range,
                                            canvas->pvt->viewrange);
  draw_range.start *= canvas->pvt->width-2*canvas->pvt->margins;
  draw_range.end *= canvas->pvt->width-2*canvas->pvt->margins;
  block_start = draw_range.start + canvas->pvt->margins;
  block_width = draw_range.end - draw_range.start;

  /* draw block caption */
  if (gt_block_caption_is_visible(block))
  {
    caption = gt_str_get(gt_block_get_caption(block));
    if (caption)
    {
      double theight = gt_graphics_get_text_height(canvas->pvt->g),
             captionspace = CAPTION_BAR_SPACE_DEFAULT;
      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_num(canvas->pvt->sty,
                          "format", "block_caption_font_size",
                          &theight, NULL, err) == GT_STYLE_QUERY_ERROR) {
        return -1;
      }
      gt_graphics_set_font(canvas->pvt->g,
                           "Sans",
                           SLANT_NORMAL,
                           WEIGHT_NORMAL,
                           theight);
      gt_graphics_draw_text_clip(canvas->pvt->g,
                                 block_start,
                                 canvas->pvt->y - bar_height/2
                                                - captionspace,
                                 caption);
    }
  }

  /* do not draw further details in very small blocks */
  if (!gt_block_has_only_one_fullsize_element(block)
       && gt_double_smaller_double(block_width, min_len_block))
  {
    /* optimise drawing for very narrow blocks,
       if <= 1px/pt width, draw as simple lines */
    if (canvas->pvt->bt && draw_range.end-draw_range.start <= 1.1)
    {
      if (!gt_bittab_bit_is_set(canvas->pvt->bt,
                                (unsigned long) draw_range.start)) {
        gt_graphics_draw_vertical_line(canvas->pvt->g,
                                       block_start,
                                       canvas->pvt->y - bar_height/2,
                                       strokecolor,
                                       bar_height,
                                       stroke_width);
        gt_bittab_set_bit(canvas->pvt->bt, (unsigned long) draw_range.start);
      }
    } else {
      if (gt_style_get_color_with_track(canvas->pvt->sty,
                             btype, "fill",
                             &fillcolor,
                             gt_block_get_top_level_feature(block),
                             gt_track_get_title(canvas->pvt->current_track),
                             err) == GT_STYLE_QUERY_ERROR) {
        return -1;
      }

      gt_graphics_draw_box(canvas->pvt->g,
                           block_start,
                           canvas->pvt->y - bar_height/2,
                           block_width,
                           bar_height,
                           fillcolor,
                           arrow_status,
                           arrow_width,
                           stroke_width,
                           strokecolor,
                           true);

      /* draw arrowheads at clipped margins */
      if (draw_range.clip == CLIPPED_LEFT || draw_range.clip == CLIPPED_BOTH)
          gt_graphics_draw_arrowhead(canvas->pvt->g,
                                     canvas->pvt->margins - 10,
                                     canvas->pvt->y - 4,
                                     grey,
                                     ARROW_LEFT);
      if (draw_range.clip == CLIPPED_RIGHT || draw_range.clip == CLIPPED_BOTH)
          gt_graphics_draw_arrowhead(canvas->pvt->g,
                                     canvas->pvt->width-canvas->pvt->margins
                                       + 10,
                                     canvas->pvt->y - 4,
                                     grey,
                                     ARROW_RIGHT);
    }

    /* register coordinates in GtImageInfo object if available */
    if (canvas->pvt->ii)
    {
      GtRecMap *rm = gt_rec_map_new(block_start,
                                    canvas->pvt->y - bar_height/2,
                                    block_start + block_width,
                                    canvas->pvt->y + bar_height/2,
                                    (GtFeatureNode*) /* XXX */
                                      gt_block_get_top_level_feature(block));
      gt_image_info_add_rec_map(canvas->pvt->ii, rm);
      gt_rec_map_set_omitted_children(rm, true);
    }
    /* signal break */
    return 1;
  }

  /* get stroke color */
  if (gt_style_get_color(canvas->pvt->sty,
                         "format", "default_stroke_color",
                         &strokecolor, NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }

  /* draw parent block boundaries */
  gt_graphics_draw_dashes(canvas->pvt->g,
                          block_start,
                          canvas->pvt->y - bar_height/2,
                          block_width,
                          bar_height,
                          ARROW_NONE,
                          arrow_width,
                          stroke_width,
                          strokecolor);
  return had_err;
}
Пример #17
0
void gt_graphics_cairo_draw_box(GtGraphics *gg, double x, double y,
                                double width, double height,
                                GtColor fill_color, ArrowStatus arrow_status,
                                double arrow_width, double stroke_width,
                                GtColor stroke_color, bool dashed)
{
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  double dashes[]={2.0};
  bool widthdiff_geq0;
  gt_assert(g);

  /* save cairo context */
  cairo_save(g->cr);
  cairo_rectangle(g->cr, rnd_to_nhalf(g->margin_x), g->margin_y,
                  rnd_to_nhalf(g->width-2*g->margin_x),
                  g->height-2*g->margin_y);
  cairo_clip(g->cr);

  widthdiff_geq0 = gt_double_smaller_double(0, width - arrow_width);
  /* construct shape of the box or arrow */
  switch (arrow_status)
  {
    case ARROW_RIGHT:
      cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y));
      if (widthdiff_geq0)
        cairo_line_to(g->cr, x + width - arrow_width, rnd_to_nhalf(y));
      cairo_line_to(g->cr, rnd_to_nhalf(x + width),
                           rnd_to_nhalf(y + height / 2));
      if (widthdiff_geq0)
        cairo_line_to(g->cr, x + width - arrow_width, rnd_to_nhalf(y + height));
      cairo_line_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height));
      cairo_close_path(g->cr);
      break;
    case ARROW_LEFT:
      cairo_move_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y));
      if (widthdiff_geq0) {
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), rnd_to_nhalf(y));
      }
      cairo_line_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height / 2));
      if (widthdiff_geq0) {
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width),
                             rnd_to_nhalf(y + height));
      }
      cairo_line_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y + height));
      cairo_close_path(g->cr);
      break;
    case ARROW_BOTH:
      cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height/2));
      if (gt_double_smaller_double(width, 2*arrow_width))
      {
        cairo_line_to(g->cr, rnd_to_nhalf(x + width/2), rnd_to_nhalf(y));
        cairo_line_to(g->cr, rnd_to_nhalf(x + width),
                             rnd_to_nhalf(y + height/2));
        cairo_line_to(g->cr, rnd_to_nhalf(x + width/2),
                             rnd_to_nhalf(y + height));
      }
      else
      {
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), rnd_to_nhalf(y));
        cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width),
                             rnd_to_nhalf(y));
        cairo_line_to(g->cr, rnd_to_nhalf(x + width),
                             rnd_to_nhalf(y + height/2));
        cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width),
                             rnd_to_nhalf(y + height));
        cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height);
      }
      cairo_close_path(g->cr);
      break;
    case ARROW_NONE:
      cairo_rectangle(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y), width, height);
   }
   /* fill area */
   cairo_set_source_rgba(g->cr, fill_color.red,
                                fill_color.green,
                                fill_color.blue,
                                fill_color.alpha);
   cairo_fill_preserve(g->cr);
   /* draw outline */
   cairo_set_line_width(g->cr, stroke_width);
   cairo_set_source_rgba(g->cr, stroke_color.red,
                                stroke_color.green,
                                stroke_color.blue,
                                stroke_color.alpha);
   if (dashed)
     cairo_set_dash(g->cr, dashes, 1, (double) 0);
   cairo_stroke(g->cr);
   /* restore cairo context */
   cairo_restore(g->cr);
}
Пример #18
0
static int gt_sketch_page_runner(GT_UNUSED int argc,
                                 const char **argv,
                                 int parsed_args,
                                 void *tool_arguments,
                                 GtError *err)
{
  SketchPageArguments *arguments = tool_arguments;
  int had_err = 0;
  GtFeatureIndex *features = NULL;
  GtRange qry_range, sequence_region_range;
  GtStyle *sty = NULL;
  GtStr *prog, *gt_style_file;
  GtDiagram *d = NULL;
  GtLayout *l = NULL;
  GtBioseq *bioseq = NULL;
  GtCanvas *canvas = NULL;
  const char *seqid = NULL, *outfile;
  unsigned long start, height, num_pages = 0;
  double offsetpos, usable_height;
  cairo_surface_t *surf = NULL;
  cairo_t *cr = NULL;
  GtTextWidthCalculator *twc;
  gt_error_check(err);

  features = gt_feature_index_memory_new();

  if (cairo_version() < CAIRO_VERSION_ENCODE(1, 8, 6))
    gt_warning("Your cairo library (version %s) is older than version 1.8.6! "
               "These versions contain a bug which may result in "
               "corrupted PDF output!", cairo_version_string());

  /* get style */
  sty = gt_style_new(err);
  if (gt_str_length(arguments->stylefile) == 0)
  {
    prog = gt_str_new();
    gt_str_append_cstr_nt(prog, argv[0],
                          gt_cstr_length_up_to_char(argv[0], ' '));
    gt_style_file = gt_get_gtdata_path(gt_str_get(prog), err);
    gt_str_delete(prog);
    gt_str_append_cstr(gt_style_file, "/sketch/default.style");
  }
  else
  {
    gt_style_file = gt_str_ref(arguments->stylefile);
  }
  had_err = gt_style_load_file(sty, gt_str_get(gt_style_file), err);

  outfile = argv[parsed_args];
  if (!had_err)
  {
    /* get features */
    had_err = gt_feature_index_add_gff3file(features, argv[parsed_args+1], err);
     if (!had_err && gt_str_length(arguments->seqid) == 0) {
      seqid = gt_feature_index_get_first_seqid(features);
      if (seqid == NULL)
      {
        gt_error_set(err, "GFF input file must contain a sequence region!");
        had_err = -1;
      }
    }
    else if (!had_err
               && !gt_feature_index_has_seqid(features,
                                              gt_str_get(arguments->seqid)))
    {
      gt_error_set(err, "sequence region '%s' does not exist in GFF input file",
                   gt_str_get(arguments->seqid));
      had_err = -1;
    }
    else if (!had_err)
      seqid = gt_str_get(arguments->seqid);
  }

  /* set text */
  if (gt_str_length(arguments->text) == 0)
  {
    gt_str_delete(arguments->text);
    arguments->text = gt_str_new_cstr(argv[parsed_args+1]);
  }

  if (!had_err)
  {
    /* set display range */
    gt_feature_index_get_range_for_seqid(features, &sequence_region_range,
                                         seqid);
    qry_range.start = (arguments->range.start == GT_UNDEF_ULONG ?
                         sequence_region_range.start :
                         arguments->range.start);
    qry_range.end   = (arguments->range.end == GT_UNDEF_ULONG ?
                         sequence_region_range.end :
                         arguments->range.end);

    /* set output format */
    if (strcmp(gt_str_get(arguments->format), "pdf") == 0)
    {
      surf = cairo_pdf_surface_create(outfile,
                                      mm_to_pt(arguments->pwidth),
                                      mm_to_pt(arguments->pheight));
    }
    else if (strcmp(gt_str_get(arguments->format), "ps") == 0)
    {
      surf =  cairo_ps_surface_create(outfile,
                                      mm_to_pt(arguments->pwidth),
                                      mm_to_pt(arguments->pheight));
    }
    gt_log_log("created page with %.2f:%.2f dimensions\n",
                                                  mm_to_pt(arguments->pwidth),
                                                  mm_to_pt(arguments->pheight));

    offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER;
    usable_height = mm_to_pt(arguments->pheight)
                              - arguments->theight
                              - arguments->theight
                              - 4*TEXT_SPACER;

    if (gt_str_length(arguments->seqfile) > 0) {
      bioseq = gt_bioseq_new(gt_str_get(arguments->seqfile), err);
    }

    cr = cairo_create(surf);
    cairo_set_font_size(cr, 8);
    twc = gt_text_width_calculator_cairo_new(cr, sty);
    for (start = qry_range.start; start <= qry_range.end;
         start += arguments->width)
    {
      GtRange single_range;
      GtCustomTrack *ct = NULL;
      const char *seq;
      single_range.start = start;
      single_range.end = start + arguments->width;

      if (had_err)
        break;

      d = gt_diagram_new(features, seqid, &single_range, sty, err);
      if (!d) {
        had_err = -1;
        break;
      }
      if (bioseq) {
        seq = gt_bioseq_get_sequence(bioseq, 0);
        ct = gt_custom_track_gc_content_new(seq,
                                      gt_bioseq_get_sequence_length(bioseq, 0),
                                      800, 70, 0.4, true);
        gt_diagram_add_custom_track(d, ct);
      }

      l = gt_layout_new_with_twc(d, mm_to_pt(arguments->width), sty, twc, err);
      had_err = gt_layout_get_height(l, &height, err);
      if (!had_err) {
        if (gt_double_smaller_double(usable_height - 10 - 2*TEXT_SPACER
              - arguments->theight, offsetpos + height))
        {
            draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1],
                        seqid, num_pages, mm_to_pt(arguments->pwidth),
                        mm_to_pt(arguments->pheight),
                        arguments->theight);
          cairo_show_page(cr);
          offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER;
          num_pages++;
        }
        canvas = gt_canvas_cairo_context_new(sty,
                                             cr,
                                             offsetpos,
                                             mm_to_pt(arguments->pwidth),
                                             height,
                                             NULL,
                                             err);
        if (!canvas)
          had_err = -1;
        offsetpos += height;
        if (!had_err)
          had_err = gt_layout_sketch(l, canvas, err);
      }
      gt_canvas_delete(canvas);
      gt_layout_delete(l);
      gt_diagram_delete(d);
      if (ct)
        gt_custom_track_delete(ct);
    }
    draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1], seqid,
                num_pages, mm_to_pt(arguments->pwidth),
                mm_to_pt(arguments->pheight),
                arguments->theight);
    cairo_show_page(cr);
    num_pages++;
    gt_log_log("finished, should be %lu pages\n", num_pages);
    gt_text_width_calculator_delete(twc);
    cairo_destroy(cr);
    cairo_surface_flush(surf);
    cairo_surface_finish(surf);
    cairo_surface_destroy(surf);
    cairo_debug_reset_static_data();
    if (bioseq)
      gt_bioseq_delete(bioseq);
    gt_style_delete(sty);
    gt_str_delete(gt_style_file);
    gt_feature_index_delete(features);
  }
  return had_err;
}
Пример #19
0
int gt_canvas_cairo_visit_element(GtCanvas *canvas, GtElement *elem,
                                  GtError *err)
{
  int had_err = 0, arrow_status = ARROW_NONE;
  GtRange elem_range = gt_element_get_range(elem);
  GtDrawingRange draw_range;
  double elem_start = GT_UNDEF_DOUBLE,
         elem_width = GT_UNDEF_DOUBLE,
         stroke_width = STROKE_WIDTH_DEFAULT,
         bar_height = BAR_HEIGHT_DEFAULT,
         arrow_width = ARROW_WIDTH_DEFAULT;
  GtColor elem_color, grey, fill_color;
  const char *type;
  GtStyleQueryStatus rval;
  GtStr *style;
  GtStrand strand = gt_element_get_strand(elem);

  gt_assert(canvas && elem);

  /* This shouldn't happen. */
  if (!gt_range_overlap(&elem_range, &canvas->pvt->viewrange))
    return -1;

  type = gt_element_get_type(elem);
  grey.red = grey.green = grey.blue = .85;
  grey.alpha = 0.5;

  /* get default or image-wide bar height */
  if (gt_style_get_num(canvas->pvt->sty, "format", "bar_height", &bar_height,
                       NULL, err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  /* try to get type-specific bar height */
  if (gt_style_get_num_with_track(canvas->pvt->sty, type, "bar_height",
                       &bar_height,
                       gt_element_get_node_ref(elem),
                       gt_track_get_title(canvas->pvt->current_track),
                       err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  /* get default or image-wide arrow width */
  if (gt_style_get_num(canvas->pvt->sty, "format", "arrow_width", &arrow_width,
                        NULL, err)== GT_STYLE_QUERY_ERROR) {
    return -1;
  }
  /* try to get type-specific arrow width */
  if (gt_style_get_num_with_track(canvas->pvt->sty, type, "arrow_width",
                       &arrow_width,
                       gt_element_get_node_ref(elem),
                       gt_track_get_title(canvas->pvt->current_track),
                       err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }

  if ((strand == GT_STRAND_REVERSE || strand == GT_STRAND_BOTH)
         /*&& delem == gt_dlist_first(elems)*/)
    arrow_status = ARROW_LEFT;
  if ((strand == GT_STRAND_FORWARD || strand == GT_STRAND_BOTH)
         /*&& gt_dlistelem_next(delem) == NULL*/)
    arrow_status = (arrow_status == ARROW_LEFT ? ARROW_BOTH : ARROW_RIGHT);

  gt_log_log("processing element from %lu to %lu, strand %d\n",
             elem_range.start, elem_range.end, (int) strand);

  draw_range = gt_coords_calc_generic_range(elem_range, canvas->pvt->viewrange);
  draw_range.start *= (canvas->pvt->width-2*canvas->pvt->margins);
  draw_range.end *= (canvas->pvt->width-2*canvas->pvt->margins);
  elem_start = draw_range.start + canvas->pvt->margins;
  elem_width = draw_range.end - draw_range.start;
  gt_assert(elem_start != GT_UNDEF_DOUBLE && elem_width != GT_UNDEF_DOUBLE);

  if (gt_element_is_marked(elem)) {
    if (gt_style_get_color_with_track(canvas->pvt->sty, type, "stroke_marked",
                           &elem_color, gt_element_get_node_ref(elem),
                           gt_track_get_title(canvas->pvt->current_track),
                           err) == GT_STYLE_QUERY_ERROR) {
      return -1;
    }
    if (gt_style_get_num_with_track(canvas->pvt->sty, "format",
                          "stroke_marked_width",
                          &stroke_width, gt_element_get_node_ref(elem),
                          gt_track_get_title(canvas->pvt->current_track),
                          err) == GT_STYLE_QUERY_ERROR) {
    return -1;
    }
  }
  else {
    if (gt_style_get_color_with_track(canvas->pvt->sty, type, "stroke",
                              &elem_color,
                              gt_element_get_node_ref(elem),
                              gt_track_get_title(canvas->pvt->current_track),
                              err) == GT_STYLE_QUERY_ERROR) {
      return -1;
    }
    if (gt_style_get_num_with_track(canvas->pvt->sty, "format", "stroke_width",
                         &stroke_width,
                         gt_element_get_node_ref(elem),
                         gt_track_get_title(canvas->pvt->current_track),
                         err) == GT_STYLE_QUERY_ERROR) {
      return -1;
    }
    if (gt_style_get_num_with_track(canvas->pvt->sty, type, "stroke_width",
                         &stroke_width,
                         gt_element_get_node_ref(elem),
                         gt_track_get_title(canvas->pvt->current_track),
                         err) == GT_STYLE_QUERY_ERROR) {
      return -1;
    }
  }
  if (gt_style_get_color_with_track(canvas->pvt->sty, type, "fill",
                                 &fill_color,
                                 gt_element_get_node_ref(elem),
                                 gt_track_get_title(canvas->pvt->current_track),
                                 err) == GT_STYLE_QUERY_ERROR) {
    return -1;
  }

  if (canvas->pvt->bt &&
          gt_double_smaller_double(draw_range.end-draw_range.start, 1.1))
  {
    if ((unsigned long) draw_range.start > gt_bittab_size(canvas->pvt->bt))
      return had_err;
    if (gt_bittab_bit_is_set(canvas->pvt->bt, (unsigned long) draw_range.start))
      return had_err;
    gt_graphics_draw_vertical_line(canvas->pvt->g,
                                   elem_start,
                                   canvas->pvt->y - bar_height/2,
                                   elem_color,
                                   bar_height,
                                   stroke_width);
    gt_bittab_set_bit(canvas->pvt->bt, (unsigned long) draw_range.start);
  }

  /* register coordinates in GtImageInfo object if available */
  if (canvas->pvt->ii)
  {
    GtRecMap *rm = gt_rec_map_new(elem_start, canvas->pvt->y - bar_height/2,
                                  elem_start+elem_width,
                                  canvas->pvt->y+bar_height/2,
                                  (GtFeatureNode*)
                                    gt_element_get_node_ref(elem));
    gt_image_info_add_rec_map(canvas->pvt->ii, rm);
    }

  if (canvas->pvt->bt && draw_range.end-draw_range.start <= 1.1)
  {
    return had_err;
  }

  gt_log_log("drawing element from %f to %f, arrow status: %d",
             draw_range.start, draw_range.end, arrow_status);

  /* draw each element according to style set in the style */
  style = gt_str_new();
  rval = gt_style_get_str_with_track(canvas->pvt->sty, type, "style", style,
                          gt_element_get_node_ref(elem),
                          gt_track_get_title(canvas->pvt->current_track),
                          err);
  switch (rval) {
    case GT_STYLE_QUERY_NOT_SET:
      gt_str_set(style, "box");    /* default style */
      break;
    case GT_STYLE_QUERY_ERROR:
      gt_str_delete(style);
      gt_assert(gt_error_is_set(err));
      return -1;
    default:
      break;
  }

  if (strcmp(gt_str_get(style), "box") == 0)
  {
    gt_graphics_draw_box(canvas->pvt->g,
                         elem_start,
                         canvas->pvt->y - bar_height/2,
                         elem_width,
                         bar_height,
                         fill_color,
                         arrow_status,
                         arrow_width,
                         stroke_width,
                         elem_color,
                         false);
  }
  else if (strcmp(gt_str_get(style), "rectangle") == 0)
  {
    gt_graphics_draw_box(canvas->pvt->g,
                         elem_start,
                         canvas->pvt->y - bar_height/2,
                         elem_width,
                         bar_height,
                         fill_color,
                         ARROW_NONE,
                         arrow_width,
                         stroke_width,
                         elem_color,
                         false);
  }
  else if (strcmp(gt_str_get(style), "caret") == 0)
  {
    gt_graphics_draw_caret(canvas->pvt->g,
                           elem_start,
                           canvas->pvt->y - bar_height/2,
                           elem_width,
                           bar_height,
                           ARROW_NONE,
                           arrow_width,
                           stroke_width,
                           elem_color);
  }
  else if (strcmp(gt_str_get(style), "dashes") == 0)
  {
    gt_graphics_draw_dashes(canvas->pvt->g,
                            elem_start,
                            canvas->pvt->y - bar_height/2,
                            elem_width,
                            bar_height,
                            arrow_status,
                            arrow_width,
                            stroke_width,
                            elem_color);
  }
  else if (strcmp(gt_str_get(style), "line") == 0)
  {
    gt_graphics_draw_horizontal_line(canvas->pvt->g,
                                     elem_start,
                                     canvas->pvt->y - bar_height/2,
                                     elem_color,
                                     elem_width,
                                     1.0);
  }
  else
  {
     gt_graphics_draw_box(canvas->pvt->g,
                          elem_start,
                          canvas->pvt->y - bar_height/2,
                          elem_width,
                          bar_height,
                          fill_color,
                          arrow_status,
                          arrow_width,
                          stroke_width,
                          elem_color,
                          false);
  }
  gt_str_delete(style);

  /* draw arrowheads at clipped margins */
  if (draw_range.clip == CLIPPED_LEFT || draw_range.clip == CLIPPED_BOTH)
      gt_graphics_draw_arrowhead(canvas->pvt->g,
                                 canvas->pvt->margins - 10,
                                 canvas->pvt->y - 4,
                                 grey,
                                 ARROW_LEFT);
  if (draw_range.clip == CLIPPED_RIGHT || draw_range.clip == CLIPPED_BOTH)
      gt_graphics_draw_arrowhead(canvas->pvt->g,
                                 canvas->pvt->width-canvas->pvt->margins + 10,
                                 canvas->pvt->y - 4,
                                 grey,
                                 ARROW_RIGHT);
  return had_err;
}