-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-
/*
- * (GLABELS) Label and Business Card Creation program for GNOME
- *
- * label.c: GLabels label module
+ * label.c
+ * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
*
- * Copyright (C) 2001-2007 Jim Evins <evins@snaught.com>.
+ * This file is part of gLabels.
*
- * 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.h"
#include <glib/gi18n.h>
+#include <math.h>
-#include "marshal.h"
+#include "template-history.h"
+#include "file-util.h"
+#include "xml-label.h"
#include "prefs.h"
-#include "util.h"
+#include "label-text.h"
+#include "label-image.h"
+#include "marshal.h"
#include "debug.h"
+
/*========================================================*/
/* Private macros and constants. */
/*========================================================*/
+
/*========================================================*/
/* Private types. */
/*========================================================*/
gchar *filename;
gint compression;
- gboolean modified_flag;
gint untitled_instance;
+ gboolean modified_flag;
+ GTimeVal time_stamp;
+
+ lglTemplate *template;
+ gboolean rotate_flag;
+
+ GList *object_list;
+
glMerge *merge;
GHashTable *pixbuf_cache;
+ GHashTable *svg_cache;
+
+ /* Delay changed signals while operating on selections of multiple objects. */
+ gboolean selection_op_flag;
+ gboolean delayed_change_flag;
+
+ /* Default object text properties */
+ gchar *default_font_family;
+ gdouble default_font_size;
+ PangoWeight default_font_weight;
+ gboolean default_font_italic_flag;
+ guint default_text_color;
+ PangoAlignment default_text_alignment;
+ gdouble default_text_line_spacing;
+
+ /* Default object line properties */
+ gdouble default_line_width;
+ guint default_line_color;
+
+ /* Default object fill properties */
+ guint default_fill_color;
+
+ /* Undo/Redo state */
+ GQueue *undo_stack;
+ GQueue *redo_stack;
+ gboolean cp_cleared_flag;
+ gchar *cp_desc;
};
+typedef struct {
+ gchar *xml_buffer;
+ gchar *text;
+ GdkPixbuf *pixbuf;
+} ClipboardData;
+
enum {
+ SELECTION_CHANGED,
CHANGED,
NAME_CHANGED,
MODIFIED_CHANGED,
MERGE_CHANGED,
SIZE_CHANGED,
- OBJECT_ADDED,
LAST_SIGNAL
};
+typedef struct {
+ gchar *description;
+
+ gboolean modified_flag;
+ GTimeVal time_stamp;
+
+ lglTemplate *template;
+ gboolean rotate_flag;
+
+ GList *object_list;
+
+ glMerge *merge;
+
+} State;
+
+
/*========================================================*/
/* Private globals. */
/*========================================================*/
static guint untitled = 0;
+
/*========================================================*/
/* Private function prototypes. */
/*========================================================*/
static void gl_label_finalize (GObject *object);
static void object_changed_cb (glLabelObject *object,
- glLabel *label);
+ glLabel *label);
static void object_moved_cb (glLabelObject *object,
- gdouble x,
- gdouble y,
- glLabel *label);
+ glLabel *label);
+
+static void do_modify (glLabel *label);
+
+static void begin_selection_op (glLabel *label);
+static void end_selection_op (glLabel *label);
+
+static void clipboard_get_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ ClipboardData *data);
+
+static void clipboard_clear_cb (GtkClipboard *clipboard,
+ ClipboardData *data);
+
+static void receive_targets_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ gint n_targets,
+ glLabel *label);
+
+static void paste_xml_received_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ glLabel *label);
+
+static void paste_text_received_cb (GtkClipboard *clipboard,
+ const gchar *text,
+ glLabel *label);
+
+static void paste_image_received_cb(GtkClipboard *clipboard,
+ GdkPixbuf *pixbuf,
+ glLabel *label);
+
+static void stack_clear (GQueue *stack);
+static void stack_push_state (GQueue *stack,
+ State *state);
+static State *stack_pop_state (GQueue *stack);
+
+static State *state_new (glLabel *this,
+ const gchar *description);
+static void state_free (State *state);
+static void state_restore (State *state,
+ glLabel *this);
+
-\f
/*****************************************************************************/
/* Boilerplate object stuff. */
/*****************************************************************************/
-G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT);
+G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT)
+
static void
gl_label_class_init (glLabelClass *class)
object_class->finalize = gl_label_finalize;
+ signals[SELECTION_CHANGED] =
+ g_signal_new ("selection_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (glLabelClass, selection_changed),
+ NULL, NULL,
+ gl_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
signals[CHANGED] =
g_signal_new ("changed",
G_OBJECT_CLASS_TYPE (object_class),
gl_marshal_VOID__VOID,
G_TYPE_NONE,
0);
- signals[OBJECT_ADDED] =
- g_signal_new ("object_added",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (glLabelClass, object_added),
- NULL, NULL,
- gl_marshal_VOID__OBJECT,
- G_TYPE_NONE,
- 1, G_TYPE_OBJECT);
gl_debug (DEBUG_LABEL, "END");
}
+
static void
gl_label_init (glLabel *label)
{
gl_debug (DEBUG_LABEL, "START");
- label->template = NULL;
- label->rotate_flag = FALSE;
- label->objects = NULL;
-
label->priv = g_new0 (glLabelPrivate, 1);
- label->priv->filename = NULL;
- label->priv->merge = NULL;
- label->priv->pixbuf_cache = gl_pixbuf_cache_new ();
+ label->priv->template = NULL;
+ label->priv->rotate_flag = FALSE;
+ label->priv->object_list = NULL;
+
+ label->priv->filename = NULL;
+ label->priv->modified_flag = FALSE;
+ label->priv->compression = 9;
+
+ label->priv->merge = NULL;
+ label->priv->pixbuf_cache = gl_pixbuf_cache_new ();
+ label->priv->svg_cache = gl_svg_cache_new ();
+
+ label->priv->undo_stack = g_queue_new ();
+ label->priv->redo_stack = g_queue_new ();
+
+ /*
+ * Defaults from preferences
+ */
+ label->priv->default_font_family = gl_prefs_model_get_default_font_family (gl_prefs);
+ label->priv->default_font_size = gl_prefs_model_get_default_font_size (gl_prefs);
+ label->priv->default_font_weight = gl_prefs_model_get_default_font_weight (gl_prefs);
+ label->priv->default_font_italic_flag = gl_prefs_model_get_default_font_italic_flag (gl_prefs);
+ label->priv->default_text_color = gl_prefs_model_get_default_text_color (gl_prefs);
+ label->priv->default_text_alignment = gl_prefs_model_get_default_text_alignment (gl_prefs);
+ label->priv->default_text_line_spacing = gl_prefs_model_get_default_text_line_spacing (gl_prefs);
+ label->priv->default_line_width = gl_prefs_model_get_default_line_width (gl_prefs);
+ label->priv->default_line_color = gl_prefs_model_get_default_line_color (gl_prefs);
+ label->priv->default_fill_color = gl_prefs_model_get_default_fill_color (gl_prefs);
gl_debug (DEBUG_LABEL, "END");
}
+
static void
gl_label_finalize (GObject *object)
{
glLabel *label = GL_LABEL (object);
- GList *p, *p_next;
+ GList *p;
gl_debug (DEBUG_LABEL, "START");
g_return_if_fail (object && GL_IS_LABEL (object));
- for (p = label->objects; p != NULL; p = p_next) {
- p_next = p->next; /* NOTE: p will be left dangling */
+ for (p = label->priv->object_list; p != NULL; p = p->next)
+ {
g_object_unref (G_OBJECT(p->data));
}
+ g_list_free (label->priv->object_list);
- lgl_template_free (label->template);
+ lgl_template_free (label->priv->template);
g_free (label->priv->filename);
- if (label->priv->merge != NULL) {
+ if (label->priv->merge != NULL)
+ {
g_object_unref (G_OBJECT(label->priv->merge));
}
+ g_free (label->priv->default_font_family);
+
+ stack_clear (label->priv->undo_stack);
+ stack_clear (label->priv->redo_stack);
+
+ g_queue_free (label->priv->undo_stack);
+ g_queue_free (label->priv->redo_stack);
+
gl_pixbuf_cache_free (label->priv->pixbuf_cache);
+ gl_svg_cache_free (label->priv->svg_cache);
g_free (label->priv);
gl_debug (DEBUG_LABEL, "END");
}
+
+/*****************************************************************************/
+/* New label. */
+/*****************************************************************************/
GObject *
gl_label_new (void)
{
label = g_object_new (gl_label_get_type(), NULL);
- label->priv->compression = 9;
-
- label->priv->modified_flag = FALSE;
-
gl_debug (DEBUG_LABEL, "END");
return G_OBJECT (label);
}
-/*****************************************************************************/
-/* Add object to label. */
-/*****************************************************************************/
+/****************************************************************************/
+/* Set filename. */
+/****************************************************************************/
void
-gl_label_add_object (glLabel *label,
- glLabelObject *object)
+gl_label_set_filename (glLabel *label,
+ const gchar *filename)
{
- gl_debug (DEBUG_LABEL, "START");
+ label->priv->filename = g_strdup (filename);
- g_return_if_fail (label && GL_IS_LABEL (label));
- g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+ g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
+}
- object->parent = label;
- label->objects = g_list_append (label->objects, g_object_ref (object));
- label->priv->modified_flag = TRUE;
+/****************************************************************************/
+/* return filename. */
+/****************************************************************************/
+gchar *
+gl_label_get_filename (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "");
- g_signal_emit (G_OBJECT(label), signals[OBJECT_ADDED], 0, object);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
+ return g_strdup ( label->priv->filename );
+}
- g_signal_connect (G_OBJECT(object), "changed",
- G_CALLBACK(object_changed_cb), label);
- g_signal_connect (G_OBJECT(object), "moved",
- G_CALLBACK(object_moved_cb), label);
+/****************************************************************************/
+/* return short filename. */
+/****************************************************************************/
+gchar *
+gl_label_get_short_name (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "");
- gl_debug (DEBUG_LABEL, "END");
-}
+ if ( label->priv->filename == NULL )
+ {
-/*****************************************************************************/
-/* Remove object from label. */
-/*****************************************************************************/
-void
-gl_label_remove_object (glLabel *label,
- glLabelObject *object)
-{
- gl_debug (DEBUG_LABEL, "START");
+ if ( label->priv->untitled_instance == 0 )
+ {
+ label->priv->untitled_instance = ++untitled;
+ }
- g_return_if_fail (label && GL_IS_LABEL (label));
- g_return_if_fail (GL_IS_LABEL_OBJECT (object));
+ return g_strdup_printf ( "%s %d", _("Untitled"),
+ label->priv->untitled_instance );
+
+ }
+ else
+ {
+ gchar *temp_name, *short_name;
+
+ temp_name = g_path_get_basename ( label->priv->filename );
+ short_name = gl_file_util_remove_extension (temp_name);
+ g_free (temp_name);
- object->parent = NULL;
- label->objects = g_list_remove (label->objects, object);
+ return short_name;
+ }
+}
- if ( G_OBJECT(label)->ref_count /* not finalized */ ) {
- g_signal_handlers_disconnect_by_func (object,
- G_CALLBACK(object_changed_cb),
- label);
- g_signal_handlers_disconnect_by_func (object,
- G_CALLBACK(object_moved_cb),
- label);
+/****************************************************************************/
+/* Is label untitled? */
+/****************************************************************************/
+gboolean
+gl_label_is_untitled (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
+ return (label->priv->filename == NULL);
+}
- label->priv->modified_flag = TRUE;
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
+/****************************************************************************/
+/* Set compression level. */
+/****************************************************************************/
+void
+gl_label_set_compression (glLabel *label,
+ gint compression)
+{
+ gl_debug (DEBUG_LABEL, "set %d", compression);
+ /* Older versions of libxml2 always return a -1 for documents "read in," so
+ * default to 9. Also, default to 9 for anything else out of range. */
+ if ((compression < 0) || (compression >9))
+ {
+ compression = 9;
}
- gl_debug (DEBUG_LABEL, "END");
+ gl_debug (DEBUG_LABEL, "actual set %d", compression);
+ label->priv->compression = compression;
}
-/*---------------------------------------------------------------------------*/
-/* PRIVATE. Object changed callback. */
-/*---------------------------------------------------------------------------*/
-static void
-object_changed_cb (glLabelObject *object,
- glLabel *label)
+
+/****************************************************************************/
+/* Get compression level. */
+/****************************************************************************/
+gint
+gl_label_get_compression (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
+ return label->priv->compression;
+}
+
+
+/****************************************************************************/
+/* Set modified flag. */
+/****************************************************************************/
+void
+gl_label_set_modified (glLabel *label)
{
- if ( !label->priv->modified_flag ) {
+ if ( !label->priv->modified_flag )
+ {
label->priv->modified_flag = TRUE;
g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
}
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
}
-/*---------------------------------------------------------------------------*/
-/* PRIVATE. Object moved callback. */
-/*---------------------------------------------------------------------------*/
-static void
-object_moved_cb (glLabelObject *object,
- gdouble x,
- gdouble y,
- glLabel *label)
+
+/****************************************************************************/
+/* Clear modified flag. */
+/****************************************************************************/
+void
+gl_label_clear_modified (glLabel *label)
{
- if ( !label->priv->modified_flag ) {
+ if ( label->priv->modified_flag )
+ {
- label->priv->modified_flag = TRUE;
+ g_get_current_time (&label->priv->time_stamp);
+ label->priv->modified_flag = FALSE;
g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
}
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
}
+
/****************************************************************************/
-/* Bring label object to front/top. */
+/* Is label modified? */
/****************************************************************************/
-void
-gl_label_raise_object_to_top (glLabel *label,
- glLabelObject *object)
+gboolean
+gl_label_is_modified (glLabel *label)
{
- gl_debug (DEBUG_LABEL, "START");
+ gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
+ return label->priv->modified_flag;
+}
- /* Move to end of list, representing front most object */
- label->objects = g_list_remove (label->objects, object);
- label->objects = g_list_append (label->objects, object);
- label->priv->modified_flag = TRUE;
+/****************************************************************************/
+/* Object "changed" callback. */
+/****************************************************************************/
+static void
+object_changed_cb (glLabelObject *object,
+ glLabel *label)
+{
+ do_modify (label);
+}
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
- gl_debug (DEBUG_LABEL, "END");
+/****************************************************************************/
+/* Object "moved" callback. */
+/****************************************************************************/
+static void
+object_moved_cb (glLabelObject *object,
+ glLabel *label)
+{
+ do_modify (label);
}
+
/****************************************************************************/
-/* Send label object to rear/bottom. */
+/* Do modify. */
/****************************************************************************/
-void
-gl_label_lower_object_to_bottom (glLabel *label,
- glLabelObject *object)
+static void
+do_modify (glLabel *label)
{
- gl_debug (DEBUG_LABEL, "START");
+ if ( label->priv->selection_op_flag )
+ {
+ label->priv->delayed_change_flag = TRUE;
+ }
+ else
+ {
+ label->priv->modified_flag = TRUE;
- /* Move to front of list, representing rear most object */
- label->objects = g_list_remove (label->objects, object);
- label->objects = g_list_prepend (label->objects, object);
+ g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
+ g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
+ }
+}
- label->priv->modified_flag = TRUE;
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
+/****************************************************************************/
+/* Begin selection operation. */
+/****************************************************************************/
+static void
+begin_selection_op (glLabel *label)
+{
+ label->priv->selection_op_flag = TRUE;
+}
- gl_debug (DEBUG_LABEL, "END");
+
+/****************************************************************************/
+/* End selection operation. */
+/****************************************************************************/
+static void
+end_selection_op (glLabel *label)
+{
+ label->priv->selection_op_flag = FALSE;
+ if ( label->priv->delayed_change_flag )
+ {
+ label->priv->delayed_change_flag = FALSE;
+ do_modify (label);
+ }
}
+
/****************************************************************************/
/* set template. */
/****************************************************************************/
-extern void
-gl_label_set_template (glLabel *label,
- lglTemplate *template)
+void
+gl_label_set_template (glLabel *label,
+ const lglTemplate *template,
+ gboolean checkpoint)
{
gchar *name;
g_return_if_fail (label && GL_IS_LABEL (label));
g_return_if_fail (template);
- if ((label->template == NULL) ||
- !lgl_template_do_templates_match (template, label->template)) {
+ if ((label->priv->template == NULL) ||
+ !lgl_template_do_templates_match (template, label->priv->template))
+ {
- lgl_template_free (label->template);
- label->template = lgl_template_dup (template);
+ if ( checkpoint )
+ {
+ gl_label_checkpoint (label, _("Label properties"));
+ }
- label->priv->modified_flag = TRUE;
+ lgl_template_free (label->priv->template);
+ label->priv->template = lgl_template_dup (template);
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
+ do_modify (label);
g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
name = lgl_template_get_name (template);
- gl_prefs_add_recent_template (name);
+ gl_template_history_model_add_name (gl_template_history, name);
g_free (name);
}
gl_debug (DEBUG_LABEL, "END");
}
+
+/****************************************************************************/
+/* get template. */
+/****************************************************************************/
+const lglTemplate *
+gl_label_get_template (glLabel *label)
+{
+ return label->priv->template;
+}
+
+
/****************************************************************************/
/* set rotate flag. */
/****************************************************************************/
-extern void
+void
gl_label_set_rotate_flag (glLabel *label,
- gboolean rotate_flag)
+ gboolean rotate_flag,
+ gboolean checkpoint)
{
gl_debug (DEBUG_LABEL, "START");
g_return_if_fail (label && GL_IS_LABEL (label));
- if (rotate_flag != label->rotate_flag) {
-
- label->rotate_flag = rotate_flag;
+ if (rotate_flag != label->priv->rotate_flag)
+ {
+ if ( checkpoint )
+ {
+ gl_label_checkpoint (label, _("Label properties"));
+ }
- label->priv->modified_flag = TRUE;
+ label->priv->rotate_flag = rotate_flag;
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
+ do_modify (label);
g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
-
}
gl_debug (DEBUG_LABEL, "END");
}
+
+/****************************************************************************/
+/* Get rotate flag. */
+/****************************************************************************/
+gboolean
+gl_label_get_rotate_flag (glLabel *label)
+{
+ return label->priv->rotate_flag;
+}
+
+
/****************************************************************************/
/* Get label size. */
/****************************************************************************/
g_return_if_fail (label && GL_IS_LABEL (label));
- template = label->template;
- if ( !template ) {
+ template = label->priv->template;
+ if ( !template )
+ {
gl_debug (DEBUG_LABEL, "END -- template NULL");
*w = *h = 0;
return;
}
frame = (lglTemplateFrame *)template->frames->data;
- if (!label->rotate_flag) {
+ if (!label->priv->rotate_flag)
+ {
lgl_template_frame_get_size (frame, w, h);
- } else {
+ }
+ else
+ {
lgl_template_frame_get_size (frame, h, w);
}
gl_debug (DEBUG_LABEL, "END");
}
+
/****************************************************************************/
/* set merge information structure. */
/****************************************************************************/
-extern void
+void
gl_label_set_merge (glLabel *label,
- glMerge *merge)
+ glMerge *merge,
+ gboolean checkpoint)
{
gl_debug (DEBUG_LABEL, "START");
g_return_if_fail (label && GL_IS_LABEL (label));
- if ( label->priv->merge != NULL ) {
+ if ( checkpoint )
+ {
+ gl_label_checkpoint (label, _("Merge properties"));
+ }
+
+ if ( label->priv->merge != NULL )
+ {
g_object_unref (G_OBJECT(label->priv->merge));
}
label->priv->merge = gl_merge_dup (merge);
- label->priv->modified_flag = TRUE;
-
+ do_modify (label);
g_signal_emit (G_OBJECT(label), signals[MERGE_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
- g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
gl_debug (DEBUG_LABEL, "END");
}
+
/****************************************************************************/
/* Get merge information structure. */
/****************************************************************************/
return gl_merge_dup (label->priv->merge);
}
+
/****************************************************************************/
-/* return filename. */
+/* Get pixbuf cache. */
/****************************************************************************/
-gchar *
-gl_label_get_filename (glLabel *label)
+GHashTable *
+gl_label_get_pixbuf_cache (glLabel *label)
{
+ return label->priv->pixbuf_cache;
+}
+
+
+/****************************************************************************/
+/* Get svg cache. */
+/****************************************************************************/
+GHashTable *
+gl_label_get_svg_cache (glLabel *label)
+{
+ return label->priv->svg_cache;
+}
+
+
+/*****************************************************************************/
+/* Add object to label. */
+/*****************************************************************************/
+void
+gl_label_add_object (glLabel *label,
+ glLabelObject *object)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+ g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+ gl_label_object_set_parent (object, label);
+ label->priv->object_list = g_list_append (label->priv->object_list, object);
+
+ g_signal_connect (G_OBJECT (object), "changed",
+ G_CALLBACK (object_changed_cb), label);
+ g_signal_connect (G_OBJECT (object), "moved",
+ G_CALLBACK (object_moved_cb), label);
+
+ do_modify (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Delete object from label. */
+/*****************************************************************************/
+void
+gl_label_delete_object (glLabel *label,
+ glLabelObject *object)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+ g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+ label->priv->object_list = g_list_remove (label->priv->object_list, object);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (object),
+ G_CALLBACK (object_changed_cb), label);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (object),
+ G_CALLBACK (object_moved_cb), label);
+ g_object_unref (object);
+
+ do_modify (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Get object list. */
+/*****************************************************************************/
+const GList *
+gl_label_get_object_list (glLabel *label)
+{
+ return label->priv->object_list;
+}
+
+
+/*****************************************************************************/
+/* Select object. */
+/*****************************************************************************/
+void
+gl_label_select_object (glLabel *label,
+ glLabelObject *object)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+ g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+ gl_label_object_select (object);
+
+ label->priv->cp_cleared_flag = TRUE;
+ g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Unselect object. */
+/*****************************************************************************/
+void
+gl_label_unselect_object (glLabel *label,
+ glLabelObject *object)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+ g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+
+ gl_label_object_unselect (object);
+
+ label->priv->cp_cleared_flag = TRUE;
+ g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Select all objects. */
+/*****************************************************************************/
+void
+gl_label_select_all (glLabel *label)
+{
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_select (object);
+ }
+
+ label->priv->cp_cleared_flag = TRUE;
+ g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Unselect all objects. */
+/*****************************************************************************/
+void
+gl_label_unselect_all (glLabel *label)
+{
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_unselect (object);
+ }
+
+ label->priv->cp_cleared_flag = TRUE;
+ g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Select all objects contained in region. */
+/*****************************************************************************/
+void
+gl_label_select_region (glLabel *label,
+ glLabelRegion *region)
+{
+ GList *p;
+ glLabelObject *object;
+ gdouble r_x1, r_y1;
+ gdouble r_x2, r_y2;
+ glLabelRegion obj_extent;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ r_x1 = MIN (region->x1, region->x2);
+ r_y1 = MIN (region->y1, region->y2);
+ r_x2 = MAX (region->x1, region->x2);
+ r_y2 = MAX (region->y1, region->y2);
+
+ for (p = label->priv->object_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT(p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ if ((obj_extent.x1 >= r_x1) &&
+ (obj_extent.x2 <= r_x2) &&
+ (obj_extent.y1 >= r_y1) &&
+ (obj_extent.y2 <= r_y2))
+ {
+ gl_label_object_select (object);
+ }
+ }
+
+ label->priv->cp_cleared_flag = TRUE;
+ g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Is selection empty? */
+/*****************************************************************************/
+gboolean
+gl_label_is_selection_empty (glLabel *label)
+{
+ GList *p;
+ glLabelObject *object;
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if ( gl_label_object_is_selected (object) )
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*****************************************************************************/
+/* Is selection atomic? */
+/*****************************************************************************/
+gboolean
+gl_label_is_selection_atomic (glLabel *label)
+{
+ GList *p;
+ glLabelObject *object;
+ gint n_selected = 0;
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if ( gl_label_object_is_selected (object) )
+ {
+ n_selected++;
+
+ if (n_selected > 1)
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return (n_selected == 1);
+}
+
+
+/*****************************************************************************/
+/* Get first selected object. */
+/*****************************************************************************/
+glLabelObject *
+gl_label_get_1st_selected_object (glLabel *label)
+{
+ GList *p;
+ glLabelObject *object;
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if ( gl_label_object_is_selected (object) )
+ {
+ return object;
+ }
+ }
+
+ return NULL;
+}
+
+
+/*****************************************************************************/
+/* Get list of selected objects. */
+/*****************************************************************************/
+GList *
+gl_label_get_selection_list (glLabel *label)
+{
+ GList *selection_list = NULL;
+ GList *p;
+ glLabelObject *object;
+
+ for ( p = label->priv->object_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if ( gl_label_object_is_selected (object) )
+ {
+ selection_list = g_list_append (selection_list, object);
+ }
+ }
+
+ return (selection_list);
+}
+
+
+/*****************************************************************************/
+/* Can text properties be set for selection? */
+/*****************************************************************************/
+gboolean
+gl_label_can_selection_text (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if (gl_label_object_can_text (object))
+ {
+ g_list_free (selection_list);
+ return TRUE;
+ }
+ }
+
+ g_list_free (selection_list);
+ return FALSE;
+}
+
+
+/*****************************************************************************/
+/* Can fill properties be set for selection? */
+/*****************************************************************************/
+gboolean
+gl_label_can_selection_fill (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if (gl_label_object_can_fill (object))
+ {
+ g_list_free (selection_list);
+ return TRUE;
+ }
+
+ }
+
+ g_list_free (selection_list);
+ return FALSE;
+}
+
+
+/*****************************************************************************/
+/* Can line color properties be set for selection? */
+/*****************************************************************************/
+gboolean
+gl_label_can_selection_line_color (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if (gl_label_object_can_line_color (object))
+ {
+ g_list_free (selection_list);
+ return TRUE;
+ }
+ }
+
+ g_list_free (selection_list);
+ return FALSE;
+}
+
+
+/*****************************************************************************/
+/* Can line width properties be set for selection? */
+/*****************************************************************************/
+gboolean
+gl_label_can_selection_line_width (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
gl_debug (DEBUG_LABEL, "");
- return g_strdup ( label->priv->filename );
+ g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ if (gl_label_object_can_line_width (object))
+ {
+ g_list_free (selection_list);
+ return TRUE;
+ }
+
+ }
+
+ g_list_free (selection_list);
+ return FALSE;
+}
+
+
+/*****************************************************************************/
+/* Delete selection from label. */
+/*****************************************************************************/
+void
+gl_label_delete_selection (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ gl_label_checkpoint (label, _("Delete"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_delete_object (label, object);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Bring selection object to front/top. */
+/****************************************************************************/
+void
+gl_label_raise_selection_to_top (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_checkpoint (label, _("Bring to front"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ label->priv->object_list = g_list_remove (label->priv->object_list, object);
+ }
+
+ /* Move to end of list, representing front most object */
+ label->priv->object_list = g_list_concat (label->priv->object_list, selection_list);
+
+ do_modify (label);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Send selection to rear/bottom. */
+/****************************************************************************/
+void
+gl_label_lower_selection_to_bottom (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_checkpoint (label, _("Send to back"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ label->priv->object_list = g_list_remove (label->priv->object_list, object);
+ }
+
+ /* Move to front of list, representing rear most object */
+ label->priv->object_list = g_list_concat (selection_list, label->priv->object_list);
+
+ do_modify (label);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Rotate selected objects by given angle. */
+/*****************************************************************************/
+void
+gl_label_rotate_selection (glLabel *label,
+ gdouble theta_degs)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ gl_label_checkpoint (label, _("Rotate"));
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_rotate (object, theta_degs);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Rotate selected objects 90 degrees left. */
+/*****************************************************************************/
+void
+gl_label_rotate_selection_left (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ gl_label_checkpoint (label, _("Rotate left"));
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_rotate (object, -90.0);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Rotate selected objects 90 degrees right. */
+/*****************************************************************************/
+void
+gl_label_rotate_selection_right (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ gl_label_checkpoint (label, _("Rotate right"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_rotate (object, 90.0);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Flip selected objects horizontally. */
+/*****************************************************************************/
+void
+gl_label_flip_selection_horiz (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ gl_label_checkpoint (label, _("Flip horizontally"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_flip_horiz (object);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Flip selected objects vertically. */
+/*****************************************************************************/
+void
+gl_label_flip_selection_vert (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ gl_label_checkpoint (label, _("Flip vertically"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for ( p = selection_list; p != NULL; p = p->next )
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_flip_vert (object);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to left most edge. */
+/*****************************************************************************/
+void
+gl_label_align_selection_left (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dx, x1_min;
+ glLabelRegion obj_extent;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align left"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find left most edge */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ x1_min = obj_extent.x1;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
+ }
+
+ /* now adjust the object positions to line up the left edges */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dx = x1_min - obj_extent.x1;
+ gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to right most edge. */
+/*****************************************************************************/
+void
+gl_label_align_selection_right (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dx, x2_max;
+ glLabelRegion obj_extent;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align right"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find left most edge */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ x2_max = obj_extent.x2;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
+ }
+
+ /* now adjust the object positions to line up the left edges */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dx = x2_max - obj_extent.x2;
+ gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to horizontal center of objects. */
+/*****************************************************************************/
+void
+gl_label_align_selection_hcenter (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dx;
+ gdouble dxmin;
+ gdouble xsum, xavg;
+ glLabelRegion obj_extent;
+ gdouble xcenter;
+ gint n;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align horizontal center"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find average center of objects */
+ xsum = 0.0;
+ n = 0;
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
+ n++;
+ }
+ xavg = xsum / n;
+
+ /* find center of object closest to average center */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+ xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
+ if ( dx < dxmin )
+ {
+ dxmin = dx;
+ xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
+ }
+ }
+
+ /* now adjust the object positions to line up this center */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
+ gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to top most edge. */
+/*****************************************************************************/
+void
+gl_label_align_selection_top (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dy, y1_min;
+ glLabelRegion obj_extent;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align tops"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find top most edge */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ y1_min = obj_extent.y1;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
+ }
+
+ /* now adjust the object positions to line up the top edges */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dy = y1_min - obj_extent.y1;
+ gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to bottom most edge. */
+/*****************************************************************************/
+void
+gl_label_align_selection_bottom (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dy, y2_max;
+ glLabelRegion obj_extent;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align bottoms"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find bottom most edge */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ y2_max = obj_extent.y2;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
+ }
+
+ /* now adjust the object positions to line up the bottom edges */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dy = y2_max - obj_extent.y2;
+ gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Align selected objects to viertical center of objects. */
+/*****************************************************************************/
+void
+gl_label_align_selection_vcenter (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dy;
+ gdouble dymin;
+ gdouble ysum, yavg;
+ glLabelRegion obj_extent;
+ gdouble ycenter;
+ gint n;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label) &&
+ !gl_label_is_selection_atomic (label));
+
+ gl_label_checkpoint (label, _("Align vertical center"));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ /* find average center of objects */
+ ysum = 0.0;
+ n = 0;
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
+ n++;
+ }
+ yavg = ysum / n;
+
+ /* find center of object closest to average center */
+ p = selection_list;
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+ ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
+ for (p = p->next; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
+ if ( dy < dymin )
+ {
+ dymin = dy;
+ ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
+ }
+ }
+
+ /* now adjust the object positions to line up this center */
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
+ gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Center selected objects to in center of label. */
+/*****************************************************************************/
+void
+gl_label_center_selection_horiz (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dx;
+ gdouble x_label_center;
+ gdouble x_obj_center;
+ glLabelRegion obj_extent;
+ gdouble w, h;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label));
+
+ gl_label_checkpoint (label, _("Center horizontally"));
+
+ begin_selection_op (label);
+
+ gl_label_get_size (label, &w, &h);
+ x_label_center = w / 2.0;
+
+ /* adjust the object positions */
+ selection_list = gl_label_get_selection_list (label);
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
+ dx = x_label_center - x_obj_center;
+ gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
+ }
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Center selected objects to in center of label. */
+/*****************************************************************************/
+void
+gl_label_center_selection_vert (glLabel *label)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+ gdouble dy;
+ gdouble y_label_center;
+ gdouble y_obj_center;
+ glLabelRegion obj_extent;
+ gdouble w, h;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_return_if_fail (!gl_label_is_selection_empty (label));
+
+ gl_label_checkpoint (label, _("Center vertically"));
+
+ begin_selection_op (label);
+
+ gl_label_get_size (label, &w, &h);
+ y_label_center = h / 2.0;
+
+ /* adjust the object positions */
+ selection_list = gl_label_get_selection_list (label);
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_get_extent (object, &obj_extent);
+ y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
+ dy = y_label_center - y_obj_center;
+ gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
+ }
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Move selected objects */
+/*****************************************************************************/
+void
+gl_label_move_selection (glLabel *label,
+ gdouble dx,
+ gdouble dy)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_object_set_position_relative (object, dx, dy, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set font family for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_font_family (glLabel *label,
+ const gchar *font_family)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_font_family (object, font_family, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set font size for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_font_size (glLabel *label,
+ gdouble font_size)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_font_size (object, font_size, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set font weight for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_font_weight (glLabel *label,
+ PangoWeight font_weight)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_font_weight (object, font_weight, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set font italic flag for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_font_italic_flag (glLabel *label,
+ gboolean font_italic_flag)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_font_italic_flag (object, font_italic_flag, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set text alignment for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_text_alignment (glLabel *label,
+ PangoAlignment text_alignment)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_text_alignment (object, text_alignment, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set text line spacing for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_text_line_spacing (glLabel *label,
+ gdouble text_line_spacing)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_text_line_spacing (object, text_line_spacing, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set text color for all text contained in selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_text_color (glLabel *label,
+ glColorNode *text_color_node)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_text_color (object, text_color_node, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set fill color for all selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_fill_color (glLabel *label,
+ glColorNode *fill_color_node)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_fill_color (object, fill_color_node, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set line color for all selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_line_color (glLabel *label,
+ glColorNode *line_color_node)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_line_color (object, line_color_node, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Set line width for all selected objects. */
+/*****************************************************************************/
+void
+gl_label_set_selection_line_width (glLabel *label,
+ gdouble line_width)
+{
+ GList *selection_list;
+ GList *p;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ begin_selection_op (label);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+ gl_label_object_set_line_width (object, line_width, TRUE);
+ }
+
+ g_list_free (selection_list);
+
+ end_selection_op (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* "Cut" selected items and place on clipboard. */
+/*****************************************************************************/
+void
+gl_label_cut_selection (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ gl_label_copy_selection (label);
+ gl_label_delete_selection (label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* "Copy" selected items to clipboard. */
+/*****************************************************************************/
+void
+gl_label_copy_selection (glLabel *label)
+{
+ GtkClipboard *clipboard;
+ GList *selection_list;
+ glLabel *label_copy;
+ GList *p;
+ glLabelObject *object;
+ glXMLLabelStatus status;
+
+ ClipboardData *data;
+
+ static GtkTargetEntry glabels_targets[] = { { "application/glabels", 0, 0 },
+ { "text/xml", 0, 0 },
+ };
+
+ GtkTargetList *target_list;
+ GtkTargetEntry *target_table;
+ gint n_targets;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ if (selection_list)
+ {
+
+ data = g_new0 (ClipboardData, 1);
+
+ target_list = gtk_target_list_new (glabels_targets, G_N_ELEMENTS(glabels_targets));
+
+ /*
+ * Serialize selection by encoding as an XML label document.
+ */
+ label_copy = GL_LABEL(gl_label_new ());
+
+ gl_label_set_template (label_copy, label->priv->template, FALSE);
+ gl_label_set_rotate_flag (label_copy, label->priv->rotate_flag, FALSE);
+
+ for (p = selection_list; p != NULL; p = p->next)
+ {
+ object = GL_LABEL_OBJECT (p->data);
+
+ gl_label_add_object (label_copy, gl_label_object_dup (object, label_copy));
+ }
+
+ data->xml_buffer = gl_xml_label_save_buffer (label_copy, &status);
+
+ g_object_unref (G_OBJECT (label_copy));
+
+
+ /*
+ * Is it an atomic text selection? If so, also make available as text.
+ */
+ if ( gl_label_is_selection_atomic (label) &&
+ GL_IS_LABEL_TEXT (selection_list->data) )
+ {
+ glLabelText *text_object = GL_LABEL_TEXT (selection_list->data);
+
+ gtk_target_list_add_text_targets (target_list, 1);
+
+ data->text = gl_label_text_get_text (text_object);
+ }
+
+
+ /*
+ * Is it an atomic image selection? If so, also make available as pixbuf.
+ */
+ if ( gl_label_is_selection_atomic (label) &&
+ GL_IS_LABEL_IMAGE (selection_list->data) )
+ {
+ glLabelImage *image_object = GL_LABEL_IMAGE (selection_list->data);
+ GdkPixbuf *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
+
+ if (pixbuf)
+ {
+ gtk_target_list_add_image_targets (target_list, 2, TRUE);
+ data->pixbuf = pixbuf;
+ }
+ }
+
+
+ target_table = gtk_target_table_new_from_list (target_list, &n_targets);
+
+ gtk_clipboard_set_with_data (clipboard,
+ target_table, n_targets,
+ (GtkClipboardGetFunc)clipboard_get_cb,
+ (GtkClipboardClearFunc)clipboard_clear_cb,
+ data);
+
+ gtk_target_table_free (target_table, n_targets);
+ gtk_target_list_unref (target_list);
+ }
+
+
+ g_list_free (selection_list);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* "Paste" from clipboard. */
+/*****************************************************************************/
+void
+gl_label_paste (glLabel *label)
+{
+ GtkClipboard *clipboard;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+ gtk_clipboard_request_targets (clipboard,
+ (GtkClipboardTargetsReceivedFunc)receive_targets_cb,
+ label);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Is there anything that can be pasted? */
+/*****************************************************************************/
+gboolean
+gl_label_can_paste (glLabel *label)
+{
+ GtkClipboard *clipboard;
+ gboolean can_flag;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+ can_flag = gtk_clipboard_wait_is_target_available (clipboard,
+ gdk_atom_intern("application/glabels", TRUE))
+ || gtk_clipboard_wait_is_text_available (clipboard)
+ || gtk_clipboard_wait_is_image_available (clipboard);
+
+ gl_debug (DEBUG_LABEL, "END");
+ return can_flag;
+}
+
+
+/****************************************************************************/
+/* Clipboard "Get" function. */
+/****************************************************************************/
+static void
+clipboard_get_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ ClipboardData *data)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ switch (info)
+ {
+
+ case 0:
+ gtk_selection_data_set (selection_data,
+ gtk_selection_data_get_target (selection_data),
+ 8,
+ (guchar *)data->xml_buffer, strlen (data->xml_buffer));
+ break;
+
+ case 1:
+ gtk_selection_data_set_text (selection_data, data->text, -1);
+ break;
+
+ case 2:
+ gtk_selection_data_set_pixbuf (selection_data, data->pixbuf);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Clipboard "Clear" function. */
+/****************************************************************************/
+static void
+clipboard_clear_cb (GtkClipboard *clipboard,
+ ClipboardData *data)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_free (data->xml_buffer);
+ g_free (data->text);
+ if (data->pixbuf)
+ {
+ g_object_unref (data->pixbuf);
+ }
+
+ g_free (data);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Deal with clipboard data. */
+/****************************************************************************/
+static void
+receive_targets_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ gint n_targets,
+ glLabel *label)
+{
+ gint i;
+
+ /*
+ * Application/glabels
+ */
+ for ( i = 0; i < n_targets; i++ )
+ {
+ if ( strcmp(gdk_atom_name(targets[i]), "application/glabels") == 0 )
+ {
+ gtk_clipboard_request_contents (clipboard,
+ gdk_atom_intern("application/glabels", TRUE),
+ (GtkClipboardReceivedFunc)paste_xml_received_cb,
+ label);
+ return;
+ }
+ }
+
+ /*
+ * Text
+ */
+ if ( gtk_targets_include_text (targets, n_targets) )
+ {
+ gtk_clipboard_request_text (clipboard,
+ (GtkClipboardTextReceivedFunc)paste_text_received_cb,
+ label);
+ return;
+ }
+
+ /*
+ * Image
+ */
+ if ( gtk_targets_include_image (targets, n_targets, TRUE) )
+ {
+ gtk_clipboard_request_image (clipboard,
+ (GtkClipboardImageReceivedFunc)paste_image_received_cb,
+ label);
+ return;
+ }
+}
+
+
+/****************************************************************************/
+/* Paste received glabels XML callback. */
+/****************************************************************************/
+static void
+paste_xml_received_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ glLabel *label)
+{
+ gchar *xml_buffer;
+ glLabel *label_copy;
+ glXMLLabelStatus status;
+ GList *p;
+ glLabelObject *object, *newobject;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_checkpoint (label, _("Paste"));
+
+ xml_buffer = (gchar *)gtk_selection_data_get_data (selection_data);
+
+ /*
+ * Deserialize XML label document and extract objects.
+ */
+ label_copy = gl_xml_label_open_buffer (xml_buffer, &status);
+ if ( label_copy )
+ {
+ gl_label_unselect_all (label);
+
+ for (p = label_copy->priv->object_list; p != NULL; p = p->next)
+ {
+ object = (glLabelObject *) p->data;
+ newobject = gl_label_object_dup (object, label);
+ gl_label_add_object( label, newobject );
+
+ gl_label_select_object (label, newobject);
+
+ gl_debug (DEBUG_LABEL, "object pasted");
+ }
+
+ g_object_unref (G_OBJECT (label_copy));
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Paste received text callback. */
+/****************************************************************************/
+static void
+paste_text_received_cb (GtkClipboard *clipboard,
+ const gchar *text,
+ glLabel *label)
+{
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_checkpoint (label, _("Paste"));
+
+ gl_label_unselect_all (label);
+
+ object = GL_LABEL_OBJECT (gl_label_text_new (label, FALSE));
+ gl_label_text_set_text (GL_LABEL_TEXT (object), text, FALSE);
+ gl_label_object_set_position (object, 18, 18, FALSE);
+
+ gl_label_select_object (label, object);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Paste received image callback. */
+/****************************************************************************/
+static void
+paste_image_received_cb (GtkClipboard *clipboard,
+ GdkPixbuf *pixbuf,
+ glLabel *label)
+{
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_checkpoint (label, _("Paste"));
+
+ gl_label_unselect_all (label);
+
+ object = GL_LABEL_OBJECT (gl_label_image_new (label, FALSE));
+ gl_label_image_set_pixbuf (GL_LABEL_IMAGE (object), pixbuf, FALSE);
+ gl_label_object_set_position (object, 18, 18, FALSE);
+
+ gl_label_select_object (label, object);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font family. */
+/****************************************************************************/
+void
+gl_label_set_default_font_family (glLabel *label,
+ const gchar *font_family)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ g_free (label->priv->default_font_family);
+ label->priv->default_font_family = g_strdup (font_family);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font size. */
+/****************************************************************************/
+void
+gl_label_set_default_font_size (glLabel *label,
+ gdouble font_size)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_font_size = font_size;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font weight. */
+/****************************************************************************/
+void
+gl_label_set_default_font_weight (glLabel *label,
+ PangoWeight font_weight)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_font_weight = font_weight;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default font italic flag. */
+/****************************************************************************/
+void
+gl_label_set_default_font_italic_flag (glLabel *label,
+ gboolean font_italic_flag)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_font_italic_flag = font_italic_flag;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default text color. */
+/****************************************************************************/
+void
+gl_label_set_default_text_color (glLabel *label,
+ guint text_color)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_text_color = text_color;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default text alignment. */
+/****************************************************************************/
+void
+gl_label_set_default_text_alignment (glLabel *label,
+ PangoAlignment text_alignment)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_text_alignment = text_alignment;
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default text line spacing. */
+/****************************************************************************/
+void
+gl_label_set_default_text_line_spacing (glLabel *label,
+ gdouble text_line_spacing)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_text_line_spacing = text_line_spacing;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default line width. */
+/****************************************************************************/
+void
+gl_label_set_default_line_width (glLabel *label,
+ gdouble line_width)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_line_width = line_width;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default line color. */
+/****************************************************************************/
+void
+gl_label_set_default_line_color (glLabel *label,
+ guint line_color)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_line_color = line_color;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Set default fill color. */
+/****************************************************************************/
+void
+gl_label_set_default_fill_color (glLabel *label,
+ guint fill_color)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ label->priv->default_fill_color = fill_color;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Get default font family. */
+/****************************************************************************/
+gchar *
+gl_label_get_default_font_family (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return g_strdup (label->priv->default_font_family);
+}
+
+
+/****************************************************************************/
+/* Get default font size. */
+/****************************************************************************/
+gdouble
+gl_label_get_default_font_size (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 12.0);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_font_size;
+}
+
+
+/****************************************************************************/
+/* Get default font weight. */
+/****************************************************************************/
+PangoWeight
+gl_label_get_default_font_weight (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_WEIGHT_NORMAL);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_font_weight;
+}
+
+
+/****************************************************************************/
+/* Get default font italic flag. */
+/****************************************************************************/
+gboolean
+gl_label_get_default_font_italic_flag (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_font_italic_flag;
+}
+
+
+/****************************************************************************/
+/* Get default text color. */
+/****************************************************************************/
+guint
+gl_label_get_default_text_color (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_text_color;
+}
+
+
+/****************************************************************************/
+/* Get default text alignment. */
+/****************************************************************************/
+PangoAlignment
+gl_label_get_default_text_alignment (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_ALIGN_LEFT);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_text_alignment;
+}
+
+
+/****************************************************************************/
+/* Get default text line spacing. */
+/****************************************************************************/
+gdouble
+gl_label_get_default_text_line_spacing (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_text_line_spacing;
+}
+
+
+/****************************************************************************/
+/* Get default line width. */
+/****************************************************************************/
+gdouble
+gl_label_get_default_line_width (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_line_width;
}
+
/****************************************************************************/
-/* return short filename. */
+/* Get default line color. */
/****************************************************************************/
-gchar *
-gl_label_get_short_name (glLabel *label)
+guint
+gl_label_get_default_line_color (glLabel *label)
{
- gl_debug (DEBUG_LABEL, "");
+ gl_debug (DEBUG_LABEL, "START");
- if ( label->priv->filename == NULL ) {
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
- if ( label->priv->untitled_instance == 0 ) {
- label->priv->untitled_instance = ++untitled;
- }
+ gl_debug (DEBUG_LABEL, "END");
- return g_strdup_printf ( "%s %d", _("Untitled"),
- label->priv->untitled_instance );
+ return label->priv->default_line_color;
+}
- } else {
- gchar *temp_name, *short_name;
- temp_name = g_path_get_basename ( label->priv->filename );
- short_name = gl_util_remove_extension (temp_name);
- g_free (temp_name);
+/****************************************************************************/
+/* Get default fill color. */
+/****************************************************************************/
+guint
+gl_label_get_default_fill_color (glLabel *label)
+{
+ gl_debug (DEBUG_LABEL, "START");
- return short_name;
+ g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
+
+ gl_debug (DEBUG_LABEL, "END");
+
+ return label->priv->default_fill_color;
+}
+
+
+/****************************************************************************/
+/* Draw label. */
+/****************************************************************************/
+void
+gl_label_draw (glLabel *label,
+ cairo_t *cr,
+ gboolean screen_flag,
+ glMergeRecord *record)
+{
+ GList *p_obj;
+ glLabelObject *object;
+
+ g_return_if_fail (label && GL_IS_LABEL (label));
+
+ for (p_obj = label->priv->object_list; p_obj != NULL; p_obj = p_obj->next)
+ {
+ object = GL_LABEL_OBJECT (p_obj->data);
+
+ gl_label_object_draw (object, cr, screen_flag, record);
}
}
+
/****************************************************************************/
-/* Get pixbuf cache. */
+/* Get object located at coordinates. */
/****************************************************************************/
-GHashTable *
-gl_label_get_pixbuf_cache (glLabel *label)
+glLabelObject *gl_label_object_at (glLabel *label,
+ cairo_t *cr,
+ gdouble x_pixels,
+ gdouble y_pixels)
{
- return label->priv->pixbuf_cache;
+ GList *p_obj;
+ glLabelObject *object;
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
+
+ for (p_obj = g_list_last (label->priv->object_list); p_obj != NULL; p_obj = p_obj->prev)
+ {
+ object = GL_LABEL_OBJECT (p_obj->data);
+
+ if (gl_label_object_is_located_at (object, cr, x_pixels, y_pixels))
+ {
+ return object;
+ }
+
+ }
+
+ return NULL;
}
+
/****************************************************************************/
-/* Is label modified? */
+/* Return handle and associated object at coordinates. */
/****************************************************************************/
-gboolean
-gl_label_is_modified (glLabel *label)
+glLabelObject *
+gl_label_get_handle_at (glLabel *label,
+ cairo_t *cr,
+ gdouble x_pixels,
+ gdouble y_pixels,
+ glLabelObjectHandle *handle)
{
- gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
- return label->priv->modified_flag;
+ GList *selection_list;
+ GList *p_obj;
+ glLabelObject *object;
+
+ g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
+
+ selection_list = gl_label_get_selection_list (label);
+
+ for (p_obj = g_list_last (selection_list); p_obj != NULL; p_obj = p_obj->prev)
+ {
+
+ object = GL_LABEL_OBJECT (p_obj->data);
+
+ if ((*handle = gl_label_object_handle_at (object, cr, x_pixels, y_pixels)))
+ {
+ g_list_free (selection_list);
+ return object;
+ }
+
+ }
+
+ g_list_free (selection_list);
+
+ *handle = GL_LABEL_OBJECT_HANDLE_NONE;
+ return NULL;
}
+
/****************************************************************************/
-/* Is label untitled? */
+/* Checkpoint state. */
/****************************************************************************/
-gboolean
-gl_label_is_untitled (glLabel *label)
+void
+gl_label_checkpoint (glLabel *this,
+ const gchar *description)
{
- gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
- return (label->priv->filename == NULL);
+ State *state;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ /*
+ * Do not perform consecutive checkpoints that are identical.
+ * E.g. moving an object by dragging, would produce a large number
+ * of incremental checkpoints -- what we really want is a single
+ * checkpoint so that we can undo the entire dragging effort with
+ * one "undo"
+ */
+ if ( this->priv->cp_cleared_flag
+ || (this->priv->cp_desc == NULL)
+ || (strcmp (description, this->priv->cp_desc) != 0) )
+ {
+
+ /* Sever old redo "thread" */
+ stack_clear (this->priv->redo_stack);
+
+ /* Save state onto undo stack. */
+ state = state_new (this, description);
+ stack_push_state (this->priv->undo_stack, state);
+
+ /* Track consecutive checkpoints. */
+ this->priv->cp_cleared_flag = FALSE;
+ this->priv->cp_desc = g_strdup (description);
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Undo. */
+/****************************************************************************/
+void
+gl_label_undo (glLabel *this)
+{
+ State *state_old;
+ State *state_now;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ state_old = stack_pop_state (this->priv->undo_stack);
+ state_now = state_new (this, state_old->description);
+
+ stack_push_state (this->priv->redo_stack, state_now);
+
+ state_restore (state_old, this);
+ state_free (state_old);
+
+ this->priv->cp_cleared_flag = TRUE;
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Redo. */
+/****************************************************************************/
+void
+gl_label_redo (glLabel *this)
+{
+ State *state_old;
+ State *state_now;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ state_old = stack_pop_state (this->priv->redo_stack);
+ state_now = state_new (this, state_old->description);
+
+ stack_push_state (this->priv->undo_stack, state_now);
+
+ state_restore (state_old, this);
+ state_free (state_old);
+
+ this->priv->cp_cleared_flag = TRUE;
+
+ gl_debug (DEBUG_LABEL, "END");
}
+
/****************************************************************************/
/* Can undo? */
/****************************************************************************/
gboolean
-gl_label_can_undo (glLabel *label)
+gl_label_can_undo (glLabel *this)
{
- return FALSE;
+ return (!g_queue_is_empty (this->priv->undo_stack));
}
/* Can redo? */
/****************************************************************************/
gboolean
-gl_label_can_redo (glLabel *label)
+gl_label_can_redo (glLabel *this)
{
- return FALSE;
+ return (!g_queue_is_empty (this->priv->redo_stack));
}
/****************************************************************************/
-/* Set filename. */
+/* Get undo description string. */
/****************************************************************************/
-void
-gl_label_set_filename (glLabel *label,
- const gchar *filename)
+gchar *
+gl_label_get_undo_description (glLabel *this)
{
- label->priv->filename = g_strdup (filename);
+ State *state;
+ gchar *description;
- g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
+ state = g_queue_peek_head (this->priv->undo_stack);
+ if ( state )
+ {
+ description = g_strdup (state->description);
+ }
+ else
+ {
+ description = g_strdup ("");
+ }
+
+ return description;
}
+
/****************************************************************************/
-/* Clear modified flag. */
+/* Get redo description string. */
/****************************************************************************/
-void
-gl_label_clear_modified (glLabel *label)
+gchar *
+gl_label_get_redo_description (glLabel *this)
{
+ State *state;
+ gchar *description;
+
+ state = g_queue_peek_head (this->priv->redo_stack);
+ if ( state )
+ {
+ description = g_strdup (state->description);
+ }
+ else
+ {
+ description = g_strdup ("");
+ }
- if ( label->priv->modified_flag ) {
+ return description;
+}
- label->priv->modified_flag = FALSE;
- g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
- }
+/****************************************************************************/
+/* Clear undo or redo stack. */
+/****************************************************************************/
+static void
+stack_clear (GQueue *stack)
+{
+ State *state;
+
+ gl_debug (DEBUG_LABEL, "START");
+ while ( (state = g_queue_pop_head (stack)) != NULL )
+ {
+ state_free (state);
+ }
+
+ gl_debug (DEBUG_LABEL, "END");
}
/****************************************************************************/
-/* Set compression level. */
+/* Push state onto stack. */
/****************************************************************************/
-void
-gl_label_set_compression (glLabel *label,
- gint compression)
+static void
+stack_push_state (GQueue *stack,
+ State *state)
{
- gl_debug (DEBUG_LABEL, "set %d", compression);
+ gl_debug (DEBUG_LABEL, "START");
- /* Older versions of libxml2 always return a -1 for documents "read in," so
- * default to 9. Also, default to 9 for anything else out of range. */
- if ((compression < 0) || (compression >9)) {
- compression = 9;
- }
+ g_queue_push_head( stack, state );
- gl_debug (DEBUG_LABEL, "actual set %d", compression);
- label->priv->compression = compression;
+ gl_debug (DEBUG_LABEL, "END");
}
/****************************************************************************/
-/* Get compression level. */
+/* Pop state from stack. */
/****************************************************************************/
-gint
-gl_label_get_compression (glLabel *label)
+static State *
+stack_pop_state (GQueue *stack)
{
- gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
- return label->priv->compression;
+ State *state;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ state = g_queue_pop_head (stack);
+
+ gl_debug (DEBUG_LABEL, "END");
+ return state;
}
/****************************************************************************/
-/* Draw label. */
+/* New state from label. */
/****************************************************************************/
-void
-gl_label_draw (glLabel *label,
- cairo_t *cr,
- gboolean screen_flag,
- glMergeRecord *record)
+static State *
+state_new (glLabel *this,
+ const gchar *description)
{
- GList *p_obj;
- glLabelObject *object;
+ State *state;
+ GList *p_obj;
+ glLabelObject *object;
- g_return_if_fail (label && GL_IS_LABEL (label));
+ gl_debug (DEBUG_LABEL, "START");
+
+ state = g_new0 (State, 1);
+
+ state->description = g_strdup (description);
+
+ state->template = lgl_template_dup (this->priv->template);
+ state->rotate_flag = this->priv->rotate_flag;
- for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
+ for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_obj->next )
{
- object = GL_LABEL_OBJECT (p_obj->data);
+ object = GL_LABEL_OBJECT (p_obj->data);
- gl_label_object_draw (object, cr, screen_flag, record);
- }
+ state->object_list = g_list_append (state->object_list,
+ gl_label_object_dup (object, this));
+ }
+
+ state->merge = gl_merge_dup (this->priv->merge);
+
+ state->modified_flag = this->priv->modified_flag;
+ state->time_stamp = this->priv->time_stamp;
+
+
+ gl_debug (DEBUG_LABEL, "END");
+ return state;
+}
+
+
+/****************************************************************************/
+/* Restore label from saved state. */
+/****************************************************************************/
+static void
+state_free (State *state)
+{
+ GList *p_obj;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ g_free (state->description);
+
+ lgl_template_free (state->template);
+ if ( state->merge )
+ {
+ g_object_unref (G_OBJECT (state->merge));
+ }
+
+ for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
+ {
+ g_object_unref (G_OBJECT (p_obj->data));
+ }
+ g_list_free (state->object_list);
+
+ g_free (state);
+
+ gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/****************************************************************************/
+/* Restore label from saved state. */
+/****************************************************************************/
+static void
+state_restore (State *state,
+ glLabel *this)
+
+{
+ GList *p_obj, *p_next;
+ glLabelObject *object;
+
+ gl_debug (DEBUG_LABEL, "START");
+
+ gl_label_set_rotate_flag (this, state->rotate_flag, FALSE);
+ gl_label_set_template (this, state->template, FALSE);
+
+ for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_next )
+ {
+ p_next = p_obj->next; /* Hold on to next; delete is destructive */
+ object = GL_LABEL_OBJECT (p_obj->data);
+
+ gl_label_delete_object (this, object);
+ }
+
+ for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
+ {
+ object = GL_LABEL_OBJECT (p_obj->data);
+
+ gl_label_add_object (this, gl_label_object_dup (object, this));
+ }
+ g_signal_emit (G_OBJECT(this), signals[SELECTION_CHANGED], 0);
+
+ gl_label_set_merge (this, state->merge, FALSE);
+
+
+ if ( !state->modified_flag &&
+ (state->time_stamp.tv_sec == this->priv->time_stamp.tv_sec) &&
+ (state->time_stamp.tv_usec == this->priv->time_stamp.tv_usec) )
+ {
+ gl_label_clear_modified (this);
+ }
+
+ 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
+ */