diff options
author | Benjamin Otte <otte@redhat.com> | 2021-08-20 05:52:54 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2021-08-30 06:02:16 +0200 |
commit | 2863095f063c7ac153e6f30e0ad579566ab53648 (patch) | |
tree | aafa38faa613f32ad2d533cd09c8f7b5cb45dbd2 | |
parent | cbc050b9ed6708e84c0a97f327400d08512ad65f (diff) | |
download | gtk+-2863095f063c7ac153e6f30e0ad579566ab53648.tar.gz |
node-editor: Allow dragging and dropping the center picture
Dragging will just drag the render node.
Dropping will replace the current contents of the textview with the
dropped node.
Neat side effect: You can drag the node onto itself to do a
deserialize/serialize of the current text.
-rw-r--r-- | demos/node-editor/node-editor-window.c | 124 | ||||
-rw-r--r-- | demos/node-editor/node-editor-window.ui | 13 |
2 files changed, 123 insertions, 14 deletions
diff --git a/demos/node-editor/node-editor-window.c b/demos/node-editor/node-editor-window.c index 6250857ae6..866b51c284 100644 --- a/demos/node-editor/node-editor-window.c +++ b/demos/node-editor/node-editor-window.c @@ -60,7 +60,7 @@ struct _NodeEditorWindow GtkWidget *renderer_listbox; GListStore *renderers; - GdkPaintable *paintable; + GskRenderNode *node; GFileMonitor *file_monitor; @@ -167,7 +167,6 @@ static void text_changed (GtkTextBuffer *buffer, NodeEditorWindow *self) { - GskRenderNode *node; char *text; GBytes *bytes; GtkTextIter iter; @@ -178,10 +177,12 @@ text_changed (GtkTextBuffer *buffer, text_buffer_remove_all_tags (self->text_buffer); bytes = g_bytes_new_take (text, strlen (text)); + g_clear_pointer (&self->node, gsk_render_node_unref); + /* If this is too slow, go fix the parser performance */ - node = gsk_render_node_deserialize (bytes, deserialize_error_func, self); + self->node = gsk_render_node_deserialize (bytes, deserialize_error_func, self); g_bytes_unref (bytes); - if (node) + if (self->node) { /* XXX: Is this code necessary or can we have API to turn nodes into paintables? */ GtkSnapshot *snapshot; @@ -190,10 +191,9 @@ text_changed (GtkTextBuffer *buffer, guint i; snapshot = gtk_snapshot_new (); - gsk_render_node_get_bounds (node, &bounds); + gsk_render_node_get_bounds (self->node, &bounds); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- bounds.origin.x, - bounds.origin.y)); - gtk_snapshot_append_node (snapshot, node); - gsk_render_node_unref (node); + gtk_snapshot_append_node (snapshot, self->node); paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size); gtk_picture_set_paintable (GTK_PICTURE (self->picture), paintable); for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i++) @@ -337,6 +337,25 @@ text_view_query_tooltip_cb (GtkWidget *widget, } static gboolean +load_bytes (NodeEditorWindow *self, + GBytes *bytes) +{ + if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL)) + { + g_bytes_unref (bytes); + return FALSE; + } + + gtk_text_buffer_set_text (self->text_buffer, + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); + + g_bytes_unref (bytes); + + return TRUE; +} + +static gboolean load_file_contents (NodeEditorWindow *self, GFile *file) { @@ -346,17 +365,91 @@ load_file_contents (NodeEditorWindow *self, if (bytes == NULL) return FALSE; - if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL)) + return load_bytes (self, bytes); +} + +static GdkContentProvider * +on_picture_drag_prepare_cb (GtkDragSource *source, + double x, + double y, + NodeEditorWindow *self) +{ + if (self->node == NULL) + return NULL; + + return gdk_content_provider_new_typed (GSK_TYPE_RENDER_NODE, self->node); +} + +static void +on_picture_drop_read_done_cb (GObject *source, + GAsyncResult *res, + gpointer data) +{ + NodeEditorWindow *self = data; + GOutputStream *stream = G_OUTPUT_STREAM (source); + GdkDrop *drop = g_object_get_data (source, "drop"); + GdkDragAction action = 0; + GBytes *bytes; + + if (g_output_stream_splice_finish (stream, res, NULL) >= 0) { - g_bytes_unref (bytes); - return FALSE; + bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream)); + if (load_bytes (self, bytes)) + action = GDK_ACTION_COPY; } - gtk_text_buffer_set_text (self->text_buffer, - g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes)); + g_object_unref (self); + gdk_drop_finish (drop, action); + g_object_unref (drop); + return; +} - g_bytes_unref (bytes); +static void +on_picture_drop_read_cb (GObject *source, + GAsyncResult *res, + gpointer data) +{ + NodeEditorWindow *self = data; + GdkDrop *drop = GDK_DROP (source); + GInputStream *input; + GOutputStream *output; + + input = gdk_drop_read_finish (drop, res, NULL, NULL); + if (input == NULL) + { + g_object_unref (self); + gdk_drop_finish (drop, 0); + return; + } + + output = g_memory_output_stream_new_resizable (); + g_object_set_data (G_OBJECT (output), "drop", drop); + g_object_ref (drop); + + g_output_stream_splice_async (output, + input, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + G_PRIORITY_DEFAULT, + NULL, + on_picture_drop_read_done_cb, + self); + g_object_unref (output); + g_object_unref (input); +} + +static gboolean +on_picture_drop_cb (GtkDropTargetAsync *dest, + GdkDrop *drop, + double x, + double y, + NodeEditorWindow *self) +{ + gdk_drop_read_async (drop, + (const char *[2]) { "application/x-gtk-render-node", NULL }, + G_PRIORITY_DEFAULT, + NULL, + on_picture_drop_read_cb, + g_object_ref (self)); return TRUE; } @@ -735,6 +828,7 @@ node_editor_window_finalize (GObject *object) g_array_free (self->errors, TRUE); + g_clear_pointer (&self->node, gsk_render_node_unref); g_clear_object (&self->renderers); G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object); @@ -844,6 +938,8 @@ node_editor_window_class_init (NodeEditorWindowClass *class) gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb); gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb); + gtk_widget_class_bind_template_callback (widget_class, on_picture_drag_prepare_cb); + gtk_widget_class_bind_template_callback (widget_class, on_picture_drop_cb); } static GtkWidget * diff --git a/demos/node-editor/node-editor-window.ui b/demos/node-editor/node-editor-window.ui index 6b492390d6..c4abee6402 100644 --- a/demos/node-editor/node-editor-window.ui +++ b/demos/node-editor/node-editor-window.ui @@ -200,6 +200,19 @@ <property name="can-shrink">0</property> <property name="halign">center</property> <property name="valign">center</property> + <child> + <object class="GtkDragSource"> + <property name="actions">copy</property> + <signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/> + </object> + </child> + </object> + </child> + <child> + <object class="GtkDropTargetAsync"> + <property name="actions">copy</property> + <property name="formats">application/x-gtk-render-node</property> + <signal name="drop" handler="on_picture_drop_cb" swapped="no"/> </object> </child> </object> |