[goffice] Use pango attributes for formatting.
- From: Andreas J. Guelzow <guelzow src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Use pango attributes for formatting.
- Date: Tue, 2 Aug 2011 03:06:07 +0000 (UTC)
commit 2c5547c8901ce9ed0c649c09bbc947c4ae662055
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date: Mon Aug 1 21:05:30 2011 -0600
Use pango attributes for formatting.
2011-08-01 Andreas J. Guelzow <aguelzow pyrshep ca>
* configure.in: disable gtk depreciation check
* goffice/graph/gog-axis-line.c: replace ticks.labels with ticks.str
throughout;
gog_renderer_get_text_OBR with gog_renderer_get_gostring_OBR, and
gog_renderer_draw_text with gog_renderer_draw_gostring as required
byt he ticks change
* goffice/graph/gog-axis.c replace ticks.labels with ticks.str
throughout and use gog_axis_ticks_set_text to initialize
(gog_get_layout): new
(gog_axis_ticks_set_text): new
(axis_format_value): add GOString argument and change all callers
* goffice/graph/gog-axis.h: replace ticks.labels with ticks.str
* goffice/graph/gog-renderer.c (gog_renderer_draw_gostring): new
(gog_renderer_draw_text): use gog_renderer_draw_gostring
(gog_renderer_get_gostring_OBR): new
(gog_renderer_get_text_OBR): use gog_renderer_get_gostring_OBR
(gog_renderer_get_gostring_OBR): new
* goffice/graph/gog-renderer.h (gog_renderer_draw_gostring): new
* goffice/gtk/go-format-sel.c (generate_preview): use PangoAttrList
(draw_format_preview): ditto
(nfs_init): create buffer tags
* goffice/utils/go-format.c (go_format_parse_number_E): use attributes
(go_format_execute): use attributes
(go_format_value_gstring): use attributes instead of passing colour
* goffice/utils/go-pango-extras.c
(go_load_pango_attributes_into_buffer_filter): new
(go_load_pango_attributes_into_buffer_named_filter): new
(go_create_std_tags_for_buffer): new
(go_load_pango_byte_to_char): new
(go_load_pango_attributes_into_buffer): new
* goffice/utils/go-pango-extras.h (go_create_std_tags_for_buffer): new
(go_load_pango_attributes_into_buffer): new
* goffice/utils/go-string.c (go_string_new_rich): ensure we have determined
the byte_len (if it was negative or zero)
ChangeLog | 37 ++++++
NEWS | 3 +
configure.in | 2 +-
goffice/canvas/goc-graph.c | 3 +-
goffice/graph/gog-axis-line.c | 38 ++++---
goffice/graph/gog-axis.c | 89 ++++++++++-----
goffice/graph/gog-axis.h | 4 +-
goffice/graph/gog-renderer.c | 143 ++++++++++++++++++------
goffice/graph/gog-renderer.h | 10 ++-
goffice/gtk/go-format-sel.c | 25 ++--
goffice/utils/go-format.c | 161 ++++++++++++++++++++++-----
goffice/utils/go-pango-extras.c | 233 +++++++++++++++++++++++++++++++++++++++
goffice/utils/go-pango-extras.h | 6 +
goffice/utils/go-string.c | 4 +-
14 files changed, 632 insertions(+), 126 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 1f791ee..fbe616c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2011-08-01 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+ * configure.in: disable gtk depreciation check
+ * goffice/graph/gog-axis-line.c: replace ticks.labels with ticks.str
+ throughout;
+ gog_renderer_get_text_OBR with gog_renderer_get_gostring_OBR, and
+ gog_renderer_draw_text with gog_renderer_draw_gostring as required
+ byt he ticks change
+ * goffice/graph/gog-axis.c replace ticks.labels with ticks.str
+ throughout and use gog_axis_ticks_set_text to initialize
+ (gog_get_layout): new
+ (gog_axis_ticks_set_text): new
+ (axis_format_value): add GOString argument and change all callers
+ * goffice/graph/gog-axis.h: replace ticks.labels with ticks.str
+ * goffice/graph/gog-renderer.c (gog_renderer_draw_gostring): new
+ (gog_renderer_draw_text): use gog_renderer_draw_gostring
+ (gog_renderer_get_gostring_OBR): new
+ (gog_renderer_get_text_OBR): use gog_renderer_get_gostring_OBR
+ (gog_renderer_get_gostring_OBR): new
+ * goffice/graph/gog-renderer.h (gog_renderer_draw_gostring): new
+ * goffice/gtk/go-format-sel.c (generate_preview): use PangoAttrList
+ (draw_format_preview): ditto
+ (nfs_init): create buffer tags
+ * goffice/utils/go-format.c (go_format_parse_number_E): use attributes
+ (go_format_execute): use attributes
+ (go_format_value_gstring): use attributes instead of passing colour
+ * goffice/utils/go-pango-extras.c
+ (go_load_pango_attributes_into_buffer_filter): new
+ (go_load_pango_attributes_into_buffer_named_filter): new
+ (go_create_std_tags_for_buffer): new
+ (go_load_pango_byte_to_char): new
+ (go_load_pango_attributes_into_buffer): new
+ * goffice/utils/go-pango-extras.h (go_create_std_tags_for_buffer): new
+ (go_load_pango_attributes_into_buffer): new
+ * goffice/utils/go-string.c (go_string_new_rich): ensure we have determined
+ the byte_len (if it was negative or zero)
+
2011-08-01 Morten Welinder <terra gnome org>
* configure.in: Branch to 0.9.0.
diff --git a/NEWS b/NEWS
index f54d893..00b1d06 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
goffice 0.9.0:
+Andreas:
+ * Use pango attributes for formatting.
+
--------------------------------------------------------------------------
goffice 0.8.17:
diff --git a/configure.in b/configure.in
index 12eaf5c..d71b962 100644
--- a/configure.in
+++ b/configure.in
@@ -306,7 +306,7 @@ fi
dnl disable for in stable release, re-enable for development series
gtk_disable_deprecated=no
-if test $goffice_devel = yes; then
+if test XXX$goffice_devel = yes; then
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
CFLAGS="$CFLAGS -DPANGO_DISABLE_DEPRECATED"
if test "x$goffice_with_gtk" = "xtrue"; then
diff --git a/goffice/canvas/goc-graph.c b/goffice/canvas/goc-graph.c
index ed84eb6..163b87d 100644
--- a/goffice/canvas/goc-graph.c
+++ b/goffice/canvas/goc-graph.c
@@ -235,8 +235,7 @@ format_coordinate (GogAxis *axis, GOFormat *fmt, double x)
go_format_measure_strlen,
go_font_metrics_unit,
fmt,
- x, 'F', NULL,
- NULL,
+ x, 'F', NULL, NULL,
width, date_conv, TRUE);
if (err) {
/* Invalid number for format. */
diff --git a/goffice/graph/gog-axis-line.c b/goffice/graph/gog-axis-line.c
index da30abc..26ffcfa 100644
--- a/goffice/graph/gog-axis-line.c
+++ b/goffice/graph/gog-axis-line.c
@@ -1054,9 +1054,9 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
obrs = g_new0 (GOGeometryOBR, tick_nbr);
for (i = 0; i < tick_nbr; i++) {
- if (ticks[i].label != NULL) {
+ if (ticks[i].str != NULL) {
GOGeometryOBR *obr = obrs + i;
- gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, obr);
+ gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr);
if (obr->w > label_size_max
|| obr->h > label_size_max) {
label_size_max = MAX (obr->w, obr->h);
@@ -1066,7 +1066,7 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
}
for (i = 0; i < tick_nbr; i++) {
- if (ticks[i].label != NULL) {
+ if (ticks[i].str != NULL) {
GOGeometryOBR *obr = obrs + i;
pos = gog_axis_map_to_view (map, ticks[i].position);
obr->w += label_padding;
@@ -1166,9 +1166,9 @@ axis_line_render (GogAxisBase *axis_base,
obrs = g_new0 (GOGeometryOBR, tick_nbr);
indexmap = g_new0 (unsigned int, tick_nbr);
for (i = 0; i < tick_nbr; i++) {
- if (ticks[i].label != NULL) {
+ if (ticks[i].str != NULL) {
GOGeometryOBR *obr = obrs + i;
- gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, obr);
+ gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr);
if (obr->w > label_size_max
|| obr->h > label_size_max) {
label_size_max = MAX (obr->w, obr->h);
@@ -1216,7 +1216,7 @@ axis_line_render (GogAxisBase *axis_base,
}
}
- if (ticks[i].label != NULL && draw_labels) {
+ if (ticks[i].str != NULL && draw_labels) {
GOGeometryOBR *obr = obrs + i;
obr->w += label_padding;
go_geometry_calc_label_position (obr, axis_angle, tick_len,
@@ -1267,9 +1267,8 @@ axis_line_render (GogAxisBase *axis_base,
GogViewAllocation label_pos;
label_pos.x = obrs[j].x;
label_pos.y = obrs[j].y;
- gog_renderer_draw_text (renderer, ticks[j].label,
- &label_pos, GTK_ANCHOR_CENTER,
- TRUE);
+ gog_renderer_draw_gostring (renderer, ticks[j].str,
+ &label_pos, GTK_ANCHOR_CENTER);
}
}
g_free (obrs);
@@ -1338,8 +1337,8 @@ axis_circle_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
angle = gog_axis_map_to_view (map, ticks[i].position);
gog_chart_map_2D_to_view (c_map, ticks[i].position, position, &x, &y);
- if (ticks[i].label != NULL && draw_labels) {
- gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, &txt_obr);
+ if (ticks[i].str != NULL && draw_labels) {
+ gog_renderer_get_gostring_OBR (renderer, ticks[i].str, &txt_obr);
txt_obr.w += label_padding;
go_geometry_calc_label_position (&txt_obr, angle + M_PI / 2.0, tick_len,
GO_SIDE_LEFT, GO_SIDE_AUTO);
@@ -1460,10 +1459,10 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
}
}
- if (ticks[i].label != NULL && draw_labels) {
+ if (ticks[i].str != NULL && draw_labels) {
gog_chart_map_2D_to_view (c_map, ticks[i].position, position,
&label_pos.x, &label_pos.y);
- gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, &txt_obr);
+ gog_renderer_get_gostring_OBR (renderer, ticks[i].str, &txt_obr);
txt_obr.w += label_padding;
go_geometry_calc_label_position (&txt_obr, angle + M_PI / 2.0, tick_len,
GO_SIDE_LEFT, GO_SIDE_AUTO);
@@ -1474,8 +1473,9 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
if (!first_label_done ||
(!go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_old) &&
!go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_first))) {
- gog_renderer_draw_text (renderer, ticks[i].label,
- &label_pos, GTK_ANCHOR_CENTER, TRUE);
+ gog_renderer_draw_gostring
+ (renderer, ticks[i].str,
+ &label_pos, GTK_ANCHOR_CENTER);
txt_obr_old = txt_obr;
}
if (!first_label_done) {
@@ -2061,10 +2061,12 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
if (axis_base->major_tick_labeled) {
label_w = label_h = 0;
for (i = 0; i < tick_nbr; i++) {
- if (ticks[i].label == NULL)
+ if (ticks[i].str == NULL)
continue;
- gog_renderer_get_text_OBR (view->renderer,
- ticks[i].label, TRUE, &obr);
+ gog_renderer_get_text_OBR
+ (view->renderer,
+ ticks[i].str->str,
+ FALSE, &obr);
if (obr.w > label_w)
label_w = obr.w;
if (obr.h > label_h)
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 4762c67..79bbe17 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -105,6 +105,22 @@ struct _GogAxis {
static void gog_axis_set_ticks (GogAxis *axis,int tick_nbr, GogAxisTick *ticks);
+static PangoLayout *
+gog_get_layout (void)
+{
+ PangoContext *context = pango_context_new ();
+ PangoLayout *layout = pango_layout_new (context);
+ g_object_unref (context);
+ return layout;
+}
+
+static void
+gog_axis_ticks_set_text (GogAxisTick *ticks, char const *str)
+{
+ go_string_unref (ticks->str);
+ ticks->str = go_string_new (str);
+}
+
static GogAxisTick *
create_invalid_axis_ticks (double min, double max)
{
@@ -114,8 +130,9 @@ create_invalid_axis_ticks (double min, double max)
ticks[0].position = min;
ticks[1].position = max;
ticks[0].type = ticks[1].type = GOG_AXIS_TICK_MAJOR;
- ticks[0].label = g_strdup ("##");
- ticks[1].label = g_strdup ("##");
+ ticks[0].str = ticks[1].str = NULL;
+ gog_axis_ticks_set_text (&ticks[0], "##");
+ gog_axis_ticks_set_text (&ticks[1], "##");
return ticks;
}
@@ -139,26 +156,36 @@ gog_axis_get_effective_format (GogAxis const *axis)
return axis->format;
}
-static char *
-axis_format_value (GogAxis *axis, double val)
+static void
+axis_format_value (GogAxis *axis, double val, GOString **str)
{
GOFormat *fmt = gog_axis_get_effective_format (axis);
- GString *res = g_string_sized_new (20);
const GODateConventions *date_conv = axis->date_conv;
- GOFormatNumberError err = go_format_value_gstring
- (NULL, res,
+ GOFormatNumberError err;
+ PangoLayout *layout = gog_get_layout ();
+
+ g_return_if_fail (layout != NULL);
+
+ go_string_unref (*str);
+
+ err = go_format_value_gstring
+ (layout, NULL,
go_format_measure_strlen,
go_font_metrics_unit,
fmt,
- val, 'F', NULL,
- NULL,
+ val, 'F', NULL, NULL,
-1, date_conv, TRUE);
- if (err) {
- /* Invalid number for format. */
- g_string_assign (res, "#####");
- }
-
- return g_string_free (res, FALSE);
+ if (err)
+ *str = go_string_new ("#####");
+ else
+ *str = go_string_new_rich
+ (g_strdup (pango_layout_get_text (layout)),
+ -1,
+ FALSE,
+ pango_attr_list_ref (pango_layout_get_attributes (layout)),
+ NULL);
+
+ g_object_unref (layout);
}
static gboolean
@@ -345,22 +372,25 @@ map_discrete_calc_ticks (GogAxis *axis)
for (i = 0; i < tick_nbr; i++) {
ticks[i].position = tick_start + (double) (i) * major_tick;
ticks[i].type = GOG_AXIS_TICK_MAJOR;
- ticks[i].label = NULL;
+ ticks[i].str = NULL;
}
for (i = 0, j = tick_nbr; i < label_nbr; i++, j++) {
+ char *label;
ticks[j].position = go_rint (label_start + (double) (i) * major_label);
index = ticks[j].position - 1;
ticks[j].type = GOG_AXIS_TICK_NONE;
+ ticks[j].str = NULL;
if (axis->labels != NULL) {
if (index < (int) go_data_get_vector_size (axis->labels) && index >= 0) {
- char *label = go_data_get_vector_string (axis->labels, index);
- ticks[j].label = g_markup_escape_text (label, -1);
+ label = go_data_get_vector_string (axis->labels, index);
+ gog_axis_ticks_set_text(&ticks[j], label);
g_free (label);
- } else
- ticks[j].label = NULL;
+ }
+ } else {
+ label = g_strdup_printf ("%d", index + 1);
+ gog_axis_ticks_set_text (&ticks[j], label);
+ g_free (label);
}
- else
- ticks[j].label = g_strdup_printf ("%d", index + 1);
}
gog_axis_set_ticks (axis, tick_nbr + label_nbr, ticks);
@@ -761,7 +791,7 @@ map_linear_calc_ticks (GogAxis *axis)
g_assert (t < N);
ticks[t].position = maj_pos;
ticks[t].type = GOG_AXIS_TICK_MAJOR;
- ticks[t].label = axis_format_value (axis, maj_pos);
+ axis_format_value (axis, maj_pos, &ticks[t].str);
t++;
}
@@ -775,7 +805,7 @@ map_linear_calc_ticks (GogAxis *axis)
g_assert (t < N);
ticks[t].position = min_pos;
ticks[t].type = GOG_AXIS_TICK_MINOR;
- ticks[t].label = NULL;
+ ticks[t].str = NULL;
t++;
}
}
@@ -985,7 +1015,7 @@ map_date_calc_ticks (GogAxis *axis)
ticks[t].position = maj_pos;
ticks[t].type = GOG_AXIS_TICK_MAJOR;
- ticks[t].label = axis_format_value (axis, maj_pos);
+ axis_format_value (axis, maj_pos, &ticks[t].str);
t++;
/* Calculate next major so we know when to stop minors. */
@@ -1007,7 +1037,7 @@ map_date_calc_ticks (GogAxis *axis)
ticks[t].position = min_pos;
ticks[t].type = GOG_AXIS_TICK_MINOR;
- ticks[t].label = NULL;
+ ticks[t].str = NULL;
t++;
}
}
@@ -1035,6 +1065,7 @@ map_date_get_dim_format (GogAxis *axis, unsigned dim)
{
switch (dim) {
case GOG_AXIS_ELEM_MIN:
+
case GOG_AXIS_ELEM_MAX: {
GOFormat *fmt = gog_axis_get_effective_format (axis);
/*
@@ -1349,7 +1380,7 @@ map_log_calc_ticks (GogAxis *axis)
g_assert (t < N);
ticks[t].position = maj_pos;
ticks[t].type = GOG_AXIS_TICK_MAJOR;
- ticks[t].label = axis_format_value (axis, maj_pos);
+ axis_format_value (axis, maj_pos, &ticks[t].str);
t++;
}
@@ -1373,7 +1404,7 @@ map_log_calc_ticks (GogAxis *axis)
g_assert (t < N);
ticks[t].position = min_pos;
ticks[t].type = GOG_AXIS_TICK_MINOR;
- ticks[t].label = NULL;
+ ticks[t].str = NULL;
t++;
}
}
@@ -1778,7 +1809,7 @@ gog_axis_set_ticks (GogAxis *axis, int tick_nbr, GogAxisTick *ticks)
if (axis->ticks != NULL) {
for (i = 0; i < axis->tick_nbr; i++)
- g_free (axis->ticks[i].label);
+ go_string_unref (axis->ticks[i].str);
g_free (axis->ticks);
}
diff --git a/goffice/graph/gog-axis.h b/goffice/graph/gog-axis.h
index 75c5b6e..8e531ee 100644
--- a/goffice/graph/gog-axis.h
+++ b/goffice/graph/gog-axis.h
@@ -44,8 +44,8 @@ typedef enum {
typedef struct {
double position;
- GogAxisTickTypes type;
- char *label;
+ GogAxisTickTypes type;
+ GOString *str;
} GogAxisTick;
typedef struct _GogAxisMap GogAxisMap;
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index 17a32ee..b77a681 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -777,51 +777,51 @@ gog_renderer_draw_marker (GogRenderer *rend, double x, double y)
}
/**
- * gog_renderer_draw_text :
+ * gog_renderer_draw_layout :
* @rend : #GogRenderer
- * @text : the string to draw
+ * @gostring : the #GOString to draw
* @pos : #GogViewAllocation
* @anchor : #GtkAnchorType how to draw relative to @pos
- * @use_markup: wether to use pango markup
*
- * Have @rend draw @text in the at @pos.{x,y} anchored by the @anchor corner.
+ * Have @rend draw @layout in the at @pos.{x,y} anchored by the @anchor corner.
* If @pos.w or @pos.h are >= 0 then clip the results to less than that size.
**/
void
-gog_renderer_draw_text (GogRenderer *rend, char const *text,
- GogViewAllocation const *pos, GtkAnchorType anchor,
- gboolean use_markup)
+gog_renderer_draw_gostring (GogRenderer *rend, GOString *str,
+ GogViewAllocation const *pos, GtkAnchorType anchor)
{
PangoLayout *layout;
PangoContext *context;
- cairo_t *cairo = rend->cairo;
+ cairo_t *cairo;
GOGeometryOBR obr;
GOGeometryAABR aabr;
GOStyle const *style;
int iw, ih;
+ PangoAttrList *attr;
+ g_return_if_fail (str != NULL);
g_return_if_fail (GOG_IS_RENDERER (rend));
g_return_if_fail (rend->cur_style != NULL);
- g_return_if_fail (text != NULL);
-
- if (*text == '\0')
- return;
+ cairo = rend->cairo;
style = rend->cur_style;
+ /* Note: orig layout may not have been created using cairo! */
layout = pango_cairo_create_layout (cairo);
context = pango_layout_get_context (layout);
+ pango_layout_set_text (layout, str->str, -1);
+ attr = go_string_get_markup (str);
+ if (attr)
+ pango_layout_set_attributes (layout, attr);
pango_cairo_context_set_resolution (context, 72.0);
- if (use_markup)
- pango_layout_set_markup (layout, text, -1);
- else
- pango_layout_set_text (layout, text, -1);
pango_layout_set_font_description (layout, style->font.font->desc);
pango_layout_get_size (layout, &iw, &ih);
- obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0) / (double) PANGO_SCALE;
- obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0) /(double) PANGO_SCALE;
+ obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0)
+ / (double) PANGO_SCALE;
+ obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0)
+ /(double) PANGO_SCALE;
obr.alpha = -style->text_layout.angle * M_PI / 180.0;
obr.x = pos->x;
obr.y = pos->y;
@@ -849,8 +849,10 @@ gog_renderer_draw_text (GogRenderer *rend, char const *text,
cairo_save (cairo);
cairo_set_source_rgba (cairo, GO_COLOR_TO_CAIRO (style->font.color));
- cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) + (obr.h / 2.0) * sin (obr.alpha),
- obr.y - (obr.w / 2.0) * sin (obr.alpha) - (obr.h / 2.0) * cos (obr.alpha));
+ cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) +
+ (obr.h / 2.0) * sin (obr.alpha),
+ obr.y - (obr.w / 2.0) * sin (obr.alpha) -
+ (obr.h / 2.0) * cos (obr.alpha));
cairo_rotate (cairo, obr.alpha);
cairo_scale (cairo, rend->scale, rend->scale);
pango_cairo_show_layout (cairo, layout);
@@ -858,30 +860,69 @@ gog_renderer_draw_text (GogRenderer *rend, char const *text,
g_object_unref (layout);
}
+
+/**
+ * gog_renderer_draw_text :
+ * @rend : #GogRenderer
+ * @text : the string to draw
+ * @pos : #GogViewAllocation
+ * @anchor : #GtkAnchorType how to draw relative to @pos
+ * @use_markup: wether to use pango markup
+ *
+ * Have @rend draw @text in the at @pos.{x,y} anchored by the @anchor corner.
+ * If @pos.w or @pos.h are >= 0 then clip the results to less than that size.
+ **/
+
+void
+gog_renderer_draw_text (GogRenderer *rend, char const *text,
+ GogViewAllocation const *pos, GtkAnchorType anchor,
+ gboolean use_markup)
+{
+ cairo_t *cairo;
+ GOString *str;
+ PangoAttrList *attr_list = NULL;
+ char *m_text = NULL;
+
+ g_return_if_fail (GOG_IS_RENDERER (rend));
+ g_return_if_fail (text != NULL);
+
+ if (*text == '\0')
+ return;
+
+ cairo = rend->cairo;
+ if (use_markup && pango_parse_markup (text, -1, 0,
+ &attr_list, &m_text,
+ NULL, NULL))
+ str = go_string_new_rich (m_text, -1, FALSE, attr_list, NULL);
+ else
+ str = go_string_new (text);
+ gog_renderer_draw_gostring (rend, str, pos, anchor);
+ go_string_unref (str);
+}
+
/**
* gog_renderer_get_text_OBR :
* @rend: #GogRenderer
- * @text: the string to draw
- * @use_markup: wether to use pango markup
+ * @gostring: the string to draw
* @obr: #GOGeometryOBR to store the Object Bounding Rectangle of @text.
**/
void
-gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
- gboolean use_markup, GOGeometryOBR *obr)
+gog_renderer_get_gostring_OBR (GogRenderer *rend, GOString *str, GOGeometryOBR *obr)
{
GOStyle const *style;
PangoLayout *layout;
PangoContext *context;
PangoRectangle logical;
- cairo_t *cairo = rend->cairo;
+ cairo_t *cairo;
+ PangoAttrList *attr;
g_return_if_fail (GOG_IS_RENDERER (rend));
g_return_if_fail (rend->cur_style != NULL);
- g_return_if_fail (text != NULL);
g_return_if_fail (obr != NULL);
+ cairo = rend->cairo;
obr->x = obr->y = 0;
- if (*text == '\0') {
+ if (str->str == NULL || *(str->str) == '\0') {
/* Make sure invisible things don't skew size */
obr->w = obr->h = 0;
obr->alpha = 0;
@@ -889,20 +930,21 @@ gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
}
style = rend->cur_style;
-
layout = pango_cairo_create_layout (cairo);
context = pango_layout_get_context (layout);
+ pango_layout_set_text (layout, str->str, -1);
+ attr = go_string_get_markup (str);
+ if (attr)
+ pango_layout_set_attributes (layout, attr);
pango_cairo_context_set_resolution (context, 72.0);
- if (use_markup)
- pango_layout_set_markup (layout, text, -1);
- else
- pango_layout_set_text (layout, text, -1);
pango_layout_set_font_description (layout, style->font.font->desc);
pango_layout_get_extents (layout, NULL, &logical);
g_object_unref (layout);
- obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0) / (double) PANGO_SCALE;
- obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0) /(double) PANGO_SCALE;
+ obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0)
+ / (double) PANGO_SCALE;
+ obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0)
+ /(double) PANGO_SCALE;
/* Make sure invisible things don't skew size */
if (obr->w == 0)
@@ -913,6 +955,39 @@ gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
obr->alpha = - style->text_layout.angle * M_PI / 180.0;
}
+
+/**
+ * gog_renderer_get_text_OBR :
+ * @rend: #GogRenderer
+ * @text: the string to draw
+ * @use_markup: wether to use pango markup
+ * @obr: #GOGeometryOBR to store the Object Bounding Rectangle of @text.
+ **/
+void
+gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
+ gboolean use_markup, GOGeometryOBR *obr)
+{
+ cairo_t *cairo;
+ GOString *str;
+ PangoAttrList *attr_list = NULL;
+ char *m_text = NULL;
+
+ g_return_if_fail (GOG_IS_RENDERER (rend));
+ g_return_if_fail (text != NULL);
+
+ cairo = rend->cairo;
+
+ if (use_markup && pango_parse_markup (text, -1, 0,
+ &attr_list, &m_text,
+ NULL, NULL))
+ str = go_string_new_rich (m_text, -1, FALSE, attr_list, NULL);
+ else
+ str = go_string_new (text);
+ gog_renderer_get_gostring_OBR (rend, str, obr);
+ go_string_unref (str);
+
+}
+
/**
* gog_renderer_get_text_AABR :
* @rend: #GogRenderer
diff --git a/goffice/graph/gog-renderer.h b/goffice/graph/gog-renderer.h
index 3c0dc5e..7db1410 100644
--- a/goffice/graph/gog-renderer.h
+++ b/goffice/graph/gog-renderer.h
@@ -115,9 +115,17 @@ void gog_renderer_draw_selection_rectangle (GogRenderer *renderer, GogViewAlloc
void gog_renderer_draw_marker (GogRenderer *rend, double x, double y);
void gog_renderer_draw_text (GogRenderer *rend, char const *text,
- GogViewAllocation const *pos, GtkAnchorType anchor,
+ GogViewAllocation const *pos,
+ GtkAnchorType anchor,
gboolean use_markup);
+void gog_renderer_draw_gostring (GogRenderer *rend,
+ GOString *str,
+ GogViewAllocation const *pos,
+ GtkAnchorType anchor);
+
+void gog_renderer_get_gostring_OBR (GogRenderer *rend, GOString *str,
+ GOGeometryOBR *obr);
void gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
gboolean use_markup, GOGeometryOBR *obr);
void gog_renderer_get_text_AABR (GogRenderer *rend, char const *text,
diff --git a/goffice/gtk/go-format-sel.c b/goffice/gtk/go-format-sel.c
index c0c4224..2b7b9d7 100644
--- a/goffice/gtk/go-format-sel.c
+++ b/goffice/gtk/go-format-sel.c
@@ -160,12 +160,12 @@ static guint go_format_sel_signals [LAST_SIGNAL] = { 0 };
static void format_entry_set_text (GOFormatSel *gfs, const gchar *text);
static char *
-generate_preview (GOFormatSel *gfs, GOColor *c)
+generate_preview (GOFormatSel *gfs, PangoAttrList **attrs)
{
char *res = NULL;
g_signal_emit (G_OBJECT (gfs),
go_format_sel_signals [GENERATE_PREVIEW], 0,
- c, &res);
+ attrs, &res);
return res;
}
@@ -174,8 +174,7 @@ draw_format_preview (GOFormatSel *gfs, gboolean regen_format)
{
char *preview;
GOFormat const *sf = NULL;
- GOColor c = 0;
- GdkColor gdk_color;
+ PangoAttrList *attrs = NULL;
gsize len;
if (regen_format) {
@@ -196,22 +195,23 @@ draw_format_preview (GOFormatSel *gfs, gboolean regen_format)
if (NULL == (sf = gfs->format.spec))
return;
- if (NULL == (preview = generate_preview (gfs, &c)))
+ if (NULL == (preview = generate_preview (gfs, &attrs)))
return;
len = g_utf8_strlen (preview, -1);
if (len > FORMAT_PREVIEW_MAX)
- strcpy (g_utf8_offset_to_pointer (preview, FORMAT_PREVIEW_MAX - 5),
+ strcpy (g_utf8_offset_to_pointer (preview,
+ FORMAT_PREVIEW_MAX - 5),
"...");
gtk_text_buffer_set_text (gfs->format.preview_buffer, preview, -1);
- if (c != 0)
- go_color_to_gdk (c, &gdk_color);
- else
- gdk_color_parse ("black", &gdk_color);
- gtk_widget_modify_text (GTK_WIDGET (gfs->format.preview),
- GTK_STATE_NORMAL, &gdk_color);
+ go_load_pango_attributes_into_buffer (attrs,
+ gfs->format.preview_buffer,
+ preview);
+
+ pango_attr_list_unref (attrs);
+
g_free (preview);
}
@@ -999,6 +999,7 @@ nfs_init (GOFormatSel *gfs)
pango_font_metrics_unref (metrics);
}
gfs->format.preview_buffer = gtk_text_view_get_buffer (gfs->format.preview);
+ go_create_std_tags_for_buffer (gfs->format.preview_buffer);
gfs->format.menu = go_gtk_builder_get_widget (gfs->gui, "format_menu");
populate_menu (gfs);
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index de13fdb..0e4ba80 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -180,6 +180,8 @@ typedef enum {
OP_NUM_MARK_MANTISSA,
OP_NUM_SIMPLIFY_MANTISSA,
OP_NUM_SIMPLIFY_EXPONENT,
+ OP_MARKUP_SUPERSCRIPT_START,
+ OP_MARKUP_SUPERSCRIPT_END,
#endif
OP_NUM_FRACTION, /* wholep explicitp (digits|denominator) */
OP_NUM_FRACTION_WHOLE,
@@ -1770,11 +1772,7 @@ go_format_parse_number_E (GOFormatParseState *pstate)
ADD_OP (OP_NUM_SIMPLIFY_MANTISSA);
ADD_OP2 (OP_CHAR, '1');
ADD_OP2 (OP_CHAR, '0');
- ADD_OP2 (OP_CHAR, '<');
- ADD_OP2 (OP_CHAR, 's');
- ADD_OP2 (OP_CHAR, 'u');
- ADD_OP2 (OP_CHAR, 'p');
- ADD_OP2 (OP_CHAR, '>');
+ ADD_OP (OP_MARKUP_SUPERSCRIPT_START);
} else
#endif
ADD_OP2 (OP_CHAR, 'E');
@@ -1786,14 +1784,9 @@ go_format_parse_number_E (GOFormatParseState *pstate)
#ifdef ALLOW_EE_MARKUP
if (use_markup) {
- ADD_OP2 (OP_CHAR, '<');
- ADD_OP2 (OP_CHAR, '/');
- ADD_OP2 (OP_CHAR, 's');
- ADD_OP2 (OP_CHAR, 'u');
- ADD_OP2 (OP_CHAR, 'p');
- ADD_OP2 (OP_CHAR, '>');
if (simplify_mantissa)
ADD_OP (OP_NUM_SIMPLIFY_EXPONENT);
+ ADD_OP (OP_MARKUP_SUPERSCRIPT_END);
}
#endif
@@ -2316,6 +2309,8 @@ go_format_dump_program (const guchar *prg)
REGULAR(OP_NUM_MARK_MANTISSA);
REGULAR(OP_NUM_SIMPLIFY_MANTISSA);
REGULAR(OP_NUM_SIMPLIFY_EXPONENT);
+ REGULAR(OP_MARKUP_SUPERSCRIPT_START);
+ REGULAR(OP_MARKUP_SUPERSCRIPT_END);
#endif
REGULAR(OP_NUM_FRACTION_WHOLE);
REGULAR(OP_NUM_FRACTION_NOMINATOR);
@@ -2498,11 +2493,19 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
DOUBLE w, n, d;
gsize nominator_start, denominator_start;
} fraction;
+ char *oldlocale = NULL;
#ifdef ALLOW_EE_MARKUP
int mantissa_start = -1;
int special_mantissa = INT_MAX;
+ PangoAttrList *attrs = NULL;
+ GSList *markup_stack = NULL;
+
+ if (layout) {
+ attrs = pango_attr_list_copy (pango_layout_get_attributes (layout));
+ if (attrs == NULL)
+ attrs = pango_attr_list_new ();
+ }
#endif
- char *oldlocale = NULL;
memset (&fraction, 0, sizeof (fraction));
@@ -2511,8 +2514,15 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
switch (op) {
case OP_END:
- if (layout)
+ if (layout) {
pango_layout_set_text (layout, dst->str, -1);
+#ifdef ALLOW_EE_MARKUP
+
+ pango_layout_set_attributes (layout, attrs);
+ pango_attr_list_unref (attrs);
+ g_slist_free (markup_stack);
+#endif
+ }
if (numtxt)
g_string_free (numtxt, TRUE);
if (oldlocale) {
@@ -3063,6 +3073,33 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
g_string_append_c (dst, '0');
}
break;
+
+ case OP_MARKUP_SUPERSCRIPT_START:
+ if (layout)
+ markup_stack = g_slist_prepend
+ (markup_stack, GSIZE_TO_POINTER (dst->len));
+ break;
+
+ case OP_MARKUP_SUPERSCRIPT_END:
+ if (layout) {
+ guint start = 0,
+ end = (guint)dst->len;
+ PangoAttribute *attr;
+ if (markup_stack) {
+ start = (guint)GPOINTER_TO_SIZE (markup_stack->data);
+ markup_stack = g_slist_delete_link (markup_stack, markup_stack);
+ }
+ /* FIXME: we need to calculate the right rise value */
+ attr = pango_attr_rise_new (5000);
+ attr->start_index = start;
+ attr->end_index = end;
+ pango_attr_list_insert (attrs, attr);
+ attr = pango_attr_scale_new (PANGO_SCALE_SMALL);
+ attr->start_index = start;
+ attr->end_index = end;
+ pango_attr_list_insert (attrs, attr);
+ }
+ break;
#endif
case OP_NUM_FRACTION: {
@@ -3128,10 +3165,50 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
case OP_NUM_FRACTION_BLANK:
if (fraction.n == 0) {
- /* Replace all added characters by spaces. */
- gsize chars = g_utf8_strlen (dst->str + fraction.nominator_start, -1);
- memset (dst->str + fraction.nominator_start, ' ', chars);
- g_string_truncate (dst, fraction.nominator_start + chars);
+ /* Replace all added characters by spaces of the right length. */
+ char const *f = dst->str + fraction.nominator_start;
+ gsize chars = g_utf8_strlen (f, -1);
+
+ if (chars > 0) {
+ /* We have layouts that have no fontmap set, we need to avoid them */
+ if (layout && pango_context_get_font_map (pango_layout_get_context (layout))) {
+ guint start = fraction.nominator_start;
+ GList *plist, *l;
+ gint length = dst->len - fraction.nominator_start;
+ plist = pango_itemize (pango_layout_get_context (layout),
+ dst->str,
+ f - dst->str,
+ length,
+ attrs,
+ NULL);
+ chars = 0;
+ for (l = plist; l != NULL; l = l->next) {
+ PangoItem *pi = l->data;
+ PangoGlyphString *glyphs = pango_glyph_string_new ();
+ PangoAttribute *attr;
+ PangoRectangle ink_rect;
+ PangoRectangle logical_rect;
+
+ pango_shape (f, length, &pi->analysis, glyphs);
+ pango_glyph_string_extents (glyphs,
+ pi->analysis.font,
+ &ink_rect,
+ &logical_rect);
+ pango_glyph_string_free (glyphs);
+
+ attr = pango_attr_shape_new (&ink_rect, &logical_rect);
+ attr->start_index = start;
+ attr->end_index = start + 1;
+ pango_attr_list_insert (attrs, attr);
+ start++;
+ chars++;
+ }
+ go_list_free_custom (plist, (GFreeFunc) pango_item_free);
+ }
+
+ memset (dst->str + fraction.nominator_start, ' ', chars);
+ g_string_truncate (dst, fraction.nominator_start + chars);
+ }
}
break;
@@ -3452,6 +3529,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
return;
}
+#define FREE_NEW_STR do { if (new_str) (void)g_string_free (new_str, TRUE); } while (0)
GOFormatNumberError
SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
@@ -3465,20 +3543,38 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
gboolean unicode_minus)
{
gboolean inhibit = FALSE;
+ GString *new_str = NULL;
+ GOFormatNumberError err;
g_return_val_if_fail (type == 'F' || sval != NULL,
(GOFormatNumberError)-1);
- g_string_truncate (str, 0);
+ if (str == NULL)
+ new_str = str = g_string_new (NULL);
+ else
+ g_string_truncate (str, 0);
if (fmt)
fmt = SUFFIX(go_format_specialize) (fmt, val, type, &inhibit);
if (!fmt)
fmt = go_format_general ();
-
if (go_color)
*go_color = fmt->color;
+ if (layout && fmt->color != 0) {
+ PangoAttrList *attrs;
+ PangoAttribute *attr;
+ attrs = pango_attr_list_ref (pango_layout_get_attributes (layout));
+ if (attrs == NULL)
+ attrs = pango_attr_list_new ();
+ attr = go_color_to_pango (fmt->color, TRUE);
+ attr->start_index = 0;
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert (attrs, attr);
+ pango_layout_set_attributes (layout, attrs);
+ pango_attr_list_unref (attrs);
+ }
+
if (type == 'F') {
switch (fmt->typ) {
case GO_FMT_TEXT:
@@ -3488,14 +3584,17 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
(layout, str, measure, metrics,
val,
col_width, unicode_minus);
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_OK;
case GO_FMT_NUMBER:
if (val < 0) {
#ifndef ALLOW_NEGATIVE_TIMES
if (fmt->u.number.has_date ||
- fmt->u.number.has_time)
+ fmt->u.number.has_time) {
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_DATE_ERROR;
+ }
#endif
if (inhibit)
val = SUFFIX(fabs)(val);
@@ -3504,16 +3603,20 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
g_printerr ("Executing %s\n", fmt->format);
go_format_dump_program (fmt->u.number.program);
#endif
- return SUFFIX(go_format_execute)
+
+ err = SUFFIX(go_format_execute)
(layout, str,
measure, metrics,
fmt->u.number.program,
col_width,
val, sval, date_conv,
unicode_minus);
-
+ FREE_NEW_STR;
+ return err;
+
case GO_FMT_EMPTY:
SETUP_LAYOUT;
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_OK;
default:
@@ -3521,26 +3624,30 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
case GO_FMT_MARKUP:
case GO_FMT_COND:
SETUP_LAYOUT;
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_INVALID_FORMAT;
}
} else {
switch (fmt->typ) {
case GO_FMT_TEXT:
- return SUFFIX(go_format_execute)
+ err = SUFFIX(go_format_execute)
(layout, str,
measure, metrics,
fmt->u.text.program,
col_width,
val, sval, date_conv,
unicode_minus);
-
+ FREE_NEW_STR;
+ return err;
case GO_FMT_NUMBER:
g_string_assign (str, sval);
SETUP_LAYOUT;
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_OK;
case GO_FMT_EMPTY:
SETUP_LAYOUT;
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_OK;
default:
@@ -3548,11 +3655,14 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
case GO_FMT_MARKUP:
case GO_FMT_COND:
SETUP_LAYOUT;
+ FREE_NEW_STR;
return GO_FORMAT_NUMBER_INVALID_FORMAT;
}
}
}
+#undef FREE_NEW_STR
+
/**
* go_format_value:
* @fmt: a #GOFormat
@@ -3572,8 +3682,7 @@ SUFFIX(go_format_value) (GOFormat const *fmt, DOUBLE val)
go_format_measure_strlen,
go_font_metrics_unit,
fmt,
- val, 'F', NULL,
- NULL,
+ val, 'F', NULL, NULL,
-1, NULL, FALSE);
if (err) {
/* Invalid number for format. */
diff --git a/goffice/utils/go-pango-extras.c b/goffice/utils/go-pango-extras.c
index 9b6e677..0097cf9 100644
--- a/goffice/utils/go-pango-extras.c
+++ b/goffice/utils/go-pango-extras.c
@@ -1,3 +1,4 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* go-pango-extras.c: Various utility routines that should have been in pango.
*
@@ -7,6 +8,8 @@
#include <goffice/goffice-config.h>
#include "go-pango-extras.h"
+#include "go-glib-extras.h"
+#include <string.h>
struct cb_splice {
guint pos, len;
@@ -244,3 +247,233 @@ go_pango_attr_list_is_empty (const PangoAttrList *attrs)
cb_empty, &empty);
return empty;
}
+
+static gboolean
+go_load_pango_attributes_into_buffer_filter (PangoAttribute *attribute,
+ G_GNUC_UNUSED gpointer data)
+{
+ return ((PANGO_ATTR_FOREGROUND == attribute->klass->type) ||
+ (PANGO_ATTR_UNDERLINE == attribute->klass->type) ||
+ (PANGO_ATTR_RISE == attribute->klass->type));
+}
+
+static gboolean
+go_load_pango_attributes_into_buffer_named_filter (PangoAttribute *attribute,
+ G_GNUC_UNUSED gpointer data)
+{
+ return ((PANGO_ATTR_STYLE == attribute->klass->type) ||
+ (PANGO_ATTR_WEIGHT == attribute->klass->type) ||
+ (PANGO_ATTR_STRIKETHROUGH == attribute->klass->type));
+}
+
+void
+go_create_std_tags_for_buffer (GtkTextBuffer *buffer)
+{
+ gtk_text_buffer_create_tag (buffer, "PANGO_STYLE_NORMAL", "style", PANGO_STYLE_NORMAL,
+ "style-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_STYLE_ITALIC", "style", PANGO_STYLE_ITALIC,
+ "style-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_STRIKETHROUGH_TRUE", "strikethrough", TRUE,
+ "strikethrough-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_STRIKETHROUGH_FALSE", "strikethrough", FALSE,
+ "strikethrough-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_THIN", "weight", 100,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRALIGHT", "weight", PANGO_WEIGHT_ULTRALIGHT,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_LIGHT", "weight", PANGO_WEIGHT_LIGHT,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_BOOK", "weight", 380,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_NORMAL", "weight", PANGO_WEIGHT_NORMAL,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_MEDIUM", "weight", 500,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_SEMIBOLD", "weight", PANGO_WEIGHT_SEMIBOLD,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_BOLD", "weight", PANGO_WEIGHT_BOLD,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRABOLD", "weight", PANGO_WEIGHT_ULTRABOLD,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_HEAVY", "weight", PANGO_WEIGHT_HEAVY,
+ "weight-set", TRUE, NULL);
+ gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRAHEAVY", "weight", 1000,
+ "weight-set", TRUE, NULL);
+}
+
+static gint
+go_load_pango_byte_to_char (gchar const *str, gint byte)
+{
+ if (byte >= (gint)strlen (str))
+ return g_utf8_strlen (str, -1);
+ return g_utf8_pointer_to_offset (str, g_utf8_prev_char (str + byte + 1));
+}
+
+void
+go_load_pango_attributes_into_buffer (PangoAttrList *markup, GtkTextBuffer *buffer, gchar const *str)
+{
+ PangoAttrIterator * iter;
+ PangoAttrList *copied_markup;
+ PangoAttrList *our_markup;
+
+ if (markup == NULL)
+ return;
+
+/* For some styles we create named tags. The names are taken from the Pango enums */
+
+ copied_markup = pango_attr_list_copy (markup);
+ our_markup = pango_attr_list_filter (copied_markup,
+ go_load_pango_attributes_into_buffer_named_filter,
+ NULL);
+ pango_attr_list_unref (copied_markup);
+ if (our_markup != NULL) {
+ iter = pango_attr_list_get_iterator (our_markup);
+
+ do {
+ GSList *attr = pango_attr_iterator_get_attrs (iter);
+ if (attr != NULL) {
+ GSList *ptr;
+ gint start, end;
+ GtkTextIter start_iter, end_iter;
+ char const *name;
+
+ pango_attr_iterator_range (iter, &start, &end);
+ start = go_load_pango_byte_to_char (str, start);
+ end = go_load_pango_byte_to_char (str, end);
+ gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+ gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+ for (ptr = attr; ptr != NULL; ptr = ptr->next) {
+ PangoAttribute *attribute = ptr->data;
+ GtkTextTag *tag;
+ int val;
+
+ switch (attribute->klass->type) {
+ case PANGO_ATTR_STYLE:
+ name = (((PangoAttrInt *)attribute)->value
+ == PANGO_STYLE_NORMAL)
+ ? "PANGO_STYLE_NORMAL" :
+ "PANGO_STYLE_ITALIC";
+ tag = gtk_text_tag_table_lookup
+ (gtk_text_buffer_get_tag_table (buffer),
+ name);
+ gtk_text_buffer_apply_tag (buffer, tag,
+ &start_iter, &end_iter);
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ name = (((PangoAttrInt *)attribute)->value) ?
+ "PANGO_STRIKETHROUGH_TRUE" :
+ "PANGO_STRIKETHROUGH_FALSE";
+ tag = gtk_text_tag_table_lookup
+ (gtk_text_buffer_get_tag_table (buffer),
+ name);
+ gtk_text_buffer_apply_tag (buffer, tag,
+ &start_iter, &end_iter);
+ break;
+ case PANGO_ATTR_WEIGHT:
+ val = ((PangoAttrInt *)attribute)->value;
+ if (val < (PANGO_WEIGHT_THIN + PANGO_WEIGHT_ULTRALIGHT)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_THIN",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRALIGHT",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_BOOK)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_LIGHT",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_BOOK + PANGO_WEIGHT_NORMAL)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOOK",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_MEDIUM)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_NORMAL",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_MEDIUM + PANGO_WEIGHT_SEMIBOLD)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_MEDIUM",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_SEMIBOLD + PANGO_WEIGHT_BOLD)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_SEMIBOLD",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOLD",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_ULTRABOLD + PANGO_WEIGHT_HEAVY)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRABOLD",
+ &start_iter, &end_iter);
+ else if (val < (PANGO_WEIGHT_HEAVY + PANGO_WEIGHT_ULTRAHEAVY)/2)
+ gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_HEAVY",
+ &start_iter, &end_iter);
+ else gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRAHEAVY",
+ &start_iter, &end_iter);
+ break;
+ default:
+ break;
+ }
+ }
+ go_slist_free_custom (attr, (GFreeFunc)pango_attribute_destroy);
+ }
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy (iter);
+ pango_attr_list_unref (our_markup);
+ }
+
+/* For other styles (that are not at true/false type styles) we use unnamed styles */
+
+ copied_markup = pango_attr_list_copy (markup);
+ our_markup = pango_attr_list_filter (copied_markup,
+ go_load_pango_attributes_into_buffer_filter,
+ NULL);
+ pango_attr_list_unref (copied_markup);
+ if (our_markup != NULL) {
+ iter = pango_attr_list_get_iterator (our_markup);
+
+ do {
+ GSList *attr = pango_attr_iterator_get_attrs (iter);
+ if (attr != NULL) {
+ char *string;
+ GSList *ptr;
+ gint start, end;
+ GtkTextIter start_iter, end_iter;
+ GtkTextTag *tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
+ for (ptr = attr; ptr != NULL; ptr = ptr->next) {
+ PangoAttribute *attribute = ptr->data;
+ switch (attribute->klass->type) {
+ case PANGO_ATTR_FOREGROUND:
+ string = pango_color_to_string
+ (&((PangoAttrColor *)attribute)->color);
+ g_object_set (G_OBJECT (tag),
+ "foreground", string,
+ "foreground-set", TRUE,
+ NULL);
+ g_free (string);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ g_object_set (G_OBJECT (tag),
+ "underline",
+ ((PangoAttrInt *)attribute)->value,
+ "underline-set", TRUE,
+ NULL);
+ break;
+ case PANGO_ATTR_RISE:
+ g_object_set (G_OBJECT (tag),
+ "rise",
+ ((PangoAttrInt *)attribute)->value,
+ "rise-set", TRUE,
+ NULL);
+ break;
+ default:
+ break;
+ }
+ }
+ pango_attr_iterator_range (iter, &start, &end);
+ start = go_load_pango_byte_to_char (str, start);
+ end = go_load_pango_byte_to_char (str, end);
+ gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+ gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+ gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);
+ go_slist_free_custom (attr, (GFreeFunc)pango_attribute_destroy);
+ }
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy (iter);
+ pango_attr_list_unref (our_markup);
+ }
+}
diff --git a/goffice/utils/go-pango-extras.h b/goffice/utils/go-pango-extras.h
index 18fd95a..33c7339 100644
--- a/goffice/utils/go-pango-extras.h
+++ b/goffice/utils/go-pango-extras.h
@@ -2,6 +2,7 @@
#define GO_PANGO_EXTRAS_H
#include <pango/pango.h>
+#include <gtk/gtk.h>
G_BEGIN_DECLS
@@ -12,6 +13,11 @@ void go_pango_attr_list_unset (PangoAttrList *list,
PangoAttrType type);
gboolean go_pango_attr_list_is_empty (const PangoAttrList *attrs);
+void go_load_pango_attributes_into_buffer (PangoAttrList *markup,
+ GtkTextBuffer *buffer,
+ gchar const *str);
+void go_create_std_tags_for_buffer (GtkTextBuffer *buffer);
+
G_END_DECLS
#endif /* GO_PANGO_EXTRAS_H */
diff --git a/goffice/utils/go-string.c b/goffice/utils/go-string.c
index 6a8c173..1783810 100644
--- a/goffice/utils/go-string.c
+++ b/goffice/utils/go-string.c
@@ -221,10 +221,12 @@ go_string_new_rich (char const *str,
/* TODO : when we use a better representation for attributes (eg array
* of GOFont indicies) look into sharing rich strings */
+ if (byte_len <= 0)
+ byte_len = strlen (str);
rich = g_slice_new (GOStringRichImpl);
rich->base.base.str = str;
rich->base.hash = g_str_hash (str);
- rich->base.flags = ((byte_len > 0) ? (guint32) byte_len : strlen (str)) | GO_STRING_IS_RICH;
+ rich->base.flags = ((guint32) byte_len) | GO_STRING_IS_RICH;
rich->base.ref_count = 1;
rich->markup = markup;
rich->phonetic = phonetic;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]