From 3b85eeec8db436bb492b3a00476e9fbea0175bda Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 7 Oct 2012 08:34:32 +0200 Subject: Add drag and drop support for symbols. --- liblogdiag/ld-diagram-view.c | 138 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) (limited to 'liblogdiag/ld-diagram-view.c') diff --git a/liblogdiag/ld-diagram-view.c b/liblogdiag/ld-diagram-view.c index 1d2764c..55a60c0 100644 --- a/liblogdiag/ld-diagram-view.c +++ b/liblogdiag/ld-diagram-view.c @@ -129,6 +129,9 @@ Color; * @y: the Y coordinate of the center of view. * @zoom: the current zoom. * @show_grid: whether to show the grid. + * @dnd_symbol: currently dragged symbol. + * @dnd_last_position: last cursor movement position. + * @dnd_left: whether the user has stopped dragging. * @terminal: position of the highlighted terminal. * @terminal_hovered: whether a terminal is hovered. * @drag_start_pos: position of the mouse pointer when dragging started. @@ -152,6 +155,10 @@ struct _LdDiagramViewPrivate gboolean show_grid; + LdDiagramObject *dnd_symbol; + LdPoint dnd_last_position; + guint dnd_left : 1; + LdPoint terminal; gboolean terminal_hovered; @@ -343,6 +350,16 @@ static gboolean on_button_release (GtkWidget *widget, GdkEventButton *event, static gboolean on_scroll (GtkWidget *widget, GdkEventScroll *event, gpointer user_data); +static gboolean on_drag_motion (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, guint time, gpointer user_data); +static gboolean on_drag_drop (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, guint time, gpointer user_data); +static void on_drag_data_received (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, GtkSelectionData *data, guint info, + guint time, gpointer user_data); +static void on_drag_leave (GtkWidget *widget, GdkDragContext *drag_ctx, + guint time, gpointer user_data); + static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); static void draw_grid (GtkWidget *widget, DrawData *data); @@ -486,6 +503,8 @@ ld_diagram_view_class_init (LdDiagramViewClass *klass) static void ld_diagram_view_init (LdDiagramView *self) { + GtkTargetEntry target = {"ld-symbol", GTK_TARGET_SAME_APP, 0}; + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, LD_TYPE_DIAGRAM_VIEW, LdDiagramViewPrivate); @@ -517,12 +536,23 @@ ld_diagram_view_init (LdDiagramView *self) g_signal_connect (self, "scroll-event", G_CALLBACK (on_scroll), NULL); + g_signal_connect (self, "drag-motion", + G_CALLBACK (on_drag_motion), NULL); + g_signal_connect (self, "drag-leave", + G_CALLBACK (on_drag_leave), NULL); + g_signal_connect (self, "drag-drop", + G_CALLBACK (on_drag_drop), NULL); + g_signal_connect (self, "drag-data-received", + G_CALLBACK (on_drag_data_received), NULL); + g_object_set (self, "can-focus", TRUE, NULL); gtk_widget_add_events (GTK_WIDGET (self), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); + + gtk_drag_dest_set (GTK_WIDGET (self), 0, &target, 1, GDK_ACTION_COPY); } static void @@ -541,6 +571,8 @@ ld_diagram_view_finalize (GObject *gobject) } if (self->priv->library) g_object_unref (self->priv->library); + if (self->priv->dnd_symbol) + g_object_unref (self->priv->dnd_symbol); /* Chain up to the parent class. */ G_OBJECT_CLASS (ld_diagram_view_parent_class)->finalize (gobject); @@ -2424,6 +2456,109 @@ on_scroll (GtkWidget *widget, GdkEventScroll *event, gpointer user_data) return TRUE; } +static gboolean +on_drag_motion (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, guint time, gpointer user_data) +{ + LdDiagramView *self; + GdkAtom target; + + self = LD_DIAGRAM_VIEW (widget); + target = gtk_drag_dest_find_target (widget, drag_ctx, NULL); + if (target == GDK_NONE) + { + gdk_drag_status (drag_ctx, 0, time); + return TRUE; + } + + gdk_drag_status (drag_ctx, + gdk_drag_context_get_suggested_action (drag_ctx), time); + + /* Discard leftovers from any previous unsuccessful drag. */ + if (self->priv->dnd_left) + { + g_object_unref (self->priv->dnd_symbol); + self->priv->dnd_symbol = NULL; + self->priv->dnd_left = FALSE; + } + + self->priv->dnd_last_position.x = x; + self->priv->dnd_last_position.y = y; + + if (!self->priv->dnd_symbol) + gtk_drag_get_data (widget, drag_ctx, target, time); + else + { + queue_object_draw (self, self->priv->dnd_symbol); + move_object_to_point (self, self->priv->dnd_symbol, + &self->priv->dnd_last_position); + queue_object_draw (self, self->priv->dnd_symbol); + } + + return TRUE; +} + +static void +on_drag_data_received (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, GtkSelectionData *data, guint info, guint time, + gpointer user_data) +{ + LdDiagramView *self; + LdDiagramSymbol *symbol; + const gchar *klass; + + self = LD_DIAGRAM_VIEW (widget); + + g_return_if_fail (gtk_selection_data_get_length (data) >= 0); + g_return_if_fail (self->priv->dnd_symbol == NULL); + + klass = (const gchar *) gtk_selection_data_get_data (data); + symbol = ld_diagram_symbol_new (NULL); + ld_diagram_symbol_set_class (symbol, klass); + self->priv->dnd_symbol = LD_DIAGRAM_OBJECT (symbol); + + move_object_to_point (self, self->priv->dnd_symbol, + &self->priv->dnd_last_position); + queue_object_draw (self, self->priv->dnd_symbol); +} + +static void +on_drag_leave (GtkWidget *widget, GdkDragContext *drag_ctx, + guint time, gpointer user_data) +{ + LdDiagramView *self; + + self = LD_DIAGRAM_VIEW (widget); + self->priv->dnd_left = TRUE; + queue_object_draw (self, self->priv->dnd_symbol); +} + +static gboolean +on_drag_drop (GtkWidget *widget, GdkDragContext *drag_ctx, + gint x, gint y, guint time, gpointer user_data) +{ + LdDiagramView *self; + gboolean del; + + del = gdk_drag_context_get_suggested_action (drag_ctx) + == GDK_ACTION_MOVE; + + self = LD_DIAGRAM_VIEW (widget); + if (!self->priv->dnd_symbol) + gtk_drag_finish (drag_ctx, FALSE, del, time); + else + { + gtk_drag_finish (drag_ctx, TRUE, del, time); + + ld_diagram_insert_object (self->priv->diagram, + self->priv->dnd_symbol, -1); + g_object_unref (self->priv->dnd_symbol); + self->priv->dnd_symbol = NULL; + self->priv->dnd_left = FALSE; + } + return TRUE; +} + static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { @@ -2572,6 +2707,9 @@ draw_diagram (GtkWidget *widget, DrawData *data) break; } + if (data->self->priv->dnd_symbol && !data->self->priv->dnd_left) + draw_object (data->self->priv->dnd_symbol, data); + cairo_restore (data->cr); } -- cgit v1.2.3-54-g00ecf