summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2021-08-20 05:52:54 +0200
committerBenjamin Otte <otte@redhat.com>2021-08-23 07:08:26 +0200
commit31556f07fca4ca940fca4277c0c67ee600b9c1c3 (patch)
treeb981d394ba77362720ef110c4a53a8f5a703566b
parent998c7defd62124b936cdfe3329f96cbf4dfda4b0 (diff)
downloadgtk+-31556f07fca4ca940fca4277c0c67ee600b9c1c3.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.c124
-rw-r--r--demos/node-editor/node-editor-window.ui13
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 ce4198d683..56d6c96dae 100644
--- a/demos/node-editor/node-editor-window.c
+++ b/demos/node-editor/node-editor-window.c
@@ -61,7 +61,7 @@ struct _NodeEditorWindow
GtkWidget *renderer_listbox;
GListStore *renderers;
- GdkPaintable *paintable;
+ GskRenderNode *node;
GFileMonitor *file_monitor;
@@ -168,7 +168,6 @@ static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
{
- GskRenderNode *node;
char *text;
GBytes *bytes;
GtkTextIter iter;
@@ -179,10 +178,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;
@@ -191,10 +192,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++)
@@ -338,6 +338,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)
{
@@ -347,17 +366,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;
}
@@ -736,6 +829,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);
@@ -848,6 +942,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>