glom r1626 - in trunk/glom/utility_widgets/egg: toolpalette util
- From: jhs svn gnome org
- To: svn-commits-list gnome org
- Subject: glom r1626 - in trunk/glom/utility_widgets/egg: toolpalette util
- Date: Mon, 16 Jun 2008 10:23:15 +0000 (UTC)
Author: jhs
Date: Mon Jun 16 10:23:15 2008
New Revision: 1626
URL: http://svn.gnome.org/viewvc/glom?rev=1626&view=rev
Log:
Really add egg directories
Added:
trunk/glom/utility_widgets/egg/toolpalette/
trunk/glom/utility_widgets/egg/toolpalette/Makefile.am
trunk/glom/utility_widgets/egg/toolpalette/TODO
trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.c
trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.h
trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.c
trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.h
trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.c
trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.h
trunk/glom/utility_widgets/egg/toolpalette/eggtoolpaletteprivate.h
trunk/glom/utility_widgets/egg/toolpalette/testtoolpalette.c
trunk/glom/utility_widgets/egg/util/
trunk/glom/utility_widgets/egg/util/Makefile.am
trunk/glom/utility_widgets/egg/util/egg-macros.h
trunk/glom/utility_widgets/egg/util/egg-marshal.c
trunk/glom/utility_widgets/egg/util/eggintl.h
trunk/glom/utility_widgets/egg/util/eggmarshalers.list
Added: trunk/glom/utility_widgets/egg/toolpalette/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/Makefile.am Mon Jun 16 10:23:15 2008
@@ -0,0 +1,18 @@
+INCLUDES = \
+ $(EGG_CFLAGS) \
+ -I../util \
+ -DEGG_COMPILATION \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DG_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libeggtoolpalette.la
+noinst_PROGRAMS = testtoolpalette
+
+libeggtoolpalette_la_SOURCES = eggenumaction.c eggtoolpalette.c eggtoolitemgroup.c
+
+testtoolpalette_SOURCES = testtoolpalette.c
+testtoolpalette_LDFLAGS = libeggtoolpalette.la ../util/libeggutil.la $(EGG_LIBS)
+testtoolpalette_DEPENDENCIES = libeggtoolpalette.la ../util/libeggutil.la
+
+-include Makefile.local
Added: trunk/glom/utility_widgets/egg/toolpalette/TODO
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/TODO Mon Jun 16 10:23:15 2008
@@ -0,0 +1,32 @@
+EggToolPalette
+==============
+
+* support horizontal orientation for other styles but icon only:
+ - GTK_TOOLBAR_ICONS: done
+ - GTK_TOOLBAR_TEXT: rotate the text labels. currently can be done
+ by poking into the tool items internal's. would be better if
+ GtkToolShell would announce the required text orientation.
+ - GTK_TOOLBAR_BOTH: place items similar to Nautilus' icon view.
+ - GTK_TOOLBAR_BOTH_HORIZ: place items similar to Nautilus' compact view.
+ guess it's only in trunk. Manny blogged about it. Don't know right now
+ how the Windows Explorer calls that view.
+* left-align labels (and center icons) in both-horiz mode:
+ - would require poking into the tool item right now. would be better
+ if GtkToolShell would announce the required text alignment.
+* apply ellipses to text item labels:
+ - would require poking into the tool item right now. would be better
+ if GtkToolShell would announce the preferred ellipsize mode.
+* consider scrollbar size in size-request
+ - is that even possible?
+* implement natural-size interface:
+ - requires GtkNaturalSize to be pushed to GTK+
+
+GtkToolShell/GtkToolItem
+========================
+
+* enforce "expand" and "homogeneous" child property. don't know if GObject can
+ enforce implementation of child properties.
+* inform tool items about the desired text orientation, alignment and ellipsize
+ mode by implementing gtk_tool_shell_get_text_orientation(),
+ gtk_tool_shell_get_text_alignment() and gtk_tool_shell_get_ellipsize_mode().
+ change GtkToolItem to use that information.
Added: trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.c
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.c Mon Jun 16 10:23:15 2008
@@ -0,0 +1,552 @@
+/* EggEnumAction -- An action that creates combo boxes for enums
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#include "eggenumaction.h"
+#include <gtk/gtk.h>
+
+#define P_(msgid) (msgid)
+
+enum
+{
+ PROP_NONE,
+ PROP_ENUM_TYPE,
+};
+
+struct _EggEnumActionPrivate
+{
+ GType enum_type;
+ GEnumClass *enum_class;
+ GSList *bindings;
+ GSList *callbacks;
+ GtkListStore *model;
+
+ EggEnumActionFilterFunc filter_func;
+ GDestroyNotify filter_destroy;
+ gpointer filter_data;
+};
+
+static GQuark egg_enum_action_child_quark;
+static GQuark egg_enum_action_value_quark;
+
+G_DEFINE_TYPE (EggEnumAction, egg_enum_action, GTK_TYPE_ACTION);
+
+static void
+egg_enum_action_init (EggEnumAction *action)
+{
+ action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action,
+ EGG_TYPE_ENUM_ACTION,
+ EggEnumActionPrivate);
+}
+
+static void
+egg_enum_action_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggEnumAction *action = EGG_ENUM_ACTION (object);
+ GType enum_type;
+
+ switch (prop_id)
+ {
+ case PROP_ENUM_TYPE:
+ enum_type = g_value_get_gtype (value);
+
+ if (enum_type == action->priv->enum_type)
+ break;
+
+ if (action->priv->enum_class)
+ {
+ g_type_class_unref (action->priv->enum_class);
+ action->priv->enum_class = NULL;
+ }
+
+ action->priv->enum_type = enum_type;
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_enum_action_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggEnumAction *action = EGG_ENUM_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENUM_TYPE:
+ g_value_set_gtype (value, action->priv->enum_type);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_enum_action_dispose (GObject *object)
+{
+ EggEnumAction *action = EGG_ENUM_ACTION (object);
+
+ if (action->priv->enum_class)
+ {
+ g_type_class_unref (action->priv->enum_class);
+ action->priv->enum_class = NULL;
+ }
+
+ if (action->priv->model)
+ {
+ g_type_class_unref (action->priv->model);
+ action->priv->model = NULL;
+ }
+
+ while (action->priv->bindings)
+ {
+ g_param_spec_unref (action->priv->bindings->data);
+ g_object_unref (action->priv->bindings->next->data);
+
+ action->priv->bindings->data = g_slist_delete_link (action->priv->bindings->data,
+ action->priv->bindings->data);
+ action->priv->bindings->data = g_slist_delete_link (action->priv->bindings->data,
+ action->priv->bindings->data);
+ }
+
+ if (action->priv->callbacks)
+ {
+ g_slist_free (action->priv->callbacks);
+ action->priv->callbacks = NULL;
+ }
+
+ if (action->priv->filter_destroy)
+ {
+ action->priv->filter_destroy (action->priv->filter_data);
+ action->priv->filter_destroy = NULL;
+ }
+
+ action->priv->filter_func = NULL;
+ action->priv->filter_data = NULL;
+
+ G_OBJECT_CLASS (egg_enum_action_parent_class)->dispose (object);
+}
+
+static GtkTreeModel*
+egg_enum_action_get_model (EggEnumAction *action)
+{
+ if (!action->priv->enum_class)
+ action->priv->enum_class = g_type_class_ref (action->priv->enum_type);
+
+ if (!action->priv->model)
+ {
+ GtkTreeIter iter;
+ guint i;
+
+ action->priv->model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ for (i = 0; i < action->priv->enum_class->n_values; ++i)
+ {
+ GEnumValue *enum_value = &action->priv->enum_class->values[i];
+
+ if (action->priv->filter_func &&
+ !action->priv->filter_func (enum_value, action->priv->filter_data))
+ continue;
+
+ gtk_list_store_append (action->priv->model, &iter);
+ gtk_list_store_set (action->priv->model, &iter,
+ 0, enum_value->value_nick,
+ 1, enum_value, -1);
+ }
+ }
+
+ return GTK_TREE_MODEL (action->priv->model);
+}
+
+static gboolean
+egg_enum_action_get_iter (EggEnumAction *action,
+ GtkTreeIter *iter,
+ GObject *object,
+ GParamSpec *property)
+{
+ GtkTreeModel *model = egg_enum_action_get_model (action);
+ GEnumValue *enum_value;
+ gint current_value;
+
+ if (!gtk_tree_model_get_iter_first (model, iter))
+ return FALSE;
+
+ if (!G_IS_OBJECT (object) || !G_IS_PARAM_SPEC_ENUM (property))
+ return TRUE;
+
+ g_object_get (object, property->name, ¤t_value, NULL);
+
+ do
+ {
+ gtk_tree_model_get (model, iter, 1, &enum_value, -1);
+
+ if (enum_value->value == current_value)
+ return TRUE;
+ }
+ while (gtk_tree_model_iter_next (model, iter));
+
+ return FALSE;
+}
+
+static gboolean
+egg_enum_action_get_active_iter (EggEnumAction *action,
+ GtkTreeIter *iter)
+{
+ GParamSpec *property = NULL;
+ GObject *object = NULL;
+
+ if (action->priv->bindings)
+ {
+ property = action->priv->bindings->data;
+ object = action->priv->bindings->next->data;
+ }
+
+ return egg_enum_action_get_iter (action, iter, object, property);
+}
+
+static void
+egg_enum_action_set_value (EggEnumAction *action,
+ GEnumValue *enum_value)
+{
+ GSList *iter;
+
+ for (iter = action->priv->bindings; iter; iter = iter->next->next)
+ {
+ GParamSpec *property = iter->data;
+ GObject *object = iter->next->data;
+
+ g_object_set (object, property->name, enum_value->value, NULL);
+ }
+
+ for (iter = action->priv->callbacks; iter; iter = iter->next->next)
+ {
+ EggEnumActionCallback callback = iter->next->data;
+ gpointer user_data = iter->data;
+
+ callback (enum_value, user_data);
+ }
+}
+
+static void
+egg_enum_action_combo_changed (GtkComboBox *combo,
+ gpointer data)
+{
+ EggEnumAction *action = EGG_ENUM_ACTION (data);
+ GEnumValue *enum_value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (combo, &iter))
+ {
+ model = egg_enum_action_get_model (action);
+ gtk_tree_model_get (model, &iter, 1, &enum_value, -1);
+ egg_enum_action_set_value (action, enum_value);
+ }
+}
+
+static void
+egg_enum_action_toolbar_reconfigured (GtkToolItem *item,
+ gpointer data)
+{
+ gboolean important = gtk_tool_item_get_is_important (item);
+ GtkToolbarStyle style = gtk_tool_item_get_toolbar_style (item);
+ EggEnumAction *action = EGG_ENUM_ACTION (data);
+ gchar *text, *tmp;
+
+ GtkWidget *align, *box = NULL;
+ GtkWidget *combo, *label;
+ GtkCellRenderer *cell;
+ GtkTreeIter iter;
+
+ align = gtk_bin_get_child (GTK_BIN (item));
+ box = gtk_bin_get_child (GTK_BIN (align));
+
+ if (box)
+ gtk_container_remove (GTK_CONTAINER (align), box);
+
+ g_object_get (action, "label", &text, NULL);
+ box = NULL;
+
+ combo = gtk_combo_box_new_with_model (egg_enum_action_get_model (action));
+ g_signal_connect (combo, "changed", G_CALLBACK (egg_enum_action_combo_changed), action);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell, "text", 0, NULL);
+ g_object_set_qdata (G_OBJECT (item), egg_enum_action_child_quark, combo);
+
+ if (egg_enum_action_get_active_iter (action, &iter))
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+
+ if (GTK_TOOLBAR_BOTH == style)
+ {
+ label = gtk_label_new (text);
+
+ box = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (box), label, FALSE, TRUE, 0);
+ }
+ else if (GTK_TOOLBAR_ICONS != style || important)
+ {
+ tmp = g_strconcat (text, ":", NULL);
+ label = gtk_label_new (tmp);
+ g_free (tmp);
+
+ gtk_misc_set_padding (GTK_MISC (label), 3, 0);
+
+ box = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
+ }
+
+ if (box)
+ {
+ gtk_box_pack_start (GTK_BOX (box), combo, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (align), box);
+ }
+ else
+ gtk_container_add (GTK_CONTAINER (align), combo);
+
+ gtk_widget_show_all (align);
+
+ g_free (text);
+}
+
+static void
+egg_enum_action_select_menu_item (EggEnumAction *action,
+ GtkTreeIter *iter,
+ GtkWidget *menu)
+{
+ GList *items = gtk_container_get_children (GTK_CONTAINER (menu));
+ GtkTreeModel *model = egg_enum_action_get_model (action);
+ GtkTreePath *path = gtk_tree_model_get_path (model, iter);
+ gint item_index = gtk_tree_path_get_indices (path)[0];
+ GtkWidget *child = g_list_nth_data (items, item_index);
+
+ if (child)
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (child), TRUE);
+
+ gtk_tree_path_free (path);
+ g_list_free (items);
+}
+
+static void
+egg_enum_action_menu_item_toggled (GtkCheckMenuItem *item,
+ gpointer data)
+{
+ GEnumValue *enum_value;
+
+ enum_value = g_object_get_qdata (G_OBJECT (item), egg_enum_action_value_quark);
+ egg_enum_action_set_value (EGG_ENUM_ACTION (data), enum_value);
+}
+
+static GtkWidget*
+egg_enum_action_create_menu_item (GtkAction *action)
+{
+ GtkTreeModel *model = egg_enum_action_get_model (EGG_ENUM_ACTION (action));
+ GEnumValue *enum_value;
+ GtkTreeIter iter;
+ gchar *label;
+
+ GtkWidget *item;
+ GtkWidget *menu = gtk_menu_new ();
+ GSList *group = NULL;
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ do
+ {
+ gtk_tree_model_get (model, &iter, 0, &label, 1, &enum_value, -1);
+
+ item = gtk_radio_menu_item_new_with_label (group, label);
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ g_object_set_qdata (G_OBJECT (item),
+ egg_enum_action_value_quark,
+ enum_value);
+
+ g_signal_connect (item, "toggled",
+ G_CALLBACK (egg_enum_action_menu_item_toggled),
+ action);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+
+ gtk_widget_show_all (menu);
+
+ if (egg_enum_action_get_active_iter (EGG_ENUM_ACTION (action), &iter))
+ egg_enum_action_select_menu_item (EGG_ENUM_ACTION (action), &iter, menu);
+
+ item = GTK_ACTION_CLASS (egg_enum_action_parent_class)->create_menu_item (action);
+ g_object_set_qdata (G_OBJECT (item), egg_enum_action_child_quark, menu);
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
+
+ return item;
+}
+
+static GtkWidget*
+egg_enum_action_create_tool_item (GtkAction *action)
+{
+ GtkToolItem *item = gtk_tool_item_new ();
+ GtkWidget *align = gtk_alignment_new (0.5, 0.5, 1, 0);
+
+ gtk_container_add (GTK_CONTAINER (item), align);
+
+ g_signal_connect (item, "toolbar-reconfigured",
+ G_CALLBACK (egg_enum_action_toolbar_reconfigured),
+ action);
+
+ return GTK_WIDGET (item);
+}
+
+static void
+egg_enum_action_class_init (EggEnumActionClass *cls)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (cls);
+ GtkActionClass *aclass = GTK_ACTION_CLASS (cls);
+
+ oclass->set_property = egg_enum_action_set_property;
+ oclass->get_property = egg_enum_action_get_property;
+ oclass->dispose = egg_enum_action_dispose;
+
+ aclass->create_menu_item = egg_enum_action_create_menu_item;
+ aclass->create_tool_item = egg_enum_action_create_tool_item;
+
+ g_object_class_install_property (oclass, PROP_ENUM_TYPE,
+ g_param_spec_gtype ("enum-type",
+ P_("Enum Type"),
+ P_("Type of the enumeration"),
+ G_TYPE_ENUM,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private (cls, sizeof (EggEnumActionPrivate));
+
+ egg_enum_action_child_quark = g_quark_from_static_string ("egg-enum-action-child-quark");
+ egg_enum_action_value_quark = g_quark_from_static_string ("egg-enum-action-value-quark");
+}
+
+GtkAction*
+egg_enum_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ GType enum_type)
+{
+ g_return_val_if_fail (NULL != name, NULL);
+ g_return_val_if_fail (g_type_is_a (enum_type, G_TYPE_ENUM), NULL);
+
+ return g_object_new (EGG_TYPE_ENUM_ACTION, "name", name, "label", label,
+ "tooltip", tooltip, "enum-type", enum_type, NULL);
+}
+
+static void
+egg_enum_action_notify (GObject *object,
+ GParamSpec *property,
+ gpointer data)
+{
+ EggEnumAction *action = EGG_ENUM_ACTION (data);
+ GtkTreeIter active_iter;
+ GtkWidget *child;
+ GSList *proxies;
+
+ if (egg_enum_action_get_iter (action, &active_iter, object, property))
+ {
+ proxies = gtk_action_get_proxies (GTK_ACTION (action));
+
+ while (proxies)
+ {
+ child = g_object_get_qdata (proxies->data, egg_enum_action_child_quark);
+
+ if (GTK_IS_COMBO_BOX (child))
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (child), &active_iter);
+ else if (GTK_IS_MENU (child))
+ egg_enum_action_select_menu_item (action, &active_iter, child);
+
+ proxies = proxies->next;
+ }
+ }
+}
+
+void
+egg_enum_action_bind (EggEnumAction *action,
+ GObject *object,
+ const gchar *property_name)
+{
+ gchar *signal_name;
+ GParamSpec *property;
+
+ g_return_if_fail (EGG_IS_ENUM_ACTION (action));
+ g_return_if_fail (GTK_IS_OBJECT (object));
+ g_return_if_fail (NULL != property_name);
+
+ property = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+ property_name);
+
+ g_return_if_fail (NULL != property);
+ g_return_if_fail (g_type_is_a (property->value_type, action->priv->enum_type));
+
+ signal_name = g_strconcat ("notify::", property_name, NULL);
+
+ g_signal_connect (object, signal_name,
+ G_CALLBACK (egg_enum_action_notify),
+ action);
+
+ g_free (signal_name);
+
+ action->priv->bindings = g_slist_prepend (action->priv->bindings, g_object_ref (object));
+ action->priv->bindings = g_slist_prepend (action->priv->bindings, g_param_spec_ref (property));
+
+ egg_enum_action_notify (object, property, action);
+}
+
+void
+egg_enum_action_connect (EggEnumAction *action,
+ EggEnumActionCallback callback,
+ gpointer data)
+{
+ g_return_if_fail (EGG_IS_ENUM_ACTION (action));
+ g_return_if_fail (NULL != callback);
+
+ action->priv->callbacks = g_slist_prepend (action->priv->callbacks, callback);
+ action->priv->callbacks = g_slist_prepend (action->priv->callbacks, data);
+}
+
+void
+egg_enum_action_set_filter (EggEnumAction *action,
+ EggEnumActionFilterFunc filter,
+ gpointer user_data,
+ GDestroyNotify destroy_data)
+{
+ g_return_if_fail (EGG_IS_ENUM_ACTION (action));
+
+ if (action->priv->filter_destroy)
+ action->priv->filter_destroy (action->priv->filter_data);
+
+ action->priv->filter_func = filter;
+ action->priv->filter_data = user_data;
+ action->priv->filter_destroy = destroy_data;
+}
Added: trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggenumaction.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,76 @@
+/* EggEnumAction -- An action that creates combo boxes for enums
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#ifndef __EGG_ENUM_ACTION_H__
+#define __EGG_ENUM_ACTION_H__
+
+#include <gtk/gtkaction.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_ENUM_ACTION (egg_enum_action_get_type())
+#define EGG_ENUM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, EGG_TYPE_ENUM_ACTION, EggEnumAction))
+#define EGG_ENUM_ACTION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, EGG_TYPE_ENUM_ACTION, EggEnumActionClass))
+#define EGG_IS_ENUM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, EGG_TYPE_ENUM_ACTION))
+#define EGG_IS_ENUM_ACTION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, EGG_TYPE_ENUM_ACTION))
+#define EGG_ENUM_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_ENUM_ACTION, EggEnumActionClass))
+
+typedef struct _EggEnumAction EggEnumAction;
+typedef struct _EggEnumActionClass EggEnumActionClass;
+typedef struct _EggEnumActionPrivate EggEnumActionPrivate;
+
+typedef void (*EggEnumActionCallback) (GEnumValue *enum_value,
+ gpointer user_data);
+typedef gboolean (*EggEnumActionFilterFunc) (GEnumValue *enum_value,
+ gpointer user_data);
+
+struct _EggEnumAction
+{
+ GtkAction parent_instance;
+ EggEnumActionPrivate *priv;
+};
+
+struct _EggEnumActionClass
+{
+ GtkActionClass parent_class;
+};
+
+GType egg_enum_action_get_type (void) G_GNUC_CONST;
+GtkAction* egg_enum_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ GType enum_type);
+
+void egg_enum_action_bind (EggEnumAction *action,
+ GObject *object,
+ const gchar *property_name);
+void egg_enum_action_connect (EggEnumAction *action,
+ EggEnumActionCallback callback,
+ gpointer data);
+
+void egg_enum_action_set_filter (EggEnumAction *action,
+ EggEnumActionFilterFunc filter,
+ gpointer user_data,
+ GDestroyNotify destroy_data);
+
+G_END_DECLS
+
+#endif /* __EGG_ENUM_ACTION_H__ */
Added: trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.c
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.c Mon Jun 16 10:23:15 2008
@@ -0,0 +1,1692 @@
+/* EggToolPalette -- A tool palette with categories and DnD support
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ * Jan Arne Petersen
+ */
+
+#include "eggtoolitemgroup.h"
+#include "eggtoolpaletteprivate.h"
+
+#include <gtk/gtk.h>
+#include <math.h>
+#include <string.h>
+
+#define P_(msgid) (msgid)
+
+#define ANIMATION_TIMEOUT 50
+#define ANIMATION_DURATION (ANIMATION_TIMEOUT * 4)
+#define DEFAULT_EXPANDER_SIZE 16
+#define DEFAULT_HEADER_SPACING 2
+
+#define DEFAULT_NAME NULL
+#define DEFAULT_COLLAPSED FALSE
+#define DEFAULT_ELLIPSIZE PANGO_ELLIPSIZE_NONE
+
+enum
+{
+ PROP_NONE,
+ PROP_NAME,
+ PROP_COLLAPSED,
+ PROP_ELLIPSIZE,
+};
+
+enum
+{
+ CHILD_PROP_NONE,
+ CHILD_PROP_HOMOGENEOUS,
+ CHILD_PROP_EXPAND,
+ CHILD_PROP_FILL,
+ CHILD_PROP_NEW_ROW,
+ CHILD_PROP_POSITION,
+};
+
+typedef struct _EggToolItemGroupChild EggToolItemGroupChild;
+
+struct _EggToolItemGroupPrivate
+{
+ GtkWidget *header;
+
+ GList *children;
+
+ gint64 animation_start;
+ GSource *animation_timeout;
+ GtkExpanderStyle expander_style;
+ gint expander_size;
+ gint header_spacing;
+ PangoEllipsizeMode ellipsize;
+
+ guint collapsed : 1;
+
+};
+
+struct _EggToolItemGroupChild
+{
+ GtkToolItem *item;
+
+ guint homogeneous : 1;
+ guint expand : 1;
+ guint fill : 1;
+ guint new_row : 1;
+};
+
+#ifdef GTK_TYPE_TOOL_SHELL
+
+static void egg_tool_item_group_tool_shell_init (GtkToolShellIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EggToolItemGroup, egg_tool_item_group, GTK_TYPE_CONTAINER,
+G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL, egg_tool_item_group_tool_shell_init));
+
+#else /* GTK_TYPE_TOOL_SHELL */
+
+#define GTK_TOOL_SHELL(obj) EGG_TOOL_ITEM_GROUP((obj))
+
+#define GtkToolShell EggToolItemGroup
+
+#define gtk_tool_shell_get_orientation egg_tool_item_group_get_orientation
+#define gtk_tool_shell_get_style egg_tool_item_group_get_style
+
+G_DEFINE_TYPE (EggToolItemGroup, egg_tool_item_group, GTK_TYPE_CONTAINER);
+
+#endif /* GTK_TYPE_TOOL_SHELL */
+
+static GtkWidget*
+egg_tool_item_group_get_alignment (EggToolItemGroup *group)
+{
+ return gtk_bin_get_child (GTK_BIN (group->priv->header));
+}
+
+static GtkWidget*
+egg_tool_item_group_get_label (EggToolItemGroup *group)
+{
+ GtkWidget *alignment = egg_tool_item_group_get_alignment (group);
+ return gtk_bin_get_child (GTK_BIN (alignment));
+}
+
+static GtkOrientation
+egg_tool_item_group_get_orientation (GtkToolShell *shell)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ return egg_tool_palette_get_orientation (EGG_TOOL_PALETTE (parent));
+
+ return GTK_ORIENTATION_VERTICAL;
+}
+
+static GtkToolbarStyle
+egg_tool_item_group_get_style (GtkToolShell *shell)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ return egg_tool_palette_get_style (EGG_TOOL_PALETTE (parent));
+
+ return GTK_TOOLBAR_ICONS;
+}
+
+#ifdef GTK_TYPE_TOOL_SHELL
+
+static GtkIconSize
+egg_tool_item_group_get_icon_size (GtkToolShell *shell)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ return egg_tool_palette_get_icon_size (EGG_TOOL_PALETTE (parent));
+
+ return GTK_ICON_SIZE_SMALL_TOOLBAR;
+}
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+
+static PangoEllipsizeMode
+egg_tool_item_group_get_ellipsize_mode (GtkToolShell *shell)
+{
+ return EGG_TOOL_ITEM_GROUP (shell)->priv->ellipsize;
+}
+
+static gfloat
+egg_tool_item_group_get_text_alignment (GtkToolShell *shell)
+{
+ if (GTK_TOOLBAR_TEXT == egg_tool_item_group_get_style (shell) ||
+ GTK_TOOLBAR_BOTH_HORIZ == egg_tool_item_group_get_style (shell))
+ return 0.0;
+
+ return 0.5;
+}
+
+static GtkOrientation
+egg_tool_item_group_get_text_orientation (GtkToolShell *shell)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ {
+ GtkOrientation orientation = egg_tool_palette_get_orientation (EGG_TOOL_PALETTE (parent));
+ if (GTK_ORIENTATION_HORIZONTAL == orientation &&
+ (GTK_TOOLBAR_TEXT == egg_tool_item_group_get_style (shell)/* ||
+ GTK_TOOLBAR_BOTH_HORIZ == egg_tool_item_group_get_style (shell)*/))
+ return GTK_ORIENTATION_VERTICAL;
+ }
+
+ return GTK_ORIENTATION_HORIZONTAL;
+}
+
+static GtkSizeGroup *
+egg_tool_item_group_get_text_size_group (GtkToolShell *shell)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ return _egg_tool_palette_get_size_group (EGG_TOOL_PALETTE (parent));
+
+ return NULL;
+}
+
+#endif
+
+static void
+egg_tool_item_group_tool_shell_init (GtkToolShellIface *iface)
+{
+ iface->get_icon_size = egg_tool_item_group_get_icon_size;
+ iface->get_orientation = egg_tool_item_group_get_orientation;
+ iface->get_style = egg_tool_item_group_get_style;
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+ iface->get_text_alignment = egg_tool_item_group_get_text_alignment;
+ iface->get_text_orientation = egg_tool_item_group_get_text_orientation;
+ iface->get_text_size_group = egg_tool_item_group_get_text_size_group;
+ iface->get_ellipsize_mode = egg_tool_item_group_get_ellipsize_mode;
+#endif
+}
+
+#endif /* GTK_TYPE_TOOL_SHELL */
+
+static gboolean
+egg_tool_item_group_header_expose_event_cb (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (data);
+ GtkExpanderStyle expander_style;
+ GtkOrientation orientation;
+ gint x, y;
+ GtkTextDirection direction;
+
+ orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group));
+ expander_style = group->priv->expander_style;
+ direction = gtk_widget_get_direction (widget);
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ {
+ if (GTK_TEXT_DIR_RTL == direction)
+ x = widget->allocation.x + widget->allocation.width - group->priv->expander_size / 2;
+ else
+ x = widget->allocation.x + group->priv->expander_size / 2;
+ y = widget->allocation.y + widget->allocation.height / 2;
+ }
+ else
+ {
+ x = widget->allocation.x + widget->allocation.width / 2;
+ y = widget->allocation.y + group->priv->expander_size / 2;
+
+ /* Unfortunatly gtk_paint_expander() doesn't support rotated drawing
+ * modes. Luckily the following shady arithmetics produce the desired
+ * result. */
+ expander_style = GTK_EXPANDER_EXPANDED - expander_style; /* XXX */
+ }
+
+ gtk_paint_expander (widget->style, widget->window,
+ group->priv->header->state,
+ &event->area, GTK_WIDGET (group),
+ "tool-palette-header", x, y,
+ expander_style);
+
+ return FALSE;
+}
+
+static void
+egg_tool_item_group_header_size_request_cb (GtkWidget *widget G_GNUC_UNUSED,
+ GtkRequisition *requisition,
+ gpointer data)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (data);
+ requisition->height = MAX (requisition->height, group->priv->expander_size);
+}
+
+static void
+egg_tool_item_group_header_clicked_cb (GtkButton *button G_GNUC_UNUSED,
+ gpointer data)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (data);
+ GtkWidget *parent = gtk_widget_get_parent (data);
+
+ if (group->priv->collapsed ||
+ !EGG_IS_TOOL_PALETTE (parent) ||
+ !egg_tool_palette_get_exclusive (EGG_TOOL_PALETTE (parent), data))
+ egg_tool_item_group_set_collapsed (group, !group->priv->collapsed);
+}
+
+static void
+egg_tool_item_group_header_adjust_style (EggToolItemGroup *group)
+{
+ GtkWidget *alignment = egg_tool_item_group_get_alignment (group);
+ GtkWidget *label = gtk_bin_get_child (GTK_BIN (alignment));
+ GtkWidget *widget = GTK_WIDGET (group);
+ gint dx = 0, dy = 0;
+ GtkTextDirection direction = gtk_widget_get_direction (widget);
+
+ gtk_widget_style_get (widget,
+ "header-spacing", &group->priv->header_spacing,
+ "expander-size", &group->priv->expander_size,
+ NULL);
+
+ switch (gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)))
+ {
+ case GTK_ORIENTATION_HORIZONTAL:
+ dy = group->priv->header_spacing + group->priv->expander_size;
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_NONE);
+ if (GTK_TEXT_DIR_RTL == direction)
+ gtk_label_set_angle (GTK_LABEL (label), -90);
+ else
+ gtk_label_set_angle (GTK_LABEL (label), 90);
+ break;
+
+ case GTK_ORIENTATION_VERTICAL:
+ dx = group->priv->header_spacing + group->priv->expander_size;
+ gtk_label_set_ellipsize (GTK_LABEL (label), group->priv->ellipsize);
+ gtk_label_set_angle (GTK_LABEL (label), 0);
+ break;
+ }
+
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), dy, 0, dx, 0);
+}
+
+static void
+egg_tool_item_group_init (EggToolItemGroup *group)
+{
+ GtkWidget *alignment;
+ GtkWidget *label;
+
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (group), FALSE);
+
+ group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
+ EGG_TYPE_TOOL_ITEM_GROUP,
+ EggToolItemGroupPrivate);
+
+ group->priv->children = NULL;
+ group->priv->header_spacing = DEFAULT_HEADER_SPACING;
+ group->priv->expander_size = DEFAULT_EXPANDER_SIZE;
+ group->priv->expander_style = GTK_EXPANDER_EXPANDED;
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_container_add (GTK_CONTAINER (alignment), label);
+ gtk_widget_show_all (alignment);
+
+ gtk_widget_push_composite_child ();
+ group->priv->header = gtk_button_new ();
+ gtk_widget_set_composite_name (group->priv->header, "header");
+ gtk_widget_pop_composite_child ();
+
+ g_object_ref_sink (group->priv->header);
+ gtk_button_set_focus_on_click (GTK_BUTTON (group->priv->header), FALSE);
+ gtk_container_add (GTK_CONTAINER (group->priv->header), alignment);
+ gtk_widget_set_parent (group->priv->header, GTK_WIDGET (group));
+
+ egg_tool_item_group_header_adjust_style (group);
+
+ g_signal_connect_after (alignment, "expose-event",
+ G_CALLBACK (egg_tool_item_group_header_expose_event_cb),
+ group);
+ g_signal_connect_after (alignment, "size-request",
+ G_CALLBACK (egg_tool_item_group_header_size_request_cb),
+ group);
+
+ g_signal_connect (group->priv->header, "clicked",
+ G_CALLBACK (egg_tool_item_group_header_clicked_cb),
+ group);
+}
+
+static void
+egg_tool_item_group_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ egg_tool_item_group_set_name (group, g_value_get_string (value));
+ break;
+
+ case PROP_COLLAPSED:
+ egg_tool_item_group_set_collapsed (group, g_value_get_boolean (value));
+ break;
+
+ case PROP_ELLIPSIZE:
+ egg_tool_item_group_set_ellipsize (group, g_value_get_enum (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_item_group_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, egg_tool_item_group_get_name (group));
+ break;
+
+ case PROP_COLLAPSED:
+ g_value_set_boolean (value, egg_tool_item_group_get_collapsed (group));
+ break;
+
+ case PROP_ELLIPSIZE:
+ g_value_set_enum (value, egg_tool_item_group_get_ellipsize (group));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_item_group_finalize (GObject *object)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (object);
+
+ if (group->priv->children)
+ {
+ g_list_free (group->priv->children);
+ group->priv->children = NULL;
+ }
+
+ G_OBJECT_CLASS (egg_tool_item_group_parent_class)->finalize (object);
+}
+
+static void
+egg_tool_item_group_get_item_size (EggToolItemGroup *group,
+ GtkRequisition *item_size)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (group));
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ _egg_tool_palette_get_item_size (EGG_TOOL_PALETTE (parent), item_size);
+ else
+ _egg_tool_item_group_item_size_request (group, item_size);
+}
+
+static void
+egg_tool_item_group_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (widget);
+ GtkOrientation orientation;
+ GtkRequisition item_size;
+
+ if (group->priv->children && egg_tool_item_group_get_name (group))
+ {
+ gtk_widget_size_request (group->priv->header, requisition);
+ gtk_widget_show (group->priv->header);
+ }
+ else
+ {
+ requisition->width = requisition->height = 0;
+ gtk_widget_hide (group->priv->header);
+ }
+
+ egg_tool_item_group_get_item_size (group, &item_size);
+
+ orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group));
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ requisition->width = MAX (requisition->width, item_size.width);
+ else
+ requisition->height = MAX (requisition->height, item_size.height);
+
+ requisition->width += border_width * 2;
+ requisition->height += border_width * 2;
+}
+
+static gboolean
+egg_tool_item_group_is_item_visible (GtkToolItem *item,
+ GtkOrientation orientation)
+{
+ return
+ (GTK_WIDGET_VISIBLE (item)) &&
+ (GTK_ORIENTATION_VERTICAL == orientation ?
+ gtk_tool_item_get_visible_vertical (item) :
+ gtk_tool_item_get_visible_horizontal (item));
+}
+
+static void
+egg_tool_item_group_real_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ GtkRequisition *inquery)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (widget);
+ GtkRequisition child_requisition;
+ GtkAllocation child_allocation;
+
+ GtkRequisition item_size;
+ GtkAllocation item_area;
+
+ GtkOrientation orientation;
+ GtkToolbarStyle style;
+
+ guint n_visible_items;
+
+ GList *it;
+
+ guint header_width = 0;
+
+ guint n_columns, n_rows;
+
+ GtkTextDirection direction = gtk_widget_get_direction (widget);
+
+ if (!inquery)
+ GTK_WIDGET_CLASS (egg_tool_item_group_parent_class)->size_allocate (widget, allocation);
+
+ orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group));
+ style = gtk_tool_shell_get_style (GTK_TOOL_SHELL (group));
+
+ /* figure out header size */
+
+ if (GTK_WIDGET_VISIBLE (group->priv->header))
+ gtk_widget_size_request (group->priv->header, &child_requisition);
+ else
+ child_requisition.width = child_requisition.height = 0;
+
+ /* figure out item size */
+
+ egg_tool_item_group_get_item_size (group, &item_size);
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ item_size.width = MIN (item_size.width, allocation->width);
+ else
+ item_size.height = MIN (item_size.height, allocation->height);
+
+ n_visible_items = 0;
+
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child = it->data;
+
+ if (egg_tool_item_group_is_item_visible (child->item, orientation))
+ n_visible_items += 1;
+ }
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ {
+ item_area.width = allocation->width - 2 * border_width;
+ n_columns = MAX (item_area.width / item_size.width, 1);
+ n_rows = (n_visible_items + n_columns - 1) / n_columns;
+ }
+ else if (inquery)
+ {
+ item_area.height = allocation->height - 2 * border_width;
+ n_rows = MAX (item_area.height / item_size.height, 1);
+ n_columns = (n_visible_items + n_rows - 1) / n_rows;
+ }
+ else
+ {
+ item_area.width = allocation->width - 2 * border_width;
+
+ if (child_requisition.width > 0)
+ item_area.width -= child_requisition.width;
+
+ n_columns = MAX (item_area.width / item_size.width, 1);
+ n_rows = (n_visible_items + n_columns - 1) / n_columns;
+ }
+
+ item_area.width = item_size.width * n_columns;
+ item_area.height = item_size.height * n_rows;
+
+ /* place the header widget */
+
+ child_allocation.x = border_width;
+ child_allocation.y = border_width;
+
+ if (GTK_WIDGET_VISIBLE (group->priv->header))
+ {
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ {
+ child_allocation.width = allocation->width;
+ child_allocation.height = child_requisition.height;
+ }
+ else
+ {
+ child_allocation.width = child_requisition.width;
+ header_width = child_allocation.width;
+ child_allocation.height = allocation->height;
+
+ if (GTK_TEXT_DIR_RTL == direction)
+ child_allocation.x = allocation->width - border_width - header_width;
+ }
+
+ if (!inquery)
+ gtk_widget_size_allocate (group->priv->header, &child_allocation);
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ child_allocation.y += child_allocation.height;
+ else if (GTK_TEXT_DIR_RTL != direction)
+ child_allocation.x += child_allocation.width;
+ else
+ child_allocation.x = border_width;
+ }
+
+ item_area.x = child_allocation.x;
+ item_area.y = child_allocation.y;
+
+ if (!inquery)
+ {
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ {
+ item_area.width = allocation->width - 2 * border_width - header_width;
+ item_size.width = item_area.width / n_columns;
+ }
+ else
+ {
+ item_area.height = allocation->height - 2 * border_width;
+ item_size.height = item_area.height / n_rows;
+ }
+ }
+
+ /* otherwise, when expanded or in transition, place the tool items */
+ if (!group->priv->collapsed || group->priv->animation_timeout)
+ {
+ guint col = 0, row = 0;
+
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child = it->data;
+
+ if (!egg_tool_item_group_is_item_visible (child->item, orientation))
+ {
+ if (!inquery)
+ gtk_widget_set_child_visible (GTK_WIDGET (child->item), FALSE);
+
+ continue;
+ }
+
+ child_requisition.width = 0;
+ if (!child->homogeneous)
+ {
+ if (GTK_ORIENTATION_HORIZONTAL == orientation && GTK_TOOLBAR_TEXT == style)
+ {
+ /* in horizontal text mode non homogneneous items are not supported */
+ gtk_widget_set_child_visible (GTK_WIDGET (child->item), FALSE);
+ continue;
+ }
+
+ gtk_widget_size_request (GTK_WIDGET (child->item), &child_requisition);
+ child_requisition.width = MIN (child_requisition.width, item_area.width);
+ }
+
+ if (col > 0 && (child->new_row || (col * item_size.width) + MAX (child_requisition.width, item_size.width) > item_area.width))
+ {
+ row++;
+ col = 0;
+ child_allocation.y += child_allocation.height;
+ }
+
+ if (!child->homogeneous)
+ {
+ guint col_width;
+ guint width;
+
+ if (child->expand)
+ col_width = n_columns - col;
+ else
+ col_width = (guint) ceil (1.0 * child_requisition.width / item_size.width);
+
+ width = col_width * item_size.width;
+
+ if (child->fill)
+ {
+ child_allocation.x = item_area.x +
+ (((GTK_TEXT_DIR_RTL == direction) ? (n_columns - col - col_width) : col) * item_size.width);
+ child_allocation.width = width;
+ }
+ else
+ {
+ child_allocation.x = item_area.x +
+ (((GTK_TEXT_DIR_RTL == direction) ? (n_columns - col - col_width) : col) * item_size.width) +
+ (width - child_requisition.width) / 2;
+ child_allocation.width = child_requisition.width;
+ }
+
+ col += col_width;
+ }
+ else
+ {
+ child_allocation.x = item_area.x +
+ (((GTK_TEXT_DIR_RTL == direction) ? (n_columns - col - 1) : col) * item_size.width);
+ child_allocation.width = item_size.width;
+
+ col++;
+ }
+
+ child_allocation.height = item_size.height;
+
+ if (!inquery)
+ {
+ gtk_widget_size_allocate (GTK_WIDGET (child->item), &child_allocation);
+ gtk_widget_set_child_visible (GTK_WIDGET (child->item), TRUE);
+ }
+ }
+
+ child_allocation.y += item_size.height;
+ }
+
+ /* or just hide all items, when collapsed */
+
+ else if (!inquery)
+ {
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child = it->data;
+
+ gtk_widget_set_child_visible (GTK_WIDGET (child->item), FALSE);
+ }
+ }
+
+ /* report effective widget size */
+
+ if (inquery)
+ {
+ inquery->width = item_area.width + header_width + 2 * border_width;
+ inquery->height = child_allocation.y + border_width;
+ }
+}
+
+static void
+egg_tool_item_group_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ egg_tool_item_group_real_size_allocate (widget, allocation, NULL);
+
+ if (GTK_WIDGET_MAPPED (widget))
+ gdk_window_invalidate_rect (widget->window, NULL, FALSE);
+}
+
+static void
+egg_tool_item_group_realize (GtkWidget *widget)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ GdkWindowAttr attributes;
+ GdkDisplay *display;
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x + border_width;
+ attributes.y = widget->allocation.y + border_width;
+ attributes.width = widget->allocation.width - border_width * 2;
+ attributes.height = widget->allocation.height - border_width * 2;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_BUTTON_MOTION_MASK;
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+
+ display = gdk_drawable_get_display (widget->window);
+
+ if (gdk_display_supports_composite (display))
+ gdk_window_set_composited (widget->window, TRUE);
+
+ gdk_window_set_user_data (widget->window, widget);
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ gtk_container_forall (GTK_CONTAINER (widget),
+ (GtkCallback) gtk_widget_set_parent_window,
+ widget->window);
+
+ gtk_widget_queue_resize_no_redraw (widget);
+}
+
+static void
+egg_tool_item_group_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ egg_tool_item_group_header_adjust_style (EGG_TOOL_ITEM_GROUP (widget));
+ GTK_WIDGET_CLASS (egg_tool_item_group_parent_class)->style_set (widget, previous_style);
+}
+
+static void
+egg_tool_item_group_add (GtkContainer *container,
+ GtkWidget *widget)
+{
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (container));
+ g_return_if_fail (GTK_IS_TOOL_ITEM (widget));
+
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (container),
+ GTK_TOOL_ITEM (widget), -1);
+}
+
+static void
+egg_tool_item_group_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ EggToolItemGroup *group;
+ GList *it;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (container));
+ group = EGG_TOOL_ITEM_GROUP (container);
+
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child_info = it->data;
+
+ if ((GtkWidget *)child_info->item == child)
+ {
+ g_object_unref (child);
+ gtk_widget_unparent (child);
+
+ g_free (child_info);
+ group->priv->children = g_list_delete_link (group->priv->children, it);
+
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ break;
+ }
+ }
+}
+
+static void
+egg_tool_item_group_forall (GtkContainer *container,
+ gboolean internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (container);
+ GList *children;
+
+ if (internals && group->priv->header)
+ callback (group->priv->header, callback_data);
+
+ children = group->priv->children;
+ while (children)
+ {
+ EggToolItemGroupChild *child = children->data;
+ children = children->next; /* store pointer before call to callback
+ because the child pointer is invalid if the
+ child->item is removed from the item group
+ in callback */
+
+ callback (GTK_WIDGET (child->item), callback_data);
+ }
+}
+
+static GType
+egg_tool_item_group_child_type (GtkContainer *container G_GNUC_UNUSED)
+{
+ return GTK_TYPE_TOOL_ITEM;
+}
+
+static EggToolItemGroupChild *
+egg_tool_item_group_get_child (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gint *position,
+ GList **link)
+{
+ guint i;
+ GList *it;
+
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), NULL);
+ g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), NULL);
+
+ for (it = group->priv->children, i = 0; it != NULL; it = it->next, ++i)
+ {
+ EggToolItemGroupChild *child = it->data;
+
+ if (child->item == item)
+ {
+ if (position)
+ *position = i;
+
+ if (link)
+ *link = it;
+
+ return child;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+egg_tool_item_group_get_item_packing (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gboolean *homogeneous,
+ gboolean *expand,
+ gboolean *fill,
+ gboolean *new_row)
+{
+ EggToolItemGroupChild *child;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ g_return_if_fail (GTK_IS_TOOL_ITEM (item));
+
+ child = egg_tool_item_group_get_child (group, item, NULL, NULL);
+ if (!child)
+ return;
+
+ if (expand)
+ *expand = child->expand;
+
+ if (homogeneous)
+ *homogeneous = child->homogeneous;
+
+ if (fill)
+ *fill = child->fill;
+
+ if (new_row)
+ *new_row = child->new_row;
+}
+
+static void
+egg_tool_item_group_set_item_packing (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gboolean homogeneous,
+ gboolean expand,
+ gboolean fill,
+ gboolean new_row)
+{
+ EggToolItemGroupChild *child;
+ gboolean changed = FALSE;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ g_return_if_fail (GTK_IS_TOOL_ITEM (item));
+
+ child = egg_tool_item_group_get_child (group, item, NULL, NULL);
+ if (!child)
+ return;
+
+ gtk_widget_freeze_child_notify (GTK_WIDGET (item));
+
+ if (child->homogeneous != homogeneous)
+ {
+ child->homogeneous = homogeneous;
+ changed = TRUE;
+ gtk_widget_child_notify (GTK_WIDGET (item), "homogeneous");
+ }
+ if (child->expand != expand)
+ {
+ child->expand = expand;
+ changed = TRUE;
+ gtk_widget_child_notify (GTK_WIDGET (item), "expand");
+ }
+ if (child->fill != fill)
+ {
+ child->fill = fill;
+ changed = TRUE;
+ gtk_widget_child_notify (GTK_WIDGET (item), "fill");
+ }
+ if (child->new_row != new_row)
+ {
+ child->new_row = new_row;
+ changed = TRUE;
+ gtk_widget_child_notify (GTK_WIDGET (item), "new-row");
+ }
+
+ gtk_widget_thaw_child_notify (GTK_WIDGET (item));
+
+ if (changed && GTK_WIDGET_VISIBLE (group) && GTK_WIDGET_VISIBLE (item))
+ gtk_widget_queue_resize (GTK_WIDGET (group));
+}
+
+static void
+egg_tool_item_group_set_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (container);
+ GtkToolItem *item = GTK_TOOL_ITEM (child);
+ gboolean homogeneous, expand, fill, new_row;
+
+ if (prop_id != CHILD_PROP_POSITION)
+ egg_tool_item_group_get_item_packing (group, item,
+ &homogeneous,
+ &expand,
+ &fill,
+ &new_row);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_HOMOGENEOUS:
+ egg_tool_item_group_set_item_packing (group, item,
+ g_value_get_boolean (value),
+ expand,
+ fill,
+ new_row);
+ break;
+
+ case CHILD_PROP_EXPAND:
+ egg_tool_item_group_set_item_packing (group, item,
+ homogeneous,
+ g_value_get_boolean (value),
+ fill,
+ new_row);
+ break;
+
+ case CHILD_PROP_FILL:
+ egg_tool_item_group_set_item_packing (group, item,
+ homogeneous,
+ expand,
+ g_value_get_boolean (value),
+ new_row);
+ break;
+
+ case CHILD_PROP_NEW_ROW:
+ egg_tool_item_group_set_item_packing (group, item,
+ homogeneous,
+ expand,
+ fill,
+ g_value_get_boolean (value));
+ break;
+
+ case CHILD_PROP_POSITION:
+ egg_tool_item_group_set_item_position (group, item, g_value_get_int (value));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_item_group_get_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (container);
+ GtkToolItem *item = GTK_TOOL_ITEM (child);
+ gboolean homogeneous, expand, fill, new_row;
+
+ if (prop_id != CHILD_PROP_POSITION)
+ egg_tool_item_group_get_item_packing (group, item,
+ &homogeneous,
+ &expand,
+ &fill,
+ &new_row);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_HOMOGENEOUS:
+ g_value_set_boolean (value, homogeneous);
+ break;
+
+ case CHILD_PROP_EXPAND:
+ g_value_set_boolean (value, expand);
+ break;
+
+ case CHILD_PROP_FILL:
+ g_value_set_boolean (value, fill);
+ break;
+
+ case CHILD_PROP_NEW_ROW:
+ g_value_set_boolean (value, new_row);
+ break;
+
+ case CHILD_PROP_POSITION:
+ g_value_set_int (value, egg_tool_item_group_get_item_position (group, item));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_item_group_class_init (EggToolItemGroupClass *cls)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (cls);
+ GtkWidgetClass *wclass = GTK_WIDGET_CLASS (cls);
+ GtkContainerClass *cclass = GTK_CONTAINER_CLASS (cls);
+
+ oclass->set_property = egg_tool_item_group_set_property;
+ oclass->get_property = egg_tool_item_group_get_property;
+ oclass->finalize = egg_tool_item_group_finalize;
+
+ wclass->size_request = egg_tool_item_group_size_request;
+ wclass->size_allocate = egg_tool_item_group_size_allocate;
+ wclass->realize = egg_tool_item_group_realize;
+ wclass->style_set = egg_tool_item_group_style_set;
+
+ cclass->add = egg_tool_item_group_add;
+ cclass->remove = egg_tool_item_group_remove;
+ cclass->forall = egg_tool_item_group_forall;
+ cclass->child_type = egg_tool_item_group_child_type;
+ cclass->set_child_property = egg_tool_item_group_set_child_property;
+ cclass->get_child_property = egg_tool_item_group_get_child_property;
+
+ g_object_class_install_property (oclass, PROP_NAME,
+ g_param_spec_string ("name",
+ P_("Name"),
+ P_("The name of this item group"),
+ DEFAULT_NAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (oclass, PROP_COLLAPSED,
+ g_param_spec_boolean ("collapsed",
+ P_("Collapsed"),
+ P_("Wether the group has been collapsed and items are hidden"),
+ DEFAULT_COLLAPSED,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (oclass, PROP_ELLIPSIZE,
+ g_param_spec_enum ("ellipsize",
+ P_("ellipsize"),
+ P_("Ellipsize for item group headers"),
+ PANGO_TYPE_ELLIPSIZE_MODE, DEFAULT_ELLIPSIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_widget_class_install_style_property (wclass,
+ g_param_spec_int ("expander-size",
+ P_("Expander Size"),
+ P_("Size of the expander arrow"),
+ 0,
+ G_MAXINT,
+ DEFAULT_EXPANDER_SIZE,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_widget_class_install_style_property (wclass,
+ g_param_spec_int ("header-spacing",
+ P_("Header Spacing"),
+ P_("Spacing between expander arrow and caption"),
+ 0,
+ G_MAXINT,
+ DEFAULT_HEADER_SPACING,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_HOMOGENEOUS,
+ g_param_spec_boolean ("homogeneous",
+ P_("Homogeneous"),
+ P_("Whether the item should be the same size as other homogeneous items"),
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_EXPAND,
+ g_param_spec_boolean ("expand",
+ P_("Expand"),
+ P_("Whether the item should receive extra space when the toolbar grows"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_FILL,
+ g_param_spec_boolean ("fill",
+ P_("Fill"),
+ P_("Whether the item should fill the avaiable space"),
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_NEW_ROW,
+ g_param_spec_boolean ("new-row",
+ P_("New Row"),
+ P_("Whether the item should start a new row"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_POSITION,
+ g_param_spec_int ("position",
+ P_("Position"),
+ P_("Position of the item within this group"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private (cls, sizeof (EggToolItemGroupPrivate));
+}
+
+GtkWidget*
+egg_tool_item_group_new (const gchar *name)
+{
+ return g_object_new (EGG_TYPE_TOOL_ITEM_GROUP, "name", name, NULL);
+}
+
+void
+egg_tool_item_group_set_name (EggToolItemGroup *group,
+ const gchar *name)
+{
+ const gchar *current_name;
+ GtkWidget *label;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ current_name = egg_tool_item_group_get_name (group);
+
+ if (current_name != name && (!current_name || !name || strcmp (current_name, name)))
+ {
+ label = egg_tool_item_group_get_label (group);
+ gtk_label_set_text (GTK_LABEL (label), name);
+
+ if (name && group->priv->children)
+ gtk_widget_show (group->priv->header);
+ else
+ gtk_widget_hide (group->priv->header);
+
+ g_object_notify (G_OBJECT (group), "name");
+ }
+}
+
+static gint64
+egg_tool_item_group_get_animation_timestamp (EggToolItemGroup *group)
+{
+ GTimeVal now;
+ g_source_get_current_time (group->priv->animation_timeout, &now);
+ return (now.tv_sec * G_USEC_PER_SEC + now.tv_usec - group->priv->animation_start) / 1000;
+}
+
+static gboolean
+egg_tool_item_group_animation_cb (gpointer data)
+{
+ EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (data);
+ gint64 timestamp = egg_tool_item_group_get_animation_timestamp (group);
+
+ /* enque this early to reduce number of expose events */
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (group));
+
+ if (GTK_WIDGET_REALIZED (group->priv->header))
+ {
+ GtkWidget *alignment = egg_tool_item_group_get_alignment (group);
+ GdkRectangle area;
+
+ area.x = alignment->allocation.x;
+ area.y = alignment->allocation.y + (alignment->allocation.height - group->priv->expander_size) / 2;
+ area.height = group->priv->expander_size;
+ area.width = group->priv->expander_size;
+
+ gdk_window_invalidate_rect (group->priv->header->window, &area, TRUE);
+ }
+
+ if (GTK_WIDGET_REALIZED (group))
+ {
+ GtkWidget *widget = GTK_WIDGET (group);
+ GtkWidget *parent = gtk_widget_get_parent (widget);
+
+ gint width = widget->allocation.width;
+ gint height = widget->allocation.height;
+ gint x, y;
+
+ gtk_widget_translate_coordinates (widget, parent, 0, 0, &x, &y);
+
+ if (GTK_WIDGET_VISIBLE (group->priv->header))
+ {
+ height -= group->priv->header->allocation.height;
+ y += group->priv->header->allocation.height;
+ }
+
+ gtk_widget_queue_draw_area (parent, x, y, width, height);
+ }
+
+ if (group->priv->collapsed)
+ {
+ if (group->priv->expander_style == GTK_EXPANDER_EXPANDED)
+ group->priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
+ else
+ group->priv->expander_style = GTK_EXPANDER_COLLAPSED;
+ }
+ else
+ {
+ if (group->priv->expander_style == GTK_EXPANDER_COLLAPSED)
+ group->priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
+ else
+ group->priv->expander_style = GTK_EXPANDER_EXPANDED;
+ }
+
+ if (timestamp >= ANIMATION_DURATION)
+ group->priv->animation_timeout = NULL;
+
+ /* Ensure that all composited windows and child windows are repainted, before
+ * the parent widget gets its expose-event. This is needed to avoid heavy
+ * rendering artifacts. GTK+ should take care about this issue by itself I
+ * guess, but currently it doesn't. Also I don't understand the parameters
+ * of this issue well enough yet, to file a bug report.
+ */
+ gdk_window_process_updates (GTK_WIDGET (group)->window, TRUE);
+
+ return (group->priv->animation_timeout != NULL);
+}
+
+void
+egg_tool_item_group_set_collapsed (EggToolItemGroup *group,
+ gboolean collapsed)
+{
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+
+ if (collapsed != group->priv->collapsed)
+ {
+ GTimeVal now;
+ GtkWidget *parent;
+
+ g_get_current_time (&now);
+
+ if (group->priv->animation_timeout)
+ g_source_destroy (group->priv->animation_timeout);
+
+ group->priv->collapsed = collapsed;
+ group->priv->animation_start = (now.tv_sec * G_USEC_PER_SEC + now.tv_usec);
+ group->priv->animation_timeout = g_timeout_source_new (ANIMATION_TIMEOUT);
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (group));
+ if (EGG_IS_TOOL_PALETTE (parent) && !collapsed)
+ _egg_tool_palette_set_expanding_child (EGG_TOOL_PALETTE (parent), GTK_WIDGET (group));
+
+ g_source_set_callback (group->priv->animation_timeout,
+ egg_tool_item_group_animation_cb,
+ group, NULL);
+
+ g_source_attach (group->priv->animation_timeout, NULL);
+ g_object_notify (G_OBJECT (group), "collapsed");
+ }
+}
+
+void
+egg_tool_item_group_set_ellipsize (EggToolItemGroup *group,
+ PangoEllipsizeMode ellipsize)
+{
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+
+ if (ellipsize != group->priv->ellipsize)
+ {
+ group->priv->ellipsize = ellipsize;
+ egg_tool_item_group_header_adjust_style (group);
+ g_object_notify (G_OBJECT (group), "ellipsize");
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+ _egg_tool_item_group_palette_reconfigured (group);
+#endif
+ }
+}
+
+G_CONST_RETURN gchar*
+egg_tool_item_group_get_name (EggToolItemGroup *group)
+{
+ GtkWidget *label;
+
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), DEFAULT_NAME);
+
+ label = egg_tool_item_group_get_label (group);
+ return gtk_label_get_text (GTK_LABEL (label));
+}
+
+gboolean
+egg_tool_item_group_get_collapsed (EggToolItemGroup *group)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), DEFAULT_COLLAPSED);
+ return group->priv->collapsed;
+}
+
+PangoEllipsizeMode
+egg_tool_item_group_get_ellipsize (EggToolItemGroup *group)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), DEFAULT_ELLIPSIZE);
+ return group->priv->ellipsize;
+}
+
+void
+egg_tool_item_group_insert (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gint position)
+{
+ GtkWidget *parent;
+ EggToolItemGroupChild *child;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ g_return_if_fail (GTK_IS_TOOL_ITEM (item));
+ g_return_if_fail (position >= -1);
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (group));
+
+ child = g_new (EggToolItemGroupChild, 1);
+ child->item = g_object_ref_sink (item);
+ child->homogeneous = TRUE;
+ child->expand = FALSE;
+ child->fill = TRUE;
+ child->new_row = FALSE;
+
+ group->priv->children = g_list_insert (group->priv->children, child, position);
+
+ if (EGG_IS_TOOL_PALETTE (parent))
+ _egg_tool_palette_child_set_drag_source (GTK_WIDGET (item), parent);
+
+ gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (group));
+}
+
+void
+egg_tool_item_group_set_item_position (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gint position)
+{
+ gint old_position;
+ GList *link;
+ EggToolItemGroupChild *child;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ g_return_if_fail (GTK_IS_TOOL_ITEM (item));
+
+ g_return_if_fail (position >= -1);
+
+ child = egg_tool_item_group_get_child (group, item, &old_position, &link);
+
+ g_return_if_fail (child != NULL);
+
+ if (position == old_position)
+ return;
+
+ group->priv->children = g_list_delete_link (group->priv->children, link);
+ group->priv->children = g_list_insert (group->priv->children, child, position);
+
+ gtk_widget_child_notify (GTK_WIDGET (item), "position");
+ if (GTK_WIDGET_VISIBLE (group) && GTK_WIDGET_VISIBLE (item))
+ gtk_widget_queue_resize (GTK_WIDGET (group));
+}
+
+gint
+egg_tool_item_group_get_item_position (EggToolItemGroup *group,
+ GtkToolItem *item)
+{
+ gint position;
+
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), -1);
+ g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
+
+ if (egg_tool_item_group_get_child (group, item, &position, NULL))
+ return position;
+
+ return -1;
+}
+
+guint
+egg_tool_item_group_get_n_items (EggToolItemGroup *group)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), 0);
+
+ return g_list_length (group->priv->children);
+}
+
+GtkToolItem*
+egg_tool_item_group_get_nth_item (EggToolItemGroup *group,
+ guint index)
+{
+ EggToolItemGroupChild *child;
+
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), NULL);
+
+ child = g_list_nth_data (group->priv->children, index);
+
+ return child != NULL ? child->item : NULL;
+}
+
+GtkToolItem*
+egg_tool_item_group_get_drop_item (EggToolItemGroup *group,
+ gint x,
+ gint y)
+{
+ GtkAllocation *allocation;
+ GtkOrientation orientation;
+ GList *it;
+
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), NULL);
+
+ allocation = >K_WIDGET (group)->allocation;
+ orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group));
+
+ g_return_val_if_fail (x >= 0 && x < allocation->width, NULL);
+ g_return_val_if_fail (y >= 0 && y < allocation->height, NULL);
+
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child = it->data;
+ GtkToolItem *item = child->item;
+ gint x0, y0;
+
+ if (!item || !egg_tool_item_group_is_item_visible (item, orientation))
+ continue;
+
+ allocation = >K_WIDGET (item)->allocation;
+
+ x0 = x - allocation->x;
+ y0 = y - allocation->y;
+
+ if (x0 >= 0 && x0 < allocation->width &&
+ y0 >= 0 && y0 < allocation->height)
+ return item;
+ }
+
+ return NULL;
+}
+
+void
+_egg_tool_item_group_item_size_request (EggToolItemGroup *group,
+ GtkRequisition *item_size)
+{
+ GtkRequisition child_requisition;
+ GList *it;
+
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+ g_return_if_fail (NULL != item_size);
+
+ item_size->width = item_size->height = 0;
+
+ for (it = group->priv->children; it != NULL; it = it->next)
+ {
+ EggToolItemGroupChild *child = it->data;
+
+ gtk_widget_size_request (GTK_WIDGET (child->item), &child_requisition);
+
+ if (child->homogeneous)
+ item_size->width = MAX (item_size->width, child_requisition.width);
+ item_size->height = MAX (item_size->height, child_requisition.height);
+ }
+}
+
+void
+_egg_tool_item_group_paint (EggToolItemGroup *group,
+ cairo_t *cr)
+{
+ GtkWidget *widget = GTK_WIDGET (group);
+
+ gdk_cairo_set_source_pixmap (cr, widget->window,
+ widget->allocation.x,
+ widget->allocation.y);
+
+ if (group->priv->animation_timeout)
+ {
+ GtkOrientation orientation = egg_tool_item_group_get_orientation (GTK_TOOL_SHELL (group));
+ cairo_pattern_t *mask;
+ gdouble v0, v1;
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ v1 = widget->allocation.height;
+ else
+ v1 = widget->allocation.width;
+
+ v0 = v1 - 256;
+
+ if (!GTK_WIDGET_VISIBLE (group->priv->header))
+ v0 = MAX (v0, 0);
+ else if (GTK_ORIENTATION_VERTICAL == orientation)
+ v0 = MAX (v0, group->priv->header->allocation.height);
+ else
+ v0 = MAX (v0, group->priv->header->allocation.width);
+
+ v1 = MIN (v0 + 256, v1);
+
+ if (GTK_ORIENTATION_VERTICAL == orientation)
+ {
+ v0 += widget->allocation.y;
+ v1 += widget->allocation.y;
+
+ mask = cairo_pattern_create_linear (0.0, v0, 0.0, v1);
+ }
+ else
+ {
+ v0 += widget->allocation.x;
+ v1 += widget->allocation.x;
+
+ mask = cairo_pattern_create_linear (v0, 0.0, v1, 0.0);
+ }
+
+ cairo_pattern_add_color_stop_rgba (mask, 0.00, 0.0, 0.0, 0.0, 1.00);
+ cairo_pattern_add_color_stop_rgba (mask, 0.25, 0.0, 0.0, 0.0, 0.25);
+ cairo_pattern_add_color_stop_rgba (mask, 0.50, 0.0, 0.0, 0.0, 0.10);
+ cairo_pattern_add_color_stop_rgba (mask, 0.75, 0.0, 0.0, 0.0, 0.01);
+ cairo_pattern_add_color_stop_rgba (mask, 1.00, 0.0, 0.0, 0.0, 0.00);
+
+ cairo_mask (cr, mask);
+ cairo_pattern_destroy (mask);
+ }
+ else
+ cairo_paint (cr);
+}
+
+gint
+_egg_tool_item_group_get_size_for_limit (EggToolItemGroup *group,
+ gint limit,
+ gboolean vertical,
+ gboolean animation)
+{
+ GtkRequisition requisition;
+
+ gtk_widget_size_request (GTK_WIDGET (group), &requisition);
+
+ if (!group->priv->collapsed || group->priv->animation_timeout)
+ {
+ GtkAllocation allocation = { 0, 0, requisition.width, requisition.height };
+ GtkRequisition inquery;
+
+ if (vertical)
+ allocation.width = limit;
+ else
+ allocation.height = limit;
+
+ egg_tool_item_group_real_size_allocate (GTK_WIDGET (group),
+ &allocation, &inquery);
+
+ if (vertical)
+ inquery.height -= requisition.height;
+ else
+ inquery.width -= requisition.width;
+
+ if (group->priv->animation_timeout && animation)
+ {
+ gint64 timestamp = egg_tool_item_group_get_animation_timestamp (group);
+
+ timestamp = MIN (timestamp, ANIMATION_DURATION);
+
+ if (group->priv->collapsed)
+ timestamp = ANIMATION_DURATION - timestamp;
+
+ if (vertical)
+ {
+ inquery.height *= timestamp;
+ inquery.height /= ANIMATION_DURATION;
+ }
+ else
+ {
+ inquery.width *= timestamp;
+ inquery.width /= ANIMATION_DURATION;
+ }
+ }
+
+ if (vertical)
+ requisition.height += inquery.height;
+ else
+ requisition.width += inquery.width;
+ }
+
+ return (vertical ? requisition.height : requisition.width);
+}
+
+gint
+_egg_tool_item_group_get_height_for_width (EggToolItemGroup *group,
+ gint width)
+{
+ return _egg_tool_item_group_get_size_for_limit (group, width, TRUE, TRUE);
+}
+
+gint
+_egg_tool_item_group_get_width_for_height (EggToolItemGroup *group,
+ gint height)
+{
+ return _egg_tool_item_group_get_size_for_limit (group, height, FALSE, TRUE);
+}
+
+#ifdef GTK_TYPE_TOOL_SHELL
+
+static void
+egg_tool_palette_reconfigured_foreach_item (GtkWidget *child,
+ gpointer data G_GNUC_UNUSED)
+{
+ if (GTK_IS_TOOL_ITEM (child))
+ gtk_tool_item_toolbar_reconfigured (GTK_TOOL_ITEM (child));
+}
+
+#endif /* GTK_TYPE_TOOL_SHELL */
+
+void
+_egg_tool_item_group_palette_reconfigured (EggToolItemGroup *group)
+{
+#ifdef GTK_TYPE_TOOL_SHELL
+
+ gtk_container_foreach (GTK_CONTAINER (group),
+ egg_tool_palette_reconfigured_foreach_item,
+ NULL);
+
+#endif /* GTK_TYPE_TOOL_SHELL */
+
+ egg_tool_item_group_header_adjust_style (group);
+}
Added: trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggtoolitemgroup.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,84 @@
+/* EggToolPalette -- A tool palette with categories and DnD support
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#ifndef __EGG_TOOL_ITEM_GROUP_H__
+#define __EGG_TOOL_ITEM_GROUP_H__
+
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtktoolitem.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TOOL_ITEM_GROUP (egg_tool_item_group_get_type())
+#define EGG_TOOL_ITEM_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, EGG_TYPE_TOOL_ITEM_GROUP, EggToolItemGroup))
+#define EGG_TOOL_ITEM_GROUP_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, EGG_TYPE_TOOL_ITEM_GROUP, EggToolItemGroupClass))
+#define EGG_IS_TOOL_ITEM_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, EGG_TYPE_TOOL_ITEM_GROUP))
+#define EGG_IS_TOOL_ITEM_GROUP_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, EGG_TYPE_TOOL_ITEM_GROUP))
+#define EGG_TOOL_ITEM_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOOL_ITEM_GROUP, EggToolItemGroupClass))
+
+typedef struct _EggToolItemGroup EggToolItemGroup;
+typedef struct _EggToolItemGroupClass EggToolItemGroupClass;
+typedef struct _EggToolItemGroupPrivate EggToolItemGroupPrivate;
+
+struct _EggToolItemGroup
+{
+ GtkContainer parent_instance;
+ EggToolItemGroupPrivate *priv;
+};
+
+struct _EggToolItemGroupClass
+{
+ GtkContainerClass parent_class;
+};
+
+GType egg_tool_item_group_get_type (void) G_GNUC_CONST;
+GtkWidget* egg_tool_item_group_new (const gchar *name);
+
+void egg_tool_item_group_set_name (EggToolItemGroup *group,
+ const gchar *name);
+void egg_tool_item_group_set_collapsed (EggToolItemGroup *group,
+ gboolean collapsed);
+void egg_tool_item_group_set_ellipsize (EggToolItemGroup *group,
+ PangoEllipsizeMode ellipsize);
+
+G_CONST_RETURN gchar* egg_tool_item_group_get_name (EggToolItemGroup *group);
+gboolean egg_tool_item_group_get_collapsed (EggToolItemGroup *group);
+PangoEllipsizeMode egg_tool_item_group_get_ellipsize (EggToolItemGroup *group);
+
+void egg_tool_item_group_insert (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gint position);
+void egg_tool_item_group_set_item_position (EggToolItemGroup *group,
+ GtkToolItem *item,
+ gint position);
+gint egg_tool_item_group_get_item_position (EggToolItemGroup *group,
+ GtkToolItem *item);
+
+guint egg_tool_item_group_get_n_items (EggToolItemGroup *group);
+GtkToolItem* egg_tool_item_group_get_nth_item (EggToolItemGroup *group,
+ guint index);
+GtkToolItem* egg_tool_item_group_get_drop_item (EggToolItemGroup *group,
+ gint x,
+ gint y);
+
+G_END_DECLS
+
+#endif /* __EGG_TOOL_ITEM_GROUP_H__ */
Added: trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.c
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.c Mon Jun 16 10:23:15 2008
@@ -0,0 +1,1356 @@
+/* EggToolPalette -- A tool palette with categories and DnD support
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#include "eggtoolpalette.h"
+#include "eggtoolpaletteprivate.h"
+#include "eggtoolitemgroup.h"
+#include "eggmarshalers.h"
+
+#include <gtk/gtk.h>
+#include <string.h>
+
+#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_SMALL_TOOLBAR
+#define DEFAULT_ORIENTATION GTK_ORIENTATION_VERTICAL
+#define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_ICONS
+
+#define DEFAULT_CHILD_EXCLUSIVE FALSE
+#define DEFAULT_CHILD_EXPAND FALSE
+
+#define P_(msgid) (msgid)
+
+typedef struct _EggToolItemGroupInfo EggToolItemGroupInfo;
+typedef struct _EggToolPaletteDragData EggToolPaletteDragData;
+
+enum
+{
+ PROP_NONE,
+ PROP_ICON_SIZE,
+ PROP_ORIENTATION,
+ PROP_TOOLBAR_STYLE,
+};
+
+enum
+{
+ CHILD_PROP_NONE,
+ CHILD_PROP_EXCLUSIVE,
+ CHILD_PROP_EXPAND,
+};
+
+struct _EggToolItemGroupInfo
+{
+ EggToolItemGroup *widget;
+
+ guint notify_collapsed;
+ guint exclusive : 1;
+ guint expand : 1;
+};
+
+struct _EggToolPalettePrivate
+{
+ EggToolItemGroupInfo *groups;
+ gsize groups_size;
+ gsize groups_length;
+
+ GtkAdjustment *hadjustment;
+ GtkAdjustment *vadjustment;
+
+ GtkRequisition item_size;
+ GtkIconSize icon_size;
+ GtkOrientation orientation;
+ GtkToolbarStyle style;
+
+ GtkWidget *expanding_child;
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+ GtkSizeGroup *text_size_group;
+#endif
+
+ guint sparse_groups : 1;
+ guint drag_source : 1;
+};
+
+struct _EggToolPaletteDragData
+{
+ EggToolPalette *palette;
+ GtkWidget *item;
+};
+
+static GdkAtom dnd_target_atom_item = GDK_NONE;
+static GdkAtom dnd_target_atom_group = GDK_NONE;
+
+static const GtkTargetEntry dnd_targets[] =
+{
+ { "application/x-egg-tool-palette-item", GTK_TARGET_SAME_APP, 0 },
+ { "application/x-egg-tool-palette-group", GTK_TARGET_SAME_APP, 0 },
+};
+
+G_DEFINE_TYPE (EggToolPalette,
+ egg_tool_palette,
+ GTK_TYPE_CONTAINER);
+
+static void
+egg_tool_palette_init (EggToolPalette *palette)
+{
+ palette->priv = G_TYPE_INSTANCE_GET_PRIVATE (palette,
+ EGG_TYPE_TOOL_PALETTE,
+ EggToolPalettePrivate);
+
+ palette->priv->groups_size = 4;
+ palette->priv->groups_length = 0;
+ palette->priv->groups = g_new0 (EggToolItemGroupInfo, palette->priv->groups_size);
+
+ palette->priv->icon_size = DEFAULT_ICON_SIZE;
+ palette->priv->orientation = DEFAULT_ORIENTATION;
+ palette->priv->style = DEFAULT_TOOLBAR_STYLE;
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+ palette->priv->text_size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
+#endif
+}
+
+static void
+egg_tool_palette_reconfigured (EggToolPalette *palette)
+{
+ guint i;
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ if (palette->priv->groups[i].widget)
+ _egg_tool_item_group_palette_reconfigured (palette->priv->groups[i].widget);
+ }
+
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (palette));
+}
+
+static void
+egg_tool_palette_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ICON_SIZE:
+ if ((guint) g_value_get_enum (value) != palette->priv->icon_size)
+ {
+ palette->priv->icon_size = g_value_get_enum (value);
+ egg_tool_palette_reconfigured (palette);
+ }
+ break;
+
+ case PROP_ORIENTATION:
+ if ((guint) g_value_get_enum (value) != palette->priv->orientation)
+ {
+ palette->priv->orientation = g_value_get_enum (value);
+ egg_tool_palette_reconfigured (palette);
+ }
+ break;
+
+ case PROP_TOOLBAR_STYLE:
+ if ((guint) g_value_get_enum (value) != palette->priv->style)
+ {
+ palette->priv->style = g_value_get_enum (value);
+ egg_tool_palette_reconfigured (palette);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_palette_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ICON_SIZE:
+ g_value_set_enum (value, egg_tool_palette_get_icon_size (palette));
+ break;
+
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, egg_tool_palette_get_orientation (palette));
+ break;
+
+ case PROP_TOOLBAR_STYLE:
+ g_value_set_enum (value, egg_tool_palette_get_style (palette));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_palette_dispose (GObject *object)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (object);
+ guint i;
+
+ if (palette->priv->hadjustment)
+ {
+ g_object_unref (palette->priv->hadjustment);
+ palette->priv->hadjustment = NULL;
+ }
+
+ if (palette->priv->vadjustment)
+ {
+ g_object_unref (palette->priv->vadjustment);
+ palette->priv->vadjustment = NULL;
+ }
+
+ for (i = 0; i < palette->priv->groups_size; ++i)
+ {
+ EggToolItemGroupInfo *group = &palette->priv->groups[i];
+
+ if (group->notify_collapsed)
+ {
+ g_signal_handler_disconnect (group->widget, group->notify_collapsed);
+ group->notify_collapsed = 0;
+ }
+ }
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+ if (palette->priv->text_size_group)
+ {
+ g_object_unref (palette->priv->text_size_group);
+ palette->priv->text_size_group = NULL;
+ }
+#endif
+
+ G_OBJECT_CLASS (egg_tool_palette_parent_class)->dispose (object);
+}
+
+static void
+egg_tool_palette_finalize (GObject *object)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (object);
+
+ if (palette->priv->groups)
+ {
+ palette->priv->groups_length = 0;
+ g_free (palette->priv->groups);
+ palette->priv->groups = NULL;
+ }
+
+ G_OBJECT_CLASS (egg_tool_palette_parent_class)->finalize (object);
+}
+
+static void
+egg_tool_palette_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
+ GtkRequisition child_requisition;
+ guint i;
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ palette->priv->item_size.width = 0;
+ palette->priv->item_size.height = 0;
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ EggToolItemGroupInfo *group = &palette->priv->groups[i];
+
+ if (!group->widget)
+ continue;
+
+ gtk_widget_size_request (GTK_WIDGET (group->widget), &child_requisition);
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ {
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+ }
+ else
+ {
+ requisition->width += child_requisition.width;
+ requisition->height = MAX (requisition->height, child_requisition.height);
+ }
+
+ _egg_tool_item_group_item_size_request (group->widget, &child_requisition);
+
+ palette->priv->item_size.width = MAX (palette->priv->item_size.width,
+ child_requisition.width);
+ palette->priv->item_size.height = MAX (palette->priv->item_size.height,
+ child_requisition.height);
+ }
+
+ requisition->width += border_width * 2;
+ requisition->height += border_width * 2;
+}
+
+static void
+egg_tool_palette_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
+ GtkAdjustment *adjustment = NULL;
+ GtkAllocation child_allocation;
+
+ gint n_expand_groups = 0;
+ gint remaining_space = 0;
+ gint expand_space = 0;
+
+ gint page_start, page_size = 0;
+ gint offset = 0;
+ guint i;
+
+ gint min_offset = -1, max_offset = -1;
+
+ gint x;
+
+ gint *group_sizes = g_newa(gint, palette->priv->groups_length);
+
+ GtkTextDirection direction = gtk_widget_get_direction (widget);
+
+ GTK_WIDGET_CLASS (egg_tool_palette_parent_class)->size_allocate (widget, allocation);
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ {
+ adjustment = palette->priv->vadjustment;
+ page_size = allocation->height;
+ }
+ else
+ {
+ adjustment = palette->priv->hadjustment;
+ page_size = allocation->width;
+ }
+
+ if (adjustment)
+ offset = gtk_adjustment_get_value (adjustment);
+ if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
+ GTK_TEXT_DIR_RTL == direction)
+ offset = -offset;
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ child_allocation.width = allocation->width - border_width * 2;
+ else
+ child_allocation.height = allocation->height - border_width * 2;
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ remaining_space = allocation->height;
+ else
+ remaining_space = allocation->width;
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ EggToolItemGroupInfo *group = &palette->priv->groups[i];
+ gint size;
+
+ if (!group->widget)
+ continue;
+
+ widget = GTK_WIDGET (group->widget);
+
+ if (egg_tool_item_group_get_n_items (group->widget))
+ {
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ size = _egg_tool_item_group_get_height_for_width (group->widget, child_allocation.width);
+ else
+ size = _egg_tool_item_group_get_width_for_height (group->widget, child_allocation.height);
+
+ if (group->expand && !egg_tool_item_group_get_collapsed (group->widget))
+ n_expand_groups += 1;
+ }
+ else
+ size = 0;
+
+ remaining_space -= size;
+ group_sizes[i] = size;
+
+ if (widget == palette->priv->expanding_child)
+ {
+ gint j, real_size;
+ gint limit = GTK_ORIENTATION_VERTICAL == palette->priv->orientation ? child_allocation.width : child_allocation.height;
+
+ min_offset = 0;
+ for (j = 0; j < i; ++j)
+ {
+ min_offset += group_sizes[j];
+ }
+ max_offset = min_offset + group_sizes[i];
+
+ real_size = _egg_tool_item_group_get_size_for_limit (EGG_TOOL_ITEM_GROUP (widget),
+ limit,
+ GTK_ORIENTATION_VERTICAL == palette->priv->orientation,
+ FALSE);
+ if (size == real_size)
+ palette->priv->expanding_child = NULL;
+ }
+ }
+
+ if (n_expand_groups > 0)
+ {
+ remaining_space = MAX (0, remaining_space);
+ expand_space = remaining_space / n_expand_groups;
+ }
+
+ if (max_offset != -1)
+ {
+ gint limit = GTK_ORIENTATION_VERTICAL == palette->priv->orientation ? allocation->height : allocation->width;
+
+ offset = MIN(MAX (offset, max_offset - limit), min_offset);
+ }
+
+ if (remaining_space > 0)
+ offset = 0;
+
+ x = border_width;
+ child_allocation.y = border_width;
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ child_allocation.y -= offset;
+ else
+ x -= offset;
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ EggToolItemGroupInfo *group = &palette->priv->groups[i];
+ GtkWidget *widget;
+
+ if (!group->widget)
+ continue;
+
+ widget = GTK_WIDGET (group->widget);
+
+ if (egg_tool_item_group_get_n_items (group->widget))
+ {
+ gint size = group_sizes[i];
+
+ if (group->expand && !egg_tool_item_group_get_collapsed (group->widget))
+ {
+ size += MIN (expand_space, remaining_space);
+ remaining_space -= expand_space;
+ }
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ child_allocation.height = size;
+ else
+ child_allocation.width = size;
+
+ if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
+ GTK_TEXT_DIR_RTL == direction)
+ child_allocation.x = allocation->width - x - child_allocation.width;
+ else
+ child_allocation.x = x;
+
+ gtk_widget_size_allocate (widget, &child_allocation);
+ gtk_widget_show (widget);
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ child_allocation.y += child_allocation.height;
+ else
+ x += child_allocation.width;
+ }
+ else
+ gtk_widget_hide (widget);
+ }
+
+ if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
+ {
+ child_allocation.y += border_width;
+ child_allocation.y += offset;
+
+ page_start = child_allocation.y;
+ }
+ else
+ {
+ x += border_width;
+ x += offset;
+
+ page_start = x;
+ }
+
+ if (adjustment)
+ {
+ gdouble value;
+
+ adjustment->page_increment = page_size * 0.9;
+ adjustment->step_increment = page_size * 0.1;
+ adjustment->page_size = page_size;
+ if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
+ GTK_TEXT_DIR_RTL == direction)
+ {
+ adjustment->lower = page_size - MAX (0, page_start);
+ adjustment->upper = page_size;
+
+ offset = -offset;
+
+ value = MAX(offset, adjustment->lower);
+ gtk_adjustment_clamp_page (adjustment, offset, value + page_size);
+ }
+ else
+ {
+ adjustment->lower = 0;
+ adjustment->upper = MAX (0, page_start);
+
+ value = MIN (offset, adjustment->upper - adjustment->page_size);
+ gtk_adjustment_clamp_page (adjustment, value, offset + page_size);
+ }
+
+ gtk_adjustment_changed (adjustment);
+ }
+}
+
+static gboolean
+egg_tool_palette_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
+ GdkDisplay *display;
+ cairo_t *cr;
+ guint i;
+
+ display = gdk_drawable_get_display (widget->window);
+
+ if (!gdk_display_supports_composite (display))
+ return FALSE;
+
+ cr = gdk_cairo_create (widget->window);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ if (palette->priv->groups[i].widget)
+ _egg_tool_item_group_paint (palette->priv->groups[i].widget, cr);
+
+ cairo_pop_group_to_source (cr);
+
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static void
+egg_tool_palette_realize (GtkWidget *widget)
+{
+ const gint border_width = GTK_CONTAINER (widget)->border_width;
+ gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ GdkWindowAttr attributes;
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x + border_width;
+ attributes.y = widget->allocation.y + border_width;
+ attributes.width = widget->allocation.width - border_width * 2;
+ attributes.height = widget->allocation.height - border_width * 2;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_BUTTON_MOTION_MASK;
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+
+ gdk_window_set_user_data (widget->window, widget);
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ gtk_container_forall (GTK_CONTAINER (widget),
+ (GtkCallback) gtk_widget_set_parent_window,
+ widget->window);
+
+ gtk_widget_queue_resize_no_redraw (widget);
+}
+
+static void
+egg_tool_palette_adjustment_value_changed (GtkAdjustment *adjustment G_GNUC_UNUSED,
+ gpointer data)
+{
+ GtkWidget *widget = GTK_WIDGET (data);
+ egg_tool_palette_size_allocate (widget, &widget->allocation);
+}
+
+static void
+egg_tool_palette_set_scroll_adjustments (GtkWidget *widget,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
+
+ if (palette->priv->hadjustment)
+ g_object_unref (palette->priv->hadjustment);
+ if (palette->priv->vadjustment)
+ g_object_unref (palette->priv->vadjustment);
+
+ if (hadjustment)
+ g_object_ref_sink (hadjustment);
+ if (vadjustment)
+ g_object_ref_sink (vadjustment);
+
+ palette->priv->hadjustment = hadjustment;
+ palette->priv->vadjustment = vadjustment;
+
+ if (palette->priv->hadjustment)
+ g_signal_connect (palette->priv->hadjustment, "value-changed",
+ G_CALLBACK (egg_tool_palette_adjustment_value_changed),
+ palette);
+ if (palette->priv->vadjustment)
+ g_signal_connect (palette->priv->vadjustment, "value-changed",
+ G_CALLBACK (egg_tool_palette_adjustment_value_changed),
+ palette);
+}
+
+static void
+egg_tool_palette_repack (EggToolPalette *palette)
+{
+ guint si, di;
+
+ for (si = di = 0; di < palette->priv->groups_length; ++si)
+ {
+ if (palette->priv->groups[si].widget)
+ {
+ palette->priv->groups[di] = palette->priv->groups[si];
+ ++di;
+ }
+ else
+ --palette->priv->groups_length;
+ }
+
+ palette->priv->sparse_groups = FALSE;
+}
+
+static void
+egg_tool_palette_add (GtkContainer *container,
+ GtkWidget *child)
+{
+ EggToolPalette *palette;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (container));
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (child));
+
+ palette = EGG_TOOL_PALETTE (container);
+
+ if (palette->priv->groups_length == palette->priv->groups_size)
+ egg_tool_palette_repack (palette);
+
+ if (palette->priv->groups_length == palette->priv->groups_size)
+ {
+ gsize old_size = palette->priv->groups_size;
+ gsize new_size = old_size * 2;
+
+ palette->priv->groups = g_renew (EggToolItemGroupInfo,
+ palette->priv->groups,
+ new_size);
+
+ memset (palette->priv->groups + old_size, 0,
+ sizeof (EggToolItemGroupInfo) * old_size);
+
+ palette->priv->groups_size = new_size;
+ }
+
+ palette->priv->groups[palette->priv->groups_length].widget = g_object_ref_sink (child);
+ palette->priv->groups_length += 1;
+
+ gtk_widget_set_parent (child, GTK_WIDGET (palette));
+}
+
+static void
+egg_tool_palette_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ EggToolPalette *palette;
+ guint i;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (container));
+ palette = EGG_TOOL_PALETTE (container);
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ if ((GtkWidget*) palette->priv->groups[i].widget == child)
+ {
+ g_object_unref (child);
+ gtk_widget_unparent (child);
+
+ memset (&palette->priv->groups[i], 0, sizeof (EggToolItemGroupInfo));
+ palette->priv->sparse_groups = TRUE;
+ }
+}
+
+static void
+egg_tool_palette_forall (GtkContainer *container,
+ gboolean internals G_GNUC_UNUSED,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (container);
+ guint i;
+
+ if (palette->priv->groups)
+ {
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ if (palette->priv->groups[i].widget)
+ callback (GTK_WIDGET (palette->priv->groups[i].widget),
+ callback_data);
+ }
+}
+
+static GType
+egg_tool_palette_child_type (GtkContainer *container G_GNUC_UNUSED)
+{
+ return EGG_TYPE_TOOL_ITEM_GROUP;
+}
+
+static void
+egg_tool_palette_set_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (container);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_EXCLUSIVE:
+ egg_tool_palette_set_exclusive (palette, child, g_value_get_boolean (value));
+ break;
+
+ case CHILD_PROP_EXPAND:
+ egg_tool_palette_set_expand (palette, child, g_value_get_boolean (value));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_palette_get_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (container);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_EXCLUSIVE:
+ g_value_set_boolean (value, egg_tool_palette_get_exclusive (palette, child));
+ break;
+
+ case CHILD_PROP_EXPAND:
+ g_value_set_boolean (value, egg_tool_palette_get_expand (palette, child));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tool_palette_class_init (EggToolPaletteClass *cls)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (cls);
+ GtkWidgetClass *wclass = GTK_WIDGET_CLASS (cls);
+ GtkContainerClass *cclass = GTK_CONTAINER_CLASS (cls);
+
+ oclass->set_property = egg_tool_palette_set_property;
+ oclass->get_property = egg_tool_palette_get_property;
+ oclass->dispose = egg_tool_palette_dispose;
+ oclass->finalize = egg_tool_palette_finalize;
+
+ wclass->size_request = egg_tool_palette_size_request;
+ wclass->size_allocate = egg_tool_palette_size_allocate;
+ wclass->expose_event = egg_tool_palette_expose_event;
+ wclass->realize = egg_tool_palette_realize;
+
+ cclass->add = egg_tool_palette_add;
+ cclass->remove = egg_tool_palette_remove;
+ cclass->forall = egg_tool_palette_forall;
+ cclass->child_type = egg_tool_palette_child_type;
+ cclass->set_child_property = egg_tool_palette_set_child_property;
+ cclass->get_child_property = egg_tool_palette_get_child_property;
+
+ cls->set_scroll_adjustments = egg_tool_palette_set_scroll_adjustments;
+
+ wclass->set_scroll_adjustments_signal =
+ g_signal_new ("set-scroll-adjustments",
+ G_TYPE_FROM_CLASS (oclass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggToolPaletteClass, set_scroll_adjustments),
+ NULL, NULL,
+ _egg_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_ADJUSTMENT,
+ GTK_TYPE_ADJUSTMENT);
+
+ g_object_class_install_property (oclass, PROP_ICON_SIZE,
+ g_param_spec_enum ("icon-size",
+ P_("Icon Size"),
+ P_("The size of palette icons"),
+ GTK_TYPE_ICON_SIZE,
+ DEFAULT_ICON_SIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (oclass, PROP_ORIENTATION,
+ g_param_spec_enum ("orientation",
+ P_("Orientation"),
+ P_("Orientation of the tool palette"),
+ GTK_TYPE_ORIENTATION,
+ DEFAULT_ORIENTATION,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (oclass, PROP_TOOLBAR_STYLE,
+ g_param_spec_enum ("toolbar-style",
+ P_("Toolbar Style"),
+ P_("Style of items in the tool palette"),
+ GTK_TYPE_TOOLBAR_STYLE,
+ DEFAULT_TOOLBAR_STYLE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_EXCLUSIVE,
+ g_param_spec_boolean ("exclusive",
+ P_("Exclusive"),
+ P_("Whether the item group should be the only expanded at a given time"),
+ DEFAULT_CHILD_EXCLUSIVE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ gtk_container_class_install_child_property (cclass, CHILD_PROP_EXPAND,
+ g_param_spec_boolean ("expand",
+ P_("Expand"),
+ P_("Whether the item group should receive extra space when the palette grows"),
+ DEFAULT_CHILD_EXPAND,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private (cls, sizeof (EggToolPalettePrivate));
+
+ dnd_target_atom_item = gdk_atom_intern_static_string (dnd_targets[0].target);
+ dnd_target_atom_group = gdk_atom_intern_static_string (dnd_targets[1].target);
+}
+
+GtkWidget*
+egg_tool_palette_new (void)
+{
+ return g_object_new (EGG_TYPE_TOOL_PALETTE, NULL);
+}
+
+void
+egg_tool_palette_set_icon_size (EggToolPalette *palette,
+ GtkIconSize icon_size)
+{
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+
+ if (icon_size != palette->priv->icon_size)
+ g_object_set (palette, "icon-size", icon_size, NULL);
+}
+
+void
+egg_tool_palette_set_orientation (EggToolPalette *palette,
+ GtkOrientation orientation)
+{
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+
+ if (orientation != palette->priv->orientation)
+ g_object_set (palette, "orientation", orientation, NULL);
+}
+
+void
+egg_tool_palette_set_style (EggToolPalette *palette,
+ GtkToolbarStyle style)
+{
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+
+ if (style != palette->priv->style)
+ g_object_set (palette, "style", style, NULL);
+}
+
+GtkIconSize
+egg_tool_palette_get_icon_size (EggToolPalette *palette)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), DEFAULT_ICON_SIZE);
+ return palette->priv->icon_size;
+}
+
+GtkOrientation
+egg_tool_palette_get_orientation (EggToolPalette *palette)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), DEFAULT_ORIENTATION);
+ return palette->priv->orientation;
+}
+
+GtkToolbarStyle
+egg_tool_palette_get_style (EggToolPalette *palette)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), DEFAULT_TOOLBAR_STYLE);
+ return palette->priv->style;
+}
+
+void
+egg_tool_palette_set_group_position (EggToolPalette *palette,
+ GtkWidget *group,
+ gint position)
+{
+ EggToolItemGroupInfo group_info;
+ gint old_position;
+ gpointer src, dst;
+ gsize len;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+
+ egg_tool_palette_repack (palette);
+
+ g_return_if_fail (position >= -1);
+
+ if (-1 == position)
+ position = palette->priv->groups_length - 1;
+
+ g_return_if_fail ((guint) position < palette->priv->groups_length);
+
+ if (EGG_TOOL_ITEM_GROUP (group) == palette->priv->groups[position].widget)
+ return;
+
+ old_position = egg_tool_palette_get_group_position (palette, group);
+ g_return_if_fail (old_position >= 0);
+
+ group_info = palette->priv->groups[old_position];
+
+ if (position < old_position)
+ {
+ dst = palette->priv->groups + position + 1;
+ src = palette->priv->groups + position;
+ len = old_position - position;
+ }
+ else
+ {
+ dst = palette->priv->groups + old_position;
+ src = palette->priv->groups + old_position + 1;
+ len = position - old_position;
+ }
+
+ memmove (dst, src, len * sizeof (*palette->priv->groups));
+ palette->priv->groups[position] = group_info;
+
+ gtk_widget_queue_resize (GTK_WIDGET (palette));
+}
+
+static void
+egg_tool_palette_group_notify_collapsed (EggToolItemGroup *group,
+ GParamSpec *pspec G_GNUC_UNUSED,
+ gpointer data)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (data);
+ guint i;
+
+ if (egg_tool_item_group_get_collapsed (group))
+ return;
+
+ for (i = 0; i < palette->priv->groups_size; ++i)
+ {
+ EggToolItemGroup *current_group = palette->priv->groups[i].widget;
+
+ if (current_group && current_group != group)
+ egg_tool_item_group_set_collapsed (palette->priv->groups[i].widget, TRUE);
+ }
+}
+
+void
+egg_tool_palette_set_exclusive (EggToolPalette *palette,
+ GtkWidget *group,
+ gboolean exclusive)
+{
+ EggToolItemGroupInfo *group_info;
+ gint position;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+
+ position = egg_tool_palette_get_group_position (palette, group);
+ g_return_if_fail (position >= 0);
+
+ group_info = &palette->priv->groups[position];
+
+ if (exclusive == group_info->exclusive)
+ return;
+
+ group_info->exclusive = exclusive;
+
+ if (group_info->exclusive != (0 != group_info->notify_collapsed))
+ {
+ if (group_info->exclusive)
+ {
+ group_info->notify_collapsed =
+ g_signal_connect (group, "notify::collapsed",
+ G_CALLBACK (egg_tool_palette_group_notify_collapsed),
+ palette);
+ }
+ else
+ {
+ g_signal_handler_disconnect (group, group_info->notify_collapsed);
+ group_info->notify_collapsed = 0;
+ }
+ }
+
+ egg_tool_palette_group_notify_collapsed (group_info->widget, NULL, palette);
+ gtk_widget_child_notify (group, "exclusive");
+}
+
+void
+egg_tool_palette_set_expand (EggToolPalette *palette,
+ GtkWidget *group,
+ gboolean expand G_GNUC_UNUSED)
+{
+ EggToolItemGroupInfo *group_info;
+ gint position;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+ g_return_if_fail (EGG_IS_TOOL_ITEM_GROUP (group));
+
+ position = egg_tool_palette_get_group_position (palette, group);
+ g_return_if_fail (position >= 0);
+
+ group_info = &palette->priv->groups[position];
+
+ if (expand != group_info->expand)
+ {
+ group_info->expand = expand;
+ gtk_widget_queue_resize (GTK_WIDGET (palette));
+ gtk_widget_child_notify (group, "expand");
+ }
+}
+
+gint
+egg_tool_palette_get_group_position (EggToolPalette *palette,
+ GtkWidget *group)
+{
+ guint i;
+
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), -1);
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), -1);
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ if ((gpointer) group == palette->priv->groups[i].widget)
+ return i;
+
+ return -1;
+}
+
+gboolean
+egg_tool_palette_get_exclusive (EggToolPalette *palette G_GNUC_UNUSED,
+ GtkWidget *group G_GNUC_UNUSED)
+{
+ gint position;
+
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXCLUSIVE);
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXCLUSIVE);
+
+ position = egg_tool_palette_get_group_position (palette, group);
+ g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXCLUSIVE);
+
+ return palette->priv->groups[position].exclusive;
+}
+
+gboolean
+egg_tool_palette_get_expand (EggToolPalette *palette,
+ GtkWidget *group)
+{
+ gint position;
+
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXPAND);
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXPAND);
+
+ position = egg_tool_palette_get_group_position (palette, group);
+ g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXPAND);
+
+ return palette->priv->groups[position].expand;
+}
+
+GtkToolItem*
+egg_tool_palette_get_drop_item (EggToolPalette *palette,
+ gint x,
+ gint y)
+{
+ GtkWidget *group = egg_tool_palette_get_drop_group (palette, x, y);
+
+ if (group)
+ return egg_tool_item_group_get_drop_item (EGG_TOOL_ITEM_GROUP (group),
+ x - group->allocation.x,
+ y - group->allocation.y);
+
+ return NULL;
+}
+
+GtkWidget*
+egg_tool_palette_get_drop_group (EggToolPalette *palette,
+ gint x,
+ gint y)
+{
+ GtkAllocation *allocation;
+ guint i;
+
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), NULL);
+
+ allocation = >K_WIDGET (palette)->allocation;
+
+ g_return_val_if_fail (x >= 0 && x < allocation->width, NULL);
+ g_return_val_if_fail (y >= 0 && y < allocation->height, NULL);
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ EggToolItemGroupInfo *group = &palette->priv->groups[i];
+ GtkWidget *widget;
+ gint x0, y0;
+
+ if (!group->widget)
+ continue;
+
+ widget = GTK_WIDGET (group->widget);
+
+ x0 = x - widget->allocation.x;
+ y0 = y - widget->allocation.y;
+
+ if (x0 >= 0 && x0 < widget->allocation.width &&
+ y0 >= 0 && y0 < widget->allocation.height)
+ return widget;
+ }
+
+ return NULL;
+}
+
+GtkWidget*
+egg_tool_palette_get_drag_item (EggToolPalette *palette,
+ const GtkSelectionData *selection)
+{
+ EggToolPaletteDragData *data;
+
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), NULL);
+ g_return_val_if_fail (NULL != selection, NULL);
+
+ g_return_val_if_fail (selection->format == 8, NULL);
+ g_return_val_if_fail (selection->length == sizeof (EggToolPaletteDragData), NULL);
+ g_return_val_if_fail (selection->target == dnd_target_atom_item ||
+ selection->target == dnd_target_atom_group,
+ NULL);
+
+ data = (EggToolPaletteDragData*) selection->data;
+
+ g_return_val_if_fail (data->palette == palette, NULL);
+
+ if (dnd_target_atom_item == selection->target)
+ g_return_val_if_fail (GTK_IS_TOOL_ITEM (data->item), NULL);
+ else if (dnd_target_atom_group == selection->target)
+ g_return_val_if_fail (EGG_IS_TOOL_ITEM_GROUP (data->item), NULL);
+
+ return data->item;
+}
+
+void
+egg_tool_palette_set_drag_source (EggToolPalette *palette)
+{
+ guint i;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+
+ if (palette->priv->drag_source)
+ return;
+
+ palette->priv->drag_source = TRUE;
+
+ for (i = 0; i < palette->priv->groups_length; ++i)
+ {
+ if (palette->priv->groups[i].widget)
+ gtk_container_forall (GTK_CONTAINER (palette->priv->groups[i].widget),
+ _egg_tool_palette_child_set_drag_source,
+ palette);
+ }
+}
+
+void
+egg_tool_palette_add_drag_dest (EggToolPalette *palette,
+ GtkWidget *widget,
+ GtkDestDefaults flags,
+ EggToolPaletteDragTargets targets,
+ GdkDragAction actions)
+{
+ GtkTargetEntry entries[G_N_ELEMENTS (dnd_targets)];
+ gint n_entries = 0;
+
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ egg_tool_palette_set_drag_source (palette);
+
+ if (targets & EGG_TOOL_PALETTE_DRAG_ITEMS)
+ entries[n_entries++] = dnd_targets[0];
+ if (targets & EGG_TOOL_PALETTE_DRAG_GROUPS)
+ entries[n_entries++] = dnd_targets[1];
+
+ gtk_drag_dest_set (widget, flags, entries, n_entries, actions);
+}
+
+void
+_egg_tool_palette_get_item_size (EggToolPalette *palette,
+ GtkRequisition *item_size)
+{
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+ g_return_if_fail (NULL != item_size);
+
+ *item_size = palette->priv->item_size;
+}
+
+static GtkWidget*
+egg_tool_palette_find_anchestor (GtkWidget *widget,
+ GType type)
+{
+ while (widget)
+ {
+ if (G_TYPE_CHECK_INSTANCE_TYPE (widget, type))
+ return widget;
+
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ return NULL;
+}
+
+static void
+egg_tool_palette_item_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context G_GNUC_UNUSED,
+ GtkSelectionData *selection,
+ guint info G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data)
+{
+ EggToolPaletteDragData drag_data = { EGG_TOOL_PALETTE (data), NULL };
+
+ if (selection->target == dnd_target_atom_item)
+ drag_data.item = egg_tool_palette_find_anchestor (widget, GTK_TYPE_TOOL_ITEM);
+
+ if (drag_data.item)
+ gtk_selection_data_set (selection, selection->target, 8,
+ (guchar*) &drag_data, sizeof (drag_data));
+}
+
+static void
+egg_tool_palette_child_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context G_GNUC_UNUSED,
+ GtkSelectionData *selection,
+ guint info G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data)
+{
+ EggToolPaletteDragData drag_data = { EGG_TOOL_PALETTE (data), NULL };
+
+ if (selection->target == dnd_target_atom_group)
+ drag_data.item = egg_tool_palette_find_anchestor (widget, EGG_TYPE_TOOL_ITEM_GROUP);
+
+ if (drag_data.item)
+ gtk_selection_data_set (selection, selection->target, 8,
+ (guchar*) &drag_data, sizeof (drag_data));
+}
+
+void
+_egg_tool_palette_child_set_drag_source (GtkWidget *child,
+ gpointer data)
+{
+ EggToolPalette *palette = EGG_TOOL_PALETTE (data);
+
+ /* Check drag_source,
+ * to work properly when called from egg_tool_item_group_insert().
+ */
+ if (!palette->priv->drag_source)
+ return;
+
+ if (GTK_IS_TOOL_ITEM (child))
+ {
+ /* Connect to child instead of the item itself,
+ * to work arround bug 510377.
+ */
+ child = gtk_bin_get_child (GTK_BIN (child));
+
+ if (!child)
+ return;
+
+ gtk_drag_source_set (child, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+ &dnd_targets[0], 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ g_signal_connect (child, "drag-data-get",
+ G_CALLBACK (egg_tool_palette_item_drag_data_get),
+ palette);
+ }
+ else if (GTK_IS_BUTTON (child))
+ {
+ gtk_drag_source_set (child, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+ &dnd_targets[1], 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ g_signal_connect (child, "drag-data-get",
+ G_CALLBACK (egg_tool_palette_child_drag_data_get),
+ palette);
+ }
+}
+
+G_CONST_RETURN GtkTargetEntry*
+egg_tool_palette_get_drag_target_item (void)
+{
+ return &dnd_targets[0];
+}
+
+G_CONST_RETURN GtkTargetEntry*
+egg_tool_palette_get_drag_target_group (void)
+{
+ return &dnd_targets[1];
+}
+
+void
+_egg_tool_palette_set_expanding_child (EggToolPalette *palette,
+ GtkWidget *widget)
+{
+ g_return_if_fail (EGG_IS_TOOL_PALETTE (palette));
+
+ palette->priv->expanding_child = widget;
+}
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+GtkSizeGroup *
+_egg_tool_palette_get_size_group (EggToolPalette *palette)
+{
+ g_return_val_if_fail (EGG_IS_TOOL_PALETTE (palette), NULL);
+
+ return palette->priv->text_size_group;
+}
+#endif
Added: trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggtoolpalette.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,117 @@
+/* EggToolPalette -- A tool palette with categories and DnD support
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#ifndef __EGG_TOOL_PALETTE_H__
+#define __EGG_TOOL_PALETTE_H__
+
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtkdnd.h>
+#include <gtk/gtktoolitem.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TOOL_PALETTE (egg_tool_palette_get_type())
+#define EGG_TOOL_PALETTE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, EGG_TYPE_TOOL_PALETTE, EggToolPalette))
+#define EGG_TOOL_PALETTE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, EGG_TYPE_TOOL_PALETTE, EggToolPaletteClass))
+#define EGG_IS_TOOL_PALETTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, EGG_TYPE_TOOL_PALETTE))
+#define EGG_IS_TOOL_PALETTE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, EGG_TYPE_TOOL_PALETTE))
+#define EGG_TOOL_PALETTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOOL_PALETTE, EggToolPaletteClass))
+
+typedef struct _EggToolPalette EggToolPalette;
+typedef struct _EggToolPaletteClass EggToolPaletteClass;
+typedef struct _EggToolPalettePrivate EggToolPalettePrivate;
+
+typedef enum /*< flags >*/
+{
+ EGG_TOOL_PALETTE_DRAG_ITEMS = (1 << 0),
+ EGG_TOOL_PALETTE_DRAG_GROUPS = (1 << 1),
+}
+EggToolPaletteDragTargets;
+
+struct _EggToolPalette
+{
+ GtkContainer parent_instance;
+ EggToolPalettePrivate *priv;
+};
+
+struct _EggToolPaletteClass
+{
+ GtkContainerClass parent_class;
+
+ void (*set_scroll_adjustments) (GtkWidget *widget,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+};
+
+GType egg_tool_palette_get_type (void) G_GNUC_CONST;
+GtkWidget* egg_tool_palette_new (void);
+
+void egg_tool_palette_set_group_position (EggToolPalette *palette,
+ GtkWidget *group,
+ gint position);
+void egg_tool_palette_set_exclusive (EggToolPalette *palette,
+ GtkWidget *group,
+ gboolean exclusive);
+void egg_tool_palette_set_expand (EggToolPalette *palette,
+ GtkWidget *group,
+ gboolean expand);
+
+gint egg_tool_palette_get_group_position (EggToolPalette *palette,
+ GtkWidget *group);
+gboolean egg_tool_palette_get_exclusive (EggToolPalette *palette,
+ GtkWidget *group);
+gboolean egg_tool_palette_get_expand (EggToolPalette *palette,
+ GtkWidget *group);
+
+void egg_tool_palette_set_icon_size (EggToolPalette *palette,
+ GtkIconSize icon_size);
+void egg_tool_palette_set_orientation (EggToolPalette *palette,
+ GtkOrientation orientation);
+void egg_tool_palette_set_style (EggToolPalette *palette,
+ GtkToolbarStyle style);
+
+GtkIconSize egg_tool_palette_get_icon_size (EggToolPalette *palette);
+GtkOrientation egg_tool_palette_get_orientation (EggToolPalette *palette);
+GtkToolbarStyle egg_tool_palette_get_style (EggToolPalette *palette);
+
+GtkToolItem* egg_tool_palette_get_drop_item (EggToolPalette *palette,
+ gint x,
+ gint y);
+GtkWidget* egg_tool_palette_get_drop_group (EggToolPalette *palette,
+ gint x,
+ gint y);
+GtkWidget* egg_tool_palette_get_drag_item (EggToolPalette *palette,
+ const GtkSelectionData *selection);
+
+void egg_tool_palette_set_drag_source (EggToolPalette *palette);
+void egg_tool_palette_add_drag_dest (EggToolPalette *palette,
+ GtkWidget *widget,
+ GtkDestDefaults flags,
+ EggToolPaletteDragTargets targets,
+ GdkDragAction actions);
+
+G_CONST_RETURN GtkTargetEntry* egg_tool_palette_get_drag_target_item (void) G_GNUC_CONST;
+G_CONST_RETURN GtkTargetEntry* egg_tool_palette_get_drag_target_group (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __EGG_TOOL_PALETTE_H__ */
Added: trunk/glom/utility_widgets/egg/toolpalette/eggtoolpaletteprivate.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/eggtoolpaletteprivate.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,57 @@
+/* EggToolPalette -- A tool palette with categories and DnD support
+ * Copyright (C) 2008 Openismus GmbH
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Mathias Hasselmann
+ */
+
+#ifndef __EGG_TOOL_PALETTE_PRIVATE_H__
+#define __EGG_TOOL_PALETTE_PRIVATE_H__
+
+#include "eggtoolpalette.h"
+#include "eggtoolitemgroup.h"
+#include <gtk/gtk.h>
+
+void _egg_tool_palette_get_item_size (EggToolPalette *palette,
+ GtkRequisition *item_size);
+void _egg_tool_palette_child_set_drag_source (GtkWidget *widget,
+ gpointer data);
+void _egg_tool_palette_set_expanding_child (EggToolPalette *palette,
+ GtkWidget *widget);
+
+void _egg_tool_item_group_palette_reconfigured (EggToolItemGroup *group);
+void _egg_tool_item_group_item_size_request (EggToolItemGroup *group,
+ GtkRequisition *item_size);
+gint _egg_tool_item_group_get_height_for_width (EggToolItemGroup *group,
+ gint width);
+gint _egg_tool_item_group_get_width_for_height (EggToolItemGroup *group,
+ gint height);
+void _egg_tool_item_group_paint (EggToolItemGroup *group,
+ cairo_t *cr);
+gint _egg_tool_item_group_get_size_for_limit (EggToolItemGroup *group,
+ gint limit,
+ gboolean vertical,
+ gboolean animation);
+
+#undef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+/* #define HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090 */
+
+#ifdef HAVE_EXTENDED_TOOL_SHELL_SUPPORT_BUG_535090
+GtkSizeGroup *_egg_tool_palette_get_size_group (EggToolPalette *palette);
+#endif
+
+#endif /* __EGG_TOOL_PALETTE_PRIVATE_H__ */
Added: trunk/glom/utility_widgets/egg/toolpalette/testtoolpalette.c
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/toolpalette/testtoolpalette.c Mon Jun 16 10:23:15 2008
@@ -0,0 +1,887 @@
+#include "eggtoolpalette.h"
+#include "eggtoolitemgroup.h"
+#include "eggenumaction.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+typedef struct _CanvasItem CanvasItem;
+
+struct _CanvasItem
+{
+ GdkPixbuf *pixbuf;
+ gdouble x, y;
+};
+
+static CanvasItem *drop_item = NULL;
+static GList *canvas_items = NULL;
+
+/********************************/
+/* ====== Canvas drawing ====== */
+/********************************/
+
+static CanvasItem*
+canvas_item_new (GtkWidget *widget,
+ GtkToolButton *button,
+ gdouble x,
+ gdouble y)
+{
+ CanvasItem *item = NULL;
+ const gchar *stock_id;
+ GdkPixbuf *pixbuf;
+
+ stock_id = gtk_tool_button_get_stock_id (button);
+ pixbuf = gtk_widget_render_icon (widget, stock_id, GTK_ICON_SIZE_DIALOG, NULL);
+
+ if (pixbuf)
+ {
+ item = g_slice_new0 (CanvasItem);
+ item->pixbuf = pixbuf;
+ item->x = x;
+ item->y = y;
+ }
+
+ return item;
+}
+
+static void
+canvas_item_free (CanvasItem *item)
+{
+ g_object_unref (item->pixbuf);
+ g_slice_free (CanvasItem, item);
+}
+
+static void
+canvas_item_draw (const CanvasItem *item,
+ cairo_t *cr,
+ gboolean preview)
+{
+ gdouble cx = gdk_pixbuf_get_width (item->pixbuf);
+ gdouble cy = gdk_pixbuf_get_height (item->pixbuf);
+
+ gdk_cairo_set_source_pixbuf (cr,
+ item->pixbuf,
+ item->x - cx * 0.5,
+ item->y - cy * 0.5);
+
+ if (preview)
+ cairo_paint_with_alpha (cr, 0.6);
+ else
+ cairo_paint (cr);
+}
+
+static gboolean
+canvas_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ cairo_t *cr;
+ GList *iter;
+
+ cr = gdk_cairo_create (widget->window);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, 0, 0, widget->allocation.width, widget->allocation.height);
+ cairo_fill (cr);
+
+ for (iter = canvas_items; iter; iter = iter->next)
+ canvas_item_draw (iter->data, cr, FALSE);
+
+ if (drop_item)
+ canvas_item_draw (drop_item, cr, TRUE);
+
+ cairo_destroy (cr);
+
+ return TRUE;
+}
+
+/*****************************/
+/* ====== Palette DnD ====== */
+/*****************************/
+
+static void
+palette_drop_item (GtkToolItem *drag_item,
+ EggToolItemGroup *drop_group,
+ gint x,
+ gint y)
+{
+ GtkWidget *drag_group = gtk_widget_get_parent (GTK_WIDGET (drag_item));
+ GtkToolItem *drop_item = egg_tool_item_group_get_drop_item (drop_group, x, y);
+ gint drop_position = -1;
+
+ if (drop_item)
+ drop_position = egg_tool_item_group_get_item_position (EGG_TOOL_ITEM_GROUP (drop_group), drop_item);
+
+ if (EGG_TOOL_ITEM_GROUP (drag_group) != drop_group)
+ {
+ gboolean homogeneous, expand, fill, new_row;
+
+ g_object_ref (drag_item);
+ gtk_container_child_get (GTK_CONTAINER (drag_group), GTK_WIDGET (drag_item),
+ "homogeneous", &homogeneous,
+ "expand", &expand,
+ "fill", &fill,
+ "new-row", &new_row,
+ NULL);
+ gtk_container_remove (GTK_CONTAINER (drag_group), GTK_WIDGET (drag_item));
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (drop_group),
+ drag_item, drop_position);
+ gtk_container_child_set (GTK_CONTAINER (drop_group), GTK_WIDGET (drag_item),
+ "homogeneous", homogeneous,
+ "expand", expand,
+ "fill", fill,
+ "new-row", new_row,
+ NULL);
+ g_object_unref (drag_item);
+ }
+ else
+ egg_tool_item_group_set_item_position (EGG_TOOL_ITEM_GROUP (drop_group),
+ drag_item, drop_position);
+}
+
+static void
+palette_drop_group (EggToolPalette *palette,
+ GtkWidget *drag_group,
+ GtkWidget *drop_group)
+{
+ gint drop_position = -1;
+
+ if (drop_group)
+ drop_position = egg_tool_palette_get_group_position (palette, drop_group);
+
+ egg_tool_palette_set_group_position (palette, drag_group, drop_position);
+}
+
+static void
+palette_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+{
+ GtkWidget *drag_palette = gtk_drag_get_source_widget (context);
+ GtkWidget *drag_item = NULL, *drop_group = NULL;
+
+ while (drag_palette && !EGG_IS_TOOL_PALETTE (drag_palette))
+ drag_palette = gtk_widget_get_parent (drag_palette);
+
+ if (drag_palette)
+ {
+ drag_item = egg_tool_palette_get_drag_item (EGG_TOOL_PALETTE (drag_palette), selection);
+ drop_group = egg_tool_palette_get_drop_group (EGG_TOOL_PALETTE (widget), x, y);
+ }
+
+ if (EGG_IS_TOOL_ITEM_GROUP (drag_item))
+ palette_drop_group (EGG_TOOL_PALETTE (drag_palette), drag_item, drop_group);
+ else if (GTK_IS_TOOL_ITEM (drag_item) && drop_group)
+ palette_drop_item (GTK_TOOL_ITEM (drag_item),
+ EGG_TOOL_ITEM_GROUP (drop_group),
+ x - GTK_WIDGET (drop_group)->allocation.x,
+ y - GTK_WIDGET (drop_group)->allocation.y);
+}
+
+/********************************/
+/* ====== Passive Canvas ====== */
+/********************************/
+
+static void
+passive_canvas_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+{
+ /* find the tool button, which is the source of this DnD operation */
+
+ GtkWidget *palette = gtk_drag_get_source_widget (context);
+ CanvasItem *canvas_item = NULL;
+ GtkWidget *tool_item = NULL;
+
+ while (palette && !EGG_IS_TOOL_PALETTE (palette))
+ palette = gtk_widget_get_parent (palette);
+
+ if (palette)
+ tool_item = egg_tool_palette_get_drag_item (EGG_TOOL_PALETTE (palette), selection);
+
+ g_assert (NULL == drop_item);
+
+ /* append a new canvas item when a tool button was found */
+
+ if (GTK_IS_TOOL_ITEM (tool_item))
+ canvas_item = canvas_item_new (widget, GTK_TOOL_BUTTON (tool_item), x, y);
+
+ if (canvas_item)
+ {
+ canvas_items = g_list_append (canvas_items, canvas_item);
+ gtk_widget_queue_draw (widget);
+ }
+}
+
+/************************************/
+/* ====== Interactive Canvas ====== */
+/************************************/
+
+static gboolean
+interactive_canvas_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ gpointer data G_GNUC_UNUSED)
+{
+ if (drop_item)
+ {
+ /* already have a drop indicator - just update position */
+
+ drop_item->x = x;
+ drop_item->y = y;
+
+ gtk_widget_queue_draw (widget);
+ gdk_drag_status (context, GDK_ACTION_COPY, time);
+ }
+ else
+ {
+ /* request DnD data for creating a drop indicator */
+
+ GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
+
+ if (!target)
+ return FALSE;
+
+ gtk_drag_get_data (widget, context, target, time);
+ }
+
+ return TRUE;
+}
+
+static void
+interactive_canvas_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+
+{
+ /* find the tool button, which is the source of this DnD operation */
+
+ GtkWidget *palette = gtk_drag_get_source_widget (context);
+ GtkWidget *tool_item = NULL;
+
+ while (palette && !EGG_IS_TOOL_PALETTE (palette))
+ palette = gtk_widget_get_parent (palette);
+
+ if (palette)
+ tool_item = egg_tool_palette_get_drag_item (EGG_TOOL_PALETTE (palette), selection);
+
+ /* create a drop indicator when a tool button was found */
+
+ g_assert (NULL == drop_item);
+
+ if (GTK_IS_TOOL_ITEM (tool_item))
+ {
+ drop_item = canvas_item_new (widget, GTK_TOOL_BUTTON (tool_item), x, y);
+ gdk_drag_status (context, GDK_ACTION_COPY, time);
+ gtk_widget_queue_draw (widget);
+ }
+}
+
+static gboolean
+interactive_canvas_drag_drop (GtkWidget *widget,
+ GdkDragContext *context G_GNUC_UNUSED,
+ gint x,
+ gint y,
+ guint time,
+ gpointer data G_GNUC_UNUSED)
+{
+ if (drop_item)
+ {
+ /* turn the drop indicator into a real canvas item */
+
+ drop_item->x = x;
+ drop_item->y = y;
+
+ canvas_items = g_list_append (canvas_items, drop_item);
+ drop_item = NULL;
+
+ /* signal the item was accepted and redraw */
+
+ gtk_drag_finish (context, TRUE, FALSE, time);
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+interactive_canvas_real_drag_leave (gpointer data)
+{
+ if (drop_item)
+ {
+ GtkWidget *widget = GTK_WIDGET (data);
+
+ canvas_item_free (drop_item);
+ drop_item = NULL;
+
+ gtk_widget_queue_draw (widget);
+ }
+
+ return FALSE;
+}
+
+static void
+interactive_canvas_drag_leave (GtkWidget *widget,
+ GdkDragContext *context G_GNUC_UNUSED,
+ guint time G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+{
+ /* defer cleanup until a potential "drag-drop" signal was received */
+ g_idle_add (interactive_canvas_real_drag_leave, widget);
+}
+
+/*******************************/
+/* ====== Setup Test UI ====== */
+/*******************************/
+
+static void
+not_implemented (GtkAction *action,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ _("Not implemented yet."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Sorry, the '%s' action is not implemented."),
+ gtk_action_get_name (action));
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+load_stock_items (EggToolPalette *palette)
+{
+ GtkWidget *group_af = egg_tool_item_group_new (_("Stock Icons (A-F)"));
+ GtkWidget *group_gn = egg_tool_item_group_new (_("Stock Icons (G-N)"));
+ GtkWidget *group_or = egg_tool_item_group_new (_("Stock Icons (O-R)"));
+ GtkWidget *group_sz = egg_tool_item_group_new (_("Stock Icons (S-Z)"));
+ GtkWidget *group = NULL;
+
+ GtkToolItem *item;
+ GSList *stock_ids;
+ GSList *iter;
+
+ stock_ids = gtk_stock_list_ids ();
+ stock_ids = g_slist_sort (stock_ids, (GCompareFunc) strcmp);
+
+ gtk_container_add (GTK_CONTAINER (palette), group_af);
+ gtk_container_add (GTK_CONTAINER (palette), group_gn);
+ gtk_container_add (GTK_CONTAINER (palette), group_or);
+ gtk_container_add (GTK_CONTAINER (palette), group_sz);
+
+ for (iter = stock_ids; iter; iter = g_slist_next (iter))
+ {
+ GtkStockItem stock_item;
+ gchar *id = iter->data;
+
+ switch (id[4])
+ {
+ case 'a':
+ group = group_af;
+ break;
+
+ case 'g':
+ group = group_gn;
+ break;
+
+ case 'o':
+ group = group_or;
+ break;
+
+ case 's':
+ group = group_sz;
+ break;
+ }
+
+ item = gtk_tool_button_new_from_stock (id);
+ gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (item), id);
+ gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+
+ if (!gtk_stock_lookup (id, &stock_item) || !stock_item.label)
+ gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), id);
+
+ g_free (id);
+ }
+
+ g_slist_free (stock_ids);
+}
+
+static void
+load_special_items (EggToolPalette *palette)
+{
+ GtkToolItem *item;
+ GtkWidget *group;
+
+ group = egg_tool_item_group_new (_("Advanced Features"));
+ gtk_container_add (GTK_CONTAINER (palette), group);
+
+ item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (item), gtk_entry_new ());
+ gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (item))), "homogeneous=FALSE");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_container_child_set (GTK_CONTAINER (group), GTK_WIDGET (item),
+ "homogeneous", FALSE,
+ NULL);
+
+ item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (item), gtk_entry_new ());
+ gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (item))), "homogeneous=FALSE, expand=TRUE");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_container_child_set (GTK_CONTAINER (group), GTK_WIDGET (item),
+ "homogeneous", FALSE,
+ "expand", TRUE,
+ NULL);
+
+ item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (item), gtk_entry_new ());
+ gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (item))), "homogeneous=FALSE, expand=TRUE, fill=FALSE");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_container_child_set (GTK_CONTAINER (group), GTK_WIDGET (item),
+ "homogeneous", FALSE,
+ "expand", TRUE,
+ "fill", FALSE,
+ NULL);
+
+ item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (item), gtk_entry_new ());
+ gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (item))), "homogeneous=FALSE, expand=TRUE, new-row=TRUE");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_container_child_set (GTK_CONTAINER (group), GTK_WIDGET (item),
+ "homogeneous", FALSE,
+ "expand", TRUE,
+ "new-row", TRUE,
+ NULL);
+
+ item = gtk_tool_button_new_from_stock (GTK_STOCK_GO_UP);
+ gtk_tool_item_set_tooltip_text (item, "Show on vertical palettes only");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_tool_item_set_visible_horizontal (item, FALSE);
+
+ item = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
+ gtk_tool_item_set_tooltip_text (item, "Show on horizontal palettes only");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_tool_item_set_visible_vertical (item, FALSE);
+
+ item = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE);
+ gtk_tool_item_set_tooltip_text (item, "Do not show at all");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_widget_set_no_show_all (GTK_WIDGET (item), TRUE);
+
+ item = gtk_tool_button_new_from_stock (GTK_STOCK_FULLSCREEN);
+ gtk_tool_item_set_tooltip_text (item, "Expanded this item");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+ gtk_container_child_set (GTK_CONTAINER (group), GTK_WIDGET (item),
+ "homogeneous", FALSE,
+ "expand", TRUE,
+ NULL);
+
+ item = gtk_tool_button_new_from_stock (GTK_STOCK_HELP);
+ gtk_tool_item_set_tooltip_text (item, "A regular item");
+ egg_tool_item_group_insert (EGG_TOOL_ITEM_GROUP (group), item, -1);
+}
+
+static gboolean
+drop_invalid_icon_size (GEnumValue *enum_value,
+ gpointer user_data G_GNUC_UNUSED)
+{
+ return (enum_value->value != GTK_ICON_SIZE_INVALID);
+}
+
+static void
+palette_notify_orientation (GObject *object,
+ GParamSpec *pspec G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+{
+ GtkWidget *scroller = gtk_widget_get_parent (GTK_WIDGET (object));
+ GtkWidget *parent = gtk_widget_get_parent (scroller);
+
+ GtkWidget *hpaned = g_object_get_data (object, "hpaned");
+ GtkWidget *vpaned = g_object_get_data (object, "vpaned");
+
+ g_object_ref (scroller);
+
+ if (parent)
+ gtk_container_remove (GTK_CONTAINER (parent), scroller);
+
+ switch (egg_tool_palette_get_orientation (EGG_TOOL_PALETTE (object)))
+ {
+ case GTK_ORIENTATION_VERTICAL:
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_paned_pack1 (GTK_PANED (hpaned), scroller, FALSE, FALSE);
+ break;
+
+ case GTK_ORIENTATION_HORIZONTAL:
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
+ gtk_paned_pack1 (GTK_PANED (vpaned), scroller, FALSE, FALSE);
+ break;
+ }
+
+ g_object_unref (scroller);
+}
+
+static void
+view_ellipsize_changed_cb (GtkWidget *widget,
+ gpointer data)
+{
+ GEnumValue *ellipsize = data;
+
+ egg_tool_item_group_set_ellipsize (EGG_TOOL_ITEM_GROUP (widget),
+ ellipsize->value);
+}
+
+static void
+view_ellipsize_changed (GEnumValue *value,
+ gpointer data)
+{
+ gtk_container_foreach (data, view_ellipsize_changed_cb, value);
+}
+
+static void
+view_exclusive_toggled_cb (GtkWidget *widget,
+ gpointer data)
+{
+ gboolean value = gtk_toggle_action_get_active (data);
+ GtkWidget *palette = gtk_widget_get_parent (widget);
+
+ egg_tool_palette_set_exclusive (EGG_TOOL_PALETTE (palette), widget, value);
+}
+
+static void
+view_exclusive_toggled (GtkToggleAction *action,
+ gpointer data)
+{
+ gtk_container_foreach (data, view_exclusive_toggled_cb, action);
+}
+
+static void
+view_expand_toggled_cb (GtkWidget *widget,
+ gpointer data)
+{
+ gboolean value = gtk_toggle_action_get_active (data);
+ GtkWidget *palette = gtk_widget_get_parent (widget);
+
+ egg_tool_palette_set_expand (EGG_TOOL_PALETTE (palette), widget, value);
+}
+
+static void
+view_expand_toggled (GtkToggleAction *action,
+ gpointer data)
+{
+ gtk_container_foreach (data, view_expand_toggled_cb, action);
+}
+
+static GtkWidget*
+create_ui (void)
+{
+ static const gchar ui_spec[] = " \
+ <ui> \
+ <menubar> \
+ <menu action='FileMenu'> \
+ <menuitem action='FileNew' /> \
+ <menuitem action='FileOpen' /> \
+ <separator /> \
+ <menuitem action='FileSave' /> \
+ <menuitem action='FileSaveAs' /> \
+ <separator /> \
+ <menuitem action='FileClose' /> \
+ <menuitem action='FileQuit' /> \
+ </menu> \
+ \
+ <menu action='ViewMenu'> \
+ <menuitem action='ViewIconSize' /> \
+ <menuitem action='ViewOrientation' /> \
+ <menuitem action='ViewStyle' /> \
+ <separator /> \
+ <menuitem action='ViewEllipsize' /> \
+ <menuitem action='ViewExclusive' /> \
+ <menuitem action='ViewExpand' /> \
+ </menu> \
+ \
+ <menu action='HelpMenu'> \
+ <menuitem action='HelpAbout' /> \
+ </menu> \
+ </menubar> \
+ \
+ <toolbar> \
+ <toolitem action='FileNew' /> \
+ <toolitem action='FileOpen' /> \
+ <toolitem action='FileSave' /> \
+ <separator /> \
+ <toolitem action='ViewIconSize' /> \
+ <toolitem action='ViewOrientation' /> \
+ <toolitem action='ViewStyle' /> \
+ <separator /> \
+ <toolitem action='ViewEllipsize' /> \
+ <toolitem action='ViewExclusive' /> \
+ <toolitem action='ViewExpand' /> \
+ <separator /> \
+ <toolitem action='HelpAbout' /> \
+ </toolbar> \
+ </ui>";
+
+ static GtkActionEntry actions[] = {
+ { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
+ { "FileNew", GTK_STOCK_NEW, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ { "FileOpen", GTK_STOCK_OPEN, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ { "FileSave", GTK_STOCK_SAVE, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ { "FileSaveAs", GTK_STOCK_SAVE_AS, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ { "FileClose", GTK_STOCK_CLOSE, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ { "FileQuit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (gtk_main_quit) },
+ { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
+ { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
+ { "HelpAbout", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (not_implemented) },
+ };
+
+ GtkActionGroup *group;
+ GError *error = NULL;
+ GtkUIManager *ui;
+
+ GtkWidget *window, *vbox, *hpaned, *vpaned;
+ GtkWidget *menubar, *toolbar, *notebook;
+ GtkWidget *palette, *palette_scroller;
+ GtkWidget *contents, *contents_scroller;
+ GtkAction *action;
+
+ /* ===== menubar/toolbar ===== */
+
+ palette = egg_tool_palette_new ();
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ group = gtk_action_group_new ("");
+ ui = gtk_ui_manager_new ();
+
+ gtk_action_group_add_actions (group, actions, G_N_ELEMENTS (actions), window);
+
+ action = egg_enum_action_new ("ViewIconSize", _("Icon Size"), NULL, GTK_TYPE_ICON_SIZE);
+ egg_enum_action_set_filter (EGG_ENUM_ACTION (action), drop_invalid_icon_size, NULL, NULL);
+ egg_enum_action_bind (EGG_ENUM_ACTION (action), G_OBJECT (palette), "icon-size");
+ gtk_action_group_add_action (group, action);
+
+ action = egg_enum_action_new ("ViewOrientation", _("Orientation"), NULL, GTK_TYPE_ORIENTATION);
+ egg_enum_action_bind (EGG_ENUM_ACTION (action), G_OBJECT (palette), "orientation");
+ gtk_action_group_add_action (group, action);
+
+ action = egg_enum_action_new ("ViewStyle", _("Style"), NULL, GTK_TYPE_TOOLBAR_STYLE);
+ egg_enum_action_bind (EGG_ENUM_ACTION (action), G_OBJECT (palette), "toolbar-style");
+ gtk_action_group_add_action (group, action);
+
+ action = egg_enum_action_new ("ViewEllipsize", _("Ellipsize Headers"), NULL, PANGO_TYPE_ELLIPSIZE_MODE);
+ egg_enum_action_connect (EGG_ENUM_ACTION (action), view_ellipsize_changed, palette);
+ gtk_action_group_add_action (group, action);
+
+ action = GTK_ACTION (gtk_toggle_action_new ("ViewExclusive", _("Exclusive Groups"), NULL, NULL));
+ g_signal_connect (action, "toggled", G_CALLBACK (view_exclusive_toggled), palette);
+ gtk_action_group_add_action (group, action);
+
+ action = GTK_ACTION (gtk_toggle_action_new ("ViewExpand", _("Expand Groups"), NULL, NULL));
+ g_signal_connect (action, "toggled", G_CALLBACK (view_expand_toggled), palette);
+ gtk_action_group_add_action (group, action);
+
+ gtk_ui_manager_insert_action_group (ui, group, -1);
+
+ if (!gtk_ui_manager_add_ui_from_string (ui, ui_spec, sizeof ui_spec - 1, &error))
+ {
+ g_message ("building ui_spec failed: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ menubar = gtk_ui_manager_get_widget (ui, "/menubar");
+ toolbar = gtk_ui_manager_get_widget (ui, "/toolbar");
+
+ gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
+
+ /* ===== palette ===== */
+
+ load_stock_items (EGG_TOOL_PALETTE (palette));
+ load_special_items (EGG_TOOL_PALETTE (palette));
+
+ g_signal_connect (palette, "notify::orientation",
+ G_CALLBACK (palette_notify_orientation),
+ NULL);
+
+ palette_scroller = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (palette_scroller),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_set_border_width (GTK_CONTAINER (palette_scroller), 6);
+ gtk_container_add (GTK_CONTAINER (palette_scroller), palette);
+ gtk_widget_show_all (palette_scroller);
+
+ /* ===== notebook ===== */
+
+ notebook = gtk_notebook_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
+
+ /* ===== DnD for tool items ===== */
+
+ g_signal_connect (palette, "drag-data-received",
+ G_CALLBACK (palette_drag_data_received),
+ NULL);
+
+ egg_tool_palette_add_drag_dest (EGG_TOOL_PALETTE (palette),
+ palette, GTK_DEST_DEFAULT_ALL,
+ EGG_TOOL_PALETTE_DRAG_ITEMS |
+ EGG_TOOL_PALETTE_DRAG_GROUPS,
+ GDK_ACTION_MOVE);
+
+ /* ===== passive DnD dest ===== */
+
+ contents = gtk_drawing_area_new ();
+ gtk_widget_set_app_paintable (contents, TRUE);
+
+ g_object_connect (contents,
+ "signal::expose-event", canvas_expose_event, NULL,
+ "signal::drag-data-received", passive_canvas_drag_data_received, NULL,
+ NULL);
+
+ egg_tool_palette_add_drag_dest (EGG_TOOL_PALETTE (palette),
+ contents, GTK_DEST_DEFAULT_ALL,
+ EGG_TOOL_PALETTE_DRAG_ITEMS,
+ GDK_ACTION_COPY);
+
+ contents_scroller = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (contents_scroller),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (contents_scroller), contents);
+ gtk_container_set_border_width (GTK_CONTAINER (contents_scroller), 6);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), contents_scroller,
+ gtk_label_new ("Passive DnD Mode"));
+
+ /* ===== interactive DnD dest ===== */
+
+ contents = gtk_drawing_area_new ();
+ gtk_widget_set_app_paintable (contents, TRUE);
+
+ g_object_connect (contents,
+ "signal::expose-event", canvas_expose_event, NULL,
+ "signal::drag-motion", interactive_canvas_drag_motion, NULL,
+ "signal::drag-data-received", interactive_canvas_drag_data_received, NULL,
+ "signal::drag-leave", interactive_canvas_drag_leave, NULL,
+ "signal::drag-drop", interactive_canvas_drag_drop, NULL,
+ NULL);
+
+ egg_tool_palette_add_drag_dest (EGG_TOOL_PALETTE (palette),
+ contents, GTK_DEST_DEFAULT_HIGHLIGHT,
+ EGG_TOOL_PALETTE_DRAG_ITEMS,
+ GDK_ACTION_COPY);
+
+ contents_scroller = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (contents_scroller),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (contents_scroller), contents);
+ gtk_container_set_border_width (GTK_CONTAINER (contents_scroller), 6);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), contents_scroller,
+ gtk_label_new ("Interactive DnD Mode"));
+
+ /* ===== hpaned ===== */
+
+ hpaned = gtk_hpaned_new ();
+ gtk_paned_pack2 (GTK_PANED (hpaned), notebook, TRUE, FALSE);
+
+ g_object_set_data_full (G_OBJECT (palette), "hpaned",
+ g_object_ref (hpaned),
+ g_object_unref);
+
+ /* ===== vpaned ===== */
+
+ vpaned = gtk_vpaned_new ();
+ gtk_paned_pack2 (GTK_PANED (vpaned), hpaned, TRUE, FALSE);
+
+ g_object_set_data_full (G_OBJECT (palette), "vpaned",
+ g_object_ref (vpaned),
+ g_object_unref);
+
+ /* ===== vbox ===== */
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0);
+ gtk_widget_show_all (vbox);
+
+ /* ===== window ===== */
+
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 500);
+ gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui));
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ /* ===== final fixup ===== */
+
+ g_object_unref (ui);
+ return window;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkWidget *ui;
+
+ gtk_init (&argc, &argv);
+
+ gtk_rc_parse_string (" \
+ style 'egg-tool-item-group' { \
+ EggToolItemGroup::expander-size = 10 \
+ } \
+ \
+ style 'egg-tool-item-group-header' { \
+ bg[NORMAL] = @selected_bg_color \
+ fg[NORMAL] = @selected_fg_color \
+ bg[PRELIGHT] = shade(1.04, @selected_bg_color) \
+ fg[PRELIGHT] = @selected_fg_color \
+ bg[ACTIVE] = shade(0.9, @selected_bg_color) \
+ fg[ACTIVE] = shade(0.9, @selected_fg_color) \
+ \
+ font_name = 'Sans Serif Bold 10.' \
+ GtkButton::inner_border = { 0, 3, 0, 0 } \
+ } \
+ \
+ style 'egg-tool-item-group-button' { \
+ GtkToolButton::icon-spacing = 12 \
+ } \
+ \
+ class 'EggToolItemGroup' \
+ style 'egg-tool-item-group' \
+ \
+ widget_class '*<EggToolItemGroup>.GtkButton*' \
+ style 'egg-tool-item-group-header' \
+ \
+ widget_class '*<EggToolItemGroup>.GtkToolButton' \
+ style 'egg-tool-item-group-button' \
+ ");
+
+ ui = create_ui ();
+ gtk_widget_show (ui);
+ gtk_main ();
+
+ return 0;
+}
Added: trunk/glom/utility_widgets/egg/util/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/util/Makefile.am Mon Jun 16 10:23:15 2008
@@ -0,0 +1,29 @@
+INCLUDES = \
+ $(EGG_CFLAGS)
+
+noinst_LTLIBRARIES=libeggutil.la
+
+eggmarshalers.h: eggmarshalers.list
+ cd $(srcdir) \
+ && $(GLIB_GENMARSHAL) --prefix=_egg_marshal eggmarshalers.list --header > xgen-emh \
+ && cp xgen-emh eggmarshalers.h \
+ && rm -f xgen-emh xgen-emh~
+
+eggmarshalers.c: eggmarshalers.list
+ cd $(srcdir) \
+ && $(GLIB_GENMARSHAL) --prefix=_egg_marshal eggmarshalers.list --body > xgen-emc \
+ && cp xgen-emc eggmarshalers.c \
+ && rm -f xgen-emc xgen-emc~
+
+egg-marshal.c: eggmarshalers.h eggmarshalers.c
+
+libeggutil_la_SOURCES = \
+ egg-marshal.c
+
+noinst_HEADERS = \
+ eggmarshalers.h \
+ eggintl.h \
+ egg-macros.h
+
+EXTRA_DIST= \
+ eggmarshalers.list
Added: trunk/glom/utility_widgets/egg/util/egg-macros.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/util/egg-macros.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,154 @@
+/**
+ * Useful macros.
+ *
+ * Author:
+ * Darin Adler <darin bentspoon com>
+ *
+ * Copyright 2001 Ben Tea Spoons, Inc.
+ */
+#ifndef _EGG_MACROS_H_
+#define _EGG_MACROS_H_
+
+#include <glib/gmacros.h>
+
+G_BEGIN_DECLS
+
+/* Macros for defining classes. Ideas taken from Nautilus and GOB. */
+
+/* Define the boilerplate type stuff to reduce typos and code size. Defines
+ * the get_type method and the parent_class static variable. */
+
+#define EGG_BOILERPLATE(type, type_as_function, corba_type, \
+ parent_type, parent_type_macro, \
+ register_type_macro) \
+static void type_as_function ## _class_init (type ## Class *klass); \
+static void type_as_function ## _instance_init (type *object); \
+static parent_type ## Class *parent_class = NULL; \
+static void \
+type_as_function ## _class_init_trampoline (gpointer klass, \
+ gpointer data) \
+{ \
+ parent_class = (parent_type ## Class *)g_type_class_ref ( \
+ parent_type_macro); \
+ type_as_function ## _class_init ((type ## Class *)klass); \
+} \
+GType \
+type_as_function ## _get_type (void) \
+{ \
+ static GType object_type = 0; \
+ if (object_type == 0) { \
+ static const GTypeInfo object_info = { \
+ sizeof (type ## Class), \
+ NULL, /* base_init */ \
+ NULL, /* base_finalize */ \
+ type_as_function ## _class_init_trampoline, \
+ NULL, /* class_finalize */ \
+ NULL, /* class_data */ \
+ sizeof (type), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) type_as_function ## _instance_init \
+ }; \
+ object_type = register_type_macro \
+ (type, type_as_function, corba_type, \
+ parent_type, parent_type_macro); \
+ } \
+ return object_type; \
+}
+
+/* Just call the parent handler. This assumes that there is a variable
+ * named parent_class that points to the (duh!) parent class. Note that
+ * this macro is not to be used with things that return something, use
+ * the _WITH_DEFAULT version for that */
+#define EGG_CALL_PARENT(parent_class_cast, name, args) \
+ ((parent_class_cast(parent_class)->name != NULL) ? \
+ parent_class_cast(parent_class)->name args : (void)0)
+
+/* Same as above, but in case there is no implementation, it evaluates
+ * to def_return */
+#define EGG_CALL_PARENT_WITH_DEFAULT(parent_class_cast, \
+ name, args, def_return) \
+ ((parent_class_cast(parent_class)->name != NULL) ? \
+ parent_class_cast(parent_class)->name args : def_return)
+
+/* Call a virtual method */
+#define EGG_CALL_VIRTUAL(object, get_class_cast, method, args) \
+ (get_class_cast (object)->method ? (* get_class_cast (object)->method) args : (void)0)
+
+/* Call a virtual method with default */
+#define EGG_CALL_VIRTUAL_WITH_DEFAULT(object, get_class_cast, method, args, default) \
+ (get_class_cast (object)->method ? (* get_class_cast (object)->method) args : default)
+
+#define EGG_CLASS_BOILERPLATE(type, type_as_function, \
+ parent_type, parent_type_macro) \
+ EGG_BOILERPLATE(type, type_as_function, type, \
+ parent_type, parent_type_macro, \
+ EGG_REGISTER_TYPE)
+
+#define EGG_REGISTER_TYPE(type, type_as_function, corba_type, \
+ parent_type, parent_type_macro) \
+ g_type_register_static (parent_type_macro, #type, &object_info, 0)
+
+
+#define EGG_DEFINE_BOXED_TYPE(TN, t_n) \
+EGG_DEFINE_BOXED_TYPE_WITH_CODE(TN, t_n, {});
+
+#define EGG_DEFINE_BOXED_TYPE_WITH_CODE(TN, t_n, _C_) \
+\
+static gpointer t_n##_copy (gpointer boxed); \
+static void t_n##_free (gpointer boxed); \
+\
+EGG_DEFINE_BOXED_TYPE_EXTENDED(TN, t_n, t_n##_copy, t_n##_free, _C_);
+
+#define EGG_DEFINE_BOXED_TYPE_EXTENDED(TN, t_n, b_c, b_f, _C_) \
+\
+_EGG_DEFINE_BOXED_TYPE_EXTENDED_BEGIN(TN, t_n, b_c, b_f) {_C_;} \
+_EGG_DEFINE_BOXED_TYPE_EXTENDED_END()
+
+#define _EGG_DEFINE_BOXED_TYPE_EXTENDED_BEGIN(TypeName, type_name, boxed_copy, boxed_free) \
+\
+GType \
+type_name##_get_type (void) \
+{ \
+ static volatile gsize g_define_type_id__volatile = 0; \
+ if (g_once_init_enter (&g_define_type_id__volatile)) \
+ { \
+ GType g_define_type_id = \
+ g_boxed_type_register_static (g_intern_static_string (#TypeName), \
+ boxed_copy, boxed_free); \
+ { /* custom code follows */
+#define _EGG_DEFINE_BOXED_TYPE_EXTENDED_END() \
+ /* following custom code */ \
+ } \
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
+ } \
+ return g_define_type_id__volatile; \
+} /* closes type_name##_get_type() */
+
+#define EGG_DEFINE_QUARK(QN, q_n) \
+\
+GQuark \
+q_n##_quark (void) \
+{ \
+ static volatile gsize g_define_quark__volatile = 0; \
+ if (g_once_init_enter (&g_define_quark__volatile)) \
+ { \
+ GQuark g_define_quark = g_quark_from_string (#QN); \
+ g_once_init_leave (&g_define_quark__volatile, g_define_quark); \
+ } \
+ return g_define_quark__volatile; \
+}
+
+#define EGG_IS_POSITIVE_RESPONSE(response_id) \
+ ((response_id) == GTK_RESPONSE_ACCEPT || \
+ (response_id) == GTK_RESPONSE_OK || \
+ (response_id) == GTK_RESPONSE_YES || \
+ (response_id) == GTK_RESPONSE_APPLY)
+
+#define EGG_IS_NEGATIVE_RESPONSE(response_id) \
+ ((response_id) == GTK_RESPONSE_REJECT || \
+ (response_id) == GTK_RESPONSE_CANCEL || \
+ (response_id) == GTK_RESPONSE_NO)
+
+G_END_DECLS
+
+#endif /* _EGG_MACROS_H_ */
Added: trunk/glom/utility_widgets/egg/util/egg-marshal.c
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/util/egg-marshal.c Mon Jun 16 10:23:15 2008
@@ -0,0 +1,2 @@
+#include "eggmarshalers.h"
+#include "eggmarshalers.c"
Added: trunk/glom/utility_widgets/egg/util/eggintl.h
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/util/eggintl.h Mon Jun 16 10:23:15 2008
@@ -0,0 +1,8 @@
+#ifndef __EGG_INTL_H__
+#define __EGG_INTL_H__
+
+/* We don't support gettext yet, dunno if we should /Anders */
+#define _(x) (x)
+#define N_(x) (x)
+
+#endif /* __EGG_INTL_H__ */
Added: trunk/glom/utility_widgets/egg/util/eggmarshalers.list
==============================================================================
--- (empty file)
+++ trunk/glom/utility_widgets/egg/util/eggmarshalers.list Mon Jun 16 10:23:15 2008
@@ -0,0 +1,20 @@
+VOID:OBJECT,OBJECT
+VOID:OBJECT,STRING,LONG,LONG
+VOID:OBJECT,LONG
+VOID:OBJECT,STRING,STRING
+VOID:UINT,UINT
+BOOLEAN:INT
+BOOLEAN:ENUM
+BOOLEAN:VOID
+OBJECT:VOID
+VOID:VOID
+VOID:INT,INT
+VOID:UINT,UINT
+VOID:BOOLEAN
+VOID:OBJECT,ENUM,BOXED
+VOID:BOXED
+BOOLEAN:BOOLEAN
+BOOLEAN:OBJECT,STRING,STRING
+BOOLEAN:ENUM,INT
+STRING:POINTER
+STRING:STRING,STRING
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]