Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e155c3fe36 | |||
| 595152bdba | |||
| 625e83e1de | |||
| daac04be82 | |||
| 8ec9bba892 | |||
| b63e365fd2 | |||
| 859a25b0e7 | |||
| f5d47a4658 | |||
| fa6645f157 | |||
| 2929686c1d | |||
| c83256e080 | |||
| 4b7e1b1233 | |||
| 95a8821614 | |||
| 73500f9ebb | |||
| eae38756c2 | |||
| 8bf7187b89 | |||
| e7fb8842b5 | |||
| aaac0cb4a1 | |||
| 67a4279d3f | |||
| dd4b8a4c89 | |||
| 4cc5a54da3 | |||
| 07add0144e | |||
| d1c7376b05 | |||
| a71388d2d6 | |||
| 62176a3bd0 | |||
| 8475a29836 | |||
| 44bc5a139c | |||
| 11f48f3c5b | |||
| fa4ad1590d | |||
| 47ddc742fc | |||
| 31d994837b | |||
| 83d692e2d3 | |||
| f2835bb48b | |||
| 857c22db32 | |||
| fff1645060 | |||
| 4f0c3c81fb | |||
| 421365cfc3 | |||
| 59c5b41f3d | |||
| 267367355f | |||
| 0aa3356499 | |||
| 14a3b35333 | |||
| 77def95659 | |||
| 4e91cd1155 | |||
| 2d923d362f | |||
| b7544636d4 | |||
| 6220baf230 | |||
| 917307a6a4 | |||
| 5f49b7b492 | |||
| b03abea402 | |||
| d4fcc883cb | |||
| ca2a2697d6 | |||
| 68c6f63e90 | |||
| 0e89fed8ed | |||
| 4d726543d0 | |||
| 2bcc998e90 | |||
| f707185248 | |||
| ded30049db | |||
| 5c55e9d11e | |||
| c35bb11c18 | |||
| cc19781d27 | |||
| 08d08678e8 | |||
| 11b632a691 | |||
| 4881ef251e | |||
| 5b39abd1a4 | |||
| f0089097dd | |||
| d603925ab2 | |||
| 5240d8cdf5 |
@@ -34,5 +34,11 @@ base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
|
||||
[extra]
|
||||
content_images = [
|
||||
"gtk-logo.svg",
|
||||
"images/caps-dark.png",
|
||||
"images/caps-light.png",
|
||||
"images/join-dark.png",
|
||||
"images/join-light.png",
|
||||
"images/path-dark.png",
|
||||
"images/path-light.png",
|
||||
]
|
||||
urlmap_file = "urlmap.js"
|
||||
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
sodipodi:docname="caps.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="2.1493149"
|
||||
inkscape:cx="438.74445"
|
||||
inkscape:cy="288.69664"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1123"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="swatch1"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-miterlimit:0;stroke-dasharray:none"
|
||||
d="m 73.096455,77.084329 c 0,0 6.439436,18.711677 18.172676,26.635721"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.214979,99.722163 c -4.705477,-3.177832 -9.013472,-9.233699 -11.888672,-14.531169 -2.8752,-5.29748 -4.353516,-9.587833 -4.353516,-9.587833 L 68.51576,78.85704 c 0,0 1.743663,5.064163 5.021484,11.103457 3.277822,6.039297 8.05428,13.302573 15.082031,18.048773"
|
||||
id="path1-1"
|
||||
sodipodi:nodetypes="csccsc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-miterlimit:0;stroke-dasharray:none"
|
||||
d="m 112.14213,75.736452 c 0,0 6.43944,18.711675 18.17268,26.635728"
|
||||
id="path1-4"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-linecap:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 132.83284,98.590758 c -4.70551,-3.177807 -9.01347,-9.233742 -11.88867,-14.53125 -2.8752,-5.297508 -4.35351,-9.587891 -4.35351,-9.587891 -0.89828,-2.611719 -3.74396,-4.000453 -6.35547,-3.101562 -2.61172,0.898277 -4.00046,3.743958 -3.10157,6.355468 0,0 1.74367,5.064185 5.02149,11.103516 3.27782,6.039331 8.05428,13.302641 15.08203,18.048851"
|
||||
id="path1-4-5"
|
||||
sodipodi:nodetypes="cscccsc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-miterlimit:0;stroke-dasharray:none"
|
||||
d="m 154.10911,73.84561 c 0,0 6.43943,18.711677 18.17267,26.63572"
|
||||
id="path1-0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 175.16683,96.47344 C 170.46135,93.295592 166.1514,87.239699 163.2762,81.94219 160.401,76.644682 158.92269,72.3543 158.92269,72.3543 l -1.62696,-4.728516 -9.45508,3.253906 1.62696,4.728516 c 0,0 1.74171,5.066138 5.01953,11.105469 3.27782,6.039331 8.05428,13.300675 15.08203,18.046895"
|
||||
id="path1-4-1"
|
||||
sodipodi:nodetypes="csccccsc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
sodipodi:docname="join.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.75989759"
|
||||
inkscape:cx="118.43701"
|
||||
inkscape:cy="570.47161"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1123"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
d="m 12.748727,122.15935 c 4.449842,-15.44496 4.175632,-15.92044 16.908788,-26.568585 0,0 8.478091,16.421195 35.150804,33.660325"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 17.59375,123.72266 c 3.810222,-13.2249 3.591775,-14.13123 11.107422,-20.53516 1.289688,1.82186 2.604788,3.71164 4.800781,6.23242 5.743296,6.59272 14.891452,15.32766 28.632813,24.20899 M 67.5625,125.23047 C 54.631174,116.87268 46.204933,108.77726 41.041016,102.84961 35.877098,96.921954 34.140625,93.474609 34.140625,93.474609 l -2.861328,-5.544922 -4.789063,4.003907 C 13.673794,102.6514 12.411529,105.58692 7.984375,120.95313"
|
||||
id="path1-3"
|
||||
sodipodi:nodetypes="ccsccscccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
d="m 147.99215,122.60257 c 4.44988,-15.44499 4.17566,-15.92048 16.90889,-26.568657 0,0 8.47814,16.421267 35.15101,33.660397"
|
||||
id="path1-5"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 152.79687,123.98633 c 3.81053,-13.22586 3.59005,-14.12993 11.10743,-20.53516 1.28968,1.82184 2.6029,3.71173 4.79882,6.23242 5.74333,6.59274 14.89333,15.32961 28.63477,24.21094 m 5.42773,-8.40039 c -12.9314,-8.35778 -21.35753,-16.45123 -26.52148,-22.37891 -5.16395,-5.927668 -6.90039,-9.374996 -6.90039,-9.374996 l -7.65039,-1.541015 C 148.87685,102.91706 147.61469,105.85252 143.1875,121.21875"
|
||||
id="path1-5-8"
|
||||
sodipodi:nodetypes="ccsccsccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000064;stroke-width:1;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
d="m 79.729342,122.0734 c 4.449844,-15.44499 4.175634,-15.92048 16.908794,-26.568654 0,0 8.478114,16.421264 35.150984,33.660394"
|
||||
id="path1-7"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 84.533203,123.19336 c 3.810222,-13.22495 3.591776,-14.1312 11.107422,-20.53516 1.289696,1.82187 2.604775,3.71164 4.800785,6.23243 5.74333,6.59275 14.89136,15.32765 28.63281,24.20898 m 5.42969,-8.39844 c -12.93141,-8.35778 -21.35949,-16.45122 -26.52344,-22.3789 -5.16395,-5.927686 -6.90039,-9.375004 -6.90039,-9.375004 -0.69636,-1.348401 -1.967393,-2.307601 -3.45508,-2.607422 -1.487509,-0.300132 -3.03083,0.09145 -4.195313,1.064453 C 80.61325,102.12215 79.350982,105.05756 74.923828,120.42383"
|
||||
id="path1-7-4"
|
||||
sodipodi:nodetypes="ccsccscccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
sodipodi:docname="path.svg"
|
||||
inkscape:export-filename="path-dark.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.75989759"
|
||||
inkscape:cx="397.42198"
|
||||
inkscape:cy="561.25984"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1123"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 128.28233,149.47912 154.23127,90.244656 86.340809,68.820468"
|
||||
id="path3" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;fill-opacity:1;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 33.956804,113.31099 c -9.049189,-11.90893 5.40551,-40.570358 20.351208,-39.990271 26.687501,1.035822 4.06495,71.984581 30.695656,74.009711 19.642072,1.49368 41.962402,-34.42048 30.634382,-50.536241 C 99.663884,74.068616 50.763019,135.42833 33.956804,113.31099 Z"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="sssss" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2"
|
||||
cx="34.517788"
|
||||
cy="113.66589"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
id="path2-8"
|
||||
cx="55.045853"
|
||||
cy="73.566689"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
id="path2-8-5"
|
||||
cx="55.045834"
|
||||
cy="73.831245"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2-8-9"
|
||||
cx="55.045834"
|
||||
cy="73.831245"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2-8-9-7"
|
||||
cx="86.398613"
|
||||
cy="68.897667"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2-8-9-7-8"
|
||||
cx="153.87553"
|
||||
cy="90.112595"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000064;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
id="path2-8-7"
|
||||
cx="84.803238"
|
||||
cy="147.51736"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2-8-7-2"
|
||||
cx="115.28235"
|
||||
cy="96.705284"
|
||||
r="1.5" />
|
||||
<circle
|
||||
style="fill:#ff0404;fill-opacity:1;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2-8-9-7-9"
|
||||
cx="127.92362"
|
||||
cy="150.03427"
|
||||
r="1.5" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,181 @@
|
||||
.. _gtk4-path-tool(1):
|
||||
|
||||
=================
|
||||
gtk4-path-tool
|
||||
=================
|
||||
|
||||
-----------------------
|
||||
GskPath Utility
|
||||
-----------------------
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
| **gtk4-path-tool** <COMMAND> [OPTIONS...] <PATH>
|
||||
|
|
||||
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** show [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** render [OPTIONS...] <PATH>
|
||||
| **gtk4-path-tool** info [OPTIONS...] <PATH>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
``gtk4-path-tool`` can perform various tasks on paths. Paths are specified
|
||||
in SVG syntax, as strings like "M 100 100 C 100 200 200 200 200 100 Z".
|
||||
|
||||
To read a path from a file, use a filename that starts with a '.' or a '/'.
|
||||
To read a path from stdin, use '-'.
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
Decomposing
|
||||
^^^^^^^^^^^
|
||||
|
||||
The ``decompose`` command approximates the path by one with simpler elements.
|
||||
When used without options, the curves of the path are approximated by line
|
||||
segments.
|
||||
|
||||
``--allow-quad``
|
||||
|
||||
Allow quadratic Bézier curves to be used in the generated path.
|
||||
|
||||
``--allow-cubic``
|
||||
|
||||
Allow cubic Bézier curves to be used in the generated path.
|
||||
|
||||
Showing
|
||||
^^^^^^^
|
||||
|
||||
The ``show`` command displays the given path in a window. The interior
|
||||
of the path is filled.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
The possible values are ``winding`` or ``even-odd``. The default is ``winding``.
|
||||
|
||||
``--fg-color=COLOR``
|
||||
|
||||
The color that is used to fill the interior of the path or stroke the path.
|
||||
If not specified, black is used.
|
||||
|
||||
``--bg-color=COLOR``
|
||||
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
|
||||
``--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.
|
||||
|
||||
Rendering
|
||||
^^^^^^^^^
|
||||
|
||||
The ``render`` command renders the given path as a PNG image.
|
||||
The interior of the path is filled.
|
||||
|
||||
``--fill-rule=VALUE``
|
||||
|
||||
The fill rule that is used to determine what areas are inside the path.
|
||||
The possible values are ``winding`` or ``even-odd``. The default is ``winding``.
|
||||
|
||||
``--fg-color=COLOR``
|
||||
|
||||
The color that is used to fill the interior of the path or stroke the path.
|
||||
If not specified, black is used.
|
||||
|
||||
``--bg-color=COLOR``
|
||||
|
||||
The color that is used to render the background behind the path.
|
||||
If not specified, white is used.
|
||||
|
||||
``--output-file=FILE``
|
||||
|
||||
The file to save the PNG image to.
|
||||
If not specified, "path.png" is used.
|
||||
|
||||
``--stroke``
|
||||
|
||||
Stroke the path instead of filling it.
|
||||
|
||||
``--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.
|
||||
|
||||
Info
|
||||
^^^^
|
||||
|
||||
The ``info`` command shows various information about the given path,
|
||||
such as its bounding box.
|
||||
|
||||
REFERENCES
|
||||
----------
|
||||
|
||||
- SVG Path Specification, https://www.w3.org/TR/SVG2/paths.html
|
||||
@@ -77,6 +77,7 @@ if get_option('man-pages') and rst2man.found()
|
||||
[ 'gtk4-query-settings', '1', ],
|
||||
[ 'gtk4-rendernode-tool', '1' ],
|
||||
[ 'gtk4-update-icon-cache', '1', ],
|
||||
[ 'gtk4-path-tool', '1', ],
|
||||
]
|
||||
|
||||
if get_option('demos')
|
||||
|
||||
@@ -297,7 +297,7 @@ gdk_clipboard_read_local_async (GdkClipboard *clipboard,
|
||||
{
|
||||
GOutputStream *output_stream;
|
||||
GIOStream *stream;
|
||||
|
||||
|
||||
stream = gdk_pipe_io_stream_new ();
|
||||
output_stream = g_io_stream_get_output_stream (stream);
|
||||
gdk_clipboard_write_async (clipboard,
|
||||
@@ -767,7 +767,7 @@ gdk_clipboard_read_value_internal (GdkClipboard *clipboard,
|
||||
GdkContentFormats *formats;
|
||||
GValue *value;
|
||||
GTask *task;
|
||||
|
||||
|
||||
task = g_task_new (clipboard, cancellable, callback, user_data);
|
||||
g_task_set_priority (task, io_priority);
|
||||
g_task_set_source_tag (task, source_tag);
|
||||
@@ -946,7 +946,7 @@ gdk_clipboard_read_texture_finish (GdkClipboard *clipboard,
|
||||
value = g_task_propagate_pointer (G_TASK (result), error);
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
|
||||
return g_value_dup_object (value);
|
||||
}
|
||||
|
||||
@@ -1011,7 +1011,7 @@ gdk_clipboard_read_text_finish (GdkClipboard *clipboard,
|
||||
value = g_task_propagate_pointer (G_TASK (result), error);
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
|
||||
return g_value_dup_string (value);
|
||||
}
|
||||
|
||||
@@ -1110,7 +1110,7 @@ gdk_clipboard_write_async (GdkClipboard *clipboard,
|
||||
GError *error = NULL;
|
||||
|
||||
g_assert (gtype != G_TYPE_INVALID);
|
||||
|
||||
|
||||
g_value_init (&value, gtype);
|
||||
if (gdk_content_provider_get_value (priv->content, &value, &error))
|
||||
{
|
||||
@@ -1126,7 +1126,7 @@ gdk_clipboard_write_async (GdkClipboard *clipboard,
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
}
|
||||
|
||||
|
||||
g_value_unset (&value);
|
||||
}
|
||||
else
|
||||
@@ -1148,7 +1148,7 @@ gdk_clipboard_write_finish (GdkClipboard *clipboard,
|
||||
g_return_val_if_fail (g_task_is_valid (result, clipboard), FALSE);
|
||||
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_clipboard_write_async, FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1248,8 +1248,8 @@ gdk_clipboard_set_content (GdkClipboard *clipboard,
|
||||
* Sets the clipboard to contain the value collected from the given varargs.
|
||||
*
|
||||
* Values should be passed the same way they are passed to other value
|
||||
* collecting APIs, such as [`method@GObject.Object.set`] or
|
||||
* [`func@GObject.signal_emit`].
|
||||
* collecting APIs, such as [method@GObject.Object.set] or
|
||||
* [func@GObject.signal_emit].
|
||||
*
|
||||
* ```c
|
||||
* gdk_clipboard_set (clipboard, GTK_TYPE_STRING, "Hello World");
|
||||
@@ -1263,7 +1263,7 @@ gdk_clipboard_set (GdkClipboard *clipboard,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
||||
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
|
||||
|
||||
va_start (args, type);
|
||||
|
||||
@@ -1528,7 +1528,8 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
|
||||
if (gdk_gl_context_get_use_es (context))
|
||||
{
|
||||
priv->has_unpack_subimage = epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
|
||||
priv->has_unpack_subimage = gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)) ||
|
||||
epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
|
||||
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -153,7 +153,7 @@ gdk_gl_texture_find_format (gboolean use_es,
|
||||
if (gdk_memory_format_alpha (format) != alpha)
|
||||
continue;
|
||||
|
||||
if (!gdk_memory_format_gl_format (format, use_es, gl_major, gl_minor, &q_internal_format, &q_format, &q_type, &q_swizzle))
|
||||
if (!gdk_memory_format_gl_format (format, use_es, gl_major, gl_minor, &q_internal_format, &q_format, &q_type, q_swizzle))
|
||||
continue;
|
||||
|
||||
if (q_format != gl_format || q_type != gl_type)
|
||||
@@ -188,7 +188,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
|
||||
FALSE,
|
||||
major, minor,
|
||||
&gl_internal_format,
|
||||
&gl_format, &gl_type, &gl_swizzle))
|
||||
&gl_format, &gl_type, gl_swizzle))
|
||||
{
|
||||
if (download->stride == expected_stride &&
|
||||
download->format == format)
|
||||
|
||||
@@ -739,12 +739,12 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
|
||||
guint *out_internal_format,
|
||||
guint *out_format,
|
||||
guint *out_type,
|
||||
GLint (*out_swizzle)[4])
|
||||
GLint out_swizzle[4])
|
||||
{
|
||||
*out_internal_format = memory_formats[format].gl.internal_format;
|
||||
*out_format = memory_formats[format].gl.format;
|
||||
*out_type = memory_formats[format].gl.type;
|
||||
memcpy (out_swizzle, &memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
|
||||
memcpy (out_swizzle, memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
|
||||
|
||||
if (gles)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ gboolean gdk_memory_format_gl_format (GdkMemoryFormat
|
||||
guint *out_internal_format,
|
||||
guint *out_format,
|
||||
guint *out_type,
|
||||
GLint (*out_gizzle)[4]);
|
||||
GLint out_gizzle[4]);
|
||||
|
||||
void gdk_memory_convert (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
|
||||
@@ -2857,7 +2857,10 @@ gdk_event_translate (MSG *msg,
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
switch (msg->wParam)
|
||||
/* From: https://learn.microsoft.com/en-us/windows/win32/menurc/wm-syscommand?redirectedfrom=MSDN
|
||||
* To obtain the correct result when testing the value of wParam,
|
||||
* an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator. */
|
||||
switch (msg->wParam & 0xFFF0)
|
||||
{
|
||||
case SC_MINIMIZE:
|
||||
case SC_RESTORE:
|
||||
@@ -2964,6 +2967,14 @@ gdk_event_translate (MSG *msg,
|
||||
windowpos = (WINDOWPOS *) msg->lParam;
|
||||
windowpos->cx = our_mmi.ptMaxSize.x;
|
||||
windowpos->cy = our_mmi.ptMaxSize.y;
|
||||
|
||||
if (!_gdk_win32_surface_lacks_wm_decorations (window) &&
|
||||
!(windowpos->flags & SWP_NOCLIENTSIZE) &&
|
||||
window->width == impl->next_layout.configured_width &&
|
||||
window->height == impl->next_layout.configured_height)
|
||||
{
|
||||
impl->inhibit_configure = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
impl->maximizing = FALSE;
|
||||
|
||||
@@ -1230,18 +1230,11 @@ get_effective_window_decorations (GdkSurface *window,
|
||||
|
||||
*decoration |= GDK_DECOR_MINIMIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
|
||||
{
|
||||
*decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
|
||||
*decoration |= GDK_DECOR_MINIMIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
|
||||
*decoration = GDK_DECOR_ALL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1456,7 +1456,7 @@ memory_format_gl_format (GdkMemoryFormat data_format,
|
||||
guint *gl_internalformat,
|
||||
guint *gl_format,
|
||||
guint *gl_type,
|
||||
GLint (*gl_swizzle)[4])
|
||||
GLint gl_swizzle[4])
|
||||
{
|
||||
GdkMemoryDepth depth;
|
||||
|
||||
@@ -1577,7 +1577,7 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type,
|
||||
&gl_swizzle);
|
||||
gl_swizzle);
|
||||
|
||||
gdk_texture_downloader_init (&downloader, texture);
|
||||
gdk_texture_downloader_set_format (&downloader, data_format);
|
||||
@@ -1595,8 +1595,7 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
|
||||
{
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data);
|
||||
}
|
||||
else if (stride % bpp == 0 &&
|
||||
(gdk_gl_context_check_version (self->context, NULL, "3.0") || gdk_gl_context_has_unpack_subimage (self->context)))
|
||||
else if (stride % bpp == 0 && gdk_gl_context_has_unpack_subimage (self->context))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
@@ -1684,7 +1683,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type,
|
||||
&gl_swizzle);
|
||||
gl_swizzle);
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ struct _GskContourClass
|
||||
GskContour * (* reverse) (const GskContour *contour);
|
||||
int (* get_winding) (const GskContour *contour,
|
||||
const graphene_point_t *point);
|
||||
gsize (* get_n_points) (const GskContour *contour);
|
||||
gboolean (* get_closest_point) (const GskContour *contour,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
@@ -76,6 +77,11 @@ struct _GskContourClass
|
||||
float (* get_curvature) (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
graphene_point_t *center);
|
||||
void (* add_segment) (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end);
|
||||
};
|
||||
|
||||
/* {{{ Utilities */
|
||||
@@ -399,6 +405,14 @@ gsk_standard_contour_get_winding (const GskContour *contour,
|
||||
return winding;
|
||||
}
|
||||
|
||||
static gsize
|
||||
gsk_standard_contour_get_n_points (const GskContour *contour)
|
||||
{
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
|
||||
return self->n_ops;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_standard_contour_get_closest_point (const GskContour *contour,
|
||||
const graphene_point_t *point,
|
||||
@@ -420,8 +434,8 @@ gsk_standard_contour_get_closest_point (const GskContour *contour,
|
||||
if (dist <= threshold)
|
||||
{
|
||||
*out_dist = dist;
|
||||
result->data.std.idx = 0;
|
||||
result->data.std.t = 0;
|
||||
result->idx = 0;
|
||||
result->t = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -437,7 +451,8 @@ gsk_standard_contour_get_closest_point (const GskContour *contour,
|
||||
continue;
|
||||
|
||||
gsk_curve_init (&c, self->ops[i]);
|
||||
if (gsk_curve_get_closest_point (&c, point, threshold, &distance, &t))
|
||||
if (gsk_curve_get_closest_point (&c, point, threshold, &distance, &t) &&
|
||||
distance < threshold)
|
||||
{
|
||||
best_idx = i;
|
||||
best_t = t;
|
||||
@@ -448,8 +463,8 @@ gsk_standard_contour_get_closest_point (const GskContour *contour,
|
||||
if (best_idx != G_MAXUINT)
|
||||
{
|
||||
*out_dist = threshold;
|
||||
result->data.std.idx = best_idx;
|
||||
result->data.std.t = best_t;
|
||||
result->idx = best_idx;
|
||||
result->t = best_t;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -464,14 +479,14 @@ gsk_standard_contour_get_position (const GskContour *contour,
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
GskCurve curve;
|
||||
|
||||
if (G_UNLIKELY (point->data.std.idx == 0))
|
||||
if (G_UNLIKELY (point->idx == 0))
|
||||
{
|
||||
*position = self->points[0];
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_curve_init (&curve, self->ops[point->data.std.idx]);
|
||||
gsk_curve_get_point (&curve, point->data.std.t, position);
|
||||
gsk_curve_init (&curve, self->ops[point->idx]);
|
||||
gsk_curve_get_point (&curve, point->t, position);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -485,19 +500,19 @@ gsk_standard_contour_get_tangent (const GskContour *contour,
|
||||
gsize idx;
|
||||
float t;
|
||||
|
||||
if (G_UNLIKELY (point->data.std.idx == 0))
|
||||
if (G_UNLIKELY (point->idx == 0))
|
||||
{
|
||||
graphene_vec2_init (tangent, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
idx = point->data.std.idx;
|
||||
t = point->data.std.t;
|
||||
idx = point->idx;
|
||||
t = point->t;
|
||||
|
||||
if (t == 0 && direction == GSK_PATH_START)
|
||||
{
|
||||
/* Look at the previous segment */
|
||||
if (idx > 0)
|
||||
if (idx > 1)
|
||||
{
|
||||
idx--;
|
||||
t = 1;
|
||||
@@ -518,7 +533,7 @@ gsk_standard_contour_get_tangent (const GskContour *contour,
|
||||
}
|
||||
else if (self->flags & GSK_PATH_CLOSED)
|
||||
{
|
||||
idx = 0;
|
||||
idx = 1;
|
||||
t = 0;
|
||||
}
|
||||
}
|
||||
@@ -535,11 +550,76 @@ gsk_standard_contour_get_curvature (const GskContour *contour,
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
GskCurve curve;
|
||||
|
||||
if (G_UNLIKELY (point->data.std.idx == 0))
|
||||
if (G_UNLIKELY (point->idx == 0))
|
||||
return 0;
|
||||
|
||||
gsk_curve_init (&curve, self->ops[point->data.std.idx]);
|
||||
return gsk_curve_get_curvature (&curve, point->data.std.t, center);
|
||||
gsk_curve_init (&curve, self->ops[point->idx]);
|
||||
return gsk_curve_get_curvature (&curve, point->t, center);
|
||||
}
|
||||
|
||||
static void
|
||||
add_curve (GskCurve *curve,
|
||||
GskPathBuilder *builder,
|
||||
gboolean *emit_move_to)
|
||||
{
|
||||
if (*emit_move_to)
|
||||
{
|
||||
const graphene_point_t *s;
|
||||
|
||||
s = gsk_curve_get_start_point (curve);
|
||||
gsk_path_builder_move_to (builder, s->x, s->y);
|
||||
*emit_move_to = FALSE;
|
||||
}
|
||||
gsk_curve_builder_to (curve, builder);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_standard_contour_add_segment (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end)
|
||||
{
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
GskCurve c, c1, c2;
|
||||
|
||||
gsk_curve_init (&c, self->ops[start->idx]);
|
||||
|
||||
if (start->idx == end->idx)
|
||||
{
|
||||
gsk_curve_segment (&c, start->t, end->t, &c1);
|
||||
add_curve (&c1, builder, &emit_move_to);
|
||||
return;
|
||||
}
|
||||
if (start->t == 0)
|
||||
{
|
||||
add_curve (&c, builder, &emit_move_to);
|
||||
}
|
||||
else if (start->t < 1)
|
||||
{
|
||||
gsk_curve_split (&c, start->t, &c1, &c2);
|
||||
add_curve (&c2, builder, &emit_move_to);
|
||||
}
|
||||
|
||||
for (gsize i = start->idx + 1; i < end->idx; i++)
|
||||
{
|
||||
gsk_curve_init (&c, self->ops[i]);
|
||||
add_curve (&c, builder, &emit_move_to);
|
||||
}
|
||||
|
||||
gsk_curve_init (&c, self->ops[end->idx]);
|
||||
if (c.op == GSK_PATH_CLOSE)
|
||||
c.op = GSK_PATH_LINE;
|
||||
|
||||
if (end->t == 1)
|
||||
{
|
||||
add_curve (&c, builder, &emit_move_to);
|
||||
}
|
||||
else if (end->t > 0)
|
||||
{
|
||||
gsk_curve_split (&c, end->t, &c1, &c2);
|
||||
add_curve (&c1, builder, &emit_move_to);
|
||||
}
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
@@ -556,10 +636,12 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
gsk_standard_contour_foreach,
|
||||
gsk_standard_contour_reverse,
|
||||
gsk_standard_contour_get_winding,
|
||||
gsk_standard_contour_get_n_points,
|
||||
gsk_standard_contour_get_closest_point,
|
||||
gsk_standard_contour_get_position,
|
||||
gsk_standard_contour_get_tangent,
|
||||
gsk_standard_contour_get_curvature,
|
||||
gsk_standard_contour_add_segment,
|
||||
};
|
||||
|
||||
/* You must ensure the contour has enough size allocated,
|
||||
@@ -706,6 +788,12 @@ gsk_contour_get_closest_point (const GskContour *self,
|
||||
return self->klass->get_closest_point (self, point, threshold, result, out_dist);
|
||||
}
|
||||
|
||||
gsize
|
||||
gsk_contour_get_n_points (const GskContour *self)
|
||||
{
|
||||
return self->klass->get_n_points (self);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_contour_get_position (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
@@ -731,6 +819,16 @@ gsk_contour_get_curvature (const GskContour *self,
|
||||
return self->klass->get_curvature (self, point, center);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end)
|
||||
{
|
||||
self->klass->add_segment (self, builder, emit_move_to, start, end);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
||||
@@ -57,6 +57,7 @@ void gsk_contour_get_start_end (const GskContou
|
||||
graphene_point_t *end);
|
||||
int gsk_contour_get_winding (const GskContour *self,
|
||||
const graphene_point_t *point);
|
||||
gsize gsk_contour_get_n_points (const GskContour *self);
|
||||
gboolean gsk_contour_get_closest_point (const GskContour *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
@@ -72,5 +73,11 @@ void gsk_contour_get_tangent (const GskContou
|
||||
float gsk_contour_get_curvature (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
graphene_point_t *center);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
* Copyright 2016 Endless
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -42,8 +42,6 @@
|
||||
* @GSK_REPEAT_NODE: A node that repeats the child's contents
|
||||
* @GSK_CLIP_NODE: A node that clips its child to a rectangular area
|
||||
* @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
|
||||
* @GSK_FILL_NODE: A node that fills a path
|
||||
* @GSK_STROKE_NODE: A node that strokes a path
|
||||
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
|
||||
* @GSK_BLEND_NODE: A node that blends two children together
|
||||
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
|
||||
@@ -53,7 +51,9 @@
|
||||
* @GSK_GL_SHADER_NODE: A node that uses OpenGL fragment shaders to render
|
||||
* @GSK_TEXTURE_SCALE_NODE: A node drawing a `GdkTexture` scaled and filtered (Since: 4.10)
|
||||
* @GSK_MASK_NODE: A node that masks one child with another (Since: 4.10)
|
||||
|
||||
* @GSK_FILL_NODE: A node that fills a path
|
||||
* @GSK_STROKE_NODE: A node that strokes a path
|
||||
|
||||
* The type of a node determines what the node is rendering.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -76,8 +76,6 @@ typedef enum {
|
||||
GSK_REPEAT_NODE,
|
||||
GSK_CLIP_NODE,
|
||||
GSK_ROUNDED_CLIP_NODE,
|
||||
GSK_FILL_NODE,
|
||||
GSK_STROKE_NODE,
|
||||
GSK_SHADOW_NODE,
|
||||
GSK_BLEND_NODE,
|
||||
GSK_CROSS_FADE_NODE,
|
||||
@@ -86,7 +84,9 @@ typedef enum {
|
||||
GSK_DEBUG_NODE,
|
||||
GSK_GL_SHADER_NODE,
|
||||
GSK_TEXTURE_SCALE_NODE,
|
||||
GSK_MASK_NODE
|
||||
GSK_MASK_NODE,
|
||||
GSK_FILL_NODE,
|
||||
GSK_STROKE_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
@@ -220,6 +220,11 @@ typedef enum {
|
||||
*
|
||||
* The default line cap style is `GSK_LINE_CAP_BUTT`.
|
||||
*
|
||||
* <picture>
|
||||
* <source srcset="caps-dark.png" media="(prefers-color-scheme: dark)">
|
||||
* <img alt="Line Cap Styles" src="caps-light.png">
|
||||
* </picture>
|
||||
*
|
||||
* New entries may be added in future versions.
|
||||
*
|
||||
* Since: 4.14
|
||||
@@ -242,6 +247,11 @@ typedef enum {
|
||||
*
|
||||
* The default line join style is `GSK_LINE_JOIN_MITER`.
|
||||
*
|
||||
* <picture>
|
||||
* <source srcset="join-dark.png" media="(prefers-color-scheme: dark)">
|
||||
* <img alt="Line Join Styles" src="join-light.png">
|
||||
* </picture>
|
||||
*
|
||||
* New entries may be added in future versions.
|
||||
*
|
||||
* Since: 4.14
|
||||
|
||||
@@ -30,18 +30,26 @@
|
||||
* GskPath:
|
||||
*
|
||||
* A `GskPath` describes lines and curves that are more complex
|
||||
* than simple rectangles. Paths can used for rendering (filling or
|
||||
* stroking) and for animations (e.g. as trajectories).
|
||||
* than simple rectangles.
|
||||
*
|
||||
* Paths can used for rendering (filling or stroking) and for animations
|
||||
* (e.g. as trajectories).
|
||||
*
|
||||
* `GskPath` is an immutable, opaque, reference-counted struct.
|
||||
* After creation, you cannot change the types it represents.
|
||||
* Instead, new `GskPath` objects have to be created.
|
||||
*
|
||||
* The [struct@Gsk.PathBuilder] structure is meant to help in this endeavor.
|
||||
* After creation, you cannot change the types it represents. Instead,
|
||||
* new `GskPath` objects have to be created. The [struct@Gsk.PathBuilder]
|
||||
* structure is meant to help in this endeavor.
|
||||
*
|
||||
* Conceptually, a path consists of zero or more contours (continous, connected
|
||||
* curves), each of which may or may not be closed. Contours are typically
|
||||
* constructed from Bézier segments.
|
||||
*
|
||||
* <picture>
|
||||
* <source srcset="path-dark.png" media="(prefers-color-scheme: dark)">
|
||||
* <img alt="A Path" src="path-light.png">
|
||||
* </picture>
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
struct _GskPath
|
||||
@@ -420,6 +428,7 @@ gsk_path_get_bounds (GskPath *self,
|
||||
*
|
||||
* Returns: `TRUE` if the path has bounds, `FALSE` if the path is known
|
||||
* to be empty and have no bounds.
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_get_stroke_bounds (GskPath *self,
|
||||
@@ -490,6 +499,72 @@ gsk_path_in_fill (GskPath *self,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_start_point:
|
||||
* @self: a `GskPath`
|
||||
* @result: (out caller-allocates): return location for point
|
||||
*
|
||||
* Gets the start point of the path.
|
||||
*
|
||||
* An empty path has no points, so `FALSE`
|
||||
* is returned in this case.
|
||||
*
|
||||
* Returns: `TRUE` if @result was filled
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_get_start_point (GskPath *self,
|
||||
GskPathPoint *result)
|
||||
{
|
||||
GskRealPathPoint *res = (GskRealPathPoint *) result;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
if (self->n_contours == 0)
|
||||
return FALSE;
|
||||
|
||||
res->contour = 0;
|
||||
res->idx = 1;
|
||||
res->t = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_end_point:
|
||||
* @self: a `GskPath`
|
||||
* @result: (out caller-allocates): return location for point
|
||||
*
|
||||
* Gets the end point of the path.
|
||||
*
|
||||
* An empty path has no points, so `FALSE`
|
||||
* is returned in this case.
|
||||
*
|
||||
* Returns: `TRUE` if @result was filled
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_get_end_point (GskPath *self,
|
||||
GskPathPoint *result)
|
||||
{
|
||||
GskRealPathPoint *res = (GskRealPathPoint *) result;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
if (self->n_contours == 0)
|
||||
return FALSE;
|
||||
|
||||
res->contour = self->n_contours - 1;
|
||||
res->idx = gsk_contour_get_n_points (self->contours[self->n_contours - 1]) - 1;
|
||||
res->t = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_closest_point:
|
||||
* @self: a `GskPath`
|
||||
@@ -532,7 +607,6 @@ gsk_path_get_closest_point (GskPath *self,
|
||||
{
|
||||
found = TRUE;
|
||||
res->contour = i;
|
||||
res->path = self;
|
||||
threshold = distance;
|
||||
}
|
||||
}
|
||||
@@ -939,6 +1013,22 @@ parse_circle (const char **p,
|
||||
* [SVG path syntax](https://www.w3.org/TR/SVG11/paths.html#PathData),
|
||||
* as e.g. produced by [method@Gsk.Path.to_string].
|
||||
*
|
||||
* A high-level summary of the syntax:
|
||||
*
|
||||
* - `M x y` Move to `(x, y)`
|
||||
* - `L x y` Add a line from the current point to `(x, y)`
|
||||
* - `Q x1 y1 x2 y2` Add a quadratic Bézier from the current point to `(x2, y2)`, with control point `(x1, y1)`
|
||||
* - `C x1 y1 x2 y2 x3 y3` Add a cubic Bézier from the current point to `(x3, y3)`, with control points `(x1, y1)` and `(x2, y2)`
|
||||
* - `Z` Close the contour by drawing a line back to the start point
|
||||
* - `H x` Add a horizontal line from the current point to the given x value
|
||||
* - `V y` Add a vertical line from the current point to the given y value
|
||||
* - `T x2 y2` Add a quadratic Bézier, using the reflection of the previous segments' control point as control point
|
||||
* - `S x2 y2 x3 y3` Add a cubic Bézier, using the reflection of the previous segments' second control point as first control point
|
||||
* - `A rx ry r l s x y` Add an elliptical arc from the current point to `(x, y)` with radii rx and ry. See the SVG documentation for how the other parameters influence the arc.
|
||||
*
|
||||
* All the commands have lowercase variants that interpret coordinates
|
||||
* relative to the current point.
|
||||
*
|
||||
* Returns: (nullable): a new `GskPath`, or `NULL`
|
||||
* if @string could not be parsed
|
||||
*
|
||||
@@ -1323,3 +1413,95 @@ error:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_position:
|
||||
* @self: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @position: (out caller-allocates): Return location for
|
||||
* the coordinates of the point
|
||||
*
|
||||
* Gets the position of the point.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gsk_path_get_position (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *position)
|
||||
{
|
||||
GskRealPathPoint *p = (GskRealPathPoint *) point;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (point != NULL);
|
||||
g_return_if_fail (position != NULL);
|
||||
g_return_if_fail (p->contour < self->n_contours);
|
||||
|
||||
gsk_contour_get_position (self->contours[p->contour], p, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_tangent:
|
||||
* @self: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @direction: the direction for which to return the tangent
|
||||
* @tangent: (out caller-allocates): Return location for
|
||||
* the tangent at the point
|
||||
*
|
||||
* Gets the tangent of the path at the point.
|
||||
*
|
||||
* Note that certain points on a path may not have a single
|
||||
* tangent, such as sharp turns. At such points, there are
|
||||
* two tangents -- the direction of the path going into the
|
||||
* point, and the direction coming out of it. The @direction
|
||||
* argument lets you choose which one to get.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gsk_path_get_tangent (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
GskRealPathPoint *p = (GskRealPathPoint *) point;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (point != NULL);
|
||||
g_return_if_fail (tangent != NULL);
|
||||
g_return_if_fail (p->contour < self->n_contours);
|
||||
|
||||
gsk_contour_get_tangent (self->contours[p->contour], p, direction, tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_get_curvature:
|
||||
* @self: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @center: (out caller-allocates) (nullable): Return location for
|
||||
* the center of the osculating circle
|
||||
*
|
||||
* Calculates the curvature of the path at the point.
|
||||
*
|
||||
* Optionally, returns the center of the osculating circle as well.
|
||||
*
|
||||
* If the curvature is infinite (at line segments), zero is returned,
|
||||
* and @center is not modified.
|
||||
*
|
||||
* Returns: The curvature of the path at the given point
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
float
|
||||
gsk_path_get_curvature (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *center)
|
||||
{
|
||||
GskRealPathPoint *p = (GskRealPathPoint *) point;
|
||||
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
g_return_val_if_fail (point != NULL, 0);
|
||||
g_return_val_if_fail (p->contour < self->n_contours, 0);
|
||||
|
||||
return gsk_contour_get_curvature (self->contours[p->contour], p, center);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ G_BEGIN_DECLS
|
||||
* By default, [method@Gsk.Path.foreach] will only emit a path with all operations
|
||||
* flattened to straight lines to allow for maximum compatibility. The only
|
||||
* operations emitted will be `GSK_PATH_MOVE`, `GSK_PATH_LINE` and `GSK_PATH_CLOSE`.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
@@ -110,12 +112,35 @@ gboolean gsk_path_in_fill (GskPath
|
||||
const graphene_point_t *point,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_get_start_point (GskPath *self,
|
||||
GskPathPoint *result);
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_get_end_point (GskPath *self,
|
||||
GskPathPoint *result);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_get_closest_point (GskPath *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
GskPathPoint *result);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_get_position (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *position);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_get_tangent (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
float gsk_path_get_curvature (GskPath *self,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *center);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_foreach (GskPath *self,
|
||||
GskPathForeachFlags flags,
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
* either common shapes like [method@Gsk.PathBuilder.add_circle]
|
||||
* or by adding from other paths like [method@Gsk.PathBuilder.add_path].
|
||||
*
|
||||
* The `gsk_path_builder_add_*` methods always add complete contours,
|
||||
* and do not use or modify the current point.
|
||||
*
|
||||
* The other option is to define each line and curve manually with
|
||||
* the `gsk_path_builder_*_to` group of functions. You start with
|
||||
* a call to [method@Gsk.PathBuilder.move_to] to set the starting point
|
||||
@@ -63,6 +66,8 @@
|
||||
* back with a line to the starting point.
|
||||
*
|
||||
* This is similar for how paths are drawn in Cairo.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
struct _GskPathBuilder
|
||||
@@ -388,9 +393,13 @@ void
|
||||
gsk_path_builder_add_cairo_path (GskPathBuilder *self,
|
||||
const cairo_path_t *path)
|
||||
{
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (path != NULL);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
for (gsize i = 0; i < path->num_data; i += path->data[i].header.length)
|
||||
{
|
||||
const cairo_path_data_t *data = &path->data[i];
|
||||
@@ -421,6 +430,9 @@ gsk_path_builder_add_cairo_path (GskPathBuilder *self,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gsk_path_builder_end_current (self);
|
||||
self->current_point = current;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,8 +454,12 @@ void
|
||||
gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
gsk_path_builder_move_to (self, rect->origin.x, rect->origin.y);
|
||||
|
||||
gsk_path_builder_rel_line_to (self, rect->size.width, 0);
|
||||
@@ -451,6 +467,79 @@ gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
gsk_path_builder_rel_line_to (self, - rect->size.width, 0);
|
||||
|
||||
gsk_path_builder_close (self);
|
||||
self->current_point = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_rounded_rect:
|
||||
* @self: a #GskPathBuilder
|
||||
* @rect: the rounded rect
|
||||
*
|
||||
* Adds @rect as a new contour to the path built in @self.
|
||||
*
|
||||
* Since: 4.14
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
|
||||
const GskRoundedRect *rect)
|
||||
{
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (rect != NULL);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
gsk_path_builder_move_to (self,
|
||||
rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* top */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_TOP_RIGHT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* topright corner */
|
||||
gsk_path_builder_svg_arc_to (self,
|
||||
rect->corner[GSK_CORNER_TOP_RIGHT].width,
|
||||
rect->corner[GSK_CORNER_TOP_RIGHT].height,
|
||||
0, FALSE, TRUE,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_RIGHT].height);
|
||||
/* right */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_RIGHT].height);
|
||||
/* bottomright corner */
|
||||
gsk_path_builder_svg_arc_to (self,
|
||||
rect->corner[GSK_CORNER_BOTTOM_RIGHT].width,
|
||||
rect->corner[GSK_CORNER_BOTTOM_RIGHT].height,
|
||||
0, FALSE, TRUE,
|
||||
rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_BOTTOM_RIGHT].width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height);
|
||||
/* bottom */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->corner[GSK_CORNER_BOTTOM_LEFT].width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height);
|
||||
/* bottomleft corner */
|
||||
gsk_path_builder_svg_arc_to (self,
|
||||
rect->corner[GSK_CORNER_BOTTOM_LEFT].width,
|
||||
rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
|
||||
0, FALSE, TRUE,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_LEFT].height);
|
||||
/* left */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_LEFT].height);
|
||||
/* topleft corner */
|
||||
gsk_path_builder_svg_arc_to (self,
|
||||
rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->corner[GSK_CORNER_TOP_LEFT].height,
|
||||
0, FALSE, TRUE,
|
||||
rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* done */
|
||||
gsk_path_builder_close (self);
|
||||
self->current_point = current;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -482,16 +571,22 @@ gsk_path_builder_add_circle (GskPathBuilder *self,
|
||||
const graphene_point_t *center,
|
||||
float radius)
|
||||
{
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (center != NULL);
|
||||
g_return_if_fail (radius > 0);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
gsk_path_builder_move_to (self, center->x + radius, center->y);
|
||||
gsk_spline_decompose_arc (center, radius,
|
||||
GSK_PATH_TOLERANCE_DEFAULT,
|
||||
0, 2 * M_PI,
|
||||
circle_contour_curve, self);
|
||||
|
||||
gsk_path_builder_close (self);
|
||||
self->current_point = current;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -983,3 +1078,81 @@ gsk_path_builder_add_layout (GskPathBuilder *self,
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_segment:
|
||||
* @self: a `GskPathBuilder`
|
||||
* @path: the `GskPath` to take the segment to
|
||||
* @start: the point on @path to start at
|
||||
* @end: the point on @path to end at
|
||||
*
|
||||
* Adds to @self the segment of @path from @start to @end.
|
||||
*
|
||||
* If @start is equal to or after @end, the path will first add the
|
||||
* segment from @start to the end of the path, and then add the segment
|
||||
* from the beginning to @end. If the path is closed, these segments
|
||||
* will be connected.
|
||||
*
|
||||
* Note that this method always adds a path with the given start point
|
||||
* and end point. To add a closed path, use [method@Gsk.PathBuilder.add_path].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gsk_path_builder_add_segment (GskPathBuilder *self,
|
||||
GskPath *path,
|
||||
const GskPathPoint *start,
|
||||
const GskPathPoint *end)
|
||||
{
|
||||
GskRealPathPoint *s = (GskRealPathPoint *) start;
|
||||
GskRealPathPoint *e = (GskRealPathPoint *) end;
|
||||
const GskContour *contour;
|
||||
gsize n_contours = gsk_path_get_n_contours (path);
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (path != NULL);
|
||||
g_return_if_fail (start != NULL);
|
||||
g_return_if_fail (end != NULL);
|
||||
g_return_if_fail (s->contour < n_contours);
|
||||
g_return_if_fail (e->contour < n_contours);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
contour = gsk_path_get_contour (path, s->contour);
|
||||
|
||||
if (s->contour == e->contour)
|
||||
{
|
||||
if (gsk_path_point_compare (start, end) < 0)
|
||||
{
|
||||
gsk_contour_add_segment (contour, self, TRUE, s, e);
|
||||
goto out;
|
||||
}
|
||||
else if (n_contours == 1)
|
||||
{
|
||||
gsk_contour_add_segment (contour, self, TRUE,
|
||||
s,
|
||||
&(GskRealPathPoint) { s->contour, gsk_contour_get_n_points (contour) - 1, 1 });
|
||||
gsk_contour_add_segment (contour, self, FALSE,
|
||||
&(GskRealPathPoint) { s->contour, 1, 0 },
|
||||
e);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
gsk_contour_add_segment (contour, self, TRUE,
|
||||
s,
|
||||
&(GskRealPathPoint) { s->contour, gsk_contour_get_n_points (contour) - 1, 1 });
|
||||
|
||||
for (gsize i = (s->contour + 1) % n_contours; i != e->contour; i = (i + 1) % n_contours)
|
||||
gsk_path_builder_add_contour (self, gsk_contour_dup (gsk_path_get_contour (path, i)));
|
||||
|
||||
contour = gsk_path_get_contour (path, e->contour);
|
||||
gsk_contour_add_segment (contour, self, FALSE,
|
||||
&(GskRealPathPoint) { e->contour, 1, 0 },
|
||||
e);
|
||||
|
||||
out:
|
||||
gsk_path_builder_end_current (self);
|
||||
self->current_point = current;
|
||||
}
|
||||
|
||||
@@ -65,10 +65,17 @@ GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
const graphene_rect_t *rect);
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
|
||||
const GskRoundedRect *rect);
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_builder_add_circle (GskPathBuilder *self,
|
||||
const graphene_point_t *center,
|
||||
float radius);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_builder_add_segment (GskPathBuilder *self,
|
||||
GskPath *path,
|
||||
const GskPathPoint *start,
|
||||
const GskPathPoint *end);
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_builder_move_to (GskPathBuilder *self,
|
||||
float x,
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
* don't a reference to the path object they are obtained from. It is the
|
||||
* callers responsibility to keep a reference to the path as long as the
|
||||
* `GskPathPoint` is used.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskPathPoint, gsk_path_point,
|
||||
@@ -65,91 +67,72 @@ gsk_path_point_free (GskPathPoint *point)
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_position:
|
||||
* @path: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @position: (out caller-allocates): Return location for
|
||||
* the coordinates of the point
|
||||
* gsk_path_point_equal:
|
||||
* @point1: a `GskPathPoint`
|
||||
* @point2: another `GskPathPoint`
|
||||
*
|
||||
* Gets the position of the point.
|
||||
* Returns whether the two path points refer to the same
|
||||
* location on all paths.
|
||||
*
|
||||
* Since: 4.14
|
||||
* Note that the start- and endpoint of a closed contour
|
||||
* will compare nonequal according to this definition.
|
||||
* Use [method@Gsk.Path.is_closed] to find out if the
|
||||
* start- and endpoint of a concrete path refer to the
|
||||
* same location.
|
||||
*
|
||||
* Return: `TRUE` if @point1 and @point2 are equal
|
||||
*/
|
||||
void
|
||||
gsk_path_point_get_position (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *position)
|
||||
gboolean
|
||||
gsk_path_point_equal (const GskPathPoint *point1,
|
||||
const GskPathPoint *point2)
|
||||
{
|
||||
GskRealPathPoint *self = (GskRealPathPoint *) point;
|
||||
const GskContour *contour = gsk_path_get_contour (path, self->contour);
|
||||
const GskRealPathPoint *p1 = (const GskRealPathPoint *) point1;
|
||||
const GskRealPathPoint *p2 = (const GskRealPathPoint *) point2;
|
||||
|
||||
g_return_if_fail (path == self->path);
|
||||
g_return_if_fail (contour != NULL);
|
||||
if (p1->contour == p2->contour)
|
||||
{
|
||||
if ((p1->idx == p2->idx && p1->t == p2->t) ||
|
||||
(p1->idx + 1 == p2->idx && p1->t == 1 && p2->t == 0) ||
|
||||
(p1->idx == p2->idx + 1 && p1->t == 0 && p2->t == 1))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gsk_contour_get_position (contour, self, position);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_tangent:
|
||||
* @path: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @direction: the direction for which to return the tangent
|
||||
* @tangent: (out caller-allocates): Return location for
|
||||
* the tangent at the point
|
||||
* gsk_path_point_compare:
|
||||
* @point1: a `GskPathPoint`
|
||||
* @point2: another `GskPathPoint`
|
||||
*
|
||||
* Gets the tangent of the path at the point.
|
||||
* Returns whether @point1 is before or after @point2.
|
||||
*
|
||||
* Note that certain points on a path may not have a single
|
||||
* tangent, such as sharp turns. At such points, there are
|
||||
* two tangents -- the direction of the path going into the
|
||||
* point, and the direction coming out of it. The @direction
|
||||
* argument lets you choose which one to get.
|
||||
*
|
||||
* Since: 4.14
|
||||
* Returns: -1 if @point1 is before @point2,
|
||||
* 1 if @point1 is after @point2,
|
||||
* 0 if they are equal
|
||||
*/
|
||||
void
|
||||
gsk_path_point_get_tangent (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
int
|
||||
gsk_path_point_compare (const GskPathPoint *point1,
|
||||
const GskPathPoint *point2)
|
||||
{
|
||||
GskRealPathPoint *self = (GskRealPathPoint *) point;
|
||||
const GskContour *contour = gsk_path_get_contour (path, self->contour);
|
||||
const GskRealPathPoint *p1 = (const GskRealPathPoint *) point1;
|
||||
const GskRealPathPoint *p2 = (const GskRealPathPoint *) point2;
|
||||
|
||||
g_return_if_fail (path == self->path);
|
||||
g_return_if_fail (contour != NULL);
|
||||
if (gsk_path_point_equal (point1, point2))
|
||||
return 0;
|
||||
|
||||
gsk_contour_get_tangent (contour, self, direction, tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_point_get_curvature:
|
||||
* @path: a `GskPath`
|
||||
* @point: a `GskPathPoint` on @path
|
||||
* @center: (out caller-allocates): Return location for
|
||||
* the center of the osculating circle
|
||||
*
|
||||
* Calculates the curvature of the path at the point.
|
||||
*
|
||||
* Optionally, returns the center of the osculating circle as well.
|
||||
*
|
||||
* If the curvature is infinite (at line segments), zero is returned,
|
||||
* and @center is not modified.
|
||||
*
|
||||
* Returns: The curvature of the path at the given point
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
float
|
||||
gsk_path_point_get_curvature (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *center)
|
||||
{
|
||||
GskRealPathPoint *self = (GskRealPathPoint *) point;
|
||||
const GskContour *contour = gsk_path_get_contour (path, self->contour);
|
||||
|
||||
g_return_val_if_fail (path == self->path, 0);
|
||||
g_return_val_if_fail (contour != NULL, 0);
|
||||
|
||||
return gsk_contour_get_curvature (contour, self, center);
|
||||
if (p1->contour < p2->contour)
|
||||
return -1;
|
||||
else if (p1->contour > p2->contour)
|
||||
return 1;
|
||||
else if (p1->idx < p2->idx)
|
||||
return -1;
|
||||
else if (p1->idx > p2->idx)
|
||||
return 1;
|
||||
else if (p1->t < p2->t)
|
||||
return -1;
|
||||
else if (p1->t > p2->t)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -49,19 +49,11 @@ GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_point_free (GskPathPoint *point);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_point_get_position (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *position);
|
||||
gboolean gsk_path_point_equal (const GskPathPoint *point1,
|
||||
const GskPathPoint *point2);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gsk_path_point_get_tangent (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
float gsk_path_point_get_curvature (GskPath *path,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *center);
|
||||
int gsk_path_point_compare (const GskPathPoint *point1,
|
||||
const GskPathPoint *point2);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -7,15 +7,9 @@ G_BEGIN_DECLS
|
||||
|
||||
struct _GskRealPathPoint
|
||||
{
|
||||
GskPath *path;
|
||||
gsize contour;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int idx;
|
||||
float t;
|
||||
} std;
|
||||
} data;
|
||||
gsize idx;
|
||||
float t;
|
||||
};
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GskRealPathPoint) <= sizeof (GskPathPoint));
|
||||
|
||||
@@ -35,7 +35,6 @@ G_BEGIN_DECLS
|
||||
|
||||
#define GSK_SERIALIZATION_ERROR (gsk_serialization_error_quark ())
|
||||
|
||||
typedef struct _GskRenderNode GskRenderNode;
|
||||
typedef struct _GskColorStop GskColorStop;
|
||||
typedef struct _GskShadow GskShadow;
|
||||
|
||||
|
||||
@@ -3970,7 +3970,7 @@ gsk_repeat_node_draw (GskRenderNode *node,
|
||||
scale_x *= width / self->child_bounds.size.width;
|
||||
scale_y *= height / self->child_bounds.size.height;
|
||||
cairo_surface_set_device_scale (surface, scale_x, scale_y);
|
||||
cairo_surface_set_device_offset (surface,
|
||||
cairo_surface_set_device_offset (surface,
|
||||
- self->child_bounds.origin.x * scale_x,
|
||||
- self->child_bounds.origin.y * scale_y);
|
||||
|
||||
@@ -4141,7 +4141,7 @@ gsk_clip_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gsk_clip_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
@@ -4372,6 +4372,15 @@ gsk_rounded_clip_node_get_clip (const GskRenderNode *node)
|
||||
/* }}} */
|
||||
/* {{{ GSK_FILL_NODE */
|
||||
|
||||
/**
|
||||
* GskFillNode:
|
||||
*
|
||||
* A render node filling the area given by [struct@Gsk.Path]
|
||||
* and [enum@Gsk.FillRule] with the child node.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
struct _GskFillNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
@@ -4572,6 +4581,15 @@ gsk_fill_node_get_fill_rule (const GskRenderNode *node)
|
||||
/* }}} */
|
||||
/* {{{ GSK_STROKE_NODE */
|
||||
|
||||
/**
|
||||
* GskStrokeNode:
|
||||
*
|
||||
* A render node that will fill the area determined by stroking the the given
|
||||
* [struct@Gsk.Path] using the [struct@Gsk.Stroke] attributes.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
struct _GskStrokeNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
@@ -4670,8 +4688,10 @@ gsk_stroke_node_class_init (gpointer g_class,
|
||||
* @path: (transfer none): The path describing the area to stroke
|
||||
* @stroke: (transfer none): The stroke attributes to use
|
||||
*
|
||||
* Creates a #GskRenderNode that will stroke the @child along the given
|
||||
* @path using the attributes defined in @stroke.
|
||||
* Creates a #GskRenderNode that will fill the outline generated by stroking
|
||||
* the given @path using the attributes defined in @stroke.
|
||||
*
|
||||
* The area is filled with @child.
|
||||
*
|
||||
* Returns: (transfer none) (type GskStrokeNode): A new #GskRenderNode
|
||||
*
|
||||
|
||||
@@ -14,7 +14,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
|
||||
* We don't add an "n-types" value to avoid having to handle
|
||||
* it in every single switch.
|
||||
*/
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_MASK_NODE + 1)
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_STROKE_NODE + 1)
|
||||
|
||||
extern GType gsk_render_node_types[];
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
*
|
||||
* A `GskStroke` struct collects the parameters that influence
|
||||
* the operation of stroking a path.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskStroke, gsk_stroke, gsk_stroke_copy, gsk_stroke_free)
|
||||
|
||||
@@ -29,6 +29,7 @@ typedef struct _GskPath GskPath;
|
||||
typedef struct _GskPathBuilder GskPathBuilder;
|
||||
typedef struct _GskPathPoint GskPathPoint;
|
||||
typedef struct _GskRenderer GskRenderer;
|
||||
typedef struct _GskRenderNode GskRenderNode;
|
||||
typedef struct _GskStroke GskStroke;
|
||||
typedef struct _GskTransform GskTransform;
|
||||
|
||||
|
||||
@@ -234,8 +234,8 @@
|
||||
* API as they come in. Usually `GtkCellArea` is only interested in
|
||||
* button events, however some customized derived areas can be implemented
|
||||
* who are interested in handling other events. Handling an event can
|
||||
* trigger the [`signal@Gtk.CellArea::focus-changed`] signal to fire; as well
|
||||
* as [`signal@Gtk.CellArea::add-editable`] in the case that an editable cell
|
||||
* trigger the [signal@Gtk.CellArea::focus-changed] signal to fire; as well
|
||||
* as [signal@Gtk.CellArea::add-editable] in the case that an editable cell
|
||||
* was clicked and needs to start editing. You can call
|
||||
* [method@Gtk.CellArea.stop_editing] at any time to cancel any cell editing
|
||||
* that is currently in progress.
|
||||
|
||||
@@ -1140,7 +1140,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
|
||||
* @column: (nullable): the `GtkTreeViewColumn` in which the activation occurred
|
||||
*
|
||||
* The "row-activated" signal is emitted when the method
|
||||
* [`method@Gtk.TreeView.row_activated`] is called.
|
||||
* [method@Gtk.TreeView.row_activated] is called.
|
||||
*
|
||||
* This signal is emitted when the user double-clicks a treeview row with the
|
||||
* [property@Gtk.TreeView:activate-on-single-click] property set to %FALSE,
|
||||
|
||||
@@ -937,13 +937,13 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
|
||||
if ((!alternative && priv->sort_order == GTK_SORT_ASCENDING) ||
|
||||
(alternative && priv->sort_order == GTK_SORT_DESCENDING))
|
||||
{
|
||||
gtk_widget_remove_css_class (arrow, "descending");
|
||||
gtk_widget_add_css_class (arrow, "ascending");
|
||||
gtk_widget_remove_css_class (arrow, "ascending");
|
||||
gtk_widget_add_css_class (arrow, "descending");
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_remove_css_class (arrow, "ascending");
|
||||
gtk_widget_add_css_class (arrow, "descending");
|
||||
gtk_widget_remove_css_class (arrow, "descending");
|
||||
gtk_widget_add_css_class (arrow, "ascending");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1798,6 +1798,8 @@ gtk_column_view_scroll_to_column (GtkColumnView *self,
|
||||
gtk_adjustment_get_page_size (self->hadjustment));
|
||||
|
||||
gtk_adjustment_set_value (self->hadjustment, new_value);
|
||||
|
||||
g_clear_pointer (&scroll_info, gtk_scroll_info_unref);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2214,9 +2216,14 @@ gtk_column_view_scroll_to (GtkColumnView *self,
|
||||
if (column && (flags & GTK_LIST_SCROLL_FOCUS))
|
||||
gtk_column_view_set_focus_column (self, column, FALSE);
|
||||
|
||||
gtk_list_view_scroll_to (self->listview, pos, flags, scroll);
|
||||
gtk_list_view_scroll_to (self->listview,
|
||||
pos,
|
||||
flags,
|
||||
scroll ? gtk_scroll_info_ref (scroll) : NULL);
|
||||
|
||||
if (column)
|
||||
gtk_column_view_scroll_to_column (self, column, scroll);
|
||||
else
|
||||
g_clear_pointer (&scroll, gtk_scroll_info_unref);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
* `GtkListHeader` is used by list widgets to represent the headers they
|
||||
* display.
|
||||
*
|
||||
* The `GtkListHeader`s are managed just like [class@gtk.ListItem]s via
|
||||
* their factory, but provide a different set of properties suitable for
|
||||
* managing the header instead of individual items.
|
||||
* `GtkListHeader` objects are managed just like [class@Gtk.ListItem]
|
||||
* objects via their factory, but provide a different set of properties suitable
|
||||
* for managing the header instead of individual items.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
/**
|
||||
* GtkListItem:
|
||||
*
|
||||
* `GtkListItem` is used by list widgets to represent items in a `GListModel`.
|
||||
* `GtkListItem` is used by list widgets to represent items in a
|
||||
* [iface@Gio.ListModel].
|
||||
*
|
||||
* The `GtkListItem`s are managed by the list widget (with its factory)
|
||||
* `GtkListItem` objects are managed by the list widget (with its factory)
|
||||
* and cannot be created by applications, but they need to be populated
|
||||
* by application code. This is done by calling [method@Gtk.ListItem.set_child].
|
||||
*
|
||||
* `GtkListItem`s exist in 2 stages:
|
||||
* `GtkListItem` objects exist in 2 stages:
|
||||
*
|
||||
* 1. The unbound stage where the listitem is not currently connected to
|
||||
* an item in the list. In that case, the [property@Gtk.ListItem:item]
|
||||
|
||||
@@ -1510,8 +1510,8 @@ gtk_menu_button_set_child (GtkMenuButton *menu_button,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkGizmoFocusFunc)gtk_widget_focus_self,
|
||||
(GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_self);
|
||||
(GtkGizmoFocusFunc)gtk_widget_focus_child,
|
||||
NULL);
|
||||
|
||||
gtk_widget_set_layout_manager (inner_widget, gtk_bin_layout_new ());
|
||||
gtk_widget_set_hexpand (inner_widget, TRUE);
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
/**
|
||||
* GtkOverlayLayout:
|
||||
*
|
||||
* `GtkOverlayLayout` is the layout manager used by `GtkOverlay`.
|
||||
* `GtkOverlayLayout` is the layout manager used by [class@Gtk.Overlay].
|
||||
*
|
||||
* It places widgets as overlays on top of the main child.
|
||||
*
|
||||
* This is not a reusable layout manager, since it expects its widget
|
||||
* to be a `GtkOverlay`. It only listed here so that its layout
|
||||
* to be a `GtkOverlay`. It is only listed here so that its layout
|
||||
* properties get documented.
|
||||
*/
|
||||
|
||||
|
||||
@@ -3977,9 +3977,11 @@ gtk_text_insert_at_cursor (GtkText *self,
|
||||
|
||||
if (priv->editable)
|
||||
{
|
||||
begin_change (self);
|
||||
gtk_text_reset_im_context (self);
|
||||
gtk_editable_insert_text (GTK_EDITABLE (self), str, -1, &pos);
|
||||
gtk_text_set_selection_bounds (self, pos, pos);
|
||||
end_change (self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3999,12 +4001,14 @@ gtk_text_delete_from_cursor (GtkText *self,
|
||||
return;
|
||||
}
|
||||
|
||||
begin_change (self);
|
||||
|
||||
if (priv->selection_bound != priv->current_pos)
|
||||
{
|
||||
gtk_text_delete_selection (self);
|
||||
gtk_text_schedule_im_reset (self);
|
||||
gtk_text_reset_im_context (self);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
@@ -4074,6 +4078,8 @@ gtk_text_delete_from_cursor (GtkText *self,
|
||||
gtk_text_reset_im_context (self);
|
||||
}
|
||||
|
||||
done:
|
||||
end_change (self);
|
||||
gtk_text_pend_cursor_blink (self);
|
||||
}
|
||||
|
||||
@@ -4089,12 +4095,14 @@ gtk_text_backspace (GtkText *self)
|
||||
return;
|
||||
}
|
||||
|
||||
begin_change (self);
|
||||
|
||||
if (priv->selection_bound != priv->current_pos)
|
||||
{
|
||||
gtk_text_delete_selection (self);
|
||||
gtk_text_schedule_im_reset (self);
|
||||
gtk_text_reset_im_context (self);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
prev_pos = gtk_text_move_logically (self, priv->current_pos, -1);
|
||||
@@ -4147,6 +4155,8 @@ gtk_text_backspace (GtkText *self)
|
||||
gtk_widget_error_bell (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
done:
|
||||
end_change (self);
|
||||
gtk_text_pend_cursor_blink (self);
|
||||
}
|
||||
|
||||
@@ -4191,7 +4201,11 @@ gtk_text_cut_clipboard (GtkText *self)
|
||||
if (priv->editable)
|
||||
{
|
||||
if (priv->selection_bound != priv->current_pos)
|
||||
gtk_text_delete_selection (self);
|
||||
{
|
||||
begin_change (self);
|
||||
gtk_text_delete_selection (self);
|
||||
end_change (self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4209,9 +4223,15 @@ gtk_text_paste_clipboard (GtkText *self)
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
if (priv->editable)
|
||||
gtk_text_paste (self, gtk_widget_get_clipboard (GTK_WIDGET (self)));
|
||||
{
|
||||
begin_change (self);
|
||||
gtk_text_paste (self, gtk_widget_get_clipboard (GTK_WIDGET (self)));
|
||||
end_change (self);
|
||||
}
|
||||
else
|
||||
gtk_widget_error_bell (GTK_WIDGET (self));
|
||||
{
|
||||
gtk_widget_error_bell (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
gtk_text_update_handles (self);
|
||||
}
|
||||
|
||||
@@ -744,5 +744,7 @@ gtk_viewport_scroll_to (GtkViewport *viewport,
|
||||
|
||||
gtk_adjustment_animate_to_value (viewport->adjustment[GTK_ORIENTATION_HORIZONTAL], x);
|
||||
gtk_adjustment_animate_to_value (viewport->adjustment[GTK_ORIENTATION_VERTICAL], y);
|
||||
|
||||
g_clear_pointer (&scroll, gtk_scroll_info_unref);
|
||||
}
|
||||
|
||||
|
||||
@@ -1312,10 +1312,22 @@ gtk_inspector_object_tree_select_object (GtkInspectorObjectTree *wt,
|
||||
GTK_LIST_SCROLL_SELECT | GTK_LIST_SCROLL_FOCUS,
|
||||
NULL);
|
||||
|
||||
g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object); // FIXME
|
||||
g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object);
|
||||
g_object_unref (row_item);
|
||||
}
|
||||
|
||||
static void
|
||||
on_selected_item (GtkSingleSelection *selection,
|
||||
GParamSpec *pspec,
|
||||
GtkInspectorObjectTree *wt)
|
||||
{
|
||||
GObject *selected = gtk_single_selection_get_selected_item (selection);
|
||||
GtkTreeListRow *row = GTK_TREE_LIST_ROW (selected);
|
||||
GObject *object = gtk_tree_list_row_get_item (row);
|
||||
g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object);
|
||||
g_object_unref (object);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_inspector_object_tree_set_display (GtkInspectorObjectTree *wt,
|
||||
GdkDisplay *display)
|
||||
@@ -1329,4 +1341,5 @@ gtk_inspector_object_tree_set_display (GtkInspectorObjectTree *wt,
|
||||
wt->priv->selection = gtk_single_selection_new (g_object_ref (G_LIST_MODEL (wt->priv->tree_model)));
|
||||
gtk_column_view_set_model (GTK_COLUMN_VIEW (wt->priv->list),
|
||||
GTK_SELECTION_MODEL (wt->priv->selection));
|
||||
g_signal_connect (wt->priv->selection, "notify::selected-item", G_CALLBACK (on_selected_item), wt);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkprintbackendprivate.h"
|
||||
#include "gtk/print/gtkprintbackendprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <cpdb/cpdb-frontend.h>
|
||||
#include <gtk/gtkprinterprivate.h>
|
||||
#include <gtk/print/gtkprinterprivate.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -43,4 +43,4 @@ void gtk_printer_cpdb_set_printer_obj (GtkPrinterCpdb
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PRINTER_CPDB_H__ */
|
||||
#endif /* __GTK_PRINTER_CPDB_H__ */
|
||||
|
||||
@@ -425,9 +425,15 @@ tools/gtk-builder-tool-screenshot.c
|
||||
tools/gtk-builder-tool-simplify.c
|
||||
tools/gtk-builder-tool-validate.c
|
||||
tools/gtk-launch.c
|
||||
tools/gtk-path-tool.c
|
||||
tools/gtk-path-tool-decompose.c
|
||||
tools/gtk-path-tool-info.c
|
||||
tools/gtk-path-tool-render.c
|
||||
tools/gtk-path-tool-show.c
|
||||
tools/gtk-path-tool-utils.c
|
||||
tools/gtk-rendernode-tool.c
|
||||
tools/gtk-rendernode-tool-info.c
|
||||
tools/gtk-rendernode-tool-show.c
|
||||
tools/gtk-rendernode-tool-render.c
|
||||
tools/gtk-rendernode-tool-show.c
|
||||
tools/gtk-rendernode-tool-utils.c
|
||||
tools/updateiconcache.c
|
||||
|
||||
@@ -423,33 +423,269 @@ test_foreach (void)
|
||||
}
|
||||
|
||||
/* Test the basics of the path point api */
|
||||
typedef struct _GskRealPathPoint GskRealPathPoint;
|
||||
struct _GskRealPathPoint
|
||||
{
|
||||
gsize contour;
|
||||
gsize idx;
|
||||
float t;
|
||||
};
|
||||
|
||||
static void
|
||||
test_path_point (void)
|
||||
{
|
||||
GskPath *path;
|
||||
GskPathPoint point;
|
||||
GskRealPathPoint *rp = (GskRealPathPoint *)&point;
|
||||
gboolean ret;
|
||||
graphene_point_t pos, center;
|
||||
graphene_vec2_t t1, t2, mx;
|
||||
float curvature;
|
||||
|
||||
path = gsk_path_parse ("M0,0L100,0L100,100L0,100Z");
|
||||
path = gsk_path_parse ("M 0 0 L 100 0 L 100 100 L 0 100 Z");
|
||||
|
||||
ret = gsk_path_get_start_point (path, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 1);
|
||||
g_assert_true (rp->t == 0);
|
||||
|
||||
ret = gsk_path_get_end_point (path, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 4);
|
||||
g_assert_true (rp->t == 1);
|
||||
|
||||
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
gsk_path_point_get_position (path, &point, &pos);
|
||||
gsk_path_point_get_tangent (path, &point, GSK_PATH_START, &t1);
|
||||
gsk_path_point_get_tangent (path, &point, GSK_PATH_END, &t2);
|
||||
curvature = gsk_path_point_get_curvature (path, &point, ¢er);
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 2);
|
||||
g_assert_true (rp->t == 1);
|
||||
|
||||
gsk_path_get_position (path, &point, &pos);
|
||||
gsk_path_get_tangent (path, &point, GSK_PATH_START, &t1);
|
||||
gsk_path_get_tangent (path, &point, GSK_PATH_END, &t2);
|
||||
curvature = gsk_path_get_curvature (path, &point, ¢er);
|
||||
|
||||
g_print ("%g %g\n", graphene_vec2_get_x (&t1), graphene_vec2_get_y (&t1));
|
||||
g_assert_true (graphene_point_equal (&pos, &GRAPHENE_POINT_INIT (100, 100)));
|
||||
g_assert_true (graphene_vec2_equal (&t1, graphene_vec2_y_axis ()));
|
||||
graphene_vec2_negate (graphene_vec2_x_axis (), &mx);
|
||||
g_assert_true (graphene_vec2_equal (&t2, &mx));
|
||||
g_assert_true (curvature == 0);
|
||||
|
||||
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (100, 50), INFINITY, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 2);
|
||||
g_assert_true (rp->t == 0.5);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
/* Test that gsk_path_builder_add_segment yields the expected results */
|
||||
static void
|
||||
test_path_segments (void)
|
||||
{
|
||||
struct {
|
||||
const char *path;
|
||||
graphene_point_t p1;
|
||||
graphene_point_t p2;
|
||||
const char *result;
|
||||
} tests[] = {
|
||||
{
|
||||
"M 0 0 L 100 0 L 50 50 Z",
|
||||
{ 100, 0 },
|
||||
{ 50, 50 },
|
||||
"M 100 0 L 50 50"
|
||||
},
|
||||
{
|
||||
"M 0 0 L 100 0 L 50 50 Z",
|
||||
{ 50, 0 },
|
||||
{ 70, 0 },
|
||||
"M 50 0 L 70 0"
|
||||
},
|
||||
{
|
||||
"M 0 0 L 100 0 L 50 50 Z",
|
||||
{ 70, 0 },
|
||||
{ 50, 0 },
|
||||
"M 70 0 L 100 0 L 50 50 L 0 0 L 50 0"
|
||||
},
|
||||
{
|
||||
"M 0 0 L 100 0 L 50 50 Z",
|
||||
{ 50, 0 },
|
||||
{ 50, 50 },
|
||||
"M 50 0 L 100 0 L 50 50"
|
||||
},
|
||||
{
|
||||
"M 0 0 L 100 0 L 50 50 Z",
|
||||
{ 100, 0 },
|
||||
{ 100, 0 },
|
||||
"M 100 0 L 50 50 L 0 0 L 100 0"
|
||||
}
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i < G_N_ELEMENTS (tests); i++)
|
||||
{
|
||||
GskPath *path;
|
||||
GskPathPoint p1, p2;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *result;
|
||||
char *str;
|
||||
|
||||
path = gsk_path_parse (tests[i].path);
|
||||
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p1, INFINITY, &p1));
|
||||
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p2, INFINITY, &p2));
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_segment (builder, path, &p1, &p2);
|
||||
result = gsk_path_builder_free_to_path (builder);
|
||||
str = gsk_path_to_string (result);
|
||||
|
||||
g_assert_cmpstr (str, ==, tests[i].result);
|
||||
|
||||
g_free (str);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_bad_in_fill (void)
|
||||
{
|
||||
GskPath *path;
|
||||
gboolean inside;
|
||||
|
||||
/* A fat Cantarell W */
|
||||
path = gsk_path_parse ("M -2 694 M 206.1748046875 704 L 390.9371337890625 704 L 551.1888427734375 99.5035400390625 L 473.0489501953125 99.5035400390625 L 649.1048583984375 704 L 828.965087890625 704 L 1028.3077392578125 10 L 857.8111572265625 10 L 710.0489501953125 621.251708984375 L 775.9720458984375 598.426513671875 L 614.5245361328125 14.0489501953125 L 430.2237548828125 14.0489501953125 L 278.6783447265625 602.230712890625 L 330.0909423828125 602.230712890625 L 195.88818359375 10 L 5.7342529296875 10 L 206.1748046875 704 Z");
|
||||
|
||||
/* The midpoint of the right foot of a fat Cantarell X */
|
||||
inside = gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (552.360107, 704.000000), GSK_FILL_RULE_WINDING);
|
||||
|
||||
g_assert_false (inside);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
/* Test that path_in_fill implicitly closes contours. I think this is wrong,
|
||||
* but it is what "everybody" does.
|
||||
*/
|
||||
static void
|
||||
test_unclosed_in_fill (void)
|
||||
{
|
||||
GskPath *path;
|
||||
|
||||
path = gsk_path_parse ("M 0 0 L 0 100 L 100 100 L 100 0 Z");
|
||||
g_assert_true (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (50, 50), GSK_FILL_RULE_WINDING));
|
||||
gsk_path_unref (path);
|
||||
|
||||
path = gsk_path_parse ("M 0 0 L 0 100 L 100 100 L 100 0");
|
||||
g_assert_true (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (50, 50), GSK_FILL_RULE_WINDING));
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
/* Test that all the gsk_path_builder_add methods close the current
|
||||
* contour in the end and do not change the current point.
|
||||
*/
|
||||
static void
|
||||
test_path_builder_add (void)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path, *path2;
|
||||
char *s;
|
||||
cairo_path_t *cpath;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
PangoLayout *layout;
|
||||
GskPathPoint point1, point2;
|
||||
|
||||
#define N_ADD_METHODS 8
|
||||
|
||||
path = gsk_path_parse ("M 10 10 L 100 100");
|
||||
|
||||
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (50, 50), INFINITY, &point1);
|
||||
gsk_path_get_end_point (path, &point2);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 100, 100);
|
||||
cr = cairo_create (surface);
|
||||
cairo_move_to (cr, 10, 10);
|
||||
cairo_line_to (cr, 20, 30);
|
||||
cpath = cairo_copy_path (cr);
|
||||
|
||||
layout = pango_cairo_create_layout (cr);
|
||||
pango_layout_set_text (layout, "ABC", -1);
|
||||
|
||||
for (unsigned int i = 0; i < N_ADD_METHODS; i++)
|
||||
{
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_move_to (builder, 123, 456);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
gsk_path_builder_add_path (builder, path);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gsk_path_builder_add_reverse_path (builder, path);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gsk_path_builder_add_segment (builder, path, &point1, &point2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gsk_path_builder_add_cairo_path (builder, cpath);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gsk_path_builder_add_layout (builder, layout);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (0, 0, 10, 10));
|
||||
break;
|
||||
|
||||
case 6:
|
||||
{
|
||||
GskRoundedRect rect;
|
||||
|
||||
gsk_rounded_rect_init (&rect,
|
||||
&GRAPHENE_RECT_INIT (0, 0, 100, 100),
|
||||
&GRAPHENE_SIZE_INIT (10, 20),
|
||||
&GRAPHENE_SIZE_INIT (20, 30),
|
||||
&GRAPHENE_SIZE_INIT (0, 0),
|
||||
&GRAPHENE_SIZE_INIT (10, 10));
|
||||
gsk_path_builder_add_rounded_rect (builder, &rect);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (0, 0), 10);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gsk_path_builder_rel_line_to (builder, 10, 0);
|
||||
path2 = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
s = gsk_path_to_string (path2);
|
||||
g_assert_true (g_str_has_prefix (s, "M 123 456"));
|
||||
g_assert_true (g_str_has_suffix (s, "M 123 456 L 133 456"));
|
||||
g_free (s);
|
||||
gsk_path_unref (path2);
|
||||
}
|
||||
|
||||
g_object_unref (layout);
|
||||
|
||||
cairo_path_destroy (cpath);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
@@ -463,6 +699,10 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/path/rect", test_rect_path);
|
||||
g_test_add_func ("/path/foreach", test_foreach);
|
||||
g_test_add_func ("/path/point", test_path_point);
|
||||
g_test_add_func ("/path/segments", test_path_segments);
|
||||
g_test_add_func ("/path/bad-in-fill", test_bad_in_fill);
|
||||
g_test_add_func ("/path/unclosed-in-fill", test_unclosed_in_fill);
|
||||
g_test_add_func ("/path/builder/add", test_path_builder_add);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -582,6 +582,166 @@ test_parse (void)
|
||||
}
|
||||
}
|
||||
|
||||
#define N_PATHS 3
|
||||
static void
|
||||
test_in_fill_union (void)
|
||||
{
|
||||
GskPath *path, *paths[N_PATHS];
|
||||
GskPathBuilder *builder;
|
||||
guint i, j, k;
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
for (k = 0; k < N_PATHS; k++)
|
||||
{
|
||||
paths[k] = create_random_path (G_MAXUINT);
|
||||
gsk_path_builder_add_path (builder, paths[k]);
|
||||
}
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
for (j = 0; j < 100; j++)
|
||||
{
|
||||
graphene_point_t test = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
|
||||
g_test_rand_double_range (-1000, 1000));
|
||||
GskFillRule fill_rule;
|
||||
|
||||
for (fill_rule = GSK_FILL_RULE_WINDING; fill_rule <= GSK_FILL_RULE_EVEN_ODD; fill_rule++)
|
||||
{
|
||||
guint n_in_fill = 0;
|
||||
gboolean in_fill;
|
||||
|
||||
for (k = 0; k < N_PATHS; k++)
|
||||
{
|
||||
if (gsk_path_in_fill (paths[k], &test, GSK_FILL_RULE_EVEN_ODD))
|
||||
n_in_fill++;
|
||||
}
|
||||
|
||||
in_fill = gsk_path_in_fill (path, &test, GSK_FILL_RULE_EVEN_ODD);
|
||||
switch (fill_rule)
|
||||
{
|
||||
case GSK_FILL_RULE_WINDING:
|
||||
if (n_in_fill == 0)
|
||||
g_assert_false (in_fill);
|
||||
else if (n_in_fill == 1)
|
||||
g_assert_true (in_fill);
|
||||
/* else we can't say anything because the winding rule doesn't give enough info */
|
||||
break;
|
||||
|
||||
case GSK_FILL_RULE_EVEN_ODD:
|
||||
g_assert_cmpint (in_fill, ==, n_in_fill & 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gsk_path_unref (path);
|
||||
|
||||
for (k = 0; k < N_PATHS; k++)
|
||||
gsk_path_unref (paths[k]);
|
||||
}
|
||||
}
|
||||
#undef N_PATHS
|
||||
|
||||
/* This is somewhat sucky because using foreach breaks up the contours
|
||||
* (like rects and circles) and replaces everything with the standard
|
||||
* contour.
|
||||
* But at least it extensively tests the standard contour.
|
||||
*/
|
||||
static gboolean
|
||||
rotate_path_cb (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathBuilder **builders = user_data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builders[0], pts[0].x, pts[0].y);
|
||||
gsk_path_builder_move_to (builders[1], pts[0].y, -pts[0].x);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (builders[0]);
|
||||
gsk_path_builder_close (builders[1]);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builders[0], pts[1].x, pts[1].y);
|
||||
gsk_path_builder_line_to (builders[1], pts[1].y, -pts[1].x);
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
gsk_path_builder_quad_to (builders[0], pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||||
gsk_path_builder_quad_to (builders[1], pts[1].y, -pts[1].x, pts[2].y, -pts[2].x);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
gsk_path_builder_cubic_to (builders[0], pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
|
||||
gsk_path_builder_cubic_to (builders[1], pts[1].y, -pts[1].x, pts[2].y, -pts[2].x, pts[3].y, -pts[3].x);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_in_fill_rotated (void)
|
||||
{
|
||||
GskPath *path;
|
||||
GskPathBuilder *builders[2];
|
||||
GskPath *paths[2];
|
||||
guint i, j;
|
||||
|
||||
#define N_FILL_RULES 2
|
||||
/* if this triggers, you added a new enum value to GskFillRule, so the define above needs
|
||||
* an update */
|
||||
g_assert_null (g_enum_get_value (g_type_class_ref (GSK_TYPE_FILL_RULE), N_FILL_RULES));
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
path = create_random_path (G_MAXUINT);
|
||||
builders[0] = gsk_path_builder_new ();
|
||||
builders[1] = gsk_path_builder_new ();
|
||||
/* Use -1 here because we want all the flags, even future additions */
|
||||
gsk_path_foreach (path, -1, rotate_path_cb, builders);
|
||||
gsk_path_unref (path);
|
||||
|
||||
paths[0] = gsk_path_builder_free_to_path (builders[0]);
|
||||
paths[1] = gsk_path_builder_free_to_path (builders[1]);
|
||||
|
||||
for (j = 0; j < 100; j++)
|
||||
{
|
||||
GskFillRule fill_rule = g_random_int_range (0, N_FILL_RULES);
|
||||
float x = g_test_rand_double_range (-1000, 1000);
|
||||
float y = g_test_rand_double_range (-1000, 1000);
|
||||
|
||||
g_assert_cmpint (gsk_path_in_fill (paths[0], &GRAPHENE_POINT_INIT (x, y), fill_rule),
|
||||
==,
|
||||
gsk_path_in_fill (paths[1], &GRAPHENE_POINT_INIT (y, -x), fill_rule));
|
||||
g_assert_cmpint (gsk_path_in_fill (paths[0], &GRAPHENE_POINT_INIT (y, x), fill_rule),
|
||||
==,
|
||||
gsk_path_in_fill (paths[1], &GRAPHENE_POINT_INIT (x, -y), fill_rule));
|
||||
}
|
||||
|
||||
gsk_path_unref (paths[0]);
|
||||
gsk_path_unref (paths[1]);
|
||||
}
|
||||
#undef N_FILL_RULES
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@@ -590,6 +750,8 @@ main (int argc,
|
||||
|
||||
g_test_add_func ("/path/create", test_create);
|
||||
g_test_add_func ("/path/parse", test_parse);
|
||||
g_test_add_func ("/path/in-fill-union", test_in_fill_union);
|
||||
g_test_add_func ("/path/in-fill-rotated", test_in_fill_rotated);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ test_calendar_set_day (void)
|
||||
|
||||
cal = gtk_calendar_new ();
|
||||
|
||||
tz = g_time_zone_new_identifier ("MET");
|
||||
tz = g_time_zone_new_identifier ("Europe/Brussels");
|
||||
g_assert_nonnull (tz);
|
||||
dt = g_date_time_new (tz, 1970, 3, 1, 0, 0, 0);
|
||||
g_assert_nonnull (dt);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
static gboolean
|
||||
foreach_cb (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathBuilder *builder = user_data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (builder);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_QUAD:
|
||||
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CUBIC:
|
||||
gsk_path_builder_cubic_to (builder, pts[1].x, pts[1].y,
|
||||
pts[2].x, pts[2].y,
|
||||
pts[3].x, pts[3].y);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
do_decompose (int *argc, const char ***argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean allow_quad = FALSE;
|
||||
gboolean allow_curve = FALSE;
|
||||
char **args = NULL;
|
||||
GOptionContext *context;
|
||||
GOptionEntry entries[] = {
|
||||
{ "allow-quad", 0, 0, G_OPTION_ARG_NONE, &allow_quad, N_("Allow quadratic Bézier curves"), NULL },
|
||||
{ "allow-cubic", 0, 0, G_OPTION_ARG_NONE, &allow_curve, N_("Allow cubic Bézier curves"), NULL },
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
|
||||
{ NULL, },
|
||||
};
|
||||
GskPathForeachFlags flags;
|
||||
GskPath *path, *result;
|
||||
GskPathBuilder *builder;
|
||||
|
||||
g_set_prgname ("gtk4-path-tool decompose");
|
||||
|
||||
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, _("Decompose 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]);
|
||||
|
||||
flags = 0;
|
||||
if (allow_quad)
|
||||
flags |= GSK_PATH_FOREACH_ALLOW_QUAD;
|
||||
if (allow_curve)
|
||||
flags |= GSK_PATH_FOREACH_ALLOW_CUBIC;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_foreach (path, flags, foreach_cb, builder);
|
||||
|
||||
result = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
void
|
||||
do_info (int *argc, const char ***argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char **args = NULL;
|
||||
GOptionContext *context;
|
||||
GOptionEntry entries[] = {
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
|
||||
{ NULL, },
|
||||
};
|
||||
GskPath *path;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
g_set_prgname ("gtk4-path-tool info");
|
||||
|
||||
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, _("Print information about 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]);
|
||||
|
||||
if (gsk_path_is_empty (path))
|
||||
g_print ("%s\n", _("Path is empty."));
|
||||
else
|
||||
{
|
||||
if (gsk_path_is_closed (path))
|
||||
g_print ("%s\n", _("Path is closed"));
|
||||
|
||||
if (gsk_path_get_bounds (path, &bounds))
|
||||
g_print ("%s: %g %g %g %g\n", _("Bounds"),
|
||||
bounds.origin.x, bounds.origin.y,
|
||||
bounds.size.width, bounds.size.height);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
|
||||
void
|
||||
do_render (int *argc,
|
||||
const char ***argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const char *fill = "winding";
|
||||
const char *fg_color = "black";
|
||||
const char *bg_color = "white";
|
||||
gboolean do_stroke = FALSE;
|
||||
double line_width = 1;
|
||||
const char *cap = "butt";
|
||||
const char *join = "miter";
|
||||
double miter_limit = 4;
|
||||
const char *dashes = NULL;
|
||||
double dash_offset = 0;
|
||||
const char *output_file = NULL;
|
||||
char **args = NULL;
|
||||
GOptionContext *context;
|
||||
const GOptionEntry entries[] = {
|
||||
{ "fill-rule", 0, 0, G_OPTION_ARG_STRING, &fill, N_("Fill rule (winding, even-odd)"), N_("VALUE") },
|
||||
{ "fg-color", 0, 0, G_OPTION_ARG_STRING, &fg_color, N_("Foreground color"), N_("COLOR") },
|
||||
{ "bg-color", 0, 0, G_OPTION_ARG_STRING, &bg_color, N_("Background color"), N_("COLOR") },
|
||||
{ "stroke", 0, 0, G_OPTION_ARG_NONE, &do_stroke, N_("Stroke the path instead of filling it"), NULL },
|
||||
{ "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") },
|
||||
{ "output", 0, 0, G_OPTION_ARG_FILENAME, &output_file, N_("The output file"), N_("FILE") },
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, NULL, N_("PATH") },
|
||||
{ NULL, }
|
||||
};
|
||||
GskPath *path;
|
||||
GskFillRule fill_rule;
|
||||
GdkRGBA fg, bg;
|
||||
graphene_rect_t bounds;
|
||||
GskRenderNode *fg_node, *nodes[2], *node;
|
||||
GdkSurface *surface;
|
||||
GskRenderer *renderer;
|
||||
GdkTexture *texture;
|
||||
const char *filename;
|
||||
GskLineCap line_cap;
|
||||
GskLineJoin line_join;
|
||||
GskStroke *stroke;
|
||||
|
||||
if (gdk_display_get_default () == NULL)
|
||||
{
|
||||
g_printerr ("%s\n", _("Could not initialize windowing system"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_set_prgname ("gtk4-path-tool render");
|
||||
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, _("Render the path to a png image."));
|
||||
|
||||
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 path specified"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (g_strv_length (args) > 1)
|
||||
{
|
||||
g_printerr ("%s\n", _("Can only render a single path"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
path = get_path (args[0]);
|
||||
|
||||
fill_rule = get_enum_value (GSK_TYPE_FILL_RULE, _("fill rule"), fill);
|
||||
get_color (&fg, fg_color);
|
||||
get_color (&bg, bg_color);
|
||||
|
||||
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);
|
||||
|
||||
if (do_stroke)
|
||||
gsk_path_get_stroke_bounds (path, stroke, &bounds);
|
||||
else
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
graphene_rect_inset (&bounds, -10, -10);
|
||||
|
||||
nodes[0] = gsk_color_node_new (&bg, &bounds);
|
||||
fg_node = gsk_color_node_new (&fg, &bounds);
|
||||
if (do_stroke)
|
||||
nodes[1] = gsk_stroke_node_new (fg_node, path, stroke);
|
||||
else
|
||||
nodes[1] = gsk_fill_node_new (fg_node, path, fill_rule);
|
||||
|
||||
node = gsk_container_node_new (nodes, 2);
|
||||
|
||||
gsk_render_node_unref (fg_node);
|
||||
gsk_render_node_unref (nodes[0]);
|
||||
gsk_render_node_unref (nodes[1]);
|
||||
|
||||
surface = gdk_surface_new_toplevel (gdk_display_get_default ());
|
||||
renderer = gsk_renderer_new_for_surface (surface);
|
||||
|
||||
texture = gsk_renderer_render_texture (renderer, node, &bounds);
|
||||
|
||||
filename = output_file ? output_file : "path.png";
|
||||
if (!gdk_texture_save_to_png (texture, filename))
|
||||
{
|
||||
char *msg = g_strdup_printf (_("Saving png to '%s' failed"), filename);
|
||||
g_printerr ("%s\n", msg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (output_file == NULL)
|
||||
{
|
||||
char *msg = g_strdup_printf (_("Output written to '%s'."), filename);
|
||||
g_print ("%s\n", msg);
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
g_object_unref (texture);
|
||||
gsk_renderer_unrealize (renderer);
|
||||
g_object_unref (renderer);
|
||||
g_object_unref (surface);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gsk_path_unref (path);
|
||||
|
||||
g_strfreev (args);
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
#include "path-view.h"
|
||||
|
||||
static void
|
||||
show_path_fill (GskPath *path,
|
||||
GskFillRule fill_rule,
|
||||
const GdkRGBA *fg_color,
|
||||
const GdkRGBA *bg_color)
|
||||
{
|
||||
GtkWidget *window, *sw, *child;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), _("Path Preview"));
|
||||
|
||||
// gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
child = path_view_new (path);
|
||||
g_object_set (child,
|
||||
"do-fill", TRUE,
|
||||
"fill-rule", fill_rule,
|
||||
"fg-color", fg_color,
|
||||
"bg-color", bg_color,
|
||||
NULL);
|
||||
gtk_widget_set_hexpand (child, TRUE);
|
||||
gtk_widget_set_vexpand (child, TRUE);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
show_path_stroke (GskPath *path,
|
||||
GskStroke *stroke,
|
||||
const GdkRGBA *fg_color,
|
||||
const GdkRGBA *bg_color)
|
||||
{
|
||||
GtkWidget *window, *sw, *child;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), _("Path Preview"));
|
||||
|
||||
// gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
child = path_view_new (path);
|
||||
g_object_set (child,
|
||||
"do-fill", FALSE,
|
||||
"stroke", stroke,
|
||||
"fg-color", fg_color,
|
||||
"bg-color", bg_color,
|
||||
NULL);
|
||||
gtk_widget_set_hexpand (child, TRUE);
|
||||
gtk_widget_set_vexpand (child, TRUE);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
do_show (int *argc,
|
||||
const char ***argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean do_stroke = FALSE;
|
||||
const char *fill = "winding";
|
||||
const char *fg_color = "black";
|
||||
const char *bg_color = "white";
|
||||
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;
|
||||
const GOptionEntry entries[] = {
|
||||
{ "fill-rule", 0, 0, G_OPTION_ARG_STRING, &fill, N_("Fill rule (winding, even-odd)"), N_("VALUE") },
|
||||
{ "fg-color", 0, 0, G_OPTION_ARG_STRING, &fg_color, N_("Foreground color"), N_("COLOR") },
|
||||
{ "bg-color", 0, 0, G_OPTION_ARG_STRING, &bg_color, N_("Background color"), N_("COLOR") },
|
||||
{ "stroke", 0, 0, G_OPTION_ARG_NONE, &do_stroke, N_("Stroke the path instead of filling it"), NULL },
|
||||
{ "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_STRING_ARRAY, &args, NULL, N_("PATH") },
|
||||
{ NULL, }
|
||||
};
|
||||
GskPath *path;
|
||||
GskFillRule fill_rule;
|
||||
GdkRGBA fg;
|
||||
GdkRGBA bg;
|
||||
GskLineCap line_cap;
|
||||
GskLineJoin line_join;
|
||||
GskStroke *stroke;
|
||||
|
||||
if (gdk_display_get_default () == NULL)
|
||||
{
|
||||
g_printerr ("%s\n", _("Could not initialize windowing system"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_set_prgname ("gtk4-path-tool show");
|
||||
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, _("Display the 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 path specified"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (g_strv_length (args) > 1)
|
||||
{
|
||||
g_printerr ("%s\n", _("Can only show a single path"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
path = get_path (args[0]);
|
||||
|
||||
fill_rule = get_enum_value (GSK_TYPE_FILL_RULE, _("fill rule"), fill);
|
||||
get_color (&fg, fg_color);
|
||||
get_color (&bg, bg_color);
|
||||
|
||||
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);
|
||||
|
||||
if (do_stroke)
|
||||
show_path_stroke (path, stroke, &fg, &bg);
|
||||
else
|
||||
show_path_fill (path, fill_rule, &fg, &bg);
|
||||
|
||||
gsk_path_unref (path);
|
||||
|
||||
g_strfreev (args);
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/gio.h>
|
||||
#ifdef G_OS_UNIX
|
||||
#include <gio/gunixinputstream.h>
|
||||
#endif
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
GskPath *
|
||||
get_path (const char *arg)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
gsize len;
|
||||
GError *error = NULL;
|
||||
GskPath *path;
|
||||
|
||||
if (arg[0] == '.' || arg[0] == '/')
|
||||
{
|
||||
if (!g_file_get_contents (arg, &buffer, &len, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
#ifdef G_OS_UNIX
|
||||
else if (strcmp (arg, "-") == 0)
|
||||
{
|
||||
GInputStream *in;
|
||||
GOutputStream *out;
|
||||
|
||||
in = g_unix_input_stream_new (0, FALSE);
|
||||
out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
|
||||
|
||||
if (g_output_stream_splice (out, in, 0, NULL, &error) < 0)
|
||||
{
|
||||
g_printerr (_("Failed to read from standard input: %s\n"), error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!g_output_stream_close (out, NULL, &error))
|
||||
{
|
||||
g_printerr (_("Error reading from standard input: %s\n"), error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
buffer = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
|
||||
|
||||
g_object_unref (out);
|
||||
g_object_unref (in);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
buffer = g_strdup (arg);
|
||||
|
||||
g_strstrip (buffer);
|
||||
|
||||
path = gsk_path_parse (buffer);
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
g_printerr (_("Failed to parse '%s' as path.\n"), arg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int
|
||||
get_enum_value (GType type,
|
||||
const char *type_nick,
|
||||
const char *str)
|
||||
{
|
||||
GEnumClass *class = g_type_class_ref (type);
|
||||
GEnumValue *value;
|
||||
int val;
|
||||
|
||||
value = g_enum_get_value_by_nick (class, str);
|
||||
if (value)
|
||||
val = value->value;
|
||||
else
|
||||
{
|
||||
GString *s;
|
||||
|
||||
s = g_string_new ("");
|
||||
g_string_append_printf (s, _("Failed to parse '%s' as %s."), str, type_nick);
|
||||
g_string_append (s, "\n");
|
||||
g_string_append (s, _("Possible values: "));
|
||||
|
||||
for (unsigned int i = 0; i < class->n_values; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, class->values[i].value_nick);
|
||||
}
|
||||
g_printerr ("%s\n", s->str);
|
||||
g_string_free (s, TRUE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_type_class_unref (class);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
get_color (GdkRGBA *rgba,
|
||||
const char *str)
|
||||
{
|
||||
if (!gdk_rgba_parse (rgba, str))
|
||||
{
|
||||
char *msg = g_strdup_printf (_("Could not parse '%s' as color"), str);
|
||||
g_printerr ("%s\n", msg);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-path-tool.h"
|
||||
|
||||
static void G_GNUC_NORETURN
|
||||
usage (void)
|
||||
{
|
||||
g_print (_("Usage:\n"
|
||||
" gtk4-path-tool [COMMAND] [OPTION…] PATH\n"
|
||||
"\n"
|
||||
"Perform various tasks on paths.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" decompose Decompose the path\n"
|
||||
" show Display the path in a window\n"
|
||||
" render Render the path as an image\n"
|
||||
" info Print information about the path\n"
|
||||
"\n"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* A simplified version of g_log_writer_default_would_drop(), to avoid
|
||||
* bumping up the required version of GLib to 2.68
|
||||
*/
|
||||
static gboolean
|
||||
would_drop (GLogLevelFlags level,
|
||||
const char *domain)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION (2, 68, 0)
|
||||
return g_log_writer_default_would_drop (level, domain);
|
||||
#else
|
||||
return (level & (G_LOG_LEVEL_ERROR |
|
||||
G_LOG_LEVEL_CRITICAL |
|
||||
G_LOG_LEVEL_WARNING)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static GLogWriterOutput
|
||||
log_writer_func (GLogLevelFlags level,
|
||||
const GLogField *fields,
|
||||
gsize n_fields,
|
||||
gpointer user_data)
|
||||
{
|
||||
gsize i;
|
||||
const char *domain = NULL;
|
||||
const char *message = NULL;
|
||||
|
||||
for (i = 0; i < n_fields; i++)
|
||||
{
|
||||
if (g_strcmp0 (fields[i].key, "GLIB_DOMAIN") == 0)
|
||||
domain = fields[i].value;
|
||||
else if (g_strcmp0 (fields[i].key, "MESSAGE") == 0)
|
||||
message = fields[i].value;
|
||||
}
|
||||
|
||||
if (message != NULL && !would_drop (level, domain))
|
||||
{
|
||||
const char *prefix;
|
||||
switch (level & G_LOG_LEVEL_MASK)
|
||||
{
|
||||
case G_LOG_LEVEL_ERROR:
|
||||
prefix = "ERROR";
|
||||
break;
|
||||
case G_LOG_LEVEL_CRITICAL:
|
||||
prefix = "CRITICAL";
|
||||
break;
|
||||
case G_LOG_LEVEL_WARNING:
|
||||
prefix = "WARNING";
|
||||
break;
|
||||
default:
|
||||
prefix = "INFO";
|
||||
break;
|
||||
}
|
||||
g_printerr ("%s-%s: %s\n", domain, prefix, message);
|
||||
}
|
||||
|
||||
return G_LOG_WRITER_HANDLED;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
g_set_prgname ("gtk4-path-tool");
|
||||
|
||||
g_log_set_writer_func (log_writer_func, NULL, NULL);
|
||||
|
||||
gtk_init_check ();
|
||||
|
||||
gtk_test_register_all_types ();
|
||||
|
||||
if (argc < 2)
|
||||
usage ();
|
||||
|
||||
if (strcmp (argv[1], "--help") == 0)
|
||||
usage ();
|
||||
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
if (strcmp (argv[0], "decompose") == 0)
|
||||
do_decompose (&argc, &argv);
|
||||
else if (strcmp (argv[0], "info") == 0)
|
||||
do_info (&argc, &argv);
|
||||
else if (strcmp (argv[0], "render") == 0)
|
||||
do_render (&argc, &argv);
|
||||
else if (strcmp (argv[0], "show") == 0)
|
||||
do_show (&argc, &argv);
|
||||
else
|
||||
usage ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
void do_info (int *argc, const char ***argv);
|
||||
void do_decompose (int *argc, const char ***argv);
|
||||
void do_render (int *argc, const char ***argv);
|
||||
void do_show (int *argc, const char ***argv);
|
||||
|
||||
GskPath *get_path (const char *arg);
|
||||
int get_enum_value (GType type,
|
||||
const char *type_nick,
|
||||
const char *str);
|
||||
void get_color (GdkRGBA *rgba,
|
||||
const char *str);
|
||||
@@ -23,6 +23,13 @@ if win32_enabled
|
||||
endif
|
||||
|
||||
gtk_tools = [
|
||||
['gtk4-path-tool', ['gtk-path-tool.c',
|
||||
'gtk-path-tool-decompose.c',
|
||||
'gtk-path-tool-info.c',
|
||||
'gtk-path-tool-render.c',
|
||||
'gtk-path-tool-show.c',
|
||||
'gtk-path-tool-utils.c',
|
||||
'path-view.c'], [libgtk_dep]],
|
||||
['gtk4-query-settings', ['gtk-query-settings.c'], [libgtk_dep]],
|
||||
['gtk4-builder-tool', ['gtk-builder-tool.c',
|
||||
'gtk-builder-tool-simplify.c',
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "path-view.h"
|
||||
|
||||
struct _PathView
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GskPath *path;
|
||||
GskStroke *stroke;
|
||||
graphene_rect_t bounds;
|
||||
GskFillRule fill_rule;
|
||||
GdkRGBA fg;
|
||||
GdkRGBA bg;
|
||||
int padding;
|
||||
gboolean do_fill;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_PATH = 1,
|
||||
PROP_DO_FILL,
|
||||
PROP_STROKE,
|
||||
PROP_FILL_RULE,
|
||||
PROP_FG_COLOR,
|
||||
PROP_BG_COLOR,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _PathViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PathView, path_view, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
path_view_init (PathView *self)
|
||||
{
|
||||
self->do_fill = TRUE;
|
||||
self->stroke = gsk_stroke_new (1);
|
||||
self->fill_rule = GSK_FILL_RULE_WINDING;
|
||||
self->fg = (GdkRGBA) { 0, 0, 0, 1};
|
||||
self->bg = (GdkRGBA) { 1, 1, 1, 1};
|
||||
self->padding = 10;
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_dispose (GObject *object)
|
||||
{
|
||||
PathView *self = PATH_VIEW (object);
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->stroke, gsk_stroke_free);
|
||||
|
||||
G_OBJECT_CLASS (path_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PathView *self = PATH_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_boxed (value, self->path);
|
||||
break;
|
||||
|
||||
case PROP_DO_FILL:
|
||||
g_value_set_boolean (value, self->do_fill);
|
||||
break;
|
||||
|
||||
case PROP_STROKE:
|
||||
g_value_set_boxed (value, self->stroke);
|
||||
break;
|
||||
|
||||
case PROP_FILL_RULE:
|
||||
g_value_set_enum (value, self->fill_rule);
|
||||
break;
|
||||
|
||||
case PROP_FG_COLOR:
|
||||
g_value_set_boxed (value, &self->fg);
|
||||
break;
|
||||
|
||||
case PROP_BG_COLOR:
|
||||
g_value_set_boxed (value, &self->bg);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_bounds (PathView *self)
|
||||
{
|
||||
if (self->do_fill)
|
||||
gsk_path_get_bounds (self->path, &self->bounds);
|
||||
else
|
||||
gsk_path_get_stroke_bounds (self->path, self->stroke, &self->bounds);
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PathView *self = PATH_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
|
||||
case PROP_PATH:
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
self->path = g_value_dup_boxed (value);
|
||||
update_bounds (self);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_DO_FILL:
|
||||
self->do_fill = g_value_get_boolean (value);
|
||||
update_bounds (self);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_STROKE:
|
||||
gsk_stroke_free (self->stroke);
|
||||
self->stroke = g_value_get_boxed (value);
|
||||
update_bounds (self);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_FILL_RULE:
|
||||
self->fill_rule = g_value_get_enum (value);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_FG_COLOR:
|
||||
self->fg = *(GdkRGBA *) g_value_get_boxed (value);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_BG_COLOR:
|
||||
self->bg = *(GdkRGBA *) g_value_get_boxed (value);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
PathView *self = PATH_VIEW (widget);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = (int) ceilf (self->bounds.size.width) + 2 * self->padding;
|
||||
else
|
||||
*minimum = *natural = (int) ceilf (self->bounds.size.height) + 2 * self->padding;
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
PathView *self = PATH_VIEW (widget);
|
||||
graphene_rect_t bounds = self->bounds;
|
||||
|
||||
graphene_rect_inset (&bounds, - self->padding, - self->padding);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_append_color (snapshot, &self->bg, &self->bounds);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (self->padding, self->padding));
|
||||
if (self->do_fill)
|
||||
gtk_snapshot_push_fill (snapshot, self->path, self->fill_rule);
|
||||
else
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, self->stroke);
|
||||
gtk_snapshot_append_color (snapshot, &self->fg, &self->bounds);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
path_view_class_init (PathViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = path_view_dispose;
|
||||
object_class->get_property = path_view_get_property;
|
||||
object_class->set_property = path_view_set_property;
|
||||
|
||||
widget_class->measure = path_view_measure;
|
||||
widget_class->snapshot = path_view_snapshot;
|
||||
|
||||
properties[PROP_PATH]
|
||||
= g_param_spec_boxed ("path", NULL, NULL,
|
||||
GSK_TYPE_PATH,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_DO_FILL]
|
||||
= g_param_spec_boolean ("do-fill", NULL, NULL,
|
||||
TRUE,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_STROKE]
|
||||
= g_param_spec_boxed ("stroke", NULL, NULL,
|
||||
GSK_TYPE_STROKE,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_FILL_RULE]
|
||||
= g_param_spec_enum ("fill-rule", NULL, NULL,
|
||||
GSK_TYPE_FILL_RULE,
|
||||
GSK_FILL_RULE_WINDING,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_FG_COLOR]
|
||||
= g_param_spec_boxed ("fg-color", NULL, NULL,
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_BG_COLOR]
|
||||
= g_param_spec_boxed ("bg-color", NULL, NULL,
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
path_view_new (GskPath *path)
|
||||
{
|
||||
return g_object_new (PATH_TYPE_VIEW,
|
||||
"path", path,
|
||||
NULL);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define PATH_TYPE_VIEW (path_view_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (PathView, path_view, PATH, VIEW, GtkWidget)
|
||||
|
||||
GtkWidget * path_view_new (GskPath *path);
|
||||