diff --git a/docs/reference/gtk/gtk4-path-tool.rst b/docs/reference/gtk/gtk4-path-tool.rst index a2cca294e5..47b7fb2b50 100644 --- a/docs/reference/gtk/gtk4-path-tool.rst +++ b/docs/reference/gtk/gtk4-path-tool.rst @@ -12,6 +12,8 @@ SYNOPSIS -------- | **gtk4-path-tool** [OPTIONS...] | +| **gtk4-path-tool** stroke [OPTIONS...] +| **gtk4-path-tool** offset [OPTIONS...] | **gtk4-path-tool** decompose [OPTIONS...] | **gtk4-path-tool** transform [OPTIONS...] | **gtk4-path-tool** reverse [OPTIONS...] @@ -32,6 +34,70 @@ To read a path from stdin, use '-'. COMMANDS -------- +Stroking +^^^^^^^^ + +The ``stroke`` command performs a stroke operation along the path according to +the parameters specified via options. + +``--line-width=VALUE`` + + The line width to use for the stroke. ``VALUE`` must be a positive number. + The default line width is 1. + +``--line-cap=VALUE`` + + The cap style to use at line ends. The possible values are ``butt``, ``round`` + or ``square``. See the SVG specification for details on these styles. + The default cap style is ``butt``. + +``--line-join=VALUE`` + + The join style to use at line joins. The possible values are ``miter``, + ``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification + for details on these styles. + The default join style is ``miter``. + +``--miter-limit=VALUE`` + + The limit at which to clip miters at line joins. The default value is 4. + +``--dashes=VALUE`` + + The dash pattern to use for this stroke. A dash pattern is specified by + a comma-separated list of alternating non-negative numbers. Each number + provides the length of alternate "on" and "off" portions of the stroke. + If the dash pattern is empty, dashing is disabled, which is the default. + See the SVG specification for details on dashing. + +``--dash-offset=VALUE`` + + The offset into the dash pattern where dashing should begin. + The default value is 0. + +Offsetting +^^^^^^^^^^ + +The ``offset`` command applies a lateral offset to the path. Note that this +is different from applying a translation transformation. + +``--distance=VALUE`` + + The distance by which to offset the path. Positive values offset to the right, + negative values to the left (wrt to the direction of the path). The default + value is 0. + +``--line-join=VALUE`` + + The join style to use at line joins. The possible values are ``miter``, + ``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification + for details on these styles. + The default join style is ``miter``. + +``--miter-limit=VALUE`` + + The limit at which to clip miters at line joins. The default value is 4. + Decomposing ^^^^^^^^^^^ @@ -132,7 +198,7 @@ Info ^^^^ The ``info`` command shows various information about the given path, -such as its bounding box and and its length. +such as the number of contours, its bounding box and and its length. REFERENCES ---------- diff --git a/tools/gtk-path-tool-offset.c b/tools/gtk-path-tool-offset.c new file mode 100644 index 0000000000..328f19afb4 --- /dev/null +++ b/tools/gtk-path-tool-offset.c @@ -0,0 +1,85 @@ +/* Copyright 2023 Red Hat, Inc. + * + * GTK+ 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 of the + * License, or (at your option) any later version. + * + * GLib 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 GTK+; see the file COPYING. If not, + * see . + * + * Author: Matthias Clasen + */ + +#include "config.h" + +#include +#include "gtk-path-tool.h" + +#include + +void +do_offset (int *argc, const char ***argv) +{ + GError *error = NULL; + double distance = 0; + const char *join = "miter"; + double miter_limit = 4; + char **args = NULL; + GOptionContext *context; + GOptionEntry entries[] = { + { "distance", 0, 0, G_OPTION_ARG_DOUBLE, &distance, N_("Offset to apply (positive or negative number)"), N_("VALUE") }, + { "line-join", 0, 0, G_OPTION_ARG_STRING, &join, N_("Line join (miter, miter-clip, round, bevel, arcs)"), N_("VALUE") }, + { "miter-limit", 0, 0, G_OPTION_ARG_DOUBLE, &miter_limit, N_("Miter limit (number"), N_("VALUE") }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") }, + { NULL, }, + }; + GskPath *path, *result; + GskLineJoin line_join; + + g_set_prgname ("gtk4-path-tool offset"); + + context = g_option_context_new (NULL); + g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_set_summary (context, _("Offset a path.")); + + if (!g_option_context_parse (context, argc, (char ***)argv, &error)) + { + g_printerr ("%s\n", error->message); + g_error_free (error); + exit (1); + } + + g_option_context_free (context); + + if (args == NULL) + { + g_printerr ("%s\n", _("No paths given.")); + exit (1); + } + + path = get_path (args[0]); + + line_join = get_enum_value (GSK_TYPE_LINE_JOIN, _("line join"), join); + + result = gsk_path_offset (path, distance, line_join, miter_limit); + + if (result) + { + char *str = gsk_path_to_string (result); + g_print ("%s\n", str); + g_free (str); + } + else + { + g_printerr ("%s\n", _("That didn't work out.")); + exit (1); + } +} diff --git a/tools/gtk-path-tool-stroke.c b/tools/gtk-path-tool-stroke.c new file mode 100644 index 0000000000..689313b969 --- /dev/null +++ b/tools/gtk-path-tool-stroke.c @@ -0,0 +1,134 @@ +/* Copyright 2023 Red Hat, Inc. + * + * GTK+ 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 of the + * License, or (at your option) any later version. + * + * GLib 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 GTK+; see the file COPYING. If not, + * see . + * + * Author: Matthias Clasen + */ + +#include "config.h" + +#include +#include "gtk-path-tool.h" + +#include + +void +do_stroke (int *argc, const char ***argv) +{ + GError *error = NULL; + double line_width = 1; + const char *cap = "butt"; + const char *join = "miter"; + double miter_limit = 4; + const char *dashes = NULL; + double dash_offset = 0; + char **args = NULL; + GOptionContext *context; + GOptionEntry entries[] = { + { "line-width", 0, 0, G_OPTION_ARG_DOUBLE, &line_width, N_("Line width (number)"), N_("VALUE") }, + { "line-cap", 0, 0, G_OPTION_ARG_STRING, &cap, N_("Line cap (butt, round, square)"), N_("VALUE") }, + { "line-join", 0, 0, G_OPTION_ARG_STRING, &join, N_("Line join (miter, miter-clip, round, bevel, arcs)"), N_("VALUE") }, + { "miter-limit", 0, 0, G_OPTION_ARG_DOUBLE, &miter_limit, N_("Miter limit (number)"), N_("VALUE") }, + { "dashes", 0, 0, G_OPTION_ARG_STRING, &dashes, N_("Dash pattern (comma-separated numbers)"), N_("VALUE") }, + { "dash-offset", 0, 0, G_OPTION_ARG_DOUBLE, &dash_offset, N_("Dash offset (number)"), N_("VALUE") }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") }, + { NULL, }, + }; + GskPath *path, *result; + GskLineCap line_cap; + GskLineJoin line_join; + GskStroke *stroke; + + g_set_prgname ("gtk4-path-tool stroke"); + + context = g_option_context_new (NULL); + g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_set_summary (context, _("Stroke a path.")); + + if (!g_option_context_parse (context, argc, (char ***)argv, &error)) + { + g_printerr ("%s\n", error->message); + g_error_free (error); + exit (1); + } + + g_option_context_free (context); + + if (args == NULL) + { + g_printerr (_("No paths given.\n")); + exit (1); + } + + path = get_path (args[0]); + + line_cap = get_enum_value (GSK_TYPE_LINE_CAP, _("line cap"), cap); + line_join = get_enum_value (GSK_TYPE_LINE_JOIN, _("line join"), join); + + stroke = gsk_stroke_new (line_width); + gsk_stroke_set_line_cap (stroke, line_cap); + gsk_stroke_set_line_join (stroke, line_join); + + gsk_stroke_set_miter_limit (stroke, miter_limit); + + if (dashes != NULL) + { + GArray *d = g_array_new (FALSE, FALSE, sizeof (float)); + char **strings; + + strings = g_strsplit (dashes, ",", 0); + + for (unsigned int i = 0; strings[i]; i++) + { + char *end = NULL; + float f; + + f = (float) g_ascii_strtod (strings[i], &end); + + if (*end != '\0') + { + char *msg = g_strdup_printf (_("Failed to parse '%s' as number"), strings[i]); + g_printerr ("%s\n", msg); + exit (1); + } + + g_array_append_val (d, f); + } + + g_strfreev (strings); + + gsk_stroke_set_dash (stroke, (const float *)d->data, d->len); + + g_array_unref (d); + } + + gsk_stroke_set_dash_offset (stroke, dash_offset); + + result = gsk_path_stroke (path, stroke); + gsk_stroke_free (stroke); + + if (result) + { + char *str = gsk_path_to_string (result); + g_print ("%s\n", str); + g_free (str); + } + else + { + g_printerr ("%s\n", _("That didn't work out.")); + exit (1); + } +} diff --git a/tools/gtk-path-tool.c b/tools/gtk-path-tool.c index 820e3da154..a039302f09 100644 --- a/tools/gtk-path-tool.c +++ b/tools/gtk-path-tool.c @@ -38,6 +38,8 @@ usage (void) "Perform various tasks on paths.\n" "\n" "Commands:\n" + " stroke Stroke the path\n" + " offset Offset the path\n" " decompose Decompose the path\n" " transform Transform the path\n" " reverse Reverse the path\n" @@ -131,6 +133,8 @@ main (int argc, const char *argv[]) do_decompose (&argc, &argv); else if (strcmp (argv[0], "info") == 0) do_info (&argc, &argv); + else if (strcmp (argv[0], "offset") == 0) + do_offset (&argc, &argv); else if (strcmp (argv[0], "render") == 0) do_render (&argc, &argv); else if (strcmp (argv[0], "restrict") == 0) @@ -139,6 +143,8 @@ main (int argc, const char *argv[]) do_reverse (&argc, &argv); else if (strcmp (argv[0], "show") == 0) do_show (&argc, &argv); + else if (strcmp (argv[0], "stroke") == 0) + do_stroke (&argc, &argv); else if (strcmp (argv[0], "transform") == 0) do_transform (&argc, &argv); else diff --git a/tools/gtk-path-tool.h b/tools/gtk-path-tool.h index d2949d8cc1..f27c7d0500 100644 --- a/tools/gtk-path-tool.h +++ b/tools/gtk-path-tool.h @@ -1,6 +1,8 @@ #pragma once void do_info (int *argc, const char ***argv); +void do_stroke (int *argc, const char ***argv); +void do_offset (int *argc, const char ***argv); void do_decompose (int *argc, const char ***argv); void do_transform (int *argc, const char ***argv); void do_reverse (int *argc, const char ***argv); diff --git a/tools/meson.build b/tools/meson.build index 698c996a13..874eb8a26a 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -26,10 +26,12 @@ gtk_tools = [ ['gtk4-path-tool', ['gtk-path-tool.c', 'gtk-path-tool-decompose.c', 'gtk-path-tool-info.c', + 'gtk-path-tool-offset.c', 'gtk-path-tool-render.c', 'gtk-path-tool-restrict.c', 'gtk-path-tool-reverse.c', 'gtk-path-tool-show.c', + 'gtk-path-tool-stroke.c', 'gtk-path-tool-transform.c', 'gtk-path-tool-utils.c', 'path-view.c'], [libgtk_dep]],