/* * Copyright (C) 2008 Tristan Van Berkom. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: * Tristan Van Berkom */ #include #include #include #include #include #include "glade-icon-sources.h" static GList * icon_set_copy (GList * set) { GList *dup_set = NULL, *l; GtkIconSource *source; for (l = set; l; l = l->next) { G_GNUC_BEGIN_IGNORE_DEPRECATIONS source = gtk_icon_source_copy ((GtkIconSource *) l->data); G_GNUC_END_IGNORE_DEPRECATIONS dup_set = g_list_prepend (dup_set, source); } return g_list_reverse (dup_set); } static void icon_set_free (GList * list) { G_GNUC_BEGIN_IGNORE_DEPRECATIONS g_list_foreach (list, (GFunc) gtk_icon_source_free, NULL); G_GNUC_END_IGNORE_DEPRECATIONS g_list_free (list); } GladeIconSources * glade_icon_sources_new (void) { GladeIconSources *sources = g_new0 (GladeIconSources, 1); sources->sources = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) icon_set_free); return sources; } static void icon_sources_dup (gchar * icon_name, GList * set, GladeIconSources * dup) { GList *dup_set = icon_set_copy (set); g_hash_table_insert (dup->sources, g_strdup (icon_name), dup_set); } GladeIconSources * glade_icon_sources_copy (GladeIconSources * sources) { if (!sources) return NULL; GladeIconSources *dup = glade_icon_sources_new (); g_hash_table_foreach (sources->sources, (GHFunc) icon_sources_dup, dup); return dup; } void glade_icon_sources_free (GladeIconSources * sources) { if (sources) { g_hash_table_destroy (sources->sources); g_free (sources); } } GType glade_icon_sources_get_type (void) { static GType type_id = 0; if (!type_id) type_id = g_boxed_type_register_static ("GladeIconSources", (GBoxedCopyFunc) glade_icon_sources_copy, (GBoxedFreeFunc) glade_icon_sources_free); return type_id; } /**************************** GladeEditorProperty *****************************/ enum { COLUMN_TEXT, /* Used for display/editing purposes */ COLUMN_TEXT_WEIGHT, /* Whether the text is bold (icon-name parent rows) */ COLUMN_TEXT_EDITABLE, /* parent icon-name displays are not editable */ COLUMN_ICON_NAME, /* store the icon name regardless */ COLUMN_LIST_INDEX, /* denotes the position in the GList of the actual property value (or -1) */ COLUMN_DIRECTION_ACTIVE, COLUMN_DIRECTION, COLUMN_SIZE_ACTIVE, COLUMN_SIZE, COLUMN_STATE_ACTIVE, COLUMN_STATE, NUM_COLUMNS }; typedef struct { GladeEditorProperty parent_instance; GtkTreeView *view; GtkTreeStore *store; GtkTreeViewColumn *filename_column; GtkWidget *combo; } GladeEPropIconSources; GLADE_MAKE_EPROP (GladeEPropIconSources, glade_eprop_icon_sources) #define GLADE_EPROP_ICON_SOURCES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ICON_SOURCES, GladeEPropIconSources)) #define GLADE_EPROP_ICON_SOURCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ICON_SOURCES, GladeEPropIconSourcesClass)) #define GLADE_IS_EPROP_ICON_SOURCES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ICON_SOURCES)) #define GLADE_IS_EPROP_ICON_SOURCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ICON_SOURCES)) #define GLADE_EPROP_ICON_SOURCES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ICON_SOURCES, GladeEPropIconSourcesClass)) static void glade_eprop_icon_sources_finalize (GObject * object) { /* Chain up */ GObjectClass *parent_class = g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)); //GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (object); G_OBJECT_CLASS (parent_class)->finalize (object); } static void populate_store_foreach (const gchar * icon_name, GList * sources, GladeEPropIconSources * eprop_sources) { GtkIconSource *source; GtkTreeIter parent_iter, iter; GList *l; /* Update the comboboxentry's store here... */ gtk_combo_box_text_insert (GTK_COMBO_BOX_TEXT (eprop_sources->combo), -1, icon_name, icon_name); gtk_combo_box_set_active_id (GTK_COMBO_BOX (eprop_sources->combo), icon_name); /* Dont set COLUMN_ICON_NAME here */ gtk_tree_store_append (eprop_sources->store, &parent_iter, NULL); gtk_tree_store_set (eprop_sources->store, &parent_iter, COLUMN_TEXT, icon_name, COLUMN_TEXT_EDITABLE, FALSE, COLUMN_TEXT_WEIGHT, PANGO_WEIGHT_BOLD, -1); for (l = sources; l; l = l->next) { GdkPixbuf *pixbuf; gchar *str; source = l->data; G_GNUC_BEGIN_IGNORE_DEPRECATIONS pixbuf = gtk_icon_source_get_pixbuf (source); G_GNUC_END_IGNORE_DEPRECATIONS str = g_object_get_data (G_OBJECT (pixbuf), "GladeFileName"); gtk_tree_store_append (eprop_sources->store, &iter, &parent_iter); gtk_tree_store_set (eprop_sources->store, &iter, COLUMN_ICON_NAME, icon_name, COLUMN_LIST_INDEX, g_list_index (sources, source), COLUMN_TEXT, str, COLUMN_TEXT_EDITABLE, TRUE, COLUMN_TEXT_WEIGHT, PANGO_WEIGHT_NORMAL, -1); G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (!gtk_icon_source_get_direction_wildcarded (source)) { GtkTextDirection direction = gtk_icon_source_get_direction (source); G_GNUC_END_IGNORE_DEPRECATIONS str = glade_utils_enum_string_from_value_displayable (GTK_TYPE_TEXT_DIRECTION, direction); gtk_tree_store_set (eprop_sources->store, &iter, COLUMN_DIRECTION_ACTIVE, TRUE, COLUMN_DIRECTION, str, -1); g_free (str); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (!gtk_icon_source_get_size_wildcarded (source)) { GtkIconSize size = gtk_icon_source_get_size (source); G_GNUC_END_IGNORE_DEPRECATIONS str = glade_utils_enum_string_from_value_displayable (GTK_TYPE_ICON_SIZE, size); gtk_tree_store_set (eprop_sources->store, &iter, COLUMN_SIZE_ACTIVE, TRUE, COLUMN_SIZE, str, -1); g_free (str); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (!gtk_icon_source_get_state_wildcarded (source)) { GtkStateType state = gtk_icon_source_get_state (source); G_GNUC_END_IGNORE_DEPRECATIONS str = glade_utils_enum_string_from_value_displayable (GTK_TYPE_STATE_TYPE, state); gtk_tree_store_set (eprop_sources->store, &iter, COLUMN_STATE_ACTIVE, TRUE, COLUMN_STATE, str, -1); g_free (str); } if (!l->next) { GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (eprop_sources->store), &iter); gtk_tree_view_expand_to_path (GTK_TREE_VIEW (eprop_sources->view), path); gtk_tree_path_free (path); } } } static void icon_sources_populate_store (GladeEPropIconSources * eprop_sources) { GladeIconSources *sources = NULL; GladeProperty *property; gtk_tree_store_clear (eprop_sources->store); gtk_combo_box_text_remove_all (GTK_COMBO_BOX_TEXT (eprop_sources->combo)); property = glade_editor_property_get_property (GLADE_EDITOR_PROPERTY (eprop_sources)); if (!property) return; glade_property_get (property, &sources); if (sources) g_hash_table_foreach (sources->sources, (GHFunc) populate_store_foreach, eprop_sources); } static void glade_eprop_icon_sources_load (GladeEditorProperty * eprop, GladeProperty * property) { GladeEditorPropertyClass *parent_class = g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)); GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); /* Chain up in a clean state... */ parent_class->load (eprop, property); icon_sources_populate_store (eprop_sources); gtk_widget_queue_draw (GTK_WIDGET (eprop_sources->view)); } static gboolean reload_icon_sources_idle (GladeEditorProperty * eprop) { GladeProperty *property = glade_editor_property_get_property (eprop); glade_editor_property_load (eprop, property); return FALSE; } typedef struct { GladeEPropIconSources *eprop; GtkTreeRowReference *row_ref; } RowEditData; static gboolean edit_row_idle (RowEditData *data) { GtkTreePath *new_item_path; new_item_path = gtk_tree_row_reference_get_path (data->row_ref); gtk_widget_grab_focus (GTK_WIDGET (data->eprop->view)); gtk_tree_view_expand_to_path (data->eprop->view, new_item_path); gtk_tree_view_set_cursor (data->eprop->view, new_item_path, data->eprop->filename_column, TRUE); gtk_tree_path_free (new_item_path); gtk_tree_row_reference_free (data->row_ref); g_slice_free (RowEditData, data); return FALSE; } static void add_clicked (GtkWidget * button, GladeEPropIconSources * eprop_sources) { /* Remember to set focus on the cell and activate it ! */ GtkTreeIter *parent_iter = NULL, iter, new_parent_iter; GtkTreePath *new_item_path; gchar *icon_name; gchar *selected_icon_name = NULL; gint index; RowEditData *edit_data; selected_icon_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (eprop_sources->combo)); if (!selected_icon_name) return; /* Find the right parent iter to add a child to... */ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (eprop_sources->store), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_TEXT, &icon_name, -1); if (icon_name && strcmp (icon_name, selected_icon_name) == 0) parent_iter = gtk_tree_iter_copy (&iter); g_free (icon_name); } while (parent_iter == NULL && gtk_tree_model_iter_next (GTK_TREE_MODEL (eprop_sources->store), &iter)); } /* check if we're already adding one here... */ if (parent_iter && gtk_tree_model_iter_children (GTK_TREE_MODEL (eprop_sources->store), &iter, parent_iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_LIST_INDEX, &index, -1); /* Iter is set, expand and return. */ if (index < 0) goto expand_to_path_and_focus; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (eprop_sources->store), &iter)); } if (!parent_iter) { /* Dont set COLUMN_ICON_NAME here */ gtk_tree_store_append (eprop_sources->store, &new_parent_iter, NULL); gtk_tree_store_set (eprop_sources->store, &new_parent_iter, COLUMN_TEXT, selected_icon_name, COLUMN_TEXT_EDITABLE, FALSE, COLUMN_TEXT_WEIGHT, PANGO_WEIGHT_BOLD, -1); parent_iter = gtk_tree_iter_copy (&new_parent_iter); } gtk_tree_store_append (eprop_sources->store, &iter, parent_iter); gtk_tree_store_set (eprop_sources->store, &iter, COLUMN_ICON_NAME, selected_icon_name, COLUMN_TEXT_EDITABLE, TRUE, COLUMN_TEXT_WEIGHT, PANGO_WEIGHT_NORMAL, COLUMN_LIST_INDEX, -1, -1); /* By now iter is valid. */ expand_to_path_and_focus: new_item_path = gtk_tree_model_get_path (GTK_TREE_MODEL (eprop_sources->store), &iter); /* Queue an idle to expand to row, GtkTreeView seems to be broken now * and will not expand to the second row we just added (instead the parent row get's focus), * deferring this to an idle handler fixes the problem. */ edit_data = g_slice_new (RowEditData); edit_data->eprop = eprop_sources; edit_data->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (eprop_sources->store), new_item_path); g_idle_add ((GSourceFunc)edit_row_idle, edit_data); g_free (selected_icon_name); gtk_tree_path_free (new_item_path); gtk_tree_iter_free (parent_iter); } static GtkIconSource * get_icon_source (GladeIconSources * sources, const gchar * icon_name, gint index) { GList *source_list = g_hash_table_lookup (sources->sources, icon_name); if (source_list) { if (index < 0) return NULL; else return (GtkIconSource *) g_list_nth_data (source_list, index); } return NULL; } static void update_icon_sources (GladeEditorProperty * eprop, GladeIconSources * icon_sources) { GValue value = { 0, }; g_value_init (&value, GLADE_TYPE_ICON_SOURCES); g_value_take_boxed (&value, icon_sources); glade_editor_property_commit (eprop, &value); g_value_unset (&value); } static void delete_clicked (GtkWidget * button, GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); GladeProperty *property = glade_editor_property_get_property (eprop); GtkTreeIter iter; GladeIconSources *icon_sources = NULL; GList *list, *sources, *new_list_head; gchar *icon_name; gint index = 0; /* NOTE: This will trigger row-deleted below... */ if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection (eprop_sources->view), NULL, &iter)) return; gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_ICON_NAME, &icon_name, COLUMN_LIST_INDEX, &index, -1); /* Could be the user pressed add and then delete without touching the * new item. */ if (index < 0) { g_idle_add ((GSourceFunc) reload_icon_sources_idle, eprop); return; } glade_property_get (property, &icon_sources); if (icon_sources) { icon_sources = glade_icon_sources_copy (icon_sources); if ((sources = g_hash_table_lookup (icon_sources->sources, icon_name)) != NULL) { new_list_head = icon_set_copy (sources); list = g_list_nth (new_list_head, index); new_list_head = g_list_remove_link (new_list_head, list); G_GNUC_BEGIN_IGNORE_DEPRECATIONS gtk_icon_source_free ((GtkIconSource *) list->data); G_GNUC_END_IGNORE_DEPRECATIONS g_list_free (list); /* We copied all that above cause this will free the old list */ g_hash_table_insert (icon_sources->sources, g_strdup (icon_name), new_list_head); } update_icon_sources (eprop, icon_sources); } g_free (icon_name); } static void value_filename_edited (GtkCellRendererText * cell, const gchar * path, const gchar * new_text, GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); GladeProperty *property = glade_editor_property_get_property (eprop); GtkTreeIter iter; GladeIconSources *icon_sources = NULL; GtkIconSource *source; gchar *icon_name; gint index = -1; GValue *value; GdkPixbuf *pixbuf; GList *source_list; if (!new_text || !new_text[0]) { g_idle_add ((GSourceFunc) reload_icon_sources_idle, eprop); return; } if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_sources->store), &iter, path)) return; gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_ICON_NAME, &icon_name, COLUMN_LIST_INDEX, &index, -1); /* get new pixbuf value... */ value = glade_utils_value_from_string (GDK_TYPE_PIXBUF, new_text, glade_widget_get_project (glade_property_get_widget (property))); pixbuf = g_value_get_object (value); glade_property_get (property, &icon_sources); if (icon_sources) { icon_sources = glade_icon_sources_copy (icon_sources); if (index >= 0 && (source = get_icon_source (icon_sources, icon_name, index)) != NULL) { G_GNUC_BEGIN_IGNORE_DEPRECATIONS gtk_icon_source_set_pixbuf (source, pixbuf); G_GNUC_END_IGNORE_DEPRECATIONS } else { G_GNUC_BEGIN_IGNORE_DEPRECATIONS source = gtk_icon_source_new (); gtk_icon_source_set_pixbuf (source, pixbuf); G_GNUC_END_IGNORE_DEPRECATIONS if ((source_list = g_hash_table_lookup (icon_sources->sources, icon_name)) != NULL) { source_list = g_list_append (source_list, source); } else { source_list = g_list_prepend (NULL, source); g_hash_table_insert (icon_sources->sources, g_strdup (icon_name), source_list); } } } else { icon_sources = glade_icon_sources_new (); G_GNUC_BEGIN_IGNORE_DEPRECATIONS source = gtk_icon_source_new (); gtk_icon_source_set_pixbuf (source, pixbuf); G_GNUC_END_IGNORE_DEPRECATIONS source_list = g_list_prepend (NULL, source); g_hash_table_insert (icon_sources->sources, g_strdup (icon_name), source_list); } g_value_unset (value); g_free (value); update_icon_sources (eprop, icon_sources); } static void value_attribute_toggled (GtkCellRendererToggle * cell_renderer, gchar * path, GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); GladeProperty *property = glade_editor_property_get_property (eprop); GtkTreeIter iter; GladeIconSources *icon_sources = NULL; GtkIconSource *source; gchar *icon_name; gint index, edit_column; gboolean edit_column_active = FALSE; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_sources->store), &iter, path)) return; edit_column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell_renderer), "attribute-column")); gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_ICON_NAME, &icon_name, COLUMN_LIST_INDEX, &index, edit_column, &edit_column_active, -1); glade_property_get (property, &icon_sources); if (icon_sources) icon_sources = glade_icon_sources_copy (icon_sources); if (icon_sources && (source = get_icon_source (icon_sources, icon_name, index)) != NULL) { /* Note the reverse meaning of active toggles vs. wildcarded sources... */ G_GNUC_BEGIN_IGNORE_DEPRECATIONS switch (edit_column) { case COLUMN_DIRECTION_ACTIVE: gtk_icon_source_set_direction_wildcarded (source, edit_column_active); break; case COLUMN_SIZE_ACTIVE: gtk_icon_source_set_size_wildcarded (source, edit_column_active); break; case COLUMN_STATE_ACTIVE: gtk_icon_source_set_state_wildcarded (source, edit_column_active); break; default: break; } G_GNUC_END_IGNORE_DEPRECATIONS update_icon_sources (eprop, icon_sources); g_free (icon_name); return; } if (icon_sources) glade_icon_sources_free (icon_sources); g_free (icon_name); return; } static void value_attribute_edited (GtkCellRendererText * cell, const gchar * path, const gchar * new_text, GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); GladeProperty *property = glade_editor_property_get_property (eprop); GtkTreeIter iter; GladeIconSources *icon_sources = NULL; GtkIconSource *source; gchar *icon_name; gint index, edit_column; if (!new_text || !new_text[0]) return; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_sources->store), &iter, path)) return; edit_column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "attribute-column")); gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_ICON_NAME, &icon_name, COLUMN_LIST_INDEX, &index, -1); glade_property_get (property, &icon_sources); if (icon_sources) icon_sources = glade_icon_sources_copy (icon_sources); if (icon_sources && (source = get_icon_source (icon_sources, icon_name, index)) != NULL) { GtkTextDirection direction; GtkIconSize size; GtkStateType state; G_GNUC_BEGIN_IGNORE_DEPRECATIONS switch (edit_column) { case COLUMN_DIRECTION: direction = glade_utils_enum_value_from_string (GTK_TYPE_TEXT_DIRECTION, new_text); gtk_icon_source_set_direction (source, direction); break; case COLUMN_SIZE: size = glade_utils_enum_value_from_string (GTK_TYPE_ICON_SIZE, new_text); gtk_icon_source_set_size (source, size); break; case COLUMN_STATE: state = glade_utils_enum_value_from_string (GTK_TYPE_STATE_TYPE, new_text); gtk_icon_source_set_state (source, state); break; default: break; } G_GNUC_END_IGNORE_DEPRECATIONS update_icon_sources (eprop, icon_sources); g_free (icon_name); return; } if (icon_sources) glade_icon_sources_free (icon_sources); g_free (icon_name); return; } static gboolean icon_sources_query_tooltip (GtkWidget * widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip * tooltip, GladeEPropIconSources * eprop_sources) { GtkTreePath *path = NULL; GtkTreeIter iter; GtkTreeViewColumn *column = NULL; gint bin_x = x, bin_y = y, col; gchar *icon_name = NULL; gboolean show_now = FALSE; if (keyboard_mode) return FALSE; gtk_tree_view_convert_widget_to_bin_window_coords (eprop_sources->view, x, y, &bin_x, &bin_y); if (gtk_tree_view_get_path_at_pos (eprop_sources->view, bin_x, bin_y, &path, &column, NULL, NULL)) { if (gtk_tree_model_get_iter (GTK_TREE_MODEL (eprop_sources->store), &iter, path)) { col = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (column), "column-id")); gtk_tree_model_get (GTK_TREE_MODEL (eprop_sources->store), &iter, COLUMN_ICON_NAME, &icon_name, -1); /* no tooltips on the parent rows */ if (icon_name) { gchar *tooltip_text = NULL; show_now = TRUE; switch (col) { case COLUMN_TEXT: tooltip_text = g_strdup_printf (_ ("Enter a filename or a relative or full path for this " "source of '%s' (Glade will only ever load them in " "the runtime from your project directory)."), icon_name); break; case COLUMN_DIRECTION_ACTIVE: tooltip_text = g_strdup_printf (_ ("Set whether you want to specify a text direction " "for this source of '%s'"), icon_name); break; case COLUMN_DIRECTION: tooltip_text = g_strdup_printf (_ ("Set the text direction for this source of '%s'"), icon_name); break; case COLUMN_SIZE_ACTIVE: tooltip_text = g_strdup_printf (_ ("Set whether you want to specify an icon size " "for this source of '%s'"), icon_name); break; case COLUMN_SIZE: tooltip_text = g_strdup_printf (_ ("Set the icon size for this source of '%s'"), icon_name); break; case COLUMN_STATE_ACTIVE: tooltip_text = g_strdup_printf (_ ("Set whether you want to specify a state " "for this source of '%s'"), icon_name); break; case COLUMN_STATE: tooltip_text = g_strdup_printf (_ ("Set the state for this source of '%s'"), icon_name); default: break; } gtk_tooltip_set_text (tooltip, tooltip_text); g_free (tooltip_text); g_free (icon_name); gtk_tree_view_set_tooltip_cell (eprop_sources->view, tooltip, path, column, NULL); } } gtk_tree_path_free (path); } return show_now; } static GtkTreeView * build_view (GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); static GtkListStore *direction_store = NULL, *size_store = NULL, *state_store = NULL; GtkTreeView *view = (GtkTreeView *) gtk_tree_view_new (); GtkCellRenderer *renderer; GtkTreeViewColumn *column; if (!direction_store) { direction_store = glade_utils_liststore_from_enum_type (GTK_TYPE_TEXT_DIRECTION, FALSE); size_store = glade_utils_liststore_from_enum_type (GTK_TYPE_ICON_SIZE, FALSE); state_store = glade_utils_liststore_from_enum_type (GTK_TYPE_STATE_TYPE, FALSE); } /* Filename / icon name column/renderer */ renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL); g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (value_filename_edited), eprop); eprop_sources->filename_column = gtk_tree_view_column_new_with_attributes (_("File Name"), renderer, "text", COLUMN_TEXT, "weight", COLUMN_TEXT_WEIGHT, "editable", COLUMN_TEXT_EDITABLE, NULL); gtk_tree_view_column_set_expand (eprop_sources->filename_column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (view), eprop_sources->filename_column); g_object_set_data (G_OBJECT (eprop_sources->filename_column), "column-id", GINT_TO_POINTER (COLUMN_TEXT)); /********************* Size *********************/ /* Attribute active portion */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "activatable", TRUE, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_SIZE_ACTIVE)); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (value_attribute_toggled), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "active", COLUMN_SIZE_ACTIVE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_SIZE_ACTIVE)); /* Attribute portion */ renderer = gtk_cell_renderer_combo_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, "has-entry", FALSE, "text-column", 0, "model", size_store, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_SIZE)); g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (value_attribute_edited), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "editable", COLUMN_SIZE_ACTIVE, "text", COLUMN_SIZE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_SIZE)); /********************* State *********************/ /* Attribute active portion */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "activatable", TRUE, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_STATE_ACTIVE)); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (value_attribute_toggled), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "active", COLUMN_STATE_ACTIVE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_STATE_ACTIVE)); /* Attribute portion */ renderer = gtk_cell_renderer_combo_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, "has-entry", FALSE, "text-column", 0, "model", state_store, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_STATE)); g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (value_attribute_edited), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "editable", COLUMN_STATE_ACTIVE, "text", COLUMN_STATE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_STATE)); /********************* Direction *********************/ /* Attribute active portion */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "activatable", TRUE, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_DIRECTION_ACTIVE)); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (value_attribute_toggled), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "active", COLUMN_DIRECTION_ACTIVE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_DIRECTION_ACTIVE)); /* Attribute portion */ renderer = gtk_cell_renderer_combo_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, "has-entry", FALSE, "text-column", 0, "model", direction_store, NULL); g_object_set_data (G_OBJECT (renderer), "attribute-column", GINT_TO_POINTER (COLUMN_DIRECTION)); g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (value_attribute_edited), eprop); column = gtk_tree_view_column_new_with_attributes ("dummy", renderer, "visible", COLUMN_TEXT_EDITABLE, "editable", COLUMN_DIRECTION_ACTIVE, "text", COLUMN_DIRECTION, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (view), column); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_DIRECTION)); /* Connect ::query-tooltip here for fancy tooltips... */ g_object_set (G_OBJECT (view), "has-tooltip", TRUE, NULL); g_signal_connect (G_OBJECT (view), "query-tooltip", G_CALLBACK (icon_sources_query_tooltip), eprop); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (view), FALSE); return view; } static void icon_name_entry_activated (GtkEntry * entry, GladeEPropIconSources * eprop_sources) { const gchar *text = gtk_entry_get_text (entry); GladeProperty *property; GladeIconSources *sources = NULL; if (!text || !text[0]) return; property = glade_editor_property_get_property (GLADE_EDITOR_PROPERTY (eprop_sources)); if (!property) return; glade_property_get (property, &sources); if (sources == NULL || g_hash_table_lookup (sources->sources, text) == NULL) { /* Add the new source if it doesnt already exist */ gtk_combo_box_text_insert (GTK_COMBO_BOX_TEXT (eprop_sources->combo), -1, text, text); } /* Set the active id whether it existed or not */ gtk_combo_box_set_active_id (GTK_COMBO_BOX (eprop_sources->combo), text); } static GtkWidget * glade_eprop_icon_sources_create_input (GladeEditorProperty * eprop) { GladeEPropIconSources *eprop_sources = GLADE_EPROP_ICON_SOURCES (eprop); GtkWidget *vbox, *hbox, *button, *swin; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); /* hbox with comboboxentry add/remove source buttons on the right... */ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); eprop_sources->combo = gtk_combo_box_text_new_with_entry (); g_signal_connect (G_OBJECT (gtk_bin_get_child (GTK_BIN (eprop_sources->combo))), "activate", G_CALLBACK (icon_name_entry_activated), eprop); gtk_box_pack_start (GTK_BOX (hbox), eprop_sources->combo, TRUE, TRUE, 0); button = gtk_button_new (); gtk_container_set_border_width (GTK_CONTAINER (button), 2); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON)); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (add_clicked), eprop_sources); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("list-remove-symbolic", GTK_ICON_SIZE_BUTTON)); gtk_container_set_border_width (GTK_CONTAINER (button), 2); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (delete_clicked), eprop_sources); /* Pack treeview/swindow on the left... */ swin = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start (GTK_BOX (vbox), swin, TRUE, TRUE, 0); eprop_sources->view = build_view (eprop); gtk_container_add (GTK_CONTAINER (swin), GTK_WIDGET (eprop_sources->view)); g_object_set (G_OBJECT (vbox), "height-request", 350, NULL); eprop_sources->store = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, // COLUMN_TEXT G_TYPE_INT, // COLUMN_TEXT_WEIGHT G_TYPE_BOOLEAN, // COLUMN_TEXT_EDITABLE G_TYPE_STRING, // COLUMN_ICON_NAME G_TYPE_INT, // COLUMN_LIST_INDEX G_TYPE_BOOLEAN, // COLUMN_DIRECTION_ACTIVE G_TYPE_STRING, // COLUMN_DIRECTION G_TYPE_BOOLEAN, // COLUMN_SIZE_ACTIVE G_TYPE_STRING, // COLUMN_SIZE G_TYPE_BOOLEAN, // COLUMN_STATE_ACTIVE, G_TYPE_STRING); // COLUMN_STATE gtk_tree_view_set_model (eprop_sources->view, GTK_TREE_MODEL (eprop_sources->store)); g_object_unref (G_OBJECT (eprop_sources->store)); // <-- pass ownership here gtk_widget_show_all (vbox); return vbox; }