[libegg] Added event boxes to EggSpreadTableDnd
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libegg] Added event boxes to EggSpreadTableDnd
- Date: Tue, 30 Aug 2011 19:02:03 +0000 (UTC)
commit d15ba17536e30ca26e6013eebbd5ce601c9cf996
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Tue Aug 30 21:03:07 2011 +0200
Added event boxes to EggSpreadTableDnd
This commit makes the EggSpreadTableDnd own event boxes internally
for all added children and adds some new apis:
- egg_spread_table_dnd_insert_child/remove_child()
Custom api to add/remove children since normal container apis are
reserved for internal use by the spread table.
- egg_spread_table_set/get_steal_events()
An added 'steal-events' property controls whether the spread-table
should trap all pointer events over the added children (temporally
allows drag'n'drop of widgets that also handle events).
libegg/spreadtable/eggspreadtablednd.c | 252 +++++++++++++++++++++++++++++---
libegg/spreadtable/eggspreadtablednd.h | 14 ++-
2 files changed, 243 insertions(+), 23 deletions(-)
---
diff --git a/libegg/spreadtable/eggspreadtablednd.c b/libegg/spreadtable/eggspreadtablednd.c
index 2b7360a..a1008c8 100644
--- a/libegg/spreadtable/eggspreadtablednd.c
+++ b/libegg/spreadtable/eggspreadtablednd.c
@@ -30,6 +30,23 @@
#define DEFAULT_LINES 2
#define P_(msgid) (msgid)
+
+enum {
+ PROP_0,
+ PROP_STEAL_EVENTS
+};
+
+
+/* GObjectClass */
+static void egg_spread_table_dnd_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void egg_spread_table_dnd_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
/* GtkWidgetClass */
static void egg_spread_table_dnd_realize (GtkWidget *widget);
static gboolean egg_spread_table_dnd_motion (GtkWidget *widget,
@@ -77,7 +94,7 @@ static void egg_spread_table_dnd_remove (GtkContainer
GtkWidget *child);
/* EggSpreadTableClass */
-static void egg_spread_table_dnd_insert_child (EggSpreadTable *spread_table,
+static void egg_spread_table_dnd_insert_child_impl (EggSpreadTable *spread_table,
GtkWidget *child,
gint index);
static gint egg_spread_table_dnd_build_segments (EggSpreadTable *table,
@@ -146,6 +163,9 @@ struct _EggSpreadTableDndPrivate {
guint dragging : 1; /* Whether the drag'n'drop operation is currently active over this table */
+ guint steal_events : 1; /* Whether to steal all child events (causes the event-boxes to
+ * place thier event window above all children) */
+
gint disappearing; /* Count of placeholders that are currently disappearing */
/* These states are used to trigger a drag operation on a child widget with no window */
@@ -164,6 +184,7 @@ enum {
LAST_SIGNAL
};
+static GQuark dnd_table_child_quark = 0;
static guint dnd_table_signals [LAST_SIGNAL] = { 0 };
static GdkAtom dnd_target_atom_child = GDK_NONE;
static const GtkTargetEntry dnd_targets[] = {
@@ -177,10 +198,14 @@ G_DEFINE_TYPE (EggSpreadTableDnd, egg_spread_table_dnd, EGG_TYPE_SPREAD_TABLE)
static void
egg_spread_table_dnd_class_init (EggSpreadTableDndClass *class)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
EggSpreadTableClass *spread_class = EGG_SPREAD_TABLE_CLASS (class);
+ gobject_class->get_property = egg_spread_table_dnd_get_property;
+ gobject_class->set_property = egg_spread_table_dnd_set_property;
+
widget_class->realize = egg_spread_table_dnd_realize;
widget_class->button_press_event = egg_spread_table_dnd_button_press;
widget_class->button_release_event = egg_spread_table_dnd_button_release;
@@ -200,12 +225,29 @@ egg_spread_table_dnd_class_init (EggSpreadTableDndClass *class)
container_class->remove = egg_spread_table_dnd_remove;
- spread_class->insert_child = egg_spread_table_dnd_insert_child;
+ spread_class->insert_child = egg_spread_table_dnd_insert_child_impl;
spread_class->build_segments_for_size = egg_spread_table_dnd_build_segments;
class->widget_drop_possible = egg_spread_table_dnd_drop_possible;
/**
+ * EggSpreadTableDnd:steal-events:
+ *
+ * Whether the table should steal all pointer events from added children
+ * for the purpose of Drag'n'Drop.
+ *
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_STEAL_EVENTS,
+ g_param_spec_boolean ("steal-events",
+ P_("Steal Events"),
+ P_("Whether the table should steal all pointer "
+ "events from children"),
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+
+ /**
* EggSpreadTableDnd::widget-drop-possible
*
* Emitted to check if a widget can be dropped into this spread table.
@@ -229,6 +271,7 @@ egg_spread_table_dnd_class_init (EggSpreadTableDndClass *class)
dnd_target_atom_child = gdk_atom_intern_static_string (dnd_targets[0].target);
+ dnd_table_child_quark = g_quark_from_static_string ("egg-spread-table-dnd-child");
g_type_class_add_private (class, sizeof (EggSpreadTableDndPrivate));
}
@@ -259,6 +302,47 @@ egg_spread_table_dnd_init (EggSpreadTableDnd *spread_table)
}
/*****************************************************
+ * GObectClass *
+ *****************************************************/
+static void
+egg_spread_table_dnd_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggSpreadTableDnd *table = EGG_SPREAD_TABLE_DND (object);
+
+ switch (prop_id)
+ {
+ case PROP_STEAL_EVENTS:
+ g_value_set_boolean (value, table->priv->steal_events);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_spread_table_dnd_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggSpreadTableDnd *table = EGG_SPREAD_TABLE_DND (object);
+
+ switch (prop_id)
+ {
+ case PROP_STEAL_EVENTS:
+ egg_spread_table_dnd_set_steal_events (table, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************
* GtkWidgetClass *
*****************************************************/
static void
@@ -716,6 +800,9 @@ egg_spread_table_dnd_drag_motion (GtkWidget *widget,
get_placeholder_size (spread_table, &width, &height);
spread_table->priv->drop_target = egg_placeholder_new (width, height);
+ g_object_set_qdata (G_OBJECT (spread_table->priv->drop_target),
+ dnd_table_child_quark, GINT_TO_POINTER (TRUE));
+
egg_spread_table_insert_child (EGG_SPREAD_TABLE (spread_table),
spread_table->priv->drop_target, index);
adjust_line_segment (spread_table, line, 1);
@@ -813,6 +900,14 @@ static void
egg_spread_table_dnd_remove (GtkContainer *container,
GtkWidget *child)
{
+ if (GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (child), dnd_table_child_quark)) == FALSE)
+ {
+ g_message ("Refusing to remove child widget from EggSpreadTableDnd directly, "
+ "use egg_spread_table_dnd_remove_child() instead.");
+ return;
+ }
+
+
/* Disconnect dnd */
if (!EGG_IS_PLACEHOLDER (child))
{
@@ -831,10 +926,17 @@ egg_spread_table_dnd_remove (GtkContainer *container,
* EggSpreadTableClass *
*****************************************************/
static void
-egg_spread_table_dnd_insert_child (EggSpreadTable *spread_table,
- GtkWidget *child,
- gint index)
+egg_spread_table_dnd_insert_child_impl (EggSpreadTable *spread_table,
+ GtkWidget *child,
+ gint index)
{
+ if (GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (child), dnd_table_child_quark)) == FALSE)
+ {
+ g_message ("Refusing to add child widget to an EggSpreadTableDnd directly, "
+ "use egg_spread_table_dnd_insert_child() instead.");
+ return;
+ }
+
EGG_SPREAD_TABLE_CLASS (egg_spread_table_dnd_parent_class)->insert_child (spread_table, child, index);
/* Connect dnd */
@@ -930,31 +1032,41 @@ static void
set_drag_icon (GtkWidget *widget,
GdkDragContext *context)
{
- GtkWidget *toplevel;
+ GtkAllocation allocation;
cairo_surface_t *surface;
cairo_t *cr;
- gint x, y;
+ GtkStyleContext *style;
+ GdkPixbuf *pixbuf;
+ gint hot_x, hot_y;
- toplevel = gtk_widget_get_toplevel (widget);
+ /* XXX Force allocate here ? need to absolutely have an allocated widget
+ * for this to work (gtk_widget_draw() needs that). */
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- gtk_widget_get_allocated_width (widget),
- gtk_widget_get_allocated_height (widget));
- cr = cairo_create (surface);
+ gtk_widget_get_allocation (widget, &allocation);
+ gtk_widget_get_pointer (widget, &hot_x, &hot_y);
- gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x, &y);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
+ cr = cairo_create (surface);
- cairo_translate (cr, -x, -y);
+ /* Synthetically render a background */
+ style = gtk_widget_get_style_context (widget);
+ gtk_style_context_save (style);
+ gtk_style_context_add_class (style, GTK_STYLE_CLASS_BACKGROUND);
+ gtk_render_background (style, cr, 0, 0, allocation.width, allocation.height);
+ gtk_style_context_restore (style);
- gtk_widget_draw (toplevel, cr);
+ /* Draw the actual widget, this might or might not draw the background */
+ gtk_widget_draw (widget, cr);
- gtk_drag_set_icon_surface (context, surface);
+ /* Make a pixbuf and use that (just to take advantage of the 'hot_x'/'hot_y' parameters) */
+ pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, allocation.width, allocation.height);
+ gtk_drag_set_icon_pixbuf (context, pixbuf, hot_x, hot_y);
+ g_object_unref (pixbuf);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
-
static void
drag_begin (GtkWidget *widget,
GdkDragContext *context,
@@ -963,6 +1075,9 @@ drag_begin (GtkWidget *widget,
GtkAllocation allocation;
gint drop_index;
+ /* Set the icon for the drag */
+ set_drag_icon (widget, context);
+
/* Mark the spread table for an active drag */
lock_table (spread_table);
spread_table->priv->dragging = TRUE;
@@ -981,6 +1096,9 @@ drag_begin (GtkWidget *widget,
/* Create a placeholder of the correct dimentions and insert it at the drag origin */
gtk_widget_get_allocation (widget, &allocation);
spread_table->priv->drop_target = egg_placeholder_new (allocation.width, allocation.height);
+ g_object_set_qdata (G_OBJECT (spread_table->priv->drop_target),
+ dnd_table_child_quark, GINT_TO_POINTER (TRUE));
+
egg_spread_table_insert_child (EGG_SPREAD_TABLE (spread_table),
spread_table->priv->drop_target,
@@ -990,9 +1108,6 @@ drag_begin (GtkWidget *widget,
adjust_line_segment (spread_table,
get_child_line (spread_table, spread_table->priv->drop_target), 1);
- /* Set the icon for the drag */
- set_drag_icon (spread_table->priv->drag_child, context);
-
/* Hide the drag child (we cant remove it because it needs a GdkWindow in the mean time) */
gtk_widget_hide (spread_table->priv->drag_child);
}
@@ -1280,3 +1395,100 @@ egg_spread_table_dnd_new (GtkOrientation orientation,
"lines", lines,
NULL);
}
+
+/**
+ * egg_spread_table_dnd_insert_child:
+ * @table: An #EggSpreadTableDnd
+ * @child: The child widget to insert.
+ *
+ * Adds a child widget to an #EggSpreadTableDnd.
+ *
+ * <note><para>Regular #GtkContainer apis and #EggSpreadTable
+ * apis are inappropriate for adding children as those
+ * are reserved for internal use by the #EggSpreadTableDnd.</para></note>
+ */
+void
+egg_spread_table_dnd_insert_child (EggSpreadTableDnd *table,
+ GtkWidget *child,
+ gint index)
+{
+ GtkWidget *event_box;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE_DND (table));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ event_box = gtk_event_box_new ();
+ gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), table->priv->steal_events);
+ g_object_set_qdata (G_OBJECT (event_box), dnd_table_child_quark, GINT_TO_POINTER (TRUE));
+ gtk_widget_show (event_box);
+
+ gtk_container_add (GTK_CONTAINER (event_box), child);
+ egg_spread_table_insert_child (EGG_SPREAD_TABLE (table), event_box, index);
+}
+
+/**
+ * egg_spread_table_dnd_remove_child:
+ * @table: An #EggSpreadTableDnd
+ * @child: The child widget to insert.
+ *
+ * Adds a child widget to an #EggSpreadTableDnd.
+ *
+ * <note><para>Regular #GtkContainer apis and #EggSpreadTable
+ * apis are inappropriate for removing children as those
+ * are reserved for internal use by the #EggSpreadTableDnd.</para></note>
+ */
+void
+egg_spread_table_dnd_remove_child (EggSpreadTableDnd *table,
+ GtkWidget *child)
+{
+ GtkWidget *event_box;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE_DND (table));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ event_box = gtk_widget_get_parent (child);
+
+ if (GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (event_box), dnd_table_child_quark)) == FALSE)
+ {
+ g_message ("Bad hierarchy encountered in egg_spread_table_dnd_remove_child().");
+ return;
+ }
+
+ /* unparent the user's child and remove the intermediate spread-table owned event-box. */
+ gtk_container_remove (GTK_CONTAINER (event_box), child);
+ gtk_container_remove (GTK_CONTAINER (table), event_box);
+}
+
+static void
+flip_event_windows (GtkEventBox *child,
+ EggSpreadTableDnd *table)
+{
+ /* Besides the internally owned event boxes, only EggPlaceholders can exist
+ * as direct children of the EggSpreadTableDnd */
+ if (GTK_IS_EVENT_BOX (child))
+ gtk_event_box_set_above_child (child, table->priv->steal_events);
+}
+
+void
+egg_spread_table_dnd_set_steal_events (EggSpreadTableDnd *table,
+ gboolean steal_events)
+{
+ g_return_if_fail (EGG_IS_SPREAD_TABLE_DND (table));
+
+ if (table->priv->steal_events != steal_events)
+ {
+ table->priv->steal_events = steal_events;
+
+ gtk_container_forall (GTK_CONTAINER (table), (GtkCallback)flip_event_windows, table);
+
+ g_object_notify (G_OBJECT (table), "steal-events");
+ }
+}
+
+gboolean
+egg_spread_table_dnd_get_steal_events (EggSpreadTableDnd *table)
+{
+ g_return_val_if_fail (EGG_IS_SPREAD_TABLE_DND (table), FALSE);
+
+ return table->priv->steal_events;
+}
diff --git a/libegg/spreadtable/eggspreadtablednd.h b/libegg/spreadtable/eggspreadtablednd.h
index 36c323b..dba5dc7 100644
--- a/libegg/spreadtable/eggspreadtablednd.h
+++ b/libegg/spreadtable/eggspreadtablednd.h
@@ -57,9 +57,17 @@ struct _EggSpreadTableDndClass
};
GType egg_spread_table_dnd_get_type (void) G_GNUC_CONST;
-GtkWidget *egg_spread_table_dnd_new (GtkOrientation orientation,
- guint lines);
-
+GtkWidget *egg_spread_table_dnd_new (GtkOrientation orientation,
+ guint lines);
+
+void egg_spread_table_dnd_insert_child (EggSpreadTableDnd *table,
+ GtkWidget *child,
+ gint index);
+void egg_spread_table_dnd_remove_child (EggSpreadTableDnd *table,
+ GtkWidget *child);
+void egg_spread_table_dnd_set_steal_events (EggSpreadTableDnd *table,
+ gboolean steal_events);
+gboolean egg_spread_table_dnd_get_steal_events (EggSpreadTableDnd *table);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]