/* * glade-adaptor-chooser.c * * Copyright (C) 2017 Juan Pablo Ugarte * * 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: * Juan Pablo Ugarte */ #include "glade-adaptor-chooser-widget.h" #include "glade-adaptor-chooser.h" #include "glade-app.h" typedef struct { GladeProject *project; GtkWidget *gtk_button_box; GtkWidget *extra_button; GtkWidget *others_button; GtkImage *class_image; GtkLabel *class_label; GtkWidget *all_button; GList *choosers; } GladeAdaptorChooserPrivate; struct _GladeAdaptorChooser { GtkBox parent_instance; }; enum { PROP_0, PROP_PROJECT, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES]; G_DEFINE_TYPE_WITH_PRIVATE (GladeAdaptorChooser, glade_adaptor_chooser, GTK_TYPE_BOX); #define GET_PRIVATE(d) ((GladeAdaptorChooserPrivate *) glade_adaptor_chooser_get_instance_private((GladeAdaptorChooser*)d)) static void glade_adaptor_chooser_init (GladeAdaptorChooser *chooser) { gtk_widget_init_template (GTK_WIDGET (chooser)); } static void glade_adaptor_chooser_finalize (GObject *object) { GladeAdaptorChooserPrivate *priv = GET_PRIVATE (object); g_list_free (priv->choosers); G_OBJECT_CLASS (glade_adaptor_chooser_parent_class)->finalize (object); } static void glade_adaptor_chooser_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { g_return_if_fail (GLADE_IS_ADAPTOR_CHOOSER (object)); switch (prop_id) { case PROP_PROJECT: glade_adaptor_chooser_set_project (GLADE_ADAPTOR_CHOOSER (object), g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void glade_adaptor_chooser_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GladeAdaptorChooserPrivate *priv; g_return_if_fail (GLADE_IS_ADAPTOR_CHOOSER (object)); priv = GET_PRIVATE (object); switch (prop_id) { case PROP_PROJECT: g_value_set_object (value, priv->project); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void on_adaptor_selected (GtkWidget *widget, GladeWidgetAdaptor *adaptor, GladeAdaptorChooser *chooser) { GladeAdaptorChooserPrivate *priv = GET_PRIVATE (chooser); /* Auto-create toplevel types */ if (GWA_IS_TOPLEVEL (adaptor)) { glade_command_create (adaptor, NULL, NULL, priv->project); } else { glade_project_set_add_item (priv->project, adaptor); glade_project_set_pointer_mode (priv->project, GLADE_POINTER_ADD_WIDGET); } gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_parent (widget))); } static void glade_adaptor_chooser_button_add_chooser (GtkWidget *button, GtkWidget *chooser) { GtkWidget *popover; popover = gtk_popover_new (button); gtk_container_add (GTK_CONTAINER (popover), chooser); gtk_widget_show (chooser); gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover); } static GtkWidget * glade_adaptor_chooser_add_chooser (GladeAdaptorChooser *chooser, gboolean show_group_title) { GladeAdaptorChooserPrivate *priv = GET_PRIVATE (chooser); GtkWidget *chooser_widget = g_object_new (GLADE_TYPE_ADAPTOR_CHOOSER_WIDGET, "show-group-title", show_group_title, NULL); priv->choosers = g_list_prepend (priv->choosers, chooser_widget); g_signal_connect (chooser_widget, "adaptor-selected", G_CALLBACK (on_adaptor_selected), chooser); return chooser_widget; } static void button_box_populate_from_catalog (GladeAdaptorChooser *chooser, GladeCatalog *catalog) { GladeAdaptorChooserPrivate *priv = GET_PRIVATE (chooser); GtkWidget *extra_chooser = NULL; GList *groups; groups = glade_catalog_get_widget_groups (catalog); gtk_box_set_homogeneous (GTK_BOX (priv->gtk_button_box), FALSE); for (; groups; groups = g_list_next (groups)) { GladeWidgetGroup *group = GLADE_WIDGET_GROUP (groups->data); if (!glade_widget_group_get_adaptors (group)) continue; if (glade_widget_group_get_expanded (group)) { GtkWidget *button, *chooser_widget; chooser_widget = glade_adaptor_chooser_add_chooser (chooser, FALSE); button = gtk_menu_button_new (); gtk_button_set_label (GTK_BUTTON (button), glade_widget_group_get_title (group)); glade_adaptor_chooser_button_add_chooser (button, chooser_widget); _glade_adaptor_chooser_widget_add_group (GLADE_ADAPTOR_CHOOSER_WIDGET (chooser_widget), group); gtk_box_pack_start (GTK_BOX (priv->gtk_button_box), button, FALSE, FALSE, 0); gtk_widget_show (button); } else { if (!extra_chooser) { extra_chooser = glade_adaptor_chooser_add_chooser (chooser, TRUE); glade_adaptor_chooser_button_add_chooser (priv->extra_button, extra_chooser); gtk_widget_show (priv->extra_button); } _glade_adaptor_chooser_widget_add_group (GLADE_ADAPTOR_CHOOSER_WIDGET (extra_chooser), group); } } } static void glade_adaptor_chooser_constructed (GObject *object) { GladeAdaptorChooser *chooser = GLADE_ADAPTOR_CHOOSER (object); GladeAdaptorChooserPrivate *priv = GET_PRIVATE (object); GtkWidget *others_chooser, *all_chooser; GladeCatalog *gtk_catalog; GList *l; /* GTK+ catalog goes first subdivided by group */ gtk_catalog = glade_app_get_catalog ("gtk+"); button_box_populate_from_catalog (chooser, gtk_catalog); others_chooser = glade_adaptor_chooser_add_chooser (chooser, TRUE); all_chooser = glade_adaptor_chooser_add_chooser (chooser, TRUE); glade_adaptor_chooser_button_add_chooser (priv->others_button, others_chooser); glade_adaptor_chooser_button_add_chooser (priv->all_button, all_chooser); /* then the rest */ for (l = glade_app_get_catalogs (); l; l = g_list_next (l)) { GladeCatalog *catalog = l->data; _glade_adaptor_chooser_widget_add_catalog (GLADE_ADAPTOR_CHOOSER_WIDGET (all_chooser), catalog); if (catalog != gtk_catalog) _glade_adaptor_chooser_widget_add_catalog (GLADE_ADAPTOR_CHOOSER_WIDGET (others_chooser), catalog); } } static void glade_adaptor_chooser_class_init (GladeAdaptorChooserClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->finalize = glade_adaptor_chooser_finalize; object_class->constructed = glade_adaptor_chooser_constructed; object_class->set_property = glade_adaptor_chooser_set_property; object_class->get_property = glade_adaptor_chooser_get_property; /* Properties */ properties[PROP_PROJECT] = g_param_spec_object ("project", "Project", "This adaptor chooser's current project", GLADE_TYPE_PROJECT, G_PARAM_READWRITE); g_object_class_install_properties (object_class, N_PROPERTIES, properties); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/gladeui/glade-adaptor-chooser.ui"); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, gtk_button_box); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, extra_button); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, others_button); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, class_image); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, class_label); gtk_widget_class_bind_template_child_private (widget_class, GladeAdaptorChooser, all_button); } /* Public API */ GtkWidget * glade_adaptor_chooser_new () { return (GtkWidget*) g_object_new (GLADE_TYPE_ADAPTOR_CHOOSER, NULL); } static void glade_adaptor_chooser_update_adaptor (GladeAdaptorChooser *chooser) { GladeAdaptorChooserPrivate *priv = GET_PRIVATE (chooser); GladeWidgetAdaptor *adaptor; if (priv->project && (adaptor = glade_project_get_add_item (priv->project))) { gtk_image_set_from_icon_name (priv->class_image, glade_widget_adaptor_get_icon_name (adaptor), GTK_ICON_SIZE_BUTTON); gtk_label_set_label (priv->class_label, glade_widget_adaptor_get_name (adaptor)); } else { gtk_image_set_from_pixbuf (priv->class_image, NULL); gtk_label_set_label (priv->class_label, ""); } } void glade_adaptor_chooser_set_project (GladeAdaptorChooser *chooser, GladeProject *project) { GladeAdaptorChooserPrivate *priv; GList *l; g_return_if_fail (GLADE_IS_ADAPTOR_CHOOSER (chooser)); priv = GET_PRIVATE (chooser); if (priv->project) { g_signal_handlers_disconnect_by_func (G_OBJECT (priv->project), G_CALLBACK (glade_adaptor_chooser_update_adaptor), chooser); g_clear_object (&priv->project); } if (project) { priv->project = g_object_ref (project); g_signal_connect_swapped (G_OBJECT (project), "notify::add-item", G_CALLBACK (glade_adaptor_chooser_update_adaptor), chooser); gtk_widget_set_sensitive (GTK_WIDGET (chooser), TRUE); } else gtk_widget_set_sensitive (GTK_WIDGET (chooser), FALSE); /* Set project in chooser for filter to work */ for (l = priv->choosers; l; l = g_list_next (l)) _glade_adaptor_chooser_widget_set_project (l->data, project); /* Update class image and label */ glade_adaptor_chooser_update_adaptor (chooser); } GladeProject * glade_adaptor_chooser_get_project (GladeAdaptorChooser *chooser) { g_return_val_if_fail (GLADE_IS_ADAPTOR_CHOOSER (chooser), NULL); return GET_PRIVATE (chooser)->project; }