diff options
author | Juan Pablo Ugarte <juanpablougarte@gmail.com> | 2012-12-17 22:35:51 -0300 |
---|---|---|
committer | Juan Pablo Ugarte <juanpablougarte@gmail.com> | 2013-01-18 19:56:05 -0300 |
commit | f19314fe1cd81e369145c607a3231a7ddcebf3b5 (patch) | |
tree | 3334717660425ee9b4f0c9d841802715fb545574 | |
parent | f8151e4584eff38f9392700485961324133aa6c7 (diff) | |
download | glade-f19314fe1cd81e369145c607a3231a7ddcebf3b5.tar.gz |
Implemented inline Drag and Drop
-rw-r--r-- | gladeui/glade-design-layout.c | 262 | ||||
-rw-r--r-- | gladeui/glade-design-private.h | 12 | ||||
-rw-r--r-- | gladeui/glade-design-view.c | 580 | ||||
-rw-r--r-- | plugins/gtk+/glade-fixed.c | 24 | ||||
-rw-r--r-- | plugins/gtk+/glade-gtk.c | 3 |
5 files changed, 647 insertions, 234 deletions
diff --git a/gladeui/glade-design-layout.c b/gladeui/glade-design-layout.c index 8a180c10..210555b7 100644 --- a/gladeui/glade-design-layout.c +++ b/gladeui/glade-design-layout.c @@ -38,6 +38,7 @@ #define GLADE_DESIGN_LAYOUT_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \ GLADE_TYPE_DESIGN_LAYOUT, \ GladeDesignLayoutPrivate)) +#define GLADE_DESIGN_LAYOUT_PRIVATE(object) (((GladeDesignLayout*)object)->priv) #define OUTLINE_WIDTH 4 #define PADDING 12 @@ -104,6 +105,11 @@ struct _GladeDesignLayoutPrivate gint new_width; /* user's new requested width */ gint new_height; /* user's new requested height */ + /* Drag & Drop */ + GtkWidget *drag_source; + GtkWidget *drag_icon; + gint drag_x, drag_y; + /* Properties */ GladeDesignView *view; GladeProject *project; @@ -227,7 +233,7 @@ glade_design_layout_leave_notify_event (GtkWidget *widget, GdkEventCrossing *ev) ev->window != gtk_widget_get_window (widget)) return FALSE; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); if (priv->activity == ACTIVITY_NONE) gdl_set_cursor (priv, NULL); @@ -355,11 +361,23 @@ glade_design_layout_motion_notify_event (GtkWidget *widget, GdkEventMotion *ev) if ((child = gtk_bin_get_child (GTK_BIN (widget))) == NULL) return FALSE; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); x = ev->x; y = ev->y; + if (ev->state & GDK_BUTTON1_MASK && priv->drag_source && + gtk_drag_check_threshold (priv->drag_source, priv->drag_x, priv->drag_y, x, y)) + { + static GtkTargetList *target = NULL; + + if (target == NULL) + target = gtk_target_list_new (_glade_design_layout_get_dnd_target (), 1); + + gtk_drag_begin (widget, target, GDK_ACTION_COPY, 1, (GdkEvent*)ev); + return TRUE; + } + gtk_widget_get_allocation (child, &allocation); allocation.x += priv->child_offset; @@ -573,7 +591,7 @@ glade_design_layout_button_press_event (GtkWidget *widget, GdkEventButton *ev) (child = gtk_bin_get_child (GTK_BIN (widget))) == NULL) return FALSE; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); x = ev->x; y = ev->y; @@ -695,7 +713,7 @@ glade_design_layout_button_release_event (GtkWidget *widget, if ((child = gtk_bin_get_child (GTK_BIN (widget))) == NULL) return FALSE; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); /* Check if margins where edited and execute corresponding glade command */ if (priv->selection && priv->activity == ACTIVITY_MARGINS) @@ -756,7 +774,7 @@ glade_design_layout_get_preferred_height (GtkWidget *widget, gint child_height = 0; guint border_width = 0; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); *minimum = 0; @@ -889,7 +907,7 @@ glade_design_layout_size_allocate (GtkWidget *widget, if (child && gtk_widget_get_visible (child)) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); GtkAllocation alloc; gint height, offset; @@ -917,7 +935,7 @@ glade_design_layout_size_allocate (GtkWidget *widget, static void on_glade_widget_name_notify (GObject *gobject, GParamSpec *pspec, GladeDesignLayout *layout) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout); + GladeDesignLayoutPrivate *priv = layout->priv; pango_layout_set_text (priv->widget_name, glade_widget_get_name (GLADE_WIDGET (gobject)), -1); gtk_widget_queue_resize (GTK_WIDGET (layout)); @@ -926,8 +944,8 @@ on_glade_widget_name_notify (GObject *gobject, GParamSpec *pspec, GladeDesignLay static void glade_design_layout_add (GtkContainer *container, GtkWidget *widget) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (container); GladeDesignLayout *layout = GLADE_DESIGN_LAYOUT (container); + GladeDesignLayoutPrivate *priv = layout->priv; GladeWidget *gchild; layout->priv->current_width = 0; @@ -1179,7 +1197,7 @@ draw_selection (cairo_t *cr, cairo_stroke (cr); } -#define DIMENSION_OFFSET 10 +#define DIMENSION_OFFSET 9 #define DIMENSION_LINE_OFFSET 4 static void @@ -1489,7 +1507,7 @@ draw_selection_nodes (cairo_t *cr, static gboolean glade_design_layout_draw (GtkWidget *widget, cairo_t *cr) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); GdkWindow *window = gtk_widget_get_window (widget); if (gtk_cairo_should_draw_window (cr, window)) @@ -1568,7 +1586,7 @@ to_child (GladeDesignLayout *bin, double *x_out, double *y_out) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (bin); + GladeDesignLayoutPrivate *priv = bin->priv; *x_out = widget_x - priv->child_offset; *y_out = widget_y - priv->child_offset; } @@ -1580,7 +1598,7 @@ to_parent (GladeDesignLayout *bin, double *x_out, double *y_out) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (bin); + GladeDesignLayoutPrivate *priv = bin->priv; *x_out = offscreen_x + priv->child_offset; *y_out = offscreen_y + priv->child_offset; } @@ -1591,7 +1609,7 @@ pick_offscreen_child (GdkWindow *offscreen_window, double widget_y, GladeDesignLayout *bin) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (bin); + GladeDesignLayoutPrivate *priv = bin->priv; GtkWidget *child = gtk_bin_get_child (GTK_BIN (bin)); if (child && gtk_widget_get_visible (child)) @@ -1660,12 +1678,11 @@ glade_design_layout_realize (GtkWidget * widget) { GladeDesignLayoutPrivate *priv; GdkWindowAttr attributes; - GtkWidget *child; gint attributes_mask, border_width; GtkAllocation allocation; GdkDisplay *display; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); gtk_widget_set_realized (widget, TRUE); @@ -1700,26 +1717,14 @@ glade_design_layout_realize (GtkWidget * widget) G_CALLBACK (pick_offscreen_child), widget); /* Offscreen window */ - child = gtk_bin_get_child (GTK_BIN (widget)); attributes.window_type = GDK_WINDOW_OFFSCREEN; attributes.x = attributes.y = 0; - - if (child && gtk_widget_get_visible (child)) - { - GtkAllocation alloc; - - gtk_widget_get_allocation (child, &alloc); - attributes.width = alloc.width; - attributes.height = alloc.height; - } - else - attributes.width = attributes.height = 0; + attributes.width = attributes.height = 0; priv->offscreen_window = gdk_window_new (gtk_widget_get_root_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (priv->offscreen_window, widget); - if (child) gtk_widget_set_parent_window (child, priv->offscreen_window); gdk_offscreen_window_set_embedder (priv->offscreen_window, priv->window); g_signal_connect (priv->offscreen_window, "to-embedder", @@ -1756,7 +1761,7 @@ glade_design_layout_unrealize (GtkWidget * widget) GladeDesignLayoutPrivate *priv; gint i; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (widget); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); if (priv->offscreen_window) { @@ -1786,26 +1791,6 @@ glade_design_layout_unrealize (GtkWidget * widget) GTK_WIDGET_CLASS (glade_design_layout_parent_class)->unrealize (widget); } -void -_glade_design_layout_get_colors (GtkStyleContext *context, - GdkRGBA *c1, GdkRGBA *c2, - GdkRGBA *c3, GdkRGBA *c4) -{ - gfloat off; - - gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, c1); - gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, c2); - - gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, c3); - gtk_style_context_get_color (context, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, c4); - - off = ((c1->red + c1->green + c1->blue)/3 < .5) ? .16 : -.16; - - c1->red += off; - c1->green += off; - c1->blue += off; -} - static void glade_design_layout_style_updated (GtkWidget *widget) { @@ -1883,7 +1868,7 @@ glade_design_layout_set_property (GObject *object, { case PROP_DESIGN_VIEW: { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object); + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (object); priv->view = GLADE_DESIGN_VIEW (g_value_get_object (value)); priv->project = glade_design_view_get_project (priv->view); g_signal_connect (priv->project, "notify::pointer-mode", @@ -1907,7 +1892,7 @@ glade_design_layout_get_property (GObject *object, switch (prop_id) { case PROP_DESIGN_VIEW: - g_value_set_object (value, GLADE_DESIGN_LAYOUT_GET_PRIVATE (object)->view); + g_value_set_object (value, GLADE_DESIGN_LAYOUT_PRIVATE (object)->view); break; default: @@ -1919,7 +1904,7 @@ glade_design_layout_get_property (GObject *object, static void on_project_selection_changed (GladeProject *project, GladeDesignLayout *layout) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout); + GladeDesignLayoutPrivate *priv = layout->priv; GladePointerMode mode = glade_project_get_pointer_mode (project); if (priv->selection) @@ -1943,7 +1928,7 @@ glade_design_layout_constructor (GType type, n_construct_params, construct_params); - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object); + priv = GLADE_DESIGN_LAYOUT_PRIVATE (object); g_signal_connect (priv->project, "selection-changed", @@ -1958,19 +1943,100 @@ glade_design_layout_constructor (GType type, static void glade_design_layout_finalize (GObject *object) { - GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (object); + GladeDesignLayout *layout = GLADE_DESIGN_LAYOUT (object); + GladeDesignLayoutPrivate *priv = layout->priv; g_signal_handlers_disconnect_by_func (priv->project, on_project_selection_changed, - GLADE_DESIGN_LAYOUT (object)); + layout); g_signal_handlers_disconnect_by_func (priv->project, on_pointer_mode_notify, - GLADE_DESIGN_LAYOUT (object)); + layout); G_OBJECT_CLASS (glade_design_layout_parent_class)->finalize (object); } static void +glade_design_layout_drag_begin (GtkWidget *widget, GdkDragContext *context) +{ + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); + cairo_pattern_t *pattern; + cairo_surface_t *surface; + GtkAllocation alloc; + GtkWidget *window; + GdkScreen *screen; + cairo_t *cr; + gint x, y; + + gtk_widget_get_allocation (priv->drag_source, &alloc); + + gtk_widget_translate_coordinates (priv->drag_source, widget, + alloc.x, alloc.y, + &x, &y); + + screen = gdk_window_get_screen (gdk_drag_context_get_source_window (context)); + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND); + gtk_window_set_screen (GTK_WINDOW (window), screen); + + gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_widget_set_app_paintable (window, TRUE); + + gtk_widget_set_size_request (window, alloc.width, alloc.height); + gtk_widget_realize (window); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, alloc.width, alloc.height); + cr = cairo_create (surface); + + gdk_cairo_set_source_window (cr, priv->window, alloc.x - x, alloc.y - y); + cairo_paint (cr); + cairo_surface_flush (surface); + + pattern = cairo_pattern_create_for_surface (surface); + + gdk_window_set_background_pattern (gtk_widget_get_window (window), pattern); + + gtk_window_set_opacity (GTK_WINDOW (window), .5); + gtk_drag_set_icon_widget (context, window, priv->drag_x, priv->drag_y); + + cairo_destroy (cr); + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + priv->drag_icon = g_object_ref_sink (window); +} + +static void +glade_design_layout_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *data, + guint info, + guint time) +{ + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); + + if (priv->drag_source) + { + static GdkAtom type = 0; + + if (!type) + type = gdk_atom_intern_static_string (GDL_DND_TARGET_WIDGET); + + gtk_selection_data_set (data, type, sizeof (gpointer), + (const guchar *)&priv->drag_source, sizeof (gpointer)); + } +} + +static void +glade_design_layout_drag_end (GtkWidget *widget, GdkDragContext *context) +{ + GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget); + + g_clear_object (&priv->drag_icon); + priv->drag_source = NULL; +} + +static void glade_design_layout_class_init (GladeDesignLayoutClass * klass) { GObjectClass *object_class; @@ -2002,6 +2068,9 @@ glade_design_layout_class_init (GladeDesignLayoutClass * klass) widget_class->get_preferred_height_for_width = glade_design_layout_get_preferred_height_for_width; widget_class->size_allocate = glade_design_layout_size_allocate; widget_class->style_updated = glade_design_layout_style_updated; + widget_class->drag_begin = glade_design_layout_drag_begin; + widget_class->drag_end = glade_design_layout_drag_end; + widget_class->drag_data_get = glade_design_layout_drag_data_get; g_object_class_install_property (object_class, PROP_DESIGN_VIEW, g_param_spec_object ("design-view", _("Design View"), @@ -2131,6 +2200,60 @@ _glade_design_layout_coords_from_event (GdkWindow *parent, *y = yy; } +void +_glade_design_layout_get_colors (GtkStyleContext *context, + GdkRGBA *c1, GdkRGBA *c2, + GdkRGBA *c3, GdkRGBA *c4) +{ + gfloat off; + + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, c1); + gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, c2); + + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, c3); + gtk_style_context_get_color (context, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, c4); + + off = ((c1->red + c1->green + c1->blue)/3 < .5) ? .16 : -.16; + + c1->red += off; + c1->green += off; + c1->blue += off; +} + +GtkTargetEntry * +_glade_design_layout_get_dnd_target (void) +{ + static GtkTargetEntry target = {GDL_DND_TARGET_WIDGET, GTK_TARGET_SAME_APP, GDL_DND_INFO_WIDGET}; + return ⌖ +} + +void +_glade_design_layout_get_hot_point (GladeDesignLayout *layout, + gint *x, + gint *y) +{ + GladeDesignLayoutPrivate *priv = layout->priv; + + if (x) + *x = priv->drag_x; + + if (y) + *y = priv->drag_y; +} + +static gboolean +widget_is_inside_fixed (GladeWidget *widget) +{ + while (widget) + { + if (GTK_IS_FIXED (glade_widget_get_object (widget))) + return TRUE; + widget = glade_widget_get_parent (widget); + } + + return FALSE; +} + /* * _glade_design_layout_do_event: * @layout: A #GladeDesignLayout @@ -2147,15 +2270,38 @@ _glade_design_layout_do_event (GladeDesignLayout *layout, GdkEvent *event) GtkWidget *widget = GTK_WIDGET (layout); GladeFindInContainerData data = { widget, 0, }; GladeDesignLayoutPrivate *priv; + GladePointerMode mode; gboolean retval; GList *l; - priv = GLADE_DESIGN_LAYOUT_GET_PRIVATE (layout); + priv = layout->priv; _glade_design_layout_coords_from_event (priv->window, event, &data.x, &data.y); + mode = glade_project_get_pointer_mode (priv->project); + glade_design_layout_find_inside_container (widget, &data); + + if (event->type == GDK_BUTTON_PRESS && event->button.button == 1 && + ((event->button.state & GDK_SHIFT_MASK && mode == GLADE_POINTER_SELECT) || + mode == GLADE_POINTER_DRAG_RESIZE)) + { + GObject *source; + + if (data.gwidget && (source = glade_widget_get_object (data.gwidget)) && + (event->button.state & GDK_SHIFT_MASK || !widget_is_inside_fixed (data.gwidget))) + { + priv->drag_source = GTK_WIDGET (source); + + gtk_widget_translate_coordinates (widget, priv->drag_source, + data.x, data.y, + &priv->drag_x, &priv->drag_y); + return TRUE; + } + } + /* Check if we want to enter in margin edit mode */ if (event->type == GDK_BUTTON_PRESS && event->button.button == 1 && + mode != GLADE_POINTER_DRAG_RESIZE && (l = glade_project_selection_get (priv->project)) && g_list_next (l) == NULL && GTK_IS_WIDGET (l->data) && gtk_widget_is_ancestor (l->data, widget)) @@ -2175,8 +2321,6 @@ _glade_design_layout_do_event (GladeDesignLayout *layout, GdkEvent *event) } _glade_design_view_freeze (priv->view); - - glade_design_layout_find_inside_container (widget, &data); /* Try the placeholder first */ if (data.placeholder && gtk_widget_event (data.placeholder, event)) diff --git a/gladeui/glade-design-private.h b/gladeui/glade-design-private.h index a6babecf..a8046f48 100644 --- a/gladeui/glade-design-private.h +++ b/gladeui/glade-design-private.h @@ -25,6 +25,12 @@ #ifndef __GLADE_DESIGN_PRIVATE_H__ #define __GLADE_DESIGN_PRIVATE_H__ +#define GDL_DND_INFO_WIDGET 15956 +#define GDL_DND_TARGET_WIDGET "glade/x-widget" + +#include "glade-design-view.h" +#include "glade-design-layout.h" + G_BEGIN_DECLS void _glade_design_view_freeze (GladeDesignView *view); @@ -47,6 +53,12 @@ void _glade_design_layout_draw_pushpin (cairo_t *cr, GdkRGBA *bg, GdkRGBA *fg); +void _glade_design_layout_get_hot_point (GladeDesignLayout *layout, + gint *x, + gint *y); + +GtkTargetEntry *_glade_design_layout_get_dnd_target (void); + G_END_DECLS #endif /* __GLADE_DESIGN_PRIVATE_H__ */ diff --git a/gladeui/glade-design-view.c b/gladeui/glade-design-view.c index aae16ff4..fa931429 100644 --- a/gladeui/glade-design-view.c +++ b/gladeui/glade-design-view.c @@ -63,6 +63,8 @@ struct _GladeDesignViewPrivate GtkToolPalette *palette; GladeWidgetAdaptor *drag_adaptor; + GtkWidget *drag_source; + GtkWidget *drag_target; }; static GtkVBoxClass *parent_class = NULL; @@ -103,30 +105,36 @@ on_layout_size_allocate (GtkWidget *widget, GtkAllocation *alloc, GladeDesignVie static void glade_design_view_selection_changed (GladeProject *project, GladeDesignView *view) { - GladeWidget *gwidget, *gtoplevel; - GObject *toplevel; - GtkWidget *layout; GList *selection; /* Check if its only one widget selected and scroll viewport to show toplevel */ if ((selection = glade_project_selection_get (project)) && g_list_next (selection) == NULL && - GTK_IS_WIDGET (selection->data) && - !GLADE_IS_PLACEHOLDER (selection->data) && - (gwidget = glade_widget_get_from_gobject (G_OBJECT (selection->data))) && - (gtoplevel = glade_widget_get_toplevel (gwidget)) && - (toplevel = glade_widget_get_object (gtoplevel)) && - GTK_IS_WIDGET (toplevel) && - (layout = gtk_widget_get_parent (GTK_WIDGET (toplevel))) && - GLADE_IS_DESIGN_LAYOUT (layout)) + GTK_IS_WIDGET (selection->data)) { - GtkAllocation alloc; - gtk_widget_get_allocation (layout, &alloc); - - if (alloc.x < 0) - g_signal_connect (layout, "size-allocate", G_CALLBACK (on_layout_size_allocate), view); - else - glade_design_layout_scroll (view, alloc.x, alloc.y, alloc.width, alloc.height); + GladeWidget *gwidget, *gtoplevel; + GObject *toplevel; + + if (!GLADE_IS_PLACEHOLDER (selection->data) && + (gwidget = glade_widget_get_from_gobject (G_OBJECT (selection->data))) && + (gtoplevel = glade_widget_get_toplevel (gwidget)) && + (toplevel = glade_widget_get_object (gtoplevel)) && + GTK_IS_WIDGET (toplevel)) + { + GtkWidget *layout; + + if ((layout = gtk_widget_get_parent (GTK_WIDGET (toplevel))) && + GLADE_IS_DESIGN_LAYOUT (layout)) + { + GtkAllocation alloc; + gtk_widget_get_allocation (layout, &alloc); + + if (alloc.x < 0) + g_signal_connect (layout, "size-allocate", G_CALLBACK (on_layout_size_allocate), view); + else + glade_design_layout_scroll (view, alloc.x, alloc.y, alloc.width, alloc.height); + } + } } } @@ -151,8 +159,9 @@ glade_design_view_add_toplevel (GladeDesignView *view, GladeWidget *widget) if ((toplevels = glade_project_toplevels (view->priv->project))) gtk_box_reorder_child (GTK_BOX (view->priv->layout_box), layout, g_list_index (toplevels, GTK_WIDGET (object))); - + gtk_container_add (GTK_CONTAINER (layout), GTK_WIDGET (object)); + gtk_widget_show (GTK_WIDGET (object)); gtk_widget_show (layout); } @@ -326,7 +335,6 @@ glade_design_view_init (GladeDesignView *view) view->priv->layout_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_valign (view->priv->layout_box, GTK_ALIGN_START); gtk_container_set_border_width (GTK_CONTAINER (view->priv->layout_box), 0); - gtk_box_pack_end (GTK_BOX (view->priv->layout_box), gtk_fixed_new (), FALSE, FALSE, 0); view->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW @@ -354,95 +362,16 @@ glade_design_view_init (GladeDesignView *view) } static void -glade_design_view_class_init (GladeDesignViewClass *klass) -{ - GObjectClass *object_class; - GtkWidgetClass *widget_class; - - parent_class = g_type_class_peek_parent (klass); - object_class = G_OBJECT_CLASS (klass); - widget_class = GTK_WIDGET_CLASS (klass); - - object_class->get_property = glade_design_view_get_property; - object_class->set_property = glade_design_view_set_property; - - widget_class->draw = glade_design_view_draw; - - g_object_class_install_property (object_class, - PROP_PROJECT, - g_param_spec_object ("project", - "Project", - "The project for this view", - GLADE_TYPE_PROJECT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, - PROP_DRAG_SOURCE, - g_param_spec_object ("drag-source", - "Drag Source", - "A palette to use as the source of drag events for this view", - GTK_TYPE_TOOL_PALETTE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GladeDesignViewPrivate)); -} - -/* Private API */ - -void -_glade_design_view_freeze (GladeDesignView *view) -{ - g_return_if_fail (GLADE_IS_DESIGN_VIEW (view)); - - g_signal_handlers_block_by_func (view->priv->project, - glade_design_view_selection_changed, - view); -} - -void -_glade_design_view_thaw (GladeDesignView *view) -{ - g_return_if_fail (GLADE_IS_DESIGN_VIEW (view)); - - g_signal_handlers_unblock_by_func (view->priv->project, - glade_design_view_selection_changed, - view); -} - -/* Public API */ - -GladeProject * -glade_design_view_get_project (GladeDesignView *view) -{ - g_return_val_if_fail (GLADE_IS_DESIGN_VIEW (view), NULL); - - return view->priv->project; - -} - -GtkWidget * -glade_design_view_new (GladeProject *project) +glade_design_view_finalize (GObject *object) { - GladeDesignView *view; + GladeDesignView *view = GLADE_DESIGN_VIEW (object); + GladeDesignViewPrivate *priv = view->priv; - g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL); - - view = g_object_new (GLADE_TYPE_DESIGN_VIEW, "project", project, NULL); - - return GTK_WIDGET (view); -} - -GladeDesignView * -glade_design_view_get_from_project (GladeProject *project) -{ - gpointer p; - - g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL); - - p = g_object_get_data (G_OBJECT (project), GLADE_DESIGN_VIEW_KEY); - - return (p != NULL) ? GLADE_DESIGN_VIEW (p) : NULL; + /* Yup, disconnect every handler that reference this view */ + g_signal_handlers_disconnect_by_data (priv->project, view); + g_signal_handlers_disconnect_by_data (priv->project, priv->scrolled_window); + G_OBJECT_CLASS (parent_class)->finalize (object); } static GtkWidget * @@ -486,107 +415,419 @@ widget_get_child_from_position (GtkWidget *toplevel, GtkWidget *widget, gint x, return retval; } +static GtkWidget * +widget_get_gchild_from_position (GtkWidget *toplevel, GtkWidget *widget, gint x, gint y) +{ + GtkWidget *retval = widget_get_child_from_position (toplevel, widget, x, y); + + while (retval) + { + if (retval == toplevel || GLADE_IS_PLACEHOLDER (retval) || + glade_widget_get_from_gobject (retval)) + return retval; + + retval = gtk_widget_get_parent (retval); + } + + return NULL; +} + static gboolean -widget_is_outside_glade_ancestor (GtkWidget *widget) +drag_highlight_draw (GtkWidget *widget, cairo_t *cr, GladeDesignView *view) { - while (widget) + GtkStyleContext *context; + gint width, height; + GdkRGBA c; + + context = gtk_widget_get_style_context (GTK_WIDGET (view)); + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED | + GTK_STATE_FLAG_FOCUSED, &c); + + if (GLADE_IS_PLACEHOLDER (widget)) { - if (glade_widget_get_from_gobject (widget)) - return TRUE; + cairo_pattern_t *gradient; + gdouble w, h; - widget = gtk_widget_get_parent (widget); + w = gtk_widget_get_allocated_width (widget)/2.0; + h = gtk_widget_get_allocated_height (widget)/2.0; + gradient = cairo_pattern_create_radial (w, h, MIN (width, height)/6, + w, h, MAX (w, h)); + cairo_pattern_add_color_stop_rgba (gradient, 0, c.red, c.green, c.blue, .08); + cairo_pattern_add_color_stop_rgba (gradient, 1, c.red, c.green, c.blue, .28); + + cairo_set_source (cr, gradient); + + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + cairo_pattern_destroy (gradient); + } + else + { + cairo_set_line_width (cr, 2); + gdk_cairo_set_source_rgba (cr, &c); + cairo_rectangle (cr, 1, 1, width-2, height-2); + cairo_stroke (cr); } return FALSE; } +static void +glade_design_view_drag_highlight (GladeDesignView *view, GtkWidget *widget) +{ + g_signal_connect_after (widget, "draw", G_CALLBACK (drag_highlight_draw), view); + gtk_widget_queue_draw (widget); +} + +static void +glade_design_view_drag_unhighlight (GladeDesignView *view, GtkWidget *widget) +{ + g_signal_handlers_disconnect_by_func (widget, drag_highlight_draw, view); + gtk_widget_queue_draw (widget); +} + static gboolean -on_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, - guint time) +glade_design_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time) { GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv; + GdkDragAction drag_action = GDK_ACTION_COPY; GtkWidget *child; - child = widget_get_child_from_position (widget, widget, x, y); - - if (!priv->drag_adaptor) + child = widget_get_gchild_from_position (widget, widget, x, y); + + if (!(priv->drag_adaptor || priv->drag_source)) { GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); - if (!target) - return FALSE; + if (target) + gtk_drag_get_data (widget, context, target, time); + } + + if (child) + { + GladeWidget *gwidget; + + if (priv->drag_source && + (priv->drag_source == child || gtk_widget_is_ancestor (child, priv->drag_source) || + (!GLADE_IS_PLACEHOLDER (child) && + !GTK_IS_FIXED (child) && + (glade_widget_get_from_gobject (child) || + ((gwidget = glade_widget_get_from_gobject (priv->drag_source)) && + !glade_widget_get_parent (gwidget) + )) + ))) + drag_action = 0; + + if (priv->drag_adaptor && + ((GLADE_IS_PLACEHOLDER (child) && GWA_IS_TOPLEVEL (priv->drag_adaptor)) || + (!GLADE_IS_PLACEHOLDER (child) && !GTK_IS_FIXED (child) && + glade_widget_get_from_gobject (child)))) + drag_action = 0; + } + else + drag_action = 0; + + gdk_drag_status (context, drag_action, time); - gtk_drag_get_data (widget, context, target, time); + if (priv->drag_target != child) + { + if (priv->drag_target) + { + glade_design_view_drag_unhighlight (GLADE_DESIGN_VIEW (widget), + priv->drag_target); + priv->drag_target = NULL; + } + + if (drag_action == GDK_ACTION_COPY) + { + glade_design_view_drag_highlight (GLADE_DESIGN_VIEW (widget), child); + priv->drag_target = child; + } } - if (child && - ((priv->drag_adaptor && GLADE_IS_PLACEHOLDER (child) && - GWA_IS_TOPLEVEL (priv->drag_adaptor)) || - (!GLADE_IS_PLACEHOLDER (child) && - widget_is_outside_glade_ancestor (child)) )) + return drag_action != 0; +} + +static void +glade_design_view_drag_leave (GtkWidget *widget, + GdkDragContext *drag_context, + guint time) +{ + GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv; + + if (priv->drag_target) { - gdk_drag_status (context, 0, time); - return FALSE; + glade_design_view_drag_unhighlight (GLADE_DESIGN_VIEW (widget), + priv->drag_target); + priv->drag_target = NULL; } +} - gdk_drag_status (context, GDK_ACTION_COPY, time); - return TRUE; +static void +on_drag_item_drag_end (GtkWidget *widget, + GdkDragContext *context, + GladeDesignView *view) +{ + GladeDesignViewPrivate *priv = view->priv; + + priv->drag_adaptor = NULL; + priv->drag_source = NULL; + priv->drag_target = NULL; + + g_signal_handlers_disconnect_by_func (widget, on_drag_item_drag_end, view); } static void -on_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) +glade_design_view_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time) { GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv; - GtkWidget *item; + GdkAtom target = gtk_selection_data_get_target (selection); + const GtkTargetEntry *palette_target; - item = gtk_tool_palette_get_drag_item (priv->palette, selection); - g_return_if_fail (item); + if (info == GDL_DND_INFO_WIDGET && + g_strcmp0 (gdk_atom_name (target), GDL_DND_TARGET_WIDGET) == 0) + { + const guchar *data = gtk_selection_data_get_data (selection); + + if (data) + priv->drag_source = *((GtkWidget **)data); + } + else if (priv->palette && + (palette_target = gtk_tool_palette_get_drag_target_item ()) && + palette_target->info == info && + g_strcmp0 (gdk_atom_name (target), palette_target->target) == 0) + { + GtkWidget *item = gtk_tool_palette_get_drag_item (priv->palette, selection); - priv->drag_adaptor = g_object_get_data (G_OBJECT (item), "glade-widget-adaptor"); + if (item) + priv->drag_adaptor = g_object_get_data (G_OBJECT (item), "glade-widget-adaptor"); + } + else + return; + + g_signal_connect (gtk_drag_get_source_widget (context), "drag-end", + G_CALLBACK (on_drag_item_drag_end), + GLADE_DESIGN_VIEW (widget)); +} + + +static void +glade_design_view_fixed_move (GladeWidget *gsource, + GtkWidget *widget, + GdkDragContext *context, + GtkWidget *child, + gint x, + gint y) +{ + GladeProperty *prop_x, *prop_y; + gint dx, dy, hx, hy; + GtkWidget *layout; + + gtk_widget_translate_coordinates (widget, child, x, y, &dx, &dy); + + prop_x = glade_widget_get_pack_property (gsource, "x"); + prop_y = glade_widget_get_pack_property (gsource, "y"); + + layout = gtk_drag_get_source_widget (context); + + if (layout && GLADE_IS_DESIGN_LAYOUT (layout)) + _glade_design_layout_get_hot_point (GLADE_DESIGN_LAYOUT (layout), &hx, &hy); + else + hx = hy = 0; + + glade_command_set_property (prop_x, dx - hx); + glade_command_set_property (prop_y, dy - hy); } static gboolean -on_drag_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time) +glade_design_view_drag_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) { GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv; GtkWidget *child; - if (!priv->drag_adaptor) - return FALSE; + child = widget_get_gchild_from_position (widget, widget, x, y); - child = widget_get_child_from_position (widget, widget, x, y); - - if (child && GLADE_IS_PLACEHOLDER (child)) + if (priv->drag_source) { - GladePlaceholder *placeholder = GLADE_PLACEHOLDER (child); + GladeWidget *gsource = glade_widget_get_from_gobject (priv->drag_source); + GList widgets = {gsource, NULL, NULL}; - glade_command_create (priv->drag_adaptor, - glade_placeholder_get_parent (placeholder), - placeholder, - priv->project); + if (GLADE_IS_PLACEHOLDER (child)) + { + GladePlaceholder *placeholder = GLADE_PLACEHOLDER (child); + GladeWidget *parent = glade_placeholder_get_parent (placeholder); + + /* Check for recursive paste */ + if (parent != gsource) + glade_command_dnd (&widgets, parent, placeholder); + } + else if (GTK_IS_FIXED (child)) + { + GladeWidget *parent = glade_widget_get_from_gobject (child); + + glade_command_push_group ("Drag and Drop"); + if (parent != glade_widget_get_parent (gsource)) + glade_command_dnd (&widgets, parent, NULL); + + glade_design_view_fixed_move (gsource, widget, context, child, x, y); + glade_command_pop_group (); + } + else if (!glade_widget_get_from_gobject (child)) + glade_command_dnd (&widgets, NULL, NULL); } - else + else if (child && priv->drag_adaptor) { - glade_command_create (priv->drag_adaptor, NULL, NULL, priv->project); + if (GLADE_IS_PLACEHOLDER (child)) + { + GladePlaceholder *placeholder = GLADE_PLACEHOLDER (child); + + glade_command_create (priv->drag_adaptor, + glade_placeholder_get_parent (placeholder), + placeholder, + priv->project); + } + else if (GTK_IS_FIXED (child)) + { + GladeWidget *parent = glade_widget_get_from_gobject (child); + + if (parent) + { + GladeWidget *gsource; + glade_command_push_group ("Drag and Drop"); + + gsource = glade_command_create (priv->drag_adaptor, + parent, NULL, + priv->project); + + glade_design_view_fixed_move (gsource, widget, context, child, x, y); + glade_command_pop_group (); + } + } + else + { + glade_command_create (priv->drag_adaptor, NULL, NULL, priv->project); + } } gtk_drag_finish (context, TRUE, FALSE, time); - priv->drag_adaptor = NULL; + return TRUE; } +static void +glade_design_view_class_init (GladeDesignViewClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (klass); + object_class = G_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = glade_design_view_finalize; + object_class->get_property = glade_design_view_get_property; + object_class->set_property = glade_design_view_set_property; + + widget_class->drag_motion = glade_design_view_drag_motion; + widget_class->drag_leave = glade_design_view_drag_leave; + widget_class->drag_data_received = glade_design_view_drag_data_received; + widget_class->drag_drop = glade_design_view_drag_drop; + widget_class->draw = glade_design_view_draw; + + g_object_class_install_property (object_class, + PROP_PROJECT, + g_param_spec_object ("project", + "Project", + "The project for this view", + GLADE_TYPE_PROJECT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_DRAG_SOURCE, + g_param_spec_object ("drag-source", + "Drag Source", + "A palette to use as the source of drag events for this view", + GTK_TYPE_TOOL_PALETTE, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (GladeDesignViewPrivate)); +} + +/* Private API */ + +void +_glade_design_view_freeze (GladeDesignView *view) +{ + g_return_if_fail (GLADE_IS_DESIGN_VIEW (view)); + + g_signal_handlers_block_by_func (view->priv->project, + glade_design_view_selection_changed, + view); +} + +void +_glade_design_view_thaw (GladeDesignView *view) +{ + g_return_if_fail (GLADE_IS_DESIGN_VIEW (view)); + + g_signal_handlers_unblock_by_func (view->priv->project, + glade_design_view_selection_changed, + view); +} + +/* Public API */ + +GladeProject * +glade_design_view_get_project (GladeDesignView *view) +{ + g_return_val_if_fail (GLADE_IS_DESIGN_VIEW (view), NULL); + + return view->priv->project; + +} + +GtkWidget * +glade_design_view_new (GladeProject *project) +{ + GladeDesignView *view; + + g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL); + + view = g_object_new (GLADE_TYPE_DESIGN_VIEW, "project", project, NULL); + + return GTK_WIDGET (view); +} + +GladeDesignView * +glade_design_view_get_from_project (GladeProject *project) +{ + gpointer p; + + g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL); + + p = g_object_get_data (G_OBJECT (project), GLADE_DESIGN_VIEW_KEY); + + return (p != NULL) ? GLADE_DESIGN_VIEW (p) : NULL; + +} + void glade_design_view_set_drag_source (GladeDesignView *view, GtkToolPalette *source) { @@ -605,20 +846,23 @@ glade_design_view_set_drag_source (GladeDesignView *view, GtkToolPalette *source target = GTK_WIDGET (view); priv->palette = source; + gtk_drag_dest_set (target, 0, NULL, 0, GDK_ACTION_COPY); + if (priv->palette) { - g_signal_connect (target, "drag-motion", G_CALLBACK (on_drag_motion), NULL); - g_signal_connect (target, "drag-data-received", G_CALLBACK (on_drag_data_received), NULL); - g_signal_connect (target, "drag-drop", G_CALLBACK (on_drag_drop), NULL); + GtkTargetEntry targets[2]; + GtkTargetList *list; gtk_tool_palette_add_drag_dest (priv->palette, target, 0, GTK_TOOL_PALETTE_DRAG_ITEMS, GDK_ACTION_COPY); - } - else - { - g_signal_handlers_disconnect_by_func (target, on_drag_motion, NULL); - g_signal_handlers_disconnect_by_func (target, on_drag_data_received, NULL); - g_signal_handlers_disconnect_by_func (target, on_drag_drop, NULL); + + targets[0] = *gtk_tool_palette_get_drag_target_item (); + targets[1] = *_glade_design_layout_get_dnd_target (); + + list = gtk_target_list_new (targets, 2); + gtk_drag_dest_set_target_list (target, list); + + gtk_target_list_unref (list); } } diff --git a/plugins/gtk+/glade-fixed.c b/plugins/gtk+/glade-fixed.c index 98808519..0362ed04 100644 --- a/plugins/gtk+/glade-fixed.c +++ b/plugins/gtk+/glade-fixed.c @@ -280,21 +280,31 @@ glade_fixed_filter_event (GladeFixed *fixed, static void glade_fixed_handle_swindow (GladeFixed *fixed, GdkRectangle *area) { - GtkWidget *swindow = NULL, *swindow_child = NULL; + GtkWidget *swindow = NULL, *swindow_child = NULL, *widget; GtkAdjustment *hadj, *vadj; GtkAllocation child_allocation; GtkWidget *fixed_widget; + GladeWidget *gwidget; gint x, y; - fixed_widget = GTK_WIDGET (glade_widget_get_object (GLADE_WIDGET (fixed))); + widget = fixed_widget = GTK_WIDGET (glade_widget_get_object (GLADE_WIDGET (fixed))); - swindow_child = swindow = fixed_widget; - while (swindow && !GTK_IS_SCROLLED_WINDOW (swindow)) + while (widget && !GTK_IS_SCROLLED_WINDOW (widget) && + ( + ((gwidget = glade_widget_get_from_gobject (widget)) && + glade_widget_get_parent (gwidget)) || + !gwidget)) { - if (!GTK_IS_VIEWPORT (swindow)) - swindow_child = swindow; + if (!GTK_IS_VIEWPORT (widget)) + swindow_child = widget; - swindow = gtk_widget_get_parent (swindow); + if (GTK_IS_SCROLLED_WINDOW (widget)) + { + swindow = widget; + break; + } + + widget = gtk_widget_get_parent (widget); } if (swindow) diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c index f095994a..9e147aaa 100644 --- a/plugins/gtk+/glade-gtk.c +++ b/plugins/gtk+/glade-gtk.c @@ -3640,6 +3640,9 @@ void glade_gtk_fixed_layout_post_create (GladeWidgetAdaptor * adaptor, GObject * object, GladeCreateReason reason) { + /* Set a minimun size so you can actually see it if you added to a box */ + gtk_widget_set_size_request (GTK_WIDGET (object), 32, 32); + /* Sync up size request at project load time */ if (reason == GLADE_CREATE_LOAD) g_signal_connect_after (object, "realize", |