diff options
Diffstat (limited to 'demos')
-rw-r--r-- | demos/gtk-demo/toolpalette.c | 425 |
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)) |