button revamp groundwork (#459)
@ -1,3 +1,3 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 23.1429H12.8571V27H15.4286V20.5714H9V23.1429ZM12.8571 12.8571H9V15.4286H15.4286V9H12.8571V12.8571ZM20.5714 27H23.1429V23.1429H27V20.5714H20.5714V27ZM23.1429 12.8571V9H20.5714V15.4286H27V12.8571H23.1429Z" fill="white"/>
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.75 9H3V11.25H4.5V7.5H0.75V9ZM3 3H0.75V4.5H4.5V0.75H3V3ZM7.5 11.25H9V9H11.25V7.5H7.5V11.25ZM9 3V0.75H7.5V4.5H11.25V3H9Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 256 B |
@ -1,3 +1,3 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.5714 20.5714H9V27H15.4286V24.4286H11.5714V20.5714ZM9 15.4286H11.5714V11.5714H15.4286V9H9V15.4286ZM24.4286 24.4286H20.5714V27H27V20.5714H24.4286V24.4286ZM20.5714 9V11.5714H24.4286V15.4286H27V9H20.5714Z" fill="white"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.17857 8.92857H0.25V13.75H5.07143V11.8214H2.17857V8.92857ZM0.25 5.07143H2.17857V2.17857H5.07143V0.25H0.25V5.07143ZM11.8214 11.8214H8.92857V13.75H13.75V8.92857H11.8214V11.8214ZM8.92857 0.25V2.17857H11.8214V5.07143H13.75V0.25H8.92857Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 369 B |
@ -1,5 +1,4 @@
|
||||
<svg width="213" height="34" viewBox="0 0 213 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M86.5 0.549998H99.65C102.75 0.549998 105.133 0.783331 106.8 1.25C108.5 1.68333 109.7 2.4 110.4 3.4C111.1 4.36667 111.45 5.73333 111.45 7.5V11.5C111.45 12.4 111.083 13.25 110.35 14.05C109.65 14.85 108.817 15.4 107.85 15.7V15.95C109.117 16.0833 110.267 16.6333 111.3 17.6C112.367 18.5333 112.9 19.5833 112.9 20.75V25.75C112.9 28.3833 111.85 30.25 109.75 31.35C107.65 32.45 104.4 33 100 33H86.5V0.549998ZM99.65 13.75C100.883 13.75 101.8 13.65 102.4 13.45C103 13.25 103.4 12.9333 103.6 12.5C103.833 12.0333 103.95 11.3667 103.95 10.5V8.9C103.95 8.13333 103.85 7.56667 103.65 7.2C103.45 6.8 103.033 6.51667 102.4 6.35C101.8 6.18333 100.833 6.1 99.5 6.1H94.3V13.75H99.65ZM99.85 27.45C101.75 27.45 103.1 27.2333 103.9 26.8C104.7 26.3667 105.1 25.6667 105.1 24.7V22.1C105.1 20.9 104.783 20.05 104.15 19.55C103.55 19.05 102.467 18.8 100.9 18.8H94.3V27.45H99.85ZM126.838 0.549998H136.338L148.038 33H140.138L137.238 24.45H125.388L122.538 33H114.838L126.838 0.549998ZM135.538 19.25L131.438 7.05H131.238L127.138 19.25H135.538ZM165.987 33.5C164.52 33.5 163.203 33.4333 162.037 33.3C160.903 33.1667 159.653 32.9167 158.287 32.55C156.753 32.15 155.487 31.6333 154.487 31C153.487 30.3333 152.653 29.4167 151.987 28.25C151.287 27.0833 150.937 25.7 150.937 24.1V9.85C150.937 3.31666 155.953 0.049998 165.987 0.049998C168.553 0.049998 171.987 0.416665 176.287 1.15V7C172.42 6.06666 169.02 5.6 166.087 5.6C164.853 5.6 163.887 5.63333 163.187 5.7C162.52 5.76667 161.82 5.93333 161.087 6.2C159.52 6.73333 158.737 7.91666 158.737 9.75V23.55C158.737 26.4833 161.42 27.95 166.787 27.95C169.087 27.95 172.32 27.4667 176.487 26.5V32.4C172.92 33.1333 169.42 33.5 165.987 33.5ZM181.471 0.549998H189.271V33H181.471V0.549998ZM189.471 15.8L201.621 0.549998H210.771L198.471 15.65L212.121 33H202.621L189.471 15.8Z" fill="white"/>
|
||||
<svg width="70" height="30" viewBox="0 0 70 30" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="19" y1="15" x2="63" y2="15" stroke="white" stroke-width="8" stroke-linecap="round"/>
|
||||
<path d="M-6.99382e-07 15L24.75 1.1436L24.75 28.8564L-6.99382e-07 15Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 280 B |
@ -1,6 +1,4 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="250" height="250" rx="10" fill="white"/>
|
||||
<path d="M37.2949 201.711C37.1012 204.389 36.11 206.497 34.3213 208.035C32.5439 209.573 30.1969 210.342 27.2803 210.342C24.0902 210.342 21.578 209.271 19.7437 207.129C17.9207 204.976 17.0093 202.025 17.0093 198.276V196.755C17.0093 194.363 17.4308 192.255 18.2739 190.432C19.117 188.609 20.319 187.214 21.8799 186.245C23.4521 185.265 25.2751 184.775 27.3486 184.775C30.2197 184.775 32.5326 185.544 34.2871 187.083C36.0417 188.621 37.0557 190.78 37.3291 193.56H32.2021C32.0768 191.953 31.6268 190.791 30.8521 190.073C30.0887 189.344 28.9209 188.979 27.3486 188.979C25.6396 188.979 24.3579 189.595 23.5034 190.825C22.6603 192.044 22.2274 193.941 22.2046 196.516V198.396C22.2046 201.085 22.609 203.05 23.418 204.292C24.2383 205.534 25.5257 206.155 27.2803 206.155C28.8639 206.155 30.0431 205.796 30.8179 205.078C31.604 204.349 32.054 203.227 32.168 201.711H37.2949ZM60.9131 210H55.7861V199.336H45.7886V210H40.6616V185.117H45.7886V195.2H55.7861V185.117H60.9131V210ZM79.7632 204.873H70.7739L69.0649 210H63.6133L72.876 185.117H77.627L86.9409 210H81.4893L79.7632 204.873ZM72.1582 200.72H78.3789L75.2515 191.406L72.1582 200.72ZM94.3921 205.881H105.278V210H89.2651V185.117H94.3921V205.881ZM113.362 205.881H124.248V210H108.235V185.117H113.362V205.881ZM142.175 199.216H132.332V205.881H143.884V210H127.205V185.117H143.85V189.27H132.332V195.2H142.175V199.216ZM167.126 210H162L152.019 193.628V210H146.892V185.117H152.019L162.017 201.523V185.117H167.126V210ZM191.292 206.855C190.369 207.961 189.064 208.821 187.378 209.436C185.692 210.04 183.823 210.342 181.772 210.342C179.619 210.342 177.728 209.875 176.099 208.94C174.481 207.995 173.228 206.628 172.339 204.839C171.462 203.05 171.012 200.948 170.989 198.533V196.841C170.989 194.357 171.405 192.209 172.236 190.398C173.079 188.575 174.287 187.185 175.859 186.228C177.443 185.26 179.294 184.775 181.414 184.775C184.364 184.775 186.672 185.482 188.335 186.895C189.998 188.296 190.984 190.341 191.292 193.03H186.301C186.073 191.606 185.566 190.563 184.78 189.902C184.006 189.242 182.935 188.911 181.567 188.911C179.824 188.911 178.497 189.566 177.585 190.876C176.674 192.187 176.213 194.135 176.201 196.721V198.311C176.201 200.92 176.697 202.891 177.688 204.224C178.679 205.557 180.132 206.223 182.046 206.223C183.971 206.223 185.344 205.813 186.165 204.993V200.703H181.499V196.926H191.292V206.855ZM210.432 199.216H200.588V205.881H212.141V210H195.461V185.117H212.107V189.27H200.588V195.2H210.432V199.216ZM228.052 203.472C228.052 202.503 227.71 201.763 227.026 201.25C226.343 200.726 225.112 200.179 223.335 199.609C221.558 199.028 220.151 198.459 219.114 197.9C216.288 196.374 214.875 194.317 214.875 191.731C214.875 190.387 215.251 189.19 216.003 188.142C216.767 187.083 217.855 186.257 219.268 185.664C220.692 185.072 222.287 184.775 224.053 184.775C225.83 184.775 227.414 185.1 228.804 185.75C230.194 186.388 231.27 187.293 232.034 188.467C232.808 189.64 233.196 190.973 233.196 192.466H228.069C228.069 191.326 227.71 190.444 226.992 189.817C226.274 189.179 225.266 188.86 223.967 188.86C222.714 188.86 221.74 189.128 221.045 189.663C220.35 190.187 220.002 190.882 220.002 191.748C220.002 192.557 220.407 193.235 221.216 193.782C222.036 194.329 223.238 194.841 224.822 195.32C227.738 196.197 229.863 197.285 231.196 198.584C232.529 199.883 233.196 201.501 233.196 203.438C233.196 205.591 232.381 207.283 230.752 208.513C229.123 209.732 226.93 210.342 224.172 210.342C222.258 210.342 220.515 209.994 218.943 209.299C217.371 208.593 216.169 207.63 215.337 206.411C214.517 205.192 214.106 203.779 214.106 202.173H219.25C219.25 204.919 220.891 206.292 224.172 206.292C225.391 206.292 226.343 206.047 227.026 205.557C227.71 205.055 228.052 204.36 228.052 203.472Z" fill="black"/>
|
||||
<svg width="250" height="200" viewBox="0 0 250 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M116.01 154.44C116.01 154.44 108.49 95.93 164.98 94.3C164.98 99.46 164.98 101.89 164.98 101.89C164.98 101.89 119.25 98.0801 124.35 154.44" fill="black"/>
|
||||
<path d="M164.98 81.51V113.55L180.48 97.53L164.98 81.51Z" fill="black"/>
|
||||
<path d="M104 51.5H136.04L120.02 36L104 51.5Z" fill="black"/>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 472 B |
@ -1,6 +1,4 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="250" height="250" rx="10" fill="white"/>
|
||||
<path d="M59.6484 203.472C59.6484 202.503 59.3066 201.763 58.623 201.25C57.9395 200.726 56.709 200.179 54.9316 199.609C53.1543 199.028 51.7472 198.459 50.7104 197.9C47.8849 196.374 46.4722 194.317 46.4722 191.731C46.4722 190.387 46.8481 189.19 47.6001 188.142C48.3634 187.083 49.4515 186.257 50.8643 185.664C52.2884 185.072 53.8835 184.775 55.6494 184.775C57.4268 184.775 59.0104 185.1 60.4004 185.75C61.7904 186.388 62.867 187.293 63.6304 188.467C64.4051 189.64 64.7925 190.973 64.7925 192.466H59.6655C59.6655 191.326 59.3066 190.444 58.5889 189.817C57.8711 189.179 56.8628 188.86 55.564 188.86C54.3107 188.86 53.3366 189.128 52.6416 189.663C51.9466 190.187 51.5991 190.882 51.5991 191.748C51.5991 192.557 52.0036 193.235 52.8125 193.782C53.6328 194.329 54.8348 194.841 56.4185 195.32C59.3351 196.197 61.46 197.285 62.793 198.584C64.126 199.883 64.7925 201.501 64.7925 203.438C64.7925 205.591 63.9779 207.283 62.3486 208.513C60.7194 209.732 58.5262 210.342 55.769 210.342C53.855 210.342 52.1118 209.994 50.5396 209.299C48.9673 208.593 47.7653 207.63 46.9336 206.411C46.1133 205.192 45.7031 203.779 45.7031 202.173H50.8472C50.8472 204.919 52.4878 206.292 55.769 206.292C56.9881 206.292 57.9395 206.047 58.623 205.557C59.3066 205.055 59.6484 204.36 59.6484 203.472ZM82.3267 204.873H73.3374L71.6284 210H66.1768L75.4395 185.117H80.1904L89.5044 210H84.0527L82.3267 204.873ZM74.7217 200.72H80.9424L77.8149 191.406L74.7217 200.72ZM112.063 210H106.936L96.9556 193.628V210H91.8286V185.117H96.9556L106.953 201.523V185.117H112.063V210ZM116.541 210V185.117H124.197C126.384 185.117 128.338 185.613 130.059 186.604C131.79 187.584 133.14 188.985 134.109 190.808C135.077 192.62 135.562 194.682 135.562 196.995V198.14C135.562 200.452 135.083 202.509 134.126 204.309C133.18 206.109 131.842 207.505 130.11 208.496C128.378 209.487 126.424 209.989 124.248 210H116.541ZM121.667 189.27V205.881H124.146C126.151 205.881 127.683 205.226 128.743 203.916C129.802 202.606 130.343 200.732 130.366 198.293V196.978C130.366 194.448 129.842 192.534 128.794 191.235C127.746 189.925 126.213 189.27 124.197 189.27H121.667ZM139.304 210V185.117H148.02C151.039 185.117 153.329 185.698 154.89 186.86C156.451 188.011 157.231 189.703 157.231 191.936C157.231 193.155 156.918 194.232 156.292 195.166C155.665 196.089 154.793 196.767 153.677 197.2C154.953 197.519 155.955 198.162 156.685 199.131C157.425 200.099 157.795 201.284 157.795 202.686C157.795 205.078 157.032 206.89 155.505 208.12C153.979 209.351 151.803 209.977 148.977 210H139.304ZM144.431 199.165V205.881H148.823C150.031 205.881 150.971 205.597 151.643 205.027C152.327 204.446 152.668 203.648 152.668 202.634C152.668 200.356 151.489 199.199 149.131 199.165H144.431ZM144.431 195.542H148.225C150.811 195.496 152.104 194.465 152.104 192.449C152.104 191.321 151.774 190.512 151.113 190.022C150.464 189.521 149.433 189.27 148.02 189.27H144.431V195.542ZM182.097 198.123C182.097 200.572 181.664 202.72 180.798 204.565C179.932 206.411 178.691 207.835 177.073 208.838C175.466 209.84 173.621 210.342 171.536 210.342C169.473 210.342 167.633 209.846 166.016 208.855C164.398 207.864 163.145 206.451 162.256 204.617C161.367 202.771 160.917 200.652 160.906 198.259V197.029C160.906 194.579 161.344 192.426 162.222 190.569C163.11 188.7 164.358 187.271 165.964 186.279C167.582 185.277 169.428 184.775 171.501 184.775C173.575 184.775 175.415 185.277 177.021 186.279C178.639 187.271 179.887 188.7 180.764 190.569C181.653 192.426 182.097 194.574 182.097 197.012V198.123ZM176.902 196.995C176.902 194.386 176.435 192.403 175.5 191.047C174.566 189.692 173.233 189.014 171.501 189.014C169.781 189.014 168.454 189.686 167.52 191.03C166.585 192.363 166.112 194.323 166.101 196.909V198.123C166.101 200.663 166.568 202.634 167.502 204.036C168.437 205.437 169.781 206.138 171.536 206.138C173.256 206.138 174.578 205.465 175.5 204.121C176.423 202.765 176.89 200.794 176.902 198.208V196.995ZM194.351 193.696L199.016 185.117H204.912L197.666 197.456L205.1 210H199.136L194.351 201.284L189.565 210H183.601L191.035 197.456L183.789 185.117H189.685L194.351 193.696Z" fill="#030500"/>
|
||||
<svg width="250" height="200" viewBox="0 0 250 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M67.0202 97.9899C67.0202 97.9899 125.53 90.4699 127.16 146.96C122 146.96 119.57 146.96 119.57 146.96C119.57 146.96 123.38 101.23 67.0202 106.33" fill="black"/>
|
||||
<path d="M139.95 146.96L107.91 146.96L123.93 162.46L139.95 146.96Z" fill="black"/>
|
||||
<path d="M169.96 85.98L169.96 118.02L185.46 102L169.96 85.98Z" fill="black"/>
|
||||
@ -8,5 +6,4 @@
|
||||
<path d="M171.46 106.45C171.46 106.45 112.95 113.97 111.32 57.48C116.48 57.48 118.91 57.48 118.91 57.48C118.91 57.48 115.1 103.21 171.46 98.11" fill="black"/>
|
||||
<path d="M98.5298 57.48L130.57 57.48L114.55 41.98L98.5298 57.48Z" fill="black"/>
|
||||
<path d="M68.52 118.46L68.52 86.42L53.02 102.44L68.52 118.46Z" fill="black"/>
|
||||
<path d="M66.5298 98.0999L66.5298 106.78L171.46 106.78L171.46 98.0999L66.5298 98.0999Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 852 B |
@ -1,6 +1,4 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="250" height="250" rx="10" fill="white"/>
|
||||
<path d="M63.2202 189.27H55.5981V210H50.4712V189.27H42.9517V185.117H63.2202V189.27ZM84.9927 185.117V201.506C84.9927 204.229 84.1382 206.383 82.4292 207.966C80.7316 209.55 78.4074 210.342 75.4565 210.342C72.5513 210.342 70.2441 209.573 68.5352 208.035C66.8262 206.497 65.9546 204.383 65.9204 201.694V185.117H71.0474V201.541C71.0474 203.17 71.4347 204.36 72.2095 205.112C72.9956 205.853 74.078 206.223 75.4565 206.223C78.339 206.223 79.8031 204.708 79.8486 201.677V185.117H84.9927ZM107.927 189.27H100.305V210H95.1782V189.27H87.6587V185.117H107.927V189.27ZM130.828 198.123C130.828 200.572 130.395 202.72 129.529 204.565C128.663 206.411 127.421 207.835 125.803 208.838C124.197 209.84 122.351 210.342 120.266 210.342C118.204 210.342 116.364 209.846 114.746 208.855C113.128 207.864 111.875 206.451 110.986 204.617C110.098 202.771 109.648 200.652 109.636 198.259V197.029C109.636 194.579 110.075 192.426 110.952 190.569C111.841 188.7 113.088 187.271 114.695 186.279C116.313 185.277 118.158 184.775 120.232 184.775C122.306 184.775 124.146 185.277 125.752 186.279C127.37 187.271 128.617 188.7 129.495 190.569C130.383 192.426 130.828 194.574 130.828 197.012V198.123ZM125.632 196.995C125.632 194.386 125.165 192.403 124.231 191.047C123.297 189.692 121.964 189.014 120.232 189.014C118.512 189.014 117.184 189.686 116.25 191.03C115.316 192.363 114.843 194.323 114.832 196.909V198.123C114.832 200.663 115.299 202.634 116.233 204.036C117.167 205.437 118.512 206.138 120.266 206.138C121.986 206.138 123.308 205.465 124.231 204.121C125.154 202.765 125.621 200.794 125.632 198.208V196.995ZM143.765 200.891H139.68V210H134.553V185.117H143.799C146.738 185.117 149.006 185.772 150.601 187.083C152.196 188.393 152.993 190.244 152.993 192.637C152.993 194.334 152.623 195.753 151.882 196.892C151.153 198.02 150.042 198.92 148.55 199.592L153.933 209.761V210H148.43L143.765 200.891ZM139.68 196.738H143.816C145.103 196.738 146.1 196.414 146.807 195.764C147.513 195.103 147.866 194.198 147.866 193.047C147.866 191.873 147.53 190.951 146.858 190.278C146.197 189.606 145.177 189.27 143.799 189.27H139.68V196.738ZM162.358 210H157.231V185.117H162.358V210ZM181.482 204.873H172.493L170.784 210H165.332L174.595 185.117H179.346L188.66 210H183.208L181.482 204.873ZM173.877 200.72H180.098L176.97 191.406L173.877 200.72ZM196.111 205.881H206.997V210H190.984V185.117H196.111V205.881Z" fill="black"/>
|
||||
<rect x="44.5" y="40.5" width="153" height="95" fill="white" stroke="black" stroke-width="5"/>
|
||||
<svg width="250" height="200" viewBox="0 0 250 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="44.5" y="40.5" width="153" height="95" stroke="black" stroke-width="5"/>
|
||||
<path d="M105.25 69.7465L136 87.5L105.25 105.254L105.25 69.7465Z" fill="black" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 349 B |
@ -1,4 +1,3 @@
|
||||
<svg width="67" height="21" viewBox="0 0 67 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.25 7.01156H8.88214L11.0514 4.77891C8.89005 2.64126 5.39065 2.56209 3.22926 4.69974C1.06786 6.8453 1.06786 10.3051 3.22926 12.4507C5.39065 14.5962 8.89005 14.5962 11.0514 12.4507C12.1282 11.3898 12.6666 10.1468 12.6666 8.57917H14.25C14.25 10.1468 13.5533 12.1815 12.1599 13.5591C9.38092 16.3143 4.86812 16.3143 2.08918 13.5591C-0.681843 10.8118 -0.705594 6.34651 2.07334 3.59925C4.85228 0.851976 9.30967 0.851976 12.0886 3.59925L14.25 1.37451V7.01156ZM7.52038 5.33311V8.69792L10.2914 10.3447L9.72136 11.3027L6.3328 9.29171V5.33311H7.52038Z" fill="white"/>
|
||||
<path d="M24.394 4.90527V17.2817C24.394 19.4146 23.4268 20.481 21.4922 20.481C21.0752 20.481 20.689 20.4194 20.3335 20.2964V18.7788C20.5522 18.8335 20.8394 18.8608 21.1948 18.8608C21.6187 18.8608 21.9399 18.7446 22.1587 18.5122C22.3843 18.2866 22.4971 17.8901 22.4971 17.3228V4.90527H24.394ZM22.3022 1.9624C22.3022 1.66162 22.3945 1.40527 22.5791 1.19336C22.7705 0.974609 23.0474 0.865234 23.4097 0.865234C23.7788 0.865234 24.0591 0.971191 24.2505 1.18311C24.4419 1.39502 24.5376 1.65479 24.5376 1.9624C24.5376 2.27002 24.4419 2.52637 24.2505 2.73145C24.0591 2.93652 23.7788 3.03906 23.4097 3.03906C23.0405 3.03906 22.7637 2.93652 22.5791 2.73145C22.3945 2.52637 22.3022 2.27002 22.3022 1.9624ZM34.3096 14.9028C33.5713 15.771 32.4878 16.2051 31.0591 16.2051C29.8765 16.2051 28.9741 15.8633 28.3521 15.1797C27.7368 14.4893 27.4258 13.4707 27.4189 12.124V4.90527H29.3159V12.0728C29.3159 13.7544 29.9995 14.5952 31.3667 14.5952C32.8159 14.5952 33.7798 14.0552 34.2583 12.9751V4.90527H36.1553V16H34.3506L34.3096 14.9028ZM40.8311 4.90527L40.8823 6.13574C41.6958 5.17871 42.793 4.7002 44.1738 4.7002C45.7256 4.7002 46.7817 5.29492 47.3423 6.48438C47.7114 5.95117 48.1899 5.52051 48.7778 5.19238C49.3726 4.86426 50.0732 4.7002 50.8799 4.7002C53.3135 4.7002 54.5508 5.98877 54.5918 8.56592V16H52.6948V8.67871C52.6948 7.88574 52.5137 7.29443 52.1514 6.90479C51.7891 6.5083 51.1807 6.31006 50.3262 6.31006C49.6221 6.31006 49.0376 6.52197 48.5728 6.9458C48.1079 7.36279 47.8379 7.92676 47.7627 8.6377V16H45.8555V8.72998C45.8555 7.1167 45.0659 6.31006 43.4868 6.31006C42.2427 6.31006 41.3916 6.83984 40.9336 7.89941V16H39.0366V4.90527H40.8311ZM66.835 10.5757C66.835 12.2642 66.4487 13.6245 65.6763 14.6567C64.9038 15.689 63.8579 16.2051 62.5386 16.2051C61.1919 16.2051 60.1323 15.7778 59.3599 14.9233V20.2656H57.4629V4.90527H59.1958L59.2881 6.13574C60.0605 5.17871 61.1338 4.7002 62.5078 4.7002C63.8408 4.7002 64.8936 5.20264 65.666 6.20752C66.4453 7.2124 66.835 8.61035 66.835 10.4014V10.5757ZM64.938 10.3604C64.938 9.10938 64.6714 8.12158 64.1382 7.39697C63.605 6.67236 62.8735 6.31006 61.9438 6.31006C60.7954 6.31006 59.9341 6.81934 59.3599 7.83789V13.1392C59.9272 14.1509 60.7954 14.6567 61.9644 14.6567C62.8735 14.6567 63.5947 14.2979 64.1279 13.5801C64.668 12.8555 64.938 11.7822 64.938 10.3604Z" fill="white"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.75 5.59H8.665L10.72 3.475C8.6725 1.45 5.3575 1.375 3.31 3.4C1.2625 5.4325 1.2625 8.71 3.31 10.7425C5.3575 12.775 8.6725 12.775 10.72 10.7425C11.74 9.7375 12.25 8.56 12.25 7.075H13.75C13.75 8.56 13.09 10.4875 11.77 11.7925C9.1375 14.4025 4.8625 14.4025 2.23 11.7925C-0.394997 9.19 -0.417497 4.96 2.215 2.3575C4.8475 -0.245 9.07 -0.245 11.7025 2.3575L13.75 0.25V5.59ZM7.375 4V7.1875L10 8.7475L9.46 9.655L6.25 7.75V4H7.375Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 555 B |
@ -1,3 +1,3 @@
|
||||
<svg width="15" height="20" viewBox="0 0 15 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 17.5H5V0H0V17.5ZM10 0V17.5H15V0H10Z" fill="white"/>
|
||||
<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.5 11.25H3.5V0.75H0.5V11.25ZM6.5 0.75V11.25H9.5V0.75H6.5Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 167 B After Width: | Height: | Size: 190 B |
@ -1,4 +1,3 @@
|
||||
<svg width="68" height="16" viewBox="0 0 68 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.0833 7.125C11.0833 6.25417 10.3708 5.54167 9.5 5.54167C8.62917 5.54167 7.91667 6.25417 7.91667 7.125C7.91667 7.99583 8.62917 8.70833 9.5 8.70833C10.3708 8.70833 11.0833 7.99583 11.0833 7.125ZM9.5 0C5.56542 0 2.375 3.19042 2.375 7.125H0L3.16667 10.2917L6.33333 7.125H3.95833C3.95833 4.06125 6.43625 1.58333 9.5 1.58333C12.5638 1.58333 15.0417 4.06125 15.0417 7.125C15.0417 10.1888 12.5638 12.6667 9.5 12.6667C8.30458 12.6667 7.19625 12.2788 6.28583 11.6375L5.16167 12.7775C6.365 13.6958 7.86917 14.25 9.5 14.25C13.4346 14.25 16.625 11.0596 16.625 7.125C16.625 3.19042 13.4346 0 9.5 0Z" fill="white"/>
|
||||
<path d="M27.7983 5.60742C27.5112 5.55957 27.2002 5.53564 26.8652 5.53564C25.6211 5.53564 24.7769 6.06543 24.3325 7.125V15H22.4355V3.90527H24.2812L24.312 5.18701C24.9341 4.1958 25.8159 3.7002 26.9575 3.7002C27.3267 3.7002 27.6069 3.74805 27.7983 3.84375V5.60742ZM33.9507 15.2051C32.4468 15.2051 31.2231 14.7129 30.2798 13.7285C29.3364 12.7373 28.8647 11.4146 28.8647 9.76025V9.41162C28.8647 8.31104 29.0732 7.33008 29.4902 6.46875C29.9141 5.60059 30.502 4.92383 31.2539 4.43848C32.0127 3.94629 32.833 3.7002 33.7148 3.7002C35.1572 3.7002 36.2783 4.17529 37.0781 5.12549C37.8779 6.07568 38.2778 7.43604 38.2778 9.20654V9.99609H30.7617C30.7891 11.0898 31.1069 11.9751 31.7153 12.6519C32.3306 13.3218 33.1099 13.6567 34.0532 13.6567C34.7231 13.6567 35.2905 13.52 35.7554 13.2466C36.2202 12.9731 36.627 12.6108 36.9756 12.1597L38.1343 13.062C37.2046 14.4907 35.8101 15.2051 33.9507 15.2051ZM33.7148 5.25879C32.9492 5.25879 32.3066 5.53906 31.7871 6.09961C31.2676 6.65332 30.9463 7.43262 30.8232 8.4375H36.3809V8.29395C36.3262 7.33008 36.0664 6.58496 35.6016 6.05859C35.1367 5.52539 34.5078 5.25879 33.7148 5.25879ZM46.9424 12.0571C46.9424 11.5444 46.7476 11.1479 46.3579 10.8677C45.9751 10.5806 45.3018 10.3345 44.3379 10.1294C43.3809 9.92432 42.6187 9.67822 42.0513 9.39111C41.4907 9.104 41.0737 8.76221 40.8003 8.36572C40.5337 7.96924 40.4004 7.49756 40.4004 6.95068C40.4004 6.0415 40.7832 5.27246 41.5488 4.64355C42.3213 4.01465 43.3057 3.7002 44.502 3.7002C45.7598 3.7002 46.7783 4.0249 47.5576 4.67432C48.3438 5.32373 48.7368 6.1543 48.7368 7.16602H46.8296C46.8296 6.64648 46.6074 6.19873 46.1631 5.82275C45.7256 5.44678 45.1719 5.25879 44.502 5.25879C43.8115 5.25879 43.2715 5.40918 42.8818 5.70996C42.4922 6.01074 42.2974 6.40381 42.2974 6.88916C42.2974 7.34717 42.4785 7.69238 42.8408 7.9248C43.2031 8.15723 43.856 8.37939 44.7993 8.59131C45.7495 8.80322 46.5186 9.05615 47.1064 9.3501C47.6943 9.64404 48.1284 9.99951 48.4087 10.4165C48.6958 10.8267 48.8394 11.3291 48.8394 11.9238C48.8394 12.915 48.4429 13.7114 47.6499 14.313C46.8569 14.9077 45.8281 15.2051 44.5635 15.2051C43.6748 15.2051 42.8887 15.0479 42.2051 14.7334C41.5215 14.4189 40.9849 13.9814 40.5952 13.4209C40.2124 12.8535 40.021 12.2417 40.021 11.5854H41.918C41.9521 12.2212 42.2051 12.7271 42.6768 13.103C43.1553 13.4722 43.7842 13.6567 44.5635 13.6567C45.2812 13.6567 45.8555 13.5132 46.2861 13.2261C46.7236 12.9321 46.9424 12.5425 46.9424 12.0571ZM55.9146 15.2051C54.4106 15.2051 53.187 14.7129 52.2437 13.7285C51.3003 12.7373 50.8286 11.4146 50.8286 9.76025V9.41162C50.8286 8.31104 51.0371 7.33008 51.4541 6.46875C51.8779 5.60059 52.4658 4.92383 53.2178 4.43848C53.9766 3.94629 54.7969 3.7002 55.6787 3.7002C57.1211 3.7002 58.2422 4.17529 59.042 5.12549C59.8418 6.07568 60.2417 7.43604 60.2417 9.20654V9.99609H52.7256C52.7529 11.0898 53.0708 11.9751 53.6792 12.6519C54.2944 13.3218 55.0737 13.6567 56.0171 13.6567C56.687 13.6567 57.2544 13.52 57.7192 13.2466C58.1841 12.9731 58.5908 12.6108 58.9395 12.1597L60.0981 13.062C59.1685 14.4907 57.7739 15.2051 55.9146 15.2051ZM55.6787 5.25879C54.9131 5.25879 54.2705 5.53906 53.751 6.09961C53.2314 6.65332 52.9102 7.43262 52.7871 8.4375H58.3447V8.29395C58.29 7.33008 58.0303 6.58496 57.5654 6.05859C57.1006 5.52539 56.4717 5.25879 55.6787 5.25879ZM65.02 1.21875V3.90527H67.0913V5.37158H65.02V12.252C65.02 12.6963 65.1123 13.0312 65.2969 13.2568C65.4814 13.4756 65.7959 13.585 66.2402 13.585C66.459 13.585 66.7598 13.5439 67.1426 13.4619V15C66.6436 15.1367 66.1582 15.2051 65.6865 15.2051C64.8389 15.2051 64.1997 14.9487 63.769 14.436C63.3384 13.9233 63.123 13.1953 63.123 12.252V5.37158H61.103V3.90527H63.123V1.21875H65.02Z" fill="white"/>
|
||||
<svg width="12" height="16" viewBox="0 0 12 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.99988 3.75V0.75L2.24988 4.5L5.99988 8.25V5.25C8.48238 5.25 10.4999 7.2675 10.4999 9.75C10.4999 12.2325 8.48238 14.25 5.99988 14.25C3.51738 14.25 1.49988 12.2325 1.49988 9.75H-0.00012207C-0.00012207 13.065 2.68488 15.75 5.99988 15.75C9.31488 15.75 11.9999 13.065 11.9999 9.75C11.9999 6.435 9.31488 3.75 5.99988 3.75Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 449 B |
@ -1,3 +1,3 @@
|
||||
<svg width="15" height="20" viewBox="0 0 15 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0V19.0909L15 9.54545L0 0Z" fill="white"/>
|
||||
<svg width="9" height="12" viewBox="0 0 9 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0.75V11.25L8.25 6L0 0.75Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
@ -1 +1,3 @@
|
||||
<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="M7 10l5 5 5-5z"/></svg>
|
||||
<svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.25 0.5L4 4.25L7.75 0.5H0.25Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 152 B After Width: | Height: | Size: 158 B |
3
data/system/assets/tools/close.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.25 1.8075L10.1925 0.75L6 4.9425L1.8075 0.75L0.75 1.8075L4.9425 6L0.75 10.1925L1.8075 11.25L6 7.0575L10.1925 11.25L11.25 10.1925L7.0575 6L11.25 1.8075Z" fill="#F2F2F2"/>
|
||||
</svg>
|
After Width: | Height: | Size: 289 B |
@ -1,3 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 20V14H14V20H19V12H22L12 3L2 12H5V20H10Z" fill="#F2F2F2"/>
|
||||
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.5 13V8.5H9.5V13H13.25V7H15.5L8 0.25L0.5 7H2.75V13H6.5Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 192 B |
@ -1,3 +1,3 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.99 24.54L10.62 18.81L9 20.07L18 27.07L27 20.07L25.37 18.8L17.99 24.54ZM18 22L25.36 16.27L27 15L18 8L9 15L10.63 16.27L18 22Z" fill="white"/>
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.9925 12.905L1.465 8.6075L0.25 9.5525L7 14.8025L13.75 9.5525L12.5275 8.6L6.9925 12.905ZM7 11L12.52 6.7025L13.75 5.75L7 0.5L0.25 5.75L1.4725 6.7025L7 11Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 256 B After Width: | Height: | Size: 289 B |
@ -1,3 +1,3 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 10.1818C12.7855 10.1818 10.1818 12.7855 10.1818 16C10.1818 19.2145 12.7855 21.8182 16 21.8182C19.2145 21.8182 21.8182 19.2145 21.8182 16C21.8182 12.7855 19.2145 10.1818 16 10.1818ZM29.0036 14.5455C28.3345 8.48 23.52 3.66545 17.4545 2.99636V0H14.5455V2.99636C8.48 3.66545 3.66545 8.48 2.99636 14.5455H0V17.4545H2.99636C3.66545 23.52 8.48 28.3345 14.5455 29.0036V32H17.4545V29.0036C23.52 28.3345 28.3345 23.52 29.0036 17.4545H32V14.5455H29.0036V14.5455ZM16 26.1818C10.3709 26.1818 5.81818 21.6291 5.81818 16C5.81818 10.3709 10.3709 5.81818 16 5.81818C21.6291 5.81818 26.1818 10.3709 26.1818 16C26.1818 21.6291 21.6291 26.1818 16 26.1818Z" fill="white"/>
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 6C7.3425 6 6 7.3425 6 9C6 10.6575 7.3425 12 9 12C10.6575 12 12 10.6575 12 9C12 7.3425 10.6575 6 9 6ZM15.705 8.25C15.36 5.1225 12.8775 2.64 9.75 2.295V0.75H8.25V2.295C5.1225 2.64 2.64 5.1225 2.295 8.25H0.75V9.75H2.295C2.64 12.8775 5.1225 15.36 8.25 15.705V17.25H9.75V15.705C12.8775 15.36 15.36 12.8775 15.705 9.75H17.25V8.25H15.705ZM9 14.25C6.0975 14.25 3.75 11.9025 3.75 9C3.75 6.0975 6.0975 3.75 9 3.75C11.9025 3.75 14.25 6.0975 14.25 9C14.25 11.9025 11.9025 14.25 9 14.25Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 610 B |
@ -1,18 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<g filter="url(#filter0_f)">
|
||||
<path d="M15.375 2.25L15.255 2.2725L11.25 3.825L6.75 2.25L2.52 3.675C2.3625 3.7275 2.25 3.8625 2.25 4.035V15.375C2.25 15.585 2.415 15.75 2.625 15.75L2.745 15.7275L6.75 14.175L11.25 15.75L15.48 14.325C15.6375 14.2725 15.75 14.1375 15.75 13.965V2.625C15.75 2.415 15.585 2.25 15.375 2.25ZM11.25 14.25L6.75 12.6675V3.75L11.25 5.3325V14.25Z" fill="#EE702E"/>
|
||||
</g>
|
||||
<path d="M15.375 2.25L15.255 2.2725L11.25 3.825L6.75 2.25L2.52 3.675C2.3625 3.7275 2.25 3.8625 2.25 4.035V15.375C2.25 15.585 2.415 15.75 2.625 15.75L2.745 15.7275L6.75 14.175L11.25 15.75L15.48 14.325C15.6375 14.2725 15.75 14.1375 15.75 13.965V2.625C15.75 2.415 15.585 2.25 15.375 2.25ZM11.25 14.25L6.75 12.6675V3.75L11.25 5.3325V14.25Z" fill="#EE702E"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f" x="-0.75" y="-0.75" width="19.5" height="19.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="1.5" result="effect1_foregroundBlur"/>
|
||||
</filter>
|
||||
<clipPath id="clip0">
|
||||
<rect width="18" height="18" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.375 0.25L13.255 0.2725L9.25 1.825L4.75 0.25L0.52 1.675C0.3625 1.7275 0.25 1.8625 0.25 2.035V13.375C0.25 13.585 0.415 13.75 0.625 13.75L0.745 13.7275L4.75 12.175L9.25 13.75L13.48 12.325C13.6375 12.2725 13.75 12.1375 13.75 11.965V0.625C13.75 0.415 13.585 0.25 13.375 0.25ZM9.25 12.25L4.75 10.6675V1.75L9.25 3.3325V12.25Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 457 B |
@ -1,5 +1,4 @@
|
||||
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="-1.5" y="1.5" width="42" height="42" rx="21" transform="matrix(-1 0 0 1 42 0)" fill="white"/>
|
||||
<path d="M18.4533 29.12L24.56 23L18.4533 16.88L20.3333 15L28.3333 23L20.3333 31L18.4533 29.12Z" fill="black"/>
|
||||
<rect x="-1.5" y="1.5" width="42" height="42" rx="21" transform="matrix(-1 0 0 1 42 0)" stroke="black" stroke-width="3"/>
|
||||
<path d="M18.4533 29.12L24.56 23L18.4533 16.88L20.3333 15L28.3333 23L20.3333 31L18.4533 29.12Z" fill="black"/>
|
||||
<rect x="1.5" y="1.5" width="42" height="42" rx="21" stroke="black" stroke-width="3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 309 B |
@ -1,3 +1,3 @@
|
||||
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.6286 4.60305L19.6294 10.9236L6.59893 24.6485L1.24876 25.2706C0.532526 25.354 -0.072614 24.7161 0.0070714 23.9617L0.602368 18.3225L13.6286 4.60305ZM23.3408 3.66203L20.5233 0.69429C19.6444 -0.23143 18.2189 -0.23143 17.3401 0.69429L14.6893 3.48626L20.6901 9.80683L23.3408 7.01486C24.2197 6.08865 24.2197 4.58775 23.3408 3.66203Z" fill="white"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.25 10.9374V13.7499H3.0625L11.3575 5.45492L8.545 2.64242L0.25 10.9374ZM13.5325 3.27992C13.825 2.98742 13.825 2.51492 13.5325 2.22242L11.7775 0.467422C11.485 0.174922 11.0125 0.174922 10.72 0.467422L9.3475 1.83992L12.16 4.65242L13.5325 3.27992Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 380 B |
@ -1,5 +1,4 @@
|
||||
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1.5" y="1.5" width="42" height="42" rx="21" fill="white"/>
|
||||
<path d="M26.5466 29.12L20.44 23L26.5466 16.88L24.6666 15L16.6666 23L24.6666 31L26.5466 29.12Z" fill="black"/>
|
||||
<rect x="1.5" y="1.5" width="42" height="42" rx="21" stroke="black" stroke-width="3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 301 B |
@ -1,3 +1,4 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.5 20H20.71L20.43 19.73C21.41 18.59 22 17.11 22 15.5C22 11.91 19.09 9 15.5 9C11.91 9 9 11.91 9 15.5C9 19.09 11.91 22 15.5 22C17.11 22 18.59 21.41 19.73 20.43L20 20.71V21.5L25 26.49L26.49 25L21.5 20ZM15.5 20C13.01 20 11 17.99 11 15.5C11 13.01 13.01 11 15.5 11C17.99 11 20 13.01 20 15.5C20 17.99 17.99 20 15.5 20Z" fill="white"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.625 8.5H9.0325L8.8225 8.2975C9.5575 7.4425 10 6.3325 10 5.125C10 2.4325 7.8175 0.25 5.125 0.25C2.4325 0.25 0.25 2.4325 0.25 5.125C0.25 7.8175 2.4325 10 5.125 10C6.3325 10 7.4425 9.5575 8.2975 8.8225L8.5 9.0325V9.625L12.25 13.3675L13.3675 12.25L9.625 8.5ZM5.125 8.5C3.2575 8.5 1.75 6.9925 1.75 5.125C1.75 3.2575 3.2575 1.75 5.125 1.75C6.9925 1.75 8.5 3.2575 8.5 5.125C8.5 6.9925 6.9925 8.5 5.125 8.5Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 534 B |
@ -1,3 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.14 12.9359C19.176 12.6359 19.2 12.3239 19.2 11.9999C19.2 11.6759 19.176 11.3639 19.128 11.0639L21.156 9.4799C21.336 9.3359 21.384 9.0719 21.276 8.8679L19.356 5.5439C19.236 5.3279 18.984 5.2559 18.768 5.3279L16.38 6.2879C15.876 5.9039 15.348 5.5919 14.76 5.3519L14.4 2.8079C14.364 2.5679 14.16 2.3999 13.92 2.3999H10.08C9.83998 2.3999 9.64799 2.5679 9.61199 2.8079L9.25199 5.3519C8.66398 5.5919 8.12399 5.9159 7.63199 6.2879L5.24398 5.3279C5.02798 5.2439 4.77598 5.3279 4.65598 5.5439L2.73598 8.8679C2.61598 9.0839 2.66398 9.3359 2.85598 9.4799L4.88398 11.0639C4.83598 11.3639 4.79998 11.6879 4.79998 11.9999C4.79998 12.3119 4.82398 12.6359 4.87198 12.9359L2.84398 14.5199C2.66398 14.6639 2.61598 14.9279 2.72398 15.1319L4.64398 18.4559C4.76398 18.6719 5.01598 18.7439 5.23198 18.6719L7.61998 17.7119C8.12398 18.0959 8.65198 18.4079 9.23998 18.6479L9.59999 21.1919C9.64798 21.4319 9.83998 21.5999 10.08 21.5999H13.92C14.16 21.5999 14.364 21.4319 14.388 21.1919L14.748 18.6479C15.336 18.4079 15.876 18.0839 16.368 17.7119L18.756 18.6719C18.972 18.7559 19.224 18.6719 19.344 18.4559L21.264 15.1319C21.384 14.9159 21.336 14.6639 21.144 14.5199L19.14 12.9359ZM12 15.5999C10.02 15.5999 8.39998 13.9799 8.39998 11.9999C8.39998 10.0199 10.02 8.3999 12 8.3999C13.98 8.3999 15.6 10.0199 15.6 11.9999C15.6 13.9799 13.98 15.5999 12 15.5999Z" fill="#F2F2F2"/>
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.355 8.70181C12.382 8.47681 12.4 8.24281 12.4 7.99981C12.4 7.75681 12.382 7.52281 12.346 7.29781L13.867 6.10981C14.002 6.00181 14.038 5.8038 13.957 5.6508L12.517 3.1578C12.427 2.9958 12.238 2.9418 12.076 2.99581L10.285 3.7158C9.90702 3.4278 9.51102 3.1938 9.07002 3.0138L8.80002 1.1058C8.77302 0.925805 8.62002 0.799805 8.44002 0.799805H5.56002C5.38002 0.799805 5.23602 0.925805 5.20902 1.1058L4.93902 3.0138C4.49802 3.1938 4.09302 3.4368 3.72402 3.7158L1.93302 2.99581C1.77102 2.93281 1.58202 2.9958 1.49202 3.1578L0.0520189 5.6508C-0.0379811 5.81281 -0.00198095 6.00181 0.142019 6.10981L1.66302 7.29781C1.62702 7.52281 1.60002 7.76581 1.60002 7.99981C1.60002 8.23381 1.61802 8.47681 1.65402 8.70181L0.133019 9.88981C-0.00198117 9.99781 -0.0379811 10.1958 0.0430189 10.3488L1.48302 12.8418C1.57302 13.0038 1.76202 13.0578 1.92402 13.0038L3.71502 12.2838C4.09302 12.5718 4.48902 12.8058 4.93002 12.9858L5.20002 14.8938C5.23602 15.0738 5.38002 15.1998 5.56002 15.1998H8.44002C8.62002 15.1998 8.77302 15.0738 8.79102 14.8938L9.06102 12.9858C9.50202 12.8058 9.90702 12.5628 10.276 12.2838L12.067 13.0038C12.229 13.0668 12.418 13.0038 12.508 12.8418L13.948 10.3488C14.038 10.1868 14.002 9.99781 13.858 9.88981L12.355 8.70181ZM7.00002 10.6998C5.51502 10.6998 4.30002 9.48481 4.30002 7.99981C4.30002 6.51481 5.51502 5.29981 7.00002 5.29981C8.48502 5.29981 9.70002 6.51481 9.70002 7.99981C9.70002 9.48481 8.48502 10.6998 7.00002 10.6998Z" fill="#F2F2F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
@ -1,7 +1,8 @@
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::grey_out_map;
|
||||
use widgetry::{
|
||||
hotkeys, Btn, Color, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, Panel,
|
||||
RewriteColor, State, Text, Widget,
|
||||
hotkeys, Btn, Color, ControlState, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line,
|
||||
Outcome, Panel, State, Text, Widget,
|
||||
};
|
||||
|
||||
use crate::app::App;
|
||||
@ -168,34 +169,31 @@ fn make_panel(
|
||||
make_task: &Box<dyn Fn(&mut EventCtx) -> Widget>,
|
||||
idx: usize,
|
||||
) -> Panel {
|
||||
let prev = if idx > 0 {
|
||||
Btn::svg(
|
||||
"system/assets/tools/prev.svg",
|
||||
RewriteColor::Change(Color::WHITE, app.cs.hovering),
|
||||
)
|
||||
.build(ctx, "back", Key::LeftArrow)
|
||||
} else {
|
||||
Widget::draw_svg_transform(
|
||||
ctx,
|
||||
"system/assets/tools/prev.svg",
|
||||
RewriteColor::ChangeAlpha(0.3),
|
||||
)
|
||||
};
|
||||
let next = Btn::svg(
|
||||
"system/assets/tools/next.svg",
|
||||
RewriteColor::Change(Color::WHITE, app.cs.hovering),
|
||||
)
|
||||
.build(
|
||||
ctx,
|
||||
"next",
|
||||
hotkeys(vec![Key::RightArrow, Key::Space, Key::Enter]),
|
||||
);
|
||||
let mut prev = app
|
||||
.cs
|
||||
.btn_plain_dark_icon("system/assets/tools/prev.svg")
|
||||
.image_dims(45.0)
|
||||
.hotkey(Key::LeftArrow)
|
||||
.bg_color(Color::CLEAR, ControlState::Disabled);
|
||||
if idx == 0 {
|
||||
prev = prev.disabled();
|
||||
}
|
||||
let prev = prev.build_widget(ctx, "back");
|
||||
|
||||
let next = app
|
||||
.cs
|
||||
.btn_plain_dark_icon("system/assets/tools/next.svg")
|
||||
.image_dims(45.0)
|
||||
.hotkey(hotkeys(vec![Key::RightArrow, Key::Space, Key::Enter]))
|
||||
.build_widget(ctx, "next");
|
||||
|
||||
let inner = if idx == scenes.len() {
|
||||
Widget::custom_col(vec![
|
||||
(make_task)(ctx),
|
||||
Btn::txt("Start", Text::from(Line("Start").fg(Color::BLACK)))
|
||||
.build_def(ctx, Key::Enter)
|
||||
app.cs
|
||||
.btn_primary_light_text("Start")
|
||||
.hotkey(Key::Enter)
|
||||
.build_def(ctx)
|
||||
.centered_horiz()
|
||||
.align_bottom(),
|
||||
])
|
||||
@ -250,13 +248,11 @@ fn make_panel(
|
||||
}
|
||||
.margin_above(100),
|
||||
Widget::col(vec![
|
||||
Widget::row(vec![prev, next]).centered_horiz(),
|
||||
Btn::txt(
|
||||
"Skip cutscene",
|
||||
Text::from(Line("Skip cutscene").fg(Color::BLACK)),
|
||||
)
|
||||
.build_def(ctx, None)
|
||||
.centered_horiz(),
|
||||
Widget::row(vec![prev.margin_right(40), next]).centered_horiz(),
|
||||
app.cs
|
||||
.btn_secondary_dark_text("Skip cutscene")
|
||||
.build_def(ctx)
|
||||
.centered_horiz(),
|
||||
])
|
||||
.align_bottom(),
|
||||
])
|
||||
@ -265,8 +261,9 @@ fn make_panel(
|
||||
let col = vec![
|
||||
// TODO Can't get this to alignment to work
|
||||
Widget::custom_row(vec![
|
||||
Btn::svg_def("system/assets/pregame/back.svg")
|
||||
.build(ctx, "quit", None)
|
||||
app.cs
|
||||
.btn_back_light("Home")
|
||||
.build_widget(ctx, "quit")
|
||||
.margin_right(100),
|
||||
Line(name).big_heading_styled().draw(ctx),
|
||||
])
|
||||
|
@ -1,5 +1,9 @@
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::{MinimapControls, Navigator};
|
||||
use widgetry::{Btn, EventCtx, GfxCtx, HorizontalAlignment, Key, Panel, VerticalAlignment, Widget};
|
||||
use widgetry::{
|
||||
ControlState, EventCtx, GfxCtx, HorizontalAlignment, Key, Panel, ScreenDims, VerticalAlignment,
|
||||
Widget,
|
||||
};
|
||||
|
||||
use crate::app::App;
|
||||
use crate::app::Transition;
|
||||
@ -94,26 +98,35 @@ impl MinimapControls<App> for MinimapController {
|
||||
}
|
||||
|
||||
fn make_tool_panel(ctx: &mut EventCtx, app: &App) -> Widget {
|
||||
let buttons = app
|
||||
.cs
|
||||
.btn_primary_light()
|
||||
.image_dims(ScreenDims::square(20.0))
|
||||
// the default transparent button background is jarring for these buttons which are floating
|
||||
// in a transparent panel.
|
||||
.bg_color(app.cs.inner_panel, ControlState::Default)
|
||||
.padding(8);
|
||||
|
||||
Widget::col(vec![
|
||||
(if ctx.canvas.cam_zoom >= app.opts.min_zoom_for_detail {
|
||||
Btn::svg_def("system/assets/minimap/zoom_out_fully.svg").build(
|
||||
ctx,
|
||||
"zoom out fully",
|
||||
None,
|
||||
)
|
||||
buttons
|
||||
.clone()
|
||||
.image_path("system/assets/minimap/zoom_out_fully.svg")
|
||||
.build_widget(ctx, "zoom out fully")
|
||||
} else {
|
||||
Btn::svg_def("system/assets/minimap/zoom_in_fully.svg").build(
|
||||
ctx,
|
||||
"zoom in fully",
|
||||
None,
|
||||
)
|
||||
})
|
||||
.bg(app.cs.inner_panel),
|
||||
Btn::svg_def("system/assets/tools/layers.svg")
|
||||
.build(ctx, "change layers", Key::L)
|
||||
.bg(app.cs.inner_panel),
|
||||
Btn::svg_def("system/assets/tools/search.svg")
|
||||
.build(ctx, "search", Key::K)
|
||||
.bg(app.cs.inner_panel),
|
||||
buttons
|
||||
.clone()
|
||||
.image_path("system/assets/minimap/zoom_in_fully.svg")
|
||||
.build_widget(ctx, "zoom in fully")
|
||||
}),
|
||||
buttons
|
||||
.clone()
|
||||
.image_path("system/assets/tools/layers.svg")
|
||||
.hotkey(Key::L)
|
||||
.build_widget(ctx, "change layers"),
|
||||
buttons
|
||||
.image_path("system/assets/tools/search.svg")
|
||||
.hotkey(Key::K)
|
||||
.build_widget(ctx, "search"),
|
||||
])
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ use map_gui::ID;
|
||||
use map_model::{IntersectionID, Map, RoadID};
|
||||
use sim::{AgentType, TripMode, TripPhaseType};
|
||||
use widgetry::{
|
||||
lctrl, Btn, Checkbox, Color, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line,
|
||||
Panel, ScreenDims, ScreenPt, ScreenRectangle, Text, TextSpan, VerticalAlignment, Widget,
|
||||
lctrl, Checkbox, Color, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, Panel,
|
||||
ScreenDims, ScreenPt, ScreenRectangle, Text, TextSpan, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
pub use self::minimap::MinimapController;
|
||||
@ -14,6 +14,7 @@ pub use self::warp::Warping;
|
||||
use crate::app::App;
|
||||
use crate::app::Transition;
|
||||
use crate::info::{ContextualActions, InfoPanel, Tab};
|
||||
use map_gui::theme::StyledButtons;
|
||||
|
||||
mod minimap;
|
||||
mod warp;
|
||||
@ -288,10 +289,15 @@ impl CommonState {
|
||||
}
|
||||
|
||||
// TODO Kinda misnomer
|
||||
pub fn tool_panel(ctx: &mut EventCtx) -> Panel {
|
||||
pub fn tool_panel(ctx: &mut EventCtx, app: &App) -> Panel {
|
||||
Panel::new(Widget::row(vec![
|
||||
Btn::svg_def("system/assets/tools/home.svg").build(ctx, "back", Key::Escape),
|
||||
Btn::svg_def("system/assets/tools/settings.svg").build(ctx, "settings", None),
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/home.svg")
|
||||
.hotkey(Key::Escape)
|
||||
.build_widget(ctx, "back"),
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/settings.svg")
|
||||
.build_widget(ctx, "settings"),
|
||||
]))
|
||||
.aligned(HorizontalAlignment::Left, VerticalAlignment::BottomAboveOSD)
|
||||
.build(ctx)
|
||||
@ -366,15 +372,6 @@ pub fn color_for_trip_phase(app: &App, tpt: TripPhaseType) -> Color {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Well, there goes the nice consolidation of stuff in BtnBuilder. :\
|
||||
pub fn hotkey_btn<I: Into<String>>(ctx: &EventCtx, app: &App, label: I, key: Key) -> Widget {
|
||||
let label = label.into();
|
||||
let mut txt = Text::new();
|
||||
txt.append(key.txt(ctx));
|
||||
txt.append(Line(format!(" - {}", label)));
|
||||
Btn::text_bg(label, txt, app.cs.section_bg, app.cs.hovering).build_def(ctx, key)
|
||||
}
|
||||
|
||||
pub fn intersections_from_roads(roads: &BTreeSet<RoadID>, map: &Map) -> BTreeSet<IntersectionID> {
|
||||
let mut results = BTreeSet::new();
|
||||
for r in roads {
|
||||
|
@ -43,7 +43,7 @@ pub struct DebugMode {
|
||||
}
|
||||
|
||||
impl DebugMode {
|
||||
pub fn new(ctx: &mut EventCtx) -> Box<dyn State<App>> {
|
||||
pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State<App>> {
|
||||
Box::new(DebugMode {
|
||||
panel: Panel::new(Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
@ -84,7 +84,7 @@ impl DebugMode {
|
||||
.aligned(HorizontalAlignment::Right, VerticalAlignment::Top)
|
||||
.build(ctx),
|
||||
common: CommonState::new(),
|
||||
tool_panel: tool_panel(ctx),
|
||||
tool_panel: tool_panel(ctx, app),
|
||||
objects: objects::ObjectDebugger,
|
||||
hidden: HashSet::new(),
|
||||
layers: ShowLayers::new(),
|
||||
|
@ -60,7 +60,7 @@ impl EditMode {
|
||||
let edits = app.primary.map.get_edits();
|
||||
let layer = crate::layer::map::Static::edits(ctx, app);
|
||||
Box::new(EditMode {
|
||||
tool_panel: tool_panel(ctx),
|
||||
tool_panel: tool_panel(ctx, app),
|
||||
top_center: make_topcenter(ctx, app),
|
||||
changelist: make_changelist(ctx, app),
|
||||
orig_edits: edits.clone(),
|
||||
@ -171,7 +171,7 @@ impl State<App> for EditMode {
|
||||
}
|
||||
|
||||
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
||||
return Transition::Push(DebugMode::new(ctx));
|
||||
return Transition::Push(DebugMode::new(ctx, app));
|
||||
}
|
||||
|
||||
match self.top_center.event(ctx) {
|
||||
|
@ -193,7 +193,7 @@ fn header(
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(id.to_string()).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(
|
||||
|
@ -17,7 +17,7 @@ pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID)
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line("Bus stop").small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
rows.push(Line(&bs.name).draw(ctx));
|
||||
|
||||
@ -144,7 +144,7 @@ fn bus_header(
|
||||
))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
rows.push(make_tabs(
|
||||
ctx,
|
||||
@ -165,7 +165,7 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
|
||||
Line(format!("Route {}", route.short_name))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
rows.push(
|
||||
Text::from(Line(&route.full_name))
|
||||
|
@ -9,7 +9,7 @@ pub fn area(ctx: &EventCtx, app: &App, _: &mut Details, id: AreaID) -> Vec<Widge
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(id.to_string()).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
|
||||
let area = app.primary.map.get_a(id);
|
||||
|
@ -397,7 +397,7 @@ fn header(
|
||||
};
|
||||
rows.push(Widget::row(vec![
|
||||
Line(label).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(ctx, &mut details.hyperlinks, tab, {
|
||||
|
@ -249,7 +249,7 @@ fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID, tab: Tab
|
||||
Line(format!("{} #{}", label, id.0))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
rows.push(format!("@ {}", r.get_name(app.opts.language.as_ref())).draw_text(ctx));
|
||||
|
||||
|
@ -3,6 +3,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
pub use trip::OpenTrip;
|
||||
|
||||
use geom::{Circle, Distance, Time};
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::open_browser;
|
||||
use map_gui::ID;
|
||||
use map_model::{AreaID, BuildingID, BusRouteID, BusStopID, IntersectionID, LaneID, ParkingLotID};
|
||||
@ -16,7 +17,7 @@ use widgetry::{
|
||||
};
|
||||
|
||||
use crate::app::{App, Transition};
|
||||
use crate::common::{color_for_agent_type, hotkey_btn, Warping};
|
||||
use crate::common::{color_for_agent_type, Warping};
|
||||
use crate::debug::path_counter::PathCounter;
|
||||
use crate::edit::{EditMode, RouteEditor};
|
||||
use crate::sandbox::{dashboards, GameplayMode, SandboxMode, TimeWarpScreen};
|
||||
@ -372,7 +373,11 @@ impl InfoPanel {
|
||||
if let Some(id) = maybe_id.clone() {
|
||||
for (key, label) in ctx_actions.actions(app, id) {
|
||||
cached_actions.push(key);
|
||||
col.push(hotkey_btn(ctx, app, label, key));
|
||||
let button = app
|
||||
.cs
|
||||
.btn_hotkey_light(&label, key)
|
||||
.build_widget(ctx, &label);
|
||||
col.push(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -701,10 +706,13 @@ fn make_tabs(
|
||||
Widget::custom_row(row).bg(Color::WHITE).margin_vert(16)
|
||||
}
|
||||
|
||||
fn header_btns(ctx: &EventCtx) -> Widget {
|
||||
fn header_btns(ctx: &EventCtx, app: &App) -> Widget {
|
||||
Widget::row(vec![
|
||||
Btn::svg_def("system/assets/tools/location.svg").build(ctx, "jump to object", Key::J),
|
||||
Btn::close(ctx),
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.hotkey(Key::J)
|
||||
.build_widget(ctx, "jump to object"),
|
||||
app.cs.btn_close().build_widget(ctx, "close"),
|
||||
])
|
||||
.align_right()
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::app::App;
|
||||
use crate::info::{header_btns, make_tabs, Details, Tab};
|
||||
|
||||
pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: ParkingLotID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, details, id, Tab::ParkingLot(id));
|
||||
let mut rows = header(ctx, app, details, id, Tab::ParkingLot(id));
|
||||
let pl = app.primary.map.get_pl(id);
|
||||
let capacity = pl.capacity();
|
||||
|
||||
@ -60,11 +60,17 @@ pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: ParkingLot
|
||||
rows
|
||||
}
|
||||
|
||||
fn header(ctx: &EventCtx, details: &mut Details, id: ParkingLotID, tab: Tab) -> Vec<Widget> {
|
||||
fn header(
|
||||
ctx: &EventCtx,
|
||||
app: &App,
|
||||
details: &mut Details,
|
||||
id: ParkingLotID,
|
||||
tab: Tab,
|
||||
) -> Vec<Widget> {
|
||||
vec![
|
||||
Widget::row(vec![
|
||||
Line(id.to_string()).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]),
|
||||
make_tabs(
|
||||
ctx,
|
||||
|
@ -11,8 +11,8 @@ use sim::{
|
||||
TripMode, TripResult, VehicleType,
|
||||
};
|
||||
use widgetry::{
|
||||
Btn, Color, EdgeInsets, EventCtx, GeomBatch, Key, Line, RewriteColor, Text, TextExt, TextSpan,
|
||||
Widget,
|
||||
Btn, Color, ControlState, EdgeInsets, EventCtx, GeomBatch, Key, Line, RewriteColor,
|
||||
StyledButtons, Text, TextExt, TextSpan, Widget,
|
||||
};
|
||||
|
||||
use crate::app::App;
|
||||
@ -435,7 +435,7 @@ pub fn crowd(
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line("Pedestrian crowd").small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
header_btns(ctx, app),
|
||||
]));
|
||||
|
||||
for (idx, id) in members.into_iter().enumerate() {
|
||||
@ -483,17 +483,17 @@ pub fn parked_car(
|
||||
// Little indirect, but the handler of this action is actually the ContextualActions
|
||||
// for SandboxMode.
|
||||
if is_paused {
|
||||
Btn::svg_def("system/assets/tools/location.svg").build(
|
||||
ctx,
|
||||
"follow (run the simulation)",
|
||||
Key::F,
|
||||
)
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.hotkey(Key::F)
|
||||
.build_widget(ctx, "follow (run the simulation)")
|
||||
} else {
|
||||
// TODO Blink
|
||||
GeomBatch::load_svg(ctx, "system/assets/tools/location.svg")
|
||||
.color(RewriteColor::ChangeAll(Color::hex("#7FFA4D")))
|
||||
.to_btn(ctx)
|
||||
.build(ctx, "unfollow (pause the simulation)", Key::F)
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.image_color(Color::hex("#7FFA4D"), ControlState::Default)
|
||||
.hotkey(Key::F)
|
||||
.build_widget(ctx, "unfollow (pause the simulation)")
|
||||
},
|
||||
Btn::close(ctx),
|
||||
])
|
||||
@ -603,17 +603,17 @@ fn header(
|
||||
// Little indirect, but the handler of this action is actually the ContextualActions
|
||||
// for SandboxMode.
|
||||
if is_paused {
|
||||
Btn::svg_def("system/assets/tools/location.svg").build(
|
||||
ctx,
|
||||
"follow (run the simulation)",
|
||||
Key::F,
|
||||
)
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.hotkey(Key::F)
|
||||
.build_widget(ctx, "follow (run the simulation)")
|
||||
} else {
|
||||
// TODO Blink
|
||||
GeomBatch::load_svg(ctx, "system/assets/tools/location.svg")
|
||||
.color(RewriteColor::ChangeAll(Color::hex("#7FFA4D")))
|
||||
.to_btn(ctx)
|
||||
.build(ctx, "unfollow (pause the simulation)", Key::F)
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.image_color(Color::hex("#7FFA4D"), ControlState::Default)
|
||||
.hotkey(Key::F)
|
||||
.build_widget(ctx, "unfollow (pause the simulation)")
|
||||
},
|
||||
Btn::close(ctx),
|
||||
])
|
||||
|
@ -4,8 +4,8 @@ use widgetry::{
|
||||
};
|
||||
|
||||
use crate::app::{App, Transition};
|
||||
use crate::common::hotkey_btn;
|
||||
use crate::sandbox::dashboards;
|
||||
use map_gui::theme::StyledButtons;
|
||||
|
||||
mod elevation;
|
||||
pub mod favorites;
|
||||
@ -92,11 +92,11 @@ impl PickLayer {
|
||||
Some(ref l) => l.name().unwrap_or(""),
|
||||
};
|
||||
let btn = |name: &str, key| {
|
||||
let mut button = app.cs.btn_hotkey_light(name, key);
|
||||
if name == current {
|
||||
Btn::text_bg2(name).inactive(ctx)
|
||||
} else {
|
||||
hotkey_btn(ctx, app, name, key)
|
||||
button = button.disabled();
|
||||
}
|
||||
button.build_widget(ctx, name)
|
||||
};
|
||||
|
||||
col.push(btn("None", Key::N));
|
||||
|
@ -7,12 +7,13 @@ use rand_xorshift::XorShiftRng;
|
||||
use abstutil::Timer;
|
||||
use geom::{Duration, Line, Percent, Pt2D, Speed};
|
||||
use map_gui::load::MapLoader;
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::{open_browser, PopupMsg};
|
||||
use map_model::PermanentMapEdits;
|
||||
use sim::{AlertHandler, ScenarioGenerator, Sim, SimOptions};
|
||||
use widgetry::{
|
||||
hotkeys, Btn, Color, DrawBaselayer, EventCtx, GfxCtx, Key, Line, Outcome, Panel, RewriteColor,
|
||||
State, Text, UpdateType, Widget,
|
||||
hotkeys, Color, ContentMode, DrawBaselayer, EdgeInsets, EventCtx, Font, GfxCtx, Key, Line,
|
||||
Outcome, Panel, ScreenDims, State, Text, UpdateType, Widget,
|
||||
};
|
||||
|
||||
use crate::app::{App, Transition};
|
||||
@ -45,11 +46,10 @@ impl TitleScreen {
|
||||
Widget::draw_svg(ctx, "system/assets/pregame/logo.svg"),
|
||||
// TODO that nicer font
|
||||
// TODO Any key
|
||||
Btn::text_bg2("PLAY").build(
|
||||
ctx,
|
||||
"start game",
|
||||
hotkeys(vec![Key::Space, Key::Enter]),
|
||||
),
|
||||
app.cs
|
||||
.btn_primary_dark_text("Play")
|
||||
.hotkey(hotkeys(vec![Key::Space, Key::Enter]))
|
||||
.build_widget(ctx, "start game"),
|
||||
])
|
||||
.bg(app.cs.dialog_bg)
|
||||
.padding(16)
|
||||
@ -93,62 +93,86 @@ pub struct MainMenu {
|
||||
impl MainMenu {
|
||||
pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State<App>> {
|
||||
let col = vec![
|
||||
Btn::svg_def("system/assets/pregame/quit.svg")
|
||||
.build(ctx, "quit", Key::Escape)
|
||||
.align_left(),
|
||||
{
|
||||
let mut txt = Text::from(Line("A/B STREET").display_title());
|
||||
txt.add(Line("Created by Dustin Carlino, Yuwen Li, & Michael Kirk"));
|
||||
txt.draw(ctx).centered_horiz()
|
||||
},
|
||||
Widget::row(vec![
|
||||
Btn::svg(
|
||||
"system/assets/pregame/tutorial.svg",
|
||||
RewriteColor::Change(Color::WHITE, app.cs.hovering),
|
||||
)
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::T, "Tutorial");
|
||||
txt.add(Line("Learn how to play the game").small());
|
||||
txt
|
||||
})
|
||||
.build(ctx, "Tutorial", Key::T),
|
||||
Btn::svg(
|
||||
"system/assets/pregame/sandbox.svg",
|
||||
RewriteColor::Change(Color::WHITE, app.cs.hovering),
|
||||
)
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::S, "Sandbox");
|
||||
txt.add(Line("No goals, try out any idea here").small());
|
||||
txt
|
||||
})
|
||||
.build(ctx, "Sandbox mode", Key::S),
|
||||
Btn::svg(
|
||||
"system/assets/pregame/challenges.svg",
|
||||
RewriteColor::Change(Color::WHITE, app.cs.hovering),
|
||||
)
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::C, "Challenges");
|
||||
txt.add(Line("Fix specific problems").small());
|
||||
txt
|
||||
})
|
||||
.build(ctx, "Challenges", Key::C),
|
||||
])
|
||||
Widget::row({
|
||||
let btn_builder = app
|
||||
.cs
|
||||
.btn_primary_dark()
|
||||
.image_dims(ScreenDims::new(200.0, 100.0))
|
||||
.font_size(40)
|
||||
.font(Font::OverpassBold)
|
||||
// CLEANUP: There's some baked in padding with our current assets which is
|
||||
// probably not desirable, but we compensate for that here by applying
|
||||
// unequal padding
|
||||
.padding(EdgeInsets {
|
||||
top: 40.0,
|
||||
bottom: 40.0,
|
||||
left: 20.0,
|
||||
right: 20.0,
|
||||
})
|
||||
.image_content_mode(ContentMode::ScaleAspectFill)
|
||||
.vertical();
|
||||
vec![
|
||||
btn_builder
|
||||
.clone()
|
||||
.image_path("system/assets/pregame/tutorial.svg")
|
||||
.label_text("Tutorial")
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::T, "Tutorial");
|
||||
txt.add(Line("Learn how to play the game").small());
|
||||
txt
|
||||
})
|
||||
.hotkey(Key::T)
|
||||
.build_widget(ctx, "Tutorial"),
|
||||
btn_builder
|
||||
.clone()
|
||||
.image_path("system/assets/pregame/sandbox.svg")
|
||||
.label_text("Sandbox")
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::S, "Sandbox");
|
||||
txt.add(Line("No goals, try out any idea here").small());
|
||||
txt
|
||||
})
|
||||
.hotkey(Key::S)
|
||||
.build_widget(ctx, "Sandbox mode"),
|
||||
btn_builder
|
||||
.clone()
|
||||
.image_path("system/assets/pregame/challenges.svg")
|
||||
.label_text("Challenge")
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::C, "Challenges");
|
||||
txt.add(Line("Fix specific problems").small());
|
||||
txt
|
||||
})
|
||||
.hotkey(Key::C)
|
||||
.build_widget(ctx, "Challenges"),
|
||||
]
|
||||
})
|
||||
.centered(),
|
||||
Widget::row(vec![
|
||||
Btn::text_bg2("Community Proposals")
|
||||
app.cs
|
||||
.btn_secondary_light_text("Community Proposals")
|
||||
.tooltip({
|
||||
let mut txt = Text::tooltip(ctx, Key::P, "Community Proposals");
|
||||
txt.add(Line("See existing ideas for improving traffic").small());
|
||||
txt
|
||||
})
|
||||
.build_def(ctx, Key::P),
|
||||
Btn::text_bg2("Internal Dev Tools").build_def(ctx, Key::D),
|
||||
.hotkey(Key::P)
|
||||
.build_widget(ctx, "Community Proposals"),
|
||||
app.cs
|
||||
.btn_secondary_light_text("Internal Dev Tools")
|
||||
.hotkey(Key::D)
|
||||
.build_widget(ctx, "Internal Dev Tools"),
|
||||
])
|
||||
.centered(),
|
||||
Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Btn::text_bg2("About").build_def(ctx, None),
|
||||
Btn::text_bg2("Feedback").build_def(ctx, None),
|
||||
app.cs.btn_secondary_light_text("About").build_def(ctx),
|
||||
app.cs.btn_secondary_light_text("Feedback").build_def(ctx),
|
||||
]),
|
||||
built_info::time().draw(ctx),
|
||||
])
|
||||
@ -167,9 +191,6 @@ impl State<App> for MainMenu {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
match self.panel.event(ctx) {
|
||||
Outcome::Clicked(x) => match x.as_ref() {
|
||||
"quit" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
"Tutorial" => {
|
||||
return Tutorial::start(ctx, app);
|
||||
}
|
||||
@ -232,8 +253,10 @@ struct About {
|
||||
impl About {
|
||||
fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State<App>> {
|
||||
let col = vec![
|
||||
Btn::svg_def("system/assets/pregame/back.svg")
|
||||
.build(ctx, "back", Key::Escape)
|
||||
app.cs
|
||||
.btn_back_light("Home")
|
||||
.hotkey(Key::Escape)
|
||||
.build_widget(ctx, "back")
|
||||
.align_left(),
|
||||
{
|
||||
Text::from_multiline(vec![
|
||||
@ -264,8 +287,9 @@ impl About {
|
||||
.bg(app.cs.panel_bg)
|
||||
.padding(16)
|
||||
},
|
||||
Btn::text_bg2("See full credits")
|
||||
.build_def(ctx, None)
|
||||
app.cs
|
||||
.btn_primary_dark_text("See full credits")
|
||||
.build_def(ctx)
|
||||
.centered_horiz(),
|
||||
];
|
||||
|
||||
@ -337,19 +361,31 @@ impl Proposals {
|
||||
|
||||
if edits.proposal_link.is_some() {
|
||||
current_tab.push(
|
||||
Btn::text_bg2("Read detailed write-up")
|
||||
.build_def(ctx, None)
|
||||
app.cs
|
||||
.btn_primary_dark_text("Read detailed write-up")
|
||||
.build_def(ctx)
|
||||
.margin_below(10),
|
||||
);
|
||||
}
|
||||
current_tab.push(Btn::text_bg2("Try out this proposal").build_def(ctx, None));
|
||||
current_tab.push(
|
||||
app.cs
|
||||
.btn_primary_dark_text("Try out this proposal")
|
||||
.build_def(ctx),
|
||||
);
|
||||
|
||||
buttons.push(Btn::text_bg2(&edits.proposal_description[0]).inactive(ctx));
|
||||
buttons.push(
|
||||
app.cs
|
||||
.btn_primary_dark_text(&edits.proposal_description[0])
|
||||
.disabled()
|
||||
.build_def(ctx)
|
||||
.margin_below(10),
|
||||
);
|
||||
} else {
|
||||
buttons.push(
|
||||
Btn::text_bg2(&edits.proposal_description[0])
|
||||
app.cs
|
||||
.btn_primary_dark_text(&edits.proposal_description[0])
|
||||
.no_tooltip()
|
||||
.build(ctx, &name, None)
|
||||
.build_widget(ctx, &name)
|
||||
.margin_below(10),
|
||||
);
|
||||
}
|
||||
@ -375,8 +411,10 @@ impl Proposals {
|
||||
Box::new(Proposals {
|
||||
proposals,
|
||||
panel: Panel::new(Widget::custom_col(vec![
|
||||
Btn::svg_def("system/assets/pregame/back.svg")
|
||||
.build(ctx, "back", Key::Escape)
|
||||
app.cs
|
||||
.btn_back_light("Home")
|
||||
.hotkey(Key::Escape)
|
||||
.build_widget(ctx, "back")
|
||||
.align_left()
|
||||
.margin_below(20),
|
||||
Widget::col(col).bg(app.cs.panel_bg).padding(16),
|
||||
|
@ -4,7 +4,7 @@ use geom::{Duration, Time};
|
||||
use sim::{OrigPersonID, PersonID, TripID};
|
||||
use widgetry::{
|
||||
Btn, Color, EventCtx, GfxCtx, HorizontalAlignment, Line, Outcome, Panel, RewriteColor, State,
|
||||
Text, TextExt, VerticalAlignment, Widget,
|
||||
StyledButtons, Text, TextExt, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::app::App;
|
||||
@ -250,7 +250,9 @@ fn make_meter(
|
||||
Panel::new(Widget::col(vec![
|
||||
Widget::horiz_separator(ctx, 0.2),
|
||||
Widget::row(vec![
|
||||
Btn::svg_def("system/assets/tools/location.svg").build(ctx, "locate VIP", None),
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.build_widget(ctx, "locate VIP"),
|
||||
format!("{}/{} trips done", done, trips).draw_text(ctx),
|
||||
txt.draw(ctx),
|
||||
]),
|
||||
|
@ -3,7 +3,7 @@ use map_gui::ID;
|
||||
use map_model::IntersectionID;
|
||||
use widgetry::{
|
||||
Btn, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, RewriteColor,
|
||||
State, Text, VerticalAlignment, Widget,
|
||||
State, StyledButtons, Text, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::app::Transition;
|
||||
@ -306,8 +306,9 @@ fn make_meter(ctx: &mut EventCtx, app: &App, worst: Option<(IntersectionID, Dura
|
||||
}),
|
||||
])
|
||||
.draw(ctx),
|
||||
Btn::svg_def("system/assets/tools/location.svg")
|
||||
.build(ctx, "go to slowest intersection", None)
|
||||
app.cs
|
||||
.btn_plain_light_icon("system/assets/tools/location.svg")
|
||||
.build_widget(ctx, "go to slowest intersection")
|
||||
.align_right(),
|
||||
])
|
||||
} else {
|
||||
|
@ -3,6 +3,7 @@ use rand::Rng;
|
||||
|
||||
use abstutil::Timer;
|
||||
use geom::{Distance, Polygon};
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::{
|
||||
grey_out_map, nice_map_name, open_browser, CityPicker, PopupMsg, PromptInput,
|
||||
};
|
||||
@ -106,23 +107,28 @@ impl GameplayState for Freeform {
|
||||
Line("Sandbox").small_heading().draw(ctx),
|
||||
Widget::vert_separator(ctx, 50.0),
|
||||
"Map:".draw_text(ctx),
|
||||
Btn::pop_up(ctx, Some(nice_map_name(app.primary.map.get_name()))).build(
|
||||
ctx,
|
||||
"change map",
|
||||
lctrl(Key::L),
|
||||
),
|
||||
app.cs
|
||||
.btn_popup_light(nice_map_name(app.primary.map.get_name()))
|
||||
.hotkey(lctrl(Key::L))
|
||||
.build_widget(ctx, "change map"),
|
||||
"Scenario:".draw_text(ctx),
|
||||
Btn::pop_up(ctx, Some("none")).build(ctx, "change scenario", Key::S),
|
||||
Btn::svg_def("system/assets/tools/edit_map.svg").build(
|
||||
ctx,
|
||||
"edit map",
|
||||
lctrl(Key::E),
|
||||
),
|
||||
app.cs
|
||||
.btn_popup_light("none")
|
||||
.hotkey(Key::S)
|
||||
.build_widget(ctx, "change scenario"),
|
||||
app.cs
|
||||
.btn_secondary_light_icon_text("system/assets/tools/pencil.svg", "Edit map")
|
||||
.hotkey(lctrl(Key::E))
|
||||
.build_widget(ctx, "edit map"),
|
||||
])
|
||||
.centered(),
|
||||
Widget::row(vec![
|
||||
Btn::text_fg("Start a new trip").build_def(ctx, None),
|
||||
Btn::text_fg("Record trips as a scenario").build_def(ctx, None),
|
||||
app.cs
|
||||
.btn_secondary_light_text("Start a new trip")
|
||||
.build_def(ctx),
|
||||
app.cs
|
||||
.btn_secondary_light_text("Record trips as a scenario")
|
||||
.build_def(ctx),
|
||||
])
|
||||
.centered(),
|
||||
Text::from_all(vec![
|
||||
|
@ -2,6 +2,7 @@ use std::collections::BTreeSet;
|
||||
|
||||
use maplit::btreeset;
|
||||
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::{grey_out_map, nice_map_name, ChooseSomething, CityPicker, PopupMsg};
|
||||
use sim::{ScenarioModifier, TripMode};
|
||||
use widgetry::{
|
||||
@ -115,29 +116,30 @@ impl GameplayState for PlayScenario {
|
||||
Line("Sandbox").small_heading().draw(ctx),
|
||||
Widget::vert_separator(ctx, 50.0),
|
||||
"Map:".draw_text(ctx),
|
||||
Btn::pop_up(ctx, Some(nice_map_name(app.primary.map.get_name()))).build(
|
||||
ctx,
|
||||
"change map",
|
||||
lctrl(Key::L),
|
||||
),
|
||||
app.cs
|
||||
.btn_popup_light(nice_map_name(app.primary.map.get_name()))
|
||||
.hotkey(lctrl(Key::L))
|
||||
.build_widget(ctx, "change map"),
|
||||
"Scenario:".draw_text(ctx),
|
||||
Btn::pop_up(ctx, Some(&self.scenario_name)).build(ctx, "change scenario", Key::S),
|
||||
Btn::svg_def("system/assets/tools/edit_map.svg").build(
|
||||
ctx,
|
||||
"edit map",
|
||||
lctrl(Key::E),
|
||||
),
|
||||
app.cs
|
||||
.btn_popup_light(&self.scenario_name)
|
||||
.hotkey(Key::S)
|
||||
.build_widget(ctx, "change scenario"),
|
||||
app.cs
|
||||
.btn_secondary_light_icon_text("system/assets/tools/pencil.svg", "Edit map")
|
||||
.hotkey(lctrl(Key::E))
|
||||
.build_widget(ctx, "edit map"),
|
||||
])
|
||||
.centered(),
|
||||
if self.scenario_name != "empty" {
|
||||
Widget::row(vec![
|
||||
Btn::svg_def("system/assets/tools/pencil.svg").build(
|
||||
ctx,
|
||||
"edit traffic patterns",
|
||||
None,
|
||||
),
|
||||
app.cs
|
||||
.btn_primary_light_icon("system/assets/tools/pencil.svg")
|
||||
.build_widget(ctx, "edit traffic patterns")
|
||||
.centered_vert(),
|
||||
format!("{} modifications to traffic patterns", self.modifiers.len())
|
||||
.draw_text(ctx),
|
||||
.draw_text(ctx)
|
||||
.centered_vert(),
|
||||
])
|
||||
.centered_horiz()
|
||||
} else {
|
||||
|
@ -895,7 +895,7 @@ impl TutorialState {
|
||||
fire_station: app.primary.map.find_b_by_osm_id(bldg(731238736)).unwrap(),
|
||||
};
|
||||
|
||||
let tool_panel = tool_panel(ctx);
|
||||
let tool_panel = tool_panel(ctx, app);
|
||||
let time = TimePanel::new(ctx, app);
|
||||
let speed = SpeedControls::new(ctx, app);
|
||||
let agent_meter = AgentMeter::new(ctx, app);
|
||||
|
@ -7,6 +7,7 @@ use map_gui::colors::ColorSchemeChoice;
|
||||
use map_gui::load::{FileLoader, MapLoader};
|
||||
use map_gui::options::OptionsPanel;
|
||||
use map_gui::render::{unzoomed_agent_radius, UnzoomedAgents};
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::{ChooseSomething, Minimap, PopupMsg, TurnExplorer};
|
||||
use map_gui::{AppLike, ID};
|
||||
use sim::{Analytics, Scenario};
|
||||
@ -134,7 +135,7 @@ impl State<App> for SandboxMode {
|
||||
|
||||
// Order here is pretty arbitrary
|
||||
if app.opts.dev && ctx.input.pressed(lctrl(Key::D)) {
|
||||
return Transition::Push(DebugMode::new(ctx));
|
||||
return Transition::Push(DebugMode::new(ctx, app));
|
||||
}
|
||||
|
||||
if let Some(ref mut m) = self.controls.minimap {
|
||||
@ -430,8 +431,10 @@ impl AgentMeter {
|
||||
} else {
|
||||
Widget::nothing()
|
||||
},
|
||||
Btn::svg_def("system/assets/meters/trip_histogram.svg")
|
||||
.build(ctx, "more data", Key::Q)
|
||||
app.cs
|
||||
.btn_primary_light_icon("system/assets/meters/trip_histogram.svg")
|
||||
.hotkey(Key::Q)
|
||||
.build_widget(ctx, "more data")
|
||||
.align_right(),
|
||||
]),
|
||||
];
|
||||
@ -894,7 +897,7 @@ impl SandboxControls {
|
||||
None
|
||||
},
|
||||
tool_panel: if gameplay.has_tool_panel() {
|
||||
Some(tool_panel(ctx))
|
||||
Some(tool_panel(ctx, app))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@ -923,7 +926,7 @@ impl SandboxControls {
|
||||
|
||||
fn recreate_panels(&mut self, ctx: &mut EventCtx, app: &App) {
|
||||
if self.tool_panel.is_some() {
|
||||
self.tool_panel = Some(tool_panel(ctx));
|
||||
self.tool_panel = Some(tool_panel(ctx, app));
|
||||
}
|
||||
if let Some(ref mut speed) = self.speed {
|
||||
speed.recreate_panel(ctx, app);
|
||||
|
@ -1,10 +1,11 @@
|
||||
use geom::{Duration, Polygon, Time};
|
||||
use map_gui::theme::StyledButtons;
|
||||
use map_gui::tools::PopupMsg;
|
||||
use map_gui::ID;
|
||||
use sim::AlertLocation;
|
||||
use widgetry::{
|
||||
Btn, Choice, Color, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, Outcome,
|
||||
Panel, PersistentSplit, RewriteColor, Text, VerticalAlignment, Widget,
|
||||
Choice, Color, ControlState, EdgeInsets, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key,
|
||||
Line, Outcome, Panel, PersistentSplit, ScreenDims, Text, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::app::{App, Transition};
|
||||
@ -44,17 +45,21 @@ impl SpeedControls {
|
||||
|
||||
pub fn recreate_panel(&mut self, ctx: &mut EventCtx, app: &App) {
|
||||
let mut row = Vec::new();
|
||||
row.push(
|
||||
if self.paused {
|
||||
Btn::svg_def("system/assets/speed/triangle.svg").build(ctx, "play", Key::Space)
|
||||
row.push({
|
||||
let button = app
|
||||
.cs
|
||||
.btn_primary_light_icon("system/assets/speed/triangle.svg")
|
||||
.hotkey(Key::Space);
|
||||
|
||||
Widget::custom_row(vec![if self.paused {
|
||||
button.build_widget(ctx, "play")
|
||||
} else {
|
||||
Btn::svg_def("system/assets/speed/pause.svg").build(ctx, "pause", Key::Space)
|
||||
}
|
||||
.container()
|
||||
.padding(9)
|
||||
.bg(app.cs.section_bg)
|
||||
.margin_right(16),
|
||||
);
|
||||
button
|
||||
.image_path("system/assets/speed/pause.svg")
|
||||
.build_widget(ctx, "pause")
|
||||
}])
|
||||
.margin_right(16)
|
||||
});
|
||||
|
||||
row.push(
|
||||
Widget::custom_row(
|
||||
@ -70,27 +75,49 @@ impl SpeedControls {
|
||||
txt.extend(Text::tooltip(ctx, Key::LeftArrow, "slow down"));
|
||||
txt.extend(Text::tooltip(ctx, Key::RightArrow, "speed up"));
|
||||
|
||||
GeomBatch::load_svg(ctx, "system/assets/speed/triangle.svg")
|
||||
.color(if self.setting >= s {
|
||||
RewriteColor::NoOp
|
||||
} else {
|
||||
RewriteColor::ChangeAll(Color::WHITE.alpha(0.2))
|
||||
})
|
||||
.to_btn(ctx)
|
||||
let mut triangle_btn = app
|
||||
.cs
|
||||
.btn_plain_light()
|
||||
.image_path("system/assets/speed/triangle.svg")
|
||||
.image_dims(ScreenDims::new(16.0, 22.0))
|
||||
.bg_color(
|
||||
app.cs.gui_style.btn_primary_light.bg_hover,
|
||||
ControlState::Hovered,
|
||||
)
|
||||
.tooltip(txt)
|
||||
.build(ctx, label, None)
|
||||
.margin_right(6)
|
||||
.padding(EdgeInsets {
|
||||
top: 8.0,
|
||||
bottom: 8.0,
|
||||
left: 3.0,
|
||||
right: 3.0,
|
||||
});
|
||||
|
||||
if s == SpeedSetting::Realtime {
|
||||
triangle_btn = triangle_btn.padding_left(10.0);
|
||||
}
|
||||
if s == SpeedSetting::Fastest {
|
||||
triangle_btn = triangle_btn.padding_right(10.0);
|
||||
}
|
||||
|
||||
if self.setting < s {
|
||||
triangle_btn = triangle_btn.image_color(
|
||||
app.cs.gui_style.btn_secondary_light.fg_disabled,
|
||||
ControlState::Default,
|
||||
)
|
||||
}
|
||||
|
||||
triangle_btn.build_widget(ctx, label)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.bg(app.cs.section_bg)
|
||||
.centered()
|
||||
.padding(6)
|
||||
// Inner buttons, styled as one composite button w/ background/border
|
||||
.bg(app.cs.gui_style.btn_primary_light.bg)
|
||||
.outline(2.0, app.cs.gui_style.btn_primary_light.outline)
|
||||
.margin_right(16),
|
||||
);
|
||||
|
||||
row.push(
|
||||
PersistentSplit::new(
|
||||
PersistentSplit::widget(
|
||||
ctx,
|
||||
"step forwards",
|
||||
app.opts.time_increment,
|
||||
@ -102,22 +129,37 @@ impl SpeedControls {
|
||||
Choice::new("+0.1s", Duration::seconds(0.1)),
|
||||
],
|
||||
)
|
||||
.bg(app.cs.section_bg)
|
||||
.margin_right(16),
|
||||
);
|
||||
|
||||
row.push(
|
||||
Widget::custom_row(vec![
|
||||
Btn::svg_def("system/assets/speed/jump_to_time.svg")
|
||||
.build(ctx, "jump to specific time", Key::B)
|
||||
.container()
|
||||
.padding(9),
|
||||
Btn::svg_def("system/assets/speed/reset.svg")
|
||||
.build(ctx, "reset to midnight", Key::X)
|
||||
.container()
|
||||
.padding(9),
|
||||
])
|
||||
.bg(app.cs.section_bg),
|
||||
{
|
||||
let buttons = app
|
||||
.cs
|
||||
.btn_plain_light()
|
||||
.bg_color(
|
||||
app.cs.gui_style.btn_primary_light.bg_hover,
|
||||
ControlState::Hovered,
|
||||
)
|
||||
.font_size(18)
|
||||
.image_dims(ScreenDims::square(20.0));
|
||||
Widget::custom_row(vec![
|
||||
buttons
|
||||
.clone()
|
||||
.label_text("jump")
|
||||
.image_path("system/assets/speed/jump_to_time.svg")
|
||||
.hotkey(Key::B)
|
||||
.build_widget(ctx, "jump to specific time"),
|
||||
buttons
|
||||
.label_text("reset")
|
||||
.image_path("system/assets/speed/reset.svg")
|
||||
.hotkey(Key::X)
|
||||
.build_widget(ctx, "reset to midnight"),
|
||||
])
|
||||
}
|
||||
// Inner buttons, styled as one composite button w/ background/border
|
||||
.bg(app.cs.gui_style.btn_primary_light.bg)
|
||||
.outline(2.0, app.cs.gui_style.btn_primary_light.outline),
|
||||
);
|
||||
|
||||
self.panel = Panel::new(Widget::custom_row(row))
|
||||
|
@ -146,6 +146,10 @@ impl Polygon {
|
||||
self.transform(|pt| Pt2D::new(pt.x() * factor, pt.y() * factor))
|
||||
}
|
||||
|
||||
pub fn scale_xy(&self, x_factor: f64, y_factor: f64) -> Polygon {
|
||||
self.transform(|pt| Pt2D::new(pt.x() * x_factor, pt.y() * y_factor))
|
||||
}
|
||||
|
||||
pub fn rotate(&self, angle: Angle) -> Polygon {
|
||||
self.rotate_around(angle, self.center())
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ pub mod load;
|
||||
pub mod options;
|
||||
pub mod render;
|
||||
mod simple_app;
|
||||
pub mod theme;
|
||||
pub mod tools;
|
||||
|
||||
/// An application wishing to use the tools in this crate has to implement this on the struct that
|
||||
|
@ -118,7 +118,7 @@ impl DrawBuilding {
|
||||
// Things closer to the isometric axis should appear in front of things farther
|
||||
// away, so we give them a higher z-index.
|
||||
//
|
||||
// Naively, we compute the entire building's distance as the distance from it's
|
||||
// Naively, we compute the entire building's distance as the distance from its
|
||||
// closest point. This is simple and usually works, but will likely fail on more
|
||||
// complex building arrangements, e.g. if a building were tightly encircled by a
|
||||
// large building.
|
||||
|
34
map_gui/src/theme/mod.rs
Normal file
@ -0,0 +1,34 @@
|
||||
pub use widgetry::StyledButtons;
|
||||
use widgetry::{ButtonBuilder, Key};
|
||||
|
||||
// This impl just delegates to the underlying impl on self.gui_style so we can more succinctly write
|
||||
// `app.cs.btn_primary_dark()` rather than `app.cs.gui_style.btn_primary_dark()`
|
||||
impl<'a> StyledButtons<'a> for crate::ColorScheme {
|
||||
fn btn_primary_dark(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_primary_dark()
|
||||
}
|
||||
|
||||
fn btn_secondary_dark(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_secondary_dark()
|
||||
}
|
||||
|
||||
fn btn_primary_light(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_primary_light()
|
||||
}
|
||||
|
||||
fn btn_secondary_light(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_secondary_light()
|
||||
}
|
||||
|
||||
fn btn_plain_dark(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_plain_dark()
|
||||
}
|
||||
|
||||
fn btn_plain_light(&self) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_plain_light()
|
||||
}
|
||||
|
||||
fn btn_hotkey_light(&self, label: &str, key: Key) -> ButtonBuilder<'a> {
|
||||
self.gui_style.btn_hotkey_light(label, key)
|
||||
}
|
||||
}
|
@ -416,12 +416,12 @@ impl MultiKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lctrl(key: Key) -> Option<MultiKey> {
|
||||
Some(MultiKey::LCtrl(key))
|
||||
pub fn lctrl(key: Key) -> MultiKey {
|
||||
MultiKey::LCtrl(key)
|
||||
}
|
||||
|
||||
pub fn hotkeys(keys: Vec<Key>) -> Option<MultiKey> {
|
||||
Some(MultiKey::Any(keys))
|
||||
pub fn hotkeys(keys: Vec<Key>) -> MultiKey {
|
||||
MultiKey::Any(keys)
|
||||
}
|
||||
|
||||
impl std::convert::From<Key> for Option<MultiKey> {
|
||||
@ -429,3 +429,9 @@ impl std::convert::From<Key> for Option<MultiKey> {
|
||||
Some(MultiKey::Normal(key))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Key> for MultiKey {
|
||||
fn from(key: Key) -> MultiKey {
|
||||
MultiKey::Normal(key)
|
||||
}
|
||||
}
|
||||
|
@ -205,14 +205,19 @@ impl GeomBatch {
|
||||
}
|
||||
|
||||
/// Scales the batch by some factor.
|
||||
pub fn scale(mut self, factor: f64) -> GeomBatch {
|
||||
if factor == 1.0 {
|
||||
pub fn scale(self, factor: f64) -> GeomBatch {
|
||||
self.scale_xy(factor, factor)
|
||||
}
|
||||
|
||||
pub fn scale_xy(mut self, x_factor: f64, y_factor: f64) -> GeomBatch {
|
||||
if x_factor == 1.0 && y_factor == 1.0 {
|
||||
return self;
|
||||
}
|
||||
|
||||
for (_, poly, _) in &mut self.list {
|
||||
// strip_rings first -- sometimes when scaling down, the original rings collapse. Since
|
||||
// this polygon is part of a GeomBatch anyway, not calling to_outline on it.
|
||||
*poly = poly.strip_rings().scale(factor);
|
||||
*poly = poly.strip_rings().scale_xy(x_factor, y_factor);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ pub use crate::geom::{GeomBatch, RewriteColor};
|
||||
pub use crate::input::UserInput;
|
||||
pub use crate::runner::{run, Settings};
|
||||
pub use crate::screen_geom::{ScreenDims, ScreenPt, ScreenRectangle};
|
||||
pub use crate::style::Style;
|
||||
pub use crate::text::{Line, Text, TextExt, TextSpan};
|
||||
pub use crate::style::{buttons::StyledButtons, Style};
|
||||
pub use crate::text::{Font, Line, Text, TextExt, TextSpan};
|
||||
pub use crate::tools::warper::Warper;
|
||||
pub use crate::tools::Cached;
|
||||
pub use crate::widgets::autocomplete::Autocomplete;
|
||||
pub(crate) use crate::widgets::button::Button;
|
||||
pub use crate::widgets::button::{Btn, MultiButton};
|
||||
pub use crate::widgets::button::{Btn, ButtonBuilder, MultiButton};
|
||||
pub use crate::widgets::checkbox::Checkbox;
|
||||
pub use crate::widgets::compare_times::CompareTimes;
|
||||
pub(crate) use crate::widgets::dropdown::Dropdown;
|
||||
@ -93,6 +93,40 @@ mod backend {
|
||||
pub use crate::backend_glow::*;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ControlState {
|
||||
Default,
|
||||
Hovered,
|
||||
Disabled,
|
||||
// TODO: Pressing
|
||||
}
|
||||
|
||||
/// Rules for how content should stretch to fill its bounds
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ContentMode {
|
||||
/// Stretches content to fit its bounds exactly, breaking aspect ratio as necessary.
|
||||
ScaleToFill,
|
||||
|
||||
/// Maintaining aspect ratio, content grows until it touches its bounds in one dimension.
|
||||
/// This is the default ContentMode.
|
||||
///
|
||||
/// If the aspect ratio of the bounds do not exactly match the aspect ratio of the content,
|
||||
/// then there will be some empty space within the bounds to center the content.
|
||||
ScaleAspectFit,
|
||||
|
||||
/// Maintaining aspect ratio, content grows until both bounds are met.
|
||||
///
|
||||
/// If the aspect ratio of the bounds do not exactly match the aspect ratio of the content,
|
||||
/// the content will overflow one dimension of its bounds.
|
||||
ScaleAspectFill,
|
||||
}
|
||||
|
||||
impl Default for ContentMode {
|
||||
fn default() -> Self {
|
||||
ContentMode::ScaleAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Choice<T> {
|
||||
pub label: String,
|
||||
pub data: T,
|
||||
@ -127,8 +161,8 @@ impl<T> Choice<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn multikey(mut self, mk: Option<MultiKey>) -> Choice<T> {
|
||||
self.hotkey = mk;
|
||||
pub fn multikey(mut self, mk: MultiKey) -> Choice<T> {
|
||||
self.hotkey = Some(mk);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@ impl ScreenRectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// REVIEW: Rename to something shorter? e.g. Dims / Size
|
||||
/// ScreenDims is in units of logical pixels, as opposed to physical pixels.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ScreenDims {
|
||||
@ -112,6 +113,10 @@ impl ScreenDims {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn square(square: f64) -> Self {
|
||||
Self::new(square, square)
|
||||
}
|
||||
|
||||
pub fn top_left_for_corner(&self, corner: ScreenPt, canvas: &Canvas) -> ScreenPt {
|
||||
// TODO Ideally also avoid covered canvas areas
|
||||
if corner.x + self.width < canvas.window_width {
|
||||
@ -154,3 +159,9 @@ impl From<ScreenDims> for winit::dpi::LogicalSize<f64> {
|
||||
winit::dpi::LogicalSize::new(dims.width, dims.height)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for ScreenDims {
|
||||
fn from(square: f64) -> ScreenDims {
|
||||
ScreenDims::square(square)
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
use crate::{Color, Text};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Style {
|
||||
pub outline_thickness: f64,
|
||||
pub outline_color: Color,
|
||||
pub panel_bg: Color,
|
||||
pub hotkey_color: Color,
|
||||
pub hovering_color: Color,
|
||||
pub loading_tips: Text,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn standard() -> Style {
|
||||
Style {
|
||||
outline_thickness: 2.0,
|
||||
outline_color: Color::WHITE,
|
||||
panel_bg: Color::grey(0.4),
|
||||
hotkey_color: Color::GREEN,
|
||||
hovering_color: Color::ORANGE,
|
||||
loading_tips: Text::new(),
|
||||
}
|
||||
}
|
||||
}
|
217
widgetry/src/style/buttons.rs
Normal file
@ -0,0 +1,217 @@
|
||||
use super::ButtonStyle;
|
||||
use crate::{ButtonBuilder, ControlState, ScreenDims, Style};
|
||||
|
||||
pub trait StyledButtons<'a> {
|
||||
fn btn_primary_dark(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_primary_dark_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_primary_dark().label_text(text)
|
||||
}
|
||||
fn btn_primary_dark_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_primary_dark().image_path(image_path))
|
||||
}
|
||||
fn btn_primary_dark_icon_text(&self, image_path: &'a str, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_primary_dark()
|
||||
.label_text(text)
|
||||
.image_path(image_path)
|
||||
.image_dims(ScreenDims::square(18.0))
|
||||
}
|
||||
|
||||
fn btn_secondary_dark(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_secondary_dark_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_dark().label_text(text)
|
||||
}
|
||||
fn btn_secondary_dark_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_secondary_dark().image_path(image_path))
|
||||
}
|
||||
fn btn_secondary_dark_icon_text(
|
||||
&self,
|
||||
image_path: &'a str,
|
||||
text: &'a str,
|
||||
) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_dark()
|
||||
.label_text(text)
|
||||
.image_path(image_path)
|
||||
.image_dims(ScreenDims::square(18.0))
|
||||
}
|
||||
|
||||
fn btn_primary_light(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_primary_light_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_primary_light().label_text(text)
|
||||
}
|
||||
fn btn_primary_light_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_primary_light().image_path(image_path))
|
||||
}
|
||||
fn btn_primary_light_icon_text(&self, image_path: &'a str, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_primary_light()
|
||||
.label_text(text)
|
||||
.image_path(image_path)
|
||||
.image_dims(ScreenDims::square(18.0))
|
||||
}
|
||||
|
||||
fn btn_secondary_light(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_secondary_light_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_light().label_text(text)
|
||||
}
|
||||
fn btn_secondary_light_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_secondary_light().image_path(image_path))
|
||||
}
|
||||
fn btn_secondary_light_icon_text(
|
||||
&self,
|
||||
image_path: &'a str,
|
||||
text: &'a str,
|
||||
) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_light()
|
||||
.label_text(text)
|
||||
.image_path(image_path)
|
||||
.image_dims(ScreenDims::square(18.0))
|
||||
}
|
||||
|
||||
fn btn_plain_dark(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_plain_dark_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_plain_dark().label_text(text)
|
||||
}
|
||||
fn btn_plain_dark_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_plain_dark().image_path(image_path))
|
||||
}
|
||||
|
||||
fn btn_plain_light(&self) -> ButtonBuilder<'a>;
|
||||
fn btn_plain_light_text(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_plain_light().label_text(text)
|
||||
}
|
||||
fn btn_plain_light_icon(&self, image_path: &'a str) -> ButtonBuilder<'a> {
|
||||
icon_button(self.btn_plain_light().image_path(image_path))
|
||||
}
|
||||
|
||||
// Specific UI Elements
|
||||
|
||||
/// title: name of previous screen, which you'll return to
|
||||
fn btn_back_light(&self, title: &'a str) -> ButtonBuilder<'a> {
|
||||
back_button(self.btn_plain_light(), title)
|
||||
}
|
||||
|
||||
/// title: name of previous screen, which you'll return to
|
||||
fn btn_back_dark(&self, title: &'a str) -> ButtonBuilder<'a> {
|
||||
back_button(self.btn_plain_dark(), title)
|
||||
}
|
||||
|
||||
fn btn_primary_light_dropdown(&self) -> ButtonBuilder<'a> {
|
||||
dropdown_button(self.btn_primary_light())
|
||||
}
|
||||
|
||||
fn btn_secondary_light_dropdown(&self) -> ButtonBuilder<'a> {
|
||||
dropdown_button(self.btn_secondary_light())
|
||||
}
|
||||
|
||||
fn btn_primary_dark_dropdown(&self) -> ButtonBuilder<'a> {
|
||||
dropdown_button(self.btn_primary_dark())
|
||||
}
|
||||
|
||||
fn btn_secondary_dark_dropdown(&self) -> ButtonBuilder<'a> {
|
||||
dropdown_button(self.btn_secondary_dark())
|
||||
}
|
||||
|
||||
fn btn_popup_light(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_light_dropdown().label_text(text)
|
||||
}
|
||||
|
||||
fn btn_popup_dark(&self, text: &'a str) -> ButtonBuilder<'a> {
|
||||
self.btn_secondary_dark_dropdown().label_text(text)
|
||||
}
|
||||
|
||||
fn btn_close(&self) -> ButtonBuilder<'a> {
|
||||
self.btn_plain_light_icon("system/assets/tools/close.svg")
|
||||
}
|
||||
|
||||
fn btn_hotkey_light(&self, label: &str, key: Key) -> ButtonBuilder<'a>;
|
||||
}
|
||||
|
||||
use crate::{Key, Line, Text};
|
||||
impl<'a> StyledButtons<'a> for Style {
|
||||
fn btn_hotkey_light(&self, label: &str, key: Key) -> ButtonBuilder<'a> {
|
||||
let default = {
|
||||
let mut txt = Text::new();
|
||||
let key_txt = Line(key.describe()).fg(self.hotkey_color);
|
||||
txt.append(key_txt);
|
||||
let label_text = Line(format!(" - {}", label)).fg(self.btn_primary_light.fg);
|
||||
txt.append(label_text);
|
||||
txt
|
||||
};
|
||||
|
||||
let disabled = {
|
||||
let mut txt = Text::new();
|
||||
let key_txt = Line(key.describe()).fg(self.hotkey_color.alpha(0.3));
|
||||
txt.append(key_txt);
|
||||
let label_text = Line(format!(" - {}", label)).fg(self.btn_primary_light.fg_disabled);
|
||||
txt.append(label_text);
|
||||
txt
|
||||
};
|
||||
|
||||
self.btn_primary_light()
|
||||
.label_styled_text(default, ControlState::Default)
|
||||
.label_styled_text(disabled, ControlState::Disabled)
|
||||
.hotkey(key)
|
||||
}
|
||||
|
||||
fn btn_primary_dark(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_primary_dark;
|
||||
plain_builder(colors).outline(2.0, colors.outline, ControlState::Default)
|
||||
}
|
||||
|
||||
fn btn_secondary_dark(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_secondary_dark;
|
||||
plain_builder(colors).outline(2.0, colors.outline, ControlState::Default)
|
||||
}
|
||||
|
||||
fn btn_plain_dark(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_secondary_dark;
|
||||
plain_builder(colors)
|
||||
}
|
||||
|
||||
fn btn_primary_light(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_primary_light;
|
||||
plain_builder(colors).outline(2.0, colors.outline, ControlState::Default)
|
||||
}
|
||||
|
||||
fn btn_secondary_light(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_secondary_light;
|
||||
plain_builder(colors).outline(2.0, colors.outline, ControlState::Default)
|
||||
}
|
||||
|
||||
fn btn_plain_light(&self) -> ButtonBuilder<'a> {
|
||||
let colors = &self.btn_secondary_light;
|
||||
plain_builder(colors)
|
||||
}
|
||||
}
|
||||
|
||||
fn plain_builder<'a>(color_scheme: &ButtonStyle) -> ButtonBuilder<'a> {
|
||||
ButtonBuilder::new()
|
||||
.label_color(color_scheme.fg, ControlState::Default)
|
||||
.label_color(color_scheme.fg_disabled, ControlState::Disabled)
|
||||
.image_color(color_scheme.fg, ControlState::Default)
|
||||
.image_color(color_scheme.fg_disabled, ControlState::Disabled)
|
||||
.bg_color(color_scheme.bg, ControlState::Default)
|
||||
.bg_color(color_scheme.bg_hover, ControlState::Hovered)
|
||||
.bg_color(color_scheme.bg_disabled, ControlState::Disabled)
|
||||
}
|
||||
|
||||
// Captures some constants for uniform styling of icon-only buttons
|
||||
fn icon_button<'a>(builder: ButtonBuilder<'a>) -> ButtonBuilder<'a> {
|
||||
builder.padding(8.0).image_dims(20.0)
|
||||
}
|
||||
|
||||
fn back_button<'a>(builder: ButtonBuilder<'a>, title: &'a str) -> ButtonBuilder<'a> {
|
||||
// DESIGN REVIEW: this button seems absurdly large
|
||||
builder
|
||||
.image_path("system/assets/pregame/back.svg")
|
||||
.label_text(title)
|
||||
.padding_left(8.0)
|
||||
.font_size(30)
|
||||
}
|
||||
|
||||
fn dropdown_button<'a>(builder: ButtonBuilder<'a>) -> ButtonBuilder<'a> {
|
||||
builder
|
||||
.image_path("system/assets/tools/arrow_drop_down.svg")
|
||||
.image_dims(12.0)
|
||||
.stack_spacing(12.0)
|
||||
.label_first()
|
||||
}
|
79
widgetry/src/style/mod.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use crate::{Color, Text};
|
||||
|
||||
pub mod buttons;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Style {
|
||||
pub outline_thickness: f64,
|
||||
pub outline_color: Color,
|
||||
pub panel_bg: Color,
|
||||
pub hotkey_color: Color,
|
||||
pub hovering_color: Color,
|
||||
pub loading_tips: Text,
|
||||
pub btn_primary_dark: ButtonStyle,
|
||||
pub btn_secondary_dark: ButtonStyle,
|
||||
pub btn_primary_light: ButtonStyle,
|
||||
pub btn_secondary_light: ButtonStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ButtonStyle {
|
||||
pub fg: Color,
|
||||
pub fg_disabled: Color,
|
||||
pub outline: Color,
|
||||
pub bg: Color,
|
||||
pub bg_hover: Color,
|
||||
pub bg_disabled: Color,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn standard() -> Style {
|
||||
Style {
|
||||
outline_thickness: 2.0,
|
||||
outline_color: Color::WHITE,
|
||||
panel_bg: Color::grey(0.4),
|
||||
hotkey_color: Color::GREEN,
|
||||
hovering_color: Color::ORANGE,
|
||||
loading_tips: Text::new(),
|
||||
|
||||
// Buttons
|
||||
btn_primary_dark: ButtonStyle {
|
||||
fg: hex("#4C4C4C"),
|
||||
fg_disabled: hex("#4C4C4C").alpha(0.3),
|
||||
bg: Color::WHITE.alpha(0.8),
|
||||
bg_hover: Color::WHITE,
|
||||
bg_disabled: Color::grey(0.6),
|
||||
outline: Color::WHITE.alpha(0.6),
|
||||
},
|
||||
btn_secondary_dark: ButtonStyle {
|
||||
fg: hex("#4C4C4C"),
|
||||
fg_disabled: hex("#4C4C4C").alpha(0.3),
|
||||
bg: Color::CLEAR,
|
||||
bg_hover: hex("#4C4C4C").alpha(0.1),
|
||||
bg_disabled: Color::grey(0.8),
|
||||
outline: hex("#4C4C4C"),
|
||||
},
|
||||
btn_primary_light: ButtonStyle {
|
||||
fg: hex("#F2F2F2"),
|
||||
fg_disabled: hex("#F2F2F2").alpha(0.3),
|
||||
bg: hex("#003046").alpha(0.8),
|
||||
bg_hover: hex("#003046"),
|
||||
bg_disabled: Color::grey(0.1),
|
||||
outline: hex("#003046").alpha(0.6),
|
||||
},
|
||||
btn_secondary_light: ButtonStyle {
|
||||
fg: hex("#F2F2F2"),
|
||||
fg_disabled: hex("#F2F2F2").alpha(0.3),
|
||||
bg: Color::CLEAR,
|
||||
bg_hover: hex("#F2F2F2").alpha(0.1),
|
||||
bg_disabled: Color::grey(0.9),
|
||||
outline: hex("#F2F2F2"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience
|
||||
fn hex(x: &str) -> Color {
|
||||
Color::hex(x)
|
||||
}
|
@ -129,6 +129,16 @@ impl TextSpan {
|
||||
self.underlined = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: usize) -> TextSpan {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn font(mut self, font: Font) -> TextSpan {
|
||||
self.font = font;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// TODO What's the better way of doing this? Also "Line" is a bit of a misnomer
|
||||
@ -440,9 +450,9 @@ fn render_line(spans: Vec<TextSpan>, tolerance: f32, assets: &Assets) -> GeomBat
|
||||
for span in spans {
|
||||
write!(
|
||||
&mut contents,
|
||||
r##"<tspan fill="{}" {}>{}</tspan>"##,
|
||||
// TODO Doesn't support alpha
|
||||
r##"<tspan fill="{}" fill-opacity="{}" {}>{}</tspan>"##,
|
||||
span.fg_color.to_hex(),
|
||||
span.fg_color.a,
|
||||
if span.underlined {
|
||||
"text-decoration=\"underline\""
|
||||
} else {
|
||||
@ -523,7 +533,7 @@ impl TextSpan {
|
||||
- (Text::from(Line(&self.text)).dims(assets).width * scale) / 2.0;
|
||||
write!(
|
||||
&mut svg,
|
||||
r##"<text xml:space="preserve" font-size="{}" font-family="{}" {} fill="{}" startOffset="{}">"##,
|
||||
r##"<text xml:space="preserve" font-size="{}" font-family="{}" {} fill="{}" fill-opacity="{}" startOffset="{}">"##,
|
||||
// This is seemingly the easiest way to do this. We could .scale() the whole batch
|
||||
// after, but then we have to re-translate it to the proper spot
|
||||
(self.size as f64) * scale,
|
||||
@ -534,6 +544,7 @@ impl TextSpan {
|
||||
_ => "",
|
||||
},
|
||||
self.fg_color.to_hex(),
|
||||
self.fg_color.a,
|
||||
start_offset,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1,18 +1,20 @@
|
||||
use geom::{Distance, Polygon};
|
||||
|
||||
use crate::{
|
||||
svg, Color, Drawable, EdgeInsets, EventCtx, GeomBatch, GfxCtx, Key, Line, MultiKey, Outcome,
|
||||
RewriteColor, ScreenDims, ScreenPt, ScreenRectangle, Text, Widget, WidgetImpl, WidgetOutput,
|
||||
svg, text::Font, Color, ContentMode, ControlState, Drawable, EdgeInsets, EventCtx, GeomBatch,
|
||||
GfxCtx, Key, Line, MultiKey, Outcome, RewriteColor, ScreenDims, ScreenPt, ScreenRectangle,
|
||||
Text, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
pub struct Button {
|
||||
/// When a button is clicked, `Outcome::Clicked` with this string is produced.
|
||||
pub action: String,
|
||||
|
||||
// Both of these must have the same dimensions and are oriented with their top-left corner at
|
||||
// These must have the same dimensions and are oriented with their top-left corner at
|
||||
// 0, 0. Transformation happens later.
|
||||
draw_normal: Drawable,
|
||||
draw_hovered: Drawable,
|
||||
draw_disabled: Drawable,
|
||||
|
||||
pub(crate) hotkey: Option<MultiKey>,
|
||||
tooltip: Text,
|
||||
@ -20,30 +22,58 @@ pub struct Button {
|
||||
hitbox: Polygon,
|
||||
|
||||
pub(crate) hovering: bool,
|
||||
is_disabled: bool,
|
||||
|
||||
pub(crate) top_left: ScreenPt,
|
||||
pub(crate) dims: ScreenDims,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
fn new(
|
||||
fn widget(
|
||||
ctx: &EventCtx,
|
||||
normal: GeomBatch,
|
||||
hovered: GeomBatch,
|
||||
disabled: GeomBatch,
|
||||
hotkey: Option<MultiKey>,
|
||||
action: &str,
|
||||
maybe_tooltip: Option<Text>,
|
||||
hitbox: Polygon,
|
||||
is_disabled: bool,
|
||||
) -> Widget {
|
||||
Widget::new(Box::new(Self::new(
|
||||
ctx,
|
||||
normal,
|
||||
hovered,
|
||||
disabled,
|
||||
hotkey,
|
||||
action,
|
||||
maybe_tooltip,
|
||||
hitbox,
|
||||
is_disabled,
|
||||
)))
|
||||
.named(action)
|
||||
}
|
||||
|
||||
fn new(
|
||||
ctx: &EventCtx,
|
||||
normal: GeomBatch,
|
||||
hovered: GeomBatch,
|
||||
disabled: GeomBatch,
|
||||
hotkey: Option<MultiKey>,
|
||||
action: &str,
|
||||
maybe_tooltip: Option<Text>,
|
||||
hitbox: Polygon,
|
||||
is_disabled: bool,
|
||||
) -> Button {
|
||||
// dims are based on the hitbox, not the two drawables!
|
||||
let bounds = hitbox.get_bounds();
|
||||
let dims = ScreenDims::new(bounds.width(), bounds.height());
|
||||
assert!(!action.is_empty());
|
||||
Widget::new(Box::new(Button {
|
||||
Button {
|
||||
action: action.to_string(),
|
||||
|
||||
draw_normal: ctx.upload(normal),
|
||||
draw_hovered: ctx.upload(hovered),
|
||||
draw_disabled: ctx.upload(disabled),
|
||||
tooltip: if let Some(t) = maybe_tooltip {
|
||||
t
|
||||
} else {
|
||||
@ -52,12 +82,12 @@ impl Button {
|
||||
hotkey,
|
||||
hitbox,
|
||||
|
||||
is_disabled,
|
||||
hovering: false,
|
||||
|
||||
top_left: ScreenPt::new(0.0, 0.0),
|
||||
dims,
|
||||
}))
|
||||
.named(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +111,11 @@ impl WidgetImpl for Button {
|
||||
self.hovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_disabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.hovering && ctx.normal_left_click() {
|
||||
self.hovering = false;
|
||||
output.outcome = Outcome::Clicked(self.action.clone());
|
||||
@ -99,7 +134,9 @@ impl WidgetImpl for Button {
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx) {
|
||||
if self.hovering {
|
||||
if self.is_disabled {
|
||||
g.redraw_at(self.top_left, &self.draw_disabled);
|
||||
} else if self.hovering {
|
||||
g.redraw_at(self.top_left, &self.draw_hovered);
|
||||
if !self.tooltip.is_empty() {
|
||||
g.draw_mouse_tooltip(self.tooltip.clone());
|
||||
@ -271,6 +308,507 @@ impl Btn {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ButtonBuilder<'a> {
|
||||
padding: EdgeInsets,
|
||||
stack_spacing: f64,
|
||||
hotkey: Option<MultiKey>,
|
||||
tooltip: Option<Text>,
|
||||
stack_axis: Option<geom_batch_stack::Axis>,
|
||||
is_label_before_image: bool,
|
||||
is_disabled: bool,
|
||||
default_style: ButtonStyle<'a>,
|
||||
hover_style: ButtonStyle<'a>,
|
||||
disable_style: ButtonStyle<'a>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct ButtonStyle<'a> {
|
||||
image: Option<Image<'a>>,
|
||||
label: Option<Label<'a>>,
|
||||
outline: Option<(f64, Color)>,
|
||||
bg_color: Option<Color>,
|
||||
}
|
||||
|
||||
impl<'b, 'a: 'b> ButtonBuilder<'a> {
|
||||
pub fn new() -> Self {
|
||||
ButtonBuilder {
|
||||
padding: EdgeInsets {
|
||||
top: 8.0,
|
||||
bottom: 8.0,
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
},
|
||||
stack_spacing: 10.0,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Extra spacing around a button's items (label and/or image).
|
||||
///
|
||||
/// If not specified, a default will be applied.
|
||||
/// ```
|
||||
/// # use widgetry::{ButtonBuilder, EdgeInsets};
|
||||
/// // Custom padding for each inset
|
||||
/// let b = ButtonBuilder::new().padding(EdgeInsets{ top: 1.0, bottom: 2.0, left: 12.0, right: 14.0 });
|
||||
/// // uniform padding
|
||||
/// let b = ButtonBuilder::new().padding(6);
|
||||
/// ```
|
||||
pub fn padding<EI: Into<EdgeInsets>>(mut self, padding: EI) -> Self {
|
||||
self.padding = padding.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Extra spacing around a button's items (label and/or image).
|
||||
pub fn padding_top(mut self, padding: f32) -> Self {
|
||||
self.padding.top = padding;
|
||||
self
|
||||
}
|
||||
|
||||
/// Extra spacing around a button's items (label and/or image).
|
||||
pub fn padding_left(mut self, padding: f32) -> Self {
|
||||
self.padding.left = padding;
|
||||
self
|
||||
}
|
||||
|
||||
/// Extra spacing around a button's items (label and/or image).
|
||||
pub fn padding_bottom(mut self, padding: f32) -> Self {
|
||||
self.padding.bottom = padding;
|
||||
self
|
||||
}
|
||||
|
||||
/// Extra spacing around a button's items (label and/or image).
|
||||
pub fn padding_right(mut self, padding: f32) -> Self {
|
||||
self.padding.right = padding;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the text of the button's label.
|
||||
///
|
||||
/// If `label_text` is not set, the button will not have a label.
|
||||
pub fn label_text(mut self, text: &'a str) -> Self {
|
||||
let mut label = self.default_style.label.take().unwrap_or_default();
|
||||
label.text = Some(text);
|
||||
self.default_style.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Assign a pre-styled `Text` instance if your button need something more than uniformly
|
||||
/// colored text.
|
||||
pub fn label_styled_text(mut self, styled_text: Text, for_state: ControlState) -> Self {
|
||||
let state_style = self.style_mut(for_state);
|
||||
let mut label = state_style.label.take().unwrap_or_default();
|
||||
label.styled_text = Some(styled_text);
|
||||
// Unset plain `text` to avoid confusion. Alternatively we could assign the inner text -
|
||||
// something like:
|
||||
// label.text = styled_text.rows.map(|r|r.text).join(" ")
|
||||
label.text = None;
|
||||
state_style.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the color of the button's label.
|
||||
///
|
||||
/// If not specified, a default font color will be used.
|
||||
pub fn label_color(mut self, color: Color, for_state: ControlState) -> Self {
|
||||
let state_style = self.style_mut(for_state);
|
||||
let mut label = state_style.label.take().unwrap_or_default();
|
||||
label.color = Some(color);
|
||||
state_style.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the font used by the button's label.
|
||||
///
|
||||
/// If not specified, a default font will be used.
|
||||
pub fn font(mut self, font: Font) -> Self {
|
||||
let mut label = self.default_style.label.take().unwrap_or_default();
|
||||
label.font = Some(font);
|
||||
self.default_style.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the size of the font of the button's label.
|
||||
///
|
||||
/// If not specified, a default font size will be used.
|
||||
pub fn font_size(mut self, font_size: usize) -> Self {
|
||||
let mut label = self.default_style.label.take().unwrap_or_default();
|
||||
label.font_size = Some(font_size);
|
||||
self.default_style.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the image for the button. If not set, the button will have no image.
|
||||
pub fn image_path(mut self, path: &'a str) -> Self {
|
||||
// Currently we don't support setting image for other states like "hover", we easily
|
||||
// could, but the API gets more verbose for a thing we don't currently need.
|
||||
let mut image = self.default_style.image.take().unwrap_or_default();
|
||||
image.path = Some(path);
|
||||
self.default_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rewrite the color of the button's image.
|
||||
///
|
||||
/// This has no effect if the button does not have an image.
|
||||
///
|
||||
/// If the style hasn't been set for the current ControlState, the style for
|
||||
/// `ControlState::Default` will be used.
|
||||
pub fn image_color(mut self, color: Color, for_state: ControlState) -> Self {
|
||||
let state_style = self.style_mut(for_state);
|
||||
let mut image = state_style.image.take().unwrap_or_default();
|
||||
image.color = Some(color);
|
||||
state_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
|
||||
/// Scale the bounds containing the image. If `image_dims` are not specified, the images
|
||||
/// intrinsic size will be used.
|
||||
///
|
||||
/// See [`ButtonBuilder::image_content_mode`] to control how the image scales to fit
|
||||
/// its custom bounds.
|
||||
pub fn image_dims<D: Into<ScreenDims>>(mut self, dims: D) -> Self {
|
||||
let mut image = self.default_style.image.take().unwrap_or_default();
|
||||
image.dims = Some(dims.into());
|
||||
self.default_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
|
||||
/// If a custom `image_dims` was set, control how the image should be scaled to its new bounds
|
||||
///
|
||||
/// If `image_dims` were not specified, the image will not be scaled, so content_mode has no
|
||||
/// affect.
|
||||
///
|
||||
/// The default, [`ContentMode::ScaleAspectFit`] will only grow as much as it can while
|
||||
/// maintaining its aspect ratio and not exceeding its bounds.
|
||||
pub fn image_content_mode(mut self, content_mode: ContentMode) -> Self {
|
||||
let mut image = self.default_style.image.take().unwrap_or_default();
|
||||
image.content_mode = content_mode;
|
||||
self.default_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a background color for the button based on the button's [`ControlState`].
|
||||
///
|
||||
/// If the style hasn't been set for the current ControlState, the style for
|
||||
/// `ControlState::Default` will be used.
|
||||
pub fn bg_color(mut self, color: Color, for_state: ControlState) -> Self {
|
||||
self.style_mut(for_state).bg_color = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set an outline for the button based on the button's [`ControlState`].
|
||||
///
|
||||
/// If the style hasn't been set for the current ControlState, the style for
|
||||
/// `ControlState::Default` will be used.
|
||||
pub fn outline(mut self, thickness: f64, color: Color, for_state: ControlState) -> Self {
|
||||
self.style_mut(for_state).outline = Some((thickness, color));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a hotkey for the button
|
||||
pub fn hotkey<MK: Into<MultiKey>>(mut self, key: MK) -> Self {
|
||||
self.hotkey = Some(key.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a non-default tooltip [`Text`] to appear when hovering over the button.
|
||||
///
|
||||
/// If a `tooltip` is not specified, a default tooltip will be applied.
|
||||
pub fn tooltip(mut self, tooltip: Text) -> Self {
|
||||
self.tooltip = Some(tooltip);
|
||||
self
|
||||
}
|
||||
|
||||
/// If a `tooltip` is not specified, a default tooltip will be applied. Use `no_tooltip` when
|
||||
/// you do not want even the default tooltip to appear.
|
||||
pub fn no_tooltip(mut self) -> Self {
|
||||
// otherwise the widgets `name` is used
|
||||
self.tooltip = Some(Text::new());
|
||||
self
|
||||
}
|
||||
|
||||
/// The button's items will be rendered in a vertical column
|
||||
///
|
||||
/// If the button doesn't have both an image and label, this has no effect.
|
||||
pub fn vertical(mut self) -> Self {
|
||||
self.stack_axis = Some(geom_batch_stack::Axis::Vertical);
|
||||
self
|
||||
}
|
||||
|
||||
/// The button's items will be rendered in a horizontal row
|
||||
///
|
||||
/// If the button doesn't have both an image and label, this has no effect.
|
||||
pub fn horizontal(mut self) -> Self {
|
||||
self.stack_axis = Some(geom_batch_stack::Axis::Horizontal);
|
||||
self
|
||||
}
|
||||
|
||||
/// The button cannot be clicked and will be styled as [`ControlState::Disabled`]
|
||||
pub fn disabled(mut self) -> Self {
|
||||
self.is_disabled = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Display the button's label before the button's image.
|
||||
///
|
||||
/// If the button doesn't have both an image and label, this has no effect.
|
||||
pub fn label_first(mut self) -> Self {
|
||||
self.is_label_before_image = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Display the button's image before the button's label.
|
||||
///
|
||||
/// If the button doesn't have both an image and label, this has no effect.
|
||||
pub fn image_first(mut self) -> Self {
|
||||
self.is_label_before_image = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Spacing between the image and text of a button.
|
||||
/// Has no effect if the button is text-only or image-only.
|
||||
pub fn stack_spacing(mut self, value: f64) -> Self {
|
||||
self.stack_spacing = value;
|
||||
self
|
||||
}
|
||||
|
||||
// Building
|
||||
|
||||
/// Build a button.
|
||||
///
|
||||
/// `action`: The event that will be fired when clicked
|
||||
/// ```
|
||||
/// # use widgetry::{Color, ButtonBuilder, ControlState, EventCtx};
|
||||
///
|
||||
/// fn build_some_buttons(ctx: &EventCtx) {
|
||||
/// let one_off_builder = ButtonBuilder::new().label_text("foo").build(ctx, "foo");
|
||||
///
|
||||
/// // If you'd like to build a series of similar buttons, `clone` the builder first.
|
||||
/// let red_builder = ButtonBuilder::new()
|
||||
/// .bg_color(Color::RED, ControlState::Default)
|
||||
/// .bg_color(Color::RED.alpha(0.3), ControlState::Disabled)
|
||||
/// .outline(2.0, Color::WHITE, ControlState::Default);
|
||||
///
|
||||
/// let red_button_1 = red_builder.clone().label_text("First red button").build(ctx, "first");
|
||||
/// let red_button_2 = red_builder.clone().label_text("Second red button").build(ctx, "second");
|
||||
/// let red_button_3 = red_builder.label_text("Last red button").build(ctx, "third");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn build(&self, ctx: &EventCtx, action: &str) -> Button {
|
||||
let normal = self.batch(ctx, ControlState::Default);
|
||||
let hovered = self.batch(ctx, ControlState::Hovered);
|
||||
let disabled = self.batch(ctx, ControlState::Disabled);
|
||||
|
||||
assert!(
|
||||
normal.get_bounds() != geom::Bounds::zero(),
|
||||
"button was empty"
|
||||
);
|
||||
let hitbox = normal.get_bounds().get_rectangle();
|
||||
Button::new(
|
||||
ctx,
|
||||
normal,
|
||||
hovered,
|
||||
disabled,
|
||||
self.hotkey.clone(),
|
||||
action,
|
||||
self.tooltip.clone(),
|
||||
hitbox,
|
||||
self.is_disabled,
|
||||
)
|
||||
}
|
||||
|
||||
/// Shorthand method to build a Button wrapped in a Widget
|
||||
///
|
||||
/// `action`: The event that will be fired when clicked
|
||||
pub fn build_widget(&self, ctx: &EventCtx, action: &str) -> Widget {
|
||||
Widget::new(Box::new(self.build(ctx, action))).named(action)
|
||||
}
|
||||
|
||||
/// Shorthand method to build a default widget whose `action` is derived from the label's text.
|
||||
pub fn build_def(&self, ctx: &EventCtx) -> Widget {
|
||||
let action = self
|
||||
.default_style
|
||||
.label
|
||||
.as_ref()
|
||||
.and_then(|label| label.text)
|
||||
.expect("Must set `label_text` before calling build_def");
|
||||
|
||||
self.build_widget(ctx, action)
|
||||
}
|
||||
|
||||
// private methods
|
||||
|
||||
fn style_mut(&'b mut self, state: ControlState) -> &'b mut ButtonStyle<'a> {
|
||||
match state {
|
||||
ControlState::Default => &mut self.default_style,
|
||||
ControlState::Hovered => &mut self.hover_style,
|
||||
ControlState::Disabled => &mut self.disable_style,
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&'b self, state: ControlState) -> &'b ButtonStyle<'a> {
|
||||
match state {
|
||||
ControlState::Default => &self.default_style,
|
||||
ControlState::Hovered => &self.hover_style,
|
||||
ControlState::Disabled => &self.disable_style,
|
||||
}
|
||||
}
|
||||
|
||||
fn batch(&self, ctx: &EventCtx, for_state: ControlState) -> GeomBatch {
|
||||
let state_style = self.style(for_state);
|
||||
let default_style = &self.default_style;
|
||||
|
||||
let image_batch = state_style
|
||||
.image
|
||||
.as_ref()
|
||||
.or(default_style.image.as_ref())
|
||||
.and_then(|image| {
|
||||
let default = default_style.image.as_ref();
|
||||
let image_path = image.path.or(default.and_then(|d| d.path));
|
||||
if image_path.is_none() {
|
||||
return None;
|
||||
}
|
||||
let image_path = image_path.unwrap();
|
||||
let (mut svg_batch, svg_bounds) = svg::load_svg(ctx.prerender, image_path);
|
||||
if let Some(color) = image.color.or(default.and_then(|d| d.color)) {
|
||||
svg_batch = svg_batch.color(RewriteColor::ChangeAll(color));
|
||||
}
|
||||
|
||||
if let Some(image_dims) = image.dims.or(default.and_then(|d| d.dims)) {
|
||||
if svg_bounds.width() != 0.0 && svg_bounds.height() != 0.0 {
|
||||
let (x_factor, y_factor) = (
|
||||
image_dims.width / svg_bounds.width(),
|
||||
image_dims.height / svg_bounds.height(),
|
||||
);
|
||||
svg_batch = match image.content_mode {
|
||||
ContentMode::ScaleToFill => svg_batch.scale_xy(x_factor, y_factor),
|
||||
ContentMode::ScaleAspectFit => svg_batch.scale(x_factor.min(y_factor)),
|
||||
ContentMode::ScaleAspectFill => svg_batch.scale(x_factor.max(y_factor)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut container_batch = GeomBatch::new();
|
||||
let container = Polygon::rectangle(image_dims.width, image_dims.height);
|
||||
container_batch.push(Color::CLEAR, container);
|
||||
|
||||
svg_batch = svg_batch
|
||||
.autocrop()
|
||||
.centered_on(container_batch.get_bounds().center());
|
||||
container_batch.append(svg_batch);
|
||||
|
||||
svg_batch = container_batch
|
||||
}
|
||||
|
||||
Some(svg_batch)
|
||||
});
|
||||
|
||||
let label_batch = state_style
|
||||
.label
|
||||
.as_ref()
|
||||
.or(default_style.label.as_ref())
|
||||
.and_then(|label| {
|
||||
let default = default_style.label.as_ref();
|
||||
|
||||
if let Some(styled_text) = label
|
||||
.styled_text
|
||||
.as_ref()
|
||||
.or(default.and_then(|d| d.styled_text.as_ref()))
|
||||
{
|
||||
return Some(styled_text.clone().bg(Color::CLEAR).render(ctx));
|
||||
}
|
||||
|
||||
let text = label.text.or(default.and_then(|d| d.text));
|
||||
|
||||
// Is there a better way to do this like a `guard let`?
|
||||
if text.is_none() {
|
||||
return None;
|
||||
}
|
||||
let text = text.unwrap();
|
||||
|
||||
let color = label
|
||||
.color
|
||||
.or(default.and_then(|d| d.color))
|
||||
.unwrap_or(ctx.style().outline_color);
|
||||
let mut line = Line(text).fg(color);
|
||||
|
||||
if let Some(font_size) = label.font_size.or(default.and_then(|d| d.font_size)) {
|
||||
line = line.size(font_size);
|
||||
}
|
||||
|
||||
if let Some(font) = label.font.or(default.and_then(|d| d.font)) {
|
||||
line = line.font(font);
|
||||
}
|
||||
|
||||
Some(
|
||||
Text::from(line)
|
||||
// Add a clear background to maintain a consistent amount of space for the
|
||||
// label based on the font, rather than the particular text.
|
||||
// Otherwise a button with text "YYY" will not line up with a button
|
||||
// with text "aaa".
|
||||
.bg(Color::CLEAR)
|
||||
.render(ctx),
|
||||
)
|
||||
});
|
||||
|
||||
use geom_batch_stack::Stack;
|
||||
let mut stack = Stack::horizontal();
|
||||
if let Some(stack_axis) = self.stack_axis {
|
||||
stack.set_axis(stack_axis);
|
||||
}
|
||||
stack.spacing(self.stack_spacing);
|
||||
|
||||
let mut items = vec![];
|
||||
if let Some(image_batch) = image_batch {
|
||||
items.push(image_batch);
|
||||
}
|
||||
if let Some(label_batch) = label_batch {
|
||||
items.push(label_batch);
|
||||
}
|
||||
if self.is_label_before_image {
|
||||
items.reverse()
|
||||
}
|
||||
stack.append(&mut items);
|
||||
|
||||
let mut button_widget = stack
|
||||
.batch()
|
||||
.batch() // TODO: rename -> `widget` or `build_widget`
|
||||
.container()
|
||||
.padding(self.padding)
|
||||
.bg(state_style
|
||||
.bg_color
|
||||
.or(default_style.bg_color)
|
||||
// If we have *no* background, buttons will be cropped differently depending on
|
||||
// their specific content, and it becomes impossible to have
|
||||
// uniformly sized buttons.
|
||||
.unwrap_or(Color::CLEAR));
|
||||
|
||||
if let Some((thickness, color)) = state_style.outline.or(default_style.outline) {
|
||||
button_widget = button_widget.outline(thickness, color);
|
||||
}
|
||||
|
||||
let (geom_batch, _hitbox) = button_widget.to_geom(ctx, None);
|
||||
geom_batch
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Image<'a> {
|
||||
path: Option<&'a str>,
|
||||
color: Option<Color>,
|
||||
dims: Option<ScreenDims>,
|
||||
content_mode: ContentMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct Label<'a> {
|
||||
text: Option<&'a str>,
|
||||
color: Option<Color>,
|
||||
styled_text: Option<Text>,
|
||||
font_size: Option<usize>,
|
||||
font: Option<Font>,
|
||||
}
|
||||
|
||||
pub enum BtnBuilder {
|
||||
SVG {
|
||||
path: String,
|
||||
@ -352,14 +890,16 @@ impl BtnBuilder {
|
||||
|
||||
let hovered = normal.clone().color(rewrite_hover);
|
||||
|
||||
Button::new(
|
||||
Button::widget(
|
||||
ctx,
|
||||
normal,
|
||||
normal.clone(),
|
||||
hovered,
|
||||
normal, // TODO: remove this method. copying disabled from normal for now
|
||||
key.into(),
|
||||
&action.into(),
|
||||
maybe_tooltip,
|
||||
geom,
|
||||
false,
|
||||
)
|
||||
}
|
||||
BtnBuilder::TextFG(_, normal_txt, maybe_t) => {
|
||||
@ -376,14 +916,16 @@ impl BtnBuilder {
|
||||
.padding(8)
|
||||
.to_geom(ctx, None);
|
||||
|
||||
Button::new(
|
||||
Button::widget(
|
||||
ctx,
|
||||
normal,
|
||||
normal.clone(),
|
||||
hovered,
|
||||
normal,
|
||||
key.into(),
|
||||
&action.into(),
|
||||
maybe_t,
|
||||
hitbox,
|
||||
false,
|
||||
)
|
||||
.outline(2.0, Color::WHITE)
|
||||
}
|
||||
@ -404,14 +946,16 @@ impl BtnBuilder {
|
||||
.padding(8)
|
||||
.to_geom(ctx, None);
|
||||
|
||||
Button::new(
|
||||
Button::widget(
|
||||
ctx,
|
||||
normal,
|
||||
normal.clone(),
|
||||
hovered,
|
||||
normal,
|
||||
key.into(),
|
||||
&action.into(),
|
||||
maybe_tooltip,
|
||||
hitbox,
|
||||
false,
|
||||
)
|
||||
}
|
||||
BtnBuilder::TextBG {
|
||||
@ -435,14 +979,16 @@ impl BtnBuilder {
|
||||
.bg(selected_bg_color)
|
||||
.to_geom(ctx, None);
|
||||
|
||||
Button::new(
|
||||
Button::widget(
|
||||
ctx,
|
||||
normal,
|
||||
normal.clone(),
|
||||
hovered,
|
||||
normal,
|
||||
key.into(),
|
||||
&action.into(),
|
||||
maybe_tooltip,
|
||||
hitbox,
|
||||
false,
|
||||
)
|
||||
}
|
||||
BtnBuilder::Custom {
|
||||
@ -452,14 +998,16 @@ impl BtnBuilder {
|
||||
maybe_tooltip,
|
||||
maybe_outline,
|
||||
} => {
|
||||
let button = Button::new(
|
||||
let button = Button::widget(
|
||||
ctx,
|
||||
normal,
|
||||
normal.clone(),
|
||||
hovered,
|
||||
normal,
|
||||
key.into(),
|
||||
&action.into(),
|
||||
maybe_tooltip,
|
||||
hitbox,
|
||||
false,
|
||||
);
|
||||
|
||||
if let Some(outline) = maybe_outline {
|
||||
@ -603,3 +1151,113 @@ impl WidgetImpl for MultiButton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Currently only the ButtonBuilder uses the Stack module below, but this might be useful in other
|
||||
// places.
|
||||
//
|
||||
// It's similar to Widget::row/column, but more of a builder pattern - you can add items
|
||||
// individually, change `spacing` and `axis`, and call `batch` at the end to apply this
|
||||
// configuration things to compute the layout.
|
||||
mod geom_batch_stack {
|
||||
use crate::GeomBatch;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Axis {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Stack {
|
||||
batches: Vec<GeomBatch>,
|
||||
axis: Axis,
|
||||
spacing: f64,
|
||||
}
|
||||
|
||||
impl Default for Stack {
|
||||
fn default() -> Self {
|
||||
Stack {
|
||||
batches: vec![],
|
||||
// TODO:
|
||||
// alignment: Alignment::Center,
|
||||
axis: Axis::Horizontal,
|
||||
spacing: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn horizontal() -> Self {
|
||||
Stack {
|
||||
axis: Axis::Horizontal,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn vertical() -> Self {
|
||||
Stack {
|
||||
axis: Axis::Vertical,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_axis(&mut self, new_value: Axis) {
|
||||
self.axis = new_value;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn push(&mut self, geom_batch: GeomBatch) {
|
||||
self.batches.push(geom_batch);
|
||||
}
|
||||
|
||||
pub fn append(&mut self, geom_batches: &mut Vec<GeomBatch>) {
|
||||
self.batches.append(geom_batches);
|
||||
}
|
||||
|
||||
pub fn spacing(&mut self, spacing: f64) -> &mut Self {
|
||||
self.spacing = spacing;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn batch(self) -> GeomBatch {
|
||||
if self.batches.is_empty() {
|
||||
return GeomBatch::new();
|
||||
}
|
||||
|
||||
let max_bound_for_axis = self
|
||||
.batches
|
||||
.iter()
|
||||
.map(GeomBatch::get_bounds)
|
||||
.max_by(|b1, b2| match self.axis {
|
||||
Axis::Vertical => b1.width().partial_cmp(&b2.width()).unwrap(),
|
||||
Axis::Horizontal => b1.height().partial_cmp(&b2.height()).unwrap(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut stack_batch = GeomBatch::new();
|
||||
let mut stack_offset = 0.0;
|
||||
for mut batch in self.batches {
|
||||
let bounds = batch.get_bounds();
|
||||
let alignment_inset = match self.axis {
|
||||
Axis::Vertical => (max_bound_for_axis.width() - bounds.width()) / 2.0,
|
||||
Axis::Horizontal => (max_bound_for_axis.height() - bounds.height()) / 2.0,
|
||||
};
|
||||
|
||||
let (dx, dy) = match self.axis {
|
||||
Axis::Vertical => (alignment_inset, stack_offset),
|
||||
Axis::Horizontal => (stack_offset, alignment_inset),
|
||||
};
|
||||
batch = batch.translate(dx, dy);
|
||||
stack_batch.append(batch);
|
||||
|
||||
stack_offset += self.spacing;
|
||||
match self.axis {
|
||||
Axis::Vertical => stack_offset += bounds.height(),
|
||||
Axis::Horizontal => stack_offset += bounds.width(),
|
||||
}
|
||||
}
|
||||
stack_batch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
|
||||
use crate::{
|
||||
Btn, Button, Choice, Color, EventCtx, GeomBatch, GfxCtx, Menu, Outcome, ScreenDims, ScreenPt,
|
||||
ScreenRectangle, WidgetImpl, WidgetOutput,
|
||||
Button, Choice, Color, ControlState, EdgeInsets, EventCtx, GeomBatch, GfxCtx, Menu, Outcome,
|
||||
ScreenDims, ScreenPt, ScreenRectangle, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
pub struct Dropdown<T: Clone> {
|
||||
@ -11,7 +11,7 @@ pub struct Dropdown<T: Clone> {
|
||||
// TODO Why not T?
|
||||
menu: Option<Menu<usize>>,
|
||||
label: String,
|
||||
blank_btn_label: bool,
|
||||
is_persisten_split: bool,
|
||||
|
||||
choices: Vec<Choice<T>>,
|
||||
}
|
||||
@ -23,7 +23,7 @@ impl<T: 'static + PartialEq + Clone + std::fmt::Debug> Dropdown<T> {
|
||||
default_value: T,
|
||||
choices: Vec<Choice<T>>,
|
||||
// TODO Ideally builder style
|
||||
blank_btn_label: bool,
|
||||
is_persisten_split: bool,
|
||||
) -> Dropdown<T> {
|
||||
let current_idx = if let Some(idx) = choices.iter().position(|c| c.data == default_value) {
|
||||
idx
|
||||
@ -36,10 +36,10 @@ impl<T: 'static + PartialEq + Clone + std::fmt::Debug> Dropdown<T> {
|
||||
|
||||
Dropdown {
|
||||
current_idx,
|
||||
btn: make_btn(ctx, &choices[current_idx].label, label, blank_btn_label),
|
||||
btn: make_btn(ctx, &choices[current_idx].label, label, is_persisten_split),
|
||||
menu: None,
|
||||
label: label.to_string(),
|
||||
blank_btn_label,
|
||||
is_persisten_split,
|
||||
choices,
|
||||
}
|
||||
}
|
||||
@ -49,8 +49,8 @@ impl<T: 'static + PartialEq + Clone> Dropdown<T> {
|
||||
pub fn current_value(&self) -> T {
|
||||
self.choices[self.current_idx].data.clone()
|
||||
}
|
||||
pub(crate) fn current_value_label(&self) -> String {
|
||||
self.choices[self.current_idx].label.clone()
|
||||
pub(crate) fn current_value_label(&self) -> &str {
|
||||
&self.choices[self.current_idx].label
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
|
||||
ctx,
|
||||
&self.choices[self.current_idx].label,
|
||||
&self.label,
|
||||
self.blank_btn_label,
|
||||
self.is_persisten_split,
|
||||
);
|
||||
self.btn.set_pos(top_left);
|
||||
output.redo_layout = true;
|
||||
@ -173,9 +173,26 @@ impl<T: 'static + Clone> WidgetImpl for Dropdown<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_btn(ctx: &EventCtx, label: &str, tooltip: &str, blank_btn_label: bool) -> Button {
|
||||
let button_label = if blank_btn_label { None } else { Some(label) };
|
||||
Btn::pop_up(ctx, button_label)
|
||||
.build(ctx, tooltip, None)
|
||||
.take_btn()
|
||||
fn make_btn(ctx: &EventCtx, label: &str, tooltip: &str, is_persisten_split: bool) -> Button {
|
||||
use crate::StyledButtons;
|
||||
// If we want to make Dropdown configurable, pass in or expose its button builder?
|
||||
let mut builder = ctx.style().btn_primary_light_dropdown();
|
||||
if is_persisten_split {
|
||||
// Quick hacks to make PersistentSplit's dropdown look a little better.
|
||||
// It's not ideal, but we only use one persistent split in the whole app
|
||||
// and it's front and center - we'll notice if something breaks.
|
||||
builder = builder
|
||||
.padding(EdgeInsets {
|
||||
top: 13.0,
|
||||
bottom: 13.0,
|
||||
left: 8.0,
|
||||
right: 8.0,
|
||||
})
|
||||
.bg_color(Color::CLEAR, ControlState::Default)
|
||||
.outline(0.0, Color::CLEAR, ControlState::Default);
|
||||
} else {
|
||||
builder = builder.label_text(label);
|
||||
}
|
||||
|
||||
builder.build(ctx, tooltip)
|
||||
}
|
||||
|
@ -378,8 +378,6 @@ impl Widget {
|
||||
false,
|
||||
)))
|
||||
.named(label)
|
||||
// Why is this still required? The button Dropdown uses *already* has an outline
|
||||
.outline(ctx.style().outline_thickness, ctx.style().outline_color)
|
||||
}
|
||||
|
||||
pub fn custom_row(widgets: Vec<Widget>) -> Widget {
|
||||
@ -737,7 +735,7 @@ impl Widget {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
pub struct EdgeInsets {
|
||||
pub top: f32,
|
||||
pub left: f32,
|
||||
@ -745,6 +743,26 @@ pub struct EdgeInsets {
|
||||
pub right: f32,
|
||||
}
|
||||
|
||||
impl EdgeInsets {
|
||||
pub fn zero() -> Self {
|
||||
EdgeInsets {
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
bottom: 0.0,
|
||||
right: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uniform(inset: f32) -> Self {
|
||||
EdgeInsets {
|
||||
top: inset,
|
||||
left: inset,
|
||||
bottom: inset,
|
||||
right: inset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for EdgeInsets {
|
||||
fn from(uniform_size: usize) -> EdgeInsets {
|
||||
EdgeInsets {
|
||||
@ -756,6 +774,17 @@ impl From<usize> for EdgeInsets {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for EdgeInsets {
|
||||
fn from(uniform_size: f32) -> EdgeInsets {
|
||||
EdgeInsets {
|
||||
top: uniform_size,
|
||||
left: uniform_size,
|
||||
bottom: uniform_size,
|
||||
right: uniform_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EdgeInsets> for Rect<Dimension> {
|
||||
fn from(insets: EdgeInsets) -> Rect<Dimension> {
|
||||
Rect {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use geom::Polygon;
|
||||
|
||||
use crate::{
|
||||
Btn, Button, Choice, Color, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw, MultiKey, Outcome,
|
||||
ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput,
|
||||
Button, ButtonBuilder, Choice, Color, Dropdown, EventCtx, GeomBatch, GfxCtx, JustDraw,
|
||||
MultiKey, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
// TODO Radio buttons in the menu
|
||||
@ -14,35 +14,68 @@ pub struct PersistentSplit<T: Clone + PartialEq> {
|
||||
}
|
||||
|
||||
impl<T: 'static + PartialEq + Clone + std::fmt::Debug> PersistentSplit<T> {
|
||||
pub fn new<MK: Into<Option<MultiKey>>>(
|
||||
pub fn widget<MK: Into<Option<MultiKey>>>(
|
||||
ctx: &EventCtx,
|
||||
label: &str,
|
||||
default_value: T,
|
||||
hotkey: MK,
|
||||
choices: Vec<Choice<T>>,
|
||||
) -> Widget {
|
||||
let dropdown = Dropdown::new(ctx, "change", default_value, choices, true);
|
||||
let btn = Btn::plaintext(dropdown.current_value_label())
|
||||
.build(ctx, label, hotkey)
|
||||
.take_btn();
|
||||
let bg = Color::hex("#003046").alpha(0.8);
|
||||
let outline = Color::hex("#003046").alpha(0.6);
|
||||
Widget::new(Box::new(PersistentSplit::new(
|
||||
ctx,
|
||||
label,
|
||||
default_value,
|
||||
hotkey,
|
||||
choices,
|
||||
)))
|
||||
.bg(bg)
|
||||
.outline(2.0, outline)
|
||||
.named(label)
|
||||
}
|
||||
|
||||
Widget::new(Box::new(PersistentSplit {
|
||||
pub fn new<MK: Into<Option<MultiKey>>>(
|
||||
ctx: &EventCtx,
|
||||
label: &str,
|
||||
default_value: T,
|
||||
hotkey: MK,
|
||||
choices: Vec<Choice<T>>,
|
||||
) -> PersistentSplit<T> {
|
||||
let dropdown = Dropdown::new(ctx, "change", default_value, choices, true);
|
||||
let mut btn = button_builder(ctx).label_text(dropdown.current_value_label());
|
||||
|
||||
if let Some(multikey) = hotkey.into() {
|
||||
btn = btn.hotkey(multikey)
|
||||
}
|
||||
let btn = btn.build(ctx, label);
|
||||
|
||||
let outline = Color::hex("#003046").alpha(0.6);
|
||||
|
||||
PersistentSplit {
|
||||
current_value: dropdown.current_value(),
|
||||
spacer: JustDraw::wrap(
|
||||
ctx,
|
||||
GeomBatch::from(vec![(
|
||||
Color::WHITE.alpha(0.5),
|
||||
outline,
|
||||
Polygon::rectangle(3.0, btn.get_dims().height),
|
||||
)]),
|
||||
)
|
||||
.take_just_draw(),
|
||||
btn,
|
||||
dropdown,
|
||||
}))
|
||||
.named(label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn button_builder<'a>(ctx: &EventCtx) -> ButtonBuilder<'a> {
|
||||
use crate::{ControlState, StyledButtons};
|
||||
ctx.style()
|
||||
.btn_primary_light()
|
||||
.font_size(18)
|
||||
.outline(0.0, Color::CLEAR, ControlState::Default)
|
||||
}
|
||||
|
||||
impl<T: 'static + PartialEq + Clone> PersistentSplit<T> {
|
||||
pub fn current_value(&self) -> T {
|
||||
self.current_value.clone()
|
||||
@ -80,11 +113,13 @@ impl<T: 'static + Clone + PartialEq> WidgetImpl for PersistentSplit<T> {
|
||||
let new_value = self.dropdown.current_value();
|
||||
if new_value != self.current_value {
|
||||
self.current_value = new_value;
|
||||
let hotkey = self.btn.hotkey.take();
|
||||
let label = self.btn.action.clone();
|
||||
self.btn = Btn::plaintext(self.dropdown.current_value_label())
|
||||
.build(ctx, label, hotkey)
|
||||
.take_btn();
|
||||
let mut button_builder =
|
||||
button_builder(ctx).label_text(self.dropdown.current_value_label());
|
||||
if let Some(multikey) = self.btn.hotkey.take() {
|
||||
button_builder = button_builder.hotkey(multikey)
|
||||
}
|
||||
self.btn = button_builder.build(ctx, &label);
|
||||
output.redo_layout = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use geom::{Polygon, Pt2D};
|
||||
|
||||
use crate::{
|
||||
text, Btn, Button, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt,
|
||||
text, Button, ButtonBuilder, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt,
|
||||
ScreenRectangle, Text, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
@ -25,12 +25,28 @@ pub struct Spinner {
|
||||
|
||||
impl Spinner {
|
||||
pub fn new(ctx: &EventCtx, (low, high): (isize, isize), mut current: isize) -> Widget {
|
||||
let up = Btn::text_fg("↑")
|
||||
.build(ctx, "increase value", None)
|
||||
.take_btn();
|
||||
let down = Btn::text_fg("↓")
|
||||
.build(ctx, "decrease value", None)
|
||||
.take_btn();
|
||||
let button_builder = ButtonBuilder::new();
|
||||
|
||||
let button_builder = button_builder
|
||||
// CLEANUP: For things to look balanced, left/right padding are unequal.
|
||||
// I'm not sure why this is - maybe an issue with text layout?
|
||||
.padding_left(7.0)
|
||||
.padding_right(4.0)
|
||||
.bg_color(Color::WHITE.alpha(0.1), ControlState::Hovered);
|
||||
|
||||
use crate::{Color, ControlState};
|
||||
let up = button_builder
|
||||
.clone()
|
||||
.label_text("↑")
|
||||
.padding_top(2.0)
|
||||
.padding_bottom(0.0)
|
||||
.build(ctx, "increase value");
|
||||
|
||||
let down = button_builder
|
||||
.label_text("↓")
|
||||
.padding_top(0.0)
|
||||
.padding_bottom(2.0)
|
||||
.build(ctx, "decrease value");
|
||||
|
||||
let dims = ScreenDims::new(
|
||||
TEXT_WIDTH + up.get_dims().width,
|
||||
|
@ -7,8 +7,8 @@ use geom::{Angle, Duration, Percent, Polygon, Pt2D, Time};
|
||||
use widgetry::{
|
||||
lctrl, Btn, Checkbox, Choice, Color, Drawable, EventCtx, Fill, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Key, Line, LinePlot, Outcome, Panel, PersistentSplit, PlotOptions, Series,
|
||||
SharedAppState, State, Text, TextExt, Texture, Transition, UpdateType, VerticalAlignment,
|
||||
Widget,
|
||||
SharedAppState, State, StyledButtons, Text, TextExt, Texture, Transition, UpdateType,
|
||||
VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
@ -162,7 +162,13 @@ impl State<App> for Demo {
|
||||
let (bg_texture, fg_texture) = self.controls.dropdown_value("texture");
|
||||
self.texture_demo = setup_texture_demo(ctx, bg_texture, fg_texture);
|
||||
}
|
||||
_ => unimplemented!("clicked: {:?}", x),
|
||||
action => {
|
||||
if action.contains("btn_") {
|
||||
log::info!("clicked button: {:?}", action);
|
||||
} else {
|
||||
unimplemented!("clicked: {:?}", x);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
@ -297,12 +303,66 @@ fn setup_scrollable_canvas(ctx: &mut EventCtx) -> Drawable {
|
||||
}
|
||||
|
||||
fn make_controls(ctx: &mut EventCtx) -> Panel {
|
||||
let btn = ctx.style();
|
||||
Panel::new(Widget::col(vec![
|
||||
Text::from_multiline(vec![
|
||||
Line("widgetry demo").small_heading(),
|
||||
Line("Click and drag to pan, use touchpad or scroll wheel to zoom"),
|
||||
Line("widgetry demo").big_heading_styled(),
|
||||
Line("Click and drag the background to pan, use touchpad or scroll wheel to zoom"),
|
||||
])
|
||||
.draw(ctx),
|
||||
// Button Style Gallery
|
||||
// TODO might be nice to have this in separate tabs or something.
|
||||
Text::from(Line("Buttons").big_heading_styled().size(18)).draw(ctx),
|
||||
Widget::row(vec![
|
||||
Widget::col(vec![
|
||||
Text::from(Line("Neutral Dark")).bg(Color::CLEAR).draw(ctx),
|
||||
btn.btn_primary_dark_text("Primary")
|
||||
.build_widget(ctx, "btn_primary_dark_text"),
|
||||
Widget::row(vec![
|
||||
btn.btn_primary_dark_icon("system/assets/tools/map.svg")
|
||||
.build_widget(ctx, "btn_primary_dark_icon_1"),
|
||||
btn.btn_primary_dark_icon("system/assets/tools/layers.svg")
|
||||
.build_widget(ctx, "btn_primary_dark_icon_2"),
|
||||
]),
|
||||
btn.btn_primary_dark_icon_text("system/assets/tools/location.svg", "Primary")
|
||||
.build_widget(ctx, "btn_primary_dark_icon_text"),
|
||||
btn.btn_secondary_dark_text("Secondary")
|
||||
.build_widget(ctx, "btn_secondary_dark_text"),
|
||||
Widget::row(vec![
|
||||
btn.btn_secondary_dark_icon("system/assets/tools/map.svg")
|
||||
.build_widget(ctx, "btn_secondary_dark_icon_1"),
|
||||
btn.btn_secondary_dark_icon("system/assets/tools/layers.svg")
|
||||
.build_widget(ctx, "btn_secondary_dark_icon_2"),
|
||||
]),
|
||||
btn.btn_secondary_dark_icon_text("system/assets/tools/home.svg", "Secondary")
|
||||
.build_widget(ctx, "btn_secondary_dark_icon_text"),
|
||||
]),
|
||||
Widget::col(vec![
|
||||
Text::from(Line("Neutral Light")).bg(Color::CLEAR).draw(ctx),
|
||||
btn.btn_primary_light_text("Primary")
|
||||
.build_widget(ctx, "btn_primary_light_text"),
|
||||
Widget::row(vec![
|
||||
btn.btn_primary_light_icon("system/assets/tools/home.svg")
|
||||
.build_widget(ctx, "btn_primary_light_icon_1"),
|
||||
btn.btn_primary_light_icon("system/assets/tools/location.svg")
|
||||
.build_widget(ctx, "btn_primary_light_icon_2"),
|
||||
]),
|
||||
btn.btn_primary_light_icon_text("system/assets/tools/map.svg", "Primary")
|
||||
.build_widget(ctx, "btn_primary_light_icon_text"),
|
||||
btn.btn_secondary_light_text("Secondary")
|
||||
.build_widget(ctx, "btn_secondary_light_text"),
|
||||
Widget::row(vec![
|
||||
btn.btn_secondary_light_icon("system/assets/tools/home.svg")
|
||||
.build_widget(ctx, "btn_secondary_light_icon_1"),
|
||||
btn.btn_secondary_light_icon("system/assets/tools/location.svg")
|
||||
.build_widget(ctx, "btn_secondary_light_icon_2"),
|
||||
]),
|
||||
btn.btn_secondary_light_icon_text("system/assets/tools/layers.svg", "Secondary")
|
||||
.build_widget(ctx, "btn_secondary_light_icon_text"),
|
||||
]),
|
||||
]),
|
||||
Text::from(Line("Spinner").big_heading_styled().size(18)).draw(ctx),
|
||||
widgetry::Spinner::new(ctx, (0, 11), 1),
|
||||
Widget::row(vec![
|
||||
Btn::text_fg("New faces").build(ctx, "generate new faces", Key::F),
|
||||
Checkbox::switch(ctx, "Draw scrollable canvas", None, true),
|
||||
@ -319,7 +379,7 @@ fn make_controls(ctx: &mut EventCtx) -> Panel {
|
||||
Btn::text_bg1("Resume").build(ctx, "resume the stopwatch", Key::Space),
|
||||
)
|
||||
.named("paused"),
|
||||
PersistentSplit::new(
|
||||
PersistentSplit::widget(
|
||||
ctx,
|
||||
"adjust timer",
|
||||
Duration::seconds(20.0),
|
||||
|