[glade] Bug 351645 - Added GladeEPropEnumInt
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glade] Bug 351645 - Added GladeEPropEnumInt
- Date: Sat, 29 Oct 2016 13:23:15 +0000 (UTC)
commit 598a6f98a716b27050ae7118f11736571e5891f9
Author: Tristan Van Berkom <tristan vanberkom codethink co uk>
Date: Sat Oct 29 22:15:58 2016 +0900
Bug 351645 - Added GladeEPropEnumInt
An enhanced enum integer editor based on patch contributed by Lukas K <lu 0x83 eu>
plugins/gtk+/Makefile.am | 2 +
plugins/gtk+/glade-eprop-enum-int.c | 443 +++++++++++++++++++++++++++++++++++
plugins/gtk+/glade-eprop-enum-int.h | 31 +++
3 files changed, 476 insertions(+), 0 deletions(-)
---
diff --git a/plugins/gtk+/Makefile.am b/plugins/gtk+/Makefile.am
index 4390c7e..a134771 100644
--- a/plugins/gtk+/Makefile.am
+++ b/plugins/gtk+/Makefile.am
@@ -160,6 +160,7 @@ libgladegtk_la_SOURCES = \
glade-stack-switcher-editor.c \
glade-store-editor.c \
glade-string-list.c \
+ glade-eprop-enum-int.c \
glade-text-view-editor.c \
glade-tool-button-editor.c \
glade-tool-item-group-editor.c \
@@ -243,6 +244,7 @@ noinst_HEADERS = \
glade-stack-switcher-editor.h \
glade-store-editor.h \
glade-string-list.h \
+ glade-eprop-enum-int.h \
glade-text-view-editor.h \
glade-tool-button-editor.h \
glade-tool-item-group-editor.h \
diff --git a/plugins/gtk+/glade-eprop-enum-int.c b/plugins/gtk+/glade-eprop-enum-int.c
new file mode 100644
index 0000000..e7bb65d
--- /dev/null
+++ b/plugins/gtk+/glade-eprop-enum-int.c
@@ -0,0 +1,443 @@
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include <gladeui/glade.h>
+#include <glib/gi18n-lib.h>
+
+#include "glade-eprop-enum-int.h"
+
+/* GObjectClass */
+static void glade_eprop_enum_int_init (GladeEPropEnumInt *eprop);
+static void glade_eprop_enum_int_class_init (GladeEPropEnumIntClass *klass);
+static void glade_eprop_enum_int_finalize (GObject *object);
+static void glade_eprop_enum_int_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+/* GladeEditorPropertyClass */
+static void glade_eprop_enum_int_load (GladeEditorProperty *eprop, GladeProperty *property);
+static GtkWidget * glade_eprop_enum_int_create_input (GladeEditorProperty *eprop);
+
+typedef struct
+{
+ GType type;
+ GtkWidget *combo_box;
+ GtkWidget *entry;
+
+ guint focus_out_idle;
+} GladeEPropEnumIntPrivate;
+
+enum {
+ PROP_0,
+ PROP_TYPE
+};
+
+enum {
+ COLUMN_ENUM_TEXT,
+ COLUMN_VALUE_INT,
+ N_COLUMNS
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GladeEPropEnumInt,
+ glade_eprop_enum_int,
+ GLADE_TYPE_EDITOR_PROPERTY);
+
+static void
+glade_eprop_enum_int_init (GladeEPropEnumInt *eprop)
+{
+
+}
+
+static void
+glade_eprop_enum_int_class_init (GladeEPropEnumIntClass *klass)
+{
+ GladeEditorPropertyClass *eprop_class = GLADE_EDITOR_PROPERTY_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ eprop_class->load = glade_eprop_enum_int_load;
+ eprop_class->create_input = glade_eprop_enum_int_create_input;
+
+ object_class->finalize = glade_eprop_enum_int_finalize;
+ object_class->set_property = glade_eprop_enum_int_set_property;
+
+ g_object_class_install_property
+ (object_class, PROP_TYPE,
+ g_param_spec_gtype ("type", _("Type"),
+ _("Type"),
+ G_TYPE_NONE, G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+glade_eprop_enum_int_load (GladeEditorProperty *eprop, GladeProperty *property)
+{
+ GladeEPropEnumInt *eprop_enum = GLADE_EPROP_ENUM_INT (eprop);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+
+ /* Chain up first */
+ GLADE_EDITOR_PROPERTY_CLASS (glade_eprop_enum_int_parent_class)->load (eprop, property);
+
+ if (property)
+ {
+ GEnumClass *enum_class;
+ gint value;
+ guint i;
+ gboolean found = FALSE;
+
+ enum_class = g_type_class_ref (priv->type);
+ value = g_value_get_int (glade_property_inline_value (property));
+
+ /*
+ * If we find the value in our enum, then set the active item, otherwise
+ * set the entry text
+ */
+ for (i = 0; i < enum_class->n_values; i++)
+ {
+ if (enum_class->values[i].value == value)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo_box), i);
+ }
+ else
+ {
+ gchar *text = g_strdup_printf ("%d", value);
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
+ g_free (text);
+ }
+
+ g_type_class_unref (enum_class);
+ }
+}
+
+
+static const gchar *
+string_from_value (GType etype, gint val)
+{
+ GEnumClass *eclass;
+ const gchar *string = NULL;
+ guint i;
+
+ g_return_val_if_fail ((eclass = g_type_class_ref (etype)) != NULL, NULL);
+ for (i = 0; i < eclass->n_values; i++)
+ {
+ if (val == eclass->values[i].value)
+ {
+ if (glade_type_has_displayable_values (etype))
+ {
+ if (!glade_displayable_value_is_disabled (etype, eclass->values[i].value_nick))
+ string = glade_get_displayable_value (etype, eclass->values[i].value_nick);
+ }
+ else
+ {
+ string = eclass->values[i].value_nick;
+ }
+
+ break;
+ }
+ }
+ g_type_class_unref (eclass);
+
+ return string;
+}
+
+static gboolean
+value_from_string (GType etype, const gchar *string, gint *value)
+{
+ GEnumClass *eclass;
+ GEnumValue *ev;
+ gchar *endptr;
+ gint val = 0;
+ gboolean found = FALSE;
+
+ /* Try a number first */
+ val = strtoul (string, &endptr, 0);
+ if (endptr != string)
+ found = TRUE;
+
+ if (!found)
+ {
+ eclass = g_type_class_ref (etype);
+ ev = g_enum_get_value_by_name (eclass, string);
+ if (!ev)
+ ev = g_enum_get_value_by_nick (eclass, string);
+
+ if (ev)
+ {
+ val = ev->value;
+ found = TRUE;
+ }
+
+ if (!found && string && string[0])
+ {
+ /* Try Displayables */
+ string = glade_get_value_from_displayable (etype, string);
+ if (string)
+ {
+ ev = g_enum_get_value_by_name (eclass, string);
+ if (!ev)
+ ev = g_enum_get_value_by_nick (eclass, string);
+
+ if (ev)
+ {
+ val = ev->value;
+ found = TRUE;
+ }
+ }
+ }
+
+ g_type_class_unref (eclass);
+ }
+
+ if (found)
+ *value = val;
+
+ return found;
+}
+
+static void
+glade_eprop_enum_int_changed_combo (GtkWidget *combo_box, GladeEditorProperty *eprop)
+{
+ GladeEPropEnumInt *eprop_enum = GLADE_EPROP_ENUM_INT (eprop);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+ gint ival;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GValue val = { 0, };
+ gboolean error = FALSE;
+
+ if (glade_editor_property_loading (eprop))
+ return;
+
+ tree_model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter))
+ {
+ gtk_tree_model_get (tree_model, &iter,
+ COLUMN_VALUE_INT, &ival,
+ -1);
+ }
+ else
+ {
+ const char *text = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+
+ if (!value_from_string (priv->type, text, &ival))
+ error = TRUE;
+ }
+
+ if (error)
+ {
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry), GTK_ENTRY_ICON_SECONDARY,
"dialog-warning-symbolic");
+ }
+ else
+ {
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry), GTK_ENTRY_ICON_SECONDARY, NULL);
+ }
+
+ if (!error)
+ {
+ g_value_init (&val, G_TYPE_INT);
+ g_value_set_int (&val, ival);
+
+ glade_editor_property_commit_no_callback (eprop, &val);
+ g_value_unset (&val);
+ }
+}
+
+static gchar *
+glade_eprop_enum_int_format_entry_cb (GtkComboBox *combo,
+ const gchar *path,
+ GladeEPropEnumInt *eprop_enum)
+{
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gint value;
+ const char *text;
+ gchar *endptr;
+ gboolean is_number = FALSE;
+
+ model = gtk_combo_box_get_model (combo);
+
+ /* Check if we currently have a number in the entry */
+ text = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+ value = strtoul (text, &endptr, 0);
+ if (endptr != text)
+ is_number = TRUE;
+
+ /* Get the selected value */
+ gtk_tree_model_get_iter_from_string (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COLUMN_VALUE_INT, &value,
+ -1);
+
+ /* If we're currently in focus, and we have a number in the entry
+ * already, then we dont want to change it.
+ *
+ * E.g. If the user types "1" and we change it to "Pony" right away,
+ * then we ignore that the user might want to enter "10"
+ *
+ * After focusing out, we'll force refresh this so that we settle
+ * on displaying an enum value if one is valid.
+ */
+ if (is_number && gtk_widget_has_focus (priv->entry))
+ return g_strdup_printf ("%d", value);
+
+ /* Now format a nice displayable value if possible
+ */
+ text = string_from_value (priv->type, value);
+ if (text)
+ return g_strdup (text);
+
+ return g_strdup_printf ("%d", value);
+}
+
+static gboolean
+glade_eprop_enum_int_focus_out_idle (gpointer user_data)
+{
+ GladeEPropEnumInt *eprop_enum = GLADE_EPROP_ENUM_INT (user_data);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+
+ /* If the editor is no longer loaded with a property (i.e. the user changed
+ * focus by selecting another widget), then just return.
+ */
+ if (glade_editor_property_get_property (GLADE_EDITOR_PROPERTY (eprop_enum)))
+ {
+ /* After focusing out, ensure we have a valid selection here if an entered
+ * number matches an enum value. Do this by provoking the combobox to
+ * format it's value.
+ */
+ g_signal_emit_by_name (priv->combo_box, "changed");
+ }
+
+ priv->focus_out_idle = 0;
+
+ return FALSE;
+}
+
+static gboolean
+glade_eprop_enum_int_entry_focus_out (GtkWidget *widget,
+ GdkEvent *event,
+ GladeEPropEnumInt *eprop_enum)
+{
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+
+ /* Queue the focus out idle, we may want to reformat the entry here
+ */
+ if (priv->focus_out_idle == 0)
+ priv->focus_out_idle = g_idle_add (glade_eprop_enum_int_focus_out_idle, eprop_enum);
+
+ return FALSE;
+}
+
+static GtkWidget *
+glade_eprop_enum_int_create_input (GladeEditorProperty *eprop)
+{
+ GladeEPropEnumInt *eprop_enum = GLADE_EPROP_ENUM_INT (eprop);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (eprop_enum);
+ GtkListStore *list_store;
+ GtkTreeIter iter;
+ guint i;
+ GEnumClass *enum_class;
+
+ enum_class = g_type_class_ref (priv->type);
+
+ list_store = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_STRING, /* COLUMN_ENUM_TEXT */
+ G_TYPE_INT); /* COLUMN_VALUE_INT */
+
+ if (!glade_type_has_displayable_values (priv->type))
+ g_warning ("No displayable value found for type %s", g_type_name (priv->type));
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter);
+ for (i = 0; i < enum_class->n_values; i++)
+ {
+ if (glade_displayable_value_is_disabled (priv->type, enum_class->values[i].value_nick))
+ continue;
+
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter,
+ COLUMN_ENUM_TEXT, string_from_value (priv->type, enum_class->values[i].value),
+ COLUMN_VALUE_INT, enum_class->values[i].value,
+ -1);
+ }
+
+ priv->combo_box = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (list_store));
+ priv->entry = gtk_bin_get_child (GTK_BIN (priv->combo_box));
+ gtk_widget_set_halign (priv->combo_box, GTK_ALIGN_FILL);
+ gtk_widget_set_valign (priv->combo_box, GTK_ALIGN_CENTER);
+ gtk_widget_set_hexpand (priv->combo_box, TRUE);
+
+ gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->combo_box), 0);
+
+ g_signal_connect (G_OBJECT (priv->combo_box), "changed",
+ G_CALLBACK (glade_eprop_enum_int_changed_combo), eprop);
+ g_signal_connect (G_OBJECT (priv->combo_box), "format-entry-text",
+ G_CALLBACK (glade_eprop_enum_int_format_entry_cb), eprop);
+
+ g_signal_connect_after (G_OBJECT (priv->entry), "focus-out-event",
+ G_CALLBACK (glade_eprop_enum_int_entry_focus_out), eprop);
+
+
+ glade_util_remove_scroll_events (priv->combo_box);
+
+ g_type_class_unref (enum_class);
+
+ return priv->combo_box;
+}
+
+static void
+glade_eprop_enum_int_finalize (GObject *object)
+{
+ GladeEPropEnumInt *self = GLADE_EPROP_ENUM_INT(object);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (self);
+
+ /* Be safe, dont leave idles hanging around */
+ if (priv->focus_out_idle != 0)
+ g_source_remove (priv->focus_out_idle);
+}
+
+static void
+glade_eprop_enum_int_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GladeEPropEnumInt *self = GLADE_EPROP_ENUM_INT(object);
+ GladeEPropEnumIntPrivate *priv = glade_eprop_enum_int_get_instance_private (self);
+
+ switch (property_id)
+ {
+ case PROP_TYPE :
+ priv->type = g_value_get_gtype (value);
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+GladeEditorProperty *
+glade_eprop_enum_int_new (GladePropertyClass *pclass,
+ GType type,
+ gboolean use_command)
+{
+ GladeEditorProperty *eprop =
+ g_object_new (GLADE_TYPE_EPROP_ENUM_INT,
+ "property-class", pclass,
+ "use-command", use_command,
+ "type", type,
+ NULL);
+ return eprop;
+}
diff --git a/plugins/gtk+/glade-eprop-enum-int.h b/plugins/gtk+/glade-eprop-enum-int.h
new file mode 100644
index 0000000..b5df6a1
--- /dev/null
+++ b/plugins/gtk+/glade-eprop-enum-int.h
@@ -0,0 +1,31 @@
+#ifndef __GLADE_EPROP_ENUM_INT_H__
+#define __GLADE_EPROP_ENUM_INT_H__
+
+#include <glib-object.h>
+#include <gladeui/glade.h>
+
+G_BEGIN_DECLS
+
+#define GLADE_TYPE_EPROP_ENUM_INT (glade_eprop_enum_int_get_type())
+#define GLADE_EPROP_ENUM_INT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ENUM_INT,
GladeEPropEnumInt))
+#define GLADE_EPROP_ENUM_INT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ENUM_INT,
GladeEPropEnumIntClass))
+#define GLADE_IS_EPROP_ENUM_INT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ENUM_INT))
+#define GLADE_IS_EPROP_ENUM_INT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ENUM_INT))
+#define GLADE_EPROP_ENUM_INT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ENUM_INT,
GladeEPropEnumIntClass))
+
+typedef struct
+{
+ GladeEditorProperty eprop;
+} GladeEPropEnumInt;
+
+typedef struct {
+ GladeEditorPropertyClass eprop_class;
+} GladeEPropEnumIntClass;
+
+GladeEditorProperty *glade_eprop_enum_int_new (GladePropertyClass *pclass,
+ GType type,
+ gboolean use_command);
+
+G_END_DECLS
+
+#endif /* __GLADE_EPROP_ENUM_INT_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]