From fb885ce6b3cdd5cde8b3c21821b49e2a82f6f11f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 25 Jan 2009 19:48:28 +1100 Subject: [PATCH] Draw title and axis labels with pango 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 | 4 +-- acre.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- acre.h | 2 +- 3 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index fcbe7ae..1d5beef 100644 --- 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 672ba62..e7b4a0f 100644 --- a/acre.c +++ b/acre.c @@ -21,6 +21,7 @@ #include "xmalloc.h" #include +#include 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 0a39df9..89079ff 100644 --- a/acre.h +++ b/acre.h @@ -20,7 +20,7 @@ #ifndef ACRE_H #define ACRE_H -#include +#include typedef struct _acre acre_t; typedef struct _acre_data acre_data_t; -- 2.43.0