diff --git a/docs/reference/gsk/gsk4.toml.in b/docs/reference/gsk/gsk4.toml.in index e451183ba8..813f974c4c 100644 --- a/docs/reference/gsk/gsk4.toml.in +++ b/docs/reference/gsk/gsk4.toml.in @@ -36,6 +36,8 @@ content_images = [ "gtk-logo.svg", "images/caps-dark.png", "images/caps-light.png", + "images/directions-dark.png", + "images/directions-light.png", "images/join-dark.png", "images/join-light.png", "images/path-dark.png", diff --git a/docs/reference/gsk/images/directions-dark.png b/docs/reference/gsk/images/directions-dark.png new file mode 100644 index 0000000000..77505ee462 Binary files /dev/null and b/docs/reference/gsk/images/directions-dark.png differ diff --git a/docs/reference/gsk/images/directions-light.png b/docs/reference/gsk/images/directions-light.png new file mode 100644 index 0000000000..c61840a84f Binary files /dev/null and b/docs/reference/gsk/images/directions-light.png differ diff --git a/docs/reference/gsk/images/directions.svg b/docs/reference/gsk/images/directions.svg new file mode 100644 index 0000000000..bb432a059e --- /dev/null +++ b/docs/reference/gsk/images/directions.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GSK_PATH_FROM_START + GSK_PATH_FROM_START + GSK_PATH_TO_START + GSK_PATH_TO_START + GSK_PATH_TO_END + GSK_PATH_TO_END + GSK_PATH_FROM_END + GSK_PATH_FROM_END + + + + diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c index f708e242f6..d76327847a 100644 --- a/gsk/gskcontour.c +++ b/gsk/gskcontour.c @@ -509,7 +509,8 @@ gsk_standard_contour_get_tangent (const GskContour *contour, idx = point->idx; t = point->t; - if (t == 0 && direction == GSK_PATH_START) + if (t == 0 && (direction == GSK_PATH_FROM_START || + direction == GSK_PATH_TO_START)) { /* Look at the previous segment */ if (idx > 1) @@ -523,7 +524,8 @@ gsk_standard_contour_get_tangent (const GskContour *contour, t = 1; } } - else if (t == 1 && direction == GSK_PATH_END) + else if (t == 1 && (direction == GSK_PATH_TO_END || + direction == GSK_PATH_FROM_END)) { /* Look at the next segment */ if (idx < self->n_ops - 1) @@ -540,6 +542,9 @@ gsk_standard_contour_get_tangent (const GskContour *contour, gsk_curve_init (&curve, self->ops[idx]); gsk_curve_get_tangent (&curve, t, tangent); + + if (direction == GSK_PATH_TO_START || direction == GSK_PATH_FROM_END) + graphene_vec2_negate (tangent, tangent); } static float diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 9ed0ee077e..fe157ab80b 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -292,17 +292,30 @@ typedef enum { /** * GskPathDirection: - * @GSK_PATH_START: The side that leads to the start of the path - * @GSK_PATH_END: The side that leads to the end of the path + * @GSK_PATH_FROM_START: The tangent in path direction of the incoming side + * of the path + * @GSK_PATH_TO_START: The tangent against path direction of the incoming side + * of the path + * @GSK_PATH_TO_END: The tangent in path direction of the outgoing side + * of the path + * @GSK_PATH_FROM_END: The tangent against path direction of the outgoing + * side of the path * * The values of the `GskPathDirection` enum are used to pick one - * of the two sides of the path that at a given point on the path. + * of the four tangents at a given point on the path. + * + * + * + * Path Tangents + * * * Since: 4.14 */ typedef enum { - GSK_PATH_START, - GSK_PATH_END + GSK_PATH_FROM_START, + GSK_PATH_TO_START, + GSK_PATH_TO_END, + GSK_PATH_FROM_END, } GskPathDirection; /** diff --git a/gsk/gskpathpoint.c b/gsk/gskpathpoint.c index a55e879b18..d1835743a1 100644 --- a/gsk/gskpathpoint.c +++ b/gsk/gskpathpoint.c @@ -19,12 +19,16 @@ #include "config.h" +#include + #include "gskpathpointprivate.h" #include "gskcontourprivate.h" #include "gdk/gdkprivate.h" +#define RAD_TO_DEG(x) ((x) / (G_PI / 180.f)) + /** * GskPathPoint: * @@ -181,6 +185,10 @@ gsk_path_point_get_position (const GskPathPoint *point, * point, and the direction coming out of it. The @direction * argument lets you choose which one to get. * + * If you want to orient something in the direction of the + * path, [method@Gsk.PathPoint.get_rotation] may be more + * convenient to use. + * * Since: 4.14 */ void @@ -201,6 +209,40 @@ gsk_path_point_get_tangent (const GskPathPoint *point, gsk_contour_get_tangent (contour, self, direction, tangent); } +/** + * gsk_path_point_get_rotation: + * @point: a `GskPathPoint` + * @path: the path that @point is on + * @direction: the direction for which to return the rotation + * + * Gets the direction of the tangent at a given point. + * + * This is a convenience variant of [method@Gsk.PathPoint.get_tangent] + * that returns the angle between the tangent and the X axis. The angle + * can e.g. be used in [method@Gtk.Snapshot.rotate]. + * + * Returns: the angle between the tangent and the X axis, in degrees + * + * Since: 4.14 + */ +float +gsk_path_point_get_rotation (const GskPathPoint *point, + GskPath *path, + GskPathDirection direction) +{ + GskRealPathPoint *self = (GskRealPathPoint *) point; + graphene_vec2_t tangent; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (path != NULL, 0); + g_return_val_if_fail (self->contour < gsk_path_get_n_contours (path), 0); + + gsk_path_point_get_tangent (point, path, direction, &tangent); + + return RAD_TO_DEG (atan2f (graphene_vec2_get_y (&tangent), + graphene_vec2_get_x (&tangent))); +} + /** * gsk_path_point_get_curvature: * @point: a `GskPathPoint` diff --git a/gsk/gskpathpoint.h b/gsk/gskpathpoint.h index 4fdacc797e..56d65cb641 100644 --- a/gsk/gskpathpoint.h +++ b/gsk/gskpathpoint.h @@ -67,6 +67,11 @@ void gsk_path_point_get_tangent (const GskPathPoint *poin GskPathDirection direction, graphene_vec2_t *tangent); +GDK_AVAILABLE_IN_4_14 +float gsk_path_point_get_rotation (const GskPathPoint *point, + GskPath *path, + GskPathDirection direction); + GDK_AVAILABLE_IN_4_14 float gsk_path_point_get_curvature (const GskPathPoint *point, GskPath *path, diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index f55a1b62d6..d838568836 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -1151,6 +1151,9 @@ gtk_snapshot_clear_fill (GtkSnapshotState *state) * * The image is recorded until the next call to [method@Gtk.Snapshot.pop]. * + * If you want to fill the path with a color, [method@Gtk.Snapshot.append_fill] + * may be more convenient. + * * Since: 4.14 */ void @@ -1171,6 +1174,35 @@ gtk_snapshot_push_fill (GtkSnapshot *snapshot, state->data.fill.fill_rule = fill_rule; } +/** + * gtk_snapshot_append_fill: + * @snapshot: a `GtkSnapshot` + * @path: The path describing the area to fill + * @fill_rule: The fill rule to use + * @color: the color to fill the path with + * + * A convenience method to fill a path with a color. + * + * See [method@Gtk.Snapshot.push_fill] if you need + * to fill a path with more complex content than + * a color. + * + * Since: 4.14 + */ +void +gtk_snapshot_append_fill (GtkSnapshot *snapshot, + GskPath *path, + GskFillRule fill_rule, + const GdkRGBA *color) +{ + graphene_rect_t bounds; + + gsk_path_get_bounds (path, &bounds); + gtk_snapshot_push_fill (snapshot, path, fill_rule); + gtk_snapshot_append_color (snapshot, color, &bounds); + gtk_snapshot_pop (snapshot); +} + static GskRenderNode * gtk_snapshot_collect_stroke (GtkSnapshot *snapshot, GtkSnapshotState *state, @@ -1222,6 +1254,9 @@ gtk_snapshot_clear_stroke (GtkSnapshotState *state) * everything else, so uneven scaling will cause horizontal and vertical * strokes to have different widths. * + * If you want to stroke the path with a color, [method@Gtk.Snapshot.append_stroke] + * may be more convenient. + * * Since: 4.14 */ void @@ -1265,6 +1300,35 @@ gtk_snapshot_collect_shadow (GtkSnapshot *snapshot, return shadow_node; } +/** + * gtk_snapshot_append_stroke: + * @snapshot: a `GtkSnapshot` + * @path: The path describing the area to fill + * @stroke: The stroke attributes + * @color: the color to fill the path with + * + * A convenience method to stroke a path with a color. + * + * See [method@Gtk.Snapshot.push_stroke] if you need + * to stroke a path with more complex content than + * a color. + * + * Since: 4.14 + */ +void +gtk_snapshot_append_stroke (GtkSnapshot *snapshot, + GskPath *path, + const GskStroke *stroke, + const GdkRGBA *color) +{ + graphene_rect_t bounds; + + gsk_path_get_stroke_bounds (path, stroke, &bounds); + gtk_snapshot_push_stroke (snapshot, path, stroke); + gtk_snapshot_append_color (snapshot, color, &bounds); + gtk_snapshot_pop (snapshot); +} + static void gtk_snapshot_clear_shadow (GtkSnapshotState *state) { diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index faa40b732d..d3d25e8c67 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -240,6 +240,16 @@ void gtk_snapshot_append_layout (GtkSnapshot PangoLayout *layout, const GdkRGBA *color); +GDK_AVAILABLE_IN_4_14 +void gtk_snapshot_append_fill (GtkSnapshot *snapshot, + GskPath *path, + GskFillRule fill_rule, + const GdkRGBA *color); +GDK_AVAILABLE_IN_4_14 +void gtk_snapshot_append_stroke (GtkSnapshot *snapshot, + GskPath *path, + const GskStroke *stroke, + const GdkRGBA *color); G_END_DECLS diff --git a/testsuite/gsk/path-special-cases.c b/testsuite/gsk/path-special-cases.c index bc83ba9249..927bc578d7 100644 --- a/testsuite/gsk/path-special-cases.c +++ b/testsuite/gsk/path-special-cases.c @@ -466,8 +466,8 @@ test_path_point (void) g_assert_true (rp->t == 1); gsk_path_point_get_position (&point, path, &pos); - gsk_path_point_get_tangent (&point, path, GSK_PATH_START, &t1); - gsk_path_point_get_tangent (&point, path, GSK_PATH_END, &t2); + gsk_path_point_get_tangent (&point, path, GSK_PATH_TO_START, &t1); + gsk_path_point_get_tangent (&point, path, GSK_PATH_TO_END, &t2); curvature = gsk_path_point_get_curvature (&point, path, ¢er); g_assert_true (graphene_point_equal (&pos, &GRAPHENE_POINT_INIT (100, 100)));