[gtk/wip/matthiasc/lottie-stroke: 61/67] Add an interactive test for stroking
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/matthiasc/lottie-stroke: 61/67] Add an interactive test for stroking
- Date: Thu, 3 Dec 2020 02:46:44 +0000 (UTC)
commit 5a04207c8cdc35fd26dc05fa3a7d7bf84bbccb9a
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Nov 28 13:30:35 2020 -0500
Add an interactive test for stroking
Give the curve test a full complement of stroke
parameters to play with and make it useful for
debugging various aspects of path functionality
and in particular path stroking.
tests/curve2.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 224 insertions(+), 31 deletions(-)
---
diff --git a/tests/curve2.c b/tests/curve2.c
index e09c4a5509..a9706b0ab3 100644
--- a/tests/curve2.c
+++ b/tests/curve2.c
@@ -18,6 +18,15 @@ struct _DemoWidget
gboolean track;
gboolean show_bounding_box;
GtkWidget *label;
+
+ gboolean do_stroke;
+ GskPath *stroke_path;
+ GskStroke *stroke;
+ GskPathMeasure *stroke_measure;
+ GskPath *outline_path;
+ GskStroke *outline_stroke;
+ gboolean inside;
+ GskFillRule fill_rule;
};
struct _DemoWidgetClass
@@ -33,29 +42,43 @@ motion (GtkEventControllerMotion *controller,
double y,
DemoWidget *self)
{
- float distance;
- char *text;
- float t;
+ if (self->track)
+ {
+ float distance;
+ char *text;
+ float t;
- if (!self->track)
- return;
+ self->x = x;
+ self->y = y;
- self->x = x;
- self->y = y;
- gsk_path_measure_get_closest_point_full (self->measure,
- &GRAPHENE_POINT_INIT (x, y),
- FLT_MAX,
- &distance,
- &self->point,
- &t,
- &self->tangent);
+ gsk_path_measure_get_closest_point_full (self->measure,
+ &GRAPHENE_POINT_INIT (x, y),
+ INFINITY,
+ &distance,
+ &self->point,
+ &t,
+ &self->tangent);
- gsk_path_measure_get_point (self->measure, t, &self->point2, NULL);
+ gsk_path_measure_get_point (self->measure, t, &self->point2, NULL);
- text = g_strdup_printf ("%.1f", distance);
- gtk_label_set_label (GTK_LABEL (self->label), text);
+ text = g_strdup_printf ("%.1f", distance);
+ gtk_label_set_label (GTK_LABEL (self->label), text);
- gtk_widget_queue_draw (GTK_WIDGET (self));
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+ }
+
+ if (self->do_stroke)
+ {
+ gboolean inside = TRUE;
+
+ inside = gsk_path_measure_in_fill (self->stroke_measure, &GRAPHENE_POINT_INIT (x, y), self->fill_rule);
+
+ if (self->inside != inside)
+ {
+ self->inside = inside;
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+ }
+ }
}
static void
@@ -85,7 +108,6 @@ demo_widget_snapshot (GtkWidget *widget,
GskStroke *stroke;
GskPathBuilder *builder;
GskPath *path;
- graphene_point_t p;
if (!self->path)
return;
@@ -93,21 +115,53 @@ demo_widget_snapshot (GtkWidget *widget,
width = gtk_widget_get_width (widget);
height = gtk_widget_get_width (widget);
- stroke = gsk_stroke_new (1.0);
- gtk_snapshot_push_stroke (snapshot, self->path, stroke);
- gsk_stroke_free (stroke);
+ if (self->do_stroke)
+ {
+ if (self->inside)
+ {
+ gtk_snapshot_push_fill (snapshot, self->stroke_path, self->fill_rule);
+
+ gtk_snapshot_append_color (snapshot,
+ &(GdkRGBA){ 1, 0, 1, 0.3},
+ &GRAPHENE_RECT_INIT (0, 0, width, height ));
+
+ gtk_snapshot_pop (snapshot);
+ }
+
+ gtk_snapshot_push_fill (snapshot, self->outline_path, GSK_FILL_RULE_WINDING);
+
+ gtk_snapshot_append_color (snapshot,
+ &(GdkRGBA){ 0, 0, 0, 0.2},
+ &GRAPHENE_RECT_INIT (0, 0, width, height ));
+
+ gtk_snapshot_pop (snapshot);
+
+ stroke = gsk_stroke_new (1);
+ gtk_snapshot_push_stroke (snapshot, self->path, stroke);
+ gsk_stroke_free (stroke);
+
+ gtk_snapshot_append_color (snapshot,
+ &(GdkRGBA){ 0, 0, 0, 0.3},
+ &GRAPHENE_RECT_INIT (0, 0, width, height ));
+
+ gtk_snapshot_pop (snapshot);
+ }
+ else
+ {
+ gtk_snapshot_push_stroke (snapshot, self->path, self->outline_stroke);
- gtk_snapshot_append_color (snapshot,
- &(GdkRGBA){ 0, 0, 0, 1},
- &GRAPHENE_RECT_INIT (0, 0, width, height ));
+ gtk_snapshot_append_color (snapshot,
+ &(GdkRGBA){ 0, 0, 0, 1},
+ &GRAPHENE_RECT_INIT (0, 0, width, height ));
- gtk_snapshot_pop (snapshot);
+ gtk_snapshot_pop (snapshot);
+ }
if (self->show_bounding_box)
{
graphene_rect_t bounds;
- if (gsk_path_get_bounds (self->path, &bounds))
+ if (gsk_path_get_bounds (self->do_stroke ? self->outline_path : self->path, &bounds))
{
builder = gsk_path_builder_new ();
@@ -131,6 +185,8 @@ demo_widget_snapshot (GtkWidget *widget,
if (self->track)
{
+ graphene_point_t p;
+
p.x = self->point.x + graphene_vec2_get_x (&self->tangent) * 40;
p.y = self->point.y + graphene_vec2_get_y (&self->tangent) * 40;
@@ -190,6 +246,11 @@ demo_widget_dispose (GObject *object)
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
+ g_clear_pointer (&self->stroke_path, gsk_path_unref);
+ g_clear_pointer (&self->stroke_measure, gsk_path_measure_unref);
+ g_clear_pointer (&self->stroke, gsk_stroke_free);
+ g_clear_pointer (&self->outline_path, gsk_path_unref);
+ g_clear_pointer (&self->outline_stroke, gsk_stroke_free);
g_clear_pointer (&self->label, gtk_widget_unparent);
G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object);
@@ -214,6 +275,33 @@ demo_widget_new (void)
return g_object_new (DEMO_TYPE_WIDGET, NULL);
}
+static void
+update_outline_path (DemoWidget *self)
+{
+ if (self->stroke_measure)
+ {
+ g_clear_pointer (&self->outline_path, gsk_path_unref);
+ self->outline_path = gsk_path_measure_stroke (self->stroke_measure, self->outline_stroke);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+ }
+}
+
+static void
+update_stroke_path (DemoWidget *self)
+{
+ g_clear_pointer (&self->stroke_path, gsk_path_unref);
+ g_clear_pointer (&self->stroke_measure, gsk_path_measure_unref);
+
+ if (self->do_stroke)
+ {
+ self->stroke_path = gsk_path_measure_stroke (self->measure, self->stroke);
+ self->stroke_measure = gsk_path_measure_new (self->stroke_path);
+ update_outline_path (self);
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
static void
update_path (DemoWidget *self)
{
@@ -238,6 +326,8 @@ update_path (DemoWidget *self)
self->measure = gsk_path_measure_new (self->path);
+ update_stroke_path (self);
+
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -279,6 +369,8 @@ init_demo (DemoWidget *demo,
gsk_path_builder_move_to (builder, 300, 150);
gsk_path_builder_curve_to (builder, 300, 50, 400, 50, 400, 150);
gsk_path_builder_curve_to (builder, 400, 250, 500, 250, 500, 150);
+ gsk_path_builder_line_to (builder, 600, 150);
+ gsk_path_builder_line_to (builder, 530, 190);
path = gsk_path_builder_free_to_path (builder);
demo_widget_set_path (demo, path);
@@ -287,6 +379,9 @@ init_demo (DemoWidget *demo,
gtk_editable_set_text (editable, string);
g_free (string);
gsk_path_unref (path);
+
+ demo->stroke = gsk_stroke_new (20);
+ demo->outline_stroke = gsk_stroke_new (1);
}
static void
@@ -305,6 +400,15 @@ bb_toggled (GtkCheckButton *button,
gtk_widget_queue_draw (GTK_WIDGET (self));
}
+static void
+stroke_toggled (GtkCheckButton *button,
+ DemoWidget *self)
+{
+ self->do_stroke = gtk_check_button_get_active (button);
+ update_stroke_path (self);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
static GtkWidget *start_scale;
static GtkWidget *end_scale;
@@ -333,17 +437,68 @@ range_changed (GtkRange *range,
update_path (self);
}
+static void
+fill_rule_changed (GtkDropDown *combo,
+ GParamSpec *pspec,
+ DemoWidget *self)
+{
+ self->fill_rule = (GskFillRule)gtk_drop_down_get_selected (combo);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+cap_changed (GtkDropDown *combo,
+ GParamSpec *pspec,
+ DemoWidget *self)
+{
+ gsk_stroke_set_line_cap (self->stroke, (GskLineCap)gtk_drop_down_get_selected (combo));
+ update_stroke_path (self);
+}
+
+static void
+join_changed (GtkDropDown *combo,
+ GParamSpec *pspec,
+ DemoWidget *self)
+{
+ gsk_stroke_set_line_join (self->stroke, (GskLineJoin)gtk_drop_down_get_selected (combo));
+ update_stroke_path (self);
+}
+
+static void
+limit_changed (GtkSpinButton *spin,
+ DemoWidget *self)
+{
+ gsk_stroke_set_miter_limit (self->stroke, gtk_spin_button_get_value (spin));
+ update_stroke_path (self);
+}
+
+static void
+stroke_width_changed (GtkSpinButton *spin,
+ DemoWidget *self)
+{
+ gsk_stroke_set_line_width (self->stroke, gtk_spin_button_get_value (spin));
+ update_stroke_path (self);
+}
+
+static void
+line_width_changed (GtkSpinButton *spin,
+ DemoWidget *self)
+{
+ gsk_stroke_set_line_width (self->outline_stroke, gtk_spin_button_get_value (spin));
+ update_outline_path (self);
+}
+
int
main (int argc, char *argv[])
{
GtkWidget *window, *box, *demo, *entry;
GtkWidget *popover, *button, *grid;
- GtkWidget *header, *toggle;
+ GtkWidget *header, *toggle, *combo, *spin;
gtk_init ();
window = gtk_window_new ();
- gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+ gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box);
@@ -368,11 +523,49 @@ main (int argc, char *argv[])
toggle = gtk_check_button_new_with_label ("Show closest point");
g_signal_connect (toggle, "toggled", G_CALLBACK (track_toggled), demo);
- gtk_grid_attach (GTK_GRID (grid), toggle, 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), toggle, 1, 0, 1, 1);
toggle = gtk_check_button_new_with_label ("Show bounding box");
g_signal_connect (toggle, "toggled", G_CALLBACK (bb_toggled), demo);
- gtk_grid_attach (GTK_GRID (grid), toggle, 0, 1, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), toggle, 1, 1, 1, 1);
+
+ toggle = gtk_check_button_new_with_label ("Stroke path");
+ g_signal_connect (toggle, "toggled", G_CALLBACK (stroke_toggled), demo);
+ gtk_grid_attach (GTK_GRID (grid), toggle, 1, 2, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Fill rule"), 0, 3, 1, 1);
+
+ combo = gtk_drop_down_new_from_strings ((const char *[]){"Winding", "Even-Odd", NULL });
+ g_signal_connect (combo, "notify::selected", G_CALLBACK (fill_rule_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), combo, 1, 3, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line cap:"), 0, 4, 1, 1);
+ combo = gtk_drop_down_new_from_strings ((const char *[]){"Butt", "Round", "Square", NULL});
+ g_signal_connect (combo, "notify::selected", G_CALLBACK (cap_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), combo, 1, 4, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line join:"), 0, 5, 1, 1);
+ combo = gtk_drop_down_new_from_strings ((const char *[]){"Miter", "Miter-clip", "Round", "Bevel", NULL});
+ g_signal_connect (combo, "notify::selected", G_CALLBACK (join_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), combo, 1, 5, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Miter limit:"), 0, 6, 1, 1);
+ spin = gtk_spin_button_new_with_range (0, 10, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 4);
+ g_signal_connect (spin, "value-changed", G_CALLBACK (limit_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), spin, 1, 6, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Stroke width:"), 0, 7, 1, 1);
+ spin = gtk_spin_button_new_with_range (1, 40, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 20);
+ g_signal_connect (spin, "value-changed", G_CALLBACK (stroke_width_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), spin, 1, 7, 1, 1);
+
+ gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line width:"), 0, 8, 1, 1);
+ spin = gtk_spin_button_new_with_range (1, 20, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 1);
+ g_signal_connect (spin, "value-changed", G_CALLBACK (line_width_changed), demo);
+ gtk_grid_attach (GTK_GRID (grid), spin, 1, 8, 1, 1);
entry = gtk_entry_new ();
g_signal_connect (entry, "activate", G_CALLBACK (activate), demo);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]