summaryrefslogtreecommitdiff
path: root/glabels2/src/label-text.c
diff options
context:
space:
mode:
Diffstat (limited to 'glabels2/src/label-text.c')
-rw-r--r--glabels2/src/label-text.c1098
1 files changed, 1098 insertions, 0 deletions
diff --git a/glabels2/src/label-text.c b/glabels2/src/label-text.c
new file mode 100644
index 0000000..b9b0da2
--- /dev/null
+++ b/glabels2/src/label-text.c
@@ -0,0 +1,1098 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * (GLABELS) Label and Business Card Creation program for GNOME
+ *
+ * label_text.c: GLabels label text object
+ *
+ * Copyright (C) 2001-2007 Jim Evins <evins@snaught.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "label-text.h"
+
+#include <glib/gmem.h>
+#include <glib/gstrfuncs.h>
+#include <glib/gmessages.h>
+#include <pango/pango.h>
+#include <math.h>
+
+#include "util.h"
+
+#include "debug.h"
+
+/*========================================================*/
+/* Private macros and constants. */
+/*========================================================*/
+
+#define DEFAULT_FONT_FAMILY "Sans"
+#define DEFAULT_FONT_SIZE 14.0
+#define DEFAULT_FONT_WEIGHT PANGO_WEIGHT_NORMAL
+#define DEFAULT_FONT_ITALIC_FLAG FALSE
+#define DEFAULT_ALIGN PANGO_ALIGN_LEFT
+#define DEFAULT_COLOR GL_COLOR (0,0,0)
+#define DEFAULT_TEXT_LINE_SPACING 1.0
+#define DEFAULT_AUTO_SHRINK FALSE
+
+#define FONT_SCALE (72.0/96.0)
+
+/*========================================================*/
+/* Private types. */
+/*========================================================*/
+
+struct _glLabelTextPrivate {
+ GtkTextTagTable *tag_table;
+ GtkTextBuffer *buffer;
+
+ gchar *font_family;
+ gdouble font_size;
+ PangoWeight font_weight;
+ gboolean font_italic_flag;
+ PangoAlignment align;
+ glColorNode *color_node;
+ gdouble line_spacing;
+ gboolean auto_shrink;
+
+ gboolean size_changed;
+ gdouble w;
+ gdouble h;
+};
+
+/*========================================================*/
+/* Private globals. */
+/*========================================================*/
+
+/*========================================================*/
+/* Private function prototypes. */
+/*========================================================*/
+
+static void gl_label_text_finalize (GObject *object);
+
+static void copy (glLabelObject *dst_object,
+ glLabelObject *src_object);
+
+static void buffer_changed_cb (GtkTextBuffer *textbuffer,
+ glLabelText *ltext);
+
+static void get_size (glLabelObject *object,
+ gdouble *w,
+ gdouble *h);
+
+static void set_font_family (glLabelObject *object,
+ const gchar *font_family);
+
+static void set_font_size (glLabelObject *object,
+ gdouble font_size);
+
+static void set_font_weight (glLabelObject *object,
+ PangoWeight font_weight);
+
+static void set_font_italic_flag (glLabelObject *object,
+ gboolean font_italic_flag);
+
+static void set_text_alignment (glLabelObject *object,
+ PangoAlignment text_alignment);
+
+static void set_text_line_spacing (glLabelObject *object,
+ gdouble text_line_spacing);
+
+static void set_text_color (glLabelObject *object,
+ glColorNode *text_color_node);
+
+static gchar *get_font_family (glLabelObject *object);
+
+static gdouble get_font_size (glLabelObject *object);
+
+static PangoWeight get_font_weight (glLabelObject *object);
+
+static gboolean get_font_italic_flag (glLabelObject *object);
+
+static PangoAlignment get_text_alignment (glLabelObject *object);
+
+static gdouble get_text_line_spacing (glLabelObject *object);
+
+static glColorNode* get_text_color (glLabelObject *object);
+
+static void draw_object (glLabelObject *object,
+ cairo_t *cr,
+ gboolean screen_flag,
+ glMergeRecord *record);
+
+static void draw_shadow (glLabelObject *object,
+ cairo_t *cr,
+ gboolean screen_flag,
+ glMergeRecord *record);
+
+static gdouble auto_shrink_font_size (cairo_t *cr,
+ gchar *family,
+ gdouble size,
+ PangoWeight weight,
+ PangoStyle style,
+ gchar *text,
+ gdouble width);
+
+
+
+/*****************************************************************************/
+/* Boilerplate object stuff. */
+/*****************************************************************************/
+G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT);
+
+static void
+gl_label_text_class_init (glLabelTextClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
+
+ gl_label_text_parent_class = g_type_class_peek_parent (class);
+
+ label_object_class->copy = copy;
+
+ label_object_class->get_size = get_size;
+
+ label_object_class->set_font_family = set_font_family;
+ label_object_class->set_font_size = set_font_size;
+ label_object_class->set_font_weight = set_font_weight;
+ label_object_class->set_font_italic_flag = set_font_italic_flag;
+ label_object_class->set_text_alignment = set_text_alignment;
+ label_object_class->set_text_line_spacing = set_text_line_spacing;
+ label_object_class->set_text_color = set_text_color;
+ label_object_class->get_font_family = get_font_family;
+ label_object_class->get_font_size = get_font_size;
+ label_object_class->get_font_weight = get_font_weight;
+ label_object_class->get_font_italic_flag = get_font_italic_flag;
+ label_object_class->get_text_alignment = get_text_alignment;
+ label_object_class->get_text_line_spacing = get_text_line_spacing;
+ label_object_class->get_text_color = get_text_color;
+ label_object_class->draw_object = draw_object;
+ label_object_class->draw_shadow = draw_shadow;
+
+ object_class->finalize = gl_label_text_finalize;
+}
+
+static void
+gl_label_text_init (glLabelText *ltext)
+{
+ ltext->priv = g_new0 (glLabelTextPrivate, 1);
+
+ ltext->priv->tag_table = gtk_text_tag_table_new ();
+ ltext->priv->buffer = gtk_text_buffer_new (ltext->priv->tag_table);
+
+ ltext->priv->font_family = g_strdup(DEFAULT_FONT_FAMILY);
+ ltext->priv->font_size = DEFAULT_FONT_SIZE;
+ ltext->priv->font_weight = DEFAULT_FONT_WEIGHT;
+ ltext->priv->font_italic_flag = DEFAULT_FONT_ITALIC_FLAG;
+ ltext->priv->align = DEFAULT_ALIGN;
+ ltext->priv->color_node = gl_color_node_new_default ();
+ ltext->priv->color_node->color = DEFAULT_COLOR;
+ ltext->priv->line_spacing = DEFAULT_TEXT_LINE_SPACING;
+ ltext->priv->auto_shrink = DEFAULT_AUTO_SHRINK;
+
+ ltext->priv->size_changed = TRUE;
+
+ g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
+ G_CALLBACK(buffer_changed_cb), ltext);
+}
+
+static void
+gl_label_text_finalize (GObject *object)
+{
+ glLabelText *ltext = GL_LABEL_TEXT (object);
+
+ g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
+
+ g_object_unref (ltext->priv->tag_table);
+ g_object_unref (ltext->priv->buffer);
+ g_free (ltext->priv->font_family);
+ gl_color_node_free (&(ltext->priv->color_node));
+ g_free (ltext->priv);
+
+ G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
+}
+
+/*****************************************************************************/
+/* NEW label "text" object. */
+/*****************************************************************************/
+GObject *
+gl_label_text_new (glLabel *label)
+{
+ glLabelText *ltext;
+
+ ltext = g_object_new (gl_label_text_get_type(), NULL);
+
+ gl_label_object_set_parent (GL_LABEL_OBJECT(ltext), label);
+
+ return G_OBJECT (ltext);
+}
+
+/*****************************************************************************/
+/* Copy object contents. */
+/*****************************************************************************/
+static void
+copy (glLabelObject *dst_object,
+ glLabelObject *src_object)
+{
+ glLabelText *ltext = (glLabelText *)src_object;
+ glLabelText *new_ltext = (glLabelText *)dst_object;
+ GList *lines;
+ glColorNode *text_color_node;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+ g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
+
+ lines = gl_label_text_get_lines (ltext);
+ text_color_node = get_text_color (src_object);
+ gl_label_text_set_lines (new_ltext, lines);
+
+ new_ltext->priv->font_family = g_strdup (ltext->priv->font_family);
+ new_ltext->priv->font_size = ltext->priv->font_size;
+ new_ltext->priv->font_weight = ltext->priv->font_weight;
+ new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
+ set_text_color (dst_object, text_color_node);
+ new_ltext->priv->align = ltext->priv->align;
+ new_ltext->priv->line_spacing = ltext->priv->line_spacing;
+ new_ltext->priv->auto_shrink = ltext->priv->auto_shrink;
+
+ new_ltext->priv->size_changed = ltext->priv->size_changed;
+ new_ltext->priv->w = ltext->priv->w;
+ new_ltext->priv->h = ltext->priv->h;
+
+ gl_color_node_free (&text_color_node);
+ gl_text_node_lines_free (&lines);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set object params. */
+/*****************************************************************************/
+void
+gl_label_text_set_lines (glLabelText *ltext,
+ GList *lines)
+{
+ gchar *text;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ text = gl_text_node_lines_expand (lines, NULL);
+ gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
+ g_free (text);
+
+ ltext->priv->size_changed = TRUE;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*****************************************************************************/
+/* Get object params. */
+/*****************************************************************************/
+GtkTextBuffer *
+gl_label_text_get_buffer (glLabelText *ltext)
+{
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
+
+ return ltext->priv->buffer;
+}
+
+GList *
+gl_label_text_get_lines (glLabelText *ltext)
+{
+ GtkTextIter start, end;
+ gchar *text;
+ GList *lines;
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
+
+ gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
+ text = gtk_text_buffer_get_text (ltext->priv->buffer,
+ &start, &end, FALSE);
+ lines = gl_text_node_lines_new_from_text (text);
+ g_free (text);
+
+ return lines;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. text buffer "changed" callback. */
+/*---------------------------------------------------------------------------*/
+void buffer_changed_cb (GtkTextBuffer *textbuffer,
+ glLabelText *ltext)
+{
+ ltext->priv->size_changed = TRUE;
+
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get object size method. */
+/*---------------------------------------------------------------------------*/
+static void
+get_size (glLabelObject *object,
+ gdouble *w,
+ gdouble *h)
+{
+ glLabelText *ltext = (glLabelText *)object;
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ cairo_font_options_t *options;
+ PangoStyle style;
+ PangoLayout *layout;
+ PangoFontDescription *desc;
+ gdouble font_size;
+ gdouble line_spacing;
+ GtkTextIter start, end;
+ gchar *text;
+ gdouble w_parent, h_parent;
+ gint iw, ih;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ gl_label_object_get_raw_size (object, &w_parent, &h_parent);
+
+ if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
+ *w = w_parent;
+ *h = h_parent;
+ return;
+ }
+
+ if (!ltext->priv->size_changed)
+ {
+ *w = ltext->priv->w;
+ *h = ltext->priv->h;
+ return;
+ }
+
+ font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
+ line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
+
+ gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
+ text = gtk_text_buffer_get_text (ltext->priv->buffer,
+ &start, &end, FALSE);
+
+
+ fontmap = pango_cairo_font_map_new ();
+ context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
+ options = cairo_font_options_create ();
+ cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
+ pango_cairo_context_set_font_options (context, options);
+ cairo_font_options_destroy (options);
+
+ layout = pango_layout_new (context);
+
+ style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
+ pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
+ pango_font_description_set_style (desc, style);
+ pango_font_description_set_size (desc, font_size * PANGO_SCALE);
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
+ pango_layout_set_text (layout, text, -1);
+ pango_layout_get_size (layout, &iw, &ih);
+ *w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
+ *h = ltext->priv->h = ih / PANGO_SCALE;
+ ltext->priv->size_changed = FALSE;
+
+ g_object_unref (layout);
+ g_object_unref (context);
+ g_object_unref (fontmap);
+ g_free (text);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set font family method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_font_family (glLabelObject *object,
+ const gchar *font_family)
+{
+ glLabelText *ltext = (glLabelText *)object;
+ GList *family_names;
+ gchar *good_font_family;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+ g_return_if_fail (font_family);
+
+ family_names = gl_util_get_font_family_list ();
+ if (g_list_find_custom (family_names, font_family, (GCompareFunc)g_utf8_collate)) {
+ good_font_family = g_strdup (font_family);
+ } else {
+ if (family_names != NULL) {
+ good_font_family = g_strdup (family_names->data); /* 1st entry */
+ } else {
+ good_font_family = g_strdup (font_family);
+ }
+ }
+ gl_util_font_family_list_free (family_names);
+
+ if (ltext->priv->font_family) {
+ if (g_strcasecmp (ltext->priv->font_family, good_font_family) == 0) {
+ g_free (good_font_family);
+ gl_debug (DEBUG_LABEL, "END (no change)");
+ return;
+ }
+ g_free (ltext->priv->font_family);
+ }
+ ltext->priv->font_family = g_strdup (good_font_family);
+ g_free (good_font_family);
+
+ gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
+
+ ltext->priv->size_changed = TRUE;
+
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set font size method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_font_size (glLabelObject *object,
+ gdouble font_size)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->font_size != font_size) {
+
+ ltext->priv->size_changed = TRUE;
+
+ ltext->priv->font_size = font_size;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set font weight method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_font_weight (glLabelObject *object,
+ PangoWeight font_weight)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->font_weight != font_weight) {
+
+ ltext->priv->size_changed = TRUE;
+
+ ltext->priv->font_weight = font_weight;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set font italic flag method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_font_italic_flag (glLabelObject *object,
+ gboolean font_italic_flag)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->font_italic_flag != font_italic_flag) {
+
+ ltext->priv->size_changed = TRUE;
+
+ ltext->priv->font_italic_flag = font_italic_flag;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set text alignment method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_text_alignment (glLabelObject *object,
+ PangoAlignment text_alignment)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->align != text_alignment) {
+
+ ltext->priv->size_changed = TRUE;
+
+ ltext->priv->align = text_alignment;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set text line spacing method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_text_line_spacing (glLabelObject *object,
+ gdouble line_spacing)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->line_spacing != line_spacing) {
+
+ ltext->priv->size_changed = TRUE;
+
+ ltext->priv->line_spacing = line_spacing;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. set text color method. */
+/*---------------------------------------------------------------------------*/
+static void
+set_text_color (glLabelObject *object,
+ glColorNode *text_color_node)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (!gl_color_node_equal (ltext->priv->color_node, text_color_node)) {
+
+ gl_color_node_free (&(ltext->priv->color_node));
+ ltext->priv->color_node = gl_color_node_dup (text_color_node);
+
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get font family method. */
+/*---------------------------------------------------------------------------*/
+static gchar *
+get_font_family (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
+
+ return g_strdup (ltext->priv->font_family);
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get font size method. */
+/*---------------------------------------------------------------------------*/
+static gdouble
+get_font_size (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
+
+ return ltext->priv->font_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get font weight method. */
+/*---------------------------------------------------------------------------*/
+static PangoWeight
+get_font_weight (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
+
+ return ltext->priv->font_weight;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get font italic flag method. */
+/*---------------------------------------------------------------------------*/
+static gboolean
+get_font_italic_flag (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
+
+ return ltext->priv->font_italic_flag;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get text alignment method. */
+/*---------------------------------------------------------------------------*/
+static PangoAlignment
+get_text_alignment (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
+
+ return ltext->priv->align;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get text line spacing method. */
+/*---------------------------------------------------------------------------*/
+static gdouble
+get_text_line_spacing (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
+
+ return ltext->priv->line_spacing;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. get text color method. */
+/*---------------------------------------------------------------------------*/
+static glColorNode*
+get_text_color (glLabelObject *object)
+{
+ glLabelText *ltext = (glLabelText *)object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
+
+ return gl_color_node_dup (ltext->priv->color_node);
+}
+
+/*****************************************************************************/
+/* Set auto shrink flag. */
+/*****************************************************************************/
+void
+gl_label_text_set_auto_shrink (glLabelText *ltext,
+ gboolean auto_shrink)
+{
+ gl_debug (DEBUG_LABEL, "BEGIN");
+
+ g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
+
+ if (ltext->priv->auto_shrink != auto_shrink) {
+
+ ltext->priv->auto_shrink = auto_shrink;
+ gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*****************************************************************************/
+/* Query auto shrink flag. */
+/*****************************************************************************/
+gboolean
+gl_label_text_get_auto_shrink (glLabelText *ltext)
+{
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
+
+ return ltext->priv->auto_shrink;
+}
+
+/*****************************************************************************/
+/* Draw object method. */
+/*****************************************************************************/
+static void
+draw_object (glLabelObject *object,
+ cairo_t *cr,
+ gboolean screen_flag,
+ glMergeRecord *record)
+{
+ gdouble x0, y0;
+ cairo_matrix_t matrix;
+ gdouble object_w, object_h;
+ gdouble raw_w, raw_h;
+ gchar *text;
+ GList *lines;
+ gchar *font_family;
+ gdouble font_size;
+ PangoWeight font_weight;
+ gboolean font_italic_flag;
+ glColorNode *color_node;
+ gboolean auto_shrink;
+ guint color;
+ gdouble text_line_spacing;
+ PangoAlignment alignment;
+ PangoStyle style;
+ PangoLayout *layout;
+ PangoFontDescription *desc;
+ gdouble scale_x, scale_y;
+ cairo_font_options_t *font_options;
+ PangoContext *context;
+
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_object_get_position (object, &x0, &y0);
+ gl_label_object_get_matrix (object, &matrix);
+
+ gl_label_object_get_size (object, &object_w, &object_h);
+ gl_label_object_get_raw_size (object, &raw_w, &raw_h);
+ lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
+ font_family = gl_label_object_get_font_family (object);
+ font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
+ font_weight = gl_label_object_get_font_weight (object);
+ font_italic_flag = gl_label_object_get_font_italic_flag (object);
+
+ color_node = gl_label_object_get_text_color (object);
+ color = gl_color_node_expand (color_node, record);
+ if (color_node->field_flag && screen_flag)
+ {
+ color = GL_COLOR_MERGE_DEFAULT;
+ }
+ gl_color_node_free (&color_node);
+
+ alignment = gl_label_object_get_text_alignment (object);
+ text_line_spacing =
+ gl_label_object_get_text_line_spacing (object);
+ auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
+
+ text = gl_text_node_lines_expand (lines, record);
+
+ style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
+
+
+ if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
+ {
+ font_size = auto_shrink_font_size (cr,
+ font_family,
+ font_size,
+ font_weight,
+ style,
+ text,
+ object_w);
+ g_print ("Autosize new size = %g\n", font_size);
+ }
+
+
+ /*
+ * Workaround for pango Bug#341481.
+ * Render font at device scale and scale font size accordingly.
+ */
+ scale_x = 1.0;
+ scale_y = 1.0;
+ cairo_device_to_user_distance (cr, &scale_x, &scale_y);
+ scale_x = fabs (scale_x);
+ scale_y = fabs (scale_y);
+ cairo_save (cr);
+ cairo_scale (cr, scale_x, scale_y);
+
+ layout = pango_cairo_create_layout (cr);
+
+ font_options = cairo_font_options_create ();
+ cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
+ cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
+ context = pango_layout_get_context (layout);
+ pango_cairo_context_set_font_options (context, font_options);
+ cairo_font_options_destroy (font_options);
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, font_family);
+ pango_font_description_set_weight (desc, font_weight);
+ pango_font_description_set_style (desc, style);
+ pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ pango_layout_set_text (layout, text, -1);
+ pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
+ if (raw_w == 0.0)
+ {
+ pango_layout_set_width (layout, -1);
+ }
+ else
+ {
+ pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
+ }
+ pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
+ pango_layout_set_alignment (layout, alignment);
+
+
+ cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
+ cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
+ pango_cairo_show_layout (cr, layout);
+
+ cairo_restore (cr);
+
+ g_object_unref (layout);
+
+
+ gl_text_node_lines_free (&lines);
+ g_free (font_family);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*****************************************************************************/
+/* Draw shadow method. */
+/*****************************************************************************/
+static void
+draw_shadow (glLabelObject *object,
+ cairo_t *cr,
+ gboolean screen_flag,
+ glMergeRecord *record)
+{
+ gdouble x0, y0;
+ cairo_matrix_t matrix;
+ gdouble object_w, object_h;
+ gdouble raw_w, raw_h;
+ gchar *text;
+ GList *lines;
+ gchar *font_family;
+ gdouble font_size;
+ PangoWeight font_weight;
+ gboolean font_italic_flag;
+ gboolean auto_shrink;
+ guint color;
+ glColorNode *color_node;
+ gdouble text_line_spacing;
+ glColorNode *shadow_color_node;
+ gdouble shadow_opacity;
+ guint shadow_color;
+ PangoAlignment alignment;
+ PangoStyle style;
+ PangoLayout *layout;
+ PangoFontDescription *desc;
+ gdouble scale_x, scale_y;
+ cairo_font_options_t *font_options;
+ PangoContext *context;
+
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_object_get_position (object, &x0, &y0);
+ gl_label_object_get_matrix (object, &matrix);
+
+ gl_label_object_get_size (object, &object_w, &object_h);
+ gl_label_object_get_raw_size (object, &raw_w, &raw_h);
+ lines = gl_label_text_get_lines (GL_LABEL_TEXT (object));
+ font_family = gl_label_object_get_font_family (object);
+ font_size = gl_label_object_get_font_size (object) * FONT_SCALE;
+ font_weight = gl_label_object_get_font_weight (object);
+ font_italic_flag = gl_label_object_get_font_italic_flag (object);
+
+ color_node = gl_label_object_get_text_color (object);
+ color = gl_color_node_expand (color_node, record);
+ gl_color_node_free (&color_node);
+
+ alignment = gl_label_object_get_text_alignment (object);
+ text_line_spacing =
+ gl_label_object_get_text_line_spacing (object);
+ auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
+
+ shadow_color_node = gl_label_object_get_shadow_color (object);
+ if (shadow_color_node->field_flag)
+ {
+ shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
+ }
+ shadow_opacity = gl_label_object_get_shadow_opacity (object);
+ shadow_color = gl_color_shadow (shadow_color_node->color, shadow_opacity, color);
+ gl_color_node_free (&shadow_color_node);
+
+ text = gl_text_node_lines_expand (lines, record);
+
+ style = font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
+
+
+ if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
+ {
+ font_size = auto_shrink_font_size (cr,
+ font_family,
+ font_size,
+ font_weight,
+ style,
+ text,
+ object_w);
+ }
+
+
+ /*
+ * Workaround for pango Bug#341481.
+ * Render font at device scale and scale font size accordingly.
+ */
+ scale_x = 1.0;
+ scale_y = 1.0;
+ cairo_device_to_user_distance (cr, &scale_x, &scale_y);
+ scale_x = fabs (scale_x);
+ scale_y = fabs (scale_y);
+ cairo_save (cr);
+ cairo_scale (cr, scale_x, scale_y);
+
+ layout = pango_cairo_create_layout (cr);
+
+ font_options = cairo_font_options_create ();
+ cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
+ cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
+ context = pango_layout_get_context (layout);
+ pango_cairo_context_set_font_options (context, font_options);
+ cairo_font_options_destroy (font_options);
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, font_family);
+ pango_font_description_set_weight (desc, font_weight);
+ pango_font_description_set_style (desc, style);
+ pango_font_description_set_size (desc, font_size * PANGO_SCALE / scale_x);
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ pango_layout_set_text (layout, text, -1);
+ pango_layout_set_spacing (layout, font_size * (text_line_spacing-1) * PANGO_SCALE / scale_x);
+ if (raw_w == 0.0)
+ {
+ pango_layout_set_width (layout, -1);
+ }
+ else
+ {
+ pango_layout_set_width (layout, object_w * PANGO_SCALE / scale_x);
+ }
+ pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
+ pango_layout_set_alignment (layout, alignment);
+
+ cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (shadow_color));
+ cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, 0);
+ pango_cairo_show_layout (cr, layout);
+
+
+ cairo_restore (cr);
+
+ g_object_unref (layout);
+
+ gl_text_node_lines_free (&lines);
+ g_free (font_family);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+/*****************************************************************************/
+/* Automatically shrink text size to fit within horizontal width. */
+/*****************************************************************************/
+static gdouble
+auto_shrink_font_size (cairo_t *cr,
+ gchar *family,
+ gdouble size,
+ PangoWeight weight,
+ PangoStyle style,
+ gchar *text,
+ gdouble width)
+{
+ PangoLayout *layout;
+ PangoFontDescription *desc;
+ gint iw, ih;
+ gdouble layout_width;
+ gdouble new_size;
+
+ layout = pango_cairo_create_layout (cr);
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, family);
+ pango_font_description_set_weight (desc, weight);
+ pango_font_description_set_style (desc, style);
+ pango_font_description_set_size (desc, size * PANGO_SCALE);
+
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ pango_layout_set_text (layout, text, -1);
+ pango_layout_set_width (layout, -1);
+ pango_layout_get_size (layout, &iw, &ih);
+ layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
+
+ g_object_unref (layout);
+
+ g_print ("Object w = %g, layout w = %g\n", width, layout_width);
+
+ if ( layout_width > width )
+ {
+ /* Scale down. */
+ new_size = size * (width-2*GL_LABEL_TEXT_MARGIN)/layout_width;
+
+ /* Round down to nearest 1/2 point */
+ new_size = (int)(new_size*2.0) / 2.0;
+
+ /* don't get ridiculously small. */
+ if (new_size < 1.0)
+ {
+ new_size = 1.0;
+ }
+ }
+ else
+ {
+ new_size = size;
+ }
+
+ return new_size;
+}
+