summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2023-05-03 07:19:58 +0200
committerBenjamin Otte <otte@redhat.com>2023-05-03 07:19:58 +0200
commita59e1254ef434673349e70d33ce3d63dab2cff80 (patch)
tree11d4146543d55a5daa62b6334472f7cf4c1ac4c7
parent43802f8b079389cf0d3901b29c07b8e02b1600a2 (diff)
downloadgtk+-wip/otte/node-editor.tar.gz
node-editor: Add initial comparison UIwip/otte/node-editor
And yes, I'm aware of the icon I'm using.
-rw-r--r--demos/node-editor/node-editor-window.c163
-rw-r--r--demos/node-editor/node-editor-window.ui76
2 files changed, 214 insertions, 25 deletions
diff --git a/demos/node-editor/node-editor-window.c b/demos/node-editor/node-editor-window.c
index 43602640b1..7a7399798b 100644
--- a/demos/node-editor/node-editor-window.c
+++ b/demos/node-editor/node-editor-window.c
@@ -64,6 +64,7 @@ struct _NodeEditorWindow
GListStore *saved_nodes;
GListStore *renderers;
GskRenderNode *node;
+ GtkAdjustment *compare_progress;
GFileMonitor *file_monitor;
@@ -391,7 +392,8 @@ text_view_query_tooltip_cb (GtkWidget *widget,
static gboolean
load_bytes (NodeEditorWindow *self,
- GBytes *bytes);
+ GBytes *bytes,
+ gboolean stash);
static void
load_error (NodeEditorWindow *self,
@@ -409,7 +411,7 @@ load_error (NodeEditorWindow *self,
node = gtk_snapshot_free_to_node (snapshot);
bytes = gsk_render_node_serialize (node);
- load_bytes (self, bytes);
+ load_bytes (self, bytes, TRUE);
gsk_render_node_unref (node);
g_object_unref (layout);
@@ -417,7 +419,8 @@ load_error (NodeEditorWindow *self,
static gboolean
load_bytes (NodeEditorWindow *self,
- GBytes *bytes)
+ GBytes *bytes,
+ gboolean stash)
{
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
{
@@ -426,7 +429,8 @@ load_bytes (NodeEditorWindow *self,
return FALSE;
}
- stash_current_node (self);
+ if (stash)
+ stash_current_node (self);
gtk_text_buffer_set_text (self->text_buffer,
g_bytes_get_data (bytes, NULL),
@@ -452,7 +456,7 @@ load_file_contents (NodeEditorWindow *self,
return FALSE;
}
- return load_bytes (self, bytes);
+ return load_bytes (self, bytes, TRUE);
}
static void
@@ -472,7 +476,7 @@ saved_node_activate_cb (GtkListView *listview,
node = gtk_snapshot_free_to_node (snapshot);
bytes = gsk_render_node_serialize (node);
- load_bytes (self, bytes);
+ load_bytes (self, bytes, TRUE);
g_object_unref (paintable);
}
@@ -503,7 +507,7 @@ on_picture_drop_read_done_cb (GObject *source,
if (g_output_stream_splice_finish (stream, res, NULL) >= 0)
{
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
- if (load_bytes (self, bytes))
+ if (load_bytes (self, bytes, TRUE))
action = GDK_ACTION_COPY;
}
@@ -1108,9 +1112,147 @@ out:
g_free (source_dir);
}
+static inline double
+double_transform (double start,
+ double end,
+ double progress)
+{
+ return start + (end - start) * progress;
+}
+
+static void
+rgba_transform (GdkRGBA *result,
+ const GdkRGBA *start,
+ const GdkRGBA *end,
+ double progress)
+{
+ result->alpha = CLAMP (double_transform (start->alpha, end->alpha, progress), 0, 1);
+
+ if (result->alpha <= 0.0)
+ {
+ result->red = result->green = result->blue = 0.0;
+ }
+ else
+ {
+ result->red = CLAMP (double_transform (start->red * start->alpha, end->red * end->alpha, progress), 0, 1) / result->alpha;
+ result->green = CLAMP (double_transform (start->green * start->alpha, end->green * end->alpha, progress), 0, 1) / result->alpha;
+ result->blue = CLAMP (double_transform (start->blue * start->alpha, end->blue * end->alpha, progress), 0, 1) / result->alpha;
+ }
+}
+
+static GskRenderNode *
+render_node_transform (GskRenderNode *start,
+ GskRenderNode *end,
+ double progress)
+{
+ GskRenderNodeType start_type, end_type;
+
+ start_type = gsk_render_node_get_node_type (start);
+ end_type = gsk_render_node_get_node_type (end);
+
+ if (start_type == end_type)
+ {
+ switch (start_type)
+ {
+ case GSK_COLOR_NODE:
+ {
+ GdkRGBA rgba;
+ graphene_rect_t start_bounds, end_bounds, bounds;
+
+ rgba_transform (&rgba, gsk_color_node_get_color (start), gsk_color_node_get_color (end), progress);
+ gsk_render_node_get_bounds (start, &start_bounds);
+ gsk_render_node_get_bounds (end, &end_bounds);
+ graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
+ return gsk_color_node_new (&rgba, &bounds);
+ }
+
+ case GSK_CAIRO_NODE:
+ case GSK_TEXT_NODE:
+ case GSK_TEXTURE_NODE:
+ case GSK_TEXTURE_SCALE_NODE:
+ case GSK_LINEAR_GRADIENT_NODE:
+ case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+ case GSK_RADIAL_GRADIENT_NODE:
+ case GSK_REPEATING_RADIAL_GRADIENT_NODE:
+ case GSK_CONIC_GRADIENT_NODE:
+ case GSK_BORDER_NODE:
+ case GSK_INSET_SHADOW_NODE:
+ case GSK_OUTSET_SHADOW_NODE:
+ case GSK_TRANSFORM_NODE:
+ case GSK_OPACITY_NODE:
+ case GSK_COLOR_MATRIX_NODE:
+ case GSK_BLUR_NODE:
+ case GSK_REPEAT_NODE:
+ case GSK_CLIP_NODE:
+ case GSK_ROUNDED_CLIP_NODE:
+ case GSK_SHADOW_NODE:
+ case GSK_BLEND_NODE:
+ case GSK_MASK_NODE:
+ case GSK_CROSS_FADE_NODE:
+ case GSK_GL_SHADER_NODE:
+ case GSK_CONTAINER_NODE:
+ case GSK_DEBUG_NODE:
+ break;
+
+ case GSK_NOT_A_RENDER_NODE:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ return gsk_cross_fade_node_new (start, end, progress);
+}
+
+static void
+update_compare (NodeEditorWindow *self)
+{
+ GdkPaintable *from, *to;
+ GtkSnapshot *snapshot;
+ GskRenderNode *node, *node_from, *node_to;
+ GBytes *bytes;
+ guint n;
+
+ n = g_list_model_get_n_items (G_LIST_MODEL (self->saved_nodes));
+
+ from = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes), n - 3);
+ snapshot = gtk_snapshot_new ();
+ gdk_paintable_snapshot (from, snapshot, gdk_paintable_get_intrinsic_width (from), gdk_paintable_get_intrinsic_height (from));
+ node_from = gtk_snapshot_free_to_node (snapshot);
+ g_object_unref (from);
+
+ to = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes), n - 2);
+ snapshot = gtk_snapshot_new ();
+ gdk_paintable_snapshot (to, snapshot, gdk_paintable_get_intrinsic_width (to), gdk_paintable_get_intrinsic_height (to));
+ node_to = gtk_snapshot_free_to_node (snapshot);
+ g_object_unref (to);
+
+ node = render_node_transform (node_from, node_to, gtk_adjustment_get_value (self->compare_progress));
+
+ bytes = gsk_render_node_serialize (node);
+ load_bytes (self, bytes, FALSE);
+
+ gsk_render_node_unref (node);
+ gsk_render_node_unref (node_to);
+ gsk_render_node_unref (node_from);
+}
+
+static void
+compare_toggled_cb (GtkToggleButton *button,
+ GParamSpec *pspec,
+ NodeEditorWindow *self)
+{
+ if (!gtk_toggle_button_get_active (button))
+ return;
+
+ stash_current_node (self);
+
+ update_compare (self);
+}
+
static void
-dark_mode_cb (GtkToggleButton *button,
- GParamSpec *pspec,
+dark_mode_cb (GtkToggleButton *button,
+ GParamSpec *pspec,
NodeEditorWindow *self)
{
g_object_set (gtk_widget_get_settings (GTK_WIDGET (self)),
@@ -1231,6 +1373,7 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_view);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, picture);
+ gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, compare_progress);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, renderer_listbox);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_popover);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_error_label);
@@ -1248,9 +1391,11 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_callback (widget_class, clip_image_cb);
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, compare_toggled_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);
+ gtk_widget_class_bind_template_callback (widget_class, update_compare);
}
static GtkWidget *
diff --git a/demos/node-editor/node-editor-window.ui b/demos/node-editor/node-editor-window.ui
index 31b3ce32b1..5d235ee1a3 100644
--- a/demos/node-editor/node-editor-window.ui
+++ b/demos/node-editor/node-editor-window.ui
@@ -158,6 +158,16 @@
</object>
</child>
<child type="end">
+ <object class="GtkToggleButton" id="compare_button">
+ <property name="focus-on-click">0</property>
+ <property name="valign">center</property>
+ <property name="has-frame">0</property>
+ <property name="icon-name">emblem-synchronizing-symbolic</property>
+ <property name="tooltip-text" translatable="yes">Compare the last 2 items</property>
+ <signal name="notify::active" handler="compare_toggled_cb" swapped="0"/>
+ </object>
+ </child>
+ <child type="end">
<object class="GtkScaleButton" id="scale_scale">
<property name="focus-on-click">0</property>
<property name="valign">center</property>
@@ -242,31 +252,65 @@
<property name="end-child">
<object class="GtkBox">
<child>
- <object class="GtkScrolledWindow">
- <property name="hexpand">1</property>
- <property name="vexpand">1</property>
- <property name="min-content-height">100</property>
- <property name="min-content-width">100</property>
+ <object class="GtkOverlay">
<child>
- <object class="GtkViewport">
+ <object class="GtkScrolledWindow">
+ <property name="hexpand">1</property>
+ <property name="vexpand">1</property>
+ <property name="min-content-height">100</property>
+ <property name="min-content-width">100</property>
<child>
- <object class="GtkPicture" id="picture">
- <property name="can-shrink">0</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
+ <object class="GtkViewport">
<child>
- <object class="GtkDragSource">
+ <object class="GtkPicture" id="picture">
+ <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>
- <signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
+ <property name="formats">application/x-gtk-render-node</property>
+ <signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
</object>
</child>
</object>
</child>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GtkBox">
+ <property name="margin-top">16</property>
+ <property name="margin-start">16</property>
+ <property name="margin-end">16</property>
+ <property name="margin-bottom">16</property>
+ <property name="halign">fill</property>
+ <property name="valign">end</property>
+ <property name="visible" bind-source="compare_button" bind-property="active">0</property>
+ <style>
+ <class name="osd" />
+ </style>
<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 class="GtkScale">
+ <property name="width-request">200</property>
+ <property name="draw-value">0</property>
+ <property name="adjustment">
+ <object class="GtkAdjustment" id="compare_progress">
+ <property name="upper">1</property>
+ <property name="value">0.5</property>
+ <property name="step-increment">0.01</property>
+ <property name="page-increment">0.1</property>
+ <signal name="notify::value" handler="update_compare" swapped="yes"/>
+ </object>
+ </property>
+ <property name="hexpand">1</property>
</object>
</child>
</object>