]> git.cworth.org Git - acre/commitdiff
Draw title and axis labels with pango
authorCarl Worth <cworth@cworth.org>
Sun, 25 Jan 2009 08:48:28 +0000 (19:48 +1100)
committerCarl Worth <cworth@cworth.org>
Thu, 16 Apr 2009 19:01:42 +0000 (12:01 -0700)
Many thanks to Owen and Behdad for all the pango love.

The layout iterates if necessary do to any wrapping from overly long
title or axis labels.

Makefile
acre.c
acre.h

index fcbe7ae3cbfb5ce67d1f483051f5525a11d63667..1d5beef2a8dabef652cc03c4e54fe8cc6cfa6a1f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,9 +7,9 @@ acre_test_SOURCES = \
        xmalloc.c \
        xmalloc.h
 
-acre_test_LDFLAGS=$$(pkg-config --libs cairo)
+acre_test_LDFLAGS=$$(pkg-config --libs pangocairo)
 
-acre_test_CFLAGS=$$(pkg-config --cflags cairo) \
+acre_test_CFLAGS=$$(pkg-config --cflags pangocairo) \
        -Wall -Wextra -Wpointer-arith -Wstrict-prototypes \
        -Wmissing-prototypes -Wmissing-declarations \
        -Wnested-externs -Wno-unused-parameter
diff --git a/acre.c b/acre.c
index 672ba62bf776aaba82a4d966fc057a80ddcbe53d..e7b4a0f82b1984dfe47a093ad0252a6d7bb3539a 100644 (file)
--- a/acre.c
+++ b/acre.c
@@ -21,6 +21,7 @@
 #include "xmalloc.h"
 
 #include <string.h>
+#include <math.h>
 
 typedef struct _acre_data_point_2d {
     double x;
@@ -124,6 +125,12 @@ acre_add_data (acre_t *acre, acre_data_t *data)
     acre->num_data++;
 }
 
+#define ACRE_FONT_FAMILY "sans"
+#define ACRE_FONT_SIZE 12
+#define ACRE_TITLE_FONT_SIZE 32
+#define ACRE_PAD (ACRE_FONT_SIZE)
+#define ACRE_TICK_SIZE 4
+
 /* Draw the plot to the given cairo context within a user-space
  * rectangle from (0, 0) to (width, height). This size includes all
  * space for extra-plot elements (such as the title, the axis labels,
@@ -132,13 +139,105 @@ acre_add_data (acre_t *acre, acre_data_t *data)
 void
 acre_draw (acre_t *acre, cairo_t *cr, double width, double height)
 {
-    cairo_save (cr);
+    PangoFontDescription *acre_font, *title_font;
+    PangoLayout *title_layout, *x_axis_layout, *y_axis_layout;
+    int title_width, title_height;
+    int x_axis_width, x_axis_height;
+    int y_axis_width, y_axis_height;
+    PangoRectangle chart, new_chart;
 
-    cairo_rectangle (cr, 0, 0, width, height);
+    cairo_save (cr);
 
-    cairo_set_source_rgb (cr, 1, 0, 1);
+    cairo_set_source_rgb (cr, 1, 1, 1);
 
     cairo_paint (cr);
+
+    acre_font = pango_font_description_new ();
+    pango_font_description_set_family (acre_font, ACRE_FONT_FAMILY);
+    pango_font_description_set_absolute_size (acre_font,
+                                             ACRE_FONT_SIZE * PANGO_SCALE);
+
+    title_font = pango_font_description_new ();
+    pango_font_description_set_family (title_font, ACRE_FONT_FAMILY);
+    pango_font_description_set_absolute_size (title_font,
+                                             ACRE_TITLE_FONT_SIZE * PANGO_SCALE);
+
+    title_layout = pango_cairo_create_layout (cr);
+    pango_layout_set_font_description (title_layout, title_font);
+    pango_layout_set_text (title_layout, acre->title, -1);
+    pango_layout_set_alignment (title_layout, PANGO_ALIGN_CENTER);
+
+    x_axis_layout = pango_cairo_create_layout (cr);
+    pango_layout_set_font_description (x_axis_layout, acre_font);
+    pango_layout_set_text (x_axis_layout, acre->x_axis_label, -1);
+    pango_layout_set_alignment (x_axis_layout, PANGO_ALIGN_CENTER);
+
+    y_axis_layout = pango_cairo_create_layout (cr);
+    pango_layout_set_font_description (y_axis_layout, acre_font);
+    pango_layout_set_text (y_axis_layout, acre->y_axis_label, -1);
+    pango_layout_set_alignment (y_axis_layout, PANGO_ALIGN_CENTER);
+
+    /* Iterate with the layout of the title and axis labels until they
+     * are stable, (this requires iteration since we don't know what
+     * to set their widths to in advance due to the wrapping of the
+     * other elements). */
+    chart.x = 0;
+    chart.y = 0;
+    chart.width = width;
+    chart.height = height;
+    while (1) {
+       pango_layout_set_width (title_layout, chart.width * PANGO_SCALE);
+       pango_layout_set_width (x_axis_layout, chart.width * PANGO_SCALE);
+       pango_layout_set_width (y_axis_layout, chart.height * PANGO_SCALE);
+
+       pango_layout_get_pixel_size (title_layout, &title_width, &title_height);
+       pango_layout_get_pixel_size (x_axis_layout, &x_axis_width, &x_axis_height);
+       pango_layout_get_pixel_size (y_axis_layout, &y_axis_width, &y_axis_height);
+
+       new_chart.x = ACRE_PAD + y_axis_height +
+           ACRE_PAD + ACRE_FONT_SIZE;
+       new_chart.width = width - chart.x - ACRE_PAD;
+
+       new_chart.y = ACRE_PAD + title_height + ACRE_PAD;
+       new_chart.height = height - chart.y - (ACRE_FONT_SIZE + ACRE_PAD + x_axis_height + ACRE_PAD);
+
+       if (new_chart.x == chart.x &&
+           new_chart.y == chart.y &&
+           new_chart.width == chart.width &&
+           new_chart.height == chart.height)
+       {
+           break;
+       }
+
+       chart.x = new_chart.x;
+       chart.y = new_chart.y;
+       chart.width = new_chart.width;
+       chart.height = new_chart.height;
+    }
+
+    cairo_set_source_rgb (cr, 0, 0, 0);
+
+    cairo_move_to (cr, chart.x, ACRE_PAD);
+    pango_cairo_show_layout (cr, title_layout);
+
+    cairo_save (cr);
+    {
+       cairo_translate (cr, ACRE_PAD, chart.y + chart.height);
+       cairo_rotate (cr, - M_PI / 2.0);
+       cairo_move_to (cr, 0, 0);
+       pango_cairo_show_layout (cr, y_axis_layout);
+    }
+    cairo_restore (cr);
+
+    cairo_move_to (cr, chart.x,
+                  chart.y + chart.height + ACRE_FONT_SIZE + ACRE_PAD);
+    pango_cairo_show_layout (cr, x_axis_layout);
+
+    cairo_rectangle (cr,
+                    chart.x - 0.5, chart.y - 0.5,
+                    chart.width + 1.0, chart.height + 1.0);
+    cairo_set_line_width (cr, 1.0);
+    cairo_stroke (cr);
 }
 
 /* Create a new dataset---a collection of (x, y) datapoints. A single
diff --git a/acre.h b/acre.h
index 0a39df9426e555410788dae41a7672d9c66c7103..89079ff3908bce3219a43cfba33719ff9777f60c 100644 (file)
--- a/acre.h
+++ b/acre.h
@@ -20,7 +20,7 @@
 #ifndef ACRE_H
 #define ACRE_H
 
-#include <cairo.h>
+#include <pango/pangocairo.h>
 
 typedef struct _acre acre_t;
 typedef struct _acre_data acre_data_t;