summaryrefslogtreecommitdiff
path: root/demos
diff options
context:
space:
mode:
authorJohannes Schmid <jhs@gnome.org>2009-11-18 10:32:37 +0100
committerJohannes Schmid <jhs@gnome.org>2009-11-18 10:32:37 +0100
commit3cc1478a2951da5b3ba626d31747ab2d1dc96fea (patch)
tree3e8e6865e249d5f3819a29c407fd4935468595cc /demos
parentffce5223fcb9e71b09c996d04c7fe41483741307 (diff)
downloadgtk+-3cc1478a2951da5b3ba626d31747ab2d1dc96fea.tar.gz
toolpalette: Added dnd code to the gtk-demo
Diffstat (limited to 'demos')
-rw-r--r--demos/gtk-demo/toolpalette.c425
1 files changed, 424 insertions, 1 deletions
diff --git a/demos/gtk-demo/toolpalette.c b/demos/gtk-demo/toolpalette.c
index befa2a09ec..4ec62e4d67 100644
--- a/demos/gtk-demo/toolpalette.c
+++ b/demos/gtk-demo/toolpalette.c
@@ -13,6 +13,351 @@ static void load_stock_items (GtkToolPalette *palette);
static void load_toggle_items (GtkToolPalette *palette);
static void load_special_items (GtkToolPalette *palette);
+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,
+ GtkToolItemGroup *drop_group,
+ gint x,
+ gint y)
+{
+ GtkWidget *drag_group = gtk_widget_get_parent (GTK_WIDGET (drag_item));
+ GtkToolItem *drop_item = gtk_tool_item_group_get_drop_item (drop_group, x, y);
+ gint drop_position = -1;
+
+ if (drop_item)
+ drop_position = gtk_tool_item_group_get_item_position (GTK_TOOL_ITEM_GROUP (drop_group), drop_item);
+
+ if (GTK_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));
+ gtk_tool_item_group_insert (GTK_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
+ gtk_tool_item_group_set_item_position (GTK_TOOL_ITEM_GROUP (drop_group),
+ drag_item, drop_position);
+}
+
+static void
+palette_drop_group (GtkToolPalette *palette,
+ GtkWidget *drag_group,
+ GtkWidget *drop_group)
+{
+ gint drop_position = -1;
+
+ if (drop_group)
+ drop_position = gtk_tool_palette_get_group_position (palette, drop_group);
+
+ gtk_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 && !GTK_IS_TOOL_PALETTE (drag_palette))
+ drag_palette = gtk_widget_get_parent (drag_palette);
+
+ if (drag_palette)
+ {
+ drag_item = gtk_tool_palette_get_drag_item (GTK_TOOL_PALETTE (drag_palette), selection);
+ drop_group = gtk_tool_palette_get_drop_group (GTK_TOOL_PALETTE (widget), x, y);
+ }
+
+ if (GTK_IS_TOOL_ITEM_GROUP (drag_item))
+ palette_drop_group (GTK_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),
+ GTK_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 && !GTK_IS_TOOL_PALETTE (palette))
+ palette = gtk_widget_get_parent (palette);
+
+ if (palette)
+ tool_item = gtk_tool_palette_get_drag_item (GTK_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 && !GTK_IS_TOOL_PALETTE (palette))
+ palette = gtk_widget_get_parent (palette);
+
+ if (palette)
+ tool_item = gtk_tool_palette_get_drag_item (GTK_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);
+}
+
static void on_combo_orientation_changed(GtkComboBox *combo_box, gpointer user_data)
{
GtkToolPalette *palette = GTK_TOOL_PALETTE (user_data);
@@ -56,6 +401,7 @@ GtkWidget *
do_toolpalette (GtkWidget *do_widget)
{
GtkWidget *box = NULL;
+ GtkWidget *hbox = NULL;
GtkWidget *combo_orientation = NULL;
GtkListStore *combo_orientation_model = NULL;
GtkWidget *combo_style = NULL;
@@ -64,6 +410,9 @@ do_toolpalette (GtkWidget *do_widget)
GtkTreeIter iter;
GtkWidget *palette = NULL;
GtkWidget *palette_scroller = NULL;
+ GtkWidget *notebook = NULL;
+ GtkWidget *contents = NULL;
+ GtkWidget *contents_scroller = NULL;
if (!window)
{
@@ -129,6 +478,10 @@ do_toolpalette (GtkWidget *do_widget)
&iter);
gtk_box_pack_start (GTK_BOX (box), combo_style, FALSE, FALSE, 0);
+ /* Add hbox */
+ hbox = gtk_hbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (box), hbox, TRUE, TRUE, 0);
+
/* Add and fill the ToolPalette: */
palette = gtk_tool_palette_new ();
@@ -142,7 +495,7 @@ do_toolpalette (GtkWidget *do_widget)
gtk_container_set_border_width (GTK_CONTAINER (palette_scroller), 6);
gtk_container_add (GTK_CONTAINER (palette_scroller), palette);
- gtk_container_add (GTK_CONTAINER (box), palette_scroller);
+ gtk_container_add (GTK_CONTAINER (hbox), palette_scroller);
gtk_widget_show_all (box);
@@ -154,6 +507,76 @@ do_toolpalette (GtkWidget *do_widget)
/* Keep the widgets in sync: */
on_combo_orientation_changed (GTK_COMBO_BOX (combo_orientation), palette);
+
+ /* ===== notebook ===== */
+
+ notebook = gtk_notebook_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
+ gtk_box_pack_end (GTK_BOX(hbox), notebook, FALSE, FALSE, 0);
+
+ /* ===== DnD for tool items ===== */
+
+ g_signal_connect (palette, "drag-data-received",
+ G_CALLBACK (palette_drag_data_received),
+ NULL);
+
+ gtk_tool_palette_add_drag_dest (GTK_TOOL_PALETTE (palette),
+ palette, GTK_DEST_DEFAULT_ALL,
+ GTK_TOOL_PALETTE_DRAG_ITEMS |
+ GTK_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);
+
+ gtk_tool_palette_add_drag_dest (GTK_TOOL_PALETTE (palette),
+ contents, GTK_DEST_DEFAULT_ALL,
+ GTK_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);
+
+ gtk_tool_palette_add_drag_dest (GTK_TOOL_PALETTE (palette),
+ contents, GTK_DEST_DEFAULT_HIGHLIGHT,
+ GTK_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"));
+
}
if (!GTK_WIDGET_VISIBLE (window))