node-editor: Add initial comparison UI
And yes, I'm aware of the icon I'm using.
This commit is contained in:
@@ -3,6 +3,7 @@ node_editor_sources = [
|
||||
'main.c',
|
||||
'node-editor-application.c',
|
||||
'node-editor-window.c',
|
||||
'rendernodeutils.c'
|
||||
]
|
||||
|
||||
node_editor_resources = gnome.compile_resources('node_editor_resources',
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "node-editor-window.h"
|
||||
|
||||
#include "gtkrendererpaintableprivate.h"
|
||||
#include "rendernodeutilsprivate.h"
|
||||
|
||||
#include "gsk/gskrendernodeparserprivate.h"
|
||||
#include "gsk/gl/gskglrenderer.h"
|
||||
@@ -64,6 +65,7 @@ struct _NodeEditorWindow
|
||||
GListStore *saved_nodes;
|
||||
GListStore *renderers;
|
||||
GskRenderNode *node;
|
||||
GtkAdjustment *compare_progress;
|
||||
|
||||
GFile *file;
|
||||
GFileMonitor *file_monitor;
|
||||
@@ -392,7 +394,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,
|
||||
@@ -410,7 +413,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);
|
||||
@@ -418,7 +421,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))
|
||||
{
|
||||
@@ -427,7 +431,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),
|
||||
@@ -453,7 +458,7 @@ load_file_contents (NodeEditorWindow *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return load_bytes (self, bytes);
|
||||
return load_bytes (self, bytes, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -473,7 +478,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);
|
||||
}
|
||||
@@ -504,7 +509,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;
|
||||
}
|
||||
|
||||
@@ -1127,8 +1132,54 @@ out:
|
||||
}
|
||||
|
||||
static void
|
||||
dark_mode_cb (GtkToggleButton *button,
|
||||
GParamSpec *pspec,
|
||||
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_interpolate (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,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
g_object_set (gtk_widget_get_settings (GTK_WIDGET (self)),
|
||||
@@ -1602,6 +1653,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);
|
||||
@@ -1619,10 +1671,12 @@ 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, click_gesture_pressed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_compare);
|
||||
|
||||
gtk_widget_class_install_action (widget_class, "smart-edit", NULL, edit_action_cb);
|
||||
|
||||
|
||||
@@ -165,6 +165,16 @@
|
||||
<signal name="notify::active" handler="dark_mode_cb" swapped="0"/>
|
||||
</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>
|
||||
@@ -257,31 +267,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>
|
||||
|
||||
435
demos/node-editor/rendernodeutils.c
Normal file
435
demos/node-editor/rendernodeutils.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright © 2023 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "rendernodeutilsprivate.h"
|
||||
|
||||
static inline double
|
||||
double_interpolate (double start,
|
||||
double end,
|
||||
double progress)
|
||||
{
|
||||
return start + (end - start) * progress;
|
||||
}
|
||||
|
||||
static inline float
|
||||
float_interpolate (float start,
|
||||
float end,
|
||||
double progress)
|
||||
{
|
||||
return start + (end - start) * progress;
|
||||
}
|
||||
|
||||
static void
|
||||
rgba_interpolate (GdkRGBA *result,
|
||||
const GdkRGBA *start,
|
||||
const GdkRGBA *end,
|
||||
double progress)
|
||||
{
|
||||
result->alpha = CLAMP (double_interpolate (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_interpolate (start->red * start->alpha, end->red * end->alpha, progress), 0, 1) / result->alpha;
|
||||
result->green = CLAMP (double_interpolate (start->green * start->alpha, end->green * end->alpha, progress), 0, 1) / result->alpha;
|
||||
result->blue = CLAMP (double_interpolate (start->blue * start->alpha, end->blue * end->alpha, progress), 0, 1) / result->alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rounded_rect_interpolate (GskRoundedRect *dest,
|
||||
const GskRoundedRect *start,
|
||||
const GskRoundedRect *end,
|
||||
double progress)
|
||||
{
|
||||
guint i;
|
||||
|
||||
graphene_rect_interpolate (&start->bounds, &end->bounds, progress, &dest->bounds);
|
||||
for (i = 0; i < 4; i++)
|
||||
graphene_size_interpolate (&start->corner[i], &end->corner[i], progress, &dest->corner[i]);
|
||||
}
|
||||
|
||||
static GskTransform *
|
||||
transform_interpolate (GskTransform *start,
|
||||
GskTransform *end,
|
||||
double progress)
|
||||
{
|
||||
switch (MIN (gsk_transform_get_category (start), gsk_transform_get_category (end)))
|
||||
{
|
||||
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
||||
return NULL;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
||||
{
|
||||
float startx, starty, endx, endy;
|
||||
|
||||
gsk_transform_to_translate (start, &startx, &starty);
|
||||
gsk_transform_to_translate (end, &endx, &endy);
|
||||
return gsk_transform_translate (NULL,
|
||||
&GRAPHENE_POINT_INIT (float_interpolate (startx, endx, progress),
|
||||
float_interpolate (starty, endy, progress)));
|
||||
}
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
|
||||
case GSK_TRANSFORM_CATEGORY_2D:
|
||||
{
|
||||
float start_skew_x, start_skew_y, start_scale_x, start_scale_y, start_angle, start_dx, start_dy;
|
||||
float end_skew_x, end_skew_y, end_scale_x, end_scale_y, end_angle, end_dx, end_dy;
|
||||
GskTransform *transform;
|
||||
|
||||
gsk_transform_to_2d_components (start,
|
||||
&start_skew_x, &start_skew_y,
|
||||
&start_scale_x, &start_scale_y,
|
||||
&start_angle,
|
||||
&start_dx, &start_dy);
|
||||
gsk_transform_to_2d_components (end,
|
||||
&end_skew_x, &end_skew_y,
|
||||
&end_scale_x, &end_scale_y,
|
||||
&end_angle,
|
||||
&end_dx, &end_dy);
|
||||
transform = gsk_transform_translate (NULL,
|
||||
&GRAPHENE_POINT_INIT (float_interpolate (start_dx, end_dx, progress),
|
||||
float_interpolate (start_dy, end_dy, progress)));
|
||||
transform = gsk_transform_rotate (transform,
|
||||
float_interpolate (start_angle, end_angle, progress));
|
||||
transform = gsk_transform_scale (transform,
|
||||
float_interpolate (start_scale_x, end_scale_x, progress),
|
||||
float_interpolate (start_scale_y, end_scale_y, progress));
|
||||
transform = gsk_transform_skew (transform,
|
||||
float_interpolate (start_skew_x, end_skew_x, progress),
|
||||
float_interpolate (start_skew_y, end_skew_y, progress));
|
||||
return transform;
|
||||
}
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
{
|
||||
graphene_matrix_t start_matrix, end_matrix, matrix;
|
||||
|
||||
gsk_transform_to_matrix (start, &start_matrix);
|
||||
gsk_transform_to_matrix (end, &end_matrix);
|
||||
graphene_matrix_interpolate (&start_matrix, &end_matrix, progress, &matrix);
|
||||
return gsk_transform_matrix (NULL, &matrix);
|
||||
}
|
||||
|
||||
default:
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
color_stops_interpolate (GskColorStop *stops,
|
||||
const GskColorStop *start_stops,
|
||||
const GskColorStop *end_stops,
|
||||
gsize n_stops,
|
||||
double progress)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < n_stops; i++)
|
||||
{
|
||||
stops[i].offset = float_interpolate (start_stops[i].offset, end_stops[i].offset, progress);
|
||||
rgba_interpolate (&stops[i].color, &start_stops[i].color, &end_stops[i].color, progress);
|
||||
}
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
render_node_interpolate (GskRenderNode *start,
|
||||
GskRenderNode *end,
|
||||
double progress)
|
||||
{
|
||||
GskRenderNodeType start_type, end_type;
|
||||
|
||||
if (progress <= 0)
|
||||
return gsk_render_node_ref (start);
|
||||
else if (progress >= 1)
|
||||
return gsk_render_node_ref (end);
|
||||
|
||||
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_interpolate (&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_DEBUG_NODE:
|
||||
{
|
||||
GskRenderNode *result, *child;
|
||||
|
||||
/* xxx: do we need to interpolate the message somehow? */
|
||||
child = render_node_interpolate (gsk_debug_node_get_child (start),
|
||||
gsk_debug_node_get_child (end),
|
||||
progress);
|
||||
result = gsk_debug_node_new (child, g_strdup_printf ("progress %g", progress));
|
||||
gsk_render_node_unref (child);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
{
|
||||
GskRenderNode **nodes;
|
||||
GskRenderNode *result;
|
||||
gsize i, n_nodes;
|
||||
|
||||
if (gsk_container_node_get_n_children (start) != gsk_container_node_get_n_children (end))
|
||||
break;
|
||||
|
||||
n_nodes = gsk_container_node_get_n_children (start);
|
||||
nodes = g_new (GskRenderNode *, n_nodes);
|
||||
|
||||
for (i = 0; i < n_nodes; i++)
|
||||
{
|
||||
nodes[i] = render_node_interpolate (gsk_container_node_get_child (start, i),
|
||||
gsk_container_node_get_child (end, i),
|
||||
progress);
|
||||
}
|
||||
|
||||
result = gsk_container_node_new (nodes, n_nodes);
|
||||
for (i = 0; i < n_nodes; i++)
|
||||
gsk_render_node_unref (nodes[i]);
|
||||
g_free (nodes);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_TEXTURE_NODE:
|
||||
{
|
||||
graphene_rect_t start_bounds, end_bounds, bounds;
|
||||
|
||||
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_texture_node_new (gsk_texture_node_get_texture (progress > 0.5 ? end : start),
|
||||
&bounds);
|
||||
}
|
||||
|
||||
case GSK_TEXTURE_SCALE_NODE:
|
||||
{
|
||||
graphene_rect_t start_bounds, end_bounds, bounds;
|
||||
|
||||
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_texture_scale_node_new (gsk_texture_scale_node_get_texture (progress > 0.5 ? end : start),
|
||||
&bounds,
|
||||
gsk_texture_scale_node_get_filter (progress > 0.5 ? end : start));
|
||||
}
|
||||
|
||||
case GSK_TRANSFORM_NODE:
|
||||
{
|
||||
GskRenderNode *result, *child;
|
||||
GskTransform *transform;
|
||||
|
||||
child = render_node_interpolate (gsk_transform_node_get_child (start),
|
||||
gsk_transform_node_get_child (end),
|
||||
progress);
|
||||
transform = transform_interpolate (gsk_transform_node_get_transform (start),
|
||||
gsk_transform_node_get_transform (end),
|
||||
progress);
|
||||
result = gsk_transform_node_new (child, transform);
|
||||
gsk_transform_unref (transform);
|
||||
gsk_render_node_unref (child);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_CLIP_NODE:
|
||||
{
|
||||
GskRenderNode *result, *child;
|
||||
graphene_rect_t clip;
|
||||
|
||||
graphene_rect_interpolate (gsk_clip_node_get_clip (start),
|
||||
gsk_clip_node_get_clip (end),
|
||||
progress,
|
||||
&clip);
|
||||
child = render_node_interpolate (gsk_clip_node_get_child (start),
|
||||
gsk_clip_node_get_child (end),
|
||||
progress);
|
||||
result = gsk_clip_node_new (child, &clip);
|
||||
gsk_render_node_unref (child);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_ROUNDED_CLIP_NODE:
|
||||
{
|
||||
GskRenderNode *result, *child;
|
||||
GskRoundedRect clip;
|
||||
|
||||
rounded_rect_interpolate (&clip,
|
||||
gsk_rounded_clip_node_get_clip (start),
|
||||
gsk_rounded_clip_node_get_clip (end),
|
||||
progress);
|
||||
child = render_node_interpolate (gsk_rounded_clip_node_get_child (start),
|
||||
gsk_rounded_clip_node_get_child (end),
|
||||
progress);
|
||||
result = gsk_rounded_clip_node_new (child, &clip);
|
||||
gsk_render_node_unref (child);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_BORDER_NODE:
|
||||
{
|
||||
GdkRGBA color[4];
|
||||
const GdkRGBA *start_color, *end_color;
|
||||
float width[4];
|
||||
const float *start_width, *end_width;
|
||||
GskRoundedRect outline;
|
||||
guint i;
|
||||
|
||||
rounded_rect_interpolate (&outline,
|
||||
gsk_border_node_get_outline (start),
|
||||
gsk_border_node_get_outline (end),
|
||||
progress);
|
||||
start_color = gsk_border_node_get_colors (start);
|
||||
end_color = gsk_border_node_get_colors (end);
|
||||
start_width = gsk_border_node_get_widths (start);
|
||||
end_width = gsk_border_node_get_widths (end);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
rgba_interpolate (&color[i], &start_color[i], &end_color[i], progress);
|
||||
width[i] = float_interpolate (start_width[i], end_width[i], progress);
|
||||
}
|
||||
return gsk_border_node_new (&outline, width, color);
|
||||
}
|
||||
|
||||
case GSK_MASK_NODE:
|
||||
{
|
||||
GskRenderNode *source, *mask, *result;
|
||||
|
||||
source = render_node_interpolate (gsk_mask_node_get_source (start),
|
||||
gsk_mask_node_get_source (end),
|
||||
progress);
|
||||
mask = render_node_interpolate (gsk_mask_node_get_mask (start),
|
||||
gsk_mask_node_get_mask (end),
|
||||
progress);
|
||||
result = gsk_mask_node_new (source,
|
||||
mask,
|
||||
gsk_mask_node_get_mask_mode (progress > 0.5 ? end : start));
|
||||
gsk_render_node_unref (source);
|
||||
gsk_render_node_unref (mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
{
|
||||
graphene_rect_t start_bounds, end_bounds, bounds;
|
||||
graphene_point_t center;
|
||||
float rotation;
|
||||
GskColorStop *color_stops;
|
||||
gsize n_color_stops;
|
||||
GskRenderNode *result;
|
||||
|
||||
if (gsk_conic_gradient_node_get_n_color_stops (start) != gsk_conic_gradient_node_get_n_color_stops (end))
|
||||
break;
|
||||
|
||||
n_color_stops = gsk_conic_gradient_node_get_n_color_stops (start);
|
||||
color_stops = g_new (GskColorStop, n_color_stops);
|
||||
|
||||
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);
|
||||
graphene_point_interpolate (gsk_conic_gradient_node_get_center (start),
|
||||
gsk_conic_gradient_node_get_center (end),
|
||||
progress,
|
||||
¢er);
|
||||
rotation = float_interpolate (gsk_conic_gradient_node_get_rotation (start),
|
||||
gsk_conic_gradient_node_get_rotation (end),
|
||||
progress);
|
||||
color_stops_interpolate (color_stops,
|
||||
gsk_conic_gradient_node_get_color_stops (start, NULL),
|
||||
gsk_conic_gradient_node_get_color_stops (end, NULL),
|
||||
n_color_stops,
|
||||
progress);
|
||||
result = gsk_conic_gradient_node_new (&bounds,
|
||||
¢er,
|
||||
rotation,
|
||||
color_stops,
|
||||
n_color_stops);
|
||||
g_free (color_stops);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
{
|
||||
graphene_rect_t start_bounds, end_bounds, bounds, child_bounds;
|
||||
GskRenderNode *child, *result;
|
||||
|
||||
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);
|
||||
graphene_rect_interpolate (gsk_repeat_node_get_child_bounds (start),
|
||||
gsk_repeat_node_get_child_bounds (end),
|
||||
progress,
|
||||
&child_bounds);
|
||||
child = render_node_interpolate (gsk_repeat_node_get_child (start),
|
||||
gsk_repeat_node_get_child (end),
|
||||
progress);
|
||||
result = gsk_repeat_node_new (&bounds, child, &child_bounds);
|
||||
gsk_render_node_unref (child);
|
||||
return result;
|
||||
}
|
||||
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
case GSK_OUTSET_SHADOW_NODE:
|
||||
case GSK_OPACITY_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_SHADOW_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
g_warning ("FIXME: not implemented");
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
break;
|
||||
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gsk_cross_fade_node_new (start, end, progress);
|
||||
}
|
||||
|
||||
30
demos/node-editor/rendernodeutilsprivate.h
Normal file
30
demos/node-editor/rendernodeutilsprivate.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GskRenderNode * render_node_interpolate (GskRenderNode *start,
|
||||
GskRenderNode *end,
|
||||
double progress);
|
||||
|
||||
G_END_DECLS
|
||||
Reference in New Issue
Block a user