new installer work in progress
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M22 11V3h-7v3H9V3H2v8h7V8h2v10h4v3h7v-8h-7v3h-2V8h2v3z"/></svg>
|
After Width: | Height: | Size: 192 B |
|
@ -0,0 +1,59 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
version="1.1"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="ic_arrow_left_alt_24px.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="734"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="12"
|
||||||
|
inkscape:cy="12"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
d="M 7.99,13 H 20 V 11 H 7.99 V 8 L 4,12 7.99,16 Z"
|
||||||
|
id="path4"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M16.01 11H4v2h12.01v3L20 12l-3.99-4z"/></svg>
|
After Width: | Height: | Size: 174 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/></svg>
|
After Width: | Height: | Size: 368 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path clip-rule="evenodd" d="M0 0h24v24H0z" fill="none"/><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg>
|
After Width: | Height: | Size: 326 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M38 6H10c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4V10c0-2.21-1.79-4-4-4zM20 34L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z"/></svg>
|
After Width: | Height: | Size: 248 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M38 10v28H10V10h28m0-4H10c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4V10c0-2.21-1.79-4-4-4z"/></svg>
|
After Width: | Height: | Size: 209 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
After Width: | Height: | Size: 239 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M38 12.83L35.17 10 24 21.17 12.83 10 10 12.83 21.17 24 10 35.17 12.83 38 24 26.83 35.17 38 38 35.17 26.83 24z"/></svg>
|
After Width: | Height: | Size: 210 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"/></svg>
|
After Width: | Height: | Size: 318 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M6 34.5V42h7.5l22.13-22.13-7.5-7.5L6 34.5zm35.41-20.41c.78-.78.78-2.05 0-2.83l-4.67-4.67c-.78-.78-2.05-.78-2.83 0l-3.66 3.66 7.5 7.5 3.66-3.66z"/></svg>
|
After Width: | Height: | Size: 244 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M12 38c0 2.21 1.79 4 4 4h16c2.21 0 4-1.79 4-4V14H12v24zM38 8h-7l-2-2H19l-2 2h-7v4h28V8z"/></svg>
|
After Width: | Height: | Size: 188 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>
|
After Width: | Height: | Size: 264 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M18 32.34L9.66 24l-2.83 2.83L18 38l24-24-2.83-2.83z"/></svg>
|
After Width: | Height: | Size: 152 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M6 34.5V42h7.5l22.13-22.13-7.5-7.5L6 34.5zm35.41-20.41c.78-.78.78-2.05 0-2.83l-4.67-4.67c-.78-.78-2.05-.78-2.83 0l-3.66 3.66 7.5 7.5 3.66-3.66z"/></svg>
|
After Width: | Height: | Size: 244 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 4C12.96 4 4 12.95 4 24s8.96 20 20 20 20-8.95 20-20S35.04 4 24 4zm2 30h-4v-4h4v4zm0-8h-4V14h4v12z"/></svg>
|
After Width: | Height: | Size: 201 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>
|
After Width: | Height: | Size: 430 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z"/></svg>
|
After Width: | Height: | Size: 274 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>
|
After Width: | Height: | Size: 229 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M40 12H24l-4-4H8c-2.21 0-3.98 1.79-3.98 4L4 36c0 2.21 1.79 4 4 4h32c2.21 0 4-1.79 4-4V16c0-2.21-1.79-4-4-4zm0 24H8V16h32v20z"/></svg>
|
After Width: | Height: | Size: 225 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
|
After Width: | Height: | Size: 258 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"/></svg>
|
After Width: | Height: | Size: 194 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="17.59,18 19,16.59 14.42,12 19,7.41 17.59,6 11.59,12"/><polygon points="11,18 12.41,16.59 7.83,12 12.41,7.41 11,6 5,12"/></g></g></svg>
|
After Width: | Height: | Size: 323 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="6.41,6 5,7.41 9.58,12 5,16.59 6.41,18 12.41,12"/><polygon points="13,6 11.59,7.41 16.17,12 11.59,16.59 13,18 19,12"/></g></g></svg>
|
After Width: | Height: | Size: 320 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M3 3h18v2H3z"/></svg>
|
After Width: | Height: | Size: 152 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M6 19h12v2H6z"/></svg>
|
After Width: | Height: | Size: 153 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M30.83 14.83L28 12 16 24l12 12 2.83-2.83L21.66 24z"/></svg>
|
After Width: | Height: | Size: 151 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M20 12l-2.83 2.83L26.34 24l-9.17 9.17L20 36l12-12z"/></svg>
|
After Width: | Height: | Size: 151 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"/></svg>
|
After Width: | Height: | Size: 263 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
|
After Width: | Height: | Size: 268 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><rect fill="none" height="24" width="24" x="0" y="0"/><path d="M12,2C6.48,2,2,6.48,2,12c0,5.52,4.48,10,10,10s10-4.48,10-10C22,6.48,17.52,2,12,2z M13.88,11.54l-4.96,4.96l-1.41-1.41 l4.96-4.96L10.34,8l5.65,0.01L16,13.66L13.88,11.54z"/></svg>
|
After Width: | Height: | Size: 356 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M28 20H4v4h24v-4zm0-8H4v4h24v-4zm8 16v-8h-4v8h-8v4h8v8h4v-8h8v-4h-8zM4 32h16v-4H4v4z"/></svg>
|
After Width: | Height: | Size: 185 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g/><g><path d="M17,19.22H5V7h7V5H5C3.9,5,3,5.9,3,7v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-7h-2V19.22z"/><path d="M19,2h-2v3h-3c0.01,0.01,0,2,0,2h3v2.99c0.01,0.01,2,0,2,0V7h3V5h-3V2z"/><rect height="2" width="8" x="7" y="9"/><polygon points="7,12 7,14 15,14 15,12 12,12"/><rect height="2" width="8" x="7" y="15"/></g></g></svg>
|
After Width: | Height: | Size: 496 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><path d="M16,9V4l1,0c0.55,0,1-0.45,1-1v0c0-0.55-0.45-1-1-1H7C6.45,2,6,2.45,6,3v0 c0,0.55,0.45,1,1,1l1,0v5c0,1.66-1.34,3-3,3h0v2h5.97v7l1,1l1-1v-7H19v-2h0C17.34,12,16,10.66,16,9z" fill-rule="evenodd"/></g></svg>
|
After Width: | Height: | Size: 379 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M36.79 21.2C33.11 17.97 28.29 16 23 16c-9.3 0-17.17 6.06-19.92 14.44L7.81 32c2.1-6.39 8.1-11 15.19-11 3.91 0 7.46 1.44 10.23 3.77L26 32h18V14l-7.21 7.2z"/></svg>
|
After Width: | Height: | Size: 253 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
|
After Width: | Height: | Size: 340 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>
|
After Width: | Height: | Size: 280 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M6 10h4V6c-2.21 0-4 1.79-4 4zm0 16h4v-4H6v4zm8 16h4v-4h-4v4zM6 18h4v-4H6v4zM26 6h-4v4h4V6zm12 0v4h4c0-2.21-1.79-4-4-4zM10 42v-4H6c0 2.21 1.79 4 4 4zm-4-8h4v-4H6v4zM18 6h-4v4h4V6zm4 36h4v-4h-4v4zm16-16h4v-4h-4v4zm0 16c2.21 0 4-1.79 4-4h-4v4zm0-24h4v-4h-4v4zm0 16h4v-4h-4v4zm-8 8h4v-4h-4v4zm0-32h4V6h-4v4zM14 34h20V14H14v20zm4-16h12v12H18V18z"/></svg>
|
After Width: | Height: | Size: 441 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/><path d="M20.41,8.41l-4.83-4.83C15.21,3.21,14.7,3,14.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V9.83 C21,9.3,20.79,8.79,20.41,8.41z M7,7h7v2H7V7z M17,17H7v-2h10V17z M17,13H7v-2h10V13z"/></g></svg>
|
After Width: | Height: | Size: 376 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M25 16c-5.29 0-10.11 1.97-13.8 5.2L4 14v18h18l-7.23-7.23C17.54 22.44 21.09 21 25 21c7.09 0 13.09 4.61 15.19 11l4.73-1.56C42.17 22.06 34.3 16 25 16z"/></svg>
|
After Width: | Height: | Size: 248 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 9C14 9 5.46 15.22 2 24c3.46 8.78 12 15 22 15 10.01 0 18.54-6.22 22-15-3.46-8.78-11.99-15-22-15zm0 25c-5.52 0-10-4.48-10-10s4.48-10 10-10 10 4.48 10 10-4.48 10-10 10zm0-16c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z"/></svg>
|
After Width: | Height: | Size: 328 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M13 13v8h8v-8h-8zM3 21h8v-8H3v8zM3 3v8h8V3H3zm13.66-1.31L11 7.34 16.66 13l5.66-5.66-5.66-5.65z"/></svg>
|
After Width: | Height: | Size: 232 B |
|
@ -0,0 +1,58 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
version="1.1"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="ic_widgets_grey_24px.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1379"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="12"
|
||||||
|
inkscape:cy="12"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
d="M13 13v8h8v-8h-8zM3 21h8v-8H3v8zM3 3v8h8V3H3zm13.66-1.31L11 7.34 16.66 13l5.66-5.66-5.66-5.65z"
|
||||||
|
id="path4"
|
||||||
|
style="fill:#808080" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,58 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
version="1.1"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="ic_widgets_red_24px.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1411"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="-4.0677967"
|
||||||
|
inkscape:cy="12"
|
||||||
|
inkscape:window-x="2560"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
d="M13 13v8h8v-8h-8zM3 21h8v-8H3v8zM3 3v8h8V3H3zm13.66-1.31L11 7.34 16.66 13l5.66-5.66-5.66-5.65z"
|
||||||
|
id="path4"
|
||||||
|
style="fill:#ff0000" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,711 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
from PySide6.QtCore import QSize, Qt, Slot, QRect, QFileSystemWatcher
|
||||||
|
from PySide6.QtGui import QIcon, QAction, QShortcut, QKeySequence, QPainter, QColor, QTextFormat, QPixmap
|
||||||
|
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget, QLabel, QVBoxLayout, QHBoxLayout, \
|
||||||
|
QGroupBox, QLineEdit, QCheckBox, QSpinBox, QPlainTextEdit, QSizePolicy, QGridLayout, QTextEdit, QScrollArea, QFrame, \
|
||||||
|
QDoubleSpinBox
|
||||||
|
|
||||||
|
from widgets import *
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def change_font_size(label: QLabel | QLineEdit, factor: float) -> QLabel:
|
||||||
|
f = label.font()
|
||||||
|
f.setPointSizeF(f.pointSizeF() * factor)
|
||||||
|
label.setFont(f)
|
||||||
|
return label
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
options = [("Buffs", "Some songs affect the characters with strengthen\nand haste afflictions."),
|
||||||
|
("De-buffs", "Some songs affect the characters with psychosis \naffliction."),
|
||||||
|
("Walkmans", "Include personal music players (walkmans)"),
|
||||||
|
("Durability", "Playing and throwing cassettes damages them."),
|
||||||
|
("Repair", "Crafting mechanics to repair broken tapes by \nduplicating them with error correction.")]
|
||||||
|
|
||||||
|
# Name options
|
||||||
|
self.name_line_edit = QLineEdit()
|
||||||
|
self.name_hbox = QHBoxLayout()
|
||||||
|
self.name_hbox.addWidget(self.name_line_edit)
|
||||||
|
self.name_gbox = QGroupBox("Local mod name")
|
||||||
|
self.name_gbox.setCheckable(True)
|
||||||
|
self.name_gbox.setLayout(self.name_hbox)
|
||||||
|
|
||||||
|
# resolution
|
||||||
|
self.width_spinbox = QSpinBox()
|
||||||
|
self.width_spinbox.setRange(100, 100000)
|
||||||
|
self.width_spinbox.setPrefix("Width: ")
|
||||||
|
self.width_spinbox.setSuffix(" px")
|
||||||
|
self.width_spinbox.setValue(1920)
|
||||||
|
|
||||||
|
self.height_spinbox = QSpinBox()
|
||||||
|
self.height_spinbox.setRange(100, 100000)
|
||||||
|
self.height_spinbox.setPrefix("Height: ")
|
||||||
|
self.height_spinbox.setSuffix(" px")
|
||||||
|
self.height_spinbox.setValue(1080)
|
||||||
|
|
||||||
|
self.detect_pushbutton = QPushButton("Detect screen resolution")
|
||||||
|
|
||||||
|
self.resolution_hbox = QVBoxLayout()
|
||||||
|
self.resolution_hbox.addWidget(self.width_spinbox)
|
||||||
|
self.resolution_hbox.addWidget(self.height_spinbox)
|
||||||
|
self.resolution_hbox.addWidget(self.detect_pushbutton)
|
||||||
|
|
||||||
|
self.tape_covers_gbox = QGroupBox("Tape covers")
|
||||||
|
self.tape_covers_gbox.setCheckable(True)
|
||||||
|
self.tape_covers_gbox.setLayout(self.resolution_hbox)
|
||||||
|
|
||||||
|
# Checkbox options
|
||||||
|
self.cbox_buffs = TelegraphingCheckbox(options[0][0], options[0][1])
|
||||||
|
self.cbox_debuffs = TelegraphingCheckbox(options[1][0], options[1][1])
|
||||||
|
self.cbox_walkmans = TelegraphingCheckbox(options[2][0], options[2][1])
|
||||||
|
self.cbox_durability = TelegraphingCheckbox(options[3][0], options[3][1])
|
||||||
|
self.cbox_repair = TelegraphingCheckbox(options[4][0], options[4][1])
|
||||||
|
|
||||||
|
self.label_options_description = QLabel()
|
||||||
|
self.label_options_description.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||||
|
self.label_options_description.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
|
self.label_options_description.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||||
|
|
||||||
|
self.options_vbox = QVBoxLayout()
|
||||||
|
|
||||||
|
for cbox in [self.cbox_buffs,
|
||||||
|
self.cbox_debuffs,
|
||||||
|
self.cbox_walkmans,
|
||||||
|
self.cbox_durability,
|
||||||
|
self.cbox_repair]:
|
||||||
|
self.options_vbox.addWidget(cbox)
|
||||||
|
cbox.hover.connect(self.label_options_description.setText)
|
||||||
|
cbox.toggle()
|
||||||
|
|
||||||
|
self.options_hbox = QHBoxLayout()
|
||||||
|
self.options_hbox.addLayout(self.options_vbox)
|
||||||
|
self.options_hbox.addWidget(self.label_options_description)
|
||||||
|
|
||||||
|
self.options_gbox = QGroupBox("Other options")
|
||||||
|
self.options_gbox.setLayout(self.options_hbox)
|
||||||
|
|
||||||
|
# Install widget
|
||||||
|
self.install = InstallWidget()
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(self.name_gbox)
|
||||||
|
layout.addWidget(self.tape_covers_gbox)
|
||||||
|
layout.addWidget(self.options_gbox)
|
||||||
|
layout.addWidget(self.install)
|
||||||
|
layout.addStretch()
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
self.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Minimum)
|
||||||
|
|
||||||
|
# def update_label_description(self):
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: implement random local mod name
|
||||||
|
|
||||||
|
|
||||||
|
class EditorWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tapes_yaml = Path("../source/tapes.yaml")
|
||||||
|
self.filename_string = f"<tt style=\"font-family: consolas;\"><b>{self.tapes_yaml.name}</b></tt>"
|
||||||
|
|
||||||
|
self.tapes_file_watcher = QFileSystemWatcher()
|
||||||
|
self.tapes_file_watcher.addPath(self.tapes_yaml.as_posix())
|
||||||
|
self.tapes_file_watcher.fileChanged.connect(self.external_file_changed)
|
||||||
|
|
||||||
|
self.external_editor_pushbutton = QPushButton()
|
||||||
|
self.external_editor_pushbutton.setIcon(QIcon("./icons/ic_open_in_new_24px.svg"))
|
||||||
|
self.external_editor_pushbutton.setToolTip("Edit in external editor")
|
||||||
|
self.external_editor_pushbutton.clicked.connect(self.open_file)
|
||||||
|
self.reload_code_pushbutton = QPushButton()
|
||||||
|
self.reload_code_pushbutton.setIcon(QIcon("./icons/ic_refresh_24px.svg"))
|
||||||
|
self.reload_code_pushbutton.setToolTip("Reload the external file")
|
||||||
|
self.reload_code_pushbutton.clicked.connect(self.load_file)
|
||||||
|
self.save_code_pushbutton = QPushButton()
|
||||||
|
self.save_code_pushbutton.setIcon(QIcon("./icons/ic_save_24px.svg"))
|
||||||
|
self.save_code_pushbutton.setToolTip("Save setup")
|
||||||
|
self.transfer_to_validator_pushbutton = QPushButton()
|
||||||
|
self.transfer_to_validator_pushbutton.setIcon(QIcon("./icons/ic_keyboard_double_arrow_right_24px.svg"))
|
||||||
|
self.transfer_to_validator_pushbutton.setToolTip("Apply the code.")
|
||||||
|
|
||||||
|
self.status_same = f"<b>Status:</b> yaml setup matches {self.filename_string} file"
|
||||||
|
self.status_external_file_changed = f"<b>Status:</b> {self.filename_string} file was edited externally"
|
||||||
|
self.status_editor_code_changed = "<b>Status:</b> yaml setup not yet saved"
|
||||||
|
|
||||||
|
self.status_label = QLabel(self.status_same)
|
||||||
|
|
||||||
|
self.editor = CodeEditor()
|
||||||
|
self.editor.setFont("Consolas")
|
||||||
|
self.editor.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
||||||
|
self.editor.setMinimumWidth(400)
|
||||||
|
self.editor.textChanged.connect(self.yaml_setup_changed)
|
||||||
|
|
||||||
|
self.button_hbox = QHBoxLayout()
|
||||||
|
self.button_hbox.addWidget(self.external_editor_pushbutton)
|
||||||
|
self.button_hbox.addWidget(self.reload_code_pushbutton)
|
||||||
|
self.button_hbox.addWidget(self.save_code_pushbutton)
|
||||||
|
self.button_hbox.addWidget(self.status_label)
|
||||||
|
self.button_hbox.addStretch()
|
||||||
|
self.button_hbox.addWidget(self.transfer_to_validator_pushbutton)
|
||||||
|
#self.button_hbox.addStretch()
|
||||||
|
|
||||||
|
self.editor_vbox = QVBoxLayout()
|
||||||
|
self.editor_vbox.addLayout(self.button_hbox)
|
||||||
|
self.editor_vbox.addWidget(self.editor)
|
||||||
|
|
||||||
|
self.editor_gbox = QGroupBox("tapes.yaml editor")
|
||||||
|
self.editor_gbox.setLayout(self.editor_vbox)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.addWidget(self.editor_gbox)
|
||||||
|
|
||||||
|
self.load_file()
|
||||||
|
|
||||||
|
def load_file(self):
|
||||||
|
with open(self.tapes_yaml, encoding="utf-8") as fp:
|
||||||
|
text = fp.read()
|
||||||
|
self.editor.setPlainText(text)
|
||||||
|
|
||||||
|
def open_file(self):
|
||||||
|
os.startfile(self.tapes_yaml)
|
||||||
|
|
||||||
|
def check_if_setups_match(self):
|
||||||
|
with open(self.tapes_yaml, encoding="utf-8") as fp:
|
||||||
|
external_text = fp.read()
|
||||||
|
|
||||||
|
contents_match = external_text == self.editor.toPlainText()
|
||||||
|
self.save_code_pushbutton.setDisabled(contents_match)
|
||||||
|
self.reload_code_pushbutton.setDisabled(contents_match)
|
||||||
|
|
||||||
|
if contents_match:
|
||||||
|
self.status_label.setText(self.status_same)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def external_file_changed(self):
|
||||||
|
if not self.check_if_setups_match():
|
||||||
|
self.status_label.setText(self.status_external_file_changed)
|
||||||
|
|
||||||
|
def yaml_setup_changed(self):
|
||||||
|
if not self.check_if_setups_match():
|
||||||
|
self.status_label.setText(self.status_editor_code_changed)
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessEditWidget(QWidget):
|
||||||
|
# TODO: move process to another part in yaml
|
||||||
|
def __init__(self, tape: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
self.cbox_clip_start = QCheckBox("Clip at start")
|
||||||
|
self.cbox_clip_end = QCheckBox("Clip at end")
|
||||||
|
self.cbox_volume_factor = QCheckBox("Volume factor")
|
||||||
|
|
||||||
|
self.clip_start = TimeEditWithoutWheel()
|
||||||
|
self.clip_start.setDisplayFormat("hh:mm:ss.z")
|
||||||
|
self.clip_end = TimeEditWithoutWheel()
|
||||||
|
self.clip_end.setDisplayFormat("hh:mm:ss.z")
|
||||||
|
self.volume_factor = SpinBoxWithoutWheel()
|
||||||
|
self.volume_factor.setSuffix(" dB")
|
||||||
|
self.volume_factor.setMinimum(-30)
|
||||||
|
self.volume_factor.setMaximum(30)
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(5, 0, 5, 0)
|
||||||
|
layout.setColumnStretch(3, 1)
|
||||||
|
|
||||||
|
layout.addWidget(self.cbox_clip_start, 0, 0)
|
||||||
|
layout.addWidget(self.cbox_clip_end, 1, 0)
|
||||||
|
layout.addWidget(self.cbox_volume_factor, 2, 0)
|
||||||
|
|
||||||
|
layout.addWidget(self.clip_start, 0, 1)
|
||||||
|
layout.addWidget(self.clip_end, 1, 1)
|
||||||
|
layout.addWidget(self.volume_factor, 2, 1)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
self.clip_start.timeChanged.connect(self.save)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
clip_start, clip_end = self.tape["process"]["start"], self.tape["process"]["end"]
|
||||||
|
start, end = QTime(), QTime()
|
||||||
|
|
||||||
|
start_time = datetime.datetime.strptime(clip_start, "%H:%M:%S.%f")
|
||||||
|
end_time = datetime.datetime.strptime(clip_end, "%H:%M:%S.%f")
|
||||||
|
|
||||||
|
start.setHMS(start_time.hour, start_time.minute, start_time.second, ms=start_time.microsecond * 1e-3)
|
||||||
|
end.setHMS(end_time.hour, end_time.minute, end_time.second, ms=end_time.microsecond * 1e-3)
|
||||||
|
|
||||||
|
self.clip_start.setTime(start)
|
||||||
|
self.clip_end.setTime(end)
|
||||||
|
|
||||||
|
self.cbox_clip_start.setChecked(clip_start != "00:00:00.0")
|
||||||
|
self.cbox_clip_end.setChecked(clip_end != "00:00:00.0")
|
||||||
|
|
||||||
|
volume_factor = self.tape["process"]["volume"]
|
||||||
|
self.volume_factor.setValue(volume_factor)
|
||||||
|
self.cbox_volume_factor.setChecked(volume_factor != 0)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
start = self.clip_start.time()
|
||||||
|
end = self.clip_end.time()
|
||||||
|
self.tape["process"]["start"] = f"{start.hour():02}:{start.minute():02}:{start.second():02}.{start.msec():03}"
|
||||||
|
self.tape["process"]["end"] = f"{end.hour():02}:{end.minute():02}:{end.second():02}.{end.msec():03}"
|
||||||
|
self.tape["process"]["volume"] = self.volume_factor.value()
|
||||||
|
|
||||||
|
|
||||||
|
class EconomyEditWidget(QWidget):
|
||||||
|
def __init__(self, tape: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
self.spinbox_price = SpinBoxWithoutWheel()
|
||||||
|
self.spinbox_price.setRange(10, 100000)
|
||||||
|
self.spinbox_price.setSuffix(" mk")
|
||||||
|
self.spinbox_price.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Maximum)
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(5, 0, 5, 0)
|
||||||
|
layout.addWidget(self.spinbox_price, 1, 0)
|
||||||
|
layout.setColumnStretch(4, 1)
|
||||||
|
|
||||||
|
for i, text in enumerate(["Price", "Sold in", "Factor", " Local price"]):
|
||||||
|
layout.addWidget(change_font_size(QLabel(text), 0.8), 0, i)
|
||||||
|
|
||||||
|
self.economy = {"outpost": {},
|
||||||
|
"city": {},
|
||||||
|
"research": {},
|
||||||
|
"military": {},
|
||||||
|
"mine": {}}
|
||||||
|
|
||||||
|
for i, (location, editors) in enumerate(self.economy.items()):
|
||||||
|
editors["cbox"] = QCheckBox(location.capitalize())
|
||||||
|
editors["float"] = DoubleSpinBoxWithoutWheel()
|
||||||
|
editors["float"].setSingleStep(0.05)
|
||||||
|
editors["label"] = QLabel()
|
||||||
|
editors["label"].setFont("consolas")
|
||||||
|
layout.addWidget(editors["cbox"], int(i) + 1, 1)
|
||||||
|
layout.addWidget(editors["float"], int(i) + 1, 2)
|
||||||
|
layout.addWidget(editors["label"], int(i) + 1, 3)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
self.update_labels()
|
||||||
|
|
||||||
|
self.spinbox_price.valueChanged.connect(self.save)
|
||||||
|
for editors in self.economy.values():
|
||||||
|
editors["cbox"].toggled.connect(self.save)
|
||||||
|
editors["float"].valueChanged.connect(self.save)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.spinbox_price.setValue(self.tape["price"])
|
||||||
|
for locale in self.tape["economy"]:
|
||||||
|
self.economy[locale["location"]]["cbox"].setChecked(locale["sold"])
|
||||||
|
self.economy[locale["location"]]["float"].setValue(locale["factor"])
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.tape["price"] = self.spinbox_price.value()
|
||||||
|
self.tape["economy"] = [{"location": location,
|
||||||
|
"factor": editors["float"].value(),
|
||||||
|
"sold": editors["cbox"].isChecked()} for location, editors in self.economy.items()]
|
||||||
|
self.update_labels()
|
||||||
|
|
||||||
|
def update_labels(self):
|
||||||
|
for editors in self.economy.values():
|
||||||
|
editors["label"].setText(f" {self.tape['price'] * editors['float'].value():4.0f} mk")
|
||||||
|
|
||||||
|
|
||||||
|
class SpawnEditWidget(QWidget):
|
||||||
|
def __init__(self, tape: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(5, 0, 5, 0)
|
||||||
|
layout.setColumnStretch(2, 1)
|
||||||
|
|
||||||
|
for i, text in enumerate(["Place", "Probability"]):
|
||||||
|
layout.addWidget(change_font_size(QLabel(text), 0.8), 0, i)
|
||||||
|
|
||||||
|
self.spawn = {"outpostcrewcabinet": {"label": QLabel("Outpost Crew Cabinet"),
|
||||||
|
"float": ProbabilitySpinBox()},
|
||||||
|
"wreckstorage": {"label": QLabel("Wreck Storage"),
|
||||||
|
"float": ProbabilitySpinBox()},
|
||||||
|
"abandonedcrewcab": {"label": QLabel("Abandoned Crew Cabinet"),
|
||||||
|
"float": ProbabilitySpinBox()},
|
||||||
|
"abandonedstoragecab": {"label": QLabel("Abandoned Storage Cabinet"),
|
||||||
|
"float": ProbabilitySpinBox()}}
|
||||||
|
|
||||||
|
for i, (location, editors) in enumerate(self.spawn.items()):
|
||||||
|
layout.addWidget(editors["label"], int(i) + 1, 0)
|
||||||
|
layout.addWidget(editors["float"], int(i) + 1, 1)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
for i, (location, editors) in enumerate(self.spawn.items()):
|
||||||
|
editors["float"].valueChanged.connect(self.save)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
for locale in self.tape["spawn"]:
|
||||||
|
self.spawn[locale["location"]]["float"].setValue(locale["probability"])
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.tape["spawn"] = [{"location": location,
|
||||||
|
"probability": editors["float"].value()} for location, editors in self.spawn.items() if
|
||||||
|
editors["float"].value() > 0]
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: afflictions with shorter range for walkman songs.
|
||||||
|
|
||||||
|
|
||||||
|
class CraftingEditWidget(QWidget):
|
||||||
|
|
||||||
|
def __init__(self, tape: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
self.int_uses = SpinBoxWithoutWheel()
|
||||||
|
self.int_uses.setMinimum(1)
|
||||||
|
self.int_uses.setMaximum(1000)
|
||||||
|
|
||||||
|
self.description = QPlainTextEdit("One use is duration of the tape")
|
||||||
|
self.description.setEnabled(False)
|
||||||
|
self.description.setMaximumHeight(QFontMetrics(self.description.font()).height() * 1.7)
|
||||||
|
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.addWidget(QLabel("Number of uses:"))
|
||||||
|
layout.addWidget(self.int_uses)
|
||||||
|
layout.addWidget(self.description)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.setContentsMargins(5, 0, 5, 0)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
self.int_uses.valueChanged.connect(self.save)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.int_uses.setValue(self.tape["no_of_uses"])
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.tape["no_of_uses"] = self.int_uses.value()
|
||||||
|
|
||||||
|
|
||||||
|
class AfflictionsEditWidget(QWidget):
|
||||||
|
|
||||||
|
def __init__(self, tape: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
self.description = QPlainTextEdit("Factor 1.0 means that the affliction will reach the "
|
||||||
|
"highest level after being exposed to the sound of the "
|
||||||
|
"tape for its play duration.")
|
||||||
|
self.description.setEnabled(False)
|
||||||
|
self.description.setMaximumWidth(212)
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(5, 0, 5, 0)
|
||||||
|
layout.addWidget(change_font_size(QLabel("Affliction"), 0.8), 0, 0)
|
||||||
|
layout.addWidget(change_font_size(QLabel("Factor"), 0.8), 0, 1)
|
||||||
|
layout.addWidget(self.description, 1, 2, 3, 1)
|
||||||
|
layout.setColumnStretch(3, 1)
|
||||||
|
|
||||||
|
self.afflictions = {"strengthen": {},
|
||||||
|
"haste": {},
|
||||||
|
"psychosis": {}}
|
||||||
|
|
||||||
|
for i, (affliction, editors) in enumerate(self.afflictions.items()):
|
||||||
|
editors["cbox"] = QCheckBox(affliction.capitalize())
|
||||||
|
editors["float"] = DoubleSpinBoxWithoutWheel()
|
||||||
|
editors["float"].setSingleStep(0.01)
|
||||||
|
layout.addWidget(editors["cbox"], int(i) + 1, 0)
|
||||||
|
layout.addWidget(editors["float"], int(i) + 1, 1)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
for editors in self.afflictions.values():
|
||||||
|
editors["cbox"].toggled.connect(self.save)
|
||||||
|
editors["float"].valueChanged.connect(self.save)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
if self.tape["afflictions"]:
|
||||||
|
for affliction in self.tape["afflictions"]:
|
||||||
|
self.afflictions[affliction["name"]]["cbox"].setChecked(True)
|
||||||
|
self.afflictions[affliction["name"]]["float"].setValue(affliction["factor"])
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.tape["afflictions"] = [{"name": affliction, "factor": editors["float"].value()} for affliction, editors in
|
||||||
|
self.afflictions.items() if editors["cbox"].isChecked()]
|
||||||
|
|
||||||
|
|
||||||
|
class TapeEditWidget(QWidget):
|
||||||
|
def __init__(self, tape: dict, number: int | None = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tape = tape
|
||||||
|
|
||||||
|
self.label_nr = QLabel(f"#{number}")
|
||||||
|
self.label_nr.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_nr.setStyleSheet("background-color: #cfd8dc;")
|
||||||
|
|
||||||
|
self.edit_identifier = QLineEdit()
|
||||||
|
self.edit_identifier.setFont("Consolas")
|
||||||
|
self.edit_identifier.setStyleSheet("font-weight: bold; background-color: #cfd8dc;")
|
||||||
|
self.edit_identifier.setTextMargins(2, 0, 2, 0)
|
||||||
|
self.edit_identifier.setFrame(QFrame.Shape.NoFrame)
|
||||||
|
self.edit_identifier.setText(self.tape["identifier"])
|
||||||
|
change_font_size(self.edit_identifier, 1.41)
|
||||||
|
change_font_size(self.label_nr, 1.41)
|
||||||
|
|
||||||
|
pix = QPixmap(f"../source/images/{self.tape['identifier']}.png")
|
||||||
|
self.pixmap = pix.scaled(350, 350,
|
||||||
|
Qt.AspectRatioMode.KeepAspectRatio,
|
||||||
|
Qt.TransformationMode.SmoothTransformation)
|
||||||
|
|
||||||
|
self.cover = QLabel()
|
||||||
|
self.cover.resize(350, 0)
|
||||||
|
self.cover.setPixmap(self.pixmap)
|
||||||
|
|
||||||
|
self.edit_name = QLineEdit()
|
||||||
|
self.edit_name.setText(self.tape["name"])
|
||||||
|
|
||||||
|
source = self.tape["source"]
|
||||||
|
self.edit_source = UrlWidget(source)
|
||||||
|
self.process = ProcessEditWidget(self.tape)
|
||||||
|
self.economy = EconomyEditWidget(self.tape)
|
||||||
|
self.spawn = SpawnEditWidget(self.tape)
|
||||||
|
self.afflictions = AfflictionsEditWidget(self.tape)
|
||||||
|
self.crafting = CraftingEditWidget(self.tape)
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 5)
|
||||||
|
|
||||||
|
for i, (text, widget) in enumerate([(f"", self.edit_identifier),
|
||||||
|
("Cover", self.cover),
|
||||||
|
("Name", self.edit_name),
|
||||||
|
("Source", self.edit_source),
|
||||||
|
("Process", self.process),
|
||||||
|
("Economy", self.economy),
|
||||||
|
("Spawn", self.spawn),
|
||||||
|
("Crafting", self.crafting),
|
||||||
|
("Afflictions", self.afflictions),
|
||||||
|
("Note", QPlainTextEdit(self.tape["note"]))]):
|
||||||
|
label = self.label_nr if i == 0 else QLabel(text)
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
layout.addWidget(label, i, 0)
|
||||||
|
else:
|
||||||
|
label_layout = QVBoxLayout()
|
||||||
|
label_layout.addWidget(label)
|
||||||
|
label_layout.addStretch()
|
||||||
|
layout.addLayout(label_layout, i, 0)
|
||||||
|
|
||||||
|
layout.addWidget(widget, i, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class TapeListWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.setContentsMargins(1, 0, 0, 0)
|
||||||
|
|
||||||
|
def append(self, widget):
|
||||||
|
self.layout.addWidget(widget)
|
||||||
|
|
||||||
|
|
||||||
|
class ValidationWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.tapes = self.load_tapes()
|
||||||
|
self.transfer_to_code_pushbutton = QPushButton()
|
||||||
|
self.transfer_to_code_pushbutton.setIcon(QIcon("./icons/ic_keyboard_double_arrow_left_24px.svg"))
|
||||||
|
self.transfer_to_code_pushbutton.setToolTip("Update the code")
|
||||||
|
self.jump_spinbox = QSpinBox()
|
||||||
|
#self.search_lineedit = QLineEdit()
|
||||||
|
#self.search_lineedit.setPlaceholderText("Search ...")
|
||||||
|
|
||||||
|
self.buttons_hbox = QHBoxLayout()
|
||||||
|
self.buttons_hbox.addWidget(self.transfer_to_code_pushbutton)
|
||||||
|
self.buttons_hbox.addWidget(QLabel("Navigate to"))
|
||||||
|
self.buttons_hbox.addWidget(self.jump_spinbox)
|
||||||
|
self.buttons_hbox.addStretch()
|
||||||
|
#self.buttons_hbox.addWidget(self.search_lineedit)
|
||||||
|
|
||||||
|
self.tape_list_widget = TapeListWidget()
|
||||||
|
|
||||||
|
self.scroll = QScrollArea()
|
||||||
|
self.scroll.setWidget(self.tape_list_widget)
|
||||||
|
self.scroll.setWidgetResizable(True)
|
||||||
|
self.scroll.setFrameStyle(QFrame.Shape.NoFrame)
|
||||||
|
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||||
|
|
||||||
|
self.validation_vbox = QVBoxLayout()
|
||||||
|
self.validation_vbox.addLayout(self.buttons_hbox)
|
||||||
|
self.validation_vbox.addWidget(self.scroll)
|
||||||
|
|
||||||
|
self.validation_gbox = QGroupBox("Data validation")
|
||||||
|
self.validation_gbox.setLayout(self.validation_vbox)
|
||||||
|
|
||||||
|
for i, tape in enumerate(self.tapes):
|
||||||
|
self.tape_list_widget.append(TapeEditWidget(tape, i))
|
||||||
|
|
||||||
|
self.jump_spinbox.setMaximum(i)
|
||||||
|
self.jump_spinbox.valueChanged.connect(self.jump_to_tape)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.addWidget(self.validation_gbox)
|
||||||
|
self.setMinimumWidth(470)
|
||||||
|
self.setMaximumWidth(470)
|
||||||
|
|
||||||
|
def load_tapes(self):
|
||||||
|
with open("../source/tapes.yaml", encoding="utf-8") as fp:
|
||||||
|
tapes = yaml.safe_load(fp)
|
||||||
|
|
||||||
|
return tapes
|
||||||
|
|
||||||
|
def jump_to_tape(self, tape_number):
|
||||||
|
scrollbar = self.scroll.verticalScrollBar()
|
||||||
|
|
||||||
|
division = (scrollbar.maximum() + scrollbar.pageStep()) / len(self.tapes)
|
||||||
|
overflow_ratio = (scrollbar.pageStep() + 5) / division
|
||||||
|
step = scrollbar.maximum() / (len(self.tapes) - overflow_ratio)
|
||||||
|
|
||||||
|
scrollbar.setValue(tape_number * step)
|
||||||
|
|
||||||
|
|
||||||
|
class InstallWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.install_grid = QGridLayout()
|
||||||
|
|
||||||
|
hr_html_string = "<hr style=\"background-color:gray;\">"
|
||||||
|
|
||||||
|
self.ffmpeg_checkbox = QCheckBox()
|
||||||
|
self.ffmpeg_checkbox.setDisabled(True)
|
||||||
|
self.ffmpeg_label = QLabel("Download and unpack ffmpeg")
|
||||||
|
self.ffmpeg_label_link = QLabel("<a href=\"https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z\">"
|
||||||
|
"gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z</a>")
|
||||||
|
self.ffmpeg_label_link.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
|
||||||
|
self.ffmpeg_label_link.setTextInteractionFlags(Qt.TextInteractionFlag.LinksAccessibleByMouse)
|
||||||
|
self.ffmpeg_label_link.setOpenExternalLinks(True)
|
||||||
|
self.ffmpeg_dir = DirWidget("./utils")
|
||||||
|
self.ffmpeg_pushbutton = QPushButton("Download")
|
||||||
|
self.install_grid.addWidget(self.ffmpeg_checkbox, 0, 0)
|
||||||
|
self.install_grid.addWidget(self.ffmpeg_label, 0, 1)
|
||||||
|
self.install_grid.addWidget(self.ffmpeg_label_link, 1, 1)
|
||||||
|
self.install_grid.addWidget(self.ffmpeg_dir, 2, 1)
|
||||||
|
self.install_grid.addWidget(self.ffmpeg_pushbutton, 0, 2)
|
||||||
|
self.install_grid.addWidget(QLabel(hr_html_string), 3, 0, 1, 3)
|
||||||
|
|
||||||
|
self.git_update_checkbox = QCheckBox()
|
||||||
|
self.git_update_checkbox.setDisabled(True)
|
||||||
|
self.git_update_label = QLabel("Download update from git")
|
||||||
|
self.git_update_label_link = QLabel("<a href=\"https://git.kompot.si/jaka/barotrauma-sunken-tapes\">"
|
||||||
|
"git.kompot.si/jaka/barotrauma-sunken-tapes</a>")
|
||||||
|
self.git_update_label_link.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
|
||||||
|
self.git_update_label_link.setTextInteractionFlags(Qt.TextInteractionFlag.LinksAccessibleByMouse)
|
||||||
|
self.git_update_label_link.setOpenExternalLinks(True)
|
||||||
|
self.git_update_pushbutton = QPushButton("Update")
|
||||||
|
self.install_grid.addWidget(self.git_update_checkbox, 10, 0)
|
||||||
|
self.install_grid.addWidget(self.git_update_label, 10, 1)
|
||||||
|
self.install_grid.addWidget(self.git_update_label_link, 11, 1)
|
||||||
|
self.install_grid.addWidget(self.git_update_pushbutton, 10, 2)
|
||||||
|
self.install_grid.addWidget(QLabel(hr_html_string), 12, 0, 1, 3)
|
||||||
|
|
||||||
|
self.songs_download_checkbox = QCheckBox()
|
||||||
|
self.songs_download_checkbox.setDisabled(True)
|
||||||
|
self.songs_download_label = QLabel("Download songs and process them")
|
||||||
|
self.songs_download_dir = DirWidget("./build/music")
|
||||||
|
self.songs_download_pushbutton = QPushButton("Download")
|
||||||
|
self.install_grid.addWidget(self.songs_download_checkbox, 20, 0)
|
||||||
|
self.install_grid.addWidget(self.songs_download_label, 20, 1)
|
||||||
|
self.install_grid.addWidget(self.songs_download_pushbutton, 20, 2)
|
||||||
|
self.install_grid.addWidget(self.songs_download_dir, 21, 1)
|
||||||
|
self.install_grid.addWidget(QLabel(hr_html_string), 22, 0, 1, 3)
|
||||||
|
|
||||||
|
self.compile_checkbox = QCheckBox()
|
||||||
|
self.compile_checkbox.setDisabled(True)
|
||||||
|
self.compile_label = QLabel("Compile mod according to the settings")
|
||||||
|
self.compile_dir = DirWidget("./build")
|
||||||
|
self.compile_pushbutton = QPushButton("Compile")
|
||||||
|
self.install_grid.addWidget(self.compile_checkbox, 30, 0)
|
||||||
|
self.install_grid.addWidget(self.compile_label, 30, 1)
|
||||||
|
self.install_grid.addWidget(self.compile_pushbutton, 30, 2)
|
||||||
|
self.install_grid.addWidget(self.compile_dir, 31, 1)
|
||||||
|
self.install_grid.addWidget(QLabel(hr_html_string), 32, 0, 1, 3)
|
||||||
|
|
||||||
|
self.install_checkbox = QCheckBox()
|
||||||
|
self.install_checkbox.setDisabled(True)
|
||||||
|
self.install_label = QLabel("Copy the files to the install directory")
|
||||||
|
self.install_dir = DirWidget()
|
||||||
|
self.install_pushbutton = QPushButton("Install")
|
||||||
|
self.install_grid.addWidget(self.install_checkbox, 40, 0)
|
||||||
|
self.install_grid.addWidget(self.install_label, 40, 1)
|
||||||
|
self.install_grid.addWidget(self.install_pushbutton, 40, 2)
|
||||||
|
self.install_grid.addWidget(self.install_dir, 41, 1)
|
||||||
|
self.install_grid.addWidget(QLabel(hr_html_string), 42, 0, 1, 3)
|
||||||
|
|
||||||
|
self.install_grid.setRowStretch(50, 20)
|
||||||
|
|
||||||
|
self.install_gbox = QGroupBox("Install steps")
|
||||||
|
self.install_gbox.setLayout(self.install_grid)
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.addWidget(self.install_gbox)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
class MainWidget(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
|
||||||
|
options = OptionsWidget()
|
||||||
|
editor = EditorWidget()
|
||||||
|
validation = ValidationWidget()
|
||||||
|
# install = InstallWidget()
|
||||||
|
layout.addWidget(options)
|
||||||
|
layout.addWidget(editor)
|
||||||
|
layout.addWidget(validation)
|
||||||
|
# layout.addWidget(install)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setWindowTitle("Sunken Tapes installer")
|
||||||
|
|
||||||
|
self.quit_shortcut = QShortcut(QKeySequence('Ctrl+Q'), self)
|
||||||
|
self.quit_shortcut.activated.connect(QApplication.instance().quit)
|
||||||
|
|
||||||
|
self.setCentralWidget(MainWidget())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = MainWindow()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,226 @@
|
||||||
|
from PySide6.QtCore import QSize, Qt, Slot, QRect, QFileSystemWatcher, Signal, QTime
|
||||||
|
from PySide6.QtGui import QIcon, QAction, QShortcut, QKeySequence, QPainter, QColor, QTextFormat, QPixmap, QFontMetrics
|
||||||
|
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget, QLabel, QVBoxLayout, QHBoxLayout, \
|
||||||
|
QGroupBox, QLineEdit, QCheckBox, QSpinBox, QPlainTextEdit, QSizePolicy, QGridLayout, QTextEdit, QScrollArea, QFrame, \
|
||||||
|
QDoubleSpinBox, QFormLayout, QTimeEdit
|
||||||
|
|
||||||
|
import webbrowser
|
||||||
|
import validators
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class LineNumberArea(QWidget):
|
||||||
|
def __init__(self, editor):
|
||||||
|
QWidget.__init__(self, editor)
|
||||||
|
self._code_editor = editor
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
return QSize(self._code_editor.line_number_area_width(), 0)
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
self._code_editor.line_number_area_paint_event(event)
|
||||||
|
|
||||||
|
|
||||||
|
class CodeEditor(QPlainTextEdit):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.line_number_area = LineNumberArea(self)
|
||||||
|
|
||||||
|
self.blockCountChanged[int].connect(self.update_line_number_area_width)
|
||||||
|
self.updateRequest[QRect, int].connect(self.update_line_number_area)
|
||||||
|
self.cursorPositionChanged.connect(self.highlight_current_line)
|
||||||
|
|
||||||
|
def line_number_area_width(self):
|
||||||
|
digits = len(str(self.blockCount()))
|
||||||
|
space = 3 + self.fontMetrics().horizontalAdvance('9') * digits
|
||||||
|
return space
|
||||||
|
|
||||||
|
def resizeEvent(self, e):
|
||||||
|
super().resizeEvent(e)
|
||||||
|
cr = self.contentsRect()
|
||||||
|
self.line_number_area.setGeometry(QRect(cr.left(),
|
||||||
|
cr.top(),
|
||||||
|
self.line_number_area_width(),
|
||||||
|
cr.height()))
|
||||||
|
|
||||||
|
def line_number_area_paint_event(self, event):
|
||||||
|
with QPainter(self.line_number_area) as painter:
|
||||||
|
painter.fillRect(event.rect(), Qt.white)
|
||||||
|
painter.setFont("Consolas")
|
||||||
|
|
||||||
|
block = self.firstVisibleBlock()
|
||||||
|
block_number = block.blockNumber()
|
||||||
|
|
||||||
|
top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
|
||||||
|
bottom = top + self.blockBoundingRect(block).height()
|
||||||
|
|
||||||
|
while block.isValid() and top <= event.rect().bottom():
|
||||||
|
if block.isVisible() and bottom >= event.rect().top():
|
||||||
|
painter.setPen(Qt.gray)
|
||||||
|
painter.drawText(-2, top,
|
||||||
|
self.line_number_area.width(),
|
||||||
|
self.fontMetrics().height(),
|
||||||
|
Qt.AlignmentFlag.AlignRight,
|
||||||
|
f"{block_number + 1}")
|
||||||
|
|
||||||
|
block = block.next()
|
||||||
|
top = bottom
|
||||||
|
bottom = top + self.blockBoundingRect(block).height()
|
||||||
|
block_number += 1
|
||||||
|
|
||||||
|
def update_line_number_area_width(self):
|
||||||
|
self.setViewportMargins(self.line_number_area_width(), 0, 0, 0)
|
||||||
|
|
||||||
|
def update_line_number_area(self, rect, dy):
|
||||||
|
if dy:
|
||||||
|
self.line_number_area.scroll(0, dy)
|
||||||
|
else:
|
||||||
|
self.line_number_area.update(0, rect.y(), self.line_number_area.width(), rect.height())
|
||||||
|
|
||||||
|
if rect.contains(self.viewport().rect()):
|
||||||
|
self.update_line_number_area_width()
|
||||||
|
|
||||||
|
def highlight_current_line(self):
|
||||||
|
extra_selections = []
|
||||||
|
|
||||||
|
if not self.isReadOnly():
|
||||||
|
selection = QTextEdit.ExtraSelection()
|
||||||
|
selection.format.setBackground(QColor(Qt.lightGray))
|
||||||
|
selection.format.setProperty(QTextFormat.FullWidthSelection, True)
|
||||||
|
|
||||||
|
selection.cursor = self.textCursor()
|
||||||
|
selection.cursor.clearSelection()
|
||||||
|
|
||||||
|
extra_selections.append(selection)
|
||||||
|
|
||||||
|
self.setExtraSelections(extra_selections)
|
||||||
|
|
||||||
|
|
||||||
|
class SpinBoxWithoutWheel(QSpinBox):
|
||||||
|
def wheelEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
|
||||||
|
class DoubleSpinBoxWithoutWheel(QDoubleSpinBox):
|
||||||
|
def wheelEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
|
||||||
|
class ProbabilitySpinBox(DoubleSpinBoxWithoutWheel):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setSingleStep(0.01)
|
||||||
|
self.valueChanged.connect(self.update_color)
|
||||||
|
self.update_color()
|
||||||
|
|
||||||
|
def update_color(self):
|
||||||
|
if self.value() > 0:
|
||||||
|
self.setStyleSheet("color: black;")
|
||||||
|
else:
|
||||||
|
self.setStyleSheet("color: gray;")
|
||||||
|
|
||||||
|
|
||||||
|
class TimeEditWithoutWheel(QTimeEdit):
|
||||||
|
def wheelEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
|
||||||
|
class DirWidget(QWidget):
|
||||||
|
def __init__(self, default_dir: Path | str | None = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.setSpacing(2)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
self.dir_lineedit = QLineEdit()
|
||||||
|
self.dir_lineedit.setFont("Consolas")
|
||||||
|
self.dir_lineedit.setText(default_dir)
|
||||||
|
|
||||||
|
self.dir_set_btn = QPushButton()
|
||||||
|
self.dir_set_btn.setIcon(QIcon("./icons/ic_folder_open_48px.svg"))
|
||||||
|
self.dir_set_btn.setIconSize(QSize(16, 16))
|
||||||
|
self.dir_set_btn.setToolTip("Set directory with selection dialog")
|
||||||
|
|
||||||
|
self.dir_open_btn = QPushButton()
|
||||||
|
self.dir_open_btn.setIcon(QIcon("./icons/ic_open_in_new_24px.svg"))
|
||||||
|
self.dir_open_btn.setIconSize(QSize(16, 16))
|
||||||
|
self.dir_open_btn.setToolTip("Open directory")
|
||||||
|
|
||||||
|
layout.addWidget(self.dir_set_btn)
|
||||||
|
layout.addWidget(self.dir_lineedit)
|
||||||
|
layout.addWidget(self.dir_open_btn)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
class UrlLineEdit(QLineEdit):
|
||||||
|
|
||||||
|
def __init__(self, initial_text: str | None = None):
|
||||||
|
super().__init__()
|
||||||
|
self.setFont("Consolas")
|
||||||
|
self.textChanged.connect(self.color_text)
|
||||||
|
self.setText(initial_text)
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
modifiers = QApplication.keyboardModifiers()
|
||||||
|
if modifiers == Qt.ControlModifier:
|
||||||
|
self.open_url()
|
||||||
|
|
||||||
|
def open_url(self):
|
||||||
|
if validators.url(self.text()):
|
||||||
|
webbrowser.open(self.text())
|
||||||
|
|
||||||
|
def color_text(self):
|
||||||
|
if validators.url(self.text()):
|
||||||
|
self.setStyleSheet("color: blue;")
|
||||||
|
else:
|
||||||
|
self.setStyleSheet("color: black;")
|
||||||
|
|
||||||
|
|
||||||
|
class UrlWidget(QWidget):
|
||||||
|
def __init__(self, initial_url: str | None = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.setSpacing(2)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
self.url_lineedit = UrlLineEdit(initial_url)
|
||||||
|
self.url_lineedit.textChanged.connect(self.toggle_url_open_btn)
|
||||||
|
|
||||||
|
self.url_open_btn = QPushButton()
|
||||||
|
self.url_open_btn.setIcon(QIcon("./icons/ic_open_in_new_24px.svg"))
|
||||||
|
self.url_open_btn.setIconSize(QSize(16, 16))
|
||||||
|
self.url_open_btn.setToolTip("Open in browser")
|
||||||
|
self.url_open_btn.clicked.connect(self.url_lineedit.open_url)
|
||||||
|
|
||||||
|
self.toggle_url_open_btn()
|
||||||
|
|
||||||
|
layout.addWidget(self.url_lineedit)
|
||||||
|
layout.addWidget(self.url_open_btn)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def toggle_url_open_btn(self):
|
||||||
|
url_valid = bool(validators.url(self.url_lineedit.text()))
|
||||||
|
self.url_open_btn.setEnabled(url_valid)
|
||||||
|
|
||||||
|
|
||||||
|
class TelegraphingCheckbox(QCheckBox):
|
||||||
|
hover = Signal(str)
|
||||||
|
|
||||||
|
def __init__(self, text: str, description_text: str | None = None):
|
||||||
|
super().__init__(text)
|
||||||
|
|
||||||
|
self.description_text = description_text
|
||||||
|
|
||||||
|
def enterEvent(self, event):
|
||||||
|
self.hover.emit(self.description_text)
|
||||||
|
|
||||||
|
def leaveEvent(self, event):
|
||||||
|
self.hover.emit("")
|
|
@ -0,0 +1,16 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "barotrauma-sunken-tapes"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Jaka <jaka@kompot.si>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
pyyaml = "^6.0.1"
|
||||||
|
validators = "^0.22.0"
|
||||||
|
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|