[gthumb/ext] added a tags entry widget to simplify tags editing



commit 8d2780fdb97fe0a43adf5c87311707570f784605
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Fri Aug 21 00:44:32 2009 +0200

    added a tags entry widget to simplify tags editing

 extensions/comments/data/ui/edit-comment-page.ui   |   14 +-
 extensions/comments/gth-edit-comment-page.c        |   22 +-
 .../photo_importer/data/ui/photo-importer.ui       |   12 +-
 extensions/photo_importer/dlg-photo-importer.c     |    8 +-
 gthumb/Makefile.am                                 |    2 +
 gthumb/gth-tags-entry.c                            |  383 ++++++++++++++++++++
 gthumb/gth-tags-entry.h                            |   56 +++
 7 files changed, 472 insertions(+), 25 deletions(-)
---
diff --git a/extensions/comments/data/ui/edit-comment-page.ui b/extensions/comments/data/ui/edit-comment-page.ui
index e1a2c72..0a68fa6 100644
--- a/extensions/comments/data/ui/edit-comment-page.ui
+++ b/extensions/comments/data/ui/edit-comment-page.ui
@@ -119,15 +119,11 @@
       </packing>
     </child>
     <child>
-      <placeholder/>
-    </child>
-    <child>
       <object class="GtkLabel" id="label1">
         <property name="visible">True</property>
         <property name="xalign">0</property>
         <property name="label" translatable="yes">_Tags:</property>
         <property name="use_underline">True</property>
-        <property name="mnemonic_widget">tags_entry</property>
       </object>
       <packing>
         <property name="top_attach">4</property>
@@ -135,10 +131,14 @@
       </packing>
     </child>
     <child>
-      <object class="GtkEntry" id="tags_entry">
+      <placeholder/>
+    </child>
+    <child>
+      <object class="GtkHBox" id="tags_entry_container">
         <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="invisible_char">&#x25CF;</property>
+        <child>
+          <placeholder/>
+        </child>
       </object>
       <packing>
         <property name="left_attach">1</property>
diff --git a/extensions/comments/gth-edit-comment-page.c b/extensions/comments/gth-edit-comment-page.c
index 5afa8d4..63f3174 100644
--- a/extensions/comments/gth-edit-comment-page.c
+++ b/extensions/comments/gth-edit-comment-page.c
@@ -49,6 +49,7 @@ struct _GthEditCommentPagePrivate {
 	GtkBuilder  *builder;
 	GtkWidget   *date_combobox;
 	GtkWidget   *date_datetime;
+	GtkWidget   *tags_entry;
 };
 
 
@@ -101,12 +102,12 @@ gth_edit_comment_page_real_set_file (GthEditMetadataPage *base,
 		char *value;
 
 		value = gth_string_list_join (tags, ", ");
-		gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("tags_entry")), value);
+		gtk_entry_set_text (GTK_ENTRY (self->priv->tags_entry), value);
 
 		g_free (value);
 	}
 	else
-		gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("tags_entry")), "");
+		gtk_entry_set_text (GTK_ENTRY (self->priv->tags_entry), "");
 
 	gtk_widget_grab_focus (GET_WIDGET ("note_text"));
 }
@@ -137,15 +138,10 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
 	g_file_info_set_attribute_string (self->priv->file_data->info, "comment::place", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))));
 	g_file_info_set_attribute_string (self->priv->file_data->info, "comment::time", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)));
 
-	tagv = g_strsplit (gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("tags_entry"))), ",", -1);
+	tagv = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (self->priv->tags_entry));
 	tags = NULL;
-	for (i = 0; tagv[i] != NULL; i++) {
-		char *tag;
-
-		tag = g_strstrip (tagv[i]);
-		if (tag[0] != '\0')
-			tags = g_list_prepend (tags, g_strdup (tag));
-	}
+	for (i = 0; tagv[i] != NULL; i++)
+		tags = g_list_prepend (tags, tagv[i]);
 	tags = g_list_reverse (tags);
 	string_list = gth_string_list_new (tags);
 	g_file_info_set_attribute_object (self->priv->file_data->info, "comment::categories", G_OBJECT (string_list));
@@ -153,7 +149,7 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
 
 	g_object_unref (string_list);
 	g_strfreev (tagv);
-	_g_string_list_free (tags);
+	g_list_free (tags);
 }
 
 
@@ -280,6 +276,10 @@ gth_edit_comment_page_init (GthEditCommentPage *self)
   	self->priv->date_datetime = gtk_entry_new ();
   	gtk_widget_show (self->priv->date_datetime);
   	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_datetime_container")), self->priv->date_datetime, FALSE, FALSE, 0);
+
+  	self->priv->tags_entry = gth_tags_entry_new (NULL);
+  	gtk_widget_show (self->priv->tags_entry);
+  	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("tags_entry_container")), self->priv->tags_entry, TRUE, TRUE, 0);
 }
 
 
diff --git a/extensions/photo_importer/data/ui/photo-importer.ui b/extensions/photo_importer/data/ui/photo-importer.ui
index a12c02d..16e7bb8 100644
--- a/extensions/photo_importer/data/ui/photo-importer.ui
+++ b/extensions/photo_importer/data/ui/photo-importer.ui
@@ -177,22 +177,22 @@
                 <property name="column_spacing">6</property>
                 <property name="row_spacing">5</property>
                 <child>
-                  <object class="GtkLabel" id="label5">
+                  <object class="GtkLabel" id="tags_label">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
                     <property name="label" translatable="yes">_Tags:</property>
                     <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">tags_entry</property>
                   </object>
                   <packing>
                     <property name="x_options">GTK_FILL</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkEntry" id="tags_entry">
+                  <object class="GtkHBox" id="tags_entry_box">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">&#x25CF;</property>
+                    <child>
+                      <placeholder/>
+                    </child>
                   </object>
                   <packing>
                     <property name="left_attach">1</property>
@@ -370,8 +370,8 @@
                             <child>
                               <object class="GtkFileChooserButton" id="destination_filechooserbutton">
                                 <property name="visible">True</property>
-                                <property name="action">select-folder</property>
                                 <property name="local_only">False</property>
+                                <property name="action">select-folder</property>
                               </object>
                               <packing>
                                 <property name="position">0</property>
diff --git a/extensions/photo_importer/dlg-photo-importer.c b/extensions/photo_importer/dlg-photo-importer.c
index 3f71c54..bdc1f8a 100644
--- a/extensions/photo_importer/dlg-photo-importer.c
+++ b/extensions/photo_importer/dlg-photo-importer.c
@@ -58,6 +58,7 @@ typedef struct {
 	gboolean       cancelling;
 	gulong         monitor_event;
 	GtkWidget     *filter_combobox;
+	GtkWidget     *tags_entry;
 	GList         *general_tests;
 } DialogData;
 
@@ -104,7 +105,7 @@ destroy_dialog (gpointer user_data)
 
 		file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (data->file_list))));
 		files = gth_file_store_get_checked (file_store);
-		tags = g_strsplit (gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("tags_entry"))), " ", -1);
+		tags = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (data->tags_entry));
 		task = gth_import_task_new (data->browser,
 					    files,
 					    destination,
@@ -706,6 +707,11 @@ dlg_photo_importer (GthBrowser *browser,
 		g_free (last_destination);
 	}
 
+	data->tags_entry = gth_tags_entry_new (NULL);
+	gtk_widget_show (data->tags_entry);
+	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("tags_entry_box")), data->tags_entry, TRUE, TRUE, 0);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("tags_label")), data->tags_entry);
+
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("delete_checkbutton")), eel_gconf_get_boolean (PREF_PHOTO_IMPORT_DELETE, FALSE));
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("adjust_orientation_checkbutton")), eel_gconf_get_boolean (PREF_PHOTO_IMPORT_ADJUST_ORIENTATION, TRUE));
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("single_subfolder_checkbutton")), eel_gconf_get_boolean (PREF_PHOTO_IMPORT_SUBFOLDER_SINGLE, FALSE));
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 23f7437..057b014 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -79,6 +79,7 @@ PUBLIC_HEADER_FILES = 					\
 	gth-source-tree.h				\
 	gth-stock.h					\
 	gth-string-list.h				\
+	gth-tags-entry.h				\
 	gth-task.h					\
 	gth-test.h					\
 	gth-test-chain.h				\
@@ -187,6 +188,7 @@ gthumb_SOURCES = 					\
 	gth-source-tree.c				\
 	gth-statusbar.c					\
 	gth-string-list.c				\
+	gth-tags-entry.c				\
 	gth-task.c					\
 	gth-test.c					\
 	gth-test-chain.c				\
diff --git a/gthumb/gth-tags-entry.c b/gthumb/gth-tags-entry.c
new file mode 100644
index 0000000..d316bc2
--- /dev/null
+++ b/gthumb/gth-tags-entry.c
@@ -0,0 +1,383 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include "gth-tags-entry.h"
+
+
+enum {
+	NAME_COLUMN,
+	N_COLUMNS
+};
+
+enum  {
+	PROP_0,
+	PROP_TAGS
+};
+
+
+struct _GthTagsEntryPrivate {
+	char               **tags;
+	GtkEntryCompletion  *completion;
+	GtkListStore        *store;
+	char                *new_tag;
+	gboolean             action_create;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_tags_entry_get_property (GObject    *object,
+			     guint       property_id,
+			     GValue     *value,
+			     GParamSpec *pspec)
+{
+	GthTagsEntry *self;
+
+	self = GTH_TAGS_ENTRY (object);
+
+	switch (property_id) {
+	case PROP_TAGS:
+		g_value_set_boxed (value, self->priv->tags);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void
+gth_tags_entry_set_property (GObject      *object,
+			     guint         property_id,
+			     const GValue *value,
+			     GParamSpec   *pspec)
+{
+	GthTagsEntry *self;
+
+	self = GTH_TAGS_ENTRY (object);
+
+	switch (property_id) {
+	case PROP_TAGS:
+		self->priv->tags = g_strdupv (g_value_get_boxed (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void
+gth_tags_entry_finalize (GObject *obj)
+{
+	GthTagsEntry *self;
+
+	self = GTH_TAGS_ENTRY (obj);
+
+	g_free (self->priv->new_tag);
+	g_object_unref (self->priv->completion);
+
+	G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+
+static void
+gth_tags_entry_class_init (GthTagsEntryClass *klass)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthTagsEntryPrivate));
+
+	object_class = (GObjectClass*) (klass);
+	object_class->get_property = gth_tags_entry_get_property;
+	object_class->set_property = gth_tags_entry_set_property;
+	object_class->finalize = gth_tags_entry_finalize;
+
+	g_object_class_install_property (object_class,
+					 PROP_TAGS,
+					 g_param_spec_boxed ("tags",
+							     "Tags",
+							     "List of tags",
+							     G_TYPE_STRV,
+							     G_PARAM_READWRITE));
+}
+
+
+static void
+get_tag_limits (GthTagsEntry  *self,
+		const char   **tag_start_p,
+		const char   **tag_end_p)
+{
+	const char *text;
+	const char *cursor_start;
+	const char *tag_start;
+	const char *tag_end;
+	const char *tmp_tag_end;
+
+	text = gtk_entry_get_text (GTK_ENTRY (self));
+	cursor_start = g_utf8_offset_to_pointer (text, gtk_editable_get_position (GTK_EDITABLE (self)));
+
+	if (g_utf8_get_char (cursor_start) == ',') {
+		if (cursor_start != tag_end)
+			tag_start = g_utf8_next_char (cursor_start);
+		else
+			tag_start = tag_end;
+	}
+	else {
+		tag_start = g_utf8_strrchr (text, (gssize)(cursor_start - text), ',');
+		if (tag_start == NULL)
+			tag_start = text;
+		else
+			tag_start = g_utf8_next_char (tag_start);
+	}
+
+	tag_end = g_utf8_strchr (tag_start, -1, ',');
+	if (tag_end == NULL)
+		tag_end = text + strlen (text);
+
+	while ((tag_start != tag_end) && g_unichar_isspace (g_utf8_get_char (tag_start)))
+		tag_start = g_utf8_next_char (tag_start);
+
+	tmp_tag_end = g_utf8_strrchr (tag_start, tag_end - tag_start, ' ');
+	if (tmp_tag_end != NULL)
+		tag_end = tmp_tag_end;
+
+	*tag_start_p = tag_start;
+	*tag_end_p = tag_end;
+}
+
+
+static void
+text_changed_cb (GthTagsEntry *self)
+{
+	const char *tag_start;
+	const char *tag_end;
+
+	if (self->priv->action_create) {
+		gtk_entry_completion_delete_action (self->priv->completion, 0);
+		g_free (self->priv->new_tag);
+		self->priv->new_tag = NULL;
+		self->priv->action_create = FALSE;
+	}
+
+	get_tag_limits (self, &tag_start, &tag_end);
+	if (tag_start == tag_end)
+		return;
+
+	self->priv->new_tag = g_strndup (tag_start, tag_end - tag_start);
+	self->priv->new_tag = g_strstrip (self->priv->new_tag);
+	if (self->priv->new_tag[0] != '\0') {
+		char *action_text;
+
+		/* â??%sâ?? */
+		action_text = g_strdup_printf (_("Create tag «%s»"), self->priv->new_tag);
+		gtk_entry_completion_insert_action_text (self->priv->completion, 0, action_text);
+		self->priv->action_create = TRUE;
+
+		g_free (action_text);
+	}
+}
+
+
+static gboolean
+match_func (GtkEntryCompletion *completion,
+            const char         *key,
+            GtkTreeIter        *iter,
+            gpointer            user_data)
+{
+	GthTagsEntry *self = user_data;
+	char         *name;
+	char         *k1;
+	char         *k2;
+	gboolean      result;
+
+	if (self->priv->new_tag == NULL)
+		return TRUE;
+
+	if (self->priv->new_tag[0] == '\0')
+		return TRUE;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (self->priv->store), iter,
+			    NAME_COLUMN, &name,
+			    -1);
+	k1 = g_utf8_casefold (self->priv->new_tag, -1);
+	k2 = g_utf8_casefold (name, strlen (self->priv->new_tag));
+
+	result = g_utf8_collate (k1, k2) == 0;
+
+	g_free (k2);
+	g_free (k1);
+	g_free (name);
+
+	return result;
+}
+
+
+static gboolean
+completion_match_selected_cb (GtkEntryCompletion *widget,
+                              GtkTreeModel       *model,
+                              GtkTreeIter        *iter,
+                              gpointer            user_data)
+{
+	GthTagsEntry *self = user_data;
+	const char   *tag_start;
+	const char   *tag_end;
+	const char   *text;
+	char         *head;
+	const char   *tail;
+	char         *tag_name = NULL;
+	char         *new_text;
+
+	get_tag_limits (self, &tag_start, &tag_end);
+	text = gtk_entry_get_text (GTK_ENTRY (self));
+	head = g_strndup (text, tag_start - text);
+	head = g_strstrip (head);
+	if (tag_end[0] != '\0')
+		tail = g_utf8_next_char (tag_end);
+	else
+		tail = tag_end;
+	gtk_tree_model_get (model, iter,
+			    NAME_COLUMN, &tag_name,
+			    -1);
+	new_text = g_strconcat (head,
+				" ",
+				tag_name,
+				(tail != tag_end ? ", " : ""),
+				tail,
+				NULL);
+
+	gtk_entry_set_text (GTK_ENTRY (self), new_text);
+	gtk_editable_set_position (GTK_EDITABLE (self), -1);
+
+	g_free (new_text);
+	g_free (tag_name);
+	g_free (head);
+
+	return TRUE;
+}
+
+
+static void
+gth_tags_entry_instance_init (GthTagsEntry *self)
+{
+
+
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_TAGS_ENTRY, GthTagsEntryPrivate);
+	self->priv->completion = gtk_entry_completion_new ();
+	gtk_entry_completion_set_popup_completion (self->priv->completion, TRUE);
+	gtk_entry_set_completion (GTK_ENTRY (self), self->priv->completion);
+	self->priv->store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING);
+	gtk_entry_completion_set_model (self->priv->completion, GTK_TREE_MODEL (self->priv->store));
+	g_object_unref (self->priv->store);
+	gtk_entry_completion_set_text_column (self->priv->completion, NAME_COLUMN);
+	gtk_entry_completion_set_match_func (self->priv->completion, match_func, self, NULL);
+
+	{
+		char *default_tags[] = { N_("Holidays"),
+                                      N_("Temporary"),
+                                      N_("Screenshots"),
+                                      N_("Science"),
+                                      N_("Favorite"),
+                                      N_("Important"),
+                                      N_("GNOME"),
+                                      N_("Games"),
+                                      N_("Party"),
+                                      N_("Birthday"),
+                                      N_("Astronomy"),
+                                      N_("Family"),
+                                      NULL };
+		int i;
+
+		for (i = 0; default_tags[i] != NULL; i++) {
+			GtkTreeIter iter;
+
+			gtk_list_store_append (self->priv->store, &iter);
+			gtk_list_store_set (self->priv->store, &iter,
+					    NAME_COLUMN, _(default_tags[i]),
+					    -1);
+		}
+	}
+
+	g_signal_connect (self, "notify::text", G_CALLBACK (text_changed_cb), self);
+	g_signal_connect (self->priv->completion, "match-selected", G_CALLBACK (completion_match_selected_cb), self);
+}
+
+
+GType
+gth_tags_entry_get_type (void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthTagsEntryClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_tags_entry_class_init,
+			NULL,
+			NULL,
+			sizeof (GthTagsEntry),
+			0,
+			(GInstanceInitFunc) gth_tags_entry_instance_init,
+			NULL
+		};
+		type = g_type_register_static (GTK_TYPE_ENTRY,
+					       "GthTagsEntry",
+					       &g_define_type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GtkWidget *
+gth_tags_entry_new (char **tags)
+{
+	return g_object_new (GTH_TYPE_TAGS_ENTRY, "tags", tags, NULL);
+}
+
+
+char **
+gth_tags_entry_get_tags (GthTagsEntry *self)
+{
+	char **all_tags;
+	char **tags;
+	int    i;
+	int    j;
+
+	all_tags = g_strsplit (gtk_entry_get_text (GTK_ENTRY (self)), ",", -1);
+	tags = g_new0 (char *, g_strv_length (all_tags) + 1);
+	for (i = 0, j = 0; all_tags[i] != NULL; i++) {
+		all_tags[i] = g_strstrip (all_tags[i]);
+		if (all_tags[i][0] != '\0')
+			tags[j++] = g_strdup (all_tags[i]);
+	}
+	g_strfreev (all_tags);
+
+	return tags;
+}
diff --git a/gthumb/gth-tags-entry.h b/gthumb/gth-tags-entry.h
new file mode 100644
index 0000000..3023f1f
--- /dev/null
+++ b/gthumb/gth-tags-entry.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_TAGS_ENTRY_H
+#define GTH_TAGS_ENTRY_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_TAGS_ENTRY            (gth_tags_entry_get_type ())
+#define GTH_TAGS_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_TAGS_ENTRY, GthTagsEntry))
+#define GTH_TAGS_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_TAGS_ENTRY, GthTagsEntryClass))
+#define GTH_IS_TAGS_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_TAGS_ENTRY))
+#define GTH_IS_TAGS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_TAGS_ENTRY))
+#define GTH_TAGS_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_TAGS_ENTRY, GthTagsEntryClass))
+
+typedef struct _GthTagsEntry GthTagsEntry;
+typedef struct _GthTagsEntryClass GthTagsEntryClass;
+typedef struct _GthTagsEntryPrivate GthTagsEntryPrivate;
+
+struct _GthTagsEntry {
+	GtkEntry parent_instance;
+	GthTagsEntryPrivate *priv;
+};
+
+struct _GthTagsEntryClass {
+	GtkEntryClass parent_class;
+};
+
+GType        gth_tags_entry_get_type  (void);
+GtkWidget *  gth_tags_entry_new       (char         **tags);
+char **      gth_tags_entry_get_tags  (GthTagsEntry  *self);
+
+G_END_DECLS
+
+#endif /* GTH_TAGS_ENTRY_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]