]> git.sur5r.net Git - glabels/blobdiff - glabels2/src/label-object.c
2009-09-17 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / label-object.c
index f7d529e639a52a79705d7c051a7afe4876e08ed3..89cefc98a9e3568f1c0d51789f831373cb6c0896 100644 (file)
@@ -1,34 +1,44 @@
 /*
- *  (GLABELS) Label and Business Card Creation program for GNOME
+ *  label-object.c
+ *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
  *
- *  label_object.c:  GLabels label object base class
+ *  This file is part of gLabels.
  *
- *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
- *
- *  This program is free software; you can redistribute it and/or modify
+ *  gLabels 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
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  gLabels 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
+ *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
  */
+
 #include <config.h>
 
+#include "label-object.h"
+
 #include <glib.h>
-#include <libart_lgpl/libart.h>
+#include <math.h>
 
-#include "label-object.h"
 #include "marshal.h"
 
 #include "debug.h"
 
+
+/*========================================================*/
+/* Private defines.                                       */
+/*========================================================*/
+
+#define DEFAULT_SHADOW_X_OFFSET (3.6)
+#define DEFAULT_SHADOW_Y_OFFSET (3.6)
+#define DEFAULT_SHADOW_OPACITY  (0.5)
+
+
 /*========================================================*/
 /* Private types.                                         */
 /*========================================================*/
@@ -37,7 +47,15 @@ struct _glLabelObjectPrivate {
        gchar             *name;
        gdouble            x, y;
        gdouble            w, h;
-       gdouble            affine[6];
+        cairo_matrix_t     matrix;
+
+       gdouble            aspect_ratio;
+
+       gboolean           shadow_state;
+       gdouble            shadow_x;
+       gdouble            shadow_y;
+       glColorNode       *shadow_color_node;
+       gdouble            shadow_opacity;
 };
 
 enum {
@@ -46,25 +64,24 @@ enum {
        FLIP_ROTATE,
        TOP,
        BOTTOM,
+        REMOVED,
        LAST_SIGNAL
 };
 
+
 /*========================================================*/
 /* Private globals.                                       */
 /*========================================================*/
 
-static GObjectClass *parent_class = NULL;
-
 static guint signals[LAST_SIGNAL] = {0};
 
 static guint instance = 0;
 
+
 /*========================================================*/
 /* Private function prototypes.                           */
 /*========================================================*/
 
-static void gl_label_object_class_init    (glLabelObjectClass *klass);
-static void gl_label_object_instance_init (glLabelObject      *object);
 static void gl_label_object_finalize      (GObject            *object);
 
 static void merge_changed_cb              (glLabel            *label,
@@ -74,57 +91,29 @@ static void set_size                      (glLabelObject      *object,
                                           gdouble             w,
                                           gdouble             h);
 
-static void get_size                      (glLabelObject      *object,
-                                          gdouble            *w,
-                                          gdouble            *h);
 
-\f
 /*****************************************************************************/
 /* Boilerplate object stuff.                                                 */
 /*****************************************************************************/
-GType
-gl_label_object_get_type (void)
-{
-       static GType type = 0;
-
-       if (!type) {
-               GTypeInfo info = {
-                       sizeof (glLabelObjectClass),
-                       NULL,
-                       NULL,
-                       (GClassInitFunc) gl_label_object_class_init,
-                       NULL,
-                       NULL,
-                       sizeof (glLabelObject),
-                       0,
-                       (GInstanceInitFunc) gl_label_object_instance_init,
-               };
-
-               type = g_type_register_static (G_TYPE_OBJECT,
-                                              "glLabelObject", &info, 0);
-       }
+G_DEFINE_TYPE (glLabelObject, gl_label_object, G_TYPE_OBJECT);
 
-       return type;
-}
 
 static void
-gl_label_object_class_init (glLabelObjectClass *klass)
+gl_label_object_class_init (glLabelObjectClass *class)
 {
-       GObjectClass       *gobject_class = (GObjectClass *) klass;
-       glLabelObjectClass *object_class  = (glLabelObjectClass *) klass;
+       GObjectClass       *object_class = G_OBJECT_CLASS (class);
 
        gl_debug (DEBUG_LABEL, "START");
 
-       parent_class = g_type_class_peek_parent (klass);
+       gl_label_object_parent_class = g_type_class_peek_parent (class);
 
-       gobject_class->finalize = gl_label_object_finalize;
+       object_class->finalize = gl_label_object_finalize;
 
-       object_class->set_size = set_size;
-       object_class->get_size = get_size;
+       class->set_size = set_size;
 
        signals[CHANGED] =
                g_signal_new ("changed",
-                             G_OBJECT_CLASS_TYPE (gobject_class),
+                             G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (glLabelObjectClass, changed),
                              NULL, NULL,
@@ -134,7 +123,7 @@ gl_label_object_class_init (glLabelObjectClass *klass)
 
        signals[MOVED] =
                g_signal_new ("moved",
-                             G_OBJECT_CLASS_TYPE (gobject_class),
+                             G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (glLabelObjectClass, moved),
                              NULL, NULL,
@@ -143,7 +132,7 @@ gl_label_object_class_init (glLabelObjectClass *klass)
                              2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
        signals[FLIP_ROTATE] =
                g_signal_new ("flip_rotate",
-                             G_OBJECT_CLASS_TYPE (gobject_class),
+                             G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (glLabelObjectClass, flip_rotate),
                              NULL, NULL,
@@ -152,7 +141,7 @@ gl_label_object_class_init (glLabelObjectClass *klass)
                              0);
        signals[TOP] =
                g_signal_new ("top",
-                             G_OBJECT_CLASS_TYPE (gobject_class),
+                             G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (glLabelObjectClass, top),
                              NULL, NULL,
@@ -162,51 +151,66 @@ gl_label_object_class_init (glLabelObjectClass *klass)
 
        signals[BOTTOM] =
                g_signal_new ("bottom",
-                             G_OBJECT_CLASS_TYPE (gobject_class),
+                             G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (glLabelObjectClass, bottom),
                              NULL, NULL,
                              gl_marshal_VOID__VOID,
                              G_TYPE_NONE,
                              0);
+       signals[REMOVED] =
+               g_signal_new ("removed",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (glLabelObjectClass, removed),
+                             NULL, NULL,
+                             gl_marshal_VOID__VOID,
+                             G_TYPE_NONE,
+                             0);
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 static void
-gl_label_object_instance_init (glLabelObject *object)
+gl_label_object_init (glLabelObject *object)
 {
        gl_debug (DEBUG_LABEL, "START");
 
-       object->private = g_new0 (glLabelObjectPrivate, 1);
+       object->priv = g_new0 (glLabelObjectPrivate, 1);
+
+       object->priv->name = g_strdup_printf ("object%d", instance++);
 
-       object->private->name = g_strdup_printf ("object%d", instance++);
+       cairo_matrix_init_identity (&object->priv->matrix);
 
-       art_affine_identity (object->private->affine);
+       object->priv->shadow_state = FALSE;
+       object->priv->shadow_x = DEFAULT_SHADOW_X_OFFSET;
+       object->priv->shadow_y = DEFAULT_SHADOW_Y_OFFSET;
+       object->priv->shadow_color_node = gl_color_node_new_default ();
+       object->priv->shadow_opacity = DEFAULT_SHADOW_OPACITY;
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 static void
 gl_label_object_finalize (GObject *object)
 {
-       glLabel       *parent;
+        glLabelObject *label_object = GL_LABEL_OBJECT (object);
 
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       parent = GL_LABEL_OBJECT(object)->parent;
-       gl_label_remove_object (parent, GL_LABEL_OBJECT(object));
-
-       g_free (GL_LABEL_OBJECT(object)->private->name);
-       g_free (GL_LABEL_OBJECT(object)->private);
+       g_free (label_object->priv->name);
+       g_free (label_object->priv);
 
-       G_OBJECT_CLASS (parent_class)->finalize (object);
+       G_OBJECT_CLASS (gl_label_object_parent_class)->finalize (object);
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* New label object.                                                         */
 /*****************************************************************************/
@@ -226,6 +230,7 @@ gl_label_object_new (glLabel *label)
        return G_OBJECT (object);
 }
 
+
 /*****************************************************************************/
 /* Duplicate object.                                                         */
 /*****************************************************************************/
@@ -235,23 +240,37 @@ gl_label_object_dup (glLabelObject *src_object,
 {
        glLabelObject    *dst_object;
        gdouble           x, y, w, h;
-       gdouble           affine[6];
+        cairo_matrix_t    matrix;
+       gboolean          shadow_state;
+       gdouble           shadow_x, shadow_y;
+       glColorNode      *shadow_color_node;
+       gdouble           shadow_opacity;
 
        gl_debug (DEBUG_LABEL, "START");
 
-       g_return_if_fail (src_object && GL_IS_LABEL_OBJECT (src_object));
+       g_return_val_if_fail (src_object && GL_IS_LABEL_OBJECT (src_object), NULL);
 
        dst_object = g_object_new (G_OBJECT_TYPE(src_object), NULL);
 
        gl_label_object_set_parent (dst_object, label);
 
-       gl_label_object_get_position (src_object, &x, &y);
-       gl_label_object_get_size     (src_object, &w, &h);
-       gl_label_object_get_affine   (src_object, affine);
+       gl_label_object_get_position      (src_object, &x, &y);
+       gl_label_object_get_size          (src_object, &w, &h);
+       gl_label_object_get_matrix        (src_object, &matrix);
+       gl_label_object_get_shadow_offset (src_object, &shadow_x, &shadow_y);
+       shadow_color_node = gl_label_object_get_shadow_color   (src_object);
+       shadow_opacity    = gl_label_object_get_shadow_opacity (src_object);
+       shadow_state      = gl_label_object_get_shadow_state   (src_object);
 
        gl_label_object_set_position (dst_object, x, y);
        gl_label_object_set_size     (dst_object, w, h);
-       gl_label_object_set_affine   (dst_object, affine);
+       gl_label_object_set_matrix   (dst_object, &matrix);
+       gl_label_object_set_shadow_offset  (dst_object, shadow_x, shadow_y);
+       gl_label_object_set_shadow_color   (dst_object, shadow_color_node);
+       gl_label_object_set_shadow_opacity (dst_object, shadow_opacity);
+       gl_label_object_set_shadow_state   (dst_object, shadow_state);
+
+       gl_color_node_free (&shadow_color_node);
 
        if ( GL_LABEL_OBJECT_GET_CLASS(src_object)->copy != NULL ) {
 
@@ -265,6 +284,7 @@ gl_label_object_dup (glLabelObject *src_object,
        return dst_object;
 }
 
+
 /*****************************************************************************/
 /* Emit "changed" signal (for derived objects).                              */
 /*****************************************************************************/
@@ -280,6 +300,7 @@ gl_label_object_emit_changed (glLabelObject *object)
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Set parent label of object.                                               */
 /*****************************************************************************/
@@ -311,6 +332,7 @@ gl_label_object_set_parent (glLabelObject *object,
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Get parent label of object.                                               */
 /*****************************************************************************/
@@ -319,13 +341,43 @@ gl_label_object_get_parent (glLabelObject *object)
 {
        gl_debug (DEBUG_LABEL, "START");
 
-       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
 
        gl_debug (DEBUG_LABEL, "END");
 
        return object->parent;
 }
 
+
+/*****************************************************************************/
+/* Set remove object from parent.                                            */
+/*****************************************************************************/
+void
+gl_label_object_remove (glLabelObject *object)
+{
+       glLabel *parent;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       parent = object->parent;
+       if ( parent != NULL ) {
+               g_signal_handlers_disconnect_by_func (parent,
+                                                     G_CALLBACK(merge_changed_cb),
+                                                     object);
+               gl_label_remove_object (parent, object);
+
+                g_signal_emit (G_OBJECT(object), signals[REMOVED], 0);
+
+                g_object_unref (G_OBJECT(object));
+       }
+
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
 /*****************************************************************************/
 /* Set name of object.                                                       */
 /*****************************************************************************/
@@ -337,14 +389,15 @@ gl_label_object_set_name (glLabelObject *object,
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       g_free(object->private->name);
-       object->private->name = name;
+       g_free(object->priv->name);
+       object->priv->name = name;
 
        g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Get name of object.                                                       */
 /*****************************************************************************/
@@ -353,13 +406,14 @@ gl_label_object_get_name (glLabelObject *object)
 {
        gl_debug (DEBUG_LABEL, "START");
 
-       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
 
        gl_debug (DEBUG_LABEL, "END");
 
-       return g_strdup(object->private->name);
+       return g_strdup(object->priv->name);
 }
 
+
 /*****************************************************************************/
 /* Set position of object.                                                   */
 /*****************************************************************************/
@@ -374,17 +428,22 @@ gl_label_object_set_position (glLabelObject *object,
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       dx = x - object->private->x;
-       dy = y - object->private->y;
+       if ( (x != object->priv->x) || (y != object->priv->y) ) {
+
+               dx = x - object->priv->x;
+               dy = y - object->priv->y;
 
-       object->private->x = x;
-       object->private->y = y;
+               object->priv->x = x;
+               object->priv->y = y;
 
-       g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
+               g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Set position of object relative to old position.                          */
 /*****************************************************************************/
@@ -397,18 +456,23 @@ gl_label_object_set_position_relative (glLabelObject *object,
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       object->private->x += dx;
-       object->private->y += dy;
+       if ( (dx != 0.0) || (dy != 0.0) ) {
+
+               object->priv->x += dx;
+               object->priv->y += dy;
 
-       gl_debug (DEBUG_LABEL, "       x = %f, y= %f",
-                 object->private->x,
-                 object->private->y);
+               gl_debug (DEBUG_LABEL, "       x = %f, y= %f",
+                         object->priv->x,
+                         object->priv->y);
 
-       g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
+               g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Get position of object.                                                   */
 /*****************************************************************************/
@@ -421,12 +485,13 @@ gl_label_object_get_position (glLabelObject *object,
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       *x = object->private->x;
-       *y = object->private->y;
+       *x = object->priv->x;
+       *y = object->priv->y;
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*---------------------------------------------------------------------------*/
 /* PRIVATE.  Default set size method.                                        */
 /*---------------------------------------------------------------------------*/
@@ -437,10 +502,16 @@ set_size (glLabelObject *object,
 {
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       object->private->w = w;
-       object->private->h = h;
+       if ( (object->priv->w != w) || (object->priv->h != h) ) {
+
+               object->priv->w = w;
+               object->priv->h = h;
+
+               g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
+       }
 }
 
+
 /*****************************************************************************/
 /* Set size of object.                                                       */
 /*****************************************************************************/
@@ -458,31 +529,63 @@ gl_label_object_set_size (glLabelObject *object,
                /* We have an object specific method, use it */
                GL_LABEL_OBJECT_GET_CLASS(object)->set_size (object, w, h);
 
+               object->priv->aspect_ratio = h / w;
+
+       }
+
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set size of object honoring current aspect ratio.                         */
+/*****************************************************************************/
+void
+gl_label_object_set_size_honor_aspect (glLabelObject *object,
+                                      gdouble        w,
+                                      gdouble        h)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( h > w*object->priv->aspect_ratio ) {
+
+               h = w * object->priv->aspect_ratio;
+
        } else {
 
-               set_size (object, w, h);
+               w = h / object->priv->aspect_ratio;
 
        }
 
-       g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_size != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_size (object, w, h);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
-/*---------------------------------------------------------------------------*/
-/* PRIVATE.  Default get size method.                                        */
-/*---------------------------------------------------------------------------*/
-static void
-get_size (glLabelObject *object,
-         gdouble       *w,
-         gdouble       *h)
+
+/*****************************************************************************/
+/* Get raw size method (don't let object content adjust size).               */
+/*****************************************************************************/
+void
+gl_label_object_get_raw_size (glLabelObject *object,
+                              gdouble       *w,
+                              gdouble       *h)
 {
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       *w = object->private->w;
-       *h = object->private->h;
+       *w = object->priv->w;
+       *h = object->priv->h;
 }
 
+
 /*****************************************************************************/
 /* Get size of object.                                                       */
 /*****************************************************************************/
@@ -502,240 +605,990 @@ gl_label_object_get_size (glLabelObject *object,
 
        } else {
 
-               get_size (object, w, h);
+               gl_label_object_get_raw_size (object, w, h);
 
        }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /*****************************************************************************/
 /* Get extent of object.                                                     */
 /*****************************************************************************/
 void
 gl_label_object_get_extent (glLabelObject *object,
-                           gdouble       *x1,
-                           gdouble       *y1,
-                           gdouble       *x2,
-                           gdouble       *y2)
+                            glLabelRegion *region)
 {
-       gdouble  w, h;
-       ArtPoint a1, a2, a3, a4, b1, b2, b3, b4;
-       gdouble  affine[6];
+       gdouble        w, h;
+        gdouble        line_w;
+       gdouble        xa1, ya1, xa2, ya2, xa3, ya3, xa4, ya4;
+        cairo_matrix_t matrix;
 
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
        gl_label_object_get_size (object, &w, &h);
-
-       /* setup untransformed corners of bounding box */
-       a1.x = 0.0;
-       a1.y = 0.0;
-       a2.x = w;
-       a2.y = 0.0;
-       a3.x = w;
-       a3.y = h;
-       a4.x = 0.0;
-       a4.y = h;
+        line_w = gl_label_object_get_line_width (object);
+
+       /* setup untransformed corners of bounding box, account for line width */
+       xa1 =   - line_w/2;
+       ya1 =   - line_w/2;
+       xa2 = w + line_w/2;
+       ya2 =   - line_w/2;
+       xa3 = w + line_w/2;
+       ya3 = h + line_w/2;
+       xa4 =   - line_w/2;
+       ya4 = h + line_w/2;
 
        /* transform these points */
-       gl_label_object_get_affine (object, affine);
-       art_affine_point (&b1, &a1, affine);
-       art_affine_point (&b2, &a2, affine);
-       art_affine_point (&b3, &a3, affine);
-       art_affine_point (&b4, &a4, affine);
+       gl_label_object_get_matrix (object, &matrix);
+        cairo_matrix_transform_point (&matrix, &xa1, &ya1);
+        cairo_matrix_transform_point (&matrix, &xa2, &ya2);
+        cairo_matrix_transform_point (&matrix, &xa3, &ya3);
+        cairo_matrix_transform_point (&matrix, &xa4, &ya4);
 
        /* now find the maximum extent of these points in x and y */
-       *x1 = MIN (b1.x, MIN (b2.x, MIN (b3.x, b4.x))) + object->private->x;
-       *y1 = MIN (b1.y, MIN (b2.y, MIN (b3.y, b4.y))) + object->private->y;
-       *x2 = MAX (b1.x, MAX (b2.x, MAX (b3.x, b4.x))) + object->private->x;
-       *y2 = MAX (b1.y, MAX (b2.y, MAX (b3.y, b4.y))) + object->private->y;
-       
+       region->x1 = MIN (xa1, MIN (xa2, MIN (xa3, xa4))) + object->priv->x;
+       region->y1 = MIN (ya1, MIN (ya2, MIN (ya3, ya4))) + object->priv->y;
+       region->x2 = MAX (xa1, MAX (xa2, MAX (xa3, xa4))) + object->priv->x;
+       region->y2 = MAX (ya1, MAX (ya2, MAX (ya3, ya4))) + object->priv->y;
+
        gl_debug (DEBUG_LABEL, "END");
 }
 
-/****************************************************************************/
-/* Flip object horizontally.                                                */
-/****************************************************************************/
-void
-gl_label_object_flip_horiz (glLabelObject *object)
+
+/*****************************************************************************/
+/* Can text properties be set for this object?                               */
+/*****************************************************************************/
+gboolean
+gl_label_object_can_text (glLabelObject     *object)
 {
-       gdouble flip_affine[6];
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL ) {
+
+               return TRUE;
+
+       } else {
+
+               return FALSE;
+
+       }
+
+}
+
 
+/*****************************************************************************/
+/* Set font family for all text contained in object.                         */
+/*****************************************************************************/
+void
+gl_label_object_set_font_family (glLabelObject     *object,
+                                const gchar       *font_family)
+{
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       art_affine_scale (flip_affine, -1.0, 1.0);
-       art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL ) {
 
-       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family (object, font_family);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Flip object vertically.                                                  */
+/* Set font size for all text contained in object.                          */
 /****************************************************************************/
 void
-gl_label_object_flip_vert (glLabelObject *object)
+gl_label_object_set_font_size (glLabelObject     *object,
+                              gdouble            font_size)
 {
-       gdouble flip_affine[6];
-
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       art_affine_scale (flip_affine, 1.0, -1.0);
-       art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size != NULL ) {
 
-       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size (object, font_size);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Rotate object.                                                           */
+/* Set font weight for all text contained in object.                        */
 /****************************************************************************/
 void
-gl_label_object_rotate (glLabelObject *object,
-                       gdouble        theta_degs)
+gl_label_object_set_font_weight (glLabelObject     *object,
+                                PangoWeight        font_weight)
 {
-       gdouble rotate_affine[6];
-
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       art_affine_rotate (rotate_affine, theta_degs);
-       art_affine_multiply (object->private->affine, object->private->affine, rotate_affine);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight != NULL ) {
 
-       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight (object, font_weight);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Set raw affine                                                           */
+/* Set font italic flag for all text contained in object.                   */
 /****************************************************************************/
 void
-gl_label_object_set_affine (glLabelObject *object,
-                           gdouble        affine[6])
+gl_label_object_set_font_italic_flag (glLabelObject     *object,
+                                     gboolean           font_italic_flag)
 {
-       gl_debug (DEBUG_LABEL, "");
+       gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       object->private->affine[0] = affine[0];
-       object->private->affine[1] = affine[1];
-       object->private->affine[2] = affine[2];
-       object->private->affine[3] = affine[3];
-       object->private->affine[4] = affine[4];
-       object->private->affine[5] = affine[5];
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag (object,
+                                                                        font_italic_flag);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Get raw affine                                                           */
+/* Set text alignment for all text contained in object.                     */
 /****************************************************************************/
 void
-gl_label_object_get_affine (glLabelObject *object,
-                           gdouble        affine[6])
+gl_label_object_set_text_alignment (glLabelObject     *object,
+                                   PangoAlignment     text_alignment)
 {
-       gl_debug (DEBUG_LABEL, "");
+       gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       affine[0] = object->private->affine[0];
-       affine[1] = object->private->affine[1];
-       affine[2] = object->private->affine[2];
-       affine[3] = object->private->affine[3];
-       affine[4] = object->private->affine[4];
-       affine[5] = object->private->affine[5];
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment (object,
+                                                                      text_alignment);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Get i2w affine, i.e. applied affine + translation.                       */
+/* Set text line spacing for all text contained in object.                  */
 /****************************************************************************/
 void
-gl_label_object_get_i2w_affine (glLabelObject *object,
-                               gdouble        affine[6])
+gl_label_object_set_text_line_spacing (glLabelObject     *object,
+                                      gdouble            text_line_spacing)
 {
-       gdouble x, y;
-       gdouble translation[6];
-
-       gl_debug (DEBUG_LABEL, "");
+       gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       gl_label_object_get_affine (object, affine);
-       gl_label_object_get_position (object, &x, &y);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_line_spacing != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_text_line_spacing (object, text_line_spacing);
+
+       }
 
-       art_affine_translate (translation, x, y);
-       art_affine_multiply (affine, affine, translation);
+       gl_debug (DEBUG_LABEL, "END");
 }
 
+
 /****************************************************************************/
-/* Get w2i affine, i.e. inverse of applied affine + translation.            */
+/* Set text color for all text contained in object.                         */
 /****************************************************************************/
 void
-gl_label_object_get_w2i_affine (glLabelObject *object,
-                               gdouble        affine[6])
+gl_label_object_set_text_color (glLabelObject     *object,
+                               glColorNode       *text_color_node)
 {
-       gdouble i2w[6];
-       gl_debug (DEBUG_LABEL, "");
+       gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
-       gl_label_object_get_i2w_affine (object, i2w);
-       art_affine_invert (affine, i2w);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color (object, text_color_node);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Get font family for all text contained in object.                         */
+/*****************************************************************************/
+gchar *
+gl_label_object_get_font_family (glLabelObject     *object)
+{
+       gchar *ret = NULL;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_family != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_family (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
 }
 
+
 /****************************************************************************/
-/* Bring label object to front/top.                                         */
+/* Get font size for all text contained in object.                          */
 /****************************************************************************/
-void
-gl_label_object_raise_to_top (glLabelObject *object)
+gdouble
+gl_label_object_get_font_size (glLabelObject     *object)
 {
-       glLabel *label;
+       gdouble ret = 0.0;
 
        gl_debug (DEBUG_LABEL, "START");
 
-       label = object->parent;
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
 
-       gl_label_raise_object_to_top (label, object);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_size != NULL ) {
 
-       g_signal_emit (G_OBJECT(object), signals[TOP], 0);
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_size (object);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
 }
 
+
 /****************************************************************************/
-/* Send label object to rear/bottom.                                        */
+/* Get font weight for all text contained in object.                        */
 /****************************************************************************/
-void
-gl_label_object_lower_to_bottom (glLabelObject *object)
+PangoWeight    
+gl_label_object_get_font_weight (glLabelObject     *object)
 {
-       glLabel *label;
+       PangoWeight     ret = PANGO_WEIGHT_NORMAL;
 
        gl_debug (DEBUG_LABEL, "START");
 
-       label = object->parent;
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), PANGO_WEIGHT_NORMAL);
 
-       gl_label_lower_object_to_bottom (label, object);
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_weight != NULL ) {
 
-       g_signal_emit (G_OBJECT(object), signals[BOTTOM], 0);
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_weight (object);
+
+       }
 
        gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
 }
 
-/*--------------------------------------------------------------------------*/
-/* PRIVATE.  Label's merge data changed callback.                           */
-/*--------------------------------------------------------------------------*/
-static void
-merge_changed_cb (glLabel       *label,
-                 glLabelObject *object)
+
+/****************************************************************************/
+/* Get font italic flag for all text contained in object.                   */
+/****************************************************************************/
+gboolean
+gl_label_object_get_font_italic_flag (glLabelObject     *object)
 {
-       gl_label_object_emit_changed (object);
+       gboolean ret = FALSE;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_italic_flag != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_italic_flag (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
 }
 
+
+/****************************************************************************/
+/* Get text alignment for all text contained in object.                     */
+/****************************************************************************/
+PangoAlignment
+gl_label_object_get_text_alignment (glLabelObject     *object)
+{
+       PangoAlignment ret = PANGO_ALIGN_LEFT;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), PANGO_ALIGN_LEFT);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_alignment != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_alignment (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/****************************************************************************/
+/* Get text line spacing for all text contained in object.                  */
+/****************************************************************************/
+gdouble
+gl_label_object_get_text_line_spacing (glLabelObject     *object)
+{
+       gdouble ret = 0.0;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_line_spacing != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_line_spacing (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/****************************************************************************/
+/* Get text color for all text contained in object.                         */
+/****************************************************************************/
+glColorNode*
+gl_label_object_get_text_color (glLabelObject     *object)
+{
+       glColorNode *ret = NULL;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_color (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/*****************************************************************************/
+/* Can fill properties be set for this object?                               */
+/*****************************************************************************/
+gboolean
+gl_label_object_can_fill (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL ) {
+
+               return TRUE;
+
+       } else {
+
+               return FALSE;
+
+       }
+
+}
+
+
+/****************************************************************************/
+/* Set fill color for object.                                               */
+/****************************************************************************/
+void
+gl_label_object_set_fill_color (glLabelObject     *object,
+                               glColorNode       *fill_color_node)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color (object, fill_color_node);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get fill color for object.                                               */
+/****************************************************************************/
+glColorNode*
+gl_label_object_get_fill_color (glLabelObject     *object)
+{
+       glColorNode *ret = NULL;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_fill_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_fill_color (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/*****************************************************************************/
+/* Can line color property be set for this object?                           */
+/*****************************************************************************/
+gboolean
+gl_label_object_can_line_color (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL ) {
+
+               return TRUE;
+
+       } else {
+
+               return FALSE;
+
+       }
+
+}
+
+
+/****************************************************************************/
+/* Set line color for object.                                               */
+/****************************************************************************/
+void
+gl_label_object_set_line_color (glLabelObject     *object,
+                               glColorNode       *line_color_node)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color (object, line_color_node);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get line color for object.                                               */
+/****************************************************************************/
+glColorNode*
+gl_label_object_get_line_color (glLabelObject     *object)
+{
+       glColorNode *ret = NULL;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_line_color != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_line_color (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/*****************************************************************************/
+/* Can line width property be set for this object?                           */
+/*****************************************************************************/
+gboolean
+gl_label_object_can_line_width (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL ) {
+
+               return TRUE;
+
+       } else {
+
+               return FALSE;
+
+       }
+
+}
+
+
+/****************************************************************************/
+/* Set line width for object.                                               */
+/****************************************************************************/
+void
+gl_label_object_set_line_width (glLabelObject     *object,
+                               gdouble            line_width)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL ) {
+
+               /* We have an object specific method, use it */
+               GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width (object, line_width);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get line width for object.                                               */
+/****************************************************************************/
+gdouble
+gl_label_object_get_line_width (glLabelObject     *object)
+{
+       gdouble ret = 0.0;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
+
+       if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_line_width != NULL ) {
+
+               /* We have an object specific method, use it */
+               ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_line_width (object);
+
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+
+       return ret;
+}
+
+
+/****************************************************************************/
+/* Set shadow state of object.                                              */
+/****************************************************************************/
+void
+gl_label_object_set_shadow_state (glLabelObject     *object,
+                                 gboolean           state)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if (object->priv->shadow_state != state)
+       {
+               object->priv->shadow_state = state;
+               gl_label_object_emit_changed (object);
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get shadow state of object.                                              */
+/****************************************************************************/
+gboolean
+gl_label_object_get_shadow_state (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       return object->priv->shadow_state;
+}
+
+
+/****************************************************************************/
+/* Set offset of object's shadow.                                           */
+/****************************************************************************/
+void
+gl_label_object_set_shadow_offset (glLabelObject     *object,
+                                  gdouble            x,
+                                  gdouble            y)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( (x != object->priv->shadow_x) || (y != object->priv->shadow_y) )
+       {
+               object->priv->shadow_x = x;
+               object->priv->shadow_y = y;
+
+               gl_label_object_emit_changed (object);
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get offset of object's shadow.                                           */
+/****************************************************************************/
+void
+gl_label_object_get_shadow_offset (glLabelObject     *object,
+                                  gdouble           *x,
+                                  gdouble           *y)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       *x = object->priv->shadow_x;
+       *y = object->priv->shadow_y;
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set color of object's shadow.                                            */
+/****************************************************************************/
+void
+gl_label_object_set_shadow_color (glLabelObject     *object,
+                                 glColorNode       *color_node)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if ( !gl_color_node_equal (object->priv->shadow_color_node, color_node ))
+       {
+               gl_color_node_free (&(object->priv->shadow_color_node));
+               object->priv->shadow_color_node = gl_color_node_dup (color_node);
+               gl_label_object_emit_changed (GL_LABEL_OBJECT(object));
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get color of object's shadow.                                            */
+/****************************************************************************/
+glColorNode*
+gl_label_object_get_shadow_color (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
+
+       return gl_color_node_dup (object->priv->shadow_color_node);
+}
+
+
+/****************************************************************************/
+/* Set opacity of object's shadow.                                          */
+/****************************************************************************/
+void
+gl_label_object_set_shadow_opacity (glLabelObject     *object,
+                                   gdouble            alpha)
+{
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+       if (object->priv->shadow_opacity != alpha)
+       {
+               object->priv->shadow_opacity = alpha;
+               gl_label_object_emit_changed (object);
+       }
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get opacity of object's shadow.                                          */
+/****************************************************************************/
+gdouble
+gl_label_object_get_shadow_opacity (glLabelObject     *object)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
+
+       return object->priv->shadow_opacity;
+}
+
+
+/****************************************************************************/
+/* Flip object horizontally.                                                */
+/****************************************************************************/
+void
+gl_label_object_flip_horiz (glLabelObject *object)
+{
+        cairo_matrix_t flip_matrix;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        cairo_matrix_init_scale (&flip_matrix, -1.0, 1.0);
+        cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &flip_matrix);
+
+       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Flip object vertically.                                                  */
+/****************************************************************************/
+void
+gl_label_object_flip_vert (glLabelObject *object)
+{
+        cairo_matrix_t flip_matrix;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        cairo_matrix_init_scale (&flip_matrix, 1.0, -1.0);
+        cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &flip_matrix);
+
+       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Rotate object.                                                           */
+/****************************************************************************/
+void
+gl_label_object_rotate (glLabelObject *object,
+                       gdouble        theta_degs)
+{
+        cairo_matrix_t rotate_matrix;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        cairo_matrix_init_rotate (&rotate_matrix, theta_degs*(G_PI/180.));
+        cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &rotate_matrix);
+
+       g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set raw affine                                                           */
+/****************************************************************************/
+void
+gl_label_object_set_matrix (glLabelObject  *object,
+                            cairo_matrix_t *matrix)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        object->priv->matrix = *matrix;
+}
+
+
+/****************************************************************************/
+/* Get raw affine                                                           */
+/****************************************************************************/
+void
+gl_label_object_get_matrix (glLabelObject  *object,
+                            cairo_matrix_t *matrix)
+{
+       gl_debug (DEBUG_LABEL, "");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        *matrix = object->priv->matrix;
+}
+
+
+/****************************************************************************/
+/* Bring label object to front/top.                                         */
+/****************************************************************************/
+void
+gl_label_object_raise_to_top (glLabelObject *object)
+{
+       glLabel *label;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       label = object->parent;
+
+       gl_label_raise_object_to_top (label, object);
+
+       g_signal_emit (G_OBJECT(object), signals[TOP], 0);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Send label object to rear/bottom.                                        */
+/****************************************************************************/
+void
+gl_label_object_lower_to_bottom (glLabelObject *object)
+{
+       glLabel *label;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       label = object->parent;
+
+       gl_label_lower_object_to_bottom (label, object);
+
+       g_signal_emit (G_OBJECT(object), signals[BOTTOM], 0);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Label's merge data changed callback.                           */
+/*--------------------------------------------------------------------------*/
+static void
+merge_changed_cb (glLabel       *label,
+                 glLabelObject *object)
+{
+       gl_label_object_emit_changed (object);
+}
+
+
+/*****************************************************************************/
+/* Draw object                                                               */
+/*****************************************************************************/
+void
+gl_label_object_draw (glLabelObject *object,
+                      cairo_t       *cr,
+                      gboolean       screen_flag,
+                      glMergeRecord *record)
+
+{
+        gdouble        x0, y0;
+        cairo_matrix_t matrix;
+       gboolean       shadow_state;
+       gdouble        shadow_x, shadow_y;
+
+       gl_debug (DEBUG_LABEL, "START");
+
+       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+        gl_label_object_get_position (object, &x0, &y0);
+        gl_label_object_get_matrix (object, &matrix);
+
+        cairo_save (cr);
+        cairo_translate (cr, x0, y0);
+
+        if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_shadow != NULL ) {
+
+                shadow_state = gl_label_object_get_shadow_state (object);
+
+                if ( shadow_state )
+                {
+                        gl_label_object_get_shadow_offset (object, &shadow_x, &shadow_y);
+
+                        cairo_save (cr);
+                        cairo_translate (cr, shadow_x, shadow_y);
+                        cairo_transform (cr, &matrix);
+
+                        GL_LABEL_OBJECT_GET_CLASS(object)->draw_shadow (object,
+                                                                        cr,
+                                                                        screen_flag,
+                                                                        record);
+
+                        cairo_restore (cr);
+                }
+        }
+
+        if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_object != NULL ) {
+
+                cairo_save (cr);
+                cairo_transform (cr, &matrix);
+
+                GL_LABEL_OBJECT_GET_CLASS(object)->draw_object (object,
+                                                                cr,
+                                                                screen_flag,
+                                                                record);
+
+                cairo_restore (cr);
+        }
+
+        cairo_restore (cr);
+
+       gl_debug (DEBUG_LABEL, "END");
+}
+
+
+
+
+/*
+ * Local Variables:       -- emacs
+ * mode: C                -- emacs
+ * c-basic-offset: 8      -- emacs
+ * tab-width: 8           -- emacs
+ * indent-tabs-mode: nil  -- emacs
+ * End:                   -- emacs
+ */