mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
Compare commits
624 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc105ecc3d | ||
|
|
649f6c28bf | ||
|
|
867972b7f5 | ||
|
|
efe3227ef2 | ||
|
|
aab8c88a96 | ||
|
|
af18ca011b | ||
|
|
24106b860a | ||
|
|
60efb6973b | ||
|
|
cffd55bdda | ||
|
|
88e767aaaf | ||
|
|
d6cda43618 | ||
|
|
3b229cd5cb | ||
|
|
72c4dbdb2f | ||
|
|
4da18d3630 | ||
|
|
2f04cfd5c6 | ||
|
|
8195db6d4c | ||
|
|
722f6315c4 | ||
|
|
173ed5475c | ||
|
|
1460044e91 | ||
|
|
06a7b6e446 | ||
|
|
28b7b4b7f1 | ||
|
|
8930adf532 | ||
|
|
f44b8a5618 | ||
|
|
6a9f79628e | ||
|
|
245c56ba8a | ||
|
|
98846421f6 | ||
|
|
0aaeeffff7 | ||
|
|
c2823facc2 | ||
|
|
fabb1596e5 | ||
|
|
725e32250b | ||
|
|
5fa264ea18 | ||
|
|
5e175b118d | ||
|
|
635173e55a | ||
|
|
eb2ed6852c | ||
|
|
2296766746 | ||
|
|
13be499510 | ||
|
|
fec5c567e1 | ||
|
|
8ef863cae1 | ||
|
|
9463105172 | ||
|
|
bb4819bce4 | ||
|
|
15be24db62 | ||
|
|
e7e2af9f91 | ||
|
|
8c5fd021f7 | ||
|
|
1a1ba19770 | ||
|
|
f95214d8fe | ||
|
|
631cfce2f8 | ||
|
|
45649264f9 | ||
|
|
0fd3cb0c4a | ||
|
|
3cfec69020 | ||
|
|
cec62d23b0 | ||
|
|
f3f0dda3d4 | ||
|
|
be16b66ac0 | ||
|
|
b9059aaa01 | ||
|
|
57a62d0544 | ||
|
|
d82f0e952f | ||
|
|
8731b7582b | ||
|
|
e6959dc572 | ||
|
|
a36b4d65e3 | ||
|
|
060ff56f9d | ||
|
|
0a0c0c0d07 | ||
|
|
17c4e405a6 | ||
|
|
53afa6ea43 | ||
|
|
a182e8daf2 | ||
|
|
a4dfaba03f | ||
|
|
6e23560e80 | ||
|
|
39e8d557e8 | ||
|
|
677c989664 | ||
|
|
c9342d90fb | ||
|
|
0693bb8d51 | ||
|
|
5cd3c305d0 | ||
|
|
e00b59c393 | ||
|
|
7c1e33dde6 | ||
|
|
367bd76046 | ||
|
|
1a1bf98905 | ||
|
|
4c1a24058c | ||
|
|
294e95caf8 | ||
|
|
031884c327 | ||
|
|
466dacaab4 | ||
|
|
1f8645fd43 | ||
|
|
880568cc60 | ||
|
|
f10fb56042 | ||
|
|
64be6d89ee | ||
|
|
5442c32a3f | ||
|
|
4ee53701e6 | ||
|
|
5097a223e3 | ||
|
|
7cdba75bef | ||
|
|
0312027ca8 | ||
|
|
c726c96286 | ||
|
|
5a2b2e0813 | ||
|
|
4271b2e9fd | ||
|
|
13ef4c04d1 | ||
|
|
96c3bb1e38 | ||
|
|
a0b36925ed | ||
|
|
daadc2ea71 | ||
|
|
ec2934b4b8 | ||
|
|
3a840c4ced | ||
|
|
bd190d2b65 | ||
|
|
9b05a36529 | ||
|
|
d9a498e8ec | ||
|
|
7d86b277a7 | ||
|
|
d463b3235e | ||
|
|
5a8433ede4 | ||
|
|
00a5fd2d7c | ||
|
|
55f9faea10 | ||
|
|
fb2e668589 | ||
|
|
0dafb3d230 | ||
|
|
e958934a22 | ||
|
|
069221757f | ||
|
|
505c1bc274 | ||
|
|
cdd5d33e89 | ||
|
|
f661f4d1d6 | ||
|
|
f435191585 | ||
|
|
00c2d7ea71 | ||
|
|
cddcc1e85d | ||
|
|
91928b45d8 | ||
|
|
277c83e6d8 | ||
|
|
0017cd2e40 | ||
|
|
774803492c | ||
|
|
83a9655772 | ||
|
|
58324b4539 | ||
|
|
09b7794d71 | ||
|
|
9e3fe9beb1 | ||
|
|
ff525fe750 | ||
|
|
94977ad216 | ||
|
|
64e34e42b8 | ||
|
|
21dc65f42a | ||
|
|
279e085887 | ||
|
|
d84dfa2c42 | ||
|
|
bf8089dc7e | ||
|
|
e48761b5c0 | ||
|
|
35437c0300 | ||
|
|
6cecc12d04 | ||
|
|
dec4231d49 | ||
|
|
fb1d12ebf3 | ||
|
|
b19276a3e9 | ||
|
|
5ccbfc1ff8 | ||
|
|
d3d6a8a838 | ||
|
|
ac83bbeb0e | ||
|
|
8cb76a26c1 | ||
|
|
20da22d59e | ||
|
|
d9fa4b452c | ||
|
|
6216d72aa6 | ||
|
|
851f132188 | ||
|
|
3067ff08ec | ||
|
|
07fd86fc9d | ||
|
|
504037c115 | ||
|
|
0fad21a980 | ||
|
|
8afd698284 | ||
|
|
9ec7b90192 | ||
|
|
08f0fff34b | ||
|
|
2c1073eda9 | ||
|
|
c9348f0651 | ||
|
|
accb461c08 | ||
|
|
75adcc0a96 | ||
|
|
61ce88ba9b | ||
|
|
4b451fd1d3 | ||
|
|
a87190960f | ||
|
|
45558027a6 | ||
|
|
e426606542 | ||
|
|
4d60942fea | ||
|
|
3003dea409 | ||
|
|
0b18930017 | ||
|
|
54ef5785cd | ||
|
|
d084ec78e9 | ||
|
|
a59c17aa83 | ||
|
|
6281adc7c3 | ||
|
|
5cc01ae89d | ||
|
|
303dd28c7c | ||
|
|
dd87dc7046 | ||
|
|
235a64deef | ||
|
|
89a96c6d25 | ||
|
|
4f0e5b99a8 | ||
|
|
f75f3f4661 | ||
|
|
b936a28921 | ||
|
|
d02507ae4b | ||
|
|
0b576adcf8 | ||
|
|
22ff033b5e | ||
|
|
b1edede53a | ||
|
|
3877f0853d | ||
|
|
9af8a0113a | ||
|
|
0d01f0c9d7 | ||
|
|
9911166c24 | ||
|
|
01736d6409 | ||
|
|
4ea8971adf | ||
|
|
8da072b602 | ||
|
|
f6823d5f13 | ||
|
|
941c7ee61d | ||
|
|
fd259dcde3 | ||
|
|
79ecf7fa59 | ||
|
|
4c761df181 | ||
|
|
94dc688324 | ||
|
|
357dd883db | ||
|
|
3bad5e1d9c | ||
|
|
d09982d99f | ||
|
|
fe7eb582a4 | ||
|
|
c76b4bc9e9 | ||
|
|
55d7d7c026 | ||
|
|
6b645192d4 | ||
|
|
d6bb408078 | ||
|
|
434ced44f0 | ||
|
|
c6e1f45dc3 | ||
|
|
c861bf9a5e | ||
|
|
86be1ef1ec | ||
|
|
c4d52da924 | ||
|
|
a142d4fe20 | ||
|
|
197e86f327 | ||
|
|
b1aa58d446 | ||
|
|
60a178f75e | ||
|
|
6799263317 | ||
|
|
9b80486285 | ||
|
|
3254376d28 | ||
|
|
29c1a0cb78 | ||
|
|
800ffb5e56 | ||
|
|
1cf9f7e990 | ||
|
|
d928325fdf | ||
|
|
b3556c7c91 | ||
|
|
4b112321d2 | ||
|
|
fee1b985c0 | ||
|
|
111eabb84c | ||
|
|
f9bb4d828a | ||
|
|
434b7649c3 | ||
|
|
fc44dd4592 | ||
|
|
8ea0e9ce9c | ||
|
|
94cd83e0dc | ||
|
|
27790532f8 | ||
|
|
90d9c91717 | ||
|
|
32ed2c30c0 | ||
|
|
cf9df6e36d | ||
|
|
915106f360 | ||
|
|
a51e4afb05 | ||
|
|
c30f8fa459 | ||
|
|
46221e936f | ||
|
|
c86891e0c3 | ||
|
|
acf6b839e5 | ||
|
|
1f50e834fc | ||
|
|
6322dbf46a | ||
|
|
0e1aeee3fb | ||
|
|
173f279ac8 | ||
|
|
89e0df86a2 | ||
|
|
7ba9349de2 | ||
|
|
15fb288a5b | ||
|
|
f17e04273d | ||
|
|
76d47bf856 | ||
|
|
d4967018c2 | ||
|
|
8e759d9b5f | ||
|
|
a9cebed903 | ||
|
|
58a70f6ad8 | ||
|
|
05c8158716 | ||
|
|
17b0f2ae77 | ||
|
|
b54e6ea531 | ||
|
|
b702ad4190 | ||
|
|
4fb544d59d | ||
|
|
e37a73ae58 | ||
|
|
c5d2739a39 | ||
|
|
def40c908e | ||
|
|
ef12798fe2 | ||
|
|
c747c15567 | ||
|
|
48a57cd981 | ||
|
|
3ddef07284 | ||
|
|
a65f0a5238 | ||
|
|
ca68150970 | ||
|
|
92f0aa9593 | ||
|
|
b368b9c6d1 | ||
|
|
7e17059154 | ||
|
|
e078d810de | ||
|
|
62bf877046 | ||
|
|
1b56c7ffae | ||
|
|
f7e22ce651 | ||
|
|
b9c2b1de5f | ||
|
|
0c302da0db | ||
|
|
45492365be | ||
|
|
b497e9d867 | ||
|
|
2840935f3d | ||
|
|
69c0e6ee6e | ||
|
|
78b07e0a46 | ||
|
|
5a865774d1 | ||
|
|
8d9667c2e0 | ||
|
|
1f6acc101f | ||
|
|
0d91db68db | ||
|
|
825e788646 | ||
|
|
f3815673c0 | ||
|
|
b070092a64 | ||
|
|
25ede7ad18 | ||
|
|
03d216f116 | ||
|
|
b1cab5ccd2 | ||
|
|
04d0458ae7 | ||
|
|
3b5d54dd96 | ||
|
|
87571450f4 | ||
|
|
766fd626f2 | ||
|
|
be1f711fda | ||
|
|
ef3627321c | ||
|
|
dbcb13f473 | ||
|
|
c1359a71d6 | ||
|
|
b1a26d02c1 | ||
|
|
ceae23eab1 | ||
|
|
ab29303c2e | ||
|
|
ed831c6fc9 | ||
|
|
d86be9d9b3 | ||
|
|
c26bed894b | ||
|
|
27cf5953ae | ||
|
|
d0b3a60a09 | ||
|
|
15f2376c62 | ||
|
|
efeeea37f6 | ||
|
|
5726e52df2 | ||
|
|
a1b596adc0 | ||
|
|
763196f0cc | ||
|
|
ff9048fcf0 | ||
|
|
7d9c86f584 | ||
|
|
6129360b06 | ||
|
|
3c5e91b611 | ||
|
|
e529a79ddb | ||
|
|
45bb9e6706 | ||
|
|
e6d14507e2 | ||
|
|
9a5881fc47 | ||
|
|
f7dd28002e | ||
|
|
496b0ec41d | ||
|
|
02df578939 | ||
|
|
eb4a1e2692 | ||
|
|
e6bec7d2b2 | ||
|
|
80f3bbb0af | ||
|
|
3a117b3bed | ||
|
|
ff91335011 | ||
|
|
01917439dd | ||
|
|
f21c80c48a | ||
|
|
3dc42b711c | ||
|
|
4b2863ca14 | ||
|
|
fe1b4b45b5 | ||
|
|
a20d6aa2b2 | ||
|
|
78e52a0fe3 | ||
|
|
b4b507ecc9 | ||
|
|
d7d19d7594 | ||
|
|
90df4413c3 | ||
|
|
4cd6646cca | ||
|
|
87ed0d31d4 | ||
|
|
921bdd9e3b | ||
|
|
1f51a603f0 | ||
|
|
5fbbdb8e3c | ||
|
|
745da6ba45 | ||
|
|
ad71e612a3 | ||
|
|
85823e8e5d | ||
|
|
b4fa8bebe9 | ||
|
|
7859a9bb1f | ||
|
|
696d8d1d54 | ||
|
|
6e8d3e0d7f | ||
|
|
6a0422fb27 | ||
|
|
26898feb62 | ||
|
|
0311feee9b | ||
|
|
cf601586fc | ||
|
|
f7b988906e | ||
|
|
5777a6d401 | ||
|
|
4807ca0057 | ||
|
|
f1aeec309e | ||
|
|
4b8e275254 | ||
|
|
4b6a75fb60 | ||
|
|
d463491026 | ||
|
|
df3d5e38ce | ||
|
|
4e22d636d3 | ||
|
|
e71841b871 | ||
|
|
e272c5d000 | ||
|
|
0d7740773e | ||
|
|
e4fbb1b640 | ||
|
|
986252d97f | ||
|
|
e0c1fc81e3 | ||
|
|
ee94e9d619 | ||
|
|
264da1ed78 | ||
|
|
ce37c795a7 | ||
|
|
ed2297ab7f | ||
|
|
ae5d8c9aad | ||
|
|
603ff9256c | ||
|
|
a966cab155 | ||
|
|
978dd65528 | ||
|
|
6502920047 | ||
|
|
ed97757dde | ||
|
|
da8ec1565e | ||
|
|
ad85a4a0e3 | ||
|
|
f9a7cdf4dd | ||
|
|
a5296bab95 | ||
|
|
bda7a2b351 | ||
|
|
f23351f11c | ||
|
|
e3f2541fde | ||
|
|
94723dbba3 | ||
|
|
6e0b92a4de | ||
|
|
13a61f5249 | ||
|
|
1347f81236 | ||
|
|
ab93894442 | ||
|
|
8ed6c2094b | ||
|
|
42d7f1ca67 | ||
|
|
cf51e04777 | ||
|
|
8398c12f74 | ||
|
|
2a345e770e | ||
|
|
b3fcf71982 | ||
|
|
3b94a42783 | ||
|
|
453ddaf0d6 | ||
|
|
d4ff36fde0 | ||
|
|
6239858d0a | ||
|
|
1dd873462e | ||
|
|
825c613d64 | ||
|
|
4aa314b3ab | ||
|
|
8e696e3fc4 | ||
|
|
217cf799c2 | ||
|
|
b10a59661e | ||
|
|
0f028db856 | ||
|
|
c194588118 | ||
|
|
398dc8101f | ||
|
|
13cb330711 | ||
|
|
c0740822a3 | ||
|
|
340e627af9 | ||
|
|
3089a710bd | ||
|
|
7d0474335a | ||
|
|
3d5190f51a | ||
|
|
de2de1e1d7 | ||
|
|
91a4f52f67 | ||
|
|
c8af25533d | ||
|
|
b1f76aeda6 | ||
|
|
3fccd03bbb | ||
|
|
3bcfa7e10b | ||
|
|
cbd7c10f3d | ||
|
|
0d09c24840 | ||
|
|
d54d371ab7 | ||
|
|
c90aa0a742 | ||
|
|
7f0bdea212 | ||
|
|
b29d184488 | ||
|
|
168d6b2080 | ||
|
|
b2c970c3bd | ||
|
|
a0445c4f7b | ||
|
|
9074a6fcf1 | ||
|
|
4c5d2f6ebb | ||
|
|
23ce2ec271 | ||
|
|
5bbc2fd94c | ||
|
|
901b8f0424 | ||
|
|
d2705988ac | ||
|
|
291da649c1 | ||
|
|
48e9d3b4e9 | ||
|
|
45e2578c5b | ||
|
|
a6742de405 | ||
|
|
948b5b2d9c | ||
|
|
6cb9714f06 | ||
|
|
c35eaa7a4d | ||
|
|
bececff9e5 | ||
|
|
2826e6f325 | ||
|
|
6bc1f94b60 | ||
|
|
9fd37221f6 | ||
|
|
db3072630a | ||
|
|
5cf6baca88 | ||
|
|
582858c0d4 | ||
|
|
7d56c64a9c | ||
|
|
902b35e189 | ||
|
|
5f6050aaec | ||
|
|
cb94213a04 | ||
|
|
fa6580f622 | ||
|
|
07effffa5e | ||
|
|
e15bcb51aa | ||
|
|
a04e2bc8f6 | ||
|
|
6aad609a48 | ||
|
|
24c0cc10a1 | ||
|
|
e567061e3c | ||
|
|
32ab1c1a06 | ||
|
|
e76d5854b8 | ||
|
|
d3b6c2d0e6 | ||
|
|
ef6cac6e92 | ||
|
|
0c5e72ab6a | ||
|
|
f67c9735c5 | ||
|
|
858e1aed3b | ||
|
|
3b7f2fbdaa | ||
|
|
2c167d6d27 | ||
|
|
f53d7fc9f3 | ||
|
|
04a4957ccf | ||
|
|
b5f7be2384 | ||
|
|
33a0ee37fa | ||
|
|
1eb9858f62 | ||
|
|
b829abf56c | ||
|
|
139a379a09 | ||
|
|
6a8611d98d | ||
|
|
241b93aab5 | ||
|
|
6d08a4386d | ||
|
|
37b4d5e7b5 | ||
|
|
f3b0971d00 | ||
|
|
05e8e53451 | ||
|
|
08251eeab7 | ||
|
|
8c96ba1c58 | ||
|
|
e170c45556 | ||
|
|
a537fe90a0 | ||
|
|
802ad96c49 | ||
|
|
5d979da3e2 | ||
|
|
b843d8e98a | ||
|
|
af6ad96cb6 | ||
|
|
f9e960070d | ||
|
|
1ab949b7ef | ||
|
|
8b39c8f219 | ||
|
|
14b28ba899 | ||
|
|
dd9b6643e6 | ||
|
|
e3f88395ec | ||
|
|
72ee1d186e | ||
|
|
ee53eca19f | ||
|
|
7331b8d5ae | ||
|
|
d17911d753 | ||
|
|
b41d01f126 | ||
|
|
27fc3fd659 | ||
|
|
cc9dc90655 | ||
|
|
015266181e | ||
|
|
299933c4f7 | ||
|
|
5312d6f9fa | ||
|
|
16eb7b3dbd | ||
|
|
cb9458dab4 | ||
|
|
e32a85a33f | ||
|
|
e4680fb0a2 | ||
|
|
1c52e0018a | ||
|
|
ee2838bada | ||
|
|
4d17265e90 | ||
|
|
6a6b860622 | ||
|
|
e78c452daf | ||
|
|
86e33a1ee9 | ||
|
|
37850ad85a | ||
|
|
daca49658e | ||
|
|
6975d7e2cd | ||
|
|
5b8bed6083 | ||
|
|
7474aa3e5d | ||
|
|
c6d2d51d4c | ||
|
|
9055105627 | ||
|
|
a44de63e24 | ||
|
|
8fc7931132 | ||
|
|
4070833229 | ||
|
|
3a9c3f939e | ||
|
|
aa42fb5076 | ||
|
|
50158a7977 | ||
|
|
f2ded359d8 | ||
|
|
0e358bbefe | ||
|
|
2cea561468 | ||
|
|
8024b0a186 | ||
|
|
2b135cf7e0 | ||
|
|
ce8c64a679 | ||
|
|
f0da6ec82f | ||
|
|
46e3b9b5d6 | ||
|
|
d5a08ae568 | ||
|
|
11f63f9b02 | ||
|
|
5694eaba8c | ||
|
|
484481f886 | ||
|
|
210106901e | ||
|
|
eb247b8607 | ||
|
|
fb1453d98a | ||
|
|
b734fb5511 | ||
|
|
2cd6cb8814 | ||
|
|
2a93eab14c | ||
|
|
f039ea68d0 | ||
|
|
e0c35e0002 | ||
|
|
5ace199dc4 | ||
|
|
556895744b | ||
|
|
7f2c60b0d7 | ||
|
|
7bb9e7ee82 | ||
|
|
26be4c3ac8 | ||
|
|
b80517ab15 | ||
|
|
b17cd3696c | ||
|
|
accd554600 | ||
|
|
8bf586cfa9 | ||
|
|
ebea409e6a | ||
|
|
6fdba3d555 | ||
|
|
e865883611 | ||
|
|
9c484e7b57 | ||
|
|
b365e16cc9 | ||
|
|
6a07a2f85d | ||
|
|
0fd7461266 | ||
|
|
62eb0ccd1d | ||
|
|
3367237da3 | ||
|
|
3504987ab3 | ||
|
|
554e625bda | ||
|
|
84530e0817 | ||
|
|
663fb88367 | ||
|
|
4d99c4b59d | ||
|
|
12ee235380 | ||
|
|
e30ed35d69 | ||
|
|
e2f8c7d989 | ||
|
|
ca6a8a7a46 | ||
|
|
f52dae4297 | ||
|
|
d643f8f8f7 | ||
|
|
08a12dd2b0 | ||
|
|
b33dd5d4f5 | ||
|
|
e797ac3a57 | ||
|
|
8bd31f6375 | ||
|
|
d3f83e63c9 | ||
|
|
b450f4797e | ||
|
|
0552084673 | ||
|
|
d021e2b362 | ||
|
|
c769e9cc32 | ||
|
|
639390115b | ||
|
|
ceaf80a186 | ||
|
|
86274b8b94 | ||
|
|
669427eb24 | ||
|
|
5ba22e7554 | ||
|
|
65ad88eed9 | ||
|
|
e34703ea5a | ||
|
|
55bd2c6da6 | ||
|
|
96b5221c1d | ||
|
|
3a94be9abb | ||
|
|
9656b40d53 | ||
|
|
7e61b513f3 | ||
|
|
1d4cbbe418 | ||
|
|
e0e2996e25 | ||
|
|
a102f5fcbf | ||
|
|
4e5d56e2c0 | ||
|
|
a55177edfa | ||
|
|
4c01a749de | ||
|
|
7b61268f22 | ||
|
|
b11dbe4fe1 | ||
|
|
6dbff81f95 | ||
|
|
9893e7a965 | ||
|
|
814c595c12 | ||
|
|
f8b4d04713 | ||
|
|
3cdc8c5884 | ||
|
|
5eabc05396 | ||
|
|
b2932773b9 | ||
|
|
59a04e6dbf | ||
|
|
ddf1e8a179 | ||
|
|
17cc87d633 | ||
|
|
fd7beb642f | ||
|
|
b766cf0807 | ||
|
|
6c9469961b | ||
|
|
d8844236d0 | ||
|
|
60eb59c605 | ||
|
|
6a7bbb8752 | ||
|
|
e4431749e1 | ||
|
|
c587b357eb | ||
|
|
7357c26d54 | ||
|
|
73ca45ad3d | ||
|
|
bf00503d1f |
178
.clang-format
178
.clang-format
@@ -1,178 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: false
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: false
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: AfterComma
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: true
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentExternBlock: Indent
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: 4
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
ShortNamespaceLines: 5
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 4
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,3 +1 @@
|
||||
lib/external/** linguist-vendored
|
||||
lib/libimhex-rs/imgui-rs/** linguist-vendored
|
||||
lib/libimhex-rs/imgui-sys/** linguist-vendored
|
||||
lib/external/** linguist-vendored
|
||||
10
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,6 +1,7 @@
|
||||
name: Bug Report
|
||||
description: Something doesn't work correctly in ImHex.
|
||||
title: "[Bug] "
|
||||
labels: bug
|
||||
body:
|
||||
- type: dropdown
|
||||
id: os
|
||||
@@ -39,10 +40,17 @@ body:
|
||||
label: ImHex Build Type
|
||||
options:
|
||||
- label: Nightly or built from sources
|
||||
- type: input
|
||||
attributes:
|
||||
label: Installation type
|
||||
description: |
|
||||
How did you install ImHex ? MSI/Portable/DMG/AppImage/Fedora package/etc..
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context?
|
||||
value: |
|
||||
placeholder: |
|
||||
- Additional information about your environment.
|
||||
- If possible and useful, please upload the binary you've been editing when the bug occurred.
|
||||
validations:
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -1,6 +1,7 @@
|
||||
name: Feature Request
|
||||
description: Something you'd like to see added to ImHex in the future
|
||||
title: "[Feature] "
|
||||
labels: feature request
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
@@ -20,3 +21,6 @@ body:
|
||||
label: Request Type
|
||||
options:
|
||||
- label: I can provide a PoC for this feature or am willing to work on it myself and submit a PR
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context?
|
||||
|
||||
17
.github/workflows/analysis.yml
vendored
17
.github/workflows/analysis.yml
vendored
@@ -25,21 +25,20 @@ jobs:
|
||||
with:
|
||||
languages: 'cpp'
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
|
||||
439
.github/workflows/build.yml
vendored
439
.github/workflows/build.yml
vendored
@@ -28,21 +28,13 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Prepare Cache
|
||||
id: prep-ccache
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p "${CCACHE_DIR}"
|
||||
echo "::set-output name=dir::$CCACHE_DIR"
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
id: cache-ccache
|
||||
with:
|
||||
path: |
|
||||
${{ steps.prep-ccache.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
@@ -64,70 +56,64 @@ jobs:
|
||||
glfw:p
|
||||
file:p
|
||||
mbedtls:p
|
||||
python:p
|
||||
freetype:p
|
||||
dlfcn:p
|
||||
libbacktrace:p
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://win.rustup.rs > rustup-init.exe
|
||||
./rustup-init.exe -y --default-host=x86_64-pc-windows-gnu --default-toolchain=none
|
||||
rm rustup-init.exe
|
||||
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
|
||||
$USERPROFILE/.cargo/bin/rustup.exe default nightly
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
# Windows cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
# Get path to mingw python library
|
||||
PYTHON_LIB_NAME=$(pkg-config --libs-only-l python3 | sed 's/^-l//' | sed 's/ //')
|
||||
PYTHON_LIB_PATH=$(cygpath -m $(which lib${PYTHON_LIB_NAME}.dll))
|
||||
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DPython_LIBRARY="$PYTHON_LIB_PATH" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
..
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
|
||||
|
||||
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Installer
|
||||
name: Windows Installer x86_64
|
||||
path: |
|
||||
build/*.msi
|
||||
imhex-*.msi
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
name: Windows Portable x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
|
||||
- name: ⬇️ Download Mesa3D for NoGPU version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
||||
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
|
||||
curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
mv opengl32.dll build/install
|
||||
|
||||
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable NoGPU
|
||||
name: Windows Portable NoGPU x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
@@ -142,7 +128,7 @@ jobs:
|
||||
custom_glfw: true
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
|
||||
name: 🍎 macOS 11.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
@@ -154,16 +140,14 @@ jobs:
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Caches/ccache
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -174,13 +158,13 @@ jobs:
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
run: |
|
||||
brew install glfw
|
||||
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
uses: actions/checkout@v3
|
||||
@@ -197,12 +181,14 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
@@ -211,30 +197,32 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
|
||||
..
|
||||
make -j4 package
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG${{matrix.suffix}}
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: build/*.dmg
|
||||
|
||||
# Ubuntu build
|
||||
@@ -248,44 +236,24 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore other caches
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
build-appimage/CMakeCache.txt
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
|
||||
sudo chmod +x /usr/local/bin/appimagetool
|
||||
sudo pip3 install appimage-builder==1.0.0
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
||||
sh rustup-init.sh -y --default-toolchain none
|
||||
rm rustup-init.sh
|
||||
$HOME/.cargo/bin/rustup install nightly
|
||||
$HOME/.cargo/bin/rustup target add x86_64-unknown-linux-gnu
|
||||
$HOME/.cargo/bin/rustup default nightly
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
@@ -297,10 +265,10 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=DebDir
|
||||
|
||||
@@ -308,23 +276,59 @@ jobs:
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
#- name: 📦 Bundle Flatpak
|
||||
# run: |
|
||||
# sudo apt install flatpak flatpak-builder
|
||||
# flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
# flatpak --user install -y flathub org.freedesktop.Platform//20.08
|
||||
# flatpak --user install -y flathub org.freedesktop.Sdk//20.08
|
||||
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
||||
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/DebDir
|
||||
dpkg-deb -Zgzip --build build/DebDir
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04-x86_64.deb
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Ubuntu 22.04 DEB x86_64
|
||||
path: '*.deb'
|
||||
|
||||
# AppImage build
|
||||
appimage:
|
||||
runs-on: ubuntu-22.04
|
||||
name: ⬇️ AppImage
|
||||
steps:
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build-appimage/CMakeCache.txt
|
||||
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
|
||||
sudo chmod +x /usr/local/bin/appimagetool
|
||||
sudo pip3 install git+https://github.com/iTrooz/appimage-builder@dpkg-package-versions
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
# AppImage cmake build
|
||||
- name: 🛠️ Reconfigure build for AppImage
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build-appimage
|
||||
cd build-appimage
|
||||
@@ -333,10 +337,10 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
-DIMHEX_USE_BUNDLED_CA=ON \
|
||||
..
|
||||
@@ -347,38 +351,24 @@ jobs:
|
||||
cd build-appimage
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
cd ..
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: Linux Flatpak
|
||||
# path: |
|
||||
# imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Ubuntu 22.04 DEB
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
name: Linux AppImage x86_64
|
||||
path: 'build-appimage/*.AppImage'
|
||||
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage zsync
|
||||
name: Linux AppImage zsync x86_64
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
name: 🐧 ArchLinux
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
container:
|
||||
image: archlinux:base-devel
|
||||
|
||||
@@ -390,7 +380,7 @@ jobs:
|
||||
- name: ⬇️ Install setup dependencies
|
||||
run: |
|
||||
pacman -Syu git ccache --noconfirm
|
||||
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -400,21 +390,20 @@ jobs:
|
||||
run: |
|
||||
dist/get_deps_archlinux.sh --noconfirm
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
# ArchLinux cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
@@ -425,21 +414,22 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-DUSE_SYSTEM_FMT=ON \
|
||||
-DUSE_SYSTEM_YARA=ON \
|
||||
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-DUSE_SYSTEM_CAPSTONE=OFF \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=installDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
cp dist/Arch/PKGBUILD build
|
||||
@@ -449,93 +439,146 @@ jobs:
|
||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||
run: |
|
||||
cd build
|
||||
|
||||
|
||||
# the name is a small trick to make makepkg recognize it as the source
|
||||
# else, it would try to download the file from the release
|
||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst -C installDir .
|
||||
|
||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
||||
|
||||
chmod -R 777 .
|
||||
|
||||
|
||||
sudo -u nobody makepkg
|
||||
|
||||
# Replace the old file
|
||||
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
|
||||
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
|
||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ArchLinux .pkg.tar.zst
|
||||
name: ArchLinux .pkg.tar.zst x86_64
|
||||
path: |
|
||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
|
||||
# Fedora build
|
||||
fedora-build:
|
||||
# RPM distro builds
|
||||
rpm-build:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- docker_image: fedora:latest
|
||||
release: Latest
|
||||
- docker_image: fedora:rawhide
|
||||
release: Rawhide
|
||||
- name: Fedora
|
||||
mock_release: rawhide
|
||||
release_num: rawhide
|
||||
mock_config: fedora-rawhide
|
||||
- name: Fedora
|
||||
mock_release: f38
|
||||
release_num: 38
|
||||
mock_config: fedora-38
|
||||
- name: Fedora
|
||||
mock_release: f37
|
||||
release_num: 37
|
||||
mock_config: fedora-37
|
||||
- name: Fedora
|
||||
mock_release: f36
|
||||
release_num: 36
|
||||
mock_config: fedora-36
|
||||
- name: RHEL-AlmaLinux
|
||||
mock_release: epel9
|
||||
release_num: 9
|
||||
mock_config: "alma+epel-9"
|
||||
|
||||
|
||||
name: 🐧 Fedora ${{ matrix.release }}
|
||||
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
container:
|
||||
image: "${{ matrix.docker_image }}"
|
||||
image: "fedora:latest"
|
||||
options: --privileged
|
||||
|
||||
steps:
|
||||
- name: ⬇️ Update all packages
|
||||
run: |
|
||||
dnf upgrade -y
|
||||
- name: ⬇️ Install git-core
|
||||
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
|
||||
|
||||
- name: ⬇️ Install setup dependencies
|
||||
run: |
|
||||
dnf install -y \
|
||||
ccache \
|
||||
desktop-file-utils \
|
||||
fmt-devel \
|
||||
git \
|
||||
json-devel \
|
||||
libcurl-devel \
|
||||
llvm-devel \
|
||||
mbedtls-devel \
|
||||
python3-devel \
|
||||
rpm-build \
|
||||
yara-devel
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ImHex
|
||||
submodules: recursive
|
||||
|
||||
- name: ⬇️ Install ImHex dependencies
|
||||
run: |
|
||||
dist/get_deps_fedora.sh
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
- name: 📜 Setup DNF Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
path: /var/cache/dnf
|
||||
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-
|
||||
|
||||
- name: ⬇️ Update all packages and install dependencies
|
||||
run: |
|
||||
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
|
||||
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
|
||||
fedpkg \
|
||||
ccache
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
echo "IMHEX_VERSION=`cat ImHex/VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: 🗜️ Create tarball from sources with dependencies
|
||||
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
|
||||
|
||||
- name: ✒️ Modify spec file
|
||||
run: |
|
||||
sed -i \
|
||||
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
|
||||
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
|
||||
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
|
||||
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 📜 Fix ccache on EL9
|
||||
if: matrix.mock_release == 'epel9'
|
||||
run: sed -i '/\. \/opt\/rh\/gcc-toolset-12\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 🟩 Copy spec file to build root
|
||||
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
|
||||
|
||||
- name: 📜 Enable ccache for mock
|
||||
run: |
|
||||
cat <<EOT > $GITHUB_WORKSPACE/mock.cfg
|
||||
include('${{ matrix.mock_config }}-x86_64.cfg')
|
||||
config_opts['plugin_conf']['ccache_enable'] = True
|
||||
config_opts['plugin_conf']['ccache_opts']['max_cache_size'] = '1G'
|
||||
config_opts['plugin_conf']['ccache_opts']['compress'] = True
|
||||
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
||||
EOT
|
||||
|
||||
- name: 📜 Setup Mock Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /var/cache/mock
|
||||
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
|
||||
|
||||
# Fedora cmake build (in imhex.spec)
|
||||
- name: 📦 Build RPM
|
||||
run: |
|
||||
rpmbuild -ba --define "_version ${{env.IMHEX_VERSION}}" --define "_src_path $GITHUB_WORKSPACE" --define "_build_type $BUILD_TYPE" $GITHUB_WORKSPACE/dist/rpm/imhex.spec
|
||||
mv ~/rpmbuild/RPMS/x86_64/*.rpm imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
|
||||
|
||||
fedpkg --path $GITHUB_WORKSPACE --release ${{ matrix.mock_release }} mockbuild --enable-network -N --root $GITHUB_WORKSPACE/mock.cfg extra_args -- -v
|
||||
|
||||
- name: 🟩 Move and rename finished RPM
|
||||
run: |
|
||||
mv $GITHUB_WORKSPACE/results_imhex/${{env.IMHEX_VERSION}}/*/imhex-${{env.IMHEX_VERSION}}-0.*.x86_64.rpm \
|
||||
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
- name: ⬆️ Upload RPM
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Fedora ${{ matrix.release }} RPM
|
||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||
path: |
|
||||
imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
|
||||
imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
105
.github/workflows/release.yml
vendored
105
.github/workflows/release.yml
vendored
@@ -9,9 +9,54 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release-common:
|
||||
release-update-repos:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release Common
|
||||
name: Release Update Repos
|
||||
|
||||
steps:
|
||||
- name: 🎫 Create PatternLanguage release
|
||||
uses: ncipollo/release-action@v1
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: PatternLanguage
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: 🎫 Create ImHex-Patterns release
|
||||
uses: ncipollo/release-action@v1
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: ImHex-Patterns
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repository: WerWolv/ImHex-Cpp-Plugin-Template
|
||||
event-type: update_submodule
|
||||
|
||||
- name: ✉️ Update Rust Plugin Template
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repository: WerWolv/ImHex-Rust-Plugin-Template
|
||||
event-type: update_submodule
|
||||
|
||||
release-upload-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release Upload Artifacts
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -34,7 +79,7 @@ jobs:
|
||||
|
||||
- name: 🗜️ Create tarball from sources with dependencies
|
||||
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
||||
|
||||
|
||||
- name: ⬇️ Download artifacts from latest workflow
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
@@ -43,7 +88,7 @@ jobs:
|
||||
branch: ${{ github.event.release.target_commitish }}
|
||||
workflow_conclusion: success
|
||||
skip_unpack: true
|
||||
|
||||
|
||||
- name: 🗜️ Unzip files when needed
|
||||
run: |
|
||||
for zipfile in ./*.zip
|
||||
@@ -60,8 +105,8 @@ jobs:
|
||||
|
||||
- name: 🟩 Rename artifacts when needed
|
||||
run: |
|
||||
mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
mv "Windows Portable NoGPU.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU.zip
|
||||
mv "Windows Portable x86_64.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-x86_64.zip
|
||||
mv "Windows Portable NoGPU x86_64.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU-x86_64.zip
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -72,14 +117,13 @@ jobs:
|
||||
run: |
|
||||
cp ImHex/dist/Arch/PKGBUILD .
|
||||
|
||||
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst | cut -d ' ' -f 1`
|
||||
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
|
||||
|
||||
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' PKGBUILD
|
||||
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
|
||||
|
||||
- name: ⬆️ Publish AUR package
|
||||
|
||||
# I couldn't make the condition in the env directly for some reason
|
||||
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
|
||||
@@ -94,46 +138,15 @@ jobs:
|
||||
commit_message: Bump to version ${{env.IMHEX_VERSION}}
|
||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||
|
||||
- name: 🎫 Create PatternLanguage release
|
||||
uses: ncipollo/release-action@v1
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: PatternLanguage
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: 🎫 Create ImHex-Patterns release
|
||||
uses: ncipollo/release-action@v1
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: ImHex-Patterns
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Cpp-Plugin-Template
|
||||
owner: WerWolv
|
||||
event_type: update_submodule
|
||||
|
||||
release-windows:
|
||||
name: Release Windows
|
||||
needs: release-common
|
||||
runs-on: windows-2022
|
||||
release-update-winget:
|
||||
name: Release update winget package
|
||||
needs: release-upload-artifacts
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: ⬇️ Download dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||
- name: ⬆️ Update winget manifest
|
||||
shell: pwsh
|
||||
env:
|
||||
@@ -142,7 +155,7 @@ jobs:
|
||||
run: |
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-win64.msi"
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"
|
||||
.\wingetcreate.exe update WerWolv.ImHex -u $url --version $version
|
||||
if ($version -notmatch "-") {
|
||||
.\wingetcreate.exe submit .\manifests\w\WerWolv\ImHex\${version}\ --token $env:WINGET_GITHUB_TOKEN
|
||||
|
||||
20
.github/workflows/tests.yml
vendored
20
.github/workflows/tests.yml
vendored
@@ -22,22 +22,21 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -49,14 +48,13 @@ jobs:
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
make -j4 unit_tests install
|
||||
make -j4 unit_tests
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,15 +2,9 @@
|
||||
.idea/
|
||||
|
||||
cmake-build-*/
|
||||
|
||||
build-linux/
|
||||
build*/
|
||||
venv/
|
||||
|
||||
*.mgc
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
plugins/.rustc_info.json
|
||||
|
||||
**/target
|
||||
|
||||
plugins/example_rust/Cargo.lock
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -29,3 +29,6 @@
|
||||
[submodule "lib/external/pattern_language"]
|
||||
path = lib/external/pattern_language
|
||||
url = https://github.com/WerWolv/PatternLanguage
|
||||
[submodule "lib/external/libwolv"]
|
||||
path = lib/external/libwolv
|
||||
url = https://github.com/WerWolv/libwolv
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/../../../../../:\_Dev\Cpp\HexEditor\.idea/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
imhex
|
||||
14
.idea/deployment.xml
generated
14
.idea/deployment.xml
generated
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
|
||||
<serverData>
|
||||
<paths name="WSL (e494f5fa-cb38-49f1-b2cb-b9524b92ed51)">
|
||||
<serverdata>
|
||||
<mappings>
|
||||
<mapping local="$PROJECT_DIR$" web="/" />
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
</serverData>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/imhex.iml
generated
2
.idea/imhex.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/imhex.iml" filepath="$PROJECT_DIR$/.idea/imhex.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
16
.idea/vcs.xml
generated
16
.idea/vcs.xml
generated
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/cli11" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -8,9 +8,12 @@ option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
|
||||
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
|
||||
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
||||
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
|
||||
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
|
||||
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
@@ -18,7 +21,11 @@ include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
# Setup project
|
||||
loadVersion(IMHEX_VERSION)
|
||||
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
project(imhex
|
||||
LANGUAGES C CXX VERSION ${IMHEX_VERSION}
|
||||
DESCRIPTION "The ImHex Hex Editor"
|
||||
HOMEPAGE_URL "https://imhex.werwolv.net"
|
||||
)
|
||||
|
||||
# Make sure project is configured correctly
|
||||
setDefaultBuiltTypeIfUnset()
|
||||
@@ -36,11 +43,13 @@ detectOS()
|
||||
detectArch()
|
||||
addVersionDefines()
|
||||
configurePackingResources()
|
||||
setUninstallTarget()
|
||||
addBundledLibraries()
|
||||
|
||||
# Add ImHex sources
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main libimhex)
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
|
||||
67
HACKING.md
Normal file
67
HACKING.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Hacking guide
|
||||
|
||||
## Introduction
|
||||
|
||||
This document is a guide for developers who want to contribute to ImHex in any way. It contains information about the codebase, the build process and the general workflow.
|
||||
|
||||
## Codebase
|
||||
|
||||
ImHex is written in C++ and usually uses the latest compiler and standard library features available in gcc on all supported OSes. At the time of writing this is C++23.
|
||||
|
||||
### Structure
|
||||
|
||||
- `main`: Contains the main application code
|
||||
- Important to understand here is that the main ImHex application is basically just an empty shell.
|
||||
- All it does is create a Window and a OpenGL context using GLFW, load all available plugins, properly configure ImGui and render it to the screen.
|
||||
- Everything else is done inside of plugins. ImHex comes with a few plugins by default, most notably the `builtin` plugin which contains the majority of the application code.
|
||||
- In most cases, this code doesn't need to be modified. Most features should be self-contained inside a plugin.
|
||||
- `lib`
|
||||
- `libimhex`: Contains all helper utilities as well as various APIs for plugins to interact with ImHex.
|
||||
- The library's main purpose is for Dependency Inversion. The ImHex main application as well as libimhex do not know about the existence of plugins at build time. Plugins and the main application instead link against libimhex and use it as a common API to interact with each other.
|
||||
- Since libimhex is a doesn't know about the existence of plugins, it cannot depend on any of them. This includes localizations and things that get registered by plugins after launch.
|
||||
- Even if the builtin plugin is technically always available, it is still a plugin and should be treated that way.
|
||||
- All important APIs can be found in the `hex/api` include directory and are documented in the respective header file.
|
||||
- `external`: All libraries that need custom patches or aren't typically available in package managers go into here.
|
||||
- If you'd like to add new features to the Pattern language, please make a PR to https://github.com/WerWolv/PatternLanguage instead. ImHex usually depends on the latest commit of the master branch of this repo.
|
||||
- `plugins`
|
||||
- `builtin`: The builtin plugin. Contains the majority of the application code.
|
||||
- It's the heart of ImHex's functionality. It contains most of the default views, providers, etc. so if you want to add new functionality to ImHex, this is the place to start.
|
||||
- `tests`: Contains all unit tests for ImHex. These are run automatically by the CI and should be kept up to date, especially when adding new helper functions to libimhex.
|
||||
|
||||
### RomFS
|
||||
|
||||
ImHex uses a custom library called [libromfs](https://github.com/WerWolv/libromfs). It's a simple static library which uses CMake's code generation feature to embed files into the binary at compile time so they can be accessed at runtime.
|
||||
All plugins have a `romfs` folder which contains all files that should be embedded into the binary. Resources that need to be embedded into the main application (this is usually not necessary), go into the `resources/romfs` folder.
|
||||
When adding, changing files or removing files, make sure to re-run CMake to update the generated code. Otherwise, the changes might not be reflected in the binary.
|
||||
|
||||
## Development Environment
|
||||
|
||||
I personally use CLion for development since it makes configuring and building the project very easy on all platforms.
|
||||
|
||||
### Windows
|
||||
- Install MSYS2 from https://www.msys2.org/ and use the `dist/get_deps_msys2.sh` script to install all dependencies.
|
||||
### Linux
|
||||
- Install all dependencies using one of the `dist/get_deps_*.sh` scripts depending on your distribution or install them manually with your package manager.
|
||||
### macOS
|
||||
- Install all dependencies using brew and the `dist/Brewfile` script.
|
||||
|
||||
## Making Changes
|
||||
|
||||
### Adding new features to ImHex
|
||||
|
||||
If you'd like to add new features, the best way to start is by joining our Discord and telling us about your idea. We can then discuss the best way to implement it and how it should be integrated into ImHex or if it should be done in a separate plugin.
|
||||
|
||||
There are standalone plugin templates that use ImHex as a submodule. You can find them here:
|
||||
- https://github.com/WerWolv/ImHex-Cpp-Plugin-Template
|
||||
- https://github.com/WerWolv/ImHex-Rust-Plugin-Template
|
||||
|
||||
### Adding a new language
|
||||
|
||||
If you'd like to support a new language in ImHex, the best way is by using the `dist/langtool.py` tool. It will create the necessary file for you and help you fill them out.
|
||||
First, run the tool with `python3 dist/langtool.py create plugins/builtin/romfs/lang <iso_code>` where `<iso_code>` is the ISO 639-1 code of your language. This will create a new file in the language directory.
|
||||
Afterwards follow the prompts of the program to populate the entire file. Once you're done, rerun cmake and rebuild ImHex. Your language should now be available in the settings.
|
||||
|
||||
### Updating an existing language
|
||||
|
||||
If you'd like to add missing keys to an existing language, you can also use the `dist/langtool.py` tool. Run it with `python3 dist/langtool.py translate plugins/builtin/romfs/lang <iso_code>` where `<iso_code>` is the ISO 639-1 code of the language.
|
||||
This will one by one list all the missing translation keys that are present in the default translation file, and you can fill them in with the correct translation for your language.
|
||||
101
INSTALL.md
Normal file
101
INSTALL.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Installing ImHex
|
||||
|
||||
## Official Releases
|
||||
|
||||
The easiest way to install ImHex is to download the latest release from the [GitHub Releases page](https://github.com/WerWolv/ImHex/releases/latest).
|
||||
|
||||
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
|
||||
|
||||
### Windows
|
||||
|
||||
#### Installer
|
||||
Simply run the installer to install ImHex on your system
|
||||
|
||||
#### Portable
|
||||
Extract the zip file to any location on your system.
|
||||
|
||||
### macOS
|
||||
Simply use the drag-n-drop dmg package to install ImHex on your system. It's possible that you need to allow the app to run in the security settings.
|
||||
|
||||
### Linux
|
||||
|
||||
#### AppImage
|
||||
To run the AppImage, make sure it's executable. Then simply run it.
|
||||
|
||||
```bash
|
||||
chmod +x imhex-*.AppImage
|
||||
./imhex-*.AppImage
|
||||
```
|
||||
|
||||
#### Flatpak
|
||||
To install the Flatpak, make sure you have the Flathub repository added to your system. Then simply run the following command:
|
||||
|
||||
```bash
|
||||
flatpak install flathub net.werwolv.ImHex
|
||||
```
|
||||
|
||||
#### Ubuntu DEB Package
|
||||
To install the DEB package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo apt install ./imhex-*.deb
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
To install the Arch Linux package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo pacman -U imhex-*.pkg.tar.zst
|
||||
```
|
||||
|
||||
#### Fedora / RHEL / AlmaLinux RPM Package
|
||||
To install the RPM package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo dnf install ./imhex-*.rpm
|
||||
```
|
||||
|
||||
## Nightly Builds
|
||||
|
||||
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
|
||||
These builds are not guaranteed to be stable and may contain bugs, however they also contain new features that are not yet available in the official releases.
|
||||
|
||||
## Building from source
|
||||
|
||||
Build instructions for Windows, Linux and macOS can be found under `/dist/compiling`:
|
||||
- Windows: [Link](dist/compiling/windows.md)
|
||||
- macOS: [Link](dist/compiling/macos.md)
|
||||
- Linux: [Link](dist/compiling/linux.md)
|
||||
|
||||
## Package managers
|
||||
|
||||
ImHex is also available on various package managers. The officially supported ones are listed here:
|
||||
|
||||
### Windows
|
||||
|
||||
- **Chocolatey**
|
||||
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
|
||||
- `choco install imhex`
|
||||
- **Winget**
|
||||
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
|
||||
- `winget install WerWolv.ImHex`
|
||||
|
||||
### Linux
|
||||
- **Arch Linux AUR**
|
||||
- [imhex-bin](https://aur.archlinux.org/packages/imhex-bin/) (Thanks to @iTrooz)
|
||||
- `yay -S imhex-bin`
|
||||
- [imhex](https://aur.archlinux.org/packages/imhex/) (Thanks to @KokaKiwi)
|
||||
- `yay -S imhex`
|
||||
- **Fedora**
|
||||
- [imhex](https://src.fedoraproject.org/rpms/imhex/) (Thanks to @jonathanspw)
|
||||
- `dnf install imhex`
|
||||
- **Flatpak**
|
||||
- [net.werwolv.Imhex](https://flathub.org/apps/details/net.werwolv.ImHex) (Thanks to @Mailaender)
|
||||
- `flatpak install flathub net.werwolv.ImHex`
|
||||
|
||||
### Available on other package managers
|
||||
|
||||
Packages that aren't explicitly mentioned above are not officially supported but they will most likely still work.
|
||||
Contact the maintainer of the package if you have any issues.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
93
README.md
93
README.md
@@ -1,11 +1,33 @@
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" ><img height="100px" src="resources/projects/logo_text.svg"></h1></a>
|
||||
<a href="https://imhex.werwolv.net">
|
||||
<h1 align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
|
||||
<img height="100px" src="./resources/projects/logo_text_dark.svg">
|
||||
</picture>
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
<p align="center">
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/workflow/status/WerWolv/ImHex/Build?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions"></a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&style=for-the-badge"></a>
|
||||
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest"><img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub"></a>
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild">
|
||||
<img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master">
|
||||
</a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY">
|
||||
<img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge">
|
||||
</a>
|
||||
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest">
|
||||
<img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub">
|
||||
</a>
|
||||
<a title="Code Quality" href="https://www.codefactor.io/repository/github/werwolv/imhex">
|
||||
<img alt="Code Quality" src="https://img.shields.io/codefactor/grade/github/WerWolv/ImHex?longCache=true&style=for-the-badge&label=Code%20Quality&logoColor=fff&logo=CodeFactor&branch=master">
|
||||
</a>
|
||||
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
|
||||
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
|
||||
</a>
|
||||
<a title="Documentation" href="https://imhex.werwolv.net/docs">
|
||||
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-green?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Supporting
|
||||
@@ -104,7 +126,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
## Pattern Language
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
The Pattern Language is the completely custom programming language developed for ImHex.
|
||||
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
|
||||
|
||||
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
|
||||
- Documentation: [Link](https://imhex.werwolv.net/docs/)
|
||||
|
||||
## Database
|
||||
|
||||
@@ -116,53 +142,17 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
|
||||
|
||||
To use ImHex, the following minimal system requirements need to be met:
|
||||
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora 36/37, RHEL/AlmaLinux 9, and Arch Linux have official packages, other and older distributions can use the AppImage)
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
|
||||
- **RAM**: 512MB, more may be required for more complicated analysis
|
||||
- **GPU**: OpenGL 3.0 or higher
|
||||
- Intel HD drivers are really buggy and often cause graphic artifacts
|
||||
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
|
||||
- **RAM**: 256MB, more may be required for more complicated analysis
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
## Installing
|
||||
The following OSs have packages available in their repositories making it easy to install ImHex.
|
||||
### Fedora (36+)
|
||||
```
|
||||
dnf install imhex
|
||||
```
|
||||
|
||||
### RHEL 9 / AlmaLinux 9 (coming soon)
|
||||
|
||||
### Arch Linux (AUR)
|
||||
```
|
||||
yay -S imhex-bin
|
||||
```
|
||||
|
||||
## Third Party Repositories
|
||||
|
||||
ImHex is available in various thid party repositores.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
|
||||
## Nightly builds
|
||||
|
||||
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
||||
|
||||
- Windows • __x86_64__
|
||||
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable.zip)
|
||||
- MacOS • __x86_64__
|
||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||
- Linux • __x86_64__
|
||||
- [Ubuntu 22.04 DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Ubuntu%2022.04%20DEB.zip)
|
||||
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
|
||||
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
|
||||
- [Fedora Rawhide RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Rawhide%20RPM.zip)
|
||||
- [Fedora Stable RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Latest%20RPM.zip)
|
||||
Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
|
||||
|
||||
## Compiling
|
||||
|
||||
@@ -173,6 +163,15 @@ All releases are being built using latest available GCC.
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For more information, check out the [Compiling](/dist/compiling) guide.
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
@@ -14,13 +14,16 @@ macro(addVersionDefines)
|
||||
message(FATAL_ERROR "IMHEX_VERSION is not defined")
|
||||
endif ()
|
||||
|
||||
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
|
||||
if (DEFINED IMHEX_COMMIT_HASH AND DEFINED IMHEX_COMMIT_BRANCH)
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${IMHEX_COMMIT_HASH}" GIT_BRANCH="${IMHEX_COMMIT_BRANCH}")
|
||||
else()
|
||||
# Get the current working branch
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_BRANCH
|
||||
)
|
||||
|
||||
# Get the latest abbreviated commit hash of the working branch
|
||||
@@ -29,9 +32,12 @@ macro(addVersionDefines)
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_HASH
|
||||
)
|
||||
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
|
||||
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH EQUAL 0)
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
|
||||
@@ -41,7 +47,7 @@ macro(addVersionDefines)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
|
||||
add_compile_definitions(DEBUG)
|
||||
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||
@@ -52,31 +58,6 @@ macro(addVersionDefines)
|
||||
|
||||
endmacro()
|
||||
|
||||
macro(configurePython)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
|
||||
# Enforce that we use non system Python 3 on macOS.
|
||||
set(Python_FIND_FRAMEWORK NEVER)
|
||||
|
||||
find_package(Python COMPONENTS Development REQUIRED)
|
||||
if(Python_VERSION LESS 3)
|
||||
message(STATUS ${PYTHON_VERSION_MAJOR_MINOR})
|
||||
message(FATAL_ERROR "No valid version of Python 3 was found.")
|
||||
endif()
|
||||
|
||||
string(REPLACE "." ";" PYTHON_VERSION_MAJOR_MINOR ${Python_VERSION})
|
||||
|
||||
list(LENGTH PYTHON_VERSION_MAJOR_MINOR PYTHON_VERSION_COMPONENT_COUNT)
|
||||
|
||||
if (PYTHON_VERSION_COMPONENT_COUNT EQUAL 3)
|
||||
list(REMOVE_AT PYTHON_VERSION_MAJOR_MINOR 2)
|
||||
endif ()
|
||||
list(JOIN PYTHON_VERSION_MAJOR_MINOR "." PYTHON_VERSION_MAJOR_MINOR)
|
||||
|
||||
add_compile_definitions(PYTHON_VERSION_MAJOR_MINOR="${PYTHON_VERSION_MAJOR_MINOR}")
|
||||
endmacro()
|
||||
|
||||
# Detect current OS / System
|
||||
macro(detectOS)
|
||||
if (WIN32)
|
||||
@@ -85,7 +66,9 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
|
||||
SET(IMHEX_USE_BUNDLED_CA ON)
|
||||
if (NOT USE_SYSTEM_CURL)
|
||||
SET(IMHEX_USE_BUNDLED_CA ON)
|
||||
endif ()
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -135,12 +118,11 @@ macro(configurePackingResources)
|
||||
if (WIN32)
|
||||
set(APPLICATION_TYPE)
|
||||
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/resource.rc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-subsystem,windows")
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_PACKAGE_NAME "imhex")
|
||||
set(CPACK_PACKAGE_NAME "ImHex")
|
||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
||||
@@ -223,7 +205,6 @@ macro(createPackage)
|
||||
|
||||
# Grab all dynamically linked dependencies.
|
||||
INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
|
||||
INSTALL(CODE "get_filename_component(PY_PARENT \"${Python_LIBRARIES}\" DIRECTORY)")
|
||||
INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
|
||||
install(CODE [[
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
@@ -334,6 +315,7 @@ function(loadVersion version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
string(STRIP ${read_version} read_version)
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -390,7 +372,9 @@ function(downloadImHexPatternsFiles dest)
|
||||
GIT_TAG master
|
||||
)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...")
|
||||
FetchContent_MakeAvailable(imhex_patterns)
|
||||
message(STATUS "Finished downloading ImHex-Patterns")
|
||||
|
||||
else ()
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
@@ -407,10 +391,166 @@ function(downloadImHexPatternsFiles dest)
|
||||
endfunction()
|
||||
|
||||
macro(setupCompilerWarnings target)
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread")
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-array-bounds")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
||||
# uninstall target
|
||||
macro(setUninstallTarget)
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(addBundledLibraries)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
set(EXTERN_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/imgui)
|
||||
set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
||||
set(CURL_USE_MBEDTLS ON)
|
||||
set(BUILD_CURL_EXE OFF)
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
|
||||
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(FMT_LIBRARIES fmt::fmt-header-only)
|
||||
else()
|
||||
find_package(fmt 8.0.0 REQUIRED)
|
||||
set(FMT_LIBRARIES fmt::fmt)
|
||||
endif()
|
||||
|
||||
if (IMHEX_USE_GTK_FILE_PICKER)
|
||||
set(NFD_PORTAL OFF CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
else ()
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use GTK for Linux file dialogs" FORCE)
|
||||
endif ()
|
||||
|
||||
if (NOT USE_SYSTEM_NFD)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
else()
|
||||
find_package(nfd)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/nlohmann_json EXCLUDE_FROM_ALL)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
else()
|
||||
find_package(nlohmann_json 3.10.2 REQUIRED)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_CURL)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/yara EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_MINIAUDIO)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
|
||||
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(MINIAUDIO_LIBRARIES miniaudio)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_CAPSTONE)
|
||||
set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${EXTERN_LIBS_FOLDER}/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
|
||||
pkg_search_module(MAGIC libmagic>=5.39)
|
||||
if(NOT MAGIC_FOUND)
|
||||
find_library(MAGIC 5.39 magic REQUIRED)
|
||||
else()
|
||||
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
||||
endif()
|
||||
|
||||
if (NOT IMHEX_DISABLE_STACKTRACE)
|
||||
if (WIN32)
|
||||
message(STATUS "StackWalk enabled!")
|
||||
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
|
||||
else ()
|
||||
find_package(Backtrace)
|
||||
if (${Backtrace_FOUND})
|
||||
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
|
||||
|
||||
if (Backtrace_HEADER STREQUAL "execinfo.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(HEX_HAS_EXECINFO)
|
||||
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(HEX_HAS_BACKTRACE)
|
||||
endif ()
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
21
cmake/cmake_uninstall.cmake.in
Normal file
21
cmake/cmake_uninstall.cmake.in
Normal file
@@ -0,0 +1,21 @@
|
||||
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
endif()
|
||||
|
||||
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
||||
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
exec_program(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
if(NOT "${rm_retval}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||
endif()
|
||||
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||
endif()
|
||||
endforeach()
|
||||
91
cmake/modules/FindBacktrace.cmake
Normal file
91
cmake/modules/FindBacktrace.cmake
Normal file
@@ -0,0 +1,91 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindBacktrace
|
||||
-------------
|
||||
|
||||
Find provider for `backtrace(3) <https://man7.org/linux/man-pages/man3/backtrace.3.html>`__.
|
||||
|
||||
Checks if OS supports ``backtrace(3)`` via either ``libc`` or custom library.
|
||||
This module defines the following variables:
|
||||
|
||||
``Backtrace_HEADER``
|
||||
The header file needed for ``backtrace(3)``. Cached.
|
||||
Could be forcibly set by user.
|
||||
``Backtrace_INCLUDE_DIRS``
|
||||
The include directories needed to use ``backtrace(3)`` header.
|
||||
``Backtrace_LIBRARIES``
|
||||
The libraries (linker flags) needed to use ``backtrace(3)``, if any.
|
||||
``Backtrace_FOUND``
|
||||
Is set if and only if ``backtrace(3)`` support detected.
|
||||
|
||||
The following cache variables are also available to set or use:
|
||||
|
||||
``Backtrace_LIBRARY``
|
||||
The external library providing backtrace, if any.
|
||||
``Backtrace_INCLUDE_DIR``
|
||||
The directory holding the ``backtrace(3)`` header.
|
||||
|
||||
Typical usage is to generate of header file using :command:`configure_file`
|
||||
with the contents like the following::
|
||||
|
||||
#cmakedefine01 Backtrace_FOUND
|
||||
#if Backtrace_FOUND
|
||||
# include <${Backtrace_HEADER}>
|
||||
#endif
|
||||
|
||||
And then reference that generated header file in actual source.
|
||||
#]=======================================================================]
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckSymbolExists)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
|
||||
|
||||
# List of variables to be provided to find_package_handle_standard_args()
|
||||
set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR)
|
||||
|
||||
if(Backtrace_HEADER)
|
||||
set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}")
|
||||
else(Backtrace_HEADER)
|
||||
set(_Backtrace_HEADER_TRY "execinfo.h")
|
||||
endif(Backtrace_HEADER)
|
||||
|
||||
find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}")
|
||||
set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
|
||||
if (NOT DEFINED Backtrace_LIBRARY)
|
||||
# First, check if we already have backtrace(), e.g., in libc
|
||||
cmake_push_check_state(RESET)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY})
|
||||
check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(_Backtrace_SYM_FOUND)
|
||||
# Avoid repeating the message() call below each time CMake is run.
|
||||
if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY)
|
||||
message(STATUS "backtrace facility detected in default set of libraries")
|
||||
endif()
|
||||
set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), empty for default set of libraries")
|
||||
else()
|
||||
# Check for external library, for non-glibc systems
|
||||
if(Backtrace_INCLUDE_DIR)
|
||||
# OpenBSD has libbacktrace renamed to libexecinfo
|
||||
find_library(Backtrace_LIBRARY "execinfo")
|
||||
else() # respect user wishes
|
||||
set(_Backtrace_HEADER_TRY "backtrace.h")
|
||||
find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY})
|
||||
find_library(Backtrace_LIBRARY "backtrace")
|
||||
endif()
|
||||
|
||||
# Prepend list with library path as it's more common practice
|
||||
set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS})
|
||||
endif()
|
||||
|
||||
set(Backtrace_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility")
|
||||
|
||||
find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS})
|
||||
mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY)
|
||||
611
cmake/modules/FindPackageHandleStandardArgs.cmake
Normal file
611
cmake/modules/FindPackageHandleStandardArgs.cmake
Normal file
@@ -0,0 +1,611 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindPackageHandleStandardArgs
|
||||
-----------------------------
|
||||
|
||||
This module provides functions intended to be used in :ref:`Find Modules`
|
||||
implementing :command:`find_package(<PackageName>)` calls.
|
||||
|
||||
.. command:: find_package_handle_standard_args
|
||||
|
||||
This command handles the ``REQUIRED``, ``QUIET`` and version-related
|
||||
arguments of :command:`find_package`. It also sets the
|
||||
``<PackageName>_FOUND`` variable. The package is considered found if all
|
||||
variables listed contain valid results, e.g. valid filepaths.
|
||||
|
||||
There are two signatures:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(<PackageName>
|
||||
(DEFAULT_MSG|<custom-failure-message>)
|
||||
<required-var>...
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(<PackageName>
|
||||
[FOUND_VAR <result-var>]
|
||||
[REQUIRED_VARS <required-var>...]
|
||||
[VERSION_VAR <version-var>]
|
||||
[HANDLE_VERSION_RANGE]
|
||||
[HANDLE_COMPONENTS]
|
||||
[CONFIG_MODE]
|
||||
[NAME_MISMATCHED]
|
||||
[REASON_FAILURE_MESSAGE <reason-failure-message>]
|
||||
[FAIL_MESSAGE <custom-failure-message>]
|
||||
)
|
||||
|
||||
The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
|
||||
the variables ``<required-var>...`` are valid and any optional
|
||||
constraints are satisfied, and ``FALSE`` otherwise. A success or
|
||||
failure message may be displayed based on the results and on
|
||||
whether the ``REQUIRED`` and/or ``QUIET`` option was given to
|
||||
the :command:`find_package` call.
|
||||
|
||||
The options are:
|
||||
|
||||
``(DEFAULT_MSG|<custom-failure-message>)``
|
||||
In the simple signature this specifies the failure message.
|
||||
Use ``DEFAULT_MSG`` to ask for a default message to be computed
|
||||
(recommended). Not valid in the full signature.
|
||||
|
||||
``FOUND_VAR <result-var>``
|
||||
.. deprecated:: 3.3
|
||||
|
||||
Specifies either ``<PackageName>_FOUND`` or
|
||||
``<PACKAGENAME>_FOUND`` as the result variable. This exists only
|
||||
for compatibility with older versions of CMake and is now ignored.
|
||||
Result variables of both names are always set for compatibility.
|
||||
|
||||
``REQUIRED_VARS <required-var>...``
|
||||
Specify the variables which are required for this package.
|
||||
These may be named in the generated failure message asking the
|
||||
user to set the missing variable values. Therefore these should
|
||||
typically be cache entries such as ``FOO_LIBRARY`` and not output
|
||||
variables like ``FOO_LIBRARIES``.
|
||||
|
||||
.. versionchanged:: 3.18
|
||||
If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
|
||||
|
||||
``VERSION_VAR <version-var>``
|
||||
Specify the name of a variable that holds the version of the package
|
||||
that has been found. This version will be checked against the
|
||||
(potentially) specified required version given to the
|
||||
:command:`find_package` call, including its ``EXACT`` option.
|
||||
The default messages include information about the required
|
||||
version and the version which has been actually found, both
|
||||
if the version is ok or not.
|
||||
|
||||
``HANDLE_VERSION_RANGE``
|
||||
.. versionadded:: 3.19
|
||||
|
||||
Enable handling of a version range, if one is specified. Without this
|
||||
option, a developer warning will be displayed if a version range is
|
||||
specified.
|
||||
|
||||
``HANDLE_COMPONENTS``
|
||||
Enable handling of package components. In this case, the command
|
||||
will report which components have been found and which are missing,
|
||||
and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
|
||||
if any of the required components (i.e. not the ones listed after
|
||||
the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
|
||||
missing.
|
||||
|
||||
``CONFIG_MODE``
|
||||
Specify that the calling find module is a wrapper around a
|
||||
call to ``find_package(<PackageName> NO_MODULE)``. This implies
|
||||
a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command
|
||||
will automatically check whether the package configuration file
|
||||
was found.
|
||||
|
||||
``REASON_FAILURE_MESSAGE <reason-failure-message>``
|
||||
.. versionadded:: 3.16
|
||||
|
||||
Specify a custom message of the reason for the failure which will be
|
||||
appended to the default generated message.
|
||||
|
||||
``FAIL_MESSAGE <custom-failure-message>``
|
||||
Specify a custom failure message instead of using the default
|
||||
generated message. Not recommended.
|
||||
|
||||
``NAME_MISMATCHED``
|
||||
.. versionadded:: 3.17
|
||||
|
||||
Indicate that the ``<PackageName>`` does not match
|
||||
``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
|
||||
warning, but it may be intentional for usage of the command for components
|
||||
of a larger package.
|
||||
|
||||
Example for the simple signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(LibXml2 DEFAULT_MSG
|
||||
LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
|
||||
|
||||
The ``LibXml2`` package is considered to be found if both
|
||||
``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
|
||||
Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found
|
||||
and ``REQUIRED`` was used, it fails with a
|
||||
:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
|
||||
used or not. If it is found, success will be reported, including
|
||||
the content of the first ``<required-var>``. On repeated CMake runs,
|
||||
the same message will not be printed again.
|
||||
|
||||
.. note::
|
||||
|
||||
If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
|
||||
calling module, a warning that there is a mismatch is given. The
|
||||
``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
|
||||
the old signature and the ``NAME_MISMATCHED`` argument using the new
|
||||
signature. To avoid forcing the caller to require newer versions of CMake for
|
||||
usage, the variable's value will be used if defined when the
|
||||
``NAME_MISMATCHED`` argument is not passed for the new signature (but using
|
||||
both is an error)..
|
||||
|
||||
Example for the full signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(LibArchive
|
||||
REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
|
||||
VERSION_VAR LibArchive_VERSION)
|
||||
|
||||
In this case, the ``LibArchive`` package is considered to be found if
|
||||
both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
|
||||
Also the version of ``LibArchive`` will be checked by using the version
|
||||
contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given,
|
||||
the default messages will be printed.
|
||||
|
||||
Another example for the full signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
|
||||
find_package_handle_standard_args(Automoc4 CONFIG_MODE)
|
||||
|
||||
In this case, a ``FindAutmoc4.cmake`` module wraps a call to
|
||||
``find_package(Automoc4 NO_MODULE)`` and adds an additional search
|
||||
directory for ``automoc4``. Then the call to
|
||||
``find_package_handle_standard_args`` produces a proper success/failure
|
||||
message.
|
||||
|
||||
.. command:: find_package_check_version
|
||||
|
||||
.. versionadded:: 3.19
|
||||
|
||||
Helper function which can be used to check if a ``<version>`` is valid
|
||||
against version-related arguments of :command:`find_package`.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_check_version(<version> <result-var>
|
||||
[HANDLE_VERSION_RANGE]
|
||||
[RESULT_MESSAGE_VARIABLE <message-var>]
|
||||
)
|
||||
|
||||
The ``<result-var>`` will hold a boolean value giving the result of the check.
|
||||
|
||||
The options are:
|
||||
|
||||
``HANDLE_VERSION_RANGE``
|
||||
Enable handling of a version range, if one is specified. Without this
|
||||
option, a developer warning will be displayed if a version range is
|
||||
specified.
|
||||
|
||||
``RESULT_MESSAGE_VARIABLE <message-var>``
|
||||
Specify a variable to get back a message describing the result of the check.
|
||||
|
||||
Example for the usage:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE
|
||||
RESULT_MESSAGE_VARIABLE reason)
|
||||
if (result)
|
||||
message (STATUS "${reason}")
|
||||
else()
|
||||
message (FATAL_ERROR "${reason}")
|
||||
endif()
|
||||
#]=======================================================================]
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
|
||||
|
||||
|
||||
cmake_policy(PUSH)
|
||||
# numbers and boolean constants
|
||||
cmake_policy (SET CMP0012 NEW)
|
||||
# IN_LIST operator
|
||||
cmake_policy (SET CMP0057 NEW)
|
||||
|
||||
|
||||
# internal helper macro
|
||||
macro(_FPHSA_FAILURE_MESSAGE _msg)
|
||||
set (__msg "${_msg}")
|
||||
if (FPHSA_REASON_FAILURE_MESSAGE)
|
||||
string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n")
|
||||
endif()
|
||||
if (${_NAME}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${__msg}")
|
||||
else ()
|
||||
if (NOT ${_NAME}_FIND_QUIETLY)
|
||||
message(STATUS "${__msg}")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
|
||||
# internal helper macro to generate the failure message when used in CONFIG_MODE:
|
||||
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
|
||||
# <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
|
||||
if(${_NAME}_CONFIG)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
|
||||
else()
|
||||
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
|
||||
# List them all in the error message:
|
||||
if(${_NAME}_CONSIDERED_CONFIGS)
|
||||
set(configsText "")
|
||||
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
|
||||
math(EXPR configsCount "${configsCount} - 1")
|
||||
foreach(currentConfigIndex RANGE ${configsCount})
|
||||
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
|
||||
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
|
||||
string(APPEND configsText "\n ${filename} (version ${version})")
|
||||
endforeach()
|
||||
if (${_NAME}_NOT_FOUND_MESSAGE)
|
||||
if (FPHSA_REASON_FAILURE_MESSAGE)
|
||||
string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ")
|
||||
else()
|
||||
set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}")
|
||||
endif()
|
||||
else()
|
||||
string(APPEND configsText "\n")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}")
|
||||
|
||||
else()
|
||||
# Simple case: No Config-file was found at all:
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_CHECK_VERSION version result)
|
||||
cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "")
|
||||
|
||||
if (FPCV_UNPARSED_ARGUMENTS)
|
||||
message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments")
|
||||
endif()
|
||||
if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES)
|
||||
message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument")
|
||||
endif()
|
||||
|
||||
set (${result} FALSE PARENT_SCOPE)
|
||||
if (FPCV_RESULT_MESSAGE_VARIABLE)
|
||||
unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (_CMAKE_FPHSA_PACKAGE_NAME)
|
||||
set (package "${_CMAKE_FPHSA_PACKAGE_NAME}")
|
||||
elseif (CMAKE_FIND_PACKAGE_NAME)
|
||||
set (package "${CMAKE_FIND_PACKAGE_NAME}")
|
||||
else()
|
||||
message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'")
|
||||
endif()
|
||||
|
||||
if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE
|
||||
AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE)
|
||||
message(AUTHOR_WARNING
|
||||
"`find_package()` specify a version range but the option "
|
||||
"HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. "
|
||||
"Only the lower endpoint of the range will be used.")
|
||||
endif()
|
||||
|
||||
|
||||
set (version_ok FALSE)
|
||||
unset (version_msg)
|
||||
|
||||
if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)
|
||||
if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
|
||||
AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)
|
||||
AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
|
||||
AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX)
|
||||
OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
|
||||
AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))
|
||||
set (version_ok TRUE)
|
||||
set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")")
|
||||
else()
|
||||
set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"")
|
||||
endif()
|
||||
elseif (DEFINED ${package}_FIND_VERSION)
|
||||
if(${package}_FIND_VERSION_EXACT) # exact version required
|
||||
# count the dots in the version string
|
||||
string(REGEX REPLACE "[^.]" "" version_dots "${version}")
|
||||
# add one dot because there is one dot more than there are components
|
||||
string(LENGTH "${version_dots}." version_dots)
|
||||
if (version_dots GREATER ${package}_FIND_VERSION_COUNT)
|
||||
# Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT
|
||||
# is at most 4 here. Therefore a simple lookup table is used.
|
||||
if (${package}_FIND_VERSION_COUNT EQUAL 1)
|
||||
set(version_regex "[^.]*")
|
||||
elseif (${package}_FIND_VERSION_COUNT EQUAL 2)
|
||||
set(version_regex "[^.]*\\.[^.]*")
|
||||
elseif (${package}_FIND_VERSION_COUNT EQUAL 3)
|
||||
set(version_regex "[^.]*\\.[^.]*\\.[^.]*")
|
||||
else()
|
||||
set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
|
||||
endif()
|
||||
string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}")
|
||||
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")")
|
||||
endif ()
|
||||
else ()
|
||||
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable exact version \"${version}\")")
|
||||
endif ()
|
||||
endif ()
|
||||
else() # minimum version
|
||||
if (${package}_FIND_VERSION VERSION_GREATER version)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"")
|
||||
else()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found version \"${version}\")")
|
||||
endif()
|
||||
|
||||
set (${result} ${version_ok} PARENT_SCOPE)
|
||||
if (FPCV_RESULT_MESSAGE_VARIABLE)
|
||||
set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
|
||||
|
||||
# Set up the arguments for `cmake_parse_arguments`.
|
||||
set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE)
|
||||
set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR)
|
||||
set(multiValueArgs REQUIRED_VARS)
|
||||
|
||||
# Check whether we are in 'simple' or 'extended' mode:
|
||||
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
|
||||
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
|
||||
|
||||
unset(FPHSA_NAME_MISMATCHED_override)
|
||||
if (DEFINED FPHSA_NAME_MISMATCHED)
|
||||
# If the variable NAME_MISMATCHED variable is set, error if it is passed as
|
||||
# an argument. The former is for old signatures, the latter is for new
|
||||
# signatures.
|
||||
list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx)
|
||||
if (NOT name_mismatched_idx EQUAL "-1")
|
||||
message(FATAL_ERROR
|
||||
"The `NAME_MISMATCHED` argument may only be specified by the argument or "
|
||||
"the variable, not both.")
|
||||
endif ()
|
||||
|
||||
# But use the variable if it is not an argument to avoid forcing minimum
|
||||
# CMake version bumps for calling modules.
|
||||
set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}")
|
||||
endif ()
|
||||
|
||||
if(${INDEX} EQUAL -1)
|
||||
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
|
||||
set(FPHSA_REQUIRED_VARS ${ARGN})
|
||||
set(FPHSA_VERSION_VAR)
|
||||
else()
|
||||
cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
|
||||
|
||||
if(FPHSA_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_FAIL_MESSAGE)
|
||||
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
|
||||
endif()
|
||||
|
||||
# In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()
|
||||
# when it successfully found the config-file, including version checking:
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
|
||||
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
|
||||
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS)
|
||||
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (DEFINED FPHSA_NAME_MISMATCHED_override)
|
||||
set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}")
|
||||
endif ()
|
||||
|
||||
if (DEFINED CMAKE_FIND_PACKAGE_NAME
|
||||
AND NOT FPHSA_NAME_MISMATCHED
|
||||
AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)
|
||||
message(AUTHOR_WARNING
|
||||
"The package name passed to `find_package_handle_standard_args` "
|
||||
"(${_NAME}) does not match the name of the calling package "
|
||||
"(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling "
|
||||
"code that expects `find_package` result variables (e.g., `_FOUND`) "
|
||||
"to follow a certain pattern.")
|
||||
endif ()
|
||||
|
||||
if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE)
|
||||
message(AUTHOR_WARNING
|
||||
"`find_package()` specify a version range but the module ${_NAME} does "
|
||||
"not support this capability. Only the lower endpoint of the range "
|
||||
"will be used.")
|
||||
endif()
|
||||
|
||||
# to propagate package name to FIND_PACKAGE_CHECK_VERSION
|
||||
set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}")
|
||||
|
||||
# now that we collected all arguments, process them
|
||||
|
||||
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
|
||||
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
|
||||
endif()
|
||||
|
||||
if (FPHSA_REQUIRED_VARS)
|
||||
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
|
||||
endif()
|
||||
|
||||
string(TOUPPER ${_NAME} _NAME_UPPER)
|
||||
string(TOLOWER ${_NAME} _NAME_LOWER)
|
||||
|
||||
if(FPHSA_FOUND_VAR)
|
||||
set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
|
||||
set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
|
||||
if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
|
||||
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
|
||||
else()
|
||||
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
|
||||
endif()
|
||||
else()
|
||||
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
|
||||
endif()
|
||||
|
||||
# collect all variables which were not found, so they can be printed, so the
|
||||
# user knows better what went wrong (#6375)
|
||||
set(MISSING_VARS "")
|
||||
set(DETAILS "")
|
||||
# check if all passed variables are valid
|
||||
set(FPHSA_FOUND_${_NAME} TRUE)
|
||||
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
|
||||
if(NOT ${_CURRENT_VAR})
|
||||
set(FPHSA_FOUND_${_NAME} FALSE)
|
||||
string(APPEND MISSING_VARS " ${_CURRENT_VAR}")
|
||||
else()
|
||||
string(APPEND DETAILS "[${${_CURRENT_VAR}}]")
|
||||
endif()
|
||||
endforeach()
|
||||
if(FPHSA_FOUND_${_NAME})
|
||||
set(${_NAME}_FOUND TRUE)
|
||||
set(${_NAME_UPPER}_FOUND TRUE)
|
||||
else()
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
set(${_NAME_UPPER}_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# component handling
|
||||
unset(FOUND_COMPONENTS_MSG)
|
||||
unset(MISSING_COMPONENTS_MSG)
|
||||
|
||||
if(FPHSA_HANDLE_COMPONENTS)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(${_NAME}_${comp}_FOUND)
|
||||
|
||||
if(NOT DEFINED FOUND_COMPONENTS_MSG)
|
||||
set(FOUND_COMPONENTS_MSG "found components:")
|
||||
endif()
|
||||
string(APPEND FOUND_COMPONENTS_MSG " ${comp}")
|
||||
|
||||
else()
|
||||
|
||||
if(NOT DEFINED MISSING_COMPONENTS_MSG)
|
||||
set(MISSING_COMPONENTS_MSG "missing components:")
|
||||
endif()
|
||||
string(APPEND MISSING_COMPONENTS_MSG " ${comp}")
|
||||
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
string(APPEND MISSING_VARS " ${comp}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
|
||||
string(APPEND DETAILS "[c${COMPONENT_MSG}]")
|
||||
endif()
|
||||
|
||||
# version handling:
|
||||
set(VERSION_MSG "")
|
||||
set(VERSION_OK TRUE)
|
||||
|
||||
# check that the version variable is not empty to avoid emitting a misleading
|
||||
# message (i.e. `Found unsuitable version ""`)
|
||||
if (DEFINED ${_NAME}_FIND_VERSION)
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
if(NOT "${${FPHSA_VERSION_VAR}}" STREQUAL "")
|
||||
set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})
|
||||
if (FPHSA_HANDLE_VERSION_RANGE)
|
||||
set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE)
|
||||
else()
|
||||
set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE)
|
||||
endif()
|
||||
find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG
|
||||
${FPCV_HANDLE_VERSION_RANGE})
|
||||
else()
|
||||
set(VERSION_OK FALSE)
|
||||
endif()
|
||||
endif()
|
||||
if("${${FPHSA_VERSION_VAR}}" STREQUAL "")
|
||||
# if the package was not found, but a version was given, add that to the output:
|
||||
if(${_NAME}_FIND_VERSION_EXACT)
|
||||
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
|
||||
elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE)
|
||||
set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")")
|
||||
else()
|
||||
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
# Check with DEFINED as the found version may be 0.
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if(VERSION_OK)
|
||||
string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]")
|
||||
else()
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
|
||||
# print the result:
|
||||
if (${_NAME}_FOUND)
|
||||
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
|
||||
else ()
|
||||
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
|
||||
else()
|
||||
if(NOT VERSION_OK)
|
||||
set(RESULT_MSG)
|
||||
if (_FIRST_REQUIRED_VAR)
|
||||
string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}")
|
||||
endif()
|
||||
if (COMPONENT_MSG)
|
||||
if (RESULT_MSG)
|
||||
string (APPEND RESULT_MSG ", ")
|
||||
endif()
|
||||
string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})")
|
||||
else()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
|
||||
set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
cmake_policy(POP)
|
||||
48
cmake/modules/FindPackageMessage.cmake
Normal file
48
cmake/modules/FindPackageMessage.cmake
Normal file
@@ -0,0 +1,48 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindPackageMessage
|
||||
------------------
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_message(<name> "message for user" "find result details")
|
||||
|
||||
This function is intended to be used in FindXXX.cmake modules files.
|
||||
It will print a message once for each unique find result. This is
|
||||
useful for telling the user where a package was found. The first
|
||||
argument specifies the name (XXX) of the package. The second argument
|
||||
specifies the message to display. The third argument lists details
|
||||
about the find result so that if they change the message will be
|
||||
displayed again. The macro also obeys the QUIET argument to the
|
||||
find_package command.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
if(X11_FOUND)
|
||||
find_package_message(X11 "Found X11: ${X11_X11_LIB}"
|
||||
"[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
|
||||
else()
|
||||
...
|
||||
endif()
|
||||
#]=======================================================================]
|
||||
|
||||
function(find_package_message pkg msg details)
|
||||
# Avoid printing a message repeatedly for the same find result.
|
||||
if(NOT ${pkg}_FIND_QUIETLY)
|
||||
string(REPLACE "\n" "" details "${details}")
|
||||
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
|
||||
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
|
||||
# The message has not yet been printed.
|
||||
message(STATUS "${msg}")
|
||||
|
||||
# Save the find details in the cache to avoid printing the same
|
||||
# message again.
|
||||
set("${DETAILS_VAR}" "${details}"
|
||||
CACHE INTERNAL "Details about finding ${pkg}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -46,7 +46,7 @@ endfunction()
|
||||
|
||||
include(BundleUtilities)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}" IGNORE_ITEM "Python")
|
||||
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")
|
||||
|
||||
if (CODE_SIGN_CERTIFICATE_ID)
|
||||
# Hack around Apple Silicon signing bugs by copying the real app, signing it and moving it back.
|
||||
|
||||
5
dist/AppImageBuilder.yml
vendored
5
dist/AppImageBuilder.yml
vendored
@@ -107,7 +107,6 @@ AppDir:
|
||||
- /lib/x86_64-linux-gnu/libpcre2-8.so.0
|
||||
- /lib/x86_64-linux-gnu/libpixman-1.so.0
|
||||
- /lib/x86_64-linux-gnu/libpng16.so.16
|
||||
- /lib/x86_64-linux-gnu/libpython3.10.so.1.0
|
||||
- /lib/x86_64-linux-gnu/libsasl2.so.2
|
||||
- /lib/x86_64-linux-gnu/libsensors.so.5
|
||||
- /lib/x86_64-linux-gnu/libstdc++.so.6
|
||||
@@ -136,5 +135,5 @@ AppDir:
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}.AppImage
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*-x86_64.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}-x86_64.AppImage
|
||||
|
||||
6
dist/Arch/PKGBUILD
vendored
6
dist/Arch/PKGBUILD
vendored
@@ -1,4 +1,4 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
# Maintainer: iTrooz_ <hey at itrooz dot fr>
|
||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||
|
||||
pkgname=imhex-bin
|
||||
@@ -8,11 +8,11 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
depends=(glfw mbedtls freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
makedepends=(git)
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux-x86_64.pkg.tar.zst")
|
||||
md5sums=(SKIP)
|
||||
|
||||
package() {
|
||||
|
||||
3
dist/Brewfile
vendored
3
dist/Brewfile
vendored
@@ -2,8 +2,9 @@ brew "mbedtls"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
brew "ccache"
|
||||
brew "python3"
|
||||
brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
brew "glfw"
|
||||
|
||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libpython3.10, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Maintainer: WerWolv <hey@werwolv.net>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
|
||||
5
dist/Dockerfile
vendored
5
dist/Dockerfile
vendored
@@ -1,6 +1,6 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
MAINTAINER WerWolv "hey@werwolv.net"
|
||||
LABEL maintainer="hey@werwolv.net WerWolv"
|
||||
|
||||
# Install dependencies
|
||||
RUN pacman -Syy --needed --noconfirm
|
||||
@@ -13,7 +13,6 @@ RUN pacman -S --needed --noconfirm \
|
||||
glfw-x11 \
|
||||
file \
|
||||
mbedtls \
|
||||
python3 \
|
||||
freetype2 \
|
||||
dbus \
|
||||
xdg-desktop-portal
|
||||
@@ -25,4 +24,4 @@ RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
|
||||
RUN mkdir /root/ImHex/build
|
||||
WORKDIR /root/ImHex/build
|
||||
RUN cmake .. && make -j
|
||||
WORKDIR /root/ImHex
|
||||
WORKDIR /root/ImHex
|
||||
|
||||
7
dist/ImHex-9999.ebuild
vendored
7
dist/ImHex-9999.ebuild
vendored
@@ -9,20 +9,15 @@ HOMEPAGE="https://github.com/WerWolv/ImHex"
|
||||
SRC_URI=""
|
||||
EGIT_REPO_URI="https://github.com/WerWolv/ImHex.git"
|
||||
|
||||
PYTHON_COMPAT=( python3_{6,7,8,9} )
|
||||
|
||||
inherit git-r3 python-single-r1 cmake
|
||||
inherit git-r3 cmake
|
||||
|
||||
LICENSE="GPL-2"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64"
|
||||
IUSE=""
|
||||
|
||||
REQUIRED_USE="${PYTHON_REQUIRED_USE}"
|
||||
|
||||
DEPEND=""
|
||||
RDEPEND="${DEPEND}
|
||||
${PYTHON_DEPS}
|
||||
media-libs/glfw
|
||||
sys-apps/file
|
||||
dev-libs/mbedtls
|
||||
|
||||
@@ -16,7 +16,7 @@ OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -28,5 +28,5 @@ make -j4 package
|
||||
```
|
||||
|
||||
If the build fails while trying to find the macOS libraries, make sure you have
|
||||
XCode installed with `xcode-select --install`. Homebrew will also help get the
|
||||
most recent SDK installed and configured with `brew doctor`.
|
||||
Xcode installed with `xcode-select --install`. Homebrew will also help get the
|
||||
most recent SDK installed and configured with `brew doctor`.
|
||||
1
dist/get_deps_archlinux.sh
vendored
1
dist/get_deps_archlinux.sh
vendored
@@ -7,7 +7,6 @@ pacman -S $@ --needed \
|
||||
glfw \
|
||||
file \
|
||||
mbedtls \
|
||||
python3 \
|
||||
freetype2 \
|
||||
dbus \
|
||||
xdg-desktop-portal \
|
||||
|
||||
1
dist/get_deps_debian.sh
vendored
1
dist/get_deps_debian.sh
vendored
@@ -19,7 +19,6 @@ apt install -y \
|
||||
libglm-dev \
|
||||
libmagic-dev \
|
||||
libmbedtls-dev \
|
||||
python3-dev \
|
||||
libfreetype-dev \
|
||||
libdbus-1-dev \
|
||||
xdg-desktop-portal
|
||||
|
||||
3
dist/get_deps_fedora.sh
vendored
3
dist/get_deps_fedora.sh
vendored
@@ -10,5 +10,4 @@ dnf install -y \
|
||||
mesa-libGL-devel \
|
||||
glfw-devel \
|
||||
lld \
|
||||
mbedtls-devel \
|
||||
python3-devel
|
||||
mbedtls-devel
|
||||
1
dist/get_deps_msys2.sh
vendored
1
dist/get_deps_msys2.sh
vendored
@@ -9,6 +9,5 @@ pacman -S --needed --noconfirm \
|
||||
mingw-w64-x86_64-glfw \
|
||||
mingw-w64-x86_64-file \
|
||||
mingw-w64-x86_64-mbedtls \
|
||||
mingw-w64-x86_64-python \
|
||||
mingw-w64-x86_64-freetype \
|
||||
mingw-w64-x86_64-dlfcn
|
||||
|
||||
104
dist/langtool.py
vendored
Normal file
104
dist/langtool.py
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import json
|
||||
|
||||
DEFAULT_LANG = "en_US"
|
||||
INVALID_TRANSLATION = ""
|
||||
|
||||
|
||||
def handle_missing_key(command, lang_data, key, value):
|
||||
if command == "check":
|
||||
print(f"Error: Translation {lang_data['code']} is missing translation for key '{key}'")
|
||||
exit(2)
|
||||
elif command == "translate" or command == "create":
|
||||
print(f"Key \033[1m'{key}': '{value}'\033[0m is missing in translation '{lang_data['code']}'")
|
||||
new_value = input("Enter translation: ")
|
||||
lang_data["translations"][key] = new_value
|
||||
elif command == "update":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
|
||||
return 1
|
||||
|
||||
command = sys.argv[1]
|
||||
if command not in ["check", "translate", "update", "create"]:
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
print(f"Using langtool in {command} mode")
|
||||
|
||||
lang_folder_path = Path(sys.argv[2])
|
||||
if not lang_folder_path.exists():
|
||||
print(f"Error: {lang_folder_path} does not exist")
|
||||
return 1
|
||||
|
||||
if not lang_folder_path.is_dir():
|
||||
print(f"Error: {lang_folder_path} is not a folder")
|
||||
return 1
|
||||
|
||||
lang = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
|
||||
print(f"Processing language files in {lang_folder_path}...")
|
||||
|
||||
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_file_path.exists():
|
||||
print(f"Error: Default language file {default_lang_file_path} does not exist")
|
||||
return 1
|
||||
|
||||
print(f"Using file '{default_lang_file_path.name}' as template language file")
|
||||
|
||||
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
|
||||
default_lang_data = json.load(default_lang_file)
|
||||
|
||||
if command == "create" and lang != "":
|
||||
lang_file_path = lang_folder_path / Path(lang + ".json")
|
||||
if lang_file_path.exists():
|
||||
print(f"Error: Language file {lang_file_path} already exists")
|
||||
return 1
|
||||
|
||||
print(f"Creating new language file '{lang_file_path.name}'")
|
||||
|
||||
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
|
||||
new_lang_data = {
|
||||
"code": lang,
|
||||
"language": input("Enter language: "),
|
||||
"country": input("Enter country: "),
|
||||
"translations": {}
|
||||
}
|
||||
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
|
||||
|
||||
for additional_lang_file_path in lang_folder_path.glob("*.json"):
|
||||
if not lang == "" and not additional_lang_file_path.stem == lang:
|
||||
continue
|
||||
|
||||
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
|
||||
continue
|
||||
|
||||
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
|
||||
|
||||
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
|
||||
additional_lang_data = json.load(additional_lang_file)
|
||||
|
||||
for key, value in default_lang_data["translations"].items():
|
||||
if key not in additional_lang_data["translations"] or additional_lang_data["translations"][key] == INVALID_TRANSLATION:
|
||||
handle_missing_key(command, additional_lang_data, key, value)
|
||||
|
||||
keys_to_remove = []
|
||||
for key, value in additional_lang_data["translations"].items():
|
||||
if key not in default_lang_data["translations"]:
|
||||
keys_to_remove.append(key)
|
||||
|
||||
for key in keys_to_remove:
|
||||
additional_lang_data["translations"].pop(key)
|
||||
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
|
||||
|
||||
additional_lang_file.seek(0)
|
||||
additional_lang_file.truncate()
|
||||
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
2
dist/msys2/PKGBUILD
vendored
2
dist/msys2/PKGBUILD
vendored
@@ -7,7 +7,6 @@ pkgdesc="${_realname}: a Hex Editor for Reverse Engineers, Programmers and peopl
|
||||
arch=('any')
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
license=('GPLv2')
|
||||
depends=("${MINGW_PACKAGE_PREFIX}-python")
|
||||
makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
|
||||
"${MINGW_PACKAGE_PREFIX}-lld"
|
||||
"${MINGW_PACKAGE_PREFIX}-cmake"
|
||||
@@ -17,7 +16,6 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
|
||||
"${MINGW_PACKAGE_PREFIX}-file"
|
||||
"${MINGW_PACKAGE_PREFIX}-mbedtls"
|
||||
"${MINGW_PACKAGE_PREFIX}-polly"
|
||||
"${MINGW_PACKAGE_PREFIX}-python"
|
||||
"${MINGW_PACKAGE_PREFIX}-freetype")
|
||||
|
||||
source=()
|
||||
|
||||
115
dist/rpm/imhex.spec
vendored
115
dist/rpm/imhex.spec
vendored
@@ -1,13 +1,14 @@
|
||||
# ftbfs without this
|
||||
%global _lto_cflags %{nil}
|
||||
|
||||
Name: imhex
|
||||
Version: %{_version}
|
||||
Version: 1.26.2
|
||||
Release: 0%{?dist}
|
||||
Summary: A hex editor for reverse engineers and programmers
|
||||
|
||||
License: GPL-2.0-only
|
||||
License: GPL-2.0-only AND Zlib AND MIT AND Apache-2.0
|
||||
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib. intervaltree is MIT
|
||||
# see license dir for full breakdown
|
||||
URL: https://imhex.werwolv.net/
|
||||
# We need the archive with deps bundled
|
||||
Source0: https://github.com/WerWolv/%{name}/releases/download/v%{version}/Full.Sources.tar.gz#/%{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
@@ -16,17 +17,36 @@ BuildRequires: file-devel
|
||||
BuildRequires: freetype-devel
|
||||
BuildRequires: fmt-devel
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: mesa-libGL-devel
|
||||
BuildRequires: libappstream-glib
|
||||
BuildRequires: libglvnd-devel
|
||||
BuildRequires: glfw-devel
|
||||
BuildRequires: json-devel
|
||||
BuildRequires: libcurl-devel
|
||||
BuildRequires: llvm-devel
|
||||
BuildRequires: mbedtls-devel
|
||||
BuildRequires: python3-devel
|
||||
%if 0%{?fedora} >= 37
|
||||
BuildRequires: yara-devel
|
||||
BuildRequires: nativefiledialog-extended-devel
|
||||
%if 0%{?rhel}
|
||||
BuildRequires: gcc-toolset-12
|
||||
%endif
|
||||
|
||||
Provides: bundled(gnulib)
|
||||
Provides: bundled(capstone) = 5.0-rc2
|
||||
Provides: bundled(imgui)
|
||||
Provides: bundled(libromfs)
|
||||
Provides: bundled(microtar)
|
||||
Provides: bundled(libpl)
|
||||
# ImHex modified upstream intervaltree so we have to package it
|
||||
# https://github.com/ekg/intervaltree
|
||||
Provides: bundled(intervaltree) = 0.1
|
||||
Provides: bundled(xdgpp)
|
||||
|
||||
# ftbfs on these arches. armv7hl might compile when capstone 5.x
|
||||
# is released upstream and we can build against it
|
||||
# [7:02 PM] WerWolv: We're not supporting 32 bit anyways soooo
|
||||
# [11:38 AM] WerWolv: Officially supported are x86_64 and aarch64
|
||||
ExclusiveArch: x86_64 %{arm64} ppc64le
|
||||
|
||||
|
||||
%description
|
||||
ImHex is a Hex Editor, a tool to display, decode and analyze binary data to
|
||||
@@ -41,26 +61,26 @@ same time ImHex is completely free and open source under the GPLv2 language.
|
||||
|
||||
|
||||
%prep
|
||||
# don't use the setup macro since we're pulling from git
|
||||
cp -r %{_src_path}/* %{_builddir}/
|
||||
|
||||
%autosetup -n ImHex
|
||||
# remove bundled libs we aren't using
|
||||
rm -rf lib/external/{curl,fmt,llvm,nlohmann_json,yara}
|
||||
|
||||
%build
|
||||
%cmake \
|
||||
-DCMAKE_BUILD_TYPE=%{_build_type} \
|
||||
-D USE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-D USE_SYSTEM_FMT=ON \
|
||||
-D USE_SYSTEM_CURL=ON \
|
||||
-D USE_SYSTEM_LLVM=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-D IMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
%if 0%{?fedora} >= 37
|
||||
-D USE_SYSTEM_YARA=ON \
|
||||
# if fedora <= 36 get updated to yara 4.2.x then they should \
|
||||
# be able to build against system libs \
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2112508 \
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
%cmake \
|
||||
-D CMAKE_BUILD_TYPE=Release \
|
||||
-D IMHEX_STRIP_RELEASE=OFF \
|
||||
-D IMHEX_OFFLINE_BUILD=ON \
|
||||
-D USE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-D USE_SYSTEM_FMT=ON \
|
||||
-D USE_SYSTEM_CURL=ON \
|
||||
-D USE_SYSTEM_LLVM=ON \
|
||||
-D USE_SYSTEM_YARA=ON \
|
||||
-D USE_SYSTEM_NFD=ON \
|
||||
# when capstone >= 5.x is released we should be able to build against \
|
||||
# system libs of it \
|
||||
# -D USE_SYSTEM_CAPSTONE=ON
|
||||
@@ -68,23 +88,46 @@ cp -r %{_src_path}/* %{_builddir}/
|
||||
%cmake_build
|
||||
|
||||
|
||||
%check
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
# build binaries required for tests
|
||||
%cmake_build --target unit_tests
|
||||
%ctest --exclude-regex '(Helpers/StoreAPI|Helpers/TipsAPI|Helpers/ContentAPI)'
|
||||
# Helpers/*API exclude tests that require network access
|
||||
|
||||
|
||||
%install
|
||||
%cmake_install
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop
|
||||
|
||||
# this is a symlink for the old appdata name that we don't need
|
||||
rm -f %{buildroot}%{_metainfodir}/net.werwolv.%{name}.appdata.xml
|
||||
|
||||
# AppData
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
# install licenses
|
||||
cp -a lib/external/nativefiledialog/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/nativefiledialog-LICENSE
|
||||
cp -a lib/external/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
|
||||
cp -a lib/external/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
|
||||
cp -a lib/external/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
|
||||
cp -a lib/external/pattern_language/external/intervaltree/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/pattern-language-intervaltree-LICENSE
|
||||
cp -a lib/external/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
||||
|
||||
|
||||
%files
|
||||
%dir %{_datadir}/licenses/imhex
|
||||
%license %{_datadir}/licenses/imhex/LICENSE
|
||||
%license %{_datadir}/licenses/%{name}/
|
||||
%doc README.md
|
||||
%{_bindir}/imhex
|
||||
%dir %{_datadir}/imhex
|
||||
%{_datadir}/imhex/*
|
||||
%{_datadir}/pixmaps/imhex.png
|
||||
%{_datadir}/applications/imhex.desktop
|
||||
%{_prefix}/lib64/libimhex.so.%{_version}
|
||||
%{_prefix}/lib64/imhex/plugins/*
|
||||
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.imhex.appdata.xml
|
||||
%{_datadir}/pixmaps/%{name}.png
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_libdir}/libimhex.so*
|
||||
%{_libdir}/%{name}/
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
|
||||
%changelog
|
||||
|
||||
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: 45ac4d0194...b16d1fa8ee
2
lib/external/fmt
vendored
2
lib/external/fmt
vendored
Submodule lib/external/fmt updated: c4ee726532...a33701196a
14
lib/external/imgui/CMakeLists.txt
vendored
14
lib/external/imgui/CMakeLists.txt
vendored
@@ -8,10 +8,6 @@ find_package(Freetype REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
pkg_search_module(GLFW REQUIRED glfw3)
|
||||
|
||||
if (UNIX)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif ()
|
||||
|
||||
add_library(imgui OBJECT
|
||||
source/imgui.cpp
|
||||
source/imgui_demo.cpp
|
||||
@@ -39,12 +35,8 @@ add_library(imgui OBJECT
|
||||
|
||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
|
||||
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
||||
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
|
||||
|
||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})
|
||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw3 opengl32.lib)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw OpenGL::GL)
|
||||
endif()
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
|
||||
6
lib/external/imgui/include/TextEditor.h
vendored
6
lib/external/imgui/include/TextEditor.h
vendored
@@ -188,8 +188,8 @@ public:
|
||||
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
||||
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
|
||||
|
||||
const Palette& GetPalette() const { return mPaletteBase; }
|
||||
void SetPalette(const Palette& aValue);
|
||||
static const Palette& GetPalette() { return sPaletteBase; }
|
||||
static void SetPalette(const Palette& aValue);
|
||||
|
||||
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
||||
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
|
||||
@@ -372,7 +372,7 @@ private:
|
||||
bool mIgnoreImGuiChild;
|
||||
bool mShowWhitespaces;
|
||||
|
||||
Palette mPaletteBase;
|
||||
static Palette sPaletteBase;
|
||||
Palette mPalette;
|
||||
LanguageDefinition mLanguageDefinition;
|
||||
RegexList mRegexList;
|
||||
|
||||
6767
lib/external/imgui/include/imgui_impl_opengl3_loader.h
vendored
6767
lib/external/imgui/include/imgui_impl_opengl3_loader.h
vendored
File diff suppressed because it is too large
Load Diff
50
lib/external/imgui/source/TextEditor.cpp
vendored
50
lib/external/imgui/source/TextEditor.cpp
vendored
@@ -21,9 +21,10 @@ bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Bi
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette();
|
||||
|
||||
TextEditor::TextEditor()
|
||||
: mLineSpacing(1.0f), mUndoIndex(0), mTabSize(4), mOverwrite(false), mReadOnly(false), mWithinRender(false), mScrollToCursor(false), mScrollToTop(false), mTextChanged(false), mColorizerEnabled(true), mTextStart(20.0f), mLeftMargin(10), mCursorPositionChanged(false), mColorRangeMin(0), mColorRangeMax(0), mSelectionMode(SelectionMode::Normal), mCheckComments(true), mLastClick(-1.0f), mHandleKeyboardInputs(true), mHandleMouseInputs(true), mIgnoreImGuiChild(false), mShowWhitespaces(true), mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) {
|
||||
SetPalette(GetDarkPalette());
|
||||
SetLanguageDefinition(LanguageDefinition::HLSL());
|
||||
mLines.push_back(Line());
|
||||
}
|
||||
@@ -42,7 +43,7 @@ void TextEditor::SetLanguageDefinition(const LanguageDefinition &aLanguageDef) {
|
||||
}
|
||||
|
||||
void TextEditor::SetPalette(const Palette &aValue) {
|
||||
mPaletteBase = aValue;
|
||||
sPaletteBase = aValue;
|
||||
}
|
||||
|
||||
std::string TextEditor::GetText(const Coordinates &aStart, const Coordinates &aEnd) const {
|
||||
@@ -313,7 +314,7 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
||||
while (cindex > 0 && isspace(line[cindex].mChar))
|
||||
--cindex;
|
||||
|
||||
auto cstart = (PaletteIndex)line[cindex].mColorIndex;
|
||||
auto cstart = line[cindex].mChar;
|
||||
while (cindex > 0) {
|
||||
auto c = line[cindex].mChar;
|
||||
if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
|
||||
@@ -322,8 +323,15 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
||||
cindex++;
|
||||
break;
|
||||
}
|
||||
if (cstart != (PaletteIndex)line[size_t(cindex - 1)].mColorIndex)
|
||||
|
||||
if (isalnum(cstart) || cstart == '_') {
|
||||
if (!isalnum(c) && c != '_') {
|
||||
cindex++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
--cindex;
|
||||
}
|
||||
@@ -631,10 +639,24 @@ void TextEditor::HandleKeyboardInputs() {
|
||||
MoveEnd(shift);
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||
Delete();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) {
|
||||
auto wordStart = GetCursorPosition();
|
||||
MoveRight();
|
||||
auto wordEnd = FindWordEnd(GetCursorPosition());
|
||||
SetSelection(wordStart, wordEnd);
|
||||
Backspace();
|
||||
}
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||
Backspace();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace))) {
|
||||
auto wordEnd = GetCursorPosition();
|
||||
MoveLeft();
|
||||
auto wordStart = FindWordStart(GetCursorPosition());
|
||||
SetSelection(wordStart, wordEnd);
|
||||
Backspace();
|
||||
}
|
||||
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
mOverwrite ^= true;
|
||||
mOverwrite = !mOverwrite;
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
Copy();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||
@@ -740,7 +762,7 @@ void TextEditor::Render() {
|
||||
|
||||
/* Update palette with the current alpha from style */
|
||||
for (int i = 0; i < (int)PaletteIndex::Max; ++i) {
|
||||
auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]);
|
||||
auto color = ImGui::ColorConvertU32ToFloat4(sPaletteBase[i]);
|
||||
color.w *= ImGui::GetStyle().Alpha;
|
||||
mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
|
||||
}
|
||||
@@ -1095,7 +1117,8 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
line.insert(line.begin(), Glyph('\t', TextEditor::PaletteIndex::Background));
|
||||
for (int j = start.mColumn % mTabSize; j < mTabSize; j++)
|
||||
line.insert(line.begin(), Glyph(' ', PaletteIndex::Background));
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
@@ -1156,6 +1179,13 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
line.erase(line.begin() + cindex, line.begin() + line.size());
|
||||
SetCursorPosition(Coordinates(coord.mLine + 1, GetCharacterColumn(coord.mLine + 1, (int)whitespaceSize)));
|
||||
u.mAdded = (char)aChar;
|
||||
} else if (aChar == '\t') {
|
||||
auto &line = mLines[coord.mLine];
|
||||
auto cindex = GetCharacterIndex(coord);
|
||||
auto spacesToInsert = mTabSize - (cindex % mTabSize);
|
||||
for (int j = 0; j < spacesToInsert; j++)
|
||||
line.insert(line.begin() + cindex, Glyph(' ', PaletteIndex::Background));
|
||||
SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + spacesToInsert)));
|
||||
} else {
|
||||
char buf[7];
|
||||
int e = ImTextCharToUtf8(buf, 7, aChar);
|
||||
@@ -2032,7 +2062,9 @@ void TextEditor::ColorizeInternal() {
|
||||
}
|
||||
}
|
||||
}
|
||||
line[currentIndex].mPreprocessor = withinPreproc;
|
||||
if (currentIndex < line.size())
|
||||
line[currentIndex].mPreprocessor = withinPreproc;
|
||||
|
||||
currentIndex += UTF8CharLength(c);
|
||||
if (currentIndex >= (int)line.size()) {
|
||||
currentIndex = 0;
|
||||
@@ -2112,7 +2144,7 @@ void TextEditor::EnsureCursorVisible() {
|
||||
if (len + mTextStart < left + 4)
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart - 4));
|
||||
if (len + mTextStart > right - 4)
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width));
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width + mCharAdvance.x * 2));
|
||||
}
|
||||
|
||||
int TextEditor::GetPageSize() const {
|
||||
|
||||
18
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
18
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
@@ -164,7 +164,10 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface();
|
||||
// Functions
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
// IMHEX PATCH BEGIN
|
||||
const char *data = glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
return data == nullptr ? "" : data;
|
||||
// IMHEX PATCH END
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
@@ -179,12 +182,12 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.ClipboardHandlerData.clear();
|
||||
if (!::OpenClipboard(NULL))
|
||||
return NULL;
|
||||
return "";
|
||||
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
|
||||
if (wbuf_handle == NULL)
|
||||
{
|
||||
::CloseClipboard();
|
||||
return NULL;
|
||||
return "";
|
||||
}
|
||||
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
|
||||
{
|
||||
@@ -194,7 +197,7 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
}
|
||||
::GlobalUnlock(wbuf_handle);
|
||||
::CloseClipboard();
|
||||
return g.ClipboardHandlerData.Data;
|
||||
return g.ClipboardHandlerData.Data == nullptr ? "" : g.ClipboardHandlerData.Data;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)
|
||||
@@ -817,7 +820,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
int monitors_count = 0;
|
||||
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
||||
platform_io.Monitors.resize(0);
|
||||
|
||||
// IMHEX PATCH BEGIN
|
||||
if (monitors_count > 0)
|
||||
platform_io.Monitors.resize(0);
|
||||
// IMHEX PATCH END
|
||||
|
||||
for (int n = 0; n < monitors_count; n++)
|
||||
{
|
||||
ImGuiPlatformMonitor monitor;
|
||||
|
||||
6
lib/external/imgui/source/imgui_widgets.cpp
vendored
6
lib/external/imgui/source/imgui_widgets.cpp
vendored
@@ -1565,8 +1565,8 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
||||
width_excess += items[n].Width - width_rounded;
|
||||
items[n].Width = width_rounded;
|
||||
}
|
||||
while (width_excess > 0.0f)
|
||||
for (int n = 0; n < count; n++)
|
||||
while (width_excess >= 1.0f)
|
||||
for (int n = 0; n < count && width_excess >= 1.0f; n++)
|
||||
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
||||
{
|
||||
items[n].Width += 1.0f;
|
||||
@@ -7638,7 +7638,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
|
||||
|
||||
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
|
||||
if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||
if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||
{
|
||||
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
|
||||
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 8c8556dd6b...40cd303e92
1
lib/external/libwolv
vendored
Submodule
1
lib/external/libwolv
vendored
Submodule
Submodule lib/external/libwolv added at 34d36a2f33
12
lib/external/miniaudio/CMakeLists.txt
vendored
Normal file
12
lib/external/miniaudio/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(miniaudio)
|
||||
|
||||
add_library(miniaudio STATIC
|
||||
source/miniaudio.c
|
||||
)
|
||||
|
||||
target_include_directories(miniaudio PUBLIC include)
|
||||
|
||||
if (APPLE)
|
||||
set_source_files_properties(source/miniaudio.c PROPERTIES LANGUAGE OBJC)
|
||||
endif ()
|
||||
47
lib/external/miniaudio/LICENSE
vendored
Normal file
47
lib/external/miniaudio/LICENSE
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
This software is available as a choice of the following licenses. Choose
|
||||
whichever you prefer.
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
|
||||
===============================================================================
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 2 - MIT No Attribution
|
||||
===============================================================================
|
||||
Copyright 2020 David Reid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
7509
lib/external/miniaudio/include/miniaudio.h
vendored
Normal file
7509
lib/external/miniaudio/include/miniaudio.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
80169
lib/external/miniaudio/source/miniaudio.c
vendored
Normal file
80169
lib/external/miniaudio/source/miniaudio.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 6967d28b06...7909f55d91
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: ac2931943d...c5e7c9e624
36
lib/external/yara/CMakeLists.txt
vendored
36
lib/external/yara/CMakeLists.txt
vendored
@@ -34,6 +34,8 @@ set(LIBYARA_INCLUDES
|
||||
${LIBYARA_SOURCE_PATH}/include/yara/types.h
|
||||
${LIBYARA_SOURCE_PATH}/include/yara/utils.h
|
||||
${LIBYARA_SOURCE_PATH}/crypto.h
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.h
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.h
|
||||
)
|
||||
|
||||
set(LIBYARA_SOURCE
|
||||
@@ -66,6 +68,7 @@ set(LIBYARA_SOURCE
|
||||
${LIBYARA_SOURCE_PATH}/scan.c
|
||||
${LIBYARA_SOURCE_PATH}/scanner.c
|
||||
${LIBYARA_SOURCE_PATH}/sizedstr.c
|
||||
${LIBYARA_SOURCE_PATH}/simple_str.c
|
||||
${LIBYARA_SOURCE_PATH}/stack.c
|
||||
${LIBYARA_SOURCE_PATH}/stopwatch.c
|
||||
${LIBYARA_SOURCE_PATH}/strutils.c
|
||||
@@ -78,6 +81,9 @@ set(LIBYARA_SOURCE
|
||||
${LIBYARA_SOURCE_PATH}/hex_grammar.c
|
||||
${LIBYARA_SOURCE_PATH}/re_grammar.c
|
||||
${LIBYARA_SOURCE_PATH}/proc/none.c
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh.c
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.c
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.c
|
||||
)
|
||||
|
||||
set(LIBYARA_MODULES
|
||||
@@ -91,27 +97,29 @@ set(LIBYARA_MODULES
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/string/string.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||
)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
add_compile_definitions("HAVE_MBEDTLS")
|
||||
|
||||
add_compile_definitions("USE_NO_PROC")
|
||||
|
||||
add_compile_definitions("HASH_MODULE")
|
||||
add_compile_definitions("DOTNET_MODULE")
|
||||
add_compile_definitions("MAGIC_MODULE")
|
||||
add_compile_definitions("MACHO_MODULE")
|
||||
add_compile_definitions("DEX_MODULE")
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shift-count-overflow")
|
||||
add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODULES})
|
||||
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
target_compile_definitions(libyara PRIVATE HAVE_MBEDTLS)
|
||||
|
||||
target_compile_definitions(libyara PRIVATE USE_NO_PROC BUCKETS_256 CHECKSUM_3B)
|
||||
|
||||
target_compile_definitions(libyara PRIVATE HASH_MODULE)
|
||||
target_compile_definitions(libyara PRIVATE DOTNET_MODULE)
|
||||
target_compile_definitions(libyara PRIVATE MAGIC_MODULE)
|
||||
target_compile_definitions(libyara PRIVATE MACHO_MODULE)
|
||||
target_compile_definitions(libyara PRIVATE DEX_MODULE)
|
||||
|
||||
target_compile_options(libyara PRIVATE "-Wno-shift-count-overflow")
|
||||
|
||||
target_include_directories(
|
||||
libyara
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/yara> $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
|
||||
@@ -127,6 +135,6 @@ else ()
|
||||
endif ()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
configure_file(${LIBYARA_SOURCE_PATH}/yara.pc.in
|
||||
${LIBYARA_SOURCE_PATH}/yara.pc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc.in
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc @ONLY)
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
2
lib/external/yara/yara
vendored
2
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara updated: d5a7565a8b...96790e56fc
808
lib/libimhex-rs/Cargo.lock
generated
808
lib/libimhex-rs/Cargo.lock
generated
@@ -1,808 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aquamarine"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96e14cb2a51c8b45d26a4219981985c7350fc05eacb7b5b2939bceb2ffefdf3e"
|
||||
dependencies = [
|
||||
"itertools 0.9.0",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e6384cb95b48be8c5b83764ef800858322436f57aa17974915d23dadb6a7d5"
|
||||
dependencies = [
|
||||
"aquamarine",
|
||||
"autocxx-engine",
|
||||
"autocxx-macro",
|
||||
"cxx",
|
||||
"moveit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-bindgen"
|
||||
version = "0.59.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e603c1eb79e21068072ef990e5463f613e0cedddd6712ff11afeae2a90b2510"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-build"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f5b45a4fe71d3ac68d8b4fd11abe54c791046ec4def7effe27961269b6ab3"
|
||||
dependencies = [
|
||||
"autocxx-engine",
|
||||
"env_logger",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-engine"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02323905bec49fde96ff028fcff1c478d0eba14fa34ea5eb5e4d17439748e42a"
|
||||
dependencies = [
|
||||
"aquamarine",
|
||||
"autocxx-bindgen",
|
||||
"autocxx-parser",
|
||||
"cc",
|
||||
"cxx",
|
||||
"cxx-gen",
|
||||
"indoc",
|
||||
"itertools 0.10.3",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
"strum_macros",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"unzip-n",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-macro"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8106ca477cbe6edf188311f2e05606b81bf463c41748ce7120c31d1b11875515"
|
||||
dependencies = [
|
||||
"autocxx-parser",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-parser"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0ad08260adcecc119b08f460b0633b6e306ea2f6fda4f27e4dd28e20b9a2f4"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chlorine"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "638fb099591b763a988ca69e5f0ee4b82bedb8bc762b3c6cfbfdd3a6dc6b54b4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-gen"
|
||||
version = "0.7.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836e95ae34fc21fb39c206444879afda2c6e704424c9c621662764f1b459e83a"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d4bde25840be4cf0eb1d7e3a74634105189d5609b855bcc8d601ffb037f5f4"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3869bf8972075de8f0446b433d40026f2dfdbd8a9edbc24e9d645ca2ebf2f93a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"imgui-sys",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui-sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chlorine",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imhex-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
|
||||
dependencies = [
|
||||
"unindent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libimhex-rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"autocxx",
|
||||
"autocxx-build",
|
||||
"cxx",
|
||||
"imgui",
|
||||
"imhex-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1becd27d473556dc610b8afa1636ef90747b574a84553bc11e82371d5ef2d1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "moveit"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd833d6adefa6bcfc56948d061c1d697dfa3ab63711963c7ef4aa23eda945676"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
|
||||
|
||||
[[package]]
|
||||
name = "unzip-n"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -1,18 +0,0 @@
|
||||
[package]
|
||||
name = "libimhex-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
imhex-macros = { path = "proc_macros" }
|
||||
imgui = { path = "imgui-rs" }
|
||||
|
||||
cxx = "1.0.55"
|
||||
autocxx = "0.16"
|
||||
|
||||
[build-dependencies]
|
||||
autocxx-build = "0.16"
|
||||
#cxx-build = "1.0.55"
|
||||
@@ -1,26 +0,0 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-lib=dylib=imhex");
|
||||
println!(
|
||||
"cargo:rustc-link-search=all={}",
|
||||
env!("LIBIMHEX_OUTPUT_DIRECTORY")
|
||||
);
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
println!("cargo:rerun-if-changed=src/imhex_api.rs");
|
||||
|
||||
let include = format!("-I{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY"));
|
||||
|
||||
let path = std::path::PathBuf::from("src");
|
||||
let mut build = autocxx_build::Builder::new("src/lib.rs", &[&path])
|
||||
.extra_clang_args(&[&include, "-x", "c++", "-std=gnu++20"])
|
||||
.auto_allowlist(true)
|
||||
.expect_build();
|
||||
|
||||
build
|
||||
.include(format!("{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY")))
|
||||
.flag_if_supported("-std=gnu++20")
|
||||
.flag_if_supported("-std=gnu++2a")
|
||||
.flag_if_supported("-fconcepts")
|
||||
.compiler(env!("CXX_COMPILER"))
|
||||
.compile("libimhex-bridge");
|
||||
}
|
||||
159
lib/libimhex-rs/imgui-rs/Cargo.lock
generated
159
lib/libimhex-rs/imgui-rs/Cargo.lock
generated
@@ -1,159 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chlorine"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"imgui-sys",
|
||||
"memoffset",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgui-sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chlorine",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -1,31 +0,0 @@
|
||||
[package]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
edition = "2018"
|
||||
authors = ["The imgui-rs Developers"]
|
||||
description = "High-level Rust bindings to dear imgui"
|
||||
homepage = "https://github.com/imgui-rs/imgui-rs"
|
||||
repository = "https://github.com/imgui-rs/imgui-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
categories = ["gui", "api-bindings"]
|
||||
readme = "../README.markdown"
|
||||
|
||||
exclude = ["/resources"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1"
|
||||
imgui-sys = { path = "../imgui-sys" }
|
||||
parking_lot = "0.11"
|
||||
|
||||
[features]
|
||||
default = ["min-const-generics"]
|
||||
|
||||
wasm = ["imgui-sys/wasm"]
|
||||
freetype = ["imgui-sys/freetype"]
|
||||
min-const-generics = []
|
||||
# this api is in beta in the upstream imgui crate. See issue #524 for more info.
|
||||
# it should be stable and fine to use though.
|
||||
tables-api = []
|
||||
|
||||
[dev-dependencies]
|
||||
memoffset = "0.6"
|
||||
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2015-2020 The imgui-rs Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1 +0,0 @@
|
||||
../README.markdown
|
||||
@@ -1,142 +0,0 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::panic::catch_unwind;
|
||||
use std::process;
|
||||
use std::ptr;
|
||||
|
||||
// use crate::string::{ImStr, ImString};
|
||||
use crate::Ui;
|
||||
|
||||
/// Trait for clipboard backends
|
||||
pub trait ClipboardBackend: 'static {
|
||||
/// Returns the current clipboard contents as an owned imgui-rs string, or None if the
|
||||
/// clipboard is empty or inaccessible
|
||||
fn get(&mut self) -> Option<String>;
|
||||
/// Sets the clipboard contents to the given imgui-rs string slice.
|
||||
fn set(&mut self, value: &str);
|
||||
}
|
||||
|
||||
pub(crate) struct ClipboardContext {
|
||||
backend: Box<dyn ClipboardBackend>,
|
||||
// this is needed to keep ownership of the value when the raw C callback is called
|
||||
last_value: CString,
|
||||
}
|
||||
|
||||
impl ClipboardContext {
|
||||
/// Creates a new [ClipboardContext]. This function previously took a `Box`, but now
|
||||
/// is generic over the T it takes and boxes itself (which should be less strange).
|
||||
pub fn new<T: ClipboardBackend>(backend: T) -> ClipboardContext {
|
||||
ClipboardContext {
|
||||
backend: Box::new(backend) as Box<dyn ClipboardBackend>,
|
||||
last_value: CString::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dummy() -> ClipboardContext {
|
||||
Self {
|
||||
backend: Box::new(DummyClipboardContext),
|
||||
last_value: CString::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyClipboardContext;
|
||||
impl ClipboardBackend for DummyClipboardContext {
|
||||
fn get(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set(&mut self, _: &str) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ClipboardContext {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ClipboardContext")
|
||||
// beautiful code, no?
|
||||
.field("backend", &(&(*self.backend) as *const _))
|
||||
.field("last_value", &self.last_value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn get_clipboard_text(user_data: *mut c_void) -> *const c_char {
|
||||
let result = catch_unwind(|| {
|
||||
let ctx = &mut *(user_data as *mut ClipboardContext);
|
||||
match ctx.backend.get() {
|
||||
Some(text) => {
|
||||
ctx.last_value = CString::new(text).unwrap();
|
||||
ctx.last_value.as_ptr()
|
||||
}
|
||||
None => ptr::null(),
|
||||
}
|
||||
});
|
||||
result.unwrap_or_else(|_| {
|
||||
eprintln!("Clipboard getter panicked");
|
||||
process::abort();
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn set_clipboard_text(user_data: *mut c_void, text: *const c_char) {
|
||||
let result = catch_unwind(|| {
|
||||
let ctx = &mut *(user_data as *mut ClipboardContext);
|
||||
let text = CStr::from_ptr(text).to_owned();
|
||||
ctx.backend.set(text.to_str().unwrap());
|
||||
});
|
||||
result.unwrap_or_else(|_| {
|
||||
eprintln!("Clipboard setter panicked");
|
||||
process::abort();
|
||||
});
|
||||
}
|
||||
|
||||
/// # Clipboard
|
||||
#[allow(clippy::fn_address_comparisons)] // This is allowed because although function addresses wont be unique, we just care if its OURS
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the current clipboard contents as text, or None if the clipboard is empty or cannot
|
||||
/// be accessed
|
||||
pub fn clipboard_text(&self) -> Option<String> {
|
||||
let io = self.io();
|
||||
io.get_clipboard_text_fn.and_then(|get_clipboard_text_fn| {
|
||||
// Bypass FFI if we end up calling our own function anyway
|
||||
if get_clipboard_text_fn == get_clipboard_text {
|
||||
let ctx = unsafe { &mut *(io.clipboard_user_data as *mut ClipboardContext) };
|
||||
ctx.backend.get()
|
||||
} else {
|
||||
unsafe {
|
||||
let text_ptr = get_clipboard_text_fn(io.clipboard_user_data);
|
||||
if text_ptr.is_null() || *text_ptr == b'\0' as c_char {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
CStr::from_ptr(text_ptr)
|
||||
.to_owned()
|
||||
.to_str()
|
||||
.ok()?
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the clipboard contents.
|
||||
///
|
||||
/// Does nothing if the clipboard cannot be accessed.
|
||||
pub fn set_clipboard_text(&self, text: impl AsRef<str>) {
|
||||
let io = self.io();
|
||||
if let Some(set_clipboard_text_fn) = io.set_clipboard_text_fn {
|
||||
// Bypass FFI if we end up calling our own function anyway
|
||||
if set_clipboard_text_fn == set_clipboard_text {
|
||||
let ctx = unsafe { &mut *(io.clipboard_user_data as *mut ClipboardContext) };
|
||||
ctx.backend.set(text.as_ref());
|
||||
} else {
|
||||
unsafe {
|
||||
set_clipboard_text_fn(io.clipboard_user_data, self.scratch_txt(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
/// Wraps u32 that represents a packed RGBA color. Mostly used by types in the
|
||||
/// low level custom drawing API, such as [`DrawListMut`](crate::DrawListMut).
|
||||
///
|
||||
/// The bits of a color are in "`0xAABBGGRR`" format (e.g. RGBA as little endian
|
||||
/// bytes). For clarity: we don't support an equivalent to the
|
||||
/// `IMGUI_USE_BGRA_PACKED_COLOR` define.
|
||||
///
|
||||
/// This used to be named `ImColor32`, but was renamed to avoid confusion with
|
||||
/// the type with that name in the C++ API (which uses 32 bits per channel).
|
||||
///
|
||||
/// While it doesn't provide methods to access the fields, they can be accessed
|
||||
/// via the `Deref`/`DerefMut` impls it provides targeting
|
||||
/// [`imgui::color::ImColor32Fields`](crate::color::ImColor32Fields), which has
|
||||
/// no other meaningful uses.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let mut c = imgui::ImColor32::from_rgba(0x80, 0xc0, 0x40, 0xff);
|
||||
/// assert_eq!(c.to_bits(), 0xff_40_c0_80); // Note: 0xAA_BB_GG_RR
|
||||
/// // Field access
|
||||
/// assert_eq!(c.r, 0x80);
|
||||
/// assert_eq!(c.g, 0xc0);
|
||||
/// assert_eq!(c.b, 0x40);
|
||||
/// assert_eq!(c.a, 0xff);
|
||||
/// c.b = 0xbb;
|
||||
/// assert_eq!(c.to_bits(), 0xff_bb_c0_80);
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct ImColor32(u32); // TBH maybe the wrapped field should be `pub`.
|
||||
|
||||
impl ImColor32 {
|
||||
/// Convenience constant for solid black.
|
||||
pub const BLACK: Self = Self(0xff_00_00_00);
|
||||
|
||||
/// Convenience constant for solid white.
|
||||
pub const WHITE: Self = Self(0xff_ff_ff_ff);
|
||||
|
||||
/// Convenience constant for full transparency.
|
||||
pub const TRANSPARENT: Self = Self(0);
|
||||
|
||||
/// Construct a color from 4 single-byte `u8` channel values, which should
|
||||
/// be between 0 and 255.
|
||||
#[inline]
|
||||
pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self(
|
||||
((a as u32) << Self::A_SHIFT)
|
||||
| ((r as u32) << Self::R_SHIFT)
|
||||
| ((g as u32) << Self::G_SHIFT)
|
||||
| ((b as u32) << Self::B_SHIFT),
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a fully opaque color from 3 single-byte `u8` channel values.
|
||||
/// Same as [`Self::from_rgba`] with a == 255
|
||||
#[inline]
|
||||
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self::from_rgba(r, g, b, 0xff)
|
||||
}
|
||||
|
||||
/// Construct a fully opaque color from 4 `f32` channel values in the range
|
||||
/// `0.0 ..= 1.0` (values outside this range are clamped to it, with NaN
|
||||
/// mapped to 0.0).
|
||||
///
|
||||
/// Note: No alpha premultiplication is done, so your input should be have
|
||||
/// premultiplied alpha if needed.
|
||||
#[inline]
|
||||
// not const fn because no float math in const eval yet 😩
|
||||
pub fn from_rgba_f32s(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||
Self::from_rgba(
|
||||
f32_to_u8_sat(r),
|
||||
f32_to_u8_sat(g),
|
||||
f32_to_u8_sat(b),
|
||||
f32_to_u8_sat(a),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the channels as an array of f32 in `[r, g, b, a]` order.
|
||||
#[inline]
|
||||
pub fn to_rgba_f32s(self) -> [f32; 4] {
|
||||
let &ImColor32Fields { r, g, b, a } = &*self;
|
||||
[
|
||||
u8_to_f32_sat(r),
|
||||
u8_to_f32_sat(g),
|
||||
u8_to_f32_sat(b),
|
||||
u8_to_f32_sat(a),
|
||||
]
|
||||
}
|
||||
|
||||
/// Return the channels as an array of u8 in `[r, g, b, a]` order.
|
||||
#[inline]
|
||||
pub fn to_rgba(self) -> [u8; 4] {
|
||||
let &ImColor32Fields { r, g, b, a } = &*self;
|
||||
[r, g, b, a]
|
||||
}
|
||||
|
||||
/// Equivalent to [`Self::from_rgba_f32s`], but with an alpha of 1.0 (e.g.
|
||||
/// opaque).
|
||||
#[inline]
|
||||
pub fn from_rgb_f32s(r: f32, g: f32, b: f32) -> Self {
|
||||
Self::from_rgba(f32_to_u8_sat(r), f32_to_u8_sat(g), f32_to_u8_sat(b), 0xff)
|
||||
}
|
||||
|
||||
/// Construct a color from the `u32` that makes up the bits in `0xAABBGGRR`
|
||||
/// format.
|
||||
///
|
||||
/// Specifically, this takes the RGBA values as a little-endian u32 with 8
|
||||
/// bits per channel.
|
||||
///
|
||||
/// Note that [`ImColor32::from_rgba`] may be a bit easier to use.
|
||||
#[inline]
|
||||
pub const fn from_bits(u: u32) -> Self {
|
||||
Self(u)
|
||||
}
|
||||
|
||||
/// Return the bits of the color as a u32. These are in "`0xAABBGGRR`" format, that
|
||||
/// is, little-endian RGBA with 8 bits per channel.
|
||||
#[inline]
|
||||
pub const fn to_bits(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
// These are public in C++ ImGui, should they be public here?
|
||||
/// The number of bits to shift the byte of the red channel. Always 0.
|
||||
const R_SHIFT: u32 = 0;
|
||||
/// The number of bits to shift the byte of the green channel. Always 8.
|
||||
const G_SHIFT: u32 = 8;
|
||||
/// The number of bits to shift the byte of the blue channel. Always 16.
|
||||
const B_SHIFT: u32 = 16;
|
||||
/// The number of bits to shift the byte of the alpha channel. Always 24.
|
||||
const A_SHIFT: u32 = 24;
|
||||
}
|
||||
|
||||
impl Default for ImColor32 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ImColor32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImColor32")
|
||||
.field("r", &self.r)
|
||||
.field("g", &self.g)
|
||||
.field("b", &self.b)
|
||||
.field("a", &self.a)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that exists to allow field access to [`ImColor32`]. It essentially
|
||||
/// exists to be a `Deref`/`DerefMut` target and provide field access.
|
||||
///
|
||||
/// Note that while this is repr(C), be aware that on big-endian machines
|
||||
/// (`cfg(target_endian = "big")`) the order of the fields is reversed, as this
|
||||
/// is a view into a packed u32.
|
||||
///
|
||||
/// Generally should not be used, except as the target of the `Deref` impl of
|
||||
/// [`ImColor32`].
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, align(4))]
|
||||
// Should this be #[non_exhaustive] to discourage direct use?
|
||||
#[rustfmt::skip]
|
||||
pub struct ImColor32Fields {
|
||||
#[cfg(target_endian = "little")] pub r: u8,
|
||||
#[cfg(target_endian = "little")] pub g: u8,
|
||||
#[cfg(target_endian = "little")] pub b: u8,
|
||||
#[cfg(target_endian = "little")] pub a: u8,
|
||||
// TODO(someday): i guess we should have BE tests, but for now I verified
|
||||
// this locally.
|
||||
#[cfg(target_endian = "big")] pub a: u8,
|
||||
#[cfg(target_endian = "big")] pub b: u8,
|
||||
#[cfg(target_endian = "big")] pub g: u8,
|
||||
#[cfg(target_endian = "big")] pub r: u8,
|
||||
}
|
||||
|
||||
// We assume that big and little are the only endiannesses, and that exactly one
|
||||
// is set. That is, PDP endian is not in use, and the we aren't using a
|
||||
// completely broken custom target json or something.
|
||||
#[cfg(any(
|
||||
all(target_endian = "little", target_endian = "big"),
|
||||
all(not(target_endian = "little"), not(target_endian = "big")),
|
||||
))]
|
||||
compile_error!("`cfg(target_endian = \"little\")` must be `cfg(not(target_endian = \"big\")`");
|
||||
|
||||
// static assert sizes match
|
||||
const _: [(); core::mem::size_of::<ImColor32>()] = [(); core::mem::size_of::<ImColor32Fields>()];
|
||||
const _: [(); core::mem::align_of::<ImColor32>()] = [(); core::mem::align_of::<ImColor32Fields>()];
|
||||
|
||||
impl core::ops::Deref for ImColor32 {
|
||||
type Target = ImColor32Fields;
|
||||
#[inline]
|
||||
fn deref(&self) -> &ImColor32Fields {
|
||||
// Safety: we statically assert the size and align match, and neither
|
||||
// type has any special invariants.
|
||||
unsafe { &*(self as *const Self as *const ImColor32Fields) }
|
||||
}
|
||||
}
|
||||
impl core::ops::DerefMut for ImColor32 {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut ImColor32Fields {
|
||||
// Safety: we statically assert the size and align match, and neither
|
||||
// type has any special invariants.
|
||||
unsafe { &mut *(self as *mut Self as *mut ImColor32Fields) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImColor32> for u32 {
|
||||
#[inline]
|
||||
fn from(color: ImColor32) -> Self {
|
||||
color.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(color: u32) -> Self {
|
||||
ImColor32(color)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 4]> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: [f32; 4]) -> Self {
|
||||
Self::from_rgba_f32s(v[0], v[1], v[2], v[3])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32, f32)> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: (f32, f32, f32, f32)) -> Self {
|
||||
Self::from_rgba_f32s(v.0, v.1, v.2, v.3)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 3]> for ImColor32 {
|
||||
#[inline]
|
||||
fn from(v: [f32; 3]) -> Self {
|
||||
Self::from_rgb_f32s(v[0], v[1], v[2])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32)> for ImColor32 {
|
||||
fn from(v: (f32, f32, f32)) -> Self {
|
||||
Self::from_rgb_f32s(v.0, v.1, v.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImColor32> for [f32; 4] {
|
||||
#[inline]
|
||||
fn from(v: ImColor32) -> Self {
|
||||
v.to_rgba_f32s()
|
||||
}
|
||||
}
|
||||
impl From<ImColor32> for (f32, f32, f32, f32) {
|
||||
#[inline]
|
||||
fn from(color: ImColor32) -> Self {
|
||||
let [r, g, b, a]: [f32; 4] = color.into();
|
||||
(r, g, b, a)
|
||||
}
|
||||
}
|
||||
|
||||
// These utilities might be worth making `pub` as free functions in
|
||||
// `crate::color` so user code can ensure their numeric handling is
|
||||
// consistent...
|
||||
|
||||
/// Clamp `v` to between 0.0 and 1.0, always returning a value between those.
|
||||
///
|
||||
/// Never returns NaN, or -0.0 — instead returns +0.0 for these (We differ from
|
||||
/// C++ Dear ImGUI here which probably is just ignoring values like these).
|
||||
#[inline]
|
||||
pub(crate) fn saturate(v: f32) -> f32 {
|
||||
// Note: written strangely so that special values (NaN/-0.0) are handled
|
||||
// automatically with no extra checks.
|
||||
if v > 0.0 {
|
||||
if v <= 1.0 {
|
||||
v
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Quantize a value in `0.0..=1.0` to `0..=u8::MAX`. Input outside 0.0..=1.0 is
|
||||
/// clamped. Uses a bias of 0.5, because we assume centered quantization is used
|
||||
/// (and because C++ imgui does it too). See:
|
||||
/// - https://github.com/ocornut/imgui/blob/e28b51786eae60f32c18214658c15952639085a2/imgui_internal.h#L218
|
||||
/// - https://cbloomrants.blogspot.com/2020/09/topics-in-quantization-for-games.html
|
||||
/// (see `quantize_centered`)
|
||||
#[inline]
|
||||
pub(crate) fn f32_to_u8_sat(f: f32) -> u8 {
|
||||
let f = saturate(f) * 255.0 + 0.5;
|
||||
// Safety: `saturate`'s result is between 0.0 and 1.0 (never NaN even for
|
||||
// NaN input), and so for all inputs, `saturate(f) * 255.0 + 0.5` is inside
|
||||
// `0.5 ..= 255.5`.
|
||||
//
|
||||
// This is verified for all f32 in `test_f32_to_u8_sat_exhaustive`.
|
||||
//
|
||||
// Also note that LLVM doesn't bother trying to figure this out so the
|
||||
// unchecked does actually help. (That said, this likely doesn't matter
|
||||
// for imgui-rs, but I had this code in another project and it felt
|
||||
// silly to needlessly pessimize it).
|
||||
unsafe { f.to_int_unchecked() }
|
||||
}
|
||||
|
||||
/// Opposite of `f32_to_u8_sat`. Since we assume centered quantization, this is
|
||||
/// equivalent to dividing by 255 (or, multiplying by 1.0/255.0)
|
||||
#[inline]
|
||||
pub(crate) fn u8_to_f32_sat(u: u8) -> f32 {
|
||||
(u as f32) * (1.0 / 255.0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_sat() {
|
||||
assert_eq!(saturate(1.0), 1.0);
|
||||
assert_eq!(saturate(0.5), 0.5);
|
||||
assert_eq!(saturate(0.0), 0.0);
|
||||
assert_eq!(saturate(-1.0), 0.0);
|
||||
// next float from 1.0
|
||||
assert_eq!(saturate(1.0 + f32::EPSILON), 1.0);
|
||||
// prev float from 0.0 (Well, from -0.0)
|
||||
assert_eq!(saturate(-f32::MIN_POSITIVE), 0.0);
|
||||
// some NaNs.
|
||||
assert_eq!(saturate(f32::NAN), 0.0);
|
||||
assert_eq!(saturate(-f32::NAN), 0.0);
|
||||
// neg zero comes through as +0
|
||||
assert_eq!(saturate(-0.0).to_bits(), 0.0f32.to_bits());
|
||||
}
|
||||
|
||||
// Check that the unsafe in `f32_to_u8_sat` is fine for all f32 (and that the
|
||||
// comments I wrote about `saturate` are actually true). This is way too slow in
|
||||
// debug mode, but finishes in ~15s on my machine for release (just this test).
|
||||
// This is tested in CI, but will only run if invoked manually with something
|
||||
// like: `cargo test -p imgui --release -- --ignored`.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_f32_to_u8_sat_exhaustive() {
|
||||
for f in (0..=u32::MAX).map(f32::from_bits) {
|
||||
let v = saturate(f);
|
||||
assert!(
|
||||
(0.0..=1.0).contains(&v) && (v.to_bits() != (-0.0f32).to_bits()),
|
||||
"sat({} [e.g. {:#x}]) => {} [e.g {:#x}]",
|
||||
f,
|
||||
f.to_bits(),
|
||||
v,
|
||||
v.to_bits(),
|
||||
);
|
||||
let sat = v * 255.0 + 0.5;
|
||||
// Note: This checks what's required by is the safety predicate for
|
||||
// `f32::to_int_unchecked`:
|
||||
// https://doc.rust-lang.org/std/primitive.f32.html#method.to_int_unchecked
|
||||
assert!(
|
||||
sat.trunc() >= 0.0 && sat.trunc() <= (u8::MAX as f32) && sat.is_finite(),
|
||||
"f32_to_u8_sat({} [e.g. {:#x}]) would be UB!",
|
||||
f,
|
||||
f.to_bits(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_saturate_all_u8s() {
|
||||
for u in 0..=u8::MAX {
|
||||
let v = f32_to_u8_sat(u8_to_f32_sat(u));
|
||||
assert_eq!(u, v);
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// # Columns
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "Columns")]
|
||||
pub fn columns(&self, count: i32, id: impl AsRef<str>, border: bool) {
|
||||
unsafe { sys::igColumns(count, self.scratch_txt(id), border) }
|
||||
}
|
||||
/// Switches to the next column.
|
||||
///
|
||||
/// If the current row is finished, switches to first column of the next row
|
||||
#[doc(alias = "NextColumn")]
|
||||
pub fn next_column(&self) {
|
||||
unsafe { sys::igNextColumn() }
|
||||
}
|
||||
/// Returns the index of the current column
|
||||
#[doc(alias = "GetColumnIndex")]
|
||||
pub fn current_column_index(&self) -> i32 {
|
||||
unsafe { sys::igGetColumnIndex() }
|
||||
}
|
||||
/// Returns the width of the current column (in pixels)
|
||||
#[doc(alias = "GetColumnWidth")]
|
||||
pub fn current_column_width(&self) -> f32 {
|
||||
unsafe { sys::igGetColumnWidth(-1) }
|
||||
}
|
||||
#[doc(alias = "GetColumnWidth")]
|
||||
/// Returns the width of the given column (in pixels)
|
||||
pub fn column_width(&self, column_index: i32) -> f32 {
|
||||
unsafe { sys::igGetColumnWidth(column_index) }
|
||||
}
|
||||
#[doc(alias = "SetColumnWidth")]
|
||||
/// Sets the width of the current column (in pixels)
|
||||
pub fn set_current_column_width(&self, width: f32) {
|
||||
unsafe { sys::igSetColumnWidth(-1, width) };
|
||||
}
|
||||
#[doc(alias = "SetColumnWidth")]
|
||||
/// Sets the width of the given column (in pixels)
|
||||
pub fn set_column_width(&self, column_index: i32, width: f32) {
|
||||
unsafe { sys::igSetColumnWidth(column_index, width) };
|
||||
}
|
||||
/// Returns the offset of the current column (in pixels from the left side of the content
|
||||
/// region)
|
||||
#[doc(alias = "GetColumnOffset")]
|
||||
pub fn current_column_offset(&self) -> f32 {
|
||||
unsafe { sys::igGetColumnOffset(-1) }
|
||||
}
|
||||
/// Returns the offset of the given column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "GetColumnOffset")]
|
||||
pub fn column_offset(&self, column_index: i32) -> f32 {
|
||||
unsafe { sys::igGetColumnOffset(column_index) }
|
||||
}
|
||||
/// Sets the offset of the current column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "SetColumnOffset")]
|
||||
pub fn set_current_column_offset(&self, offset_x: f32) {
|
||||
unsafe { sys::igSetColumnOffset(-1, offset_x) };
|
||||
}
|
||||
/// Sets the offset of the given column (in pixels from the left side of the content region)
|
||||
#[doc(alias = "SetColumnOffset")]
|
||||
pub fn set_column_offset(&self, column_index: i32, offset_x: f32) {
|
||||
unsafe { sys::igSetColumnOffset(column_index, offset_x) };
|
||||
}
|
||||
/// Returns the current amount of columns
|
||||
#[doc(alias = "GetColumnCount")]
|
||||
pub fn column_count(&self) -> i32 {
|
||||
unsafe { sys::igGetColumnsCount() }
|
||||
}
|
||||
}
|
||||
@@ -1,582 +0,0 @@
|
||||
use parking_lot::ReentrantMutex;
|
||||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::Drop;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::clipboard::{ClipboardBackend, ClipboardContext};
|
||||
use crate::fonts::atlas::{FontAtlas, FontAtlasRefMut, FontId, SharedFontAtlas};
|
||||
use crate::io::Io;
|
||||
use crate::style::Style;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// An imgui-rs context.
|
||||
///
|
||||
/// A context needs to be created to access most library functions. Due to current Dear ImGui
|
||||
/// design choices, at most one active Context can exist at any time. This limitation will likely
|
||||
/// be removed in a future Dear ImGui version.
|
||||
///
|
||||
/// If you need more than one context, you can use suspended contexts. As long as only one context
|
||||
/// is active at a time, it's possible to have multiple independent contexts.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Creating a new active context:
|
||||
/// ```
|
||||
/// let ctx = imgui::Context::create();
|
||||
/// // ctx is dropped naturally when it goes out of scope, which deactivates and destroys the
|
||||
/// // context
|
||||
/// ```
|
||||
///
|
||||
/// Never try to create an active context when another one is active:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// let ctx1 = imgui::Context::create();
|
||||
///
|
||||
/// let ctx2 = imgui::Context::create(); // PANIC
|
||||
/// ```
|
||||
///
|
||||
/// Suspending an active context allows you to create another active context:
|
||||
///
|
||||
/// ```
|
||||
/// let ctx1 = imgui::Context::create();
|
||||
/// let suspended1 = ctx1.suspend();
|
||||
/// let ctx2 = imgui::Context::create(); // this is now OK
|
||||
/// ```
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
raw: *mut sys::ImGuiContext,
|
||||
shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>,
|
||||
ini_filename: Option<CString>,
|
||||
log_filename: Option<CString>,
|
||||
platform_name: Option<CString>,
|
||||
renderer_name: Option<CString>,
|
||||
// we need to box this because we hand imgui a pointer to it,
|
||||
// and we don't want to deal with finding `clipboard_ctx`.
|
||||
// we also put it in an unsafecell since we're going to give
|
||||
// imgui a mutable pointer to it.
|
||||
clipboard_ctx: Box<UnsafeCell<ClipboardContext>>,
|
||||
}
|
||||
|
||||
// This mutex needs to be used to guard all public functions that can affect the underlying
|
||||
// Dear ImGui active context
|
||||
static CTX_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(());
|
||||
|
||||
fn clear_current_context() {
|
||||
unsafe {
|
||||
sys::igSetCurrentContext(ptr::null_mut());
|
||||
}
|
||||
}
|
||||
fn no_current_context() -> bool {
|
||||
let ctx = unsafe { sys::igGetCurrentContext() };
|
||||
ctx.is_null()
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Creates a new active imgui-rs context.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an active context already exists
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create() -> Self {
|
||||
Self::create_internal(None)
|
||||
}
|
||||
/// Creates a new active imgui-rs context with a shared font atlas.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an active context already exists
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create_with_shared_font_atlas(shared_font_atlas: Rc<RefCell<SharedFontAtlas>>) -> Self {
|
||||
Self::create_internal(Some(shared_font_atlas))
|
||||
}
|
||||
/// Suspends this context so another context can be the active context.
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn suspend(self) -> SuspendedContext {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
assert!(
|
||||
self.is_current_context(),
|
||||
"context to be suspended is not the active context"
|
||||
);
|
||||
clear_current_context();
|
||||
SuspendedContext(self)
|
||||
}
|
||||
/// Returns the path to the ini file, or None if not set
|
||||
pub fn ini_filename(&self) -> Option<PathBuf> {
|
||||
let io = self.io();
|
||||
if io.ini_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
let s = unsafe { CStr::from_ptr(io.ini_filename) };
|
||||
Some(PathBuf::from(s.to_str().ok()?))
|
||||
}
|
||||
}
|
||||
/// Sets the path to the ini file (default is "imgui.ini")
|
||||
///
|
||||
/// Pass None to disable automatic .Ini saving.
|
||||
pub fn set_ini_filename<T: Into<Option<PathBuf>>>(&mut self, ini_filename: T) {
|
||||
let ini_filename: Option<PathBuf> = ini_filename.into();
|
||||
let ini_filename = ini_filename.and_then(|v| CString::new(v.to_str()?).ok());
|
||||
|
||||
self.io_mut().ini_filename = ini_filename
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.ini_filename = ini_filename;
|
||||
}
|
||||
/// Returns the path to the log file, or None if not set
|
||||
// TODO: why do we return an `Option<PathBuf>` instead of an `Option<&Path>`?
|
||||
pub fn log_filename(&self) -> Option<PathBuf> {
|
||||
let io = self.io();
|
||||
if io.log_filename.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.log_filename) };
|
||||
Some(PathBuf::from(cstr.to_str().ok()?))
|
||||
}
|
||||
}
|
||||
/// Sets the log filename (default is "imgui_log.txt").
|
||||
pub fn set_log_filename<T: Into<Option<PathBuf>>>(&mut self, log_filename: T) {
|
||||
let log_filename = log_filename
|
||||
.into()
|
||||
.and_then(|v| CString::new(v.to_str()?).ok());
|
||||
|
||||
self.io_mut().log_filename = log_filename
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.log_filename = log_filename;
|
||||
}
|
||||
/// Returns the backend platform name, or None if not set
|
||||
pub fn platform_name(&self) -> Option<&str> {
|
||||
let io = self.io();
|
||||
if io.backend_platform_name.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.backend_platform_name) };
|
||||
cstr.to_str().ok()
|
||||
}
|
||||
}
|
||||
/// Sets the backend platform name
|
||||
pub fn set_platform_name<T: Into<Option<String>>>(&mut self, platform_name: T) {
|
||||
let platform_name: Option<CString> =
|
||||
platform_name.into().and_then(|v| CString::new(v).ok());
|
||||
self.io_mut().backend_platform_name = platform_name
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
self.platform_name = platform_name;
|
||||
}
|
||||
/// Returns the backend renderer name, or None if not set
|
||||
pub fn renderer_name(&self) -> Option<&str> {
|
||||
let io = self.io();
|
||||
if io.backend_renderer_name.is_null() {
|
||||
None
|
||||
} else {
|
||||
let cstr = unsafe { CStr::from_ptr(io.backend_renderer_name) };
|
||||
cstr.to_str().ok()
|
||||
}
|
||||
}
|
||||
/// Sets the backend renderer name
|
||||
pub fn set_renderer_name<T: Into<Option<String>>>(&mut self, renderer_name: T) {
|
||||
let renderer_name: Option<CString> =
|
||||
renderer_name.into().and_then(|v| CString::new(v).ok());
|
||||
|
||||
self.io_mut().backend_renderer_name = renderer_name
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or(ptr::null());
|
||||
|
||||
self.renderer_name = renderer_name;
|
||||
}
|
||||
/// Loads settings from a string slice containing settings in .Ini file format
|
||||
#[doc(alias = "LoadIniSettingsFromMemory")]
|
||||
pub fn load_ini_settings(&mut self, data: &str) {
|
||||
unsafe { sys::igLoadIniSettingsFromMemory(data.as_ptr() as *const _, data.len()) }
|
||||
}
|
||||
/// Saves settings to a mutable string buffer in .Ini file format
|
||||
#[doc(alias = "SaveInitSettingsToMemory")]
|
||||
pub fn save_ini_settings(&mut self, buf: &mut String) {
|
||||
let data = unsafe { CStr::from_ptr(sys::igSaveIniSettingsToMemory(ptr::null_mut())) };
|
||||
buf.push_str(&data.to_string_lossy());
|
||||
}
|
||||
/// Sets the clipboard backend used for clipboard operations
|
||||
pub fn set_clipboard_backend<T: ClipboardBackend>(&mut self, backend: T) {
|
||||
let clipboard_ctx: Box<UnsafeCell<_>> = Box::new(ClipboardContext::new(backend).into());
|
||||
let io = self.io_mut();
|
||||
io.set_clipboard_text_fn = Some(crate::clipboard::set_clipboard_text);
|
||||
io.get_clipboard_text_fn = Some(crate::clipboard::get_clipboard_text);
|
||||
|
||||
io.clipboard_user_data = clipboard_ctx.get() as *mut _;
|
||||
self.clipboard_ctx = clipboard_ctx;
|
||||
}
|
||||
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
assert!(
|
||||
no_current_context(),
|
||||
"A new active context cannot be created, because another one already exists"
|
||||
);
|
||||
|
||||
let shared_font_atlas_ptr = match &shared_font_atlas {
|
||||
Some(shared_font_atlas) => {
|
||||
let borrowed_font_atlas = shared_font_atlas.borrow();
|
||||
borrowed_font_atlas.0
|
||||
}
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
// Dear ImGui implicitly sets the current context during igCreateContext if the current
|
||||
// context doesn't exist
|
||||
let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
|
||||
|
||||
Context {
|
||||
raw,
|
||||
shared_font_atlas,
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
}
|
||||
}
|
||||
fn is_current_context(&self) -> bool {
|
||||
let ctx = unsafe { sys::igGetCurrentContext() };
|
||||
self.raw == ctx
|
||||
}
|
||||
|
||||
/// Get a reference to the current context
|
||||
pub fn current() -> Option<ContextRef> {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
|
||||
let raw = unsafe { sys::igGetCurrentContext() };
|
||||
|
||||
if raw.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(ContextRef(ManuallyDrop::new(Context {
|
||||
raw,
|
||||
shared_font_atlas: None, // XXX: this might be needed tbh
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference to a [`Context`] object
|
||||
#[derive(Debug)]
|
||||
pub struct ContextRef(ManuallyDrop<Context>);
|
||||
|
||||
impl core::ops::Deref for ContextRef {
|
||||
type Target = Context;
|
||||
|
||||
fn deref(&self) -> &Context {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for ContextRef {
|
||||
fn deref_mut(&mut self) -> &mut Context {
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
#[doc(alias = "DestroyContext")]
|
||||
fn drop(&mut self) {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
// If this context is the active context, Dear ImGui automatically deactivates it during
|
||||
// destruction
|
||||
unsafe {
|
||||
sys::igDestroyContext(self.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A suspended imgui-rs context.
|
||||
///
|
||||
/// A suspended context retains its state, but is not usable without activating it first.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Suspended contexts are not directly very useful, but you can activate them:
|
||||
///
|
||||
/// ```
|
||||
/// let suspended = imgui::SuspendedContext::create();
|
||||
/// match suspended.activate() {
|
||||
/// Ok(ctx) => {
|
||||
/// // ctx is now the active context
|
||||
/// },
|
||||
/// Err(suspended) => {
|
||||
/// // activation failed, so you get the suspended context back
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct SuspendedContext(Context);
|
||||
|
||||
impl SuspendedContext {
|
||||
/// Creates a new suspended imgui-rs context.
|
||||
#[doc(alias = "CreateContext")]
|
||||
pub fn create() -> Self {
|
||||
Self::create_internal(None)
|
||||
}
|
||||
/// Creates a new suspended imgui-rs context with a shared font atlas.
|
||||
pub fn create_with_shared_font_atlas(shared_font_atlas: Rc<RefCell<SharedFontAtlas>>) -> Self {
|
||||
Self::create_internal(Some(shared_font_atlas))
|
||||
}
|
||||
/// Attempts to activate this suspended context.
|
||||
///
|
||||
/// If there is no active context, this suspended context is activated and `Ok` is returned,
|
||||
/// containing the activated context.
|
||||
/// If there is already an active context, nothing happens and `Err` is returned, containing
|
||||
/// the original suspended context.
|
||||
#[doc(alias = "SetCurrentContext")]
|
||||
pub fn activate(self) -> Result<Context, SuspendedContext> {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
if no_current_context() {
|
||||
unsafe {
|
||||
sys::igSetCurrentContext(self.0.raw);
|
||||
}
|
||||
Ok(self.0)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
||||
let _guard = CTX_MUTEX.lock();
|
||||
let raw = unsafe { sys::igCreateContext(ptr::null_mut()) };
|
||||
let ctx = Context {
|
||||
raw,
|
||||
shared_font_atlas,
|
||||
ini_filename: None,
|
||||
log_filename: None,
|
||||
platform_name: None,
|
||||
renderer_name: None,
|
||||
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||
};
|
||||
if ctx.is_current_context() {
|
||||
// Oops, the context was activated -> deactivate
|
||||
clear_current_context();
|
||||
}
|
||||
SuspendedContext(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_context() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let _ctx = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_clears_current_context() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
{
|
||||
let _ctx1 = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
assert!(no_current_context());
|
||||
{
|
||||
let _ctx2 = Context::create();
|
||||
assert!(!no_current_context());
|
||||
}
|
||||
assert!(no_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_suspended() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
let _suspended = SuspendedContext::create();
|
||||
assert!(ctx.is_current_context());
|
||||
::std::mem::drop(_suspended);
|
||||
assert!(ctx.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert!(!no_current_context());
|
||||
let _suspended = ctx.suspend();
|
||||
assert!(no_current_context());
|
||||
let _ctx2 = Context::create();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_suspended() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
assert!(no_current_context());
|
||||
let ctx2 = Context::create();
|
||||
::std::mem::drop(suspended);
|
||||
assert!(ctx2.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend_activate() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
assert!(no_current_context());
|
||||
let ctx = suspended.activate().unwrap();
|
||||
assert!(ctx.is_current_context());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suspend_failure() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let suspended = Context::create().suspend();
|
||||
let _ctx = Context::create();
|
||||
assert!(suspended.activate().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shared_font_atlas() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let atlas = Rc::new(RefCell::new(SharedFontAtlas::create()));
|
||||
let suspended1 = SuspendedContext::create_with_shared_font_atlas(atlas.clone());
|
||||
let mut ctx2 = Context::create_with_shared_font_atlas(atlas);
|
||||
{
|
||||
let _borrow = ctx2.fonts();
|
||||
}
|
||||
let _suspended2 = ctx2.suspend();
|
||||
let mut ctx = suspended1.activate().unwrap();
|
||||
let _borrow = ctx.fonts();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_shared_font_atlas_borrow_panic() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let atlas = Rc::new(RefCell::new(SharedFontAtlas::create()));
|
||||
let _suspended = SuspendedContext::create_with_shared_font_atlas(atlas.clone());
|
||||
let mut ctx = Context::create_with_shared_font_atlas(atlas.clone());
|
||||
let _borrow1 = atlas.borrow();
|
||||
let _borrow2 = ctx.fonts();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ini_load_save() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
let data = "[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0";
|
||||
ctx.load_ini_settings(data);
|
||||
let mut buf = String::new();
|
||||
ctx.save_ini_settings(&mut buf);
|
||||
assert_eq!(data.trim(), buf.trim());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_ini_filename() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert_eq!(ctx.ini_filename(), Some(PathBuf::from("imgui.ini")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_ini_filename() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
ctx.set_ini_filename(Some(PathBuf::from("test.ini")));
|
||||
assert_eq!(ctx.ini_filename(), Some(PathBuf::from("test.ini")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_log_filename() {
|
||||
let _guard = crate::test::TEST_MUTEX.lock();
|
||||
let ctx = Context::create();
|
||||
assert_eq!(ctx.log_filename(), Some(PathBuf::from("imgui_log.txt")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_log_filename() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
ctx.set_log_filename(Some(PathBuf::from("test.log")));
|
||||
assert_eq!(ctx.log_filename(), Some(PathBuf::from("test.log")));
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Returns an immutable reference to the inputs/outputs object
|
||||
pub fn io(&self) -> &Io {
|
||||
unsafe {
|
||||
// safe because Io is a transparent wrapper around sys::ImGuiIO
|
||||
&*(sys::igGetIO() as *const Io)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the inputs/outputs object
|
||||
pub fn io_mut(&mut self) -> &mut Io {
|
||||
unsafe {
|
||||
// safe because Io is a transparent wrapper around sys::ImGuiIO
|
||||
&mut *(sys::igGetIO() as *mut Io)
|
||||
}
|
||||
}
|
||||
/// Returns an immutable reference to the user interface style
|
||||
#[doc(alias = "GetStyle")]
|
||||
pub fn style(&self) -> &Style {
|
||||
unsafe {
|
||||
// safe because Style is a transparent wrapper around sys::ImGuiStyle
|
||||
&*(sys::igGetStyle() as *const Style)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the user interface style
|
||||
#[doc(alias = "GetStyle")]
|
||||
pub fn style_mut(&mut self) -> &mut Style {
|
||||
unsafe {
|
||||
// safe because Style is a transparent wrapper around sys::ImGuiStyle
|
||||
&mut *(sys::igGetStyle() as *mut Style)
|
||||
}
|
||||
}
|
||||
/// Returns a mutable reference to the font atlas.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the context uses a shared font atlas that is already borrowed
|
||||
pub fn fonts(&mut self) -> FontAtlasRefMut<'_> {
|
||||
match self.shared_font_atlas {
|
||||
Some(ref font_atlas) => FontAtlasRefMut::Shared(font_atlas.borrow_mut()),
|
||||
None => unsafe {
|
||||
// safe because FontAtlas is a transparent wrapper around sys::ImFontAtlas
|
||||
let fonts = &mut *(self.io_mut().fonts as *mut FontAtlas);
|
||||
FontAtlasRefMut::Owned(fonts)
|
||||
},
|
||||
}
|
||||
}
|
||||
/// Starts a new frame and returns an `Ui` instance for constructing a user interface.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the context uses a shared font atlas that is already borrowed
|
||||
#[doc(alias = "NewFame")]
|
||||
pub fn frame(&mut self) -> Ui<'_> {
|
||||
// Clear default font if it no longer exists. This could be an error in the future
|
||||
let default_font = self.io().font_default;
|
||||
if !default_font.is_null() && self.fonts().get_font(FontId(default_font)).is_none() {
|
||||
self.io_mut().font_default = ptr::null_mut();
|
||||
}
|
||||
// NewFrame/Render/EndFrame mutate the font atlas so we need exclusive access to it
|
||||
let font_atlas = self
|
||||
.shared_font_atlas
|
||||
.as_ref()
|
||||
.map(|font_atlas| font_atlas.borrow_mut());
|
||||
// TODO: precondition checks
|
||||
unsafe {
|
||||
sys::igNewFrame();
|
||||
}
|
||||
Ui {
|
||||
ctx: self,
|
||||
font_atlas,
|
||||
buffer: crate::UiBuffer::new(1024).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,594 +0,0 @@
|
||||
//! Structs to create a Drag and Drop sequence. Almost all structs are re-exported
|
||||
//! and can be accessed from the crate root; some additional utilities can be found in here.
|
||||
//!
|
||||
//! A DragDrop is a UI mechanism where users can appear to "drag"
|
||||
//! some data from one [source](DragDropSource) to one [target](DragDropTarget).
|
||||
//! A source and a target must both have some `name` identifier, which is declared when they
|
||||
//! are created. If these names are equal, then a `payload` of some kind
|
||||
//! will be given to the target caller when the user releases their mouse button over
|
||||
//! the target (additionally, the UI will reflect that the payload *can* be deposited
|
||||
//! in the target).
|
||||
//!
|
||||
//! The complexity of this implementation is primarily in managing this payload. Users
|
||||
//! can provide three different kinds of payloads:
|
||||
//!
|
||||
//! 1. Users can give an [empty payload](DragDropPayloadEmpty) with [begin](DragDropSource::begin).
|
||||
//! This payload type is essentially just a notification system, but using some shared state,
|
||||
//! this can be reasonably powerful, and is the safest way to transfer non-Copy data offered
|
||||
//! right now.
|
||||
//! 2. Users can give a [simple Copy payload](DragDropPayloadPod) with [begin](DragDropSource::begin_payload).
|
||||
//! This allows users to copy data to Dear ImGui, which will take ownership over it, and then be given
|
||||
//! it back to the Target. Please note: users are of course free to not drop any drag (cancel a drag),
|
||||
//! so this data could easily be lost forever. Our `'static + Copy` bound is intended to keep users
|
||||
//! to simplistic types.
|
||||
//! 3. An unsafe implementation is provided which allows for any data to be unsafely copied. Note that once
|
||||
//! you use this method, the safe implementations in #1 and #2 can create memory unsafety problems; notably,
|
||||
//! they both assume that a payload has certain header information within it.
|
||||
//!
|
||||
//! For examples of each payload type, see [DragDropSource].
|
||||
use std::{any, ffi, marker::PhantomData};
|
||||
|
||||
use crate::{sys, Condition, Ui};
|
||||
use bitflags::bitflags;
|
||||
|
||||
bitflags!(
|
||||
/// Flags for igBeginDragDropSource(), igAcceptDragDropPayload()
|
||||
#[repr(transparent)]
|
||||
pub struct DragDropFlags: u32 {
|
||||
/// By default, a successful call to igBeginDragDropSource opens a tooltip so you can
|
||||
/// display a preview or description of the source contents. This flag disable this
|
||||
/// behavior.
|
||||
const SOURCE_NO_PREVIEW_TOOLTIP = sys::ImGuiDragDropFlags_SourceNoPreviewTooltip;
|
||||
/// By default, when dragging we clear data so that igIsItemHovered() will return false, to
|
||||
/// avoid subsequent user code submitting tooltips. This flag disable this behavior so you
|
||||
/// can still call igIsItemHovered() on the source item.
|
||||
const SOURCE_NO_DISABLE_HOVER = sys::ImGuiDragDropFlags_SourceNoDisableHover;
|
||||
/// Disable the behavior that allows to open tree nodes and collapsing header by holding
|
||||
/// over them while dragging a source item.
|
||||
const SOURCE_NO_HOLD_TO_OPEN_OTHERS = sys::ImGuiDragDropFlags_SourceNoHoldToOpenOthers;
|
||||
/// Allow items such as igText(), igImage() that have no unique identifier to be used as
|
||||
/// drag source, by manufacturing a temporary identifier based on their window-relative
|
||||
/// position. This is extremely unusual within the dear imgui ecosystem and so we made it
|
||||
/// explicit.
|
||||
const SOURCE_ALLOW_NULL_ID = sys::ImGuiDragDropFlags_SourceAllowNullID;
|
||||
/// External source (from outside of imgui), won't attempt to read current item/window
|
||||
/// info. Will always return true. Only one Extern source can be active simultaneously.
|
||||
const SOURCE_EXTERN = sys::ImGuiDragDropFlags_SourceExtern;
|
||||
/// Automatically expire the payload if the source ceases to be submitted (otherwise
|
||||
/// payloads are persisting while being dragged)
|
||||
const SOURCE_AUTO_EXPIRE_PAYLOAD = sys::ImGuiDragDropFlags_SourceAutoExpirePayload;
|
||||
/// igAcceptDragDropPayload() will returns true even before the mouse button is released.
|
||||
/// You can then call igIsDelivery() to test if the payload needs to be delivered.
|
||||
const ACCEPT_BEFORE_DELIVERY = sys::ImGuiDragDropFlags_AcceptBeforeDelivery;
|
||||
/// Do not draw the default highlight rectangle when hovering over target.
|
||||
const ACCEPT_NO_DRAW_DEFAULT_RECT = sys::ImGuiDragDropFlags_AcceptNoDrawDefaultRect;
|
||||
/// Request hiding the igBeginDragDropSource tooltip from the igBeginDragDropTarget site.
|
||||
const ACCEPT_NO_PREVIEW_TOOLTIP = sys::ImGuiDragDropFlags_AcceptNoPreviewTooltip;
|
||||
/// For peeking ahead and inspecting the payload before delivery. This is just a convenience
|
||||
/// flag for the intersection of `ACCEPT_BEFORE_DELIVERY` and `ACCEPT_NO_DRAW_DEFAULT_RECT`
|
||||
const ACCEPT_PEEK_ONLY = sys::ImGuiDragDropFlags_AcceptPeekOnly;
|
||||
}
|
||||
);
|
||||
|
||||
/// Creates a source for drag drop data out of the last ID created.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// ui.button("Hello, I am a drag source!");
|
||||
///
|
||||
/// // Creates an empty DragSource with no tooltip
|
||||
/// DragDropSource::new("BUTTON_DRAG").begin(ui);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Notice especially the `"BUTTON_DRAG"` name -- this is the identifier of this
|
||||
/// DragDropSource; [DragDropTarget]'s will specify an identifier to *receive*, and these
|
||||
/// names must match up. A single item should only have one [DragDropSource], though
|
||||
/// a target may have multiple different targets.
|
||||
///
|
||||
/// DropDropSources don't do anything until you use one of the three `begin_` methods
|
||||
/// on this struct. Each of these methods describes how you handle the Payload which ImGui
|
||||
/// will manage, and then give to a [DragDropTarget], which will received the payload. The
|
||||
/// simplest and safest Payload is the empty payload, created with [begin](Self::begin).
|
||||
#[derive(Debug)]
|
||||
pub struct DragDropSource<T> {
|
||||
name: T,
|
||||
flags: DragDropFlags,
|
||||
cond: Condition,
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> DragDropSource<T> {
|
||||
/// Creates a new [DragDropSource] with no flags and the `Condition::Always` with the given name.
|
||||
/// ImGui refers to this `name` field as a `type`, but really it's just an identifier to match up
|
||||
/// Source/Target for DragDrop.
|
||||
pub fn new(name: T) -> Self {
|
||||
Self {
|
||||
name,
|
||||
flags: DragDropFlags::empty(),
|
||||
cond: Condition::Always,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the flags on the [DragDropSource]. Only the flags `SOURCE_NO_PREVIEW_TOOLTIP`,
|
||||
/// `SOURCE_NO_DISABLE_HOVER`, `SOURCE_NO_HOLD_TO_OPEN_OTHERS`, `SOURCE_ALLOW_NULL_ID`,
|
||||
/// `SOURCE_EXTERN`, `SOURCE_AUTO_EXPIRE_PAYLOAD` make semantic sense, but any other flags will
|
||||
/// be accepted without panic.
|
||||
#[inline]
|
||||
pub fn flags(mut self, flags: DragDropFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the condition on the [DragDropSource]. Defaults to [Always](Condition::Always).
|
||||
#[inline]
|
||||
pub fn condition(mut self, cond: Condition) -> Self {
|
||||
self.cond = cond;
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This drag has no payload, but is still probably the most useful way in imgui-rs to handle payloads.
|
||||
/// Using `once_cell` or some shared data, this pattern can be very powerful:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>, drop_message: &mut Option<String>) {
|
||||
/// ui.button("Drag me!");
|
||||
///
|
||||
/// let drag_drop_name = "Test Drag";
|
||||
///
|
||||
/// // drag drop SOURCE
|
||||
/// if DragDropSource::new(drag_drop_name).begin(ui).is_some() {
|
||||
/// // warning -- this would allocate every frame if `DragDropSource` has
|
||||
/// // condition `Always`, which it does by default. We're okay with that for
|
||||
/// // this example, but real code probably wouldn't want to allocate so much.
|
||||
/// *drop_message = Some("Test Payload".to_string());
|
||||
/// }
|
||||
///
|
||||
/// ui.button("Target me!");
|
||||
///
|
||||
/// // drag drop TARGET
|
||||
/// if let Some(target) = imgui::DragDropTarget::new(ui) {
|
||||
/// if target
|
||||
/// .accept_payload_empty(drag_drop_name, DragDropFlags::empty())
|
||||
/// .is_some()
|
||||
/// {
|
||||
/// let msg = drop_message.take().unwrap();
|
||||
/// assert_eq!(msg, "Test Payload");
|
||||
/// }
|
||||
///
|
||||
/// target.pop();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In the above, you'll see how the payload is really just a message passing service.
|
||||
/// If you want to pass a simple integer or other "plain old data", take a look at
|
||||
/// [begin_payload](Self::begin_payload).
|
||||
#[inline]
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
self.begin_payload(ui, ())
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This function also takes a payload in the form of `T: Copy + 'static`. ImGui will
|
||||
/// memcpy this data immediately to an internally held buffer, and will return the data
|
||||
/// to [DragDropTarget].
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// ui.button("Drag me!");
|
||||
///
|
||||
/// let drag_drop_name = "Test Drag";
|
||||
/// let msg_to_send = "hello there sailor";
|
||||
///
|
||||
/// // drag drop SOURCE
|
||||
/// if let Some(tooltip) = DragDropSource::new(drag_drop_name).begin_payload(ui, msg_to_send) {
|
||||
/// ui.text("Sending message!");
|
||||
/// tooltip.end();
|
||||
/// }
|
||||
///
|
||||
/// ui.button("Target me!");
|
||||
///
|
||||
/// // drag drop TARGET
|
||||
/// if let Some(target) = imgui::DragDropTarget::new(ui) {
|
||||
/// if let Some(Ok(payload_data)) = target
|
||||
/// .accept_payload::<&'static str, _>(drag_drop_name, DragDropFlags::empty())
|
||||
/// {
|
||||
/// let msg = payload_data.data;
|
||||
/// assert_eq!(msg, msg_to_send);
|
||||
/// }
|
||||
///
|
||||
/// target.pop();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn begin_payload<'ui, P: Copy + 'static>(
|
||||
self,
|
||||
ui: &Ui<'ui>,
|
||||
payload: P,
|
||||
) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
unsafe {
|
||||
let payload = TypedPayload::new(payload);
|
||||
self.begin_payload_unchecked(
|
||||
ui,
|
||||
&payload as *const _ as *const ffi::c_void,
|
||||
std::mem::size_of::<TypedPayload<P>>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the source of a drag and returns a handle on the tooltip.
|
||||
/// This handle can be immediately dropped without binding it, in which case a default empty
|
||||
/// circle will be used for the "blank" tooltip as this item is being dragged around.
|
||||
///
|
||||
/// Otherwise, use this tooltip to add data which will display as this item is dragged.
|
||||
/// If `SOURCE_NO_PREVIEW_TOOLTIP` is enabled, however, no preview will be displayed
|
||||
/// and this returned token does nothing. Additionally, a given target may use the flag
|
||||
/// `ACCEPT_NO_PREVIEW_TOOLTIP`, which will also prevent this tooltip from being shown.
|
||||
///
|
||||
/// This function also takes a payload of any `*const T`. ImGui will
|
||||
/// memcpy this data immediately to an internally held buffer, and will return the data
|
||||
/// to [DragDropTarget].
|
||||
///
|
||||
/// ## Safety
|
||||
/// This function itself will not cause a panic, but using it directly opts you into
|
||||
/// managing the lifetime of the pointer provided yourself. Dear ImGui will execute a memcpy on
|
||||
/// the data passed in with the size (in bytes) given, but this is, of course, just a copy,
|
||||
/// so if you pass in an `&String`, for example, the underlying String data will not be cloned,
|
||||
/// and could easily dangle if the `String` is dropped.
|
||||
///
|
||||
/// Moreover, if `Condition::Always` is set (as it is by default), you will be copying in your data
|
||||
/// every time this function is ran in your update loop, which if it involves an allocating and then
|
||||
/// handing the allocation to ImGui, would result in a significant amount of data created.
|
||||
///
|
||||
/// Overall, users should be very sure that this function is needed before they reach for it, and instead
|
||||
/// should consider either [begin](Self::begin) or [begin_payload](Self::begin_payload).
|
||||
#[inline]
|
||||
pub unsafe fn begin_payload_unchecked<'ui>(
|
||||
&self,
|
||||
ui: &Ui<'ui>,
|
||||
ptr: *const ffi::c_void,
|
||||
size: usize,
|
||||
) -> Option<DragDropSourceToolTip<'ui>> {
|
||||
let should_begin = sys::igBeginDragDropSource(self.flags.bits() as i32);
|
||||
|
||||
if should_begin {
|
||||
sys::igSetDragDropPayload(ui.scratch_txt(&self.name), ptr, size, self.cond as i32);
|
||||
|
||||
Some(DragDropSourceToolTip::push())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper struct for RAII drag-drop support.
|
||||
pub struct DragDropSourceToolTip<'ui>(PhantomData<Ui<'ui>>);
|
||||
|
||||
impl DragDropSourceToolTip<'_> {
|
||||
/// Creates a new tooltip internally.
|
||||
#[inline]
|
||||
fn push() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
|
||||
/// Ends the tooltip directly. You could choose to simply allow this to drop
|
||||
/// by not calling this, which will also be fine.
|
||||
#[inline]
|
||||
pub fn end(self) {
|
||||
// left empty to invoke drop...
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DragDropSourceToolTip<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::igEndDragDropSource() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a target for drag drop data out of the last ID created.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// fn show_ui(ui: &Ui<'_>) {
|
||||
/// // Drop something on this button please!
|
||||
/// ui.button("Hello, I am a drag Target!");
|
||||
///
|
||||
/// if let Some(target) = DragDropTarget::new(ui) {
|
||||
/// // accepting an empty payload (which is really just raising an event)
|
||||
/// if let Some(_payload_data) = target.accept_payload_empty("BUTTON_DRAG", DragDropFlags::empty()) {
|
||||
/// println!("Nice job getting on the payload!");
|
||||
/// }
|
||||
///
|
||||
/// // and we can accept multiple, different types of payloads with one drop target.
|
||||
/// // this is a good pattern for handling different kinds of drag/drop situations with
|
||||
/// // different kinds of data in them.
|
||||
/// if let Some(Ok(payload_data)) = target.accept_payload::<usize, _>("BUTTON_ID", DragDropFlags::empty()) {
|
||||
/// println!("Our payload's data was {}", payload_data.data);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Notice especially the `"BUTTON_DRAG"` and `"BUTTON_ID"` name -- this is the identifier of this
|
||||
/// DragDropTarget; [DragDropSource]s will specify an identifier when they send a payload, and these
|
||||
/// names must match up. Notice how a target can have multiple acceptances on them -- this is a good
|
||||
/// pattern to handle multiple kinds of data which could be passed around.
|
||||
///
|
||||
/// DropDropTargets don't do anything until you use one of the three `accept_` methods
|
||||
/// on this struct. Each of these methods will spit out a _Payload struct with an increasing
|
||||
/// amount of information on the Payload. The absolute safest solution is [accept_payload_empty](Self::accept_payload_empty).
|
||||
#[derive(Debug)]
|
||||
pub struct DragDropTarget<'ui>(&'ui Ui<'ui>);
|
||||
|
||||
impl<'ui> DragDropTarget<'ui> {
|
||||
/// Creates a new DragDropTarget, holding the [Ui]'s lifetime for the duration
|
||||
/// of its existence. This is required since this struct runs some code on its Drop
|
||||
/// to end the DragDropTarget code.
|
||||
#[doc(alias = "BeginDragDropTarget")]
|
||||
pub fn new(ui: &'ui Ui<'ui>) -> Option<Self> {
|
||||
let should_begin = unsafe { sys::igBeginDragDropTarget() };
|
||||
if should_begin {
|
||||
Some(Self(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts an empty payload. This is the safest option for raising named events
|
||||
/// in the DragDrop API. See [DragDropSource::begin] for more information on how you
|
||||
/// might use this pattern.
|
||||
///
|
||||
/// Note: If you began this operation with `begin_payload_unchecked` it always incorrect
|
||||
/// to use this function. Use `accept_payload_unchecked` instead
|
||||
pub fn accept_payload_empty(
|
||||
&self,
|
||||
name: impl AsRef<str>,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<DragDropPayloadEmpty> {
|
||||
self.accept_payload(name, flags)?
|
||||
.ok()
|
||||
.map(|payload_pod: DragDropPayloadPod<()>| DragDropPayloadEmpty {
|
||||
preview: payload_pod.preview,
|
||||
delivery: payload_pod.delivery,
|
||||
})
|
||||
}
|
||||
|
||||
/// Accepts a payload with plain old data in it. This returns a Result, since you can specify any
|
||||
/// type. The sent type must match the return type (via TypeId) to receive an `Ok`.
|
||||
///
|
||||
/// Note: If you began this operation with `begin_payload_unchecked` it always incorrect
|
||||
/// to use this function. Use `accept_payload_unchecked` instead
|
||||
pub fn accept_payload<T: 'static + Copy, Name: AsRef<str>>(
|
||||
&self,
|
||||
name: Name,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<Result<DragDropPayloadPod<T>, PayloadIsWrongType>> {
|
||||
let output = unsafe { self.accept_payload_unchecked(name, flags) };
|
||||
|
||||
// convert the unsafe payload to our Result
|
||||
output.map(|unsafe_payload| {
|
||||
// sheering off the typeid...
|
||||
let received =
|
||||
unsafe { (unsafe_payload.data as *const TypedPayloadHeader).read_unaligned() };
|
||||
let expected = any::TypeId::of::<T>();
|
||||
|
||||
if received.type_id == expected {
|
||||
let data =
|
||||
unsafe { (unsafe_payload.data as *const TypedPayload<T>).read_unaligned() }
|
||||
.data;
|
||||
Ok(DragDropPayloadPod {
|
||||
data,
|
||||
preview: unsafe_payload.preview,
|
||||
delivery: unsafe_payload.delivery,
|
||||
})
|
||||
} else {
|
||||
Err(PayloadIsWrongType {
|
||||
received,
|
||||
expected: TypedPayloadHeader::new::<T>(),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Accepts a drag and drop payload which contains a raw pointer to [c_void](std::ffi::c_void)
|
||||
/// and a size in bytes. Users should generally avoid using this function
|
||||
/// if one of the safer variants is acceptable.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// Because this pointer comes from ImGui, absolutely no promises can be made on its
|
||||
/// contents, alignment, or lifetime. Interacting with it is therefore extremely unsafe.
|
||||
/// **Important:** a special note needs to be made to the [ACCEPT_BEFORE_DELIVERY](DragDropFlags::ACCEPT_BEFORE_DELIVERY) flag --
|
||||
/// passing this flag will make this function return `Some(DragDropPayload)` **even before
|
||||
/// the user has actually "dropped" the payload by release their mouse button.**
|
||||
///
|
||||
/// In safe functions, this works just fine, since the data can be freely copied
|
||||
/// (or doesn't exist at all!). However, if you are working with your own data, you must
|
||||
/// be extremely careful with this data, as you may, effectively, only have immutable access to it.
|
||||
///
|
||||
/// Moreover, if the `DragDropSource` has also used `Condition::Once` or similar when they sent the data,
|
||||
/// ImGui will assume its data is still valid even after your preview, so corrupting that data could
|
||||
/// lead to all sorts of unsafe behavior on ImGui's side. In summary, using this function for any data
|
||||
/// which isn't truly `Copy` or "plain old data" is difficult, and requires substantial knowledge
|
||||
/// of the various edge cases.
|
||||
pub unsafe fn accept_payload_unchecked(
|
||||
&self,
|
||||
name: impl AsRef<str>,
|
||||
flags: DragDropFlags,
|
||||
) -> Option<DragDropPayload> {
|
||||
let inner = sys::igAcceptDragDropPayload(self.0.scratch_txt(name), flags.bits() as i32);
|
||||
if inner.is_null() {
|
||||
None
|
||||
} else {
|
||||
let inner = *inner;
|
||||
|
||||
// @fixme: there are actually other fields on `inner` which I have shorn -- they're
|
||||
// considered internal to imgui (such as id of who sent this), so i've left it for
|
||||
// now this way.
|
||||
Some(DragDropPayload {
|
||||
data: inner.Data,
|
||||
size: inner.DataSize as usize,
|
||||
preview: inner.Preview,
|
||||
delivery: inner.Delivery,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Ends the current target. Ironically, this doesn't really do anything in ImGui
|
||||
/// or in imgui-rs, but it might in the future.
|
||||
pub fn pop(self) {
|
||||
// omitted...exists just to run Drop.
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DragDropTarget<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::igEndDragDropTarget() }
|
||||
}
|
||||
}
|
||||
|
||||
/// An empty DragDropPayload. It has no data in it, and just includes
|
||||
/// two bools with status information.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayloadEmpty {
|
||||
/// Set when [`accept_payload_empty`](DragDropTarget::accept_payload_empty) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload_empty`](DragDropTarget::accept_payload_empty) was
|
||||
/// called and mouse button is released over the target item.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
/// A DragDropPayload with status information and some POD, or plain old data,
|
||||
/// in it.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayloadPod<T: 'static + Copy> {
|
||||
/// The kind data which was requested.
|
||||
pub data: T,
|
||||
|
||||
/// Set when [`accept_payload`](DragDropTarget::accept_payload) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload`](DragDropTarget::accept_payload) was
|
||||
/// called and mouse button is released over the target item.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct DragDropPayload {
|
||||
/// Data which is copied and owned by ImGui. If you have accepted the payload, you can
|
||||
/// take ownership of the data; otherwise, view it immutably. Interacting with `data` is
|
||||
/// very unsafe.
|
||||
pub data: *const ffi::c_void,
|
||||
|
||||
/// The size of the data in bytes.
|
||||
pub size: usize,
|
||||
|
||||
/// Set when [`accept_payload_unchecked`](DragDropTarget::accept_payload_unchecked) was called
|
||||
/// and mouse has been hovering the target item.
|
||||
pub preview: bool,
|
||||
|
||||
/// Set when [`accept_payload_unchecked`](DragDropTarget::accept_payload_unchecked) was
|
||||
/// called and mouse button is released over the target item. If this is set to false, then you
|
||||
/// set DragDropFlags::ACCEPT_BEFORE_DELIVERY and shouldn't mutate `data`.
|
||||
pub delivery: bool,
|
||||
}
|
||||
|
||||
/// A typed payload.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct TypedPayload<T> {
|
||||
header: TypedPayloadHeader,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Copy + 'static> TypedPayload<T> {
|
||||
/// Creates a new typed payload which contains this data.
|
||||
fn new(data: T) -> Self {
|
||||
Self {
|
||||
header: TypedPayloadHeader::new::<T>(),
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A header for a typed payload.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
#[repr(C)]
|
||||
struct TypedPayloadHeader {
|
||||
type_id: any::TypeId,
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: &'static str,
|
||||
}
|
||||
|
||||
impl TypedPayloadHeader {
|
||||
#[cfg(debug_assertions)]
|
||||
fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
type_id: any::TypeId::of::<T>(),
|
||||
type_name: any::type_name::<T>(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
type_id: any::TypeId::of::<T>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that an incorrect payload type was received. It is opaque,
|
||||
/// but you can view useful information with Debug formatting when
|
||||
/// `debug_assertions` are enabled.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct PayloadIsWrongType {
|
||||
expected: TypedPayloadHeader,
|
||||
received: TypedPayloadHeader,
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl std::fmt::Display for PayloadIsWrongType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Payload is {} -- expected {}",
|
||||
self.received.type_name, self.expected.type_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
impl std::fmt::Display for PayloadIsWrongType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.pad("Payload is wrong type")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PayloadIsWrongType {}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,508 +0,0 @@
|
||||
use bitflags::bitflags;
|
||||
use std::cell;
|
||||
use std::f32;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::{c_int, c_uchar, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use crate::fonts::font::Font;
|
||||
use crate::fonts::glyph_ranges::FontGlyphRanges;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
use crate::TextureId;
|
||||
|
||||
bitflags! {
|
||||
/// Font atlas configuration flags
|
||||
#[repr(transparent)]
|
||||
pub struct FontAtlasFlags: u32 {
|
||||
/// Don't round the height to next power of two
|
||||
const NO_POWER_OF_TWO_HEIGHT = sys::ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||
/// Don't build software mouse cursors into the atlas
|
||||
const NO_MOUSE_CURSORS = sys::ImFontAtlasFlags_NoMouseCursors;
|
||||
/// Don't build thick line textures into the atlas
|
||||
const NO_BAKED_LINES = sys::ImFontAtlasFlags_NoBakedLines;
|
||||
}
|
||||
}
|
||||
|
||||
/// A font identifier
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct FontId(pub(crate) *const Font);
|
||||
|
||||
/// A font atlas that builds a single texture
|
||||
#[repr(C)]
|
||||
pub struct FontAtlas {
|
||||
/// Configuration flags
|
||||
pub flags: FontAtlasFlags,
|
||||
/// Texture identifier
|
||||
pub tex_id: TextureId,
|
||||
/// Texture width desired by user before building the atlas.
|
||||
///
|
||||
/// Must be a power-of-two. If you have many glyphs and your graphics API has texture size
|
||||
/// restrictions, you may want to increase texture width to decrease the height.
|
||||
pub tex_desired_width: i32,
|
||||
/// Padding between glyphs within texture in pixels.
|
||||
///
|
||||
/// Defaults to 1. If your rendering method doesn't rely on bilinear filtering, you may set
|
||||
/// this to 0.
|
||||
pub tex_glyph_padding: i32,
|
||||
|
||||
locked: bool,
|
||||
text_ready: bool,
|
||||
tex_pixels_use_colors: bool,
|
||||
tex_pixels_alpha8: *mut u8,
|
||||
tex_pixels_rgba32: *mut u32,
|
||||
tex_width: i32,
|
||||
tex_height: i32,
|
||||
tex_uv_scale: [f32; 2],
|
||||
tex_uv_white_pixel: [f32; 2],
|
||||
fonts: ImVector<*mut Font>,
|
||||
custom_rects: sys::ImVector_ImFontAtlasCustomRect,
|
||||
config_data: sys::ImVector_ImFontConfig,
|
||||
tex_uv_lines: [[f32; 4]; 64],
|
||||
font_builder_io: *const sys::ImFontBuilderIO,
|
||||
font_builder_flags: i32,
|
||||
pack_id_mouse_cursors: i32,
|
||||
pack_id_lines: i32,
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFontAtlas> for FontAtlas {}
|
||||
|
||||
impl FontAtlas {
|
||||
#[doc(alias = "AddFontDefault", alias = "AddFont")]
|
||||
pub fn add_font(&mut self, font_sources: &[FontSource<'_>]) -> FontId {
|
||||
let (head, tail) = font_sources.split_first().unwrap();
|
||||
let font_id = self.add_font_internal(head, false);
|
||||
for font in tail {
|
||||
self.add_font_internal(font, true);
|
||||
}
|
||||
font_id
|
||||
}
|
||||
fn add_font_internal(&mut self, font_source: &FontSource<'_>, merge_mode: bool) -> FontId {
|
||||
let mut raw_config = sys_font_config_default();
|
||||
raw_config.MergeMode = merge_mode;
|
||||
let raw_font = match font_source {
|
||||
FontSource::DefaultFontData { config } => unsafe {
|
||||
if let Some(config) = config {
|
||||
config.apply_to_raw_config(&mut raw_config, self.raw_mut());
|
||||
}
|
||||
sys::ImFontAtlas_AddFontDefault(self.raw_mut(), &raw_config)
|
||||
},
|
||||
FontSource::TtfData {
|
||||
data,
|
||||
size_pixels,
|
||||
config,
|
||||
} => {
|
||||
if let Some(config) = config {
|
||||
unsafe {
|
||||
config.apply_to_raw_config(&mut raw_config, self.raw_mut());
|
||||
}
|
||||
}
|
||||
// We can't guarantee `data` is alive when the font atlas is built, so
|
||||
// make a copy and move ownership of the data to the atlas
|
||||
let data_copy = unsafe {
|
||||
let ptr = sys::igMemAlloc(data.len()) as *mut u8;
|
||||
assert!(!ptr.is_null());
|
||||
slice::from_raw_parts_mut(ptr, data.len())
|
||||
};
|
||||
data_copy.copy_from_slice(data);
|
||||
raw_config.FontData = data_copy.as_mut_ptr() as *mut c_void;
|
||||
raw_config.FontDataSize = data_copy.len() as i32;
|
||||
raw_config.FontDataOwnedByAtlas = true;
|
||||
raw_config.SizePixels = *size_pixels;
|
||||
unsafe { sys::ImFontAtlas_AddFont(self.raw_mut(), &raw_config) }
|
||||
}
|
||||
};
|
||||
FontId(raw_font as *const _)
|
||||
}
|
||||
pub fn fonts(&self) -> Vec<FontId> {
|
||||
let mut result = Vec::new();
|
||||
unsafe {
|
||||
for &font in self.fonts.as_slice() {
|
||||
result.push((*font).id());
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn get_font(&self, id: FontId) -> Option<&Font> {
|
||||
unsafe {
|
||||
for &font in self.fonts.as_slice() {
|
||||
if id == FontId(font) {
|
||||
return Some(&*(font as *const Font));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Returns true if the font atlas has been built
|
||||
#[doc(alias = "IsBuilt")]
|
||||
pub fn is_built(&self) -> bool {
|
||||
unsafe { sys::ImFontAtlas_IsBuilt(self.raw() as *const sys::ImFontAtlas as *mut _) }
|
||||
}
|
||||
/// Builds a 1 byte per-pixel font atlas texture
|
||||
#[doc(alias = "GetTextDataAsAlpha8")]
|
||||
pub fn build_alpha8_texture(&mut self) -> FontAtlasTexture<'_> {
|
||||
let mut pixels: *mut c_uchar = ptr::null_mut();
|
||||
let mut width: c_int = 0;
|
||||
let mut height: c_int = 0;
|
||||
let mut bytes_per_pixel: c_int = 0;
|
||||
unsafe {
|
||||
sys::ImFontAtlas_GetTexDataAsAlpha8(
|
||||
self.raw_mut(),
|
||||
&mut pixels,
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut bytes_per_pixel,
|
||||
);
|
||||
assert!(width >= 0, "font texture width must be positive");
|
||||
assert!(height >= 0, "font texture height must be positive");
|
||||
assert!(
|
||||
bytes_per_pixel >= 0,
|
||||
"font texture bytes per pixel must be positive"
|
||||
);
|
||||
let height = height as usize;
|
||||
// Check multiplication to avoid constructing an invalid slice in case of overflow
|
||||
let pitch = width
|
||||
.checked_mul(bytes_per_pixel)
|
||||
.expect("Overflow in font texture pitch calculation")
|
||||
as usize;
|
||||
FontAtlasTexture {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
data: slice::from_raw_parts(pixels, pitch * height),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Builds a 4 byte per-pixel font atlas texture
|
||||
#[doc(alias = "GetTextDataAsRGBA32")]
|
||||
pub fn build_rgba32_texture(&mut self) -> FontAtlasTexture<'_> {
|
||||
let mut pixels: *mut c_uchar = ptr::null_mut();
|
||||
let mut width: c_int = 0;
|
||||
let mut height: c_int = 0;
|
||||
let mut bytes_per_pixel: c_int = 0;
|
||||
unsafe {
|
||||
sys::ImFontAtlas_GetTexDataAsRGBA32(
|
||||
self.raw_mut(),
|
||||
&mut pixels,
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut bytes_per_pixel,
|
||||
);
|
||||
assert!(width >= 0, "font texture width must be positive");
|
||||
assert!(height >= 0, "font texture height must be positive");
|
||||
assert!(
|
||||
bytes_per_pixel >= 0,
|
||||
"font texture bytes per pixel must be positive"
|
||||
);
|
||||
let height = height as usize;
|
||||
// Check multiplication to avoid constructing an invalid slice in case of overflow
|
||||
let pitch = width
|
||||
.checked_mul(bytes_per_pixel)
|
||||
.expect("Overflow in font texture pitch calculation")
|
||||
as usize;
|
||||
FontAtlasTexture {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
data: slice::from_raw_parts(pixels, pitch * height),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Clears the font atlas completely (both input and output data)
|
||||
#[doc(alias = "Clear")]
|
||||
pub fn clear(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_Clear(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears output font data (glyph storage, UV coordinates)
|
||||
#[doc(alias = "ClearFonts")]
|
||||
pub fn clear_fonts(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearFonts(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears output texture data.
|
||||
///
|
||||
/// Can be used to save RAM once the texture has been transferred to the GPU.
|
||||
#[doc(alias = "ClearTexData")]
|
||||
pub fn clear_tex_data(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearTexData(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Clears all the data used to build the textures and fonts
|
||||
#[doc(alias = "ClearInputData")]
|
||||
pub fn clear_input_data(&mut self) {
|
||||
unsafe {
|
||||
sys::ImFontAtlas_ClearInputData(self.raw_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_font_atlas_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<FontAtlas>(),
|
||||
mem::size_of::<sys::ImFontAtlas>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<FontAtlas>(),
|
||||
mem::align_of::<sys::ImFontAtlas>()
|
||||
);
|
||||
use sys::ImFontAtlas;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(FontAtlas, $l),
|
||||
memoffset::offset_of!(ImFontAtlas, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(locked, Locked);
|
||||
assert_field_offset!(flags, Flags);
|
||||
assert_field_offset!(tex_id, TexID);
|
||||
assert_field_offset!(tex_desired_width, TexDesiredWidth);
|
||||
assert_field_offset!(tex_glyph_padding, TexGlyphPadding);
|
||||
assert_field_offset!(tex_pixels_use_colors, TexPixelsUseColors);
|
||||
assert_field_offset!(tex_pixels_alpha8, TexPixelsAlpha8);
|
||||
assert_field_offset!(tex_pixels_rgba32, TexPixelsRGBA32);
|
||||
assert_field_offset!(tex_width, TexWidth);
|
||||
assert_field_offset!(tex_height, TexHeight);
|
||||
assert_field_offset!(tex_uv_scale, TexUvScale);
|
||||
assert_field_offset!(tex_uv_white_pixel, TexUvWhitePixel);
|
||||
assert_field_offset!(fonts, Fonts);
|
||||
assert_field_offset!(custom_rects, CustomRects);
|
||||
assert_field_offset!(config_data, ConfigData);
|
||||
assert_field_offset!(tex_uv_lines, TexUvLines);
|
||||
assert_field_offset!(pack_id_mouse_cursors, PackIdMouseCursors);
|
||||
assert_field_offset!(pack_id_lines, PackIdLines);
|
||||
}
|
||||
|
||||
/// A source for binary font data
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FontSource<'a> {
|
||||
/// Default font included with the library (ProggyClean.ttf)
|
||||
DefaultFontData { config: Option<FontConfig> },
|
||||
/// Binary TTF/OTF font data
|
||||
TtfData {
|
||||
data: &'a [u8],
|
||||
size_pixels: f32,
|
||||
config: Option<FontConfig>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Configuration settings for a font
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FontConfig {
|
||||
/// Size in pixels for the rasterizer
|
||||
pub size_pixels: f32,
|
||||
/// Horizontal oversampling
|
||||
pub oversample_h: i32,
|
||||
/// Vertical oversampling
|
||||
pub oversample_v: i32,
|
||||
/// Align every glyph to pixel boundary
|
||||
pub pixel_snap_h: bool,
|
||||
/// Extra spacing (in pixels) between glyphs
|
||||
pub glyph_extra_spacing: [f32; 2],
|
||||
/// Offset for all glyphs in this font
|
||||
pub glyph_offset: [f32; 2],
|
||||
/// Unicode ranges to use from this font
|
||||
pub glyph_ranges: FontGlyphRanges,
|
||||
/// Minimum advance_x for glyphs
|
||||
pub glyph_min_advance_x: f32,
|
||||
/// Maximum advance_x for glyphs
|
||||
pub glyph_max_advance_x: f32,
|
||||
/// Settings for a custom font rasterizer if used
|
||||
pub font_builder_flags: u32,
|
||||
/// Brighten (>1.0) or darken (<1.0) font output
|
||||
pub rasterizer_multiply: f32,
|
||||
/// Explicitly specify the ellipsis character.
|
||||
///
|
||||
/// With multiple font sources the first specified ellipsis is used.
|
||||
pub ellipsis_char: Option<char>,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for FontConfig {
|
||||
fn default() -> FontConfig {
|
||||
FontConfig {
|
||||
size_pixels: 0.0,
|
||||
oversample_h: 3,
|
||||
oversample_v: 1,
|
||||
pixel_snap_h: false,
|
||||
glyph_extra_spacing: [0.0, 0.0],
|
||||
glyph_offset: [0.0, 0.0],
|
||||
glyph_ranges: FontGlyphRanges::default(),
|
||||
glyph_min_advance_x: 0.0,
|
||||
glyph_max_advance_x: f32::MAX,
|
||||
font_builder_flags: 0,
|
||||
rasterizer_multiply: 1.0,
|
||||
ellipsis_char: None,
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontConfig {
|
||||
fn apply_to_raw_config(&self, raw: &mut sys::ImFontConfig, atlas: *mut sys::ImFontAtlas) {
|
||||
raw.SizePixels = self.size_pixels;
|
||||
raw.OversampleH = self.oversample_h;
|
||||
raw.OversampleV = self.oversample_v;
|
||||
raw.PixelSnapH = self.pixel_snap_h;
|
||||
raw.GlyphExtraSpacing = self.glyph_extra_spacing.into();
|
||||
raw.GlyphOffset = self.glyph_offset.into();
|
||||
raw.GlyphRanges = unsafe { self.glyph_ranges.to_ptr(atlas) };
|
||||
raw.GlyphMinAdvanceX = self.glyph_min_advance_x;
|
||||
raw.GlyphMaxAdvanceX = self.glyph_max_advance_x;
|
||||
raw.FontBuilderFlags = self.font_builder_flags;
|
||||
raw.RasterizerMultiply = self.rasterizer_multiply;
|
||||
// char is used as "unset" for EllipsisChar
|
||||
raw.EllipsisChar = self.ellipsis_char.map(|c| c as u32).unwrap_or(!0);
|
||||
if let Some(name) = self.name.as_ref() {
|
||||
let bytes = name.as_bytes();
|
||||
let mut len = bytes.len().min(raw.Name.len() - 1);
|
||||
while !name.is_char_boundary(len) {
|
||||
len -= 1;
|
||||
}
|
||||
unsafe {
|
||||
bytes.as_ptr().copy_to(raw.Name.as_mut_ptr() as _, len);
|
||||
raw.Name[len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_font_config_default() -> sys::ImFontConfig {
|
||||
unsafe {
|
||||
let heap_allocated = sys::ImFontConfig_ImFontConfig();
|
||||
let copy = *heap_allocated;
|
||||
sys::ImFontConfig_destroy(heap_allocated);
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_font_config_default() {
|
||||
let sys_font_config = sys_font_config_default();
|
||||
let font_config = FontConfig::default();
|
||||
assert_eq!(font_config.size_pixels, sys_font_config.SizePixels);
|
||||
assert_eq!(font_config.oversample_h, sys_font_config.OversampleH);
|
||||
assert_eq!(font_config.oversample_v, sys_font_config.OversampleV);
|
||||
assert_eq!(font_config.pixel_snap_h, sys_font_config.PixelSnapH);
|
||||
assert_eq!(
|
||||
font_config.glyph_extra_spacing[0],
|
||||
sys_font_config.GlyphExtraSpacing.x
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.glyph_extra_spacing[1],
|
||||
sys_font_config.GlyphExtraSpacing.y
|
||||
);
|
||||
assert_eq!(font_config.glyph_offset[0], sys_font_config.GlyphOffset.x);
|
||||
assert_eq!(font_config.glyph_offset[1], sys_font_config.GlyphOffset.y);
|
||||
assert_eq!(
|
||||
font_config.glyph_min_advance_x,
|
||||
sys_font_config.GlyphMinAdvanceX
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.glyph_max_advance_x,
|
||||
sys_font_config.GlyphMaxAdvanceX
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.font_builder_flags,
|
||||
sys_font_config.FontBuilderFlags
|
||||
);
|
||||
assert_eq!(
|
||||
font_config.rasterizer_multiply,
|
||||
sys_font_config.RasterizerMultiply
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle to a font atlas texture
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FontAtlasTexture<'a> {
|
||||
/// Texture width (in pixels)
|
||||
pub width: u32,
|
||||
/// Texture height (in pixels)
|
||||
pub height: u32,
|
||||
/// Raw texture data (in bytes).
|
||||
///
|
||||
/// The format depends on which function was called to obtain this data.
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
/// A font atlas that can be shared between contexts
|
||||
#[derive(Debug)]
|
||||
pub struct SharedFontAtlas(pub(crate) *mut sys::ImFontAtlas);
|
||||
|
||||
impl SharedFontAtlas {
|
||||
#[doc(alias = "ImFontAtlas", alias = "ImFontAtlas::ImFontAtlas")]
|
||||
pub fn create() -> SharedFontAtlas {
|
||||
SharedFontAtlas(unsafe { sys::ImFontAtlas_ImFontAtlas() })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SharedFontAtlas {
|
||||
#[doc(alias = "ImFontAtlas::Destroy")]
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::ImFontAtlas_destroy(self.0) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SharedFontAtlas {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
unsafe { &*(self.0 as *const FontAtlas) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for SharedFontAtlas {
|
||||
fn deref_mut(&mut self) -> &mut FontAtlas {
|
||||
unsafe { &mut *(self.0 as *mut FontAtlas) }
|
||||
}
|
||||
}
|
||||
|
||||
/// An immutably borrowed reference to a (possibly shared) font atlas
|
||||
pub enum FontAtlasRef<'a> {
|
||||
Owned(&'a FontAtlas),
|
||||
Shared(&'a cell::RefMut<'a, SharedFontAtlas>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FontAtlasRef<'a> {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
use self::FontAtlasRef::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutably borrowed reference to a (possibly shared) font atlas
|
||||
pub enum FontAtlasRefMut<'a> {
|
||||
Owned(&'a mut FontAtlas),
|
||||
Shared(cell::RefMut<'a, SharedFontAtlas>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FontAtlasRefMut<'a> {
|
||||
type Target = FontAtlas;
|
||||
fn deref(&self) -> &FontAtlas {
|
||||
use self::FontAtlasRefMut::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for FontAtlasRefMut<'a> {
|
||||
fn deref_mut(&mut self) -> &mut FontAtlas {
|
||||
use self::FontAtlasRefMut::*;
|
||||
match self {
|
||||
Owned(atlas) => atlas,
|
||||
Shared(cell) => cell,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::fonts::atlas::{FontAtlas, FontId};
|
||||
use crate::fonts::glyph::FontGlyph;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
|
||||
/// Runtime data for a single font within a font atlas
|
||||
#[repr(C)]
|
||||
pub struct Font {
|
||||
index_advance_x: ImVector<f32>,
|
||||
pub fallback_advance_x: f32,
|
||||
pub font_size: f32,
|
||||
index_lookup: ImVector<sys::ImWchar>,
|
||||
glyphs: ImVector<FontGlyph>,
|
||||
fallback_glyph: *const FontGlyph,
|
||||
container_atlas: *mut FontAtlas,
|
||||
config_data: *const sys::ImFontConfig,
|
||||
pub config_data_count: i16,
|
||||
pub fallback_char: sys::ImWchar,
|
||||
pub ellipsis_char: sys::ImWchar,
|
||||
pub dot_char: sys::ImWchar,
|
||||
pub dirty_lookup_tables: bool,
|
||||
pub scale: f32,
|
||||
pub ascent: f32,
|
||||
pub descent: f32,
|
||||
pub metrics_total_surface: c_int,
|
||||
pub used_4k_pages_map: [u8; 34],
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFont> for Font {}
|
||||
|
||||
impl Font {
|
||||
/// Returns the identifier of this font
|
||||
pub fn id(&self) -> FontId {
|
||||
FontId(self as *const _)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_font_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<Font>(), mem::size_of::<sys::ImFont>());
|
||||
assert_eq!(mem::align_of::<Font>(), mem::align_of::<sys::ImFont>());
|
||||
use sys::ImFont;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(Font, $l),
|
||||
memoffset::offset_of!(ImFont, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(index_advance_x, IndexAdvanceX);
|
||||
assert_field_offset!(fallback_advance_x, FallbackAdvanceX);
|
||||
assert_field_offset!(font_size, FontSize);
|
||||
assert_field_offset!(index_lookup, IndexLookup);
|
||||
assert_field_offset!(glyphs, Glyphs);
|
||||
assert_field_offset!(fallback_glyph, FallbackGlyph);
|
||||
assert_field_offset!(container_atlas, ContainerAtlas);
|
||||
assert_field_offset!(config_data, ConfigData);
|
||||
assert_field_offset!(config_data_count, ConfigDataCount);
|
||||
assert_field_offset!(fallback_char, FallbackChar);
|
||||
assert_field_offset!(ellipsis_char, EllipsisChar);
|
||||
assert_field_offset!(dirty_lookup_tables, DirtyLookupTables);
|
||||
assert_field_offset!(scale, Scale);
|
||||
assert_field_offset!(ascent, Ascent);
|
||||
assert_field_offset!(descent, Descent);
|
||||
assert_field_offset!(metrics_total_surface, MetricsTotalSurface);
|
||||
assert_field_offset!(used_4k_pages_map, Used4kPagesMap);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
use crate::internal::RawCast;
|
||||
use crate::sys;
|
||||
|
||||
/// A single font glyph
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct FontGlyph {
|
||||
bitfields: u32,
|
||||
pub advance_x: f32,
|
||||
pub x0: f32,
|
||||
pub y0: f32,
|
||||
pub x1: f32,
|
||||
pub y1: f32,
|
||||
pub u0: f32,
|
||||
pub v0: f32,
|
||||
pub u1: f32,
|
||||
pub v1: f32,
|
||||
}
|
||||
|
||||
impl FontGlyph {
|
||||
pub fn codepoint(&self) -> u32 {
|
||||
unsafe { self.raw().Codepoint() }
|
||||
}
|
||||
pub fn set_codepoint(&mut self, codepoint: u32) {
|
||||
unsafe { self.raw_mut().set_Codepoint(codepoint) };
|
||||
}
|
||||
pub fn visible(&self) -> bool {
|
||||
unsafe { self.raw().Visible() != 0 }
|
||||
}
|
||||
pub fn set_visible(&mut self, visible: bool) {
|
||||
unsafe { self.raw_mut().set_Visible(visible as u32) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImFontGlyph> for FontGlyph {}
|
||||
|
||||
#[test]
|
||||
fn test_font_glyph_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<FontGlyph>(),
|
||||
mem::size_of::<sys::ImFontGlyph>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<FontGlyph>(),
|
||||
mem::align_of::<sys::ImFontGlyph>()
|
||||
);
|
||||
use sys::ImFontGlyph;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(FontGlyph, $l),
|
||||
memoffset::offset_of!(ImFontGlyph, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(bitfields, _bitfield_1);
|
||||
assert_field_offset!(advance_x, AdvanceX);
|
||||
assert_field_offset!(x0, X0);
|
||||
assert_field_offset!(y0, Y0);
|
||||
assert_field_offset!(x1, X1);
|
||||
assert_field_offset!(y1, Y1);
|
||||
assert_field_offset!(u0, U0);
|
||||
assert_field_offset!(v0, V0);
|
||||
assert_field_offset!(u1, U1);
|
||||
assert_field_offset!(v1, V1);
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
use crate::sys;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
enum FontGlyphRangeData {
|
||||
ChineseSimplifiedCommon,
|
||||
ChineseFull,
|
||||
Cyrillic,
|
||||
Default,
|
||||
Japanese,
|
||||
Korean,
|
||||
Thai,
|
||||
Vietnamese,
|
||||
Custom(*const sys::ImWchar),
|
||||
}
|
||||
|
||||
/// A set of Unicode codepoints
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct FontGlyphRanges(FontGlyphRangeData);
|
||||
impl FontGlyphRanges {
|
||||
/// The default set of glyph ranges used by imgui.
|
||||
pub fn default() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Default)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with simplified common Chinese text.
|
||||
pub fn chinese_simplified_common() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::ChineseSimplifiedCommon)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Chinese text.
|
||||
pub fn chinese_full() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::ChineseFull)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Cyrillic text.
|
||||
pub fn cyrillic() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Cyrillic)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Japanese text.
|
||||
pub fn japanese() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Japanese)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Korean text.
|
||||
pub fn korean() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Korean)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Thai text.
|
||||
pub fn thai() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Thai)
|
||||
}
|
||||
/// A set of glyph ranges appropriate for use with Vietnamese text.
|
||||
pub fn vietnamese() -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Vietnamese)
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a static slice. The expected format is a series of pairs of
|
||||
/// non-zero codepoints, each representing an inclusive range, followed by a single
|
||||
/// zero terminating the range. The ranges must not overlap.
|
||||
///
|
||||
/// As the slice is expected to last as long as a font is used, and is written into global
|
||||
/// state, it must be `'static`.
|
||||
///
|
||||
/// Panics
|
||||
/// ======
|
||||
///
|
||||
/// This function will panic if the given slice is not a valid font range.
|
||||
// TODO(thom): This takes `u32` for now, since I believe it's fine for it to
|
||||
// contain surrogates? (It seems plausible that font data can describe what
|
||||
// to show for unpaired surrogates) Would be nice to be sure, if so, this
|
||||
// should accept `char` (we'd still have to check that the range doesn't
|
||||
// fully contain the surrogate range though)
|
||||
pub fn from_slice(slice: &'static [u32]) -> FontGlyphRanges {
|
||||
assert_eq!(
|
||||
slice.len() % 2,
|
||||
1,
|
||||
"The length of a glyph range must be odd."
|
||||
);
|
||||
assert_eq!(
|
||||
slice.last(),
|
||||
Some(&0),
|
||||
"A glyph range must be zero-terminated."
|
||||
);
|
||||
|
||||
for (i, &glyph) in slice.iter().enumerate().take(slice.len() - 1) {
|
||||
assert_ne!(
|
||||
glyph, 0,
|
||||
"A glyph in a range cannot be zero. \
|
||||
(Glyph is zero at index {})",
|
||||
i
|
||||
);
|
||||
assert!(
|
||||
glyph <= core::char::MAX as u32,
|
||||
"A glyph in a range cannot exceed the maximum codepoint. \
|
||||
(Glyph is {:#x} at index {})",
|
||||
glyph,
|
||||
i,
|
||||
);
|
||||
}
|
||||
|
||||
let mut ranges = Vec::new();
|
||||
for i in 0..slice.len() / 2 {
|
||||
let (start, end) = (slice[i * 2], slice[i * 2 + 1]);
|
||||
assert!(
|
||||
start <= end,
|
||||
"The start of a range cannot be larger than its end. \
|
||||
(At index {}, {} > {})",
|
||||
i * 2,
|
||||
start,
|
||||
end
|
||||
);
|
||||
ranges.push((start, end));
|
||||
}
|
||||
ranges.sort_unstable_by_key(|x| x.0);
|
||||
for i in 0..ranges.len() - 1 {
|
||||
let (range_a, range_b) = (ranges[i], ranges[i + 1]);
|
||||
if range_a.1 >= range_b.0 {
|
||||
panic!(
|
||||
"The glyph ranges {:?} and {:?} overlap between {:?}.",
|
||||
range_a,
|
||||
range_b,
|
||||
(range_a.1, range_b.0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { FontGlyphRanges::from_slice_unchecked(slice) }
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a static slice without checking its validity.
|
||||
///
|
||||
/// See [`FontGlyphRanges::from_slice`] for more information.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the slice contents are valid.
|
||||
pub unsafe fn from_slice_unchecked(slice: &'static [u32]) -> FontGlyphRanges {
|
||||
FontGlyphRanges::from_ptr(slice.as_ptr())
|
||||
}
|
||||
|
||||
/// Creates a glyph range from a pointer, without checking its validity or enforcing its
|
||||
/// lifetime. The memory the pointer points to must be valid for as long as the font is
|
||||
/// in use.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the pointer is not null, remains valid forever, and
|
||||
/// points to valid data.
|
||||
pub unsafe fn from_ptr(ptr: *const u32) -> FontGlyphRanges {
|
||||
FontGlyphRanges(FontGlyphRangeData::Custom(ptr))
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn to_ptr(&self, atlas: *mut sys::ImFontAtlas) -> *const sys::ImWchar {
|
||||
match self.0 {
|
||||
FontGlyphRangeData::ChineseFull => sys::ImFontAtlas_GetGlyphRangesChineseFull(atlas),
|
||||
FontGlyphRangeData::ChineseSimplifiedCommon => {
|
||||
sys::ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(atlas)
|
||||
}
|
||||
FontGlyphRangeData::Cyrillic => sys::ImFontAtlas_GetGlyphRangesCyrillic(atlas),
|
||||
FontGlyphRangeData::Default => sys::ImFontAtlas_GetGlyphRangesDefault(atlas),
|
||||
FontGlyphRangeData::Japanese => sys::ImFontAtlas_GetGlyphRangesJapanese(atlas),
|
||||
FontGlyphRangeData::Korean => sys::ImFontAtlas_GetGlyphRangesKorean(atlas),
|
||||
FontGlyphRangeData::Thai => sys::ImFontAtlas_GetGlyphRangesThai(atlas),
|
||||
FontGlyphRangeData::Vietnamese => sys::ImFontAtlas_GetGlyphRangesVietnamese(atlas),
|
||||
FontGlyphRangeData::Custom(ptr) => ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
use crate::fonts::font::Font;
|
||||
use crate::internal::RawCast;
|
||||
use crate::Ui;
|
||||
|
||||
pub mod atlas;
|
||||
pub mod font;
|
||||
pub mod glyph;
|
||||
pub mod glyph_ranges;
|
||||
|
||||
/// # Fonts
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the current font
|
||||
#[doc(alias = "GetFont")]
|
||||
pub fn current_font(&self) -> &Font {
|
||||
unsafe { Font::from_raw(&*sys::igGetFont()) }
|
||||
}
|
||||
/// Returns the current font size (= height in pixels) with font scale applied
|
||||
#[doc(alias = "GetFontSize")]
|
||||
pub fn current_font_size(&self) -> f32 {
|
||||
unsafe { sys::igGetFontSize() }
|
||||
}
|
||||
/// Returns the UV coordinate for a white pixel.
|
||||
///
|
||||
/// Useful for drawing custom shapes with the draw list API.
|
||||
#[doc(alias = "FontTexUvWhitePixel")]
|
||||
pub fn font_tex_uv_white_pixel(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetFontTexUvWhitePixel(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the font scale of the current window
|
||||
#[doc(alias = "SetWindowFontScale")]
|
||||
pub fn set_window_font_scale(&self, scale: f32) {
|
||||
unsafe { sys::igSetWindowFontScale(scale) }
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// A key identifier
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum Key {
|
||||
Tab = sys::ImGuiKey_Tab,
|
||||
LeftArrow = sys::ImGuiKey_LeftArrow,
|
||||
RightArrow = sys::ImGuiKey_RightArrow,
|
||||
UpArrow = sys::ImGuiKey_UpArrow,
|
||||
DownArrow = sys::ImGuiKey_DownArrow,
|
||||
PageUp = sys::ImGuiKey_PageUp,
|
||||
PageDown = sys::ImGuiKey_PageDown,
|
||||
Home = sys::ImGuiKey_Home,
|
||||
End = sys::ImGuiKey_End,
|
||||
Insert = sys::ImGuiKey_Insert,
|
||||
Delete = sys::ImGuiKey_Delete,
|
||||
Backspace = sys::ImGuiKey_Backspace,
|
||||
Space = sys::ImGuiKey_Space,
|
||||
Enter = sys::ImGuiKey_Enter,
|
||||
Escape = sys::ImGuiKey_Escape,
|
||||
KeyPadEnter = sys::ImGuiKey_KeyPadEnter,
|
||||
A = sys::ImGuiKey_A,
|
||||
C = sys::ImGuiKey_C,
|
||||
V = sys::ImGuiKey_V,
|
||||
X = sys::ImGuiKey_X,
|
||||
Y = sys::ImGuiKey_Y,
|
||||
Z = sys::ImGuiKey_Z,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
/// All possible `Key` variants
|
||||
pub const VARIANTS: [Key; Key::COUNT] = [
|
||||
Key::Tab,
|
||||
Key::LeftArrow,
|
||||
Key::RightArrow,
|
||||
Key::UpArrow,
|
||||
Key::DownArrow,
|
||||
Key::PageUp,
|
||||
Key::PageDown,
|
||||
Key::Home,
|
||||
Key::End,
|
||||
Key::Insert,
|
||||
Key::Delete,
|
||||
Key::Backspace,
|
||||
Key::Space,
|
||||
Key::Enter,
|
||||
Key::Escape,
|
||||
Key::KeyPadEnter,
|
||||
Key::A,
|
||||
Key::C,
|
||||
Key::V,
|
||||
Key::X,
|
||||
Key::Y,
|
||||
Key::Z,
|
||||
];
|
||||
/// Total count of `Key` variants
|
||||
pub const COUNT: usize = sys::ImGuiKey_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_key_variants() {
|
||||
for (idx, &value) in Key::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Target widget selection for keyboard focus
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum FocusedWidget {
|
||||
/// Previous widget
|
||||
Previous,
|
||||
/// Next widget
|
||||
Next,
|
||||
/// Widget using a relative positive offset (0 is the next widget).
|
||||
///
|
||||
/// Use this to access sub components of a multiple component widget.
|
||||
Offset(u32),
|
||||
}
|
||||
|
||||
impl FocusedWidget {
|
||||
#[inline]
|
||||
fn as_offset(self) -> i32 {
|
||||
match self {
|
||||
FocusedWidget::Previous => -1,
|
||||
FocusedWidget::Next => 0,
|
||||
FocusedWidget::Offset(offset) => offset as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Input: Keyboard
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns the key index of the given key identifier.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `key_map` field: `ui.io().key_map[key]`
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyIndex")]
|
||||
fn key_index(&self, key: Key) -> i32 {
|
||||
unsafe { sys::igGetKeyIndex(key as i32) }
|
||||
}
|
||||
/// Returns true if the key is being held.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct `keys_down` field: `ui.io().keys_down[key_index]`
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyDown")]
|
||||
pub fn is_key_down(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_down(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_down`](Self::is_key_down) but takes a key index. The meaning of
|
||||
/// index is defined by your backend implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyDown")]
|
||||
pub fn is_key_index_down(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyDown(key_index) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was pressed (went from !down to down).
|
||||
///
|
||||
/// Affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_pressed(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_pressed(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_pressed`](Self::is_key_pressed) but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_index_pressed(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyPressed(key_index, true) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was pressed (went from !down to down).
|
||||
///
|
||||
/// Is **not** affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_pressed_no_repeat(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_pressed_no_repeat`](Self::is_key_pressed_no_repeat)
|
||||
/// but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyPressed")]
|
||||
pub fn is_key_index_pressed_no_repeat(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyPressed(key_index, false) }
|
||||
}
|
||||
|
||||
/// Returns true if the key was released (went from down to !down)
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyReleased")]
|
||||
pub fn is_key_released(&self, key: Key) -> bool {
|
||||
let key_index = self.key_index(key);
|
||||
self.is_key_index_released(key_index)
|
||||
}
|
||||
|
||||
/// Same as [`is_key_released`](Self::is_key_released) but takes a key index.
|
||||
///
|
||||
/// The meaning of index is defined by your backend
|
||||
/// implementation.
|
||||
#[inline]
|
||||
#[doc(alias = "IsKeyReleased")]
|
||||
pub fn is_key_index_released(&self, key_index: i32) -> bool {
|
||||
unsafe { sys::igIsKeyReleased(key_index) }
|
||||
}
|
||||
|
||||
/// Returns a count of key presses using the given repeat rate/delay settings.
|
||||
///
|
||||
/// Usually returns 0 or 1, but might be >1 if `rate` is small enough that `io.delta_time` >
|
||||
/// `rate`.
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyPressedAmount")]
|
||||
pub fn key_pressed_amount(&self, key: Key, repeat_delay: f32, rate: f32) -> u32 {
|
||||
let key_index = self.key_index(key);
|
||||
self.key_index_pressed_amount(key_index, repeat_delay, rate)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(alias = "GetKeyPressedAmount")]
|
||||
pub fn key_index_pressed_amount(&self, key_index: i32, repeat_delay: f32, rate: f32) -> u32 {
|
||||
unsafe { sys::igGetKeyPressedAmount(key_index, repeat_delay, rate) as u32 }
|
||||
}
|
||||
|
||||
/// Focuses keyboard on the next widget.
|
||||
///
|
||||
/// This is the equivalent to [set_keyboard_focus_here_with_offset](Self::set_keyboard_focus_here_with_offset)
|
||||
/// with `target_widget` set to `FocusedWidget::Next`.
|
||||
#[inline]
|
||||
#[doc(alias = "SetKeyboardFocusHere")]
|
||||
pub fn set_keyboard_focus_here(&self) {
|
||||
self.set_keyboard_focus_here_with_offset(FocusedWidget::Next);
|
||||
}
|
||||
|
||||
/// Focuses keyboard on a widget relative to current position.
|
||||
#[inline]
|
||||
#[doc(alias = "SetKeyboardFocusHere")]
|
||||
pub fn set_keyboard_focus_here_with_offset(&self, target_widget: FocusedWidget) {
|
||||
unsafe {
|
||||
sys::igSetKeyboardFocusHere(target_widget.as_offset());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
@@ -1,478 +0,0 @@
|
||||
use std::ptr;
|
||||
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
/// Represents one of the supported mouse buttons
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum MouseButton {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Middle = 2,
|
||||
Extra1 = 3,
|
||||
Extra2 = 4,
|
||||
}
|
||||
|
||||
impl MouseButton {
|
||||
/// All possible `MouseButton` variants
|
||||
pub const VARIANTS: [MouseButton; MouseButton::COUNT] = [
|
||||
MouseButton::Left,
|
||||
MouseButton::Right,
|
||||
MouseButton::Middle,
|
||||
MouseButton::Extra1,
|
||||
MouseButton::Extra2,
|
||||
];
|
||||
/// Total count of `MouseButton` variants
|
||||
pub const COUNT: usize = 5;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_button_variants() {
|
||||
for (idx, &value) in MouseButton::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse cursor type identifier
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
// TODO: this should just be `#[allow(clippy::upper_case_acronyms)]`, but doing
|
||||
// so in a way that works before it stabilizes is a pain (in part because
|
||||
// `unknown_clippy_lints` was renamed to unknown_lints). Oh well, it's over a
|
||||
// small amount of code.
|
||||
#[allow(warnings)]
|
||||
pub enum MouseCursor {
|
||||
Arrow = sys::ImGuiMouseCursor_Arrow,
|
||||
/// Automatically used when hovering over text inputs, etc.
|
||||
TextInput = sys::ImGuiMouseCursor_TextInput,
|
||||
/// Not used automatically
|
||||
ResizeAll = sys::ImGuiMouseCursor_ResizeAll,
|
||||
/// Automatically used when hovering over a horizontal border
|
||||
ResizeNS = sys::ImGuiMouseCursor_ResizeNS,
|
||||
/// Automatically used when hovering over a vertical border or a column
|
||||
ResizeEW = sys::ImGuiMouseCursor_ResizeEW,
|
||||
/// Automatically used when hovering over the bottom-left corner of a window
|
||||
ResizeNESW = sys::ImGuiMouseCursor_ResizeNESW,
|
||||
/// Automatically used when hovering over the bottom-right corner of a window
|
||||
ResizeNWSE = sys::ImGuiMouseCursor_ResizeNWSE,
|
||||
/// Not used automatically, use for e.g. hyperlinks
|
||||
Hand = sys::ImGuiMouseCursor_Hand,
|
||||
/// When hovering something with disallowed interactions.
|
||||
///
|
||||
/// Usually a crossed circle.
|
||||
NotAllowed = sys::ImGuiMouseCursor_NotAllowed,
|
||||
}
|
||||
|
||||
impl MouseCursor {
|
||||
/// All possible `MouseCursor` variants
|
||||
pub const VARIANTS: [MouseCursor; MouseCursor::COUNT] = [
|
||||
MouseCursor::Arrow,
|
||||
MouseCursor::TextInput,
|
||||
MouseCursor::ResizeAll,
|
||||
MouseCursor::ResizeNS,
|
||||
MouseCursor::ResizeEW,
|
||||
MouseCursor::ResizeNESW,
|
||||
MouseCursor::ResizeNWSE,
|
||||
MouseCursor::Hand,
|
||||
MouseCursor::NotAllowed,
|
||||
];
|
||||
/// Total count of `MouseCursor` variants
|
||||
pub const COUNT: usize = sys::ImGuiMouseCursor_COUNT as usize;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_cursor_variants() {
|
||||
for (idx, &value) in MouseCursor::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// # Input: Mouse
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Returns true if the given mouse button is held down.
|
||||
///
|
||||
/// Equivalent to indexing the Io struct with the button, e.g. `ui.io()[button]`.
|
||||
#[doc(alias = "IsMouseDown")]
|
||||
pub fn is_mouse_down(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDown(button as i32) }
|
||||
}
|
||||
/// Returns true if any mouse button is held down
|
||||
#[doc(alias = "IsAnyMouseDown")]
|
||||
pub fn is_any_mouse_down(&self) -> bool {
|
||||
unsafe { sys::igIsAnyMouseDown() }
|
||||
}
|
||||
/// Returns true if the given mouse button was clicked (went from !down to down)
|
||||
#[doc(alias = "IsMouseClicked")]
|
||||
pub fn is_mouse_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseClicked(button as i32, false) }
|
||||
}
|
||||
/// Returns true if the given mouse button was double-clicked
|
||||
#[doc(alias = "IsMouseDoubleClicked")]
|
||||
pub fn is_mouse_double_clicked(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDoubleClicked(button as i32) }
|
||||
}
|
||||
/// Returns true if the given mouse button was released (went from down to !down)
|
||||
#[doc(alias = "IsMouseReleased")]
|
||||
pub fn is_mouse_released(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseReleased(button as i32) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down
|
||||
#[doc(alias = "IsMouseDragging")]
|
||||
pub fn is_mouse_dragging(&self, button: MouseButton) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, -1.0) }
|
||||
}
|
||||
/// Returns true if the mouse is currently dragging with the given mouse button held down.
|
||||
///
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
#[doc(alias = "IsMouseDragging")]
|
||||
pub fn is_mouse_dragging_with_threshold(&self, button: MouseButton, threshold: f32) -> bool {
|
||||
unsafe { sys::igIsMouseDragging(button as i32, threshold) }
|
||||
}
|
||||
/// Returns true if the mouse is hovering over the given bounding rect.
|
||||
///
|
||||
/// Clipped by current clipping settings, but disregards other factors like focus, window
|
||||
/// ordering, modal popup blocking.
|
||||
pub fn is_mouse_hovering_rect(&self, r_min: [f32; 2], r_max: [f32; 2]) -> bool {
|
||||
unsafe { sys::igIsMouseHoveringRect(r_min.into(), r_max.into(), true) }
|
||||
}
|
||||
/// Returns the mouse position backed up at the time of opening a popup
|
||||
#[doc(alias = "GetMousePosOnOpeningCurrentPopup")]
|
||||
pub fn mouse_pos_on_opening_current_popup(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetMousePosOnOpeningCurrentPopup(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
|
||||
/// Returns the delta from the initial position when the left mouse button clicked.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance
|
||||
/// threshold (`io.mouse_drag_threshold`).
|
||||
///
|
||||
/// This is the same as [mouse_drag_delta_with_button](Self::mouse_drag_delta_with_button) with
|
||||
/// `button` set to `MouseButton::Left`.
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta(&self) -> [f32; 2] {
|
||||
self.mouse_drag_delta_with_button(MouseButton::Left)
|
||||
}
|
||||
|
||||
/// Returns the delta from the initial position when the given button was clicked.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance
|
||||
/// threshold (`io.mouse_drag_threshold`).
|
||||
///
|
||||
/// This is the same as [mouse_drag_delta_with_threshold](Self::mouse_drag_delta_with_threshold) with
|
||||
/// `threshold` set to `-1.0`, which uses the global threshold `io.mouse_drag_threshold`.
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta_with_button(&self, button: MouseButton) -> [f32; 2] {
|
||||
self.mouse_drag_delta_with_threshold(button, -1.0)
|
||||
}
|
||||
/// Returns the delta from the initial clicking position.
|
||||
///
|
||||
/// This is locked and returns [0.0, 0.0] until the mouse has moved past the given threshold.
|
||||
/// If the given threshold is invalid or negative, the global distance threshold is used
|
||||
/// (`io.mouse_drag_threshold`).
|
||||
#[doc(alias = "GetMouseDragDelta")]
|
||||
pub fn mouse_drag_delta_with_threshold(&self, button: MouseButton, threshold: f32) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetMouseDragDelta(&mut out, button as i32, threshold) };
|
||||
out.into()
|
||||
}
|
||||
/// Resets the current delta from initial clicking position.
|
||||
#[doc(alias = "ResetMouseDragDelta")]
|
||||
pub fn reset_mouse_drag_delta(&self, button: MouseButton) {
|
||||
// This mutates the Io struct, but targets an internal field so there can't be any
|
||||
// references to it
|
||||
unsafe { sys::igResetMouseDragDelta(button as i32) }
|
||||
}
|
||||
/// Returns the currently desired mouse cursor type.
|
||||
///
|
||||
/// Returns `None` if no cursor should be displayed
|
||||
#[doc(alias = "GetMouseCursor")]
|
||||
pub fn mouse_cursor(&self) -> Option<MouseCursor> {
|
||||
match unsafe { sys::igGetMouseCursor() } {
|
||||
sys::ImGuiMouseCursor_Arrow => Some(MouseCursor::Arrow),
|
||||
sys::ImGuiMouseCursor_TextInput => Some(MouseCursor::TextInput),
|
||||
sys::ImGuiMouseCursor_ResizeAll => Some(MouseCursor::ResizeAll),
|
||||
sys::ImGuiMouseCursor_ResizeNS => Some(MouseCursor::ResizeNS),
|
||||
sys::ImGuiMouseCursor_ResizeEW => Some(MouseCursor::ResizeEW),
|
||||
sys::ImGuiMouseCursor_ResizeNESW => Some(MouseCursor::ResizeNESW),
|
||||
sys::ImGuiMouseCursor_ResizeNWSE => Some(MouseCursor::ResizeNWSE),
|
||||
sys::ImGuiMouseCursor_Hand => Some(MouseCursor::Hand),
|
||||
sys::ImGuiMouseCursor_NotAllowed => Some(MouseCursor::NotAllowed),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// Sets the desired mouse cursor type.
|
||||
///
|
||||
/// Passing `None` hides the mouse cursor.
|
||||
#[doc(alias = "SetMouseCursor")]
|
||||
pub fn set_mouse_cursor(&self, cursor_type: Option<MouseCursor>) {
|
||||
unsafe {
|
||||
sys::igSetMouseCursor(
|
||||
cursor_type
|
||||
.map(|x| x as i32)
|
||||
.unwrap_or(sys::ImGuiMouseCursor_None),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[doc(alias = "IsMousePosValid")]
|
||||
pub fn is_current_mouse_pos_valid(&self) -> bool {
|
||||
unsafe { sys::igIsMousePosValid(ptr::null()) }
|
||||
}
|
||||
#[doc(alias = "IsMousePosValid")]
|
||||
pub fn is_mouse_pos_valid(&self, mouse_pos: [f32; 2]) -> bool {
|
||||
unsafe { sys::igIsMousePosValid(&mouse_pos.into()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_down_clicked_released() {
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_down(button));
|
||||
assert!(ui.is_any_mouse_down());
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_down(button));
|
||||
assert!(ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(ui.is_mouse_released(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_down(button));
|
||||
assert!(!ui.is_any_mouse_down());
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_released(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_double_click() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
// Workaround for dear imgui bug/feature:
|
||||
// If a button is clicked before io.mouse_double_click_time seconds has passed after the
|
||||
// context is initialized, the single click is interpreted as a double-click. This happens
|
||||
// because internally g.IO.MouseClickedTime is set to 0.0, so the context creation is
|
||||
// considered a "click".
|
||||
{
|
||||
// Pass one second of time
|
||||
ctx.io_mut().delta_time = 1.0;
|
||||
let _ = ctx.frame();
|
||||
}
|
||||
// Fast clicks
|
||||
ctx.io_mut().delta_time = 1.0 / 60.0;
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
}
|
||||
// Slow clicks
|
||||
ctx.io_mut().delta_time = 1.0;
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
{
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
{
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_clicked(button));
|
||||
assert!(!ui.is_mouse_double_clicked(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_get_mouse_cursor() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
let ui = ctx.frame();
|
||||
ui.set_mouse_cursor(None);
|
||||
assert_eq!(None, ui.mouse_cursor());
|
||||
ui.set_mouse_cursor(Some(MouseCursor::Hand));
|
||||
assert_eq!(Some(MouseCursor::Hand), ui.mouse_cursor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_drags() {
|
||||
for &button in MouseButton::VARIANTS.iter() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx_initialized();
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 0.0];
|
||||
ctx.io_mut().mouse_down = [false; 5];
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 100.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 100.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [0.0, 200.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 200.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 200.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [10.0, 10.0];
|
||||
ctx.io_mut()[button] = false;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [10.0, 10.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[10.0, 10.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut()[button] = true;
|
||||
let ui = ctx.frame();
|
||||
assert!(!ui.is_mouse_dragging(button));
|
||||
assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [180.0, 180.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [170.0, 170.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[170.0, 170.0]
|
||||
);
|
||||
ui.reset_mouse_drag_delta(button);
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[0.0, 0.0]
|
||||
);
|
||||
}
|
||||
{
|
||||
ctx.io_mut().mouse_pos = [200.0, 200.0];
|
||||
let ui = ctx.frame();
|
||||
assert!(ui.is_mouse_dragging(button));
|
||||
assert!(ui.is_mouse_dragging_with_threshold(button, 200.0));
|
||||
assert_eq!(ui.mouse_drag_delta_with_button(button), [20.0, 20.0]);
|
||||
assert_eq!(
|
||||
ui.mouse_drag_delta_with_threshold(button, 200.0),
|
||||
[20.0, 20.0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,159 +0,0 @@
|
||||
//! Internal raw utilities (don't use unless you know what you're doing!)
|
||||
|
||||
use std::slice;
|
||||
|
||||
/// A generic version of the raw imgui-sys ImVector struct types
|
||||
#[repr(C)]
|
||||
pub struct ImVector<T> {
|
||||
size: i32,
|
||||
capacity: i32,
|
||||
pub(crate) data: *mut T,
|
||||
}
|
||||
|
||||
impl<T> ImVector<T> {
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
unsafe { slice::from_raw_parts(self.data, self.size as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_imvector_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<ImVector<u8>>(),
|
||||
mem::size_of::<sys::ImVector_char>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<ImVector<u8>>(),
|
||||
mem::align_of::<sys::ImVector_char>()
|
||||
);
|
||||
use sys::ImVector_char;
|
||||
type VectorChar = ImVector<u8>;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(VectorChar, $l),
|
||||
memoffset::offset_of!(ImVector_char, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(size, Size);
|
||||
assert_field_offset!(capacity, Capacity);
|
||||
assert_field_offset!(data, Data);
|
||||
}
|
||||
|
||||
/// Marks a type as a transparent wrapper over a raw type
|
||||
pub trait RawWrapper {
|
||||
/// Wrapped raw type
|
||||
type Raw;
|
||||
/// Returns an immutable reference to the wrapped raw value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to use the returned raw reference without causing undefined
|
||||
/// behaviour or breaking safety rules.
|
||||
unsafe fn raw(&self) -> &Self::Raw;
|
||||
/// Returns a mutable reference to the wrapped raw value
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to use the returned mutable raw reference without causing undefined
|
||||
/// behaviour or breaking safety rules.
|
||||
unsafe fn raw_mut(&mut self) -> &mut Self::Raw;
|
||||
}
|
||||
|
||||
/// Casting from/to a raw type that has the same layout and alignment as the target type
|
||||
pub unsafe trait RawCast<T>: Sized {
|
||||
/// Casts an immutable reference from the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn from_raw(raw: &T) -> &Self {
|
||||
&*(raw as *const _ as *const Self)
|
||||
}
|
||||
/// Casts a mutable reference from the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn from_raw_mut(raw: &mut T) -> &mut Self {
|
||||
&mut *(raw as *mut _ as *mut Self)
|
||||
}
|
||||
/// Casts an immutable reference to the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn raw(&self) -> &T {
|
||||
&*(self as *const _ as *const T)
|
||||
}
|
||||
/// Casts a mutable reference to the raw type
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the cast is valid.
|
||||
#[inline]
|
||||
unsafe fn raw_mut(&mut self) -> &mut T {
|
||||
&mut *(self as *mut _ as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
/// A primary data type
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DataType {
|
||||
I8 = sys::ImGuiDataType_S8,
|
||||
U8 = sys::ImGuiDataType_U8,
|
||||
I16 = sys::ImGuiDataType_S16,
|
||||
U16 = sys::ImGuiDataType_U16,
|
||||
I32 = sys::ImGuiDataType_S32,
|
||||
U32 = sys::ImGuiDataType_U32,
|
||||
I64 = sys::ImGuiDataType_S64,
|
||||
U64 = sys::ImGuiDataType_U64,
|
||||
F32 = sys::ImGuiDataType_Float,
|
||||
F64 = sys::ImGuiDataType_Double,
|
||||
}
|
||||
|
||||
/// Primitive type marker.
|
||||
///
|
||||
/// If this trait is implemented for a type, it is assumed to have *exactly* the same
|
||||
/// representation in memory as the primitive value described by the associated `KIND` constant.
|
||||
pub unsafe trait DataTypeKind: Copy {
|
||||
const KIND: DataType;
|
||||
}
|
||||
unsafe impl DataTypeKind for i8 {
|
||||
const KIND: DataType = DataType::I8;
|
||||
}
|
||||
unsafe impl DataTypeKind for u8 {
|
||||
const KIND: DataType = DataType::U8;
|
||||
}
|
||||
unsafe impl DataTypeKind for i16 {
|
||||
const KIND: DataType = DataType::I16;
|
||||
}
|
||||
unsafe impl DataTypeKind for u16 {
|
||||
const KIND: DataType = DataType::U16;
|
||||
}
|
||||
unsafe impl DataTypeKind for i32 {
|
||||
const KIND: DataType = DataType::I32;
|
||||
}
|
||||
unsafe impl DataTypeKind for u32 {
|
||||
const KIND: DataType = DataType::U32;
|
||||
}
|
||||
unsafe impl DataTypeKind for i64 {
|
||||
const KIND: DataType = DataType::I64;
|
||||
}
|
||||
unsafe impl DataTypeKind for u64 {
|
||||
const KIND: DataType = DataType::U64;
|
||||
}
|
||||
unsafe impl DataTypeKind for f32 {
|
||||
const KIND: DataType = DataType::F32;
|
||||
}
|
||||
unsafe impl DataTypeKind for f64 {
|
||||
const KIND: DataType = DataType::F64;
|
||||
}
|
||||
@@ -1,506 +0,0 @@
|
||||
use bitflags::bitflags;
|
||||
use std::f32;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::fonts::atlas::FontAtlas;
|
||||
use crate::fonts::font::Font;
|
||||
use crate::input::keyboard::Key;
|
||||
use crate::input::mouse::MouseButton;
|
||||
use crate::internal::{ImVector, RawCast};
|
||||
use crate::sys;
|
||||
|
||||
bitflags! {
|
||||
/// Configuration flags
|
||||
#[repr(transparent)]
|
||||
pub struct ConfigFlags: u32 {
|
||||
/// Master keyboard navigation enable flag.
|
||||
///
|
||||
/// `frame()` will automatically fill `io.nav_inputs` based on `io.keys_down`.
|
||||
const NAV_ENABLE_KEYBOARD = sys::ImGuiConfigFlags_NavEnableKeyboard;
|
||||
/// Master gamepad navigation enable flag.
|
||||
///
|
||||
/// This is mostly to instruct the backend to fill `io.nav_inputs`. The backend
|
||||
/// also needs to set `BackendFlags::HasGamepad`.
|
||||
const NAV_ENABLE_GAMEPAD = sys::ImGuiConfigFlags_NavEnableGamepad;
|
||||
/// Instruction navigation to move the mouse cursor.
|
||||
///
|
||||
/// May be useful on TV/console systems where moving a virtual mouse is awkward.
|
||||
/// Will update `io.mouse_pos` and set `io.want_set_mouse_pos = true`. If enabled,
|
||||
/// you *must* honor `io.want_set_mouse_pos`, or imgui-rs will react as if the mouse is
|
||||
/// jumping around back and forth.
|
||||
const NAV_ENABLE_SET_MOUSE_POS = sys::ImGuiConfigFlags_NavEnableSetMousePos;
|
||||
/// Instruction navigation to not set the `io.want_capture_keyboard` flag when
|
||||
/// `io.nav_active` is set.
|
||||
const NAV_NO_CAPTURE_KEYBOARD = sys::ImGuiConfigFlags_NavNoCaptureKeyboard;
|
||||
/// Instruction imgui-rs to clear mouse position/buttons in `frame()`.
|
||||
///
|
||||
/// This allows ignoring the mouse information set by the backend.
|
||||
const NO_MOUSE = sys::ImGuiConfigFlags_NoMouse;
|
||||
/// Instruction backend to not alter mouse cursor shape and visibility.
|
||||
///
|
||||
/// Use if the backend cursor changes are interfering with yours and you don't want to use
|
||||
/// `set_mouse_cursor` to change the mouse cursor. You may want to honor requests from
|
||||
/// imgui-rs by reading `get_mouse_cursor` yourself instead.
|
||||
const NO_MOUSE_CURSOR_CHANGE = sys::ImGuiConfigFlags_NoMouseCursorChange;
|
||||
/// Application is SRGB-aware.
|
||||
///
|
||||
/// Not used by core imgui-rs.
|
||||
const IS_SRGB = sys::ImGuiConfigFlags_IsSRGB;
|
||||
/// Application is using a touch screen instead of a mouse.
|
||||
///
|
||||
/// Not used by core imgui-rs.
|
||||
const IS_TOUCH_SCREEN = sys::ImGuiConfigFlags_IsTouchScreen;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Backend capabilities
|
||||
#[repr(transparent)]
|
||||
pub struct BackendFlags: u32 {
|
||||
/// Backend supports gamepad and currently has one connected
|
||||
const HAS_GAMEPAD = sys::ImGuiBackendFlags_HasGamepad;
|
||||
/// Backend supports honoring `get_mouse_cursor` value to change the OS cursor shape
|
||||
const HAS_MOUSE_CURSORS = sys::ImGuiBackendFlags_HasMouseCursors;
|
||||
/// Backend supports `io.want_set_mouse_pos` requests to reposition the OS mouse position.
|
||||
///
|
||||
/// Only used if `ConfigFlags::NavEnableSetMousePos` is set.
|
||||
const HAS_SET_MOUSE_POS = sys::ImGuiBackendFlags_HasSetMousePos;
|
||||
/// Backend renderer supports DrawCmd::vtx_offset.
|
||||
///
|
||||
/// This enables output of large meshes (64K+ vertices) while still using 16-bits indices.
|
||||
const RENDERER_HAS_VTX_OFFSET = sys::ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// An input identifier for navigation
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum NavInput {
|
||||
Activate = sys::ImGuiNavInput_Activate,
|
||||
Cancel = sys::ImGuiNavInput_Cancel,
|
||||
Input = sys::ImGuiNavInput_Input,
|
||||
Menu = sys::ImGuiNavInput_Menu,
|
||||
DpadLeft = sys::ImGuiNavInput_DpadLeft,
|
||||
DpadRight = sys::ImGuiNavInput_DpadRight,
|
||||
DpadUp = sys::ImGuiNavInput_DpadUp,
|
||||
DpadDown = sys::ImGuiNavInput_DpadDown,
|
||||
LStickLeft = sys::ImGuiNavInput_LStickLeft,
|
||||
LStickRight = sys::ImGuiNavInput_LStickRight,
|
||||
LStickUp = sys::ImGuiNavInput_LStickUp,
|
||||
LStickDown = sys::ImGuiNavInput_LStickDown,
|
||||
FocusPrev = sys::ImGuiNavInput_FocusPrev,
|
||||
FocusNext = sys::ImGuiNavInput_FocusNext,
|
||||
TweakSlow = sys::ImGuiNavInput_TweakSlow,
|
||||
TweakFast = sys::ImGuiNavInput_TweakFast,
|
||||
}
|
||||
|
||||
impl NavInput {
|
||||
/// All possible `NavInput` variants
|
||||
pub const VARIANTS: [NavInput; NavInput::COUNT] = [
|
||||
NavInput::Activate,
|
||||
NavInput::Cancel,
|
||||
NavInput::Input,
|
||||
NavInput::Menu,
|
||||
NavInput::DpadLeft,
|
||||
NavInput::DpadRight,
|
||||
NavInput::DpadUp,
|
||||
NavInput::DpadDown,
|
||||
NavInput::LStickLeft,
|
||||
NavInput::LStickRight,
|
||||
NavInput::LStickUp,
|
||||
NavInput::LStickDown,
|
||||
NavInput::FocusPrev,
|
||||
NavInput::FocusNext,
|
||||
NavInput::TweakSlow,
|
||||
NavInput::TweakFast,
|
||||
];
|
||||
/// Amount of internal/hidden variants (not exposed by imgui-rs)
|
||||
const INTERNAL_COUNT: usize = 4;
|
||||
/// Total count of `NavInput` variants
|
||||
pub const COUNT: usize = sys::ImGuiNavInput_COUNT as usize - NavInput::INTERNAL_COUNT;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nav_input_variants() {
|
||||
for (idx, &value) in NavInput::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Settings and inputs/outputs for imgui-rs
|
||||
#[repr(C)]
|
||||
pub struct Io {
|
||||
/// Flags set by user/application
|
||||
pub config_flags: ConfigFlags,
|
||||
/// Flags set by backend
|
||||
pub backend_flags: BackendFlags,
|
||||
/// Main display size in pixels
|
||||
pub display_size: [f32; 2],
|
||||
/// Time elapsed since last frame, in seconds
|
||||
pub delta_time: f32,
|
||||
/// Minimum time between saving positions/sizes to .ini file, in seconds
|
||||
pub ini_saving_rate: f32,
|
||||
|
||||
pub(crate) ini_filename: *const c_char,
|
||||
pub(crate) log_filename: *const c_char,
|
||||
|
||||
/// Time for a double-click, in seconds
|
||||
pub mouse_double_click_time: f32,
|
||||
/// Distance threshold to stay in to validate a double-click, in pixels
|
||||
pub mouse_double_click_max_dist: f32,
|
||||
/// Distance threshold before considering we are dragging
|
||||
pub mouse_drag_threshold: f32,
|
||||
/// Map of indices into the `keys_down` entries array, which represent your "native" keyboard
|
||||
/// state
|
||||
pub key_map: [u32; sys::ImGuiKey_COUNT as usize],
|
||||
/// When holding a key/button, time before it starts repeating, in seconds
|
||||
pub key_repeat_delay: f32,
|
||||
/// When holding a key/button, rate at which it repeats, in seconds
|
||||
pub key_repeat_rate: f32,
|
||||
|
||||
user_data: *mut c_void,
|
||||
pub(crate) fonts: *mut FontAtlas,
|
||||
|
||||
/// Global scale for all fonts
|
||||
pub font_global_scale: f32,
|
||||
/// Allow user to scale text of individual window with CTRL+wheel
|
||||
pub font_allow_user_scaling: bool,
|
||||
|
||||
pub(crate) font_default: *mut Font,
|
||||
|
||||
/// For retina display or other situations where window coordinates are different from
|
||||
/// framebuffer coordinates
|
||||
pub display_framebuffer_scale: [f32; 2],
|
||||
|
||||
/// Request imgui-rs to draw a mouse cursor for you
|
||||
pub mouse_draw_cursor: bool,
|
||||
/// macOS-style input behavior.
|
||||
///
|
||||
/// Defaults to true on Apple platforms. Changes in behavior:
|
||||
///
|
||||
/// * Text editing cursor movement using Alt instead of Ctrl
|
||||
/// * Shortcuts using Cmd/Super instead of Ctrl
|
||||
/// * Line/text start and end using Cmd+Arrows instead of Home/End
|
||||
/// * Double-click selects by word instead of selecting the whole text
|
||||
/// * Multi-selection in lists uses Cmd/Super instead of Ctrl
|
||||
pub config_mac_os_behaviors: bool,
|
||||
/// Set to false to disable blinking cursor
|
||||
pub config_input_text_cursor_blink: bool,
|
||||
/// Enable turning DragXXX widgets into text input with a simple mouse
|
||||
/// click-release (without moving). Not desirable on devices without a
|
||||
/// keyboard.
|
||||
pub config_drag_click_to_input_text: bool,
|
||||
/// Enable resizing of windows from their edges and from the lower-left corner.
|
||||
///
|
||||
/// Requires `HasMouserCursors` in `backend_flags`, because it needs mouse cursor feedback.
|
||||
pub config_windows_resize_from_edges: bool,
|
||||
/// Set to true to only allow moving windows when clicked+dragged from the title bar.
|
||||
///
|
||||
/// Windows without a title bar are not affected.
|
||||
pub config_windows_move_from_title_bar_only: bool,
|
||||
/// Compact memory usage when unused.
|
||||
///
|
||||
/// Set to -1.0 to disable.
|
||||
pub config_memory_compact_timer: f32,
|
||||
|
||||
pub(crate) backend_platform_name: *const c_char,
|
||||
pub(crate) backend_renderer_name: *const c_char,
|
||||
backend_platform_user_data: *mut c_void,
|
||||
backend_renderer_user_data: *mut c_void,
|
||||
backend_language_user_data: *mut c_void,
|
||||
pub(crate) get_clipboard_text_fn:
|
||||
Option<unsafe extern "C" fn(user_data: *mut c_void) -> *const c_char>,
|
||||
pub(crate) set_clipboard_text_fn:
|
||||
Option<unsafe extern "C" fn(user_data: *mut c_void, text: *const c_char)>,
|
||||
pub(crate) clipboard_user_data: *mut c_void,
|
||||
ime_set_input_screen_pos_fn: Option<unsafe extern "C" fn(x: c_int, y: c_int)>,
|
||||
ime_window_handle: *mut c_void,
|
||||
/// Mouse position, in pixels.
|
||||
///
|
||||
/// Set to [f32::MAX, f32::MAX] if mouse is unavailable (on another screen, etc.).
|
||||
pub mouse_pos: [f32; 2],
|
||||
/// Mouse buttons: 0=left, 1=right, 2=middle + extras
|
||||
pub mouse_down: [bool; 5],
|
||||
/// Mouse wheel (vertical).
|
||||
///
|
||||
/// 1 unit scrolls about 5 lines of text.
|
||||
pub mouse_wheel: f32,
|
||||
/// Mouse wheel (horizontal).
|
||||
///
|
||||
/// Most users don't have a mouse with a horizontal wheel, and may not be filled by all
|
||||
/// backends.
|
||||
pub mouse_wheel_h: f32,
|
||||
/// Keyboard modifier pressed: Control
|
||||
pub key_ctrl: bool,
|
||||
/// Keyboard modifier pressed: Shift
|
||||
pub key_shift: bool,
|
||||
/// Keyboard modifier pressed: Alt
|
||||
pub key_alt: bool,
|
||||
/// Keyboard modifier pressed: Cmd/Super/Windows
|
||||
pub key_super: bool,
|
||||
/// Keyboard keys that are pressed (indexing defined by the user/application)
|
||||
pub keys_down: [bool; 512],
|
||||
/// Gamepad inputs.
|
||||
///
|
||||
/// Cleared back to zero after each frame. Keyboard keys will be auto-mapped and written
|
||||
/// here by `frame()`.
|
||||
pub nav_inputs: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
/// When true, imgui-rs will use the mouse inputs, so do not dispatch them to your main
|
||||
/// game/application
|
||||
pub want_capture_mouse: bool,
|
||||
/// When true, imgui-rs will use the keyboard inputs, so do not dispatch them to your main
|
||||
/// game/application
|
||||
pub want_capture_keyboard: bool,
|
||||
/// Mobile/console: when true, you may display an on-screen keyboard.
|
||||
///
|
||||
/// This is set by imgui-rs when it wants textual keyboard input to happen.
|
||||
pub want_text_input: bool,
|
||||
/// Mouse position has been altered, so the backend should reposition the mouse on the next
|
||||
/// frame.
|
||||
///
|
||||
/// Set only when `ConfigFlags::NavEnableSetMousePos` is enabled.
|
||||
pub want_set_mouse_pos: bool,
|
||||
/// When manual .ini load/save is active (`ini_filename` is `None`), this will be set to notify
|
||||
/// your application that you can call `save_ini_settings` and save the settings yourself.
|
||||
///
|
||||
/// *Important*: You need to clear this flag yourself
|
||||
pub want_save_ini_settings: bool,
|
||||
/// Keyboard/Gamepad navigation is currently allowed
|
||||
pub nav_active: bool,
|
||||
/// Keyboard/Gamepad navigation is visible and allowed
|
||||
pub nav_visible: bool,
|
||||
/// Application framerate estimation, in frames per second.
|
||||
///
|
||||
/// Rolling average estimation based on `io.delta_time` over 120 frames.
|
||||
pub framerate: f32,
|
||||
/// Vertices output during last rendering
|
||||
pub metrics_render_vertices: i32,
|
||||
/// Indices output during last rendering (= number of triangles * 3)
|
||||
pub metrics_render_indices: i32,
|
||||
/// Number of visible windows
|
||||
pub metrics_render_windows: i32,
|
||||
/// Number of active windows
|
||||
pub metrics_active_windows: i32,
|
||||
/// Number of active internal imgui-rs allocations
|
||||
pub metrics_active_allocations: i32,
|
||||
/// Mouse delta.
|
||||
///
|
||||
/// Note that this is zero if either current or previous position is invalid ([f32::MAX,
|
||||
/// f32::MAX]), so a disappearing/reappearing mouse won't have a huge delta.
|
||||
pub mouse_delta: [f32; 2],
|
||||
|
||||
key_mods: sys::ImGuiKeyModFlags,
|
||||
key_mods_prev: sys::ImGuiKeyModFlags,
|
||||
mouse_pos_prev: [f32; 2],
|
||||
mouse_clicked_pos: [[f32; 2]; 5],
|
||||
mouse_clicked_time: [f64; 5],
|
||||
mouse_clicked: [bool; 5],
|
||||
mouse_double_clicked: [bool; 5],
|
||||
mouse_released: [bool; 5],
|
||||
mouse_down_owned: [bool; 5],
|
||||
mouse_down_was_double_click: [bool; 5],
|
||||
mouse_down_duration: [f32; 5],
|
||||
mouse_down_duration_prev: [f32; 5],
|
||||
mouse_drag_max_distance_abs: [[f32; 2]; 5],
|
||||
mouse_drag_max_distance_sqr: [f32; 5],
|
||||
keys_down_duration: [f32; 512],
|
||||
keys_down_duration_prev: [f32; 512],
|
||||
nav_inputs_down_duration: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
nav_inputs_down_duration_prev: [f32; NavInput::COUNT + NavInput::INTERNAL_COUNT],
|
||||
pen_pressure: f32,
|
||||
input_queue_surrogate: sys::ImWchar16,
|
||||
input_queue_characters: ImVector<sys::ImWchar>,
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImGuiIO> for Io {}
|
||||
|
||||
impl Io {
|
||||
/// Queue new character input
|
||||
#[doc(alias = "AddInputCharactersUTF8")]
|
||||
pub fn add_input_character(&mut self, character: char) {
|
||||
let mut buf = [0; 5];
|
||||
character.encode_utf8(&mut buf);
|
||||
unsafe {
|
||||
sys::ImGuiIO_AddInputCharactersUTF8(self.raw_mut(), buf.as_ptr() as *const _);
|
||||
}
|
||||
}
|
||||
/// Clear character input buffer
|
||||
#[doc(alias = "ClearCharacters")]
|
||||
pub fn clear_input_characters(&mut self) {
|
||||
unsafe {
|
||||
sys::ImGuiIO_ClearInputCharacters(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Peek character input buffer, return a copy of entire buffer
|
||||
pub fn peek_input_characters(&self) -> String {
|
||||
self.input_queue_characters().collect()
|
||||
}
|
||||
|
||||
/// Returns a view of the data in the input queue (without copying it).
|
||||
///
|
||||
/// The returned iterator is a simple mapping over a slice more or less what
|
||||
/// you need for random access to the data (Rust has no
|
||||
/// `RandomAccessIterator`, or we'd use that).
|
||||
pub fn input_queue_characters(
|
||||
&self,
|
||||
) -> impl Iterator<Item = char> + DoubleEndedIterator + ExactSizeIterator + Clone + '_ {
|
||||
self.input_queue_characters
|
||||
.as_slice()
|
||||
.iter()
|
||||
// TODO: are the values in the buffer guaranteed to be valid unicode
|
||||
// scalar values? if so we can just expose this as a `&[char]`...
|
||||
.map(|c| core::char::from_u32(*c).unwrap_or(core::char::REPLACEMENT_CHARACTER))
|
||||
}
|
||||
|
||||
pub fn update_delta_time(&mut self, delta: Duration) {
|
||||
let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
|
||||
if delta_s > 0.0 {
|
||||
self.delta_time = delta_s;
|
||||
} else {
|
||||
self.delta_time = f32::MIN_POSITIVE;
|
||||
}
|
||||
self.delta_time = delta_s;
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Key> for Io {
|
||||
type Output = u32;
|
||||
fn index(&self, index: Key) -> &u32 {
|
||||
&self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Key> for Io {
|
||||
fn index_mut(&mut self, index: Key) -> &mut u32 {
|
||||
&mut self.key_map[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NavInput> for Io {
|
||||
type Output = f32;
|
||||
fn index(&self, index: NavInput) -> &f32 {
|
||||
&self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NavInput> for Io {
|
||||
fn index_mut(&mut self, index: NavInput) -> &mut f32 {
|
||||
&mut self.nav_inputs[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<MouseButton> for Io {
|
||||
type Output = bool;
|
||||
fn index(&self, index: MouseButton) -> &bool {
|
||||
&self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<MouseButton> for Io {
|
||||
fn index_mut(&mut self, index: MouseButton) -> &mut bool {
|
||||
&mut self.mouse_down[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_io_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<Io>(), mem::size_of::<sys::ImGuiIO>());
|
||||
assert_eq!(mem::align_of::<Io>(), mem::align_of::<sys::ImGuiIO>());
|
||||
use sys::ImGuiIO;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(Io, $l),
|
||||
memoffset::offset_of!(ImGuiIO, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(config_flags, ConfigFlags);
|
||||
assert_field_offset!(backend_flags, BackendFlags);
|
||||
assert_field_offset!(display_size, DisplaySize);
|
||||
assert_field_offset!(delta_time, DeltaTime);
|
||||
assert_field_offset!(ini_saving_rate, IniSavingRate);
|
||||
assert_field_offset!(ini_filename, IniFilename);
|
||||
assert_field_offset!(log_filename, LogFilename);
|
||||
assert_field_offset!(mouse_double_click_time, MouseDoubleClickTime);
|
||||
assert_field_offset!(mouse_double_click_max_dist, MouseDoubleClickMaxDist);
|
||||
assert_field_offset!(mouse_drag_threshold, MouseDragThreshold);
|
||||
assert_field_offset!(key_map, KeyMap);
|
||||
assert_field_offset!(key_repeat_delay, KeyRepeatDelay);
|
||||
assert_field_offset!(key_repeat_rate, KeyRepeatRate);
|
||||
assert_field_offset!(user_data, UserData);
|
||||
assert_field_offset!(fonts, Fonts);
|
||||
assert_field_offset!(font_global_scale, FontGlobalScale);
|
||||
assert_field_offset!(font_allow_user_scaling, FontAllowUserScaling);
|
||||
assert_field_offset!(font_default, FontDefault);
|
||||
assert_field_offset!(display_framebuffer_scale, DisplayFramebufferScale);
|
||||
assert_field_offset!(mouse_draw_cursor, MouseDrawCursor);
|
||||
assert_field_offset!(config_mac_os_behaviors, ConfigMacOSXBehaviors);
|
||||
assert_field_offset!(config_input_text_cursor_blink, ConfigInputTextCursorBlink);
|
||||
assert_field_offset!(
|
||||
config_windows_resize_from_edges,
|
||||
ConfigWindowsResizeFromEdges
|
||||
);
|
||||
assert_field_offset!(
|
||||
config_windows_move_from_title_bar_only,
|
||||
ConfigWindowsMoveFromTitleBarOnly
|
||||
);
|
||||
assert_field_offset!(backend_platform_name, BackendPlatformName);
|
||||
assert_field_offset!(backend_renderer_name, BackendRendererName);
|
||||
assert_field_offset!(backend_platform_user_data, BackendPlatformUserData);
|
||||
assert_field_offset!(backend_renderer_user_data, BackendRendererUserData);
|
||||
assert_field_offset!(backend_language_user_data, BackendLanguageUserData);
|
||||
assert_field_offset!(get_clipboard_text_fn, GetClipboardTextFn);
|
||||
assert_field_offset!(set_clipboard_text_fn, SetClipboardTextFn);
|
||||
assert_field_offset!(clipboard_user_data, ClipboardUserData);
|
||||
assert_field_offset!(ime_set_input_screen_pos_fn, ImeSetInputScreenPosFn);
|
||||
assert_field_offset!(ime_window_handle, ImeWindowHandle);
|
||||
assert_field_offset!(mouse_pos, MousePos);
|
||||
assert_field_offset!(mouse_down, MouseDown);
|
||||
assert_field_offset!(mouse_wheel, MouseWheel);
|
||||
assert_field_offset!(mouse_wheel_h, MouseWheelH);
|
||||
assert_field_offset!(key_ctrl, KeyCtrl);
|
||||
assert_field_offset!(key_shift, KeyShift);
|
||||
assert_field_offset!(key_alt, KeyAlt);
|
||||
assert_field_offset!(key_super, KeySuper);
|
||||
assert_field_offset!(keys_down, KeysDown);
|
||||
assert_field_offset!(nav_inputs, NavInputs);
|
||||
assert_field_offset!(want_capture_mouse, WantCaptureMouse);
|
||||
assert_field_offset!(want_capture_keyboard, WantCaptureKeyboard);
|
||||
assert_field_offset!(want_text_input, WantTextInput);
|
||||
assert_field_offset!(want_set_mouse_pos, WantSetMousePos);
|
||||
assert_field_offset!(want_save_ini_settings, WantSaveIniSettings);
|
||||
assert_field_offset!(nav_active, NavActive);
|
||||
assert_field_offset!(nav_visible, NavVisible);
|
||||
assert_field_offset!(framerate, Framerate);
|
||||
assert_field_offset!(metrics_render_vertices, MetricsRenderVertices);
|
||||
assert_field_offset!(metrics_render_indices, MetricsRenderIndices);
|
||||
assert_field_offset!(metrics_render_windows, MetricsRenderWindows);
|
||||
assert_field_offset!(metrics_active_windows, MetricsActiveWindows);
|
||||
assert_field_offset!(metrics_active_allocations, MetricsActiveAllocations);
|
||||
assert_field_offset!(mouse_delta, MouseDelta);
|
||||
assert_field_offset!(key_mods, KeyMods);
|
||||
assert_field_offset!(mouse_pos_prev, MousePosPrev);
|
||||
assert_field_offset!(mouse_clicked_pos, MouseClickedPos);
|
||||
assert_field_offset!(mouse_clicked_time, MouseClickedTime);
|
||||
assert_field_offset!(mouse_clicked, MouseClicked);
|
||||
assert_field_offset!(mouse_double_clicked, MouseDoubleClicked);
|
||||
assert_field_offset!(mouse_released, MouseReleased);
|
||||
assert_field_offset!(mouse_down_owned, MouseDownOwned);
|
||||
assert_field_offset!(mouse_down_was_double_click, MouseDownWasDoubleClick);
|
||||
assert_field_offset!(mouse_down_duration, MouseDownDuration);
|
||||
assert_field_offset!(mouse_down_duration_prev, MouseDownDurationPrev);
|
||||
assert_field_offset!(mouse_drag_max_distance_abs, MouseDragMaxDistanceAbs);
|
||||
assert_field_offset!(mouse_drag_max_distance_sqr, MouseDragMaxDistanceSqr);
|
||||
assert_field_offset!(keys_down_duration, KeysDownDuration);
|
||||
assert_field_offset!(keys_down_duration_prev, KeysDownDurationPrev);
|
||||
assert_field_offset!(nav_inputs_down_duration, NavInputsDownDuration);
|
||||
assert_field_offset!(nav_inputs_down_duration_prev, NavInputsDownDurationPrev);
|
||||
assert_field_offset!(pen_pressure, PenPressure);
|
||||
assert_field_offset!(input_queue_surrogate, InputQueueSurrogate);
|
||||
assert_field_offset!(input_queue_characters, InputQueueCharacters);
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
create_token!(
|
||||
/// Tracks a layout group that can be ended with `end` or by dropping.
|
||||
pub struct GroupToken<'ui>;
|
||||
|
||||
/// Drops the layout group manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndGroup() }
|
||||
);
|
||||
|
||||
/// # Cursor / Layout
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Renders a separator (generally horizontal).
|
||||
///
|
||||
/// This becomes a vertical separator inside a menu bar or in horizontal layout mode.
|
||||
#[doc(alias = "Separator")]
|
||||
pub fn separator(&self) {
|
||||
unsafe { sys::igSeparator() }
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
///
|
||||
/// This is equivalent to calling [same_line_with_pos](Self::same_line_with_pos)
|
||||
/// with the `pos` set to 0.0, which uses `Style::item_spacing`.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line(&self) {
|
||||
self.same_line_with_pos(0.0);
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
///
|
||||
/// This is equivalent to calling [same_line_with_spacing](Self::same_line_with_spacing)
|
||||
/// with the `spacing` set to -1.0, which means no extra spacing.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line_with_pos(&self, pos_x: f32) {
|
||||
self.same_line_with_spacing(pos_x, -1.0)
|
||||
}
|
||||
|
||||
/// Call between widgets or groups to layout them horizontally.
|
||||
///
|
||||
/// X position is given in window coordinates.
|
||||
#[doc(alias = "SameLine")]
|
||||
pub fn same_line_with_spacing(&self, pos_x: f32, spacing_w: f32) {
|
||||
unsafe { sys::igSameLine(pos_x, spacing_w) }
|
||||
}
|
||||
|
||||
/// Undo a `same_line` call or force a new line when in horizontal layout mode
|
||||
#[doc(alias = "NewLine")]
|
||||
pub fn new_line(&self) {
|
||||
unsafe { sys::igNewLine() }
|
||||
}
|
||||
/// Adds vertical spacing
|
||||
#[doc(alias = "Spacing")]
|
||||
pub fn spacing(&self) {
|
||||
unsafe { sys::igSpacing() }
|
||||
}
|
||||
/// Fills a space of `size` in pixels with nothing on the current window.
|
||||
///
|
||||
/// Can be used to move the cursor on the window.
|
||||
#[doc(alias = "Dummy")]
|
||||
pub fn dummy(&self, size: [f32; 2]) {
|
||||
unsafe { sys::igDummy(size.into()) }
|
||||
}
|
||||
|
||||
/// Moves content position to the right by `Style::indent_spacing`
|
||||
///
|
||||
/// This is equivalent to [indent_by](Self::indent_by) with `width` set to
|
||||
/// `Style::ident_spacing`.
|
||||
#[doc(alias = "Indent")]
|
||||
pub fn indent(&self) {
|
||||
self.indent_by(0.0)
|
||||
}
|
||||
|
||||
/// Moves content position to the right by `width`
|
||||
#[doc(alias = "Indent")]
|
||||
pub fn indent_by(&self, width: f32) {
|
||||
unsafe { sys::igIndent(width) };
|
||||
}
|
||||
/// Moves content position to the left by `Style::indent_spacing`
|
||||
///
|
||||
/// This is equivalent to [unindent_by](Self::unindent_by) with `width` set to
|
||||
/// `Style::ident_spacing`.
|
||||
#[doc(alias = "Unindent")]
|
||||
pub fn unindent(&self) {
|
||||
self.unindent_by(0.0)
|
||||
}
|
||||
/// Moves content position to the left by `width`
|
||||
#[doc(alias = "Unindent")]
|
||||
pub fn unindent_by(&self, width: f32) {
|
||||
unsafe { sys::igUnindent(width) };
|
||||
}
|
||||
/// Groups items together as a single item.
|
||||
///
|
||||
/// May be useful to handle the same mouse event on a group of items, for example.
|
||||
///
|
||||
/// Returns a `GroupToken` that must be ended by calling `.end()`
|
||||
#[doc(alias = "BeginGroup")]
|
||||
pub fn begin_group(&self) -> GroupToken<'_> {
|
||||
unsafe { sys::igBeginGroup() };
|
||||
GroupToken::new(self)
|
||||
}
|
||||
/// Creates a layout group and runs a closure to construct the contents.
|
||||
///
|
||||
/// May be useful to handle the same mouse event on a group of items, for example.
|
||||
#[doc(alias = "BeginGroup")]
|
||||
pub fn group<R, F: FnOnce() -> R>(&self, f: F) -> R {
|
||||
let group = self.begin_group();
|
||||
let result = f();
|
||||
group.end();
|
||||
result
|
||||
}
|
||||
/// Returns the cursor position (in window coordinates)
|
||||
#[doc(alias = "GetCursorPos")]
|
||||
pub fn cursor_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the cursor position (in window coordinates).
|
||||
///
|
||||
/// This sets the point on which the next widget will be drawn.
|
||||
#[doc(alias = "SetCursorPos")]
|
||||
pub fn set_cursor_pos(&self, pos: [f32; 2]) {
|
||||
unsafe { sys::igSetCursorPos(pos.into()) };
|
||||
}
|
||||
/// Returns the initial cursor position (in window coordinates)
|
||||
#[doc(alias = "GetCursorStartPos")]
|
||||
pub fn cursor_start_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorStartPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Returns the cursor position (in absolute screen coordinates).
|
||||
///
|
||||
/// This is especially useful for drawing, as the drawing API uses screen coordinates.
|
||||
#[doc(alias = "GetCursorScreenPos")]
|
||||
pub fn cursor_screen_pos(&self) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
unsafe { sys::igGetCursorScreenPos(&mut out) };
|
||||
out.into()
|
||||
}
|
||||
/// Sets the cursor position (in absolute screen coordinates)
|
||||
#[doc(alias = "SetCursorScreenPos")]
|
||||
pub fn set_cursor_screen_pos(&self, pos: [f32; 2]) {
|
||||
unsafe { sys::igSetCursorScreenPos(pos.into()) }
|
||||
}
|
||||
/// Vertically aligns text baseline so that it will align properly to regularly frame items.
|
||||
///
|
||||
/// Call this if you have text on a line before a framed item.
|
||||
#[doc(alias = "AlignTextToFramePadding")]
|
||||
pub fn align_text_to_frame_padding(&self) {
|
||||
unsafe { sys::igAlignTextToFramePadding() };
|
||||
}
|
||||
#[doc(alias = "GetTextLineHeight")]
|
||||
pub fn text_line_height(&self) -> f32 {
|
||||
unsafe { sys::igGetTextLineHeight() }
|
||||
}
|
||||
#[doc(alias = "GetTextLineHeightWithSpacing")]
|
||||
pub fn text_line_height_with_spacing(&self) -> f32 {
|
||||
unsafe { sys::igGetTextLineHeightWithSpacing() }
|
||||
}
|
||||
#[doc(alias = "GetFrameHeight")]
|
||||
pub fn frame_height(&self) -> f32 {
|
||||
unsafe { sys::igGetFrameHeight() }
|
||||
}
|
||||
#[doc(alias = "GetFrameLineHeightWithSpacing")]
|
||||
pub fn frame_height_with_spacing(&self) -> f32 {
|
||||
unsafe { sys::igGetFrameHeightWithSpacing() }
|
||||
}
|
||||
}
|
||||
@@ -1,753 +0,0 @@
|
||||
#![cfg_attr(test, allow(clippy::float_cmp))]
|
||||
#![deny(rust_2018_idioms)]
|
||||
// #![deny(missing_docs)]
|
||||
|
||||
pub extern crate imgui_sys as sys;
|
||||
|
||||
use std::cell;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::thread;
|
||||
|
||||
pub use self::clipboard::*;
|
||||
pub use self::color::ImColor32;
|
||||
pub use self::context::*;
|
||||
pub use self::drag_drop::{DragDropFlags, DragDropSource, DragDropTarget};
|
||||
pub use self::draw_list::{ChannelsSplit, DrawListMut};
|
||||
pub use self::fonts::atlas::*;
|
||||
pub use self::fonts::font::*;
|
||||
pub use self::fonts::glyph::*;
|
||||
pub use self::fonts::glyph_ranges::*;
|
||||
pub use self::input::keyboard::*;
|
||||
pub use self::input::mouse::*;
|
||||
pub use self::input_widget::*;
|
||||
pub use self::io::*;
|
||||
pub use self::layout::*;
|
||||
pub use self::list_clipper::ListClipper;
|
||||
pub use self::plothistogram::PlotHistogram;
|
||||
pub use self::plotlines::PlotLines;
|
||||
pub use self::popups::*;
|
||||
pub use self::render::draw_data::*;
|
||||
pub use self::render::renderer::*;
|
||||
pub use self::stacks::*;
|
||||
pub use self::string::*;
|
||||
pub use self::style::*;
|
||||
|
||||
#[cfg(feature = "tables-api")]
|
||||
pub use self::tables::*;
|
||||
pub use self::utils::*;
|
||||
pub use self::widget::color_editors::*;
|
||||
pub use self::widget::combo_box::*;
|
||||
pub use self::widget::drag::*;
|
||||
pub use self::widget::image::*;
|
||||
pub use self::widget::list_box::*;
|
||||
pub use self::widget::menu::*;
|
||||
pub use self::widget::misc::*;
|
||||
pub use self::widget::progress_bar::*;
|
||||
pub use self::widget::selectable::*;
|
||||
pub use self::widget::slider::*;
|
||||
pub use self::widget::tab::*;
|
||||
pub use self::widget::tree::*;
|
||||
pub use self::window::child_window::*;
|
||||
pub use self::window::*;
|
||||
use internal::RawCast;
|
||||
|
||||
#[macro_use]
|
||||
mod string;
|
||||
|
||||
#[macro_use]
|
||||
mod tokens;
|
||||
|
||||
mod clipboard;
|
||||
pub mod color;
|
||||
mod columns;
|
||||
mod context;
|
||||
pub mod drag_drop;
|
||||
pub mod draw_list;
|
||||
mod fonts;
|
||||
mod input;
|
||||
mod input_widget;
|
||||
pub mod internal;
|
||||
mod io;
|
||||
mod layout;
|
||||
mod list_clipper;
|
||||
mod plothistogram;
|
||||
mod plotlines;
|
||||
mod popups;
|
||||
mod render;
|
||||
mod stacks;
|
||||
mod style;
|
||||
#[cfg(feature = "tables-api")]
|
||||
mod tables;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
mod utils;
|
||||
mod widget;
|
||||
mod window;
|
||||
|
||||
// Used by macros. Underscores are just to make it clear it's not part of the
|
||||
// public API.
|
||||
#[doc(hidden)]
|
||||
pub use core as __core;
|
||||
|
||||
/// Returns the underlying Dear ImGui library version
|
||||
#[doc(alias = "GetVersion")]
|
||||
pub fn dear_imgui_version() -> &'static str {
|
||||
unsafe {
|
||||
let bytes = CStr::from_ptr(sys::igGetVersion()).to_bytes();
|
||||
str::from_utf8_unchecked(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Returns the global imgui-rs time.
|
||||
///
|
||||
/// Incremented by Io::delta_time every frame.
|
||||
#[doc(alias = "GetTime")]
|
||||
pub fn time(&self) -> f64 {
|
||||
unsafe { sys::igGetTime() }
|
||||
}
|
||||
/// Returns the global imgui-rs frame count.
|
||||
///
|
||||
/// Incremented by 1 every frame.
|
||||
#[doc(alias = "GetFrameCount")]
|
||||
pub fn frame_count(&self) -> i32 {
|
||||
unsafe { sys::igGetFrameCount() }
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary reference for building the user interface for one frame
|
||||
#[derive(Debug)]
|
||||
pub struct Ui<'ui> {
|
||||
ctx: &'ui Context,
|
||||
font_atlas: Option<cell::RefMut<'ui, SharedFontAtlas>>,
|
||||
// imgui isn't multi-threaded -- so no one will ever access twice.
|
||||
buffer: cell::UnsafeCell<string::UiBuffer>,
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Internal method to push a single text to our scratch buffer.
|
||||
fn scratch_txt(&self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt(txt)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal method to push an option text to our scratch buffer.
|
||||
fn scratch_txt_opt(&self, txt: Option<impl AsRef<str>>) -> *const sys::cty::c_char {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_opt(txt)
|
||||
}
|
||||
}
|
||||
|
||||
fn scratch_txt_two(
|
||||
&self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: impl AsRef<str>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_two(txt_0, txt_1)
|
||||
}
|
||||
}
|
||||
|
||||
fn scratch_txt_with_opt(
|
||||
&self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: Option<impl AsRef<str>>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
handle.scratch_txt_with_opt(txt_0, txt_1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the inputs/outputs object
|
||||
#[doc(alias = "GetIO")]
|
||||
pub fn io(&self) -> &Io {
|
||||
unsafe { &*(sys::igGetIO() as *const Io) }
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the font atlas
|
||||
pub fn fonts(&self) -> FontAtlasRef<'_> {
|
||||
match self.font_atlas {
|
||||
Some(ref font_atlas) => FontAtlasRef::Shared(font_atlas),
|
||||
None => unsafe {
|
||||
let fonts = &*(self.io().fonts as *const FontAtlas);
|
||||
FontAtlasRef::Owned(fonts)
|
||||
},
|
||||
}
|
||||
}
|
||||
/// Returns a clone of the user interface style
|
||||
pub fn clone_style(&self) -> Style {
|
||||
*self.ctx.style()
|
||||
}
|
||||
/// Renders the frame and returns a reference to the resulting draw data
|
||||
#[doc(alias = "Render", alias = "GetDrawData")]
|
||||
pub fn render(self) -> &'ui DrawData {
|
||||
unsafe {
|
||||
sys::igRender();
|
||||
&*(sys::igGetDrawData() as *mut DrawData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Ui<'a> {
|
||||
#[doc(alias = "EndFrame")]
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() {
|
||||
unsafe {
|
||||
sys::igEndFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Demo, debug, information
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Renders a demo window (previously called a test window), which demonstrates most
|
||||
/// Dear Imgui features.
|
||||
#[doc(alias = "ShowDemoWindow")]
|
||||
pub fn show_demo_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowDemoWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders an about window.
|
||||
///
|
||||
/// Displays the Dear ImGui version/credits, and build/system information.
|
||||
#[doc(alias = "ShowAboutWindow")]
|
||||
pub fn show_about_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowAboutWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders a metrics/debug window.
|
||||
///
|
||||
/// Displays Dear ImGui internals: draw commands (with individual draw calls and vertices),
|
||||
/// window list, basic internal state, etc.
|
||||
#[doc(alias = "ShowMetricsWindow")]
|
||||
pub fn show_metrics_window(&self, opened: &mut bool) {
|
||||
unsafe {
|
||||
sys::igShowMetricsWindow(opened);
|
||||
}
|
||||
}
|
||||
/// Renders a style editor block (not a window) for the given `Style` structure
|
||||
#[doc(alias = "ShowStyleEditor")]
|
||||
pub fn show_style_editor(&self, style: &mut Style) {
|
||||
unsafe {
|
||||
sys::igShowStyleEditor(style.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Renders a style editor block (not a window) for the currently active style
|
||||
#[doc(alias = "ShowStyleEditor")]
|
||||
pub fn show_default_style_editor(&self) {
|
||||
unsafe { sys::igShowStyleEditor(ptr::null_mut()) };
|
||||
}
|
||||
/// Renders a basic help/info block (not a window)
|
||||
#[doc(alias = "ShowUserGuide")]
|
||||
pub fn show_user_guide(&self) {
|
||||
unsafe { sys::igShowUserGuide() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique ID used by widgets
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Id<'a> {
|
||||
Int(i32),
|
||||
Str(&'a str),
|
||||
Ptr(*const c_void),
|
||||
}
|
||||
|
||||
impl From<i32> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(i: i32) -> Self {
|
||||
Id::Int(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> {
|
||||
#[inline]
|
||||
fn from(s: &'a T) -> Self {
|
||||
Id::Str(s.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*const T> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(p: *const T) -> Self {
|
||||
Id::Ptr(p as *const c_void)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*mut T> for Id<'static> {
|
||||
#[inline]
|
||||
fn from(p: *mut T) -> Self {
|
||||
Id::Ptr(p as *const T as *const c_void)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Id<'a> {
|
||||
// this is used in the tables-api and possibly elsewhere,
|
||||
// but not with just default features...
|
||||
#[allow(dead_code)]
|
||||
fn as_imgui_id(&self) -> sys::ImGuiID {
|
||||
unsafe {
|
||||
match self {
|
||||
Id::Ptr(p) => sys::igGetID_Ptr(*p),
|
||||
Id::Str(s) => {
|
||||
let s1 = s.as_ptr() as *const std::os::raw::c_char;
|
||||
let s2 = s1.add(s.len());
|
||||
sys::igGetID_StrStr(s1, s2)
|
||||
}
|
||||
Id::Int(i) => {
|
||||
let p = *i as *const std::os::raw::c_void;
|
||||
sys::igGetID_Ptr(p)
|
||||
} // Id::ImGuiID(n) => *n,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for Id<'a> {
|
||||
fn default() -> Self {
|
||||
Self::Int(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: Input
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "InputText", alias = "InputTextWithHint")]
|
||||
pub fn input_text<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
buf: &'p mut String,
|
||||
) -> InputText<'ui, 'p, L> {
|
||||
InputText::new(self, label, buf)
|
||||
}
|
||||
#[doc(alias = "InputText", alias = "InputTextMultiline")]
|
||||
pub fn input_text_multiline<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
buf: &'p mut String,
|
||||
size: [f32; 2],
|
||||
) -> InputTextMultiline<'ui, 'p, L> {
|
||||
InputTextMultiline::new(self, label, buf, size)
|
||||
}
|
||||
#[doc(alias = "InputFloat2")]
|
||||
pub fn input_float<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut f32,
|
||||
) -> InputFloat<'ui, 'p, L> {
|
||||
InputFloat::new(self, label, value)
|
||||
}
|
||||
pub fn input_float2<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 2],
|
||||
) -> InputFloat2<'ui, 'p, L> {
|
||||
InputFloat2::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputFloat3")]
|
||||
pub fn input_float3<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 3],
|
||||
) -> InputFloat3<'ui, 'p, L> {
|
||||
InputFloat3::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputFloat4")]
|
||||
pub fn input_float4<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [f32; 4],
|
||||
) -> InputFloat4<'ui, 'p, L> {
|
||||
InputFloat4::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt")]
|
||||
pub fn input_int<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut i32,
|
||||
) -> InputInt<'ui, 'p, L> {
|
||||
InputInt::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt2")]
|
||||
pub fn input_int2<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 2],
|
||||
) -> InputInt2<'ui, 'p, L> {
|
||||
InputInt2::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt3")]
|
||||
pub fn input_int3<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 3],
|
||||
) -> InputInt3<'ui, 'p, L> {
|
||||
InputInt3::new(self, label, value)
|
||||
}
|
||||
#[doc(alias = "InputInt4")]
|
||||
pub fn input_int4<'p, L: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: L,
|
||||
value: &'p mut [i32; 4],
|
||||
) -> InputInt4<'ui, 'p, L> {
|
||||
InputInt4::new(self, label, value)
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a layout tooltip that can be ended by calling `.end()` or by dropping.
|
||||
pub struct TooltipToken<'ui>;
|
||||
|
||||
/// Drops the layout tooltip manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndTooltip() }
|
||||
);
|
||||
|
||||
/// # Tooltips
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Construct a tooltip window that can have any kind of content.
|
||||
///
|
||||
/// Typically used with `Ui::is_item_hovered()` or some other conditional check.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// ui.text("Hover over me");
|
||||
/// if ui.is_item_hovered() {
|
||||
/// ui.tooltip(|| {
|
||||
/// ui.text_colored([1.0, 0.0, 0.0, 1.0], im_str!("I'm red!"));
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginTooltip", alias = "EndTooltip")]
|
||||
pub fn tooltip<F: FnOnce()>(&self, f: F) {
|
||||
unsafe { sys::igBeginTooltip() };
|
||||
f();
|
||||
unsafe { sys::igEndTooltip() };
|
||||
}
|
||||
/// Construct a tooltip window that can have any kind of content.
|
||||
///
|
||||
/// Returns a `TooltipToken` that must be ended by calling `.end()`
|
||||
#[doc(alias = "BeginTooltip")]
|
||||
pub fn begin_tooltip(&self) -> TooltipToken<'_> {
|
||||
unsafe { sys::igBeginTooltip() };
|
||||
TooltipToken::new(self)
|
||||
}
|
||||
/// Construct a tooltip window with simple text content.
|
||||
///
|
||||
/// Typically used with `Ui::is_item_hovered()` or some other conditional check.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// ui.text("Hover over me");
|
||||
/// if ui.is_item_hovered() {
|
||||
/// ui.tooltip_text("I'm a tooltip!");
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginTooltip", alias = "EndTooltip")]
|
||||
pub fn tooltip_text<T: AsRef<str>>(&self, text: T) {
|
||||
self.tooltip(|| self.text(text));
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Starts a scope where interaction is disabled. Ends be calling `.end()` or when the token is dropped.
|
||||
pub struct DisabledToken<'ui>;
|
||||
|
||||
/// Drops the layout tooltip manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndDisabled() }
|
||||
);
|
||||
|
||||
/// # Disabling widgets
|
||||
///
|
||||
/// imgui can disable widgets so they don't react to mouse/keyboard
|
||||
/// inputs, and are displayed differently (currently dimmed by an
|
||||
/// amount set in [`Style::disabled_alpha`])
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Creates a scope where interactions are disabled.
|
||||
///
|
||||
/// Scope ends when returned token is dropped, or `.end()` is
|
||||
/// explicitly called
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// let disable_buttons = true;
|
||||
/// let _d = ui.begin_disabled(disable_buttons);
|
||||
/// ui.button(im_str!("Dangerous button"));
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[doc(alias = "BeginDisabled")]
|
||||
pub fn begin_disabled(&self, disabled: bool) -> DisabledToken<'_> {
|
||||
unsafe { sys::igBeginDisabled(disabled) };
|
||||
DisabledToken::new(self)
|
||||
}
|
||||
|
||||
/// Identical to [`Ui::begin_disabled`] but exists to allow avoiding a
|
||||
/// double-negative, for example `begin_enabled(enable_buttons)`
|
||||
/// instead of `begin_disabled(!enable_buttons)`)
|
||||
#[doc(alias = "BeginDisabled")]
|
||||
pub fn begin_enabled(&self, enabled: bool) -> DisabledToken<'_> {
|
||||
self.begin_disabled(!enabled)
|
||||
}
|
||||
|
||||
/// Helper to create a disabled section of widgets
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use imgui::*;
|
||||
/// fn user_interface(ui: &Ui) {
|
||||
/// let safe_mode = true;
|
||||
/// ui.disabled(safe_mode, || {
|
||||
/// ui.button(im_str!("Dangerous button"));
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[doc(alias = "BeginDisabled", alias = "EndDisabled")]
|
||||
pub fn disabled<F: FnOnce()>(&self, disabled: bool, f: F) {
|
||||
unsafe { sys::igBeginDisabled(disabled) };
|
||||
f();
|
||||
unsafe { sys::igEndDisabled() };
|
||||
}
|
||||
|
||||
/// Same as [`Ui::disabled`] but with logic reversed. See
|
||||
/// [`Ui::begin_enabled`].
|
||||
#[doc(alias = "BeginDisabled", alias = "EndDisabled")]
|
||||
pub fn enabled<F: FnOnce()>(&self, enabled: bool, f: F) {
|
||||
unsafe { sys::igBeginDisabled(!enabled) };
|
||||
f();
|
||||
unsafe { sys::igEndDisabled() };
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: ListBox
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "ListBox")]
|
||||
pub fn list_box<'p, StringType: AsRef<str> + ?Sized>(
|
||||
&self,
|
||||
label: impl AsRef<str>,
|
||||
current_item: &mut i32,
|
||||
items: &'p [&'p StringType],
|
||||
height_in_items: i32,
|
||||
) -> bool {
|
||||
let (label_ptr, items_inner) = unsafe {
|
||||
let handle = &mut *self.buffer.get();
|
||||
|
||||
handle.refresh_buffer();
|
||||
let label_ptr = handle.push(label);
|
||||
|
||||
let items_inner: Vec<_> = items.iter().map(|&v| handle.push(v)).collect();
|
||||
|
||||
(label_ptr, items_inner)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sys::igListBox_Str_arr(
|
||||
label_ptr,
|
||||
current_item,
|
||||
items_inner.as_ptr() as *mut *const c_char,
|
||||
items_inner.len() as i32,
|
||||
height_in_items,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// written out for the future times...
|
||||
// #[doc(alias = "ListBox")]
|
||||
// pub fn list_box_const<'p, StringType: AsRef<str> + ?Sized, const N: usize>(
|
||||
// &self,
|
||||
// label: impl AsRef<str>,
|
||||
// current_item: &mut i32,
|
||||
// items: [&'p StringType; N],
|
||||
// height_in_items: i32,
|
||||
// ) -> bool {
|
||||
// let (label_ptr, items_inner) = unsafe {
|
||||
// let handle = &mut *self.buffer.get();
|
||||
|
||||
// handle.refresh_buffer();
|
||||
// let label_ptr = handle.push(label);
|
||||
|
||||
// let mut items_inner: [*const i8; N] = [std::ptr::null(); N];
|
||||
|
||||
// for (i, item) in items.iter().enumerate() {
|
||||
// items_inner[i] = handle.push(item);
|
||||
// }
|
||||
|
||||
// (label_ptr, items_inner)
|
||||
// };
|
||||
|
||||
// unsafe {
|
||||
// sys::igListBoxStr_arr(
|
||||
// label_ptr,
|
||||
// current_item,
|
||||
// items_inner.as_ptr() as *mut *const c_char,
|
||||
// items_inner.len() as i32,
|
||||
// height_in_items,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "PlotLines")]
|
||||
pub fn plot_lines<'p, Label: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
) -> PlotLines<'ui, 'p, Label> {
|
||||
PlotLines::new(self, label, values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "PlotHistogram")]
|
||||
pub fn plot_histogram<'p, Label: AsRef<str>>(
|
||||
&'ui self,
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
) -> PlotHistogram<'ui, 'p, Label> {
|
||||
PlotHistogram::new(self, label, values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Calculate the size required for a given text string.
|
||||
///
|
||||
/// This is the same as [calc_text_size_with_opts](Self::calc_text_size_with_opts)
|
||||
/// with `hide_text_after_double_hash` set to false and `wrap_width` set to `-1.0`.
|
||||
#[doc(alias = "CalcTextSize")]
|
||||
pub fn calc_text_size<T: AsRef<str>>(&self, text: T) -> [f32; 2] {
|
||||
self.calc_text_size_with_opts(text, false, -1.0)
|
||||
}
|
||||
|
||||
/// Calculate the size required for a given text string.
|
||||
///
|
||||
/// hide_text_after_double_hash allows the user to insert comments into their text, using a double hash-tag prefix.
|
||||
/// This is a feature of imgui.
|
||||
///
|
||||
/// wrap_width allows you to request a width at which to wrap the text to a newline for the calculation.
|
||||
#[doc(alias = "CalcTextSize")]
|
||||
pub fn calc_text_size_with_opts<T: AsRef<str>>(
|
||||
&self,
|
||||
text: T,
|
||||
hide_text_after_double_hash: bool,
|
||||
wrap_width: f32,
|
||||
) -> [f32; 2] {
|
||||
let mut out = sys::ImVec2::zero();
|
||||
let text = text.as_ref();
|
||||
|
||||
unsafe {
|
||||
let start = text.as_ptr();
|
||||
let end = start.add(text.len());
|
||||
|
||||
sys::igCalcTextSize(
|
||||
&mut out,
|
||||
start as *const c_char,
|
||||
end as *const c_char,
|
||||
hide_text_after_double_hash,
|
||||
wrap_width,
|
||||
)
|
||||
};
|
||||
out.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// # Draw list for custom drawing
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Get access to drawing API
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// fn custom_draw(ui: &Ui) {
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// // Draw a line
|
||||
/// const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
|
||||
/// draw_list.add_line([100.0, 100.0], [200.0, 200.0], WHITE).build();
|
||||
/// // Continue drawing ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This function will panic if several instances of [`DrawListMut`]
|
||||
/// coexist. Before a new instance is got, a previous instance should be
|
||||
/// dropped.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use imgui::*;
|
||||
/// fn custom_draw(ui: &Ui) {
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// // Draw something...
|
||||
///
|
||||
/// // This second call will panic!
|
||||
/// let draw_list = ui.get_window_draw_list();
|
||||
/// }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[doc(alias = "GetWindowDrawList")]
|
||||
pub fn get_window_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::window(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(alias = "GetBackgroundDrawList")]
|
||||
pub fn get_background_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::background(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(alias = "GetForegroundDrawList")]
|
||||
pub fn get_foreground_draw_list(&'ui self) -> DrawListMut<'ui> {
|
||||
DrawListMut::foreground(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Condition for applying a setting
|
||||
#[repr(i8)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Condition {
|
||||
/// Never apply the setting
|
||||
Never = -1,
|
||||
/// Always apply the setting
|
||||
Always = sys::ImGuiCond_Always as i8,
|
||||
/// Apply the setting once per runtime session (only the first call will succeed)
|
||||
Once = sys::ImGuiCond_Once as i8,
|
||||
/// Apply the setting if the object/window has no persistently saved data (no entry in .ini
|
||||
/// file)
|
||||
FirstUseEver = sys::ImGuiCond_FirstUseEver as i8,
|
||||
/// Apply the setting if the object/window is appearing after being hidden/inactive (or the
|
||||
/// first time)
|
||||
Appearing = sys::ImGuiCond_Appearing as i8,
|
||||
}
|
||||
|
||||
/// A cardinal direction
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Direction {
|
||||
None = sys::ImGuiDir_None,
|
||||
Left = sys::ImGuiDir_Left,
|
||||
Right = sys::ImGuiDir_Right,
|
||||
Up = sys::ImGuiDir_Up,
|
||||
Down = sys::ImGuiDir_Down,
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::thread;
|
||||
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
|
||||
pub struct ListClipper {
|
||||
items_count: i32,
|
||||
items_height: f32,
|
||||
}
|
||||
|
||||
impl ListClipper {
|
||||
pub const fn new(items_count: i32) -> Self {
|
||||
ListClipper {
|
||||
items_count,
|
||||
items_height: -1.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn items_height(mut self, items_height: f32) -> Self {
|
||||
self.items_height = items_height;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> ListClipperToken<'ui> {
|
||||
let list_clipper = unsafe {
|
||||
let list_clipper = sys::ImGuiListClipper_ImGuiListClipper();
|
||||
sys::ImGuiListClipper_Begin(list_clipper, self.items_count, self.items_height);
|
||||
list_clipper
|
||||
};
|
||||
ListClipperToken::new(ui, list_clipper)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ListClipperToken<'ui> {
|
||||
list_clipper: *mut sys::ImGuiListClipper,
|
||||
_phantom: PhantomData<&'ui Ui<'ui>>,
|
||||
}
|
||||
|
||||
impl<'ui> ListClipperToken<'ui> {
|
||||
fn new(_: &Ui<'ui>, list_clipper: *mut sys::ImGuiListClipper) -> Self {
|
||||
Self {
|
||||
list_clipper,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self) -> bool {
|
||||
unsafe { sys::ImGuiListClipper_Step(self.list_clipper) }
|
||||
}
|
||||
|
||||
pub fn end(&mut self) {
|
||||
unsafe {
|
||||
sys::ImGuiListClipper_End(self.list_clipper);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_start(&self) -> i32 {
|
||||
unsafe { (*self.list_clipper).DisplayStart }
|
||||
}
|
||||
|
||||
pub fn display_end(&self) -> i32 {
|
||||
unsafe { (*self.list_clipper).DisplayEnd }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Drop for ListClipperToken<'ui> {
|
||||
fn drop(&mut self) {
|
||||
if !self.step() {
|
||||
unsafe {
|
||||
sys::ImGuiListClipper_destroy(self.list_clipper);
|
||||
};
|
||||
} else if !thread::panicking() {
|
||||
panic!(
|
||||
"Forgot to call End(), or to Step() until false? \
|
||||
This is the only token in the repository which users must call `.end()` or `.step()` \
|
||||
with. See https://github.com/imgui-rs/imgui-rs/issues/438"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use std::os::raw::c_float;
|
||||
use std::{f32, mem};
|
||||
|
||||
use super::Ui;
|
||||
|
||||
#[must_use]
|
||||
pub struct PlotHistogram<'ui, 'p, Label, Overlay = &'static str> {
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
values_offset: usize,
|
||||
overlay_text: Option<Overlay>,
|
||||
scale_min: f32,
|
||||
scale_max: f32,
|
||||
graph_size: [f32; 2],
|
||||
ui: &'ui Ui<'ui>,
|
||||
}
|
||||
|
||||
impl<'ui, 'p, Label: AsRef<str>> PlotHistogram<'ui, 'p, Label> {
|
||||
pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self {
|
||||
PlotHistogram {
|
||||
label,
|
||||
values,
|
||||
values_offset: 0usize,
|
||||
overlay_text: None,
|
||||
scale_min: f32::MAX,
|
||||
scale_max: f32::MAX,
|
||||
graph_size: [0.0, 0.0],
|
||||
ui,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui, 'p, Label: AsRef<str>, Overlay: AsRef<str>> PlotHistogram<'ui, 'p, Label, Overlay> {
|
||||
pub fn values_offset(mut self, values_offset: usize) -> Self {
|
||||
self.values_offset = values_offset;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overlay_text<NewOverlay: AsRef<str>>(
|
||||
self,
|
||||
overlay_text: NewOverlay,
|
||||
) -> PlotHistogram<'ui, 'p, Label, NewOverlay> {
|
||||
PlotHistogram {
|
||||
label: self.label,
|
||||
values: self.values,
|
||||
values_offset: self.values_offset,
|
||||
overlay_text: Some(overlay_text),
|
||||
scale_min: self.scale_min,
|
||||
scale_max: self.scale_max,
|
||||
graph_size: self.graph_size,
|
||||
ui: self.ui,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale_min(mut self, scale_min: f32) -> Self {
|
||||
self.scale_min = scale_min;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn scale_max(mut self, scale_max: f32) -> Self {
|
||||
self.scale_max = scale_max;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
|
||||
self.graph_size = graph_size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) {
|
||||
unsafe {
|
||||
let (label, overlay_text) = self.ui.scratch_txt_with_opt(self.label, self.overlay_text);
|
||||
|
||||
sys::igPlotHistogram_FloatPtr(
|
||||
label,
|
||||
self.values.as_ptr() as *const c_float,
|
||||
self.values.len() as i32,
|
||||
self.values_offset as i32,
|
||||
overlay_text,
|
||||
self.scale_min,
|
||||
self.scale_max,
|
||||
self.graph_size.into(),
|
||||
mem::size_of::<f32>() as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use std::os::raw::c_float;
|
||||
use std::{f32, mem};
|
||||
|
||||
use super::Ui;
|
||||
|
||||
#[must_use]
|
||||
pub struct PlotLines<'ui, 'p, Label, Overlay = &'static str> {
|
||||
label: Label,
|
||||
values: &'p [f32],
|
||||
values_offset: usize,
|
||||
overlay_text: Option<Overlay>,
|
||||
scale_min: f32,
|
||||
scale_max: f32,
|
||||
graph_size: [f32; 2],
|
||||
ui: &'ui Ui<'ui>,
|
||||
}
|
||||
|
||||
impl<'ui, 'p, Label: AsRef<str>> PlotLines<'ui, 'p, Label> {
|
||||
pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self {
|
||||
PlotLines {
|
||||
label,
|
||||
values,
|
||||
values_offset: 0usize,
|
||||
overlay_text: None,
|
||||
scale_min: f32::MAX,
|
||||
scale_max: f32::MAX,
|
||||
graph_size: [0.0, 0.0],
|
||||
ui,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui, 'p, Label: AsRef<str>, Overlay: AsRef<str>> PlotLines<'ui, 'p, Label, Overlay> {
|
||||
pub fn values_offset(mut self, values_offset: usize) -> Self {
|
||||
self.values_offset = values_offset;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overlay_text<Overlay2: AsRef<str>>(
|
||||
self,
|
||||
overlay_text: Overlay2,
|
||||
) -> PlotLines<'ui, 'p, Label, Overlay2> {
|
||||
PlotLines {
|
||||
label: self.label,
|
||||
values: self.values,
|
||||
values_offset: self.values_offset,
|
||||
overlay_text: Some(overlay_text),
|
||||
scale_min: self.scale_min,
|
||||
scale_max: self.scale_max,
|
||||
graph_size: self.graph_size,
|
||||
ui: self.ui,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale_min(mut self, scale_min: f32) -> Self {
|
||||
self.scale_min = scale_min;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn scale_max(mut self, scale_max: f32) -> Self {
|
||||
self.scale_max = scale_max;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
|
||||
self.graph_size = graph_size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) {
|
||||
unsafe {
|
||||
let (label, overlay) = self.ui.scratch_txt_with_opt(self.label, self.overlay_text);
|
||||
|
||||
sys::igPlotLines_FloatPtr(
|
||||
label,
|
||||
self.values.as_ptr() as *const c_float,
|
||||
self.values.len() as i32,
|
||||
self.values_offset as i32,
|
||||
overlay,
|
||||
self.scale_min,
|
||||
self.scale_max,
|
||||
self.graph_size.into(),
|
||||
mem::size_of::<f32>() as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
use std::ptr;
|
||||
|
||||
use crate::sys;
|
||||
use crate::window::WindowFlags;
|
||||
use crate::Ui;
|
||||
|
||||
/// Create a modal pop-up.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust,no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut imgui = Context::create();
|
||||
/// # let ui = imgui.frame();
|
||||
/// if ui.button(im_str!("Show modal")) {
|
||||
/// ui.open_popup(im_str!("modal"));
|
||||
/// }
|
||||
/// if let Some(_token) = PopupModal::new(im_str!("modal")).begin_popup(&ui) {
|
||||
/// ui.text("Content of my modal");
|
||||
/// if ui.button(im_str!("OK")) {
|
||||
/// ui.close_current_popup();
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub struct PopupModal<'p, Label> {
|
||||
label: Label,
|
||||
opened: Option<&'p mut bool>,
|
||||
flags: WindowFlags,
|
||||
}
|
||||
|
||||
impl<'p, Label: AsRef<str>> PopupModal<'p, Label> {
|
||||
pub fn new(label: Label) -> Self {
|
||||
PopupModal {
|
||||
label,
|
||||
opened: None,
|
||||
flags: WindowFlags::empty(),
|
||||
}
|
||||
}
|
||||
/// Pass a mutable boolean which will be updated to refer to the current
|
||||
/// "open" state of the modal.
|
||||
pub fn opened(mut self, opened: &'p mut bool) -> Self {
|
||||
self.opened = Some(opened);
|
||||
self
|
||||
}
|
||||
pub fn flags(mut self, flags: WindowFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
pub fn title_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_TITLE_BAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn resizable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_RESIZE, !value);
|
||||
self
|
||||
}
|
||||
pub fn movable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_MOVE, !value);
|
||||
self
|
||||
}
|
||||
pub fn scroll_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn scrollable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn collapsible(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_COLLAPSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn always_auto_resize(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
|
||||
self
|
||||
}
|
||||
pub fn save_settings(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value);
|
||||
self
|
||||
}
|
||||
pub fn inputs(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_INPUTS, !value);
|
||||
self
|
||||
}
|
||||
pub fn menu_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::MENU_BAR, value);
|
||||
self
|
||||
}
|
||||
pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn no_focus_on_appearing(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, value);
|
||||
self
|
||||
}
|
||||
pub fn no_bring_to_front_on_focus(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, value);
|
||||
self
|
||||
}
|
||||
pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_use_window_padding(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Consume and draw the PopupModal.
|
||||
/// Returns the result of the closure, if it is called.
|
||||
#[doc(alias = "BeginPopupModal")]
|
||||
pub fn build<T, F: FnOnce() -> T>(self, ui: &Ui<'_>, f: F) -> Option<T> {
|
||||
self.begin_popup(ui).map(|_popup| f())
|
||||
}
|
||||
|
||||
/// Consume and draw the PopupModal.
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`Ui::open_popup`]
|
||||
/// should be called *once* when you want to actual create the popup.
|
||||
#[doc(alias = "BeginPopupModal")]
|
||||
pub fn begin_popup<'ui>(self, ui: &Ui<'ui>) -> Option<PopupToken<'ui>> {
|
||||
let render = unsafe {
|
||||
sys::igBeginPopupModal(
|
||||
ui.scratch_txt(self.label),
|
||||
self.opened
|
||||
.map(|x| x as *mut bool)
|
||||
.unwrap_or(ptr::null_mut()),
|
||||
self.flags.bits() as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if render {
|
||||
Some(PopupToken::new(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: Popups
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Instructs ImGui to open a popup, which must be began with either [`begin_popup`](Self::begin_popup)
|
||||
/// or [`popup`](Self::popup). You also use this function to begin [PopupModal].
|
||||
///
|
||||
/// The confusing aspect to popups is that ImGui holds "control" over the popup fundamentally, so that ImGui
|
||||
/// can also force close a popup when a user clicks outside a popup. If you do not want users to be
|
||||
/// able to close a popup without selected an option, use [`PopupModal`].
|
||||
#[doc(alias = "OpenPopup")]
|
||||
pub fn open_popup(&self, str_id: impl AsRef<str>) {
|
||||
unsafe { sys::igOpenPopup_Str(self.scratch_txt(str_id), 0) };
|
||||
}
|
||||
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||
/// when you want to actual create the popup.
|
||||
#[doc(alias = "BeginPopup")]
|
||||
pub fn begin_popup(&self, str_id: impl AsRef<str>) -> Option<PopupToken<'_>> {
|
||||
let render = unsafe {
|
||||
sys::igBeginPopup(self.scratch_txt(str_id), WindowFlags::empty().bits() as i32)
|
||||
};
|
||||
|
||||
if render {
|
||||
Some(PopupToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||
/// when you want to actual create the popup.
|
||||
#[doc(alias = "BeginPopup")]
|
||||
pub fn popup<F>(&self, str_id: impl AsRef<str>, f: F)
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
if let Some(_t) = self.begin_popup(str_id) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a PopupModal directly.
|
||||
pub fn popup_modal<'p, Label: AsRef<str>>(&self, str_id: Label) -> PopupModal<'p, Label> {
|
||||
PopupModal::new(str_id)
|
||||
}
|
||||
|
||||
/// Close a popup. Should be called within the closure given as argument to
|
||||
/// [`Ui::popup`] or [`Ui::popup_modal`].
|
||||
#[doc(alias = "CloseCurrentPopup")]
|
||||
pub fn close_current_popup(&self) {
|
||||
unsafe { sys::igCloseCurrentPopup() };
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a popup token that can be ended with `end` or by dropping.
|
||||
pub struct PopupToken<'ui>;
|
||||
|
||||
/// Drops the popup token manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { sys::igEndPopup() }
|
||||
);
|
||||
@@ -1,285 +0,0 @@
|
||||
use std::slice;
|
||||
|
||||
use crate::internal::{RawCast, RawWrapper};
|
||||
use crate::render::renderer::TextureId;
|
||||
use crate::sys;
|
||||
|
||||
/// All draw data to render a Dear ImGui frame.
|
||||
#[repr(C)]
|
||||
pub struct DrawData {
|
||||
/// Only valid after render() is called and before the next new frame() is called.
|
||||
valid: bool,
|
||||
/// Number of DrawList to render.
|
||||
cmd_lists_count: i32,
|
||||
/// For convenience, sum of all draw list index buffer sizes.
|
||||
pub total_idx_count: i32,
|
||||
/// For convenience, sum of all draw list vertex buffer sizes.
|
||||
pub total_vtx_count: i32,
|
||||
// Array of DrawList.
|
||||
cmd_lists: *mut *mut DrawList,
|
||||
/// Upper-left position of the viewport to render.
|
||||
///
|
||||
/// (= upper-left corner of the orthogonal projection matrix to use)
|
||||
pub display_pos: [f32; 2],
|
||||
/// Size of the viewport to render.
|
||||
///
|
||||
/// (= display_pos + display_size == lower-right corner of the orthogonal matrix to use)
|
||||
pub display_size: [f32; 2],
|
||||
/// Amount of pixels for each unit of display_size.
|
||||
///
|
||||
/// Based on io.display_frame_buffer_scale. Typically [1.0, 1.0] on normal displays, and
|
||||
/// [2.0, 2.0] on Retina displays, but fractional values are also possible.
|
||||
pub framebuffer_scale: [f32; 2],
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImDrawData> for DrawData {}
|
||||
|
||||
impl DrawData {
|
||||
/// Returns an iterator over the draw lists included in the draw data.
|
||||
#[inline]
|
||||
pub fn draw_lists(&self) -> DrawListIterator<'_> {
|
||||
unsafe {
|
||||
DrawListIterator {
|
||||
iter: self.cmd_lists().iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Returns the number of draw lists included in the draw data.
|
||||
#[inline]
|
||||
pub fn draw_lists_count(&self) -> usize {
|
||||
use std::convert::TryInto;
|
||||
self.cmd_lists_count.try_into().unwrap()
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) unsafe fn cmd_lists(&self) -> &[*const DrawList] {
|
||||
slice::from_raw_parts(
|
||||
self.cmd_lists as *const *const DrawList,
|
||||
self.cmd_lists_count as usize,
|
||||
)
|
||||
}
|
||||
/// Converts all buffers from indexed to non-indexed, in case you cannot render indexed
|
||||
/// buffers.
|
||||
///
|
||||
/// **This is slow and most likely a waste of resources. Always prefer indexed rendering!**
|
||||
#[doc(alias = "DeIndexAllBuffers")]
|
||||
pub fn deindex_all_buffers(&mut self) {
|
||||
unsafe {
|
||||
sys::ImDrawData_DeIndexAllBuffers(self.raw_mut());
|
||||
}
|
||||
}
|
||||
/// Scales the clip rect of each draw command.
|
||||
///
|
||||
/// Can be used if your final output buffer is at a different scale than imgui-rs expects, or
|
||||
/// if there is a difference between your window resolution and framebuffer resolution.
|
||||
#[doc(alias = "ScaleClipRects")]
|
||||
pub fn scale_clip_rects(&mut self, fb_scale: [f32; 2]) {
|
||||
unsafe {
|
||||
sys::ImDrawData_ScaleClipRects(self.raw_mut(), fb_scale.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over draw lists
|
||||
pub struct DrawListIterator<'a> {
|
||||
iter: std::slice::Iter<'a, *const DrawList>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DrawListIterator<'a> {
|
||||
type Item = &'a DrawList;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|&ptr| unsafe { &*ptr })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_drawdata_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<DrawData>(),
|
||||
mem::size_of::<sys::ImDrawData>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<DrawData>(),
|
||||
mem::align_of::<sys::ImDrawData>()
|
||||
);
|
||||
use sys::ImDrawData;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(DrawData, $l),
|
||||
memoffset::offset_of!(ImDrawData, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(valid, Valid);
|
||||
assert_field_offset!(cmd_lists, CmdLists);
|
||||
assert_field_offset!(cmd_lists_count, CmdListsCount);
|
||||
assert_field_offset!(total_idx_count, TotalIdxCount);
|
||||
assert_field_offset!(total_vtx_count, TotalVtxCount);
|
||||
assert_field_offset!(display_pos, DisplayPos);
|
||||
assert_field_offset!(display_size, DisplaySize);
|
||||
assert_field_offset!(framebuffer_scale, FramebufferScale);
|
||||
}
|
||||
|
||||
/// Draw command list
|
||||
#[repr(transparent)]
|
||||
pub struct DrawList(sys::ImDrawList);
|
||||
|
||||
impl RawWrapper for DrawList {
|
||||
type Raw = sys::ImDrawList;
|
||||
#[inline]
|
||||
unsafe fn raw(&self) -> &sys::ImDrawList {
|
||||
&self.0
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn raw_mut(&mut self) -> &mut sys::ImDrawList {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawList {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
|
||||
slice::from_raw_parts(
|
||||
self.0.CmdBuffer.Data as *const sys::ImDrawCmd,
|
||||
self.0.CmdBuffer.Size as usize,
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
pub fn idx_buffer(&self) -> &[DrawIdx] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
self.0.IdxBuffer.Data as *const DrawIdx,
|
||||
self.0.IdxBuffer.Size as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn vtx_buffer(&self) -> &[DrawVert] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
self.0.VtxBuffer.Data as *const DrawVert,
|
||||
self.0.VtxBuffer.Size as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This is equivalent to `transmute(self.vtx_buffer())` with a little more
|
||||
/// checking, and thus inherits the safety considerations of `transmute`ing
|
||||
/// slices.
|
||||
pub unsafe fn transmute_vtx_buffer<VTy: Copy>(&self) -> &[VTy] {
|
||||
// these checks are constant and thus are removed from release builds
|
||||
assert_eq!(
|
||||
core::mem::size_of::<VTy>(),
|
||||
core::mem::size_of::<DrawVert>(),
|
||||
);
|
||||
assert!(core::mem::align_of::<VTy>() <= core::mem::align_of::<DrawVert>());
|
||||
slice::from_raw_parts(self.0.VtxBuffer.Data.cast(), self.0.VtxBuffer.Size as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn commands(&self) -> DrawCmdIterator<'_> {
|
||||
unsafe {
|
||||
DrawCmdIterator {
|
||||
iter: self.cmd_buffer().iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DrawCmdIterator<'a> {
|
||||
iter: std::slice::Iter<'a, sys::ImDrawCmd>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DrawCmdIterator<'a> {
|
||||
type Item = DrawCmd;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|cmd| {
|
||||
let cmd_params = DrawCmdParams {
|
||||
clip_rect: cmd.ClipRect.into(),
|
||||
texture_id: TextureId::from(cmd.TextureId),
|
||||
vtx_offset: cmd.VtxOffset as usize,
|
||||
idx_offset: cmd.IdxOffset as usize,
|
||||
};
|
||||
match cmd.UserCallback {
|
||||
Some(raw_callback) if raw_callback as usize == -1isize as usize => {
|
||||
DrawCmd::ResetRenderState
|
||||
}
|
||||
Some(raw_callback) => DrawCmd::RawCallback {
|
||||
callback: raw_callback,
|
||||
raw_cmd: cmd,
|
||||
},
|
||||
None => DrawCmd::Elements {
|
||||
count: cmd.ElemCount as usize,
|
||||
cmd_params,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A vertex index
|
||||
pub type DrawIdx = sys::ImDrawIdx;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct DrawCmdParams {
|
||||
/// left, up, right, down
|
||||
pub clip_rect: [f32; 4],
|
||||
pub texture_id: TextureId,
|
||||
pub vtx_offset: usize,
|
||||
pub idx_offset: usize,
|
||||
}
|
||||
|
||||
/// A draw command
|
||||
pub enum DrawCmd {
|
||||
Elements {
|
||||
/// The number of indices used for this draw command
|
||||
count: usize,
|
||||
cmd_params: DrawCmdParams,
|
||||
},
|
||||
ResetRenderState,
|
||||
RawCallback {
|
||||
callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
|
||||
raw_cmd: *const sys::ImDrawCmd,
|
||||
},
|
||||
}
|
||||
|
||||
/// A single vertex
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct DrawVert {
|
||||
pub pos: [f32; 2],
|
||||
pub uv: [f32; 2],
|
||||
pub col: [u8; 4],
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_drawvert_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<DrawVert>(),
|
||||
mem::size_of::<sys::ImDrawVert>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<DrawVert>(),
|
||||
mem::align_of::<sys::ImDrawVert>()
|
||||
);
|
||||
use sys::ImDrawVert;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(DrawVert, $l),
|
||||
memoffset::offset_of!(ImDrawVert, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(pos, pos);
|
||||
assert_field_offset!(uv, uv);
|
||||
assert_field_offset!(col, col);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod draw_data;
|
||||
pub mod renderer;
|
||||
@@ -1,95 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// An opaque texture identifier
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct TextureId(usize);
|
||||
|
||||
impl TextureId {
|
||||
/// Creates a new texture id with the given identifier.
|
||||
#[inline]
|
||||
pub const fn new(id: usize) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
|
||||
/// Returns the id of the TextureId.
|
||||
#[inline]
|
||||
pub const fn id(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for TextureId {
|
||||
#[inline]
|
||||
fn from(id: usize) -> Self {
|
||||
TextureId(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*const T> for TextureId {
|
||||
#[inline]
|
||||
fn from(ptr: *const T) -> Self {
|
||||
TextureId(ptr as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<*mut T> for TextureId {
|
||||
#[inline]
|
||||
fn from(ptr: *mut T) -> Self {
|
||||
TextureId(ptr as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_texture_id_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(
|
||||
mem::size_of::<TextureId>(),
|
||||
mem::size_of::<sys::ImTextureID>()
|
||||
);
|
||||
assert_eq!(
|
||||
mem::align_of::<TextureId>(),
|
||||
mem::align_of::<sys::ImTextureID>()
|
||||
);
|
||||
}
|
||||
|
||||
/// Generic texture mapping for use by renderers.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Textures<T> {
|
||||
textures: HashMap<usize, T>,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl<T> Textures<T> {
|
||||
// TODO: hasher like rustc_hash::FxHashMap or something would let this be
|
||||
// `const fn`
|
||||
pub fn new() -> Self {
|
||||
Textures {
|
||||
textures: HashMap::new(),
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, texture: T) -> TextureId {
|
||||
let id = self.next;
|
||||
self.textures.insert(id, texture);
|
||||
self.next += 1;
|
||||
TextureId::from(id)
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, id: TextureId, texture: T) -> Option<T> {
|
||||
self.textures.insert(id.0, texture)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: TextureId) -> Option<T> {
|
||||
self.textures.remove(&id.0)
|
||||
}
|
||||
|
||||
pub fn get(&self, id: TextureId) -> Option<&T> {
|
||||
self.textures.get(&id.0)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: TextureId) -> Option<&mut T> {
|
||||
self.textures.get_mut(&id.0)
|
||||
}
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::fonts::atlas::FontId;
|
||||
use crate::internal::RawCast;
|
||||
use crate::style::{StyleColor, StyleVar};
|
||||
use crate::sys;
|
||||
use crate::{Id, Ui};
|
||||
|
||||
/// # Parameter stacks (shared)
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Switches to the given font by pushing it to the font stack.
|
||||
///
|
||||
/// Returns a `FontStackToken` that must be popped by calling `.pop()`
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the font atlas does not contain the given font
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut ctx = Context::create();
|
||||
/// # let font_data_sources = [];
|
||||
/// // At initialization time
|
||||
/// let my_custom_font = ctx.fonts().add_font(&font_data_sources);
|
||||
/// # let ui = ctx.frame();
|
||||
/// // During UI construction
|
||||
/// let font = ui.push_font(my_custom_font);
|
||||
/// ui.text("I use the custom font!");
|
||||
/// font.pop();
|
||||
/// ```
|
||||
#[doc(alias = "PushFont")]
|
||||
pub fn push_font(&self, id: FontId) -> FontStackToken<'_> {
|
||||
let fonts = self.fonts();
|
||||
let font = fonts
|
||||
.get_font(id)
|
||||
.expect("Font atlas did not contain the given font");
|
||||
unsafe { sys::igPushFont(font.raw() as *const _ as *mut _) };
|
||||
FontStackToken::new(self)
|
||||
}
|
||||
/// Changes a style color by pushing a change to the color stack.
|
||||
///
|
||||
/// Returns a `ColorStackToken` that must be popped by calling `.pop()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut ctx = Context::create();
|
||||
/// # let ui = ctx.frame();
|
||||
/// const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
|
||||
/// let color = ui.push_style_color(StyleColor::Text, RED);
|
||||
/// ui.text("I'm red!");
|
||||
/// color.pop();
|
||||
/// ```
|
||||
#[doc(alias = "PushStyleColorVec4")]
|
||||
pub fn push_style_color(
|
||||
&self,
|
||||
style_color: StyleColor,
|
||||
color: [f32; 4],
|
||||
) -> ColorStackToken<'_> {
|
||||
unsafe { sys::igPushStyleColor_Vec4(style_color as i32, color.into()) };
|
||||
ColorStackToken::new(self)
|
||||
}
|
||||
|
||||
/// Changes style colors by pushing several changes to the color stack.
|
||||
///
|
||||
/// Returns a `ColorStackToken` that must be popped by calling `.pop()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut ctx = Context::create();
|
||||
/// # let ui = ctx.frame();
|
||||
/// const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
|
||||
/// const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
|
||||
/// let colors = ui.push_style_colors(&[
|
||||
/// (StyleColor::Text, RED),
|
||||
/// (StyleColor::TextDisabled, GREEN),
|
||||
/// ]);
|
||||
/// ui.text("I'm red!");
|
||||
/// ui.text_disabled("I'm green!");
|
||||
/// colors.pop(&ui);
|
||||
/// ```
|
||||
#[deprecated = "deprecated in 0.7.0. Use `push_style_color` multiple times for similar effect."]
|
||||
pub fn push_style_colors<'a, I>(&self, style_colors: I) -> MultiColorStackToken
|
||||
where
|
||||
I: IntoIterator<Item = &'a (StyleColor, [f32; 4])>,
|
||||
{
|
||||
let mut count = 0;
|
||||
for &(style_color, color) in style_colors {
|
||||
unsafe { sys::igPushStyleColor_Vec4(style_color as i32, color.into()) };
|
||||
count += 1;
|
||||
}
|
||||
MultiColorStackToken {
|
||||
count,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
}
|
||||
/// Changes a style variable by pushing a change to the style stack.
|
||||
///
|
||||
/// Returns a `StyleStackToken` that can be popped by calling `.end()`
|
||||
/// or by allowing to drop.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut ctx = Context::create();
|
||||
/// # let ui = ctx.frame();
|
||||
/// let style = ui.push_style_var(StyleVar::Alpha(0.2));
|
||||
/// ui.text("I'm transparent!");
|
||||
/// style.pop();
|
||||
/// ```
|
||||
#[doc(alias = "PushStyleVar")]
|
||||
pub fn push_style_var(&self, style_var: StyleVar) -> StyleStackToken<'_> {
|
||||
unsafe { push_style_var(style_var) };
|
||||
StyleStackToken::new(self)
|
||||
}
|
||||
/// Changes style variables by pushing several changes to the style stack.
|
||||
///
|
||||
/// Returns a `StyleStackToken` that must be popped by calling `.pop()`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use imgui::*;
|
||||
/// # let mut ctx = Context::create();
|
||||
/// # let ui = ctx.frame();
|
||||
/// let styles = ui.push_style_vars(&[
|
||||
/// StyleVar::Alpha(0.2),
|
||||
/// StyleVar::ItemSpacing([50.0, 50.0])
|
||||
/// ]);
|
||||
/// ui.text("We're transparent...");
|
||||
/// ui.text("...with large spacing as well");
|
||||
/// styles.pop(&ui);
|
||||
/// ```
|
||||
#[deprecated = "deprecated in 0.7.0. Use `push_style_var` multiple times for similar effect."]
|
||||
pub fn push_style_vars<'a, I>(&self, style_vars: I) -> MultiStyleStackToken
|
||||
where
|
||||
I: IntoIterator<Item = &'a StyleVar>,
|
||||
{
|
||||
let mut count = 0;
|
||||
for &style_var in style_vars {
|
||||
unsafe { push_style_var(style_var) };
|
||||
count += 1;
|
||||
}
|
||||
MultiStyleStackToken {
|
||||
count,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a font pushed to the font stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct FontStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the font stack.
|
||||
drop { sys::igPopFont() }
|
||||
);
|
||||
|
||||
impl FontStackToken<'_> {
|
||||
/// Pops a change from the font stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a color pushed to the color stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct ColorStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the color stack.
|
||||
drop { sys::igPopStyleColor(1) }
|
||||
);
|
||||
|
||||
impl ColorStackToken<'_> {
|
||||
/// Pops a change from the color stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks one or more changes pushed to the color stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct MultiColorStackToken {
|
||||
count: usize,
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl MultiColorStackToken {
|
||||
/// Pops changes from the color stack
|
||||
#[doc(alias = "PopStyleColor")]
|
||||
pub fn pop(mut self, _: &Ui<'_>) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igPopStyleColor(self.count as i32) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MultiColorStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A ColorStackToken was leaked. Did you call .pop()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a style pushed to the style stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct StyleStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the style stack.
|
||||
drop { sys::igPopStyleVar(1) }
|
||||
);
|
||||
|
||||
impl StyleStackToken<'_> {
|
||||
/// Pops a change from the style stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks one or more changes pushed to the style stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct MultiStyleStackToken {
|
||||
count: usize,
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl MultiStyleStackToken {
|
||||
/// Pops changes from the style stack
|
||||
#[doc(alias = "PopStyleVar")]
|
||||
pub fn pop(mut self, _: &Ui<'_>) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igPopStyleVar(self.count as i32) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MultiStyleStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A StyleStackToken was leaked. Did you call .pop()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn push_style_var(style_var: StyleVar) {
|
||||
use crate::style::StyleVar::*;
|
||||
use crate::sys::{igPushStyleVar_Float, igPushStyleVar_Vec2};
|
||||
match style_var {
|
||||
Alpha(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_Alpha as i32, v),
|
||||
WindowPadding(v) => igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowPadding as i32, v.into()),
|
||||
WindowRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_WindowRounding as i32, v),
|
||||
WindowBorderSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_WindowBorderSize as i32, v),
|
||||
WindowMinSize(v) => igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowMinSize as i32, v.into()),
|
||||
WindowTitleAlign(v) => {
|
||||
igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowTitleAlign as i32, v.into())
|
||||
}
|
||||
ChildRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_ChildRounding as i32, v),
|
||||
ChildBorderSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_ChildBorderSize as i32, v),
|
||||
PopupRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_PopupRounding as i32, v),
|
||||
PopupBorderSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_PopupBorderSize as i32, v),
|
||||
FramePadding(v) => igPushStyleVar_Vec2(sys::ImGuiStyleVar_FramePadding as i32, v.into()),
|
||||
FrameRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_FrameRounding as i32, v),
|
||||
FrameBorderSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_FrameBorderSize as i32, v),
|
||||
ItemSpacing(v) => igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemSpacing as i32, v.into()),
|
||||
ItemInnerSpacing(v) => {
|
||||
igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemInnerSpacing as i32, v.into())
|
||||
}
|
||||
IndentSpacing(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_IndentSpacing as i32, v),
|
||||
ScrollbarSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarSize as i32, v),
|
||||
ScrollbarRounding(v) => {
|
||||
igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarRounding as i32, v)
|
||||
}
|
||||
GrabMinSize(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_GrabMinSize as i32, v),
|
||||
GrabRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_GrabRounding as i32, v),
|
||||
TabRounding(v) => igPushStyleVar_Float(sys::ImGuiStyleVar_TabRounding as i32, v),
|
||||
ButtonTextAlign(v) => {
|
||||
igPushStyleVar_Vec2(sys::ImGuiStyleVar_ButtonTextAlign as i32, v.into())
|
||||
}
|
||||
SelectableTextAlign(v) => {
|
||||
igPushStyleVar_Vec2(sys::ImGuiStyleVar_SelectableTextAlign as i32, v.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Parameter stacks (current window)
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Changes the item width by pushing a change to the item width stack.
|
||||
///
|
||||
/// Returns an `ItemWidthStackToken` that may be popped by calling `.pop()`
|
||||
///
|
||||
/// - `> 0.0`: width is `item_width` pixels
|
||||
/// - `= 0.0`: default to ~2/3 of window width
|
||||
/// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to
|
||||
/// the right side)
|
||||
#[doc(alias = "PushItemWith")]
|
||||
pub fn push_item_width(&self, item_width: f32) -> ItemWidthStackToken {
|
||||
unsafe { sys::igPushItemWidth(item_width) };
|
||||
ItemWidthStackToken { _ctx: self.ctx }
|
||||
}
|
||||
/// Sets the width of the next item.
|
||||
///
|
||||
/// - `> 0.0`: width is `item_width` pixels
|
||||
/// - `= 0.0`: default to ~2/3 of window width
|
||||
/// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to
|
||||
/// the right side)
|
||||
#[doc(alias = "SetNextItemWidth")]
|
||||
pub fn set_next_item_width(&self, item_width: f32) {
|
||||
unsafe { sys::igSetNextItemWidth(item_width) };
|
||||
}
|
||||
/// Returns the width of the item given the pushed settings and the current cursor position.
|
||||
///
|
||||
/// This is NOT necessarily the width of last item.
|
||||
#[doc(alias = "CalcItemWidth")]
|
||||
pub fn calc_item_width(&self) -> f32 {
|
||||
unsafe { sys::igCalcItemWidth() }
|
||||
}
|
||||
|
||||
/// Changes the text wrapping position to the end of window (or column), which
|
||||
/// is generally the default.
|
||||
///
|
||||
/// This is the same as calling [push_text_wrap_pos_with_pos](Self::push_text_wrap_pos_with_pos)
|
||||
/// with `wrap_pos_x` set to 0.0.
|
||||
///
|
||||
/// Returns a `TextWrapPosStackToken` that may be popped by calling `.pop()`
|
||||
#[doc(alias = "PushTextWrapPos")]
|
||||
pub fn push_text_wrap_pos(&self) -> TextWrapPosStackToken {
|
||||
self.push_text_wrap_pos_with_pos(0.0)
|
||||
}
|
||||
|
||||
/// Changes the text wrapping position by pushing a change to the text wrapping position stack.
|
||||
///
|
||||
/// Returns a `TextWrapPosStackToken` that may be popped by calling `.pop()`
|
||||
///
|
||||
/// - `> 0.0`: wrap at `wrap_pos_x` position in window local space
|
||||
/// - `= 0.0`: wrap to end of window (or column)
|
||||
/// - `< 0.0`: no wrapping
|
||||
#[doc(alias = "PushTextWrapPos")]
|
||||
pub fn push_text_wrap_pos_with_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken {
|
||||
unsafe { sys::igPushTextWrapPos(wrap_pos_x) };
|
||||
TextWrapPosStackToken { _ctx: self.ctx }
|
||||
}
|
||||
|
||||
/// Changes an item flag by pushing a change to the item flag stack.
|
||||
///
|
||||
/// Returns a `ItemFlagsStackToken` that may be popped by calling `.pop()`
|
||||
#[doc(alias = "PushItemFlag")]
|
||||
pub fn push_item_flag(&self, item_flag: ItemFlag) -> ItemFlagsStackToken {
|
||||
use self::ItemFlag::*;
|
||||
match item_flag {
|
||||
AllowKeyboardFocus(v) => unsafe { sys::igPushAllowKeyboardFocus(v) },
|
||||
ButtonRepeat(v) => unsafe { sys::igPushButtonRepeat(v) },
|
||||
}
|
||||
ItemFlagsStackToken {
|
||||
discriminant: mem::discriminant(&item_flag),
|
||||
_ctx: self.ctx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary change in item flags
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ItemFlag {
|
||||
AllowKeyboardFocus(bool),
|
||||
ButtonRepeat(bool),
|
||||
}
|
||||
|
||||
pub struct ItemWidthStackToken {
|
||||
_ctx: *const Context,
|
||||
}
|
||||
|
||||
impl ItemWidthStackToken {
|
||||
/// Pops a change from the item width stack
|
||||
#[doc(alias = "PopItemWidth")]
|
||||
pub fn pop(mut self, _: &Ui<'_>) {
|
||||
self._ctx = ptr::null();
|
||||
unsafe { sys::igPopItemWidth() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a change pushed to the text wrap position stack
|
||||
pub struct TextWrapPosStackToken {
|
||||
_ctx: *const Context,
|
||||
}
|
||||
|
||||
impl TextWrapPosStackToken {
|
||||
/// Pops a change from the text wrap position stack
|
||||
#[doc(alias = "PopTextWrapPos")]
|
||||
pub fn pop(mut self, _: &Ui<'_>) {
|
||||
self._ctx = ptr::null();
|
||||
unsafe { sys::igPopTextWrapPos() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a change pushed to the item flags stack
|
||||
pub struct ItemFlagsStackToken {
|
||||
discriminant: mem::Discriminant<ItemFlag>,
|
||||
_ctx: *const Context,
|
||||
}
|
||||
|
||||
impl ItemFlagsStackToken {
|
||||
/// Pops a change from the item flags stack
|
||||
|
||||
#[doc(alias = "PopAllowKeyboardFocus", alias = "PopButtonRepeat")]
|
||||
pub fn pop(mut self, _: &Ui<'_>) {
|
||||
self._ctx = ptr::null();
|
||||
const ALLOW_KEYBOARD_FOCUS: ItemFlag = ItemFlag::AllowKeyboardFocus(true);
|
||||
const BUTTON_REPEAT: ItemFlag = ItemFlag::ButtonRepeat(true);
|
||||
|
||||
if self.discriminant == mem::discriminant(&ALLOW_KEYBOARD_FOCUS) {
|
||||
unsafe { sys::igPopAllowKeyboardFocus() };
|
||||
} else if self.discriminant == mem::discriminant(&BUTTON_REPEAT) {
|
||||
unsafe { sys::igPopButtonRepeat() };
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks an ID pushed to the ID stack that can be popped by calling `.pop()`
|
||||
/// or by dropping.
|
||||
pub struct IdStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the ID stack
|
||||
drop { sys::igPopID() }
|
||||
);
|
||||
|
||||
impl IdStackToken<'_> {
|
||||
/// Pops a change from the ID stack
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// # ID stack
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Pushes an identifier to the ID stack.
|
||||
///
|
||||
/// Returns an `IdStackToken` that can be popped by calling `.end()`
|
||||
/// or by dropping manually.
|
||||
#[doc(alias = "PushId")]
|
||||
pub fn push_id<'a, I: Into<Id<'a>>>(&self, id: I) -> IdStackToken<'ui> {
|
||||
let id = id.into();
|
||||
|
||||
unsafe {
|
||||
match id {
|
||||
Id::Int(i) => sys::igPushID_Int(i),
|
||||
Id::Str(s) => {
|
||||
let start = s.as_ptr() as *const c_char;
|
||||
let end = start.add(s.len());
|
||||
sys::igPushID_StrStr(start, end)
|
||||
}
|
||||
Id::Ptr(p) => sys::igPushID_Ptr(p as *const c_void),
|
||||
}
|
||||
}
|
||||
IdStackToken::new(self)
|
||||
}
|
||||
}
|
||||
@@ -1,544 +0,0 @@
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::ffi::CStr;
|
||||
use std::ops::{Deref, Index, RangeFull};
|
||||
use std::os::raw::c_char;
|
||||
use std::str;
|
||||
use std::{fmt, ptr};
|
||||
|
||||
/// this is the unsafe cell upon which we build our abstraction.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UiBuffer {
|
||||
buffer: Vec<u8>,
|
||||
max_len: usize,
|
||||
}
|
||||
|
||||
impl UiBuffer {
|
||||
/// Creates a new max buffer with the given length.
|
||||
pub fn new(max_len: usize) -> Self {
|
||||
Self {
|
||||
buffer: Vec::with_capacity(max_len),
|
||||
max_len,
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal method to push a single text to our scratch buffer.
|
||||
pub fn scratch_txt(&mut self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
|
||||
self.refresh_buffer();
|
||||
self.push(txt)
|
||||
}
|
||||
|
||||
/// Internal method to push an option text to our scratch buffer.
|
||||
pub fn scratch_txt_opt(&mut self, txt: Option<impl AsRef<str>>) -> *const sys::cty::c_char {
|
||||
match txt {
|
||||
Some(v) => self.scratch_txt(v),
|
||||
None => ptr::null(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scratch_txt_two(
|
||||
&mut self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: impl AsRef<str>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
self.refresh_buffer();
|
||||
(self.push(txt_0), self.push(txt_1))
|
||||
}
|
||||
|
||||
pub fn scratch_txt_with_opt(
|
||||
&mut self,
|
||||
txt_0: impl AsRef<str>,
|
||||
txt_1: Option<impl AsRef<str>>,
|
||||
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
|
||||
match txt_1 {
|
||||
Some(value) => self.scratch_txt_two(txt_0, value),
|
||||
None => (self.scratch_txt(txt_0), ptr::null()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to clear the buffer if it's over the maximum length allowed.
|
||||
pub fn refresh_buffer(&mut self) {
|
||||
if self.buffer.len() > self.max_len {
|
||||
self.buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a new scratch sheet text, which means it's not handling any clearing at all.
|
||||
pub fn push(&mut self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
|
||||
unsafe {
|
||||
let len = self.buffer.len();
|
||||
self.buffer.extend(txt.as_ref().as_bytes());
|
||||
self.buffer.push(b'\0');
|
||||
|
||||
self.buffer.as_ptr().add(len) as *const _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[deprecated = "all functions take AsRef<str> now -- use inline strings or `format` instead"]
|
||||
macro_rules! im_str {
|
||||
($e:literal $(,)?) => {{
|
||||
const __INPUT: &str = concat!($e, "\0");
|
||||
{
|
||||
// Trigger a compile error if there's an interior NUL character.
|
||||
const _CHECK_NUL: [(); 0] = [(); {
|
||||
let bytes = __INPUT.as_bytes();
|
||||
let mut i = 0;
|
||||
let mut found_nul = 0;
|
||||
while i < bytes.len() - 1 && found_nul == 0 {
|
||||
if bytes[i] == 0 {
|
||||
found_nul = 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
found_nul
|
||||
}];
|
||||
const RESULT: &'static $crate::ImStr = unsafe {
|
||||
$crate::__core::mem::transmute::<&'static [u8], &'static $crate::ImStr>(__INPUT.as_bytes())
|
||||
};
|
||||
RESULT
|
||||
}
|
||||
}};
|
||||
($e:literal, $($arg:tt)+) => ({
|
||||
$crate::ImString::new(format!($e, $($arg)*))
|
||||
});
|
||||
}
|
||||
|
||||
/// A UTF-8 encoded, growable, implicitly nul-terminated string.
|
||||
#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
|
||||
pub struct ImString(pub(crate) Vec<u8>);
|
||||
|
||||
impl ImString {
|
||||
/// Creates a new `ImString` from an existing string.
|
||||
pub fn new<T: Into<String>>(value: T) -> ImString {
|
||||
unsafe {
|
||||
let mut s = ImString::from_utf8_unchecked(value.into().into_bytes());
|
||||
s.refresh_len();
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new empty `ImString` with a particular capacity
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> ImString {
|
||||
let mut v = Vec::with_capacity(capacity + 1);
|
||||
v.push(b'\0');
|
||||
ImString(v)
|
||||
}
|
||||
|
||||
/// Converts a vector of bytes to a `ImString` without checking that the string contains valid
|
||||
/// UTF-8
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the vector contains valid UTF-8 and no null terminator.
|
||||
#[inline]
|
||||
pub unsafe fn from_utf8_unchecked(mut v: Vec<u8>) -> ImString {
|
||||
v.push(b'\0');
|
||||
ImString(v)
|
||||
}
|
||||
|
||||
/// Converts a vector of bytes to a `ImString` without checking that the string contains valid
|
||||
/// UTF-8
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the vector contains valid UTF-8 and a null terminator.
|
||||
#[inline]
|
||||
pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> ImString {
|
||||
ImString(v)
|
||||
}
|
||||
|
||||
/// Truncates this `ImString`, removing all contents
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
self.0.push(b'\0');
|
||||
}
|
||||
|
||||
/// Appends the given character to the end of this `ImString`
|
||||
#[inline]
|
||||
pub fn push(&mut self, ch: char) {
|
||||
let mut buf = [0; 4];
|
||||
self.push_str(ch.encode_utf8(&mut buf));
|
||||
}
|
||||
|
||||
/// Appends a given string slice to the end of this `ImString`
|
||||
#[inline]
|
||||
pub fn push_str(&mut self, string: &str) {
|
||||
self.0.pop();
|
||||
self.0.extend(string.bytes());
|
||||
self.0.push(b'\0');
|
||||
unsafe {
|
||||
self.refresh_len();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capacity of this `ImString` in bytes
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.0.capacity() - 1
|
||||
}
|
||||
|
||||
/// Returns the capacity of this `ImString` in bytes, including the implicit null byte
|
||||
#[inline]
|
||||
pub fn capacity_with_nul(&self) -> usize {
|
||||
self.0.capacity()
|
||||
}
|
||||
|
||||
/// Ensures that the capacity of this `ImString` is at least `additional` bytes larger than the
|
||||
/// current length.
|
||||
///
|
||||
/// The capacity may be increased by more than `additional` bytes.
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.0.reserve(additional);
|
||||
}
|
||||
|
||||
/// Ensures that the capacity of this `ImString` is at least `additional` bytes larger than the
|
||||
/// current length
|
||||
pub fn reserve_exact(&mut self, additional: usize) {
|
||||
self.0.reserve_exact(additional);
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the underlying buffer
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const c_char {
|
||||
self.0.as_ptr() as *const c_char
|
||||
}
|
||||
|
||||
/// Returns a raw mutable pointer to the underlying buffer.
|
||||
///
|
||||
/// If the underlying data is modified, `refresh_len` *must* be called afterwards.
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut c_char {
|
||||
self.0.as_mut_ptr() as *mut c_char
|
||||
}
|
||||
|
||||
/// Updates the underlying buffer length based on the current contents.
|
||||
///
|
||||
/// This function *must* be called if the underlying data is modified via a pointer
|
||||
/// obtained by `as_mut_ptr`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the this ImString contains valid UTF-8 and a null
|
||||
/// terminator.
|
||||
#[inline]
|
||||
pub unsafe fn refresh_len(&mut self) {
|
||||
let len = CStr::from_ptr(self.0.as_ptr() as *const c_char)
|
||||
.to_bytes_with_nul()
|
||||
.len();
|
||||
self.0.set_len(len);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for ImString {
|
||||
#[inline]
|
||||
fn default() -> ImString {
|
||||
ImString(vec![b'\0'])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ImString {
|
||||
#[inline]
|
||||
fn from(s: String) -> ImString {
|
||||
ImString::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ImString> for Cow<'a, ImStr> {
|
||||
#[inline]
|
||||
fn from(s: ImString) -> Cow<'a, ImStr> {
|
||||
Cow::Owned(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ImString> for Cow<'a, ImStr> {
|
||||
#[inline]
|
||||
fn from(s: &'a ImString) -> Cow<'a, ImStr> {
|
||||
Cow::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + AsRef<ImStr>> From<&'a T> for ImString {
|
||||
#[inline]
|
||||
fn from(s: &'a T) -> ImString {
|
||||
s.as_ref().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ImStr> for ImString {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &ImStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<ImStr> for ImString {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &ImStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for ImString {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<str> for ImString {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<RangeFull> for ImString {
|
||||
type Output = ImStr;
|
||||
#[inline]
|
||||
fn index(&self, _index: RangeFull) -> &ImStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ImString {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self.to_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ImString {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self.to_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ImString {
|
||||
type Target = ImStr;
|
||||
#[inline]
|
||||
fn deref(&self) -> &ImStr {
|
||||
// as_ptr() is used, because we need to look at the bytes to figure out the length
|
||||
// self.0.len() is incorrect, because there might be more than one nul byte in the end, or
|
||||
// some interior nulls in the data
|
||||
unsafe {
|
||||
&*(CStr::from_ptr(self.0.as_ptr() as *const c_char) as *const CStr as *const ImStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for ImString {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.push_str(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
self.push(c);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A UTF-8 encoded, implicitly nul-terminated string slice.
|
||||
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct ImStr([u8]);
|
||||
|
||||
impl<'a> Default for &'a ImStr {
|
||||
#[inline]
|
||||
fn default() -> &'a ImStr {
|
||||
static SLICE: &[u8] = &[0];
|
||||
unsafe { ImStr::from_utf8_with_nul_unchecked(SLICE) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ImStr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ImStr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self.to_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImStr {
|
||||
/// Wraps a raw UTF-8 encoded C string
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the pointer is not null and it points to a
|
||||
/// null-terminated UTF-8 string valid for the duration of the arbitrary lifetime 'a.
|
||||
#[inline]
|
||||
pub unsafe fn from_ptr_unchecked<'a>(ptr: *const c_char) -> &'a ImStr {
|
||||
ImStr::from_cstr_unchecked(CStr::from_ptr(ptr))
|
||||
}
|
||||
|
||||
/// Converts a slice of bytes to an imgui-rs string slice without checking for valid UTF-8 or
|
||||
/// null termination.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the slice contains valid UTF-8 and a null terminator.
|
||||
#[inline]
|
||||
pub unsafe fn from_utf8_with_nul_unchecked(bytes: &[u8]) -> &ImStr {
|
||||
&*(bytes as *const [u8] as *const ImStr)
|
||||
}
|
||||
|
||||
/// Converts a CStr reference to an imgui-rs string slice without checking for valid UTF-8.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee the CStr reference contains valid UTF-8.
|
||||
#[inline]
|
||||
pub unsafe fn from_cstr_unchecked(value: &CStr) -> &ImStr {
|
||||
&*(value.to_bytes_with_nul() as *const [u8] as *const ImStr)
|
||||
}
|
||||
|
||||
/// Converts an imgui-rs string slice to a raw pointer
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const c_char {
|
||||
self.0.as_ptr() as *const c_char
|
||||
}
|
||||
|
||||
/// Converts an imgui-rs string slice to a normal string slice
|
||||
#[inline]
|
||||
pub fn to_str(&self) -> &str {
|
||||
self.sanity_check();
|
||||
unsafe { str::from_utf8_unchecked(&self.0[..(self.0.len() - 1)]) }
|
||||
}
|
||||
|
||||
/// Returns true if the imgui-rs string slice is empty
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
debug_assert!(self.0.len() != 0);
|
||||
self.0.len() == 1
|
||||
}
|
||||
|
||||
// TODO: if this is too slow, avoid the UTF8 validation except if we'd
|
||||
// already be doing O(n) stuff.
|
||||
#[inline]
|
||||
fn sanity_check(&self) {
|
||||
debug_assert!(
|
||||
str::from_utf8(&self.0).is_ok()
|
||||
&& !self.0.is_empty()
|
||||
&& !self.0[..(self.0.len() - 1)].contains(&0u8)
|
||||
&& self.0[self.0.len() - 1] == 0,
|
||||
"bad ImStr: {:?}",
|
||||
&self.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<CStr> for ImStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &CStr {
|
||||
// Safety: our safety requirements are a superset of CStr's, so this is fine
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(&self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ImStr> for ImStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &ImStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for ImStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ImStr> for Cow<'a, ImStr> {
|
||||
#[inline]
|
||||
fn from(s: &'a ImStr) -> Cow<'a, ImStr> {
|
||||
Cow::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToOwned for ImStr {
|
||||
type Owned = ImString;
|
||||
#[inline]
|
||||
fn to_owned(&self) -> ImString {
|
||||
self.sanity_check();
|
||||
ImString(self.0.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imstring_constructors() {
|
||||
let s = ImString::new("test");
|
||||
assert_eq!(s.0, b"test\0");
|
||||
|
||||
let s = ImString::with_capacity(100);
|
||||
assert_eq!(s.0, b"\0");
|
||||
|
||||
let s = unsafe { ImString::from_utf8_unchecked(vec![b't', b'e', b's', b't']) };
|
||||
assert_eq!(s.0, b"test\0");
|
||||
|
||||
let s = unsafe { ImString::from_utf8_with_nul_unchecked(vec![b't', b'e', b's', b't', b'\0']) };
|
||||
assert_eq!(s.0, b"test\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imstring_operations() {
|
||||
let mut s = ImString::new("test");
|
||||
s.clear();
|
||||
assert_eq!(s.0, b"\0");
|
||||
s.push('z');
|
||||
assert_eq!(s.0, b"z\0");
|
||||
s.push('ä');
|
||||
assert_eq!(s.0, b"z\xc3\xa4\0");
|
||||
s.clear();
|
||||
s.push_str("imgui-rs");
|
||||
assert_eq!(s.0, b"imgui-rs\0");
|
||||
s.push_str("öä");
|
||||
assert_eq!(s.0, b"imgui-rs\xc3\xb6\xc3\xa4\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imstring_fmt_write() {
|
||||
use std::fmt::Write;
|
||||
let mut s = ImString::default();
|
||||
let _ = write!(s, "format {:02x}", 0x42);
|
||||
assert_eq!(s.0, b"format 42\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imstring_refresh_len() {
|
||||
let mut s = ImString::new("testing");
|
||||
unsafe {
|
||||
let mut ptr = s.as_mut_ptr() as *mut u8;
|
||||
ptr = ptr.wrapping_add(2);
|
||||
*ptr = b'z';
|
||||
ptr = ptr.wrapping_add(1);
|
||||
*ptr = b'\0';
|
||||
}
|
||||
assert_eq!(s.0, b"tez\0ing\0");
|
||||
unsafe { s.refresh_len() };
|
||||
assert_eq!(s.0, b"tez\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imstring_interior_nul() {
|
||||
let s = ImString::new("test\0ohno");
|
||||
assert_eq!(s.0, b"test\0");
|
||||
assert_eq!(s.to_str(), "test");
|
||||
assert!(!s.is_empty());
|
||||
|
||||
let s = ImString::new("\0ohno");
|
||||
assert_eq!(s.to_str(), "");
|
||||
assert!(s.is_empty());
|
||||
}
|
||||
@@ -1,506 +0,0 @@
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
use crate::internal::RawCast;
|
||||
use crate::sys;
|
||||
use crate::Direction;
|
||||
|
||||
/// User interface style/colors
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Style {
|
||||
/// Global alpha applies to everything
|
||||
pub alpha: f32,
|
||||
/// Additional alpha multiplier applied to disabled elements. Multiplies over current value of [`Style::alpha`].
|
||||
pub disabled_alpha: f32,
|
||||
/// Padding within a window
|
||||
pub window_padding: [f32; 2],
|
||||
/// Rounding radius of window corners.
|
||||
///
|
||||
/// Set to 0.0 to have rectangular windows.
|
||||
/// Large values tend to lead to a variety of artifacts and are not recommended.
|
||||
pub window_rounding: f32,
|
||||
/// Thickness of border around windows.
|
||||
///
|
||||
/// Generally set to 0.0 or 1.0 (other values are not well tested and cost more CPU/GPU).
|
||||
pub window_border_size: f32,
|
||||
/// Minimum window size
|
||||
pub window_min_size: [f32; 2],
|
||||
/// Alignment for title bar text.
|
||||
///
|
||||
/// Defaults to [0.5, 0.5] for left-aligned, vertically centered.
|
||||
pub window_title_align: [f32; 2],
|
||||
/// Side of the collapsing/docking button in the title bar (left/right).
|
||||
///
|
||||
/// Defaults to Direction::Left.
|
||||
pub window_menu_button_position: Direction,
|
||||
/// Rounding radius of child window corners.
|
||||
///
|
||||
/// Set to 0.0 to have rectangular child windows.
|
||||
pub child_rounding: f32,
|
||||
/// Thickness of border around child windows.
|
||||
///
|
||||
/// Generally set to 0.0 or 1.0 (other values are not well tested and cost more CPU/GPU).
|
||||
pub child_border_size: f32,
|
||||
/// Rounding radius of popup window corners.
|
||||
///
|
||||
/// Note that tooltip windows use `window_rounding` instead.
|
||||
pub popup_rounding: f32,
|
||||
/// Thickness of border around popup/tooltip windows.
|
||||
///
|
||||
/// Generally set to 0.0 or 1.0 (other values are not well tested and cost more CPU/GPU).
|
||||
pub popup_border_size: f32,
|
||||
/// Padding within a framed rectangle (used by most widgets)
|
||||
pub frame_padding: [f32; 2],
|
||||
/// Rounding radius of frame corners (used by most widgets).
|
||||
///
|
||||
/// Set to 0.0 to have rectangular frames.
|
||||
pub frame_rounding: f32,
|
||||
/// Thickness of border around frames.
|
||||
///
|
||||
/// Generally set to 0.0 or 1.0 (other values are not well tested and cost more CPU/GPU).
|
||||
pub frame_border_size: f32,
|
||||
/// Horizontal and vertical spacing between widgets/lines
|
||||
pub item_spacing: [f32; 2],
|
||||
/// Horizontal and vertical spacing between elements of a composed widget (e.g. a slider and
|
||||
/// its label)
|
||||
pub item_inner_spacing: [f32; 2],
|
||||
/// Padding within a table cell.
|
||||
pub cell_padding: [f32; 2],
|
||||
/// Expand reactive bounding box for touch-based system where touch position is not accurate
|
||||
/// enough.
|
||||
///
|
||||
/// Unfortunately we don't sort widgets so priority on overlap will always be given to the
|
||||
/// first widget, so don't grow this too much.
|
||||
pub touch_extra_padding: [f32; 2],
|
||||
/// Horizontal indentation when e.g. entering a tree node.
|
||||
///
|
||||
/// Generally equal to (font size + horizontal frame padding * 2).
|
||||
pub indent_spacing: f32,
|
||||
/// Minimum horizontal spacing between two columns
|
||||
pub columns_min_spacing: f32,
|
||||
/// Width of the vertical scrollbar, height of the horizontal scrollbar
|
||||
pub scrollbar_size: f32,
|
||||
/// Rounding radius of scrollbar grab corners
|
||||
pub scrollbar_rounding: f32,
|
||||
/// Minimum width/height of a grab box for slider/scrollbar
|
||||
pub grab_min_size: f32,
|
||||
/// Rounding radius of grab corners.
|
||||
///
|
||||
/// Set to 0.0 to have rectangular slider grabs.
|
||||
pub grab_rounding: f32,
|
||||
/// The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero
|
||||
pub log_slider_deadzone: f32,
|
||||
/// Rounding radius of upper corners of tabs.
|
||||
///
|
||||
/// Set to 0.0 to have rectangular tabs.
|
||||
pub tab_rounding: f32,
|
||||
/// Thickness of border around tabs
|
||||
pub tab_border_size: f32,
|
||||
/// Minimum width for close button to appear on an unselected tab when hovered.
|
||||
///
|
||||
/// `= 0.0`: always show when hovering
|
||||
/// `= f32::MAX`: never show close button unless selected
|
||||
pub tab_min_width_for_close_button: f32,
|
||||
/// Side of the color button position color editor widgets (left/right).
|
||||
pub color_button_position: Direction,
|
||||
/// Alignment of button text when button is larger than text.
|
||||
///
|
||||
/// Defaults to [0.5, 0.5] (centered).
|
||||
pub button_text_align: [f32; 2],
|
||||
/// Alignment of selectable text when selectable is larger than text.
|
||||
///
|
||||
/// Defaults to [0.5, 0.5] (top-left aligned).
|
||||
pub selectable_text_align: [f32; 2],
|
||||
/// Window positions are clamped to be visible within the display area or monitors by at least
|
||||
/// this amount.
|
||||
///
|
||||
/// Only applies to regular windows.
|
||||
pub display_window_padding: [f32; 2],
|
||||
/// If you cannot see the edges of your screen (e.g. on a TV), increase the safe area padding.
|
||||
///
|
||||
/// Also applies to popups/tooltips in addition to regular windows.
|
||||
pub display_safe_area_padding: [f32; 2],
|
||||
/// Scale software-rendered mouse cursor.
|
||||
///
|
||||
/// May be removed later.
|
||||
pub mouse_cursor_scale: f32,
|
||||
/// Enable anti-aliased lines/borders.
|
||||
///
|
||||
/// Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame.
|
||||
pub anti_aliased_lines: bool,
|
||||
/// Enable anti-aliased lines/borders using textures where possible.
|
||||
///
|
||||
/// Require back-end to render with bilinear filtering. Latched at the beginning of the frame.
|
||||
pub anti_aliased_lines_use_tex: bool,
|
||||
/// Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.).
|
||||
///
|
||||
/// Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame.
|
||||
pub anti_aliased_fill: bool,
|
||||
/// Tessellation tolerance when using path_bezier_curve_to without a specific number of
|
||||
/// segments.
|
||||
///
|
||||
/// Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce
|
||||
/// quality.
|
||||
pub curve_tessellation_tol: f32,
|
||||
/// Maximum error (in pixels) allowed when drawing circles or rounded corner rectangles with no
|
||||
/// explicit segment count specified.
|
||||
///
|
||||
/// Decrease for higher quality but more geometry.
|
||||
pub circle_tesselation_max_error: f32,
|
||||
/// Style colors.
|
||||
pub colors: [[f32; 4]; StyleColor::COUNT],
|
||||
}
|
||||
|
||||
unsafe impl RawCast<sys::ImGuiStyle> for Style {}
|
||||
|
||||
impl Style {
|
||||
/// Scales all sizes in the style
|
||||
#[doc(alias = "ScaleAllSizes")]
|
||||
pub fn scale_all_sizes(&mut self, scale_factor: f32) {
|
||||
unsafe {
|
||||
sys::ImGuiStyle_ScaleAllSizes(self.raw_mut(), scale_factor);
|
||||
}
|
||||
}
|
||||
/// Replaces current colors with classic Dear ImGui style
|
||||
#[doc(alias = "StyleColors", alias = "StyleColorsClassic")]
|
||||
pub fn use_classic_colors(&mut self) -> &mut Self {
|
||||
unsafe {
|
||||
sys::igStyleColorsClassic(self.raw_mut());
|
||||
}
|
||||
self
|
||||
}
|
||||
/// Replaces current colors with a new, recommended style
|
||||
#[doc(alias = "StyleColors", alias = "StyleColorsDark")]
|
||||
pub fn use_dark_colors(&mut self) -> &mut Self {
|
||||
unsafe {
|
||||
sys::igStyleColorsDark(self.raw_mut());
|
||||
}
|
||||
self
|
||||
}
|
||||
/// Replaces current colors with a light style. Best used with borders and a custom, thicker
|
||||
/// font
|
||||
#[doc(alias = "StyleColors", alias = "StyleColorsLight")]
|
||||
pub fn use_light_colors(&mut self) -> &mut Self {
|
||||
unsafe {
|
||||
sys::igStyleColorsLight(self.raw_mut());
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<StyleColor> for Style {
|
||||
type Output = [f32; 4];
|
||||
#[inline]
|
||||
fn index(&self, index: StyleColor) -> &[f32; 4] {
|
||||
&self.colors[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<StyleColor> for Style {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: StyleColor) -> &mut [f32; 4] {
|
||||
&mut self.colors[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
/// A color identifier for styling
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum StyleColor {
|
||||
Text = sys::ImGuiCol_Text,
|
||||
TextDisabled = sys::ImGuiCol_TextDisabled,
|
||||
/// Background of normal windows
|
||||
WindowBg = sys::ImGuiCol_WindowBg,
|
||||
/// Background of child windows
|
||||
ChildBg = sys::ImGuiCol_ChildBg,
|
||||
/// Background of popups, menus, tooltips windows
|
||||
PopupBg = sys::ImGuiCol_PopupBg,
|
||||
Border = sys::ImGuiCol_Border,
|
||||
BorderShadow = sys::ImGuiCol_BorderShadow,
|
||||
/// Background of checkbox, radio button, plot, slider, text input
|
||||
FrameBg = sys::ImGuiCol_FrameBg,
|
||||
FrameBgHovered = sys::ImGuiCol_FrameBgHovered,
|
||||
FrameBgActive = sys::ImGuiCol_FrameBgActive,
|
||||
TitleBg = sys::ImGuiCol_TitleBg,
|
||||
TitleBgActive = sys::ImGuiCol_TitleBgActive,
|
||||
TitleBgCollapsed = sys::ImGuiCol_TitleBgCollapsed,
|
||||
MenuBarBg = sys::ImGuiCol_MenuBarBg,
|
||||
ScrollbarBg = sys::ImGuiCol_ScrollbarBg,
|
||||
ScrollbarGrab = sys::ImGuiCol_ScrollbarGrab,
|
||||
ScrollbarGrabHovered = sys::ImGuiCol_ScrollbarGrabHovered,
|
||||
ScrollbarGrabActive = sys::ImGuiCol_ScrollbarGrabActive,
|
||||
CheckMark = sys::ImGuiCol_CheckMark,
|
||||
SliderGrab = sys::ImGuiCol_SliderGrab,
|
||||
SliderGrabActive = sys::ImGuiCol_SliderGrabActive,
|
||||
Button = sys::ImGuiCol_Button,
|
||||
ButtonHovered = sys::ImGuiCol_ButtonHovered,
|
||||
ButtonActive = sys::ImGuiCol_ButtonActive,
|
||||
Header = sys::ImGuiCol_Header,
|
||||
HeaderHovered = sys::ImGuiCol_HeaderHovered,
|
||||
HeaderActive = sys::ImGuiCol_HeaderActive,
|
||||
Separator = sys::ImGuiCol_Separator,
|
||||
SeparatorHovered = sys::ImGuiCol_SeparatorHovered,
|
||||
SeparatorActive = sys::ImGuiCol_SeparatorActive,
|
||||
ResizeGrip = sys::ImGuiCol_ResizeGrip,
|
||||
ResizeGripHovered = sys::ImGuiCol_ResizeGripHovered,
|
||||
ResizeGripActive = sys::ImGuiCol_ResizeGripActive,
|
||||
Tab = sys::ImGuiCol_Tab,
|
||||
TabHovered = sys::ImGuiCol_TabHovered,
|
||||
TabActive = sys::ImGuiCol_TabActive,
|
||||
TabUnfocused = sys::ImGuiCol_TabUnfocused,
|
||||
TabUnfocusedActive = sys::ImGuiCol_TabUnfocusedActive,
|
||||
PlotLines = sys::ImGuiCol_PlotLines,
|
||||
PlotLinesHovered = sys::ImGuiCol_PlotLinesHovered,
|
||||
PlotHistogram = sys::ImGuiCol_PlotHistogram,
|
||||
PlotHistogramHovered = sys::ImGuiCol_PlotHistogramHovered,
|
||||
TableHeaderBg = sys::ImGuiCol_TableHeaderBg,
|
||||
TableBorderStrong = sys::ImGuiCol_TableBorderStrong,
|
||||
TableBorderLight = sys::ImGuiCol_TableBorderLight,
|
||||
TableRowBg = sys::ImGuiCol_TableRowBg,
|
||||
TableRowBgAlt = sys::ImGuiCol_TableRowBgAlt,
|
||||
TextSelectedBg = sys::ImGuiCol_TextSelectedBg,
|
||||
DragDropTarget = sys::ImGuiCol_DragDropTarget,
|
||||
/// Gamepad/keyboard: current highlighted item
|
||||
NavHighlight = sys::ImGuiCol_NavHighlight,
|
||||
/// Highlight window when using CTRL+TAB
|
||||
NavWindowingHighlight = sys::ImGuiCol_NavWindowingHighlight,
|
||||
/// Darken/colorize entire screen behind the CTRL+TAB window list, when active
|
||||
NavWindowingDimBg = sys::ImGuiCol_NavWindowingDimBg,
|
||||
/// Darken/colorize entire screen behind a modal window, when one is active
|
||||
ModalWindowDimBg = sys::ImGuiCol_ModalWindowDimBg,
|
||||
}
|
||||
|
||||
impl StyleColor {
|
||||
/// All possible `StyleColor` variants
|
||||
pub const VARIANTS: [StyleColor; StyleColor::COUNT] = [
|
||||
StyleColor::Text,
|
||||
StyleColor::TextDisabled,
|
||||
StyleColor::WindowBg,
|
||||
StyleColor::ChildBg,
|
||||
StyleColor::PopupBg,
|
||||
StyleColor::Border,
|
||||
StyleColor::BorderShadow,
|
||||
StyleColor::FrameBg,
|
||||
StyleColor::FrameBgHovered,
|
||||
StyleColor::FrameBgActive,
|
||||
StyleColor::TitleBg,
|
||||
StyleColor::TitleBgActive,
|
||||
StyleColor::TitleBgCollapsed,
|
||||
StyleColor::MenuBarBg,
|
||||
StyleColor::ScrollbarBg,
|
||||
StyleColor::ScrollbarGrab,
|
||||
StyleColor::ScrollbarGrabHovered,
|
||||
StyleColor::ScrollbarGrabActive,
|
||||
StyleColor::CheckMark,
|
||||
StyleColor::SliderGrab,
|
||||
StyleColor::SliderGrabActive,
|
||||
StyleColor::Button,
|
||||
StyleColor::ButtonHovered,
|
||||
StyleColor::ButtonActive,
|
||||
StyleColor::Header,
|
||||
StyleColor::HeaderHovered,
|
||||
StyleColor::HeaderActive,
|
||||
StyleColor::Separator,
|
||||
StyleColor::SeparatorHovered,
|
||||
StyleColor::SeparatorActive,
|
||||
StyleColor::ResizeGrip,
|
||||
StyleColor::ResizeGripHovered,
|
||||
StyleColor::ResizeGripActive,
|
||||
StyleColor::Tab,
|
||||
StyleColor::TabHovered,
|
||||
StyleColor::TabActive,
|
||||
StyleColor::TabUnfocused,
|
||||
StyleColor::TabUnfocusedActive,
|
||||
StyleColor::PlotLines,
|
||||
StyleColor::PlotLinesHovered,
|
||||
StyleColor::PlotHistogram,
|
||||
StyleColor::PlotHistogramHovered,
|
||||
StyleColor::TableHeaderBg,
|
||||
StyleColor::TableBorderStrong,
|
||||
StyleColor::TableBorderLight,
|
||||
StyleColor::TableRowBg,
|
||||
StyleColor::TableRowBgAlt,
|
||||
StyleColor::TextSelectedBg,
|
||||
StyleColor::DragDropTarget,
|
||||
StyleColor::NavHighlight,
|
||||
StyleColor::NavWindowingHighlight,
|
||||
StyleColor::NavWindowingDimBg,
|
||||
StyleColor::ModalWindowDimBg,
|
||||
];
|
||||
/// Total count of `StyleColor` variants
|
||||
pub const COUNT: usize = sys::ImGuiCol_COUNT as usize;
|
||||
}
|
||||
|
||||
/// A temporary change in user interface style
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum StyleVar {
|
||||
/// Global alpha applies to everything
|
||||
Alpha(f32),
|
||||
/// Padding within a window
|
||||
WindowPadding([f32; 2]),
|
||||
/// Rounding radius of window corners
|
||||
WindowRounding(f32),
|
||||
/// Thickness of border around windows
|
||||
WindowBorderSize(f32),
|
||||
/// Minimum window size
|
||||
WindowMinSize([f32; 2]),
|
||||
/// Alignment for title bar text
|
||||
WindowTitleAlign([f32; 2]),
|
||||
/// Rounding radius of child window corners
|
||||
ChildRounding(f32),
|
||||
/// Thickness of border around child windows
|
||||
ChildBorderSize(f32),
|
||||
/// Rounding radius of popup window corners
|
||||
PopupRounding(f32),
|
||||
/// Thickness of border around popup/tooltip windows
|
||||
PopupBorderSize(f32),
|
||||
/// Padding within a framed rectangle (used by most widgets)
|
||||
FramePadding([f32; 2]),
|
||||
/// Rounding radius of frame corners (used by most widgets)
|
||||
FrameRounding(f32),
|
||||
/// Thickness of border around frames
|
||||
FrameBorderSize(f32),
|
||||
/// Horizontal and vertical spacing between widgets/lines
|
||||
ItemSpacing([f32; 2]),
|
||||
/// Horizontal and vertical spacing between elements of a composed widget (e.g. a slider and
|
||||
/// its label)
|
||||
ItemInnerSpacing([f32; 2]),
|
||||
/// Horizontal indentation when e.g. entering a tree node
|
||||
IndentSpacing(f32),
|
||||
/// Width of the vertical scrollbar, height of the horizontal scrollbar
|
||||
ScrollbarSize(f32),
|
||||
/// Rounding radius of scrollbar grab corners
|
||||
ScrollbarRounding(f32),
|
||||
/// Minimum width/height of a grab box for slider/scrollbar
|
||||
GrabMinSize(f32),
|
||||
/// Rounding radius of grab corners
|
||||
GrabRounding(f32),
|
||||
/// Rounding radius of upper corners of tabs
|
||||
TabRounding(f32),
|
||||
/// Alignment of button text when button is larger than text
|
||||
ButtonTextAlign([f32; 2]),
|
||||
/// Alignment of selectable text when selectable is larger than text
|
||||
SelectableTextAlign([f32; 2]),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_style_scaling() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
let style = ctx.style_mut();
|
||||
style.window_padding = [1.0, 2.0];
|
||||
style.window_rounding = 3.0;
|
||||
style.window_min_size = [4.0, 5.0];
|
||||
style.child_rounding = 6.0;
|
||||
style.popup_rounding = 7.0;
|
||||
style.frame_padding = [8.0, 9.0];
|
||||
style.frame_rounding = 10.0;
|
||||
style.item_spacing = [11.0, 12.0];
|
||||
style.item_inner_spacing = [13.0, 14.0];
|
||||
style.touch_extra_padding = [15.0, 16.0];
|
||||
style.indent_spacing = 17.0;
|
||||
style.columns_min_spacing = 18.0;
|
||||
style.scrollbar_size = 19.0;
|
||||
style.scrollbar_rounding = 20.0;
|
||||
style.grab_min_size = 21.0;
|
||||
style.grab_rounding = 22.0;
|
||||
style.log_slider_deadzone = 29.0;
|
||||
style.tab_rounding = 23.0;
|
||||
style.display_window_padding = [24.0, 25.0];
|
||||
style.display_safe_area_padding = [26.0, 27.0];
|
||||
style.mouse_cursor_scale = 28.0;
|
||||
style.scale_all_sizes(2.0);
|
||||
assert_eq!(style.window_padding, [2.0, 4.0]);
|
||||
assert_eq!(style.window_rounding, 6.0);
|
||||
assert_eq!(style.window_min_size, [8.0, 10.0]);
|
||||
assert_eq!(style.child_rounding, 12.0);
|
||||
assert_eq!(style.popup_rounding, 14.0);
|
||||
assert_eq!(style.frame_padding, [16.0, 18.0]);
|
||||
assert_eq!(style.frame_rounding, 20.0);
|
||||
assert_eq!(style.item_spacing, [22.0, 24.0]);
|
||||
assert_eq!(style.item_inner_spacing, [26.0, 28.0]);
|
||||
assert_eq!(style.touch_extra_padding, [30.0, 32.0]);
|
||||
assert_eq!(style.indent_spacing, 34.0);
|
||||
assert_eq!(style.columns_min_spacing, 36.0);
|
||||
assert_eq!(style.scrollbar_size, 38.0);
|
||||
assert_eq!(style.scrollbar_rounding, 40.0);
|
||||
assert_eq!(style.grab_min_size, 42.0);
|
||||
assert_eq!(style.grab_rounding, 44.0);
|
||||
assert_eq!(style.log_slider_deadzone, 58.0);
|
||||
assert_eq!(style.tab_rounding, 46.0);
|
||||
assert_eq!(style.display_window_padding, [48.0, 50.0]);
|
||||
assert_eq!(style.display_safe_area_padding, [52.0, 54.0]);
|
||||
assert_eq!(style.mouse_cursor_scale, 56.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_style_color_indexing() {
|
||||
let (_guard, mut ctx) = crate::test::test_ctx();
|
||||
let style = ctx.style_mut();
|
||||
let value = [0.1, 0.2, 0.3, 1.0];
|
||||
style[StyleColor::Tab] = value;
|
||||
assert_eq!(style[StyleColor::Tab], value);
|
||||
assert_eq!(style.colors[StyleColor::Tab as usize], value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn test_style_memory_layout() {
|
||||
use std::mem;
|
||||
assert_eq!(mem::size_of::<Style>(), mem::size_of::<sys::ImGuiStyle>());
|
||||
assert_eq!(mem::align_of::<Style>(), mem::align_of::<sys::ImGuiStyle>());
|
||||
use sys::ImGuiStyle;
|
||||
macro_rules! assert_field_offset {
|
||||
($l:ident, $r:ident) => {
|
||||
assert_eq!(
|
||||
memoffset::offset_of!(Style, $l),
|
||||
memoffset::offset_of!(ImGuiStyle, $r)
|
||||
);
|
||||
};
|
||||
}
|
||||
assert_field_offset!(alpha, Alpha);
|
||||
assert_field_offset!(window_padding, WindowPadding);
|
||||
assert_field_offset!(window_rounding, WindowRounding);
|
||||
assert_field_offset!(window_border_size, WindowBorderSize);
|
||||
assert_field_offset!(window_min_size, WindowMinSize);
|
||||
assert_field_offset!(window_title_align, WindowTitleAlign);
|
||||
assert_field_offset!(window_menu_button_position, WindowMenuButtonPosition);
|
||||
assert_field_offset!(child_rounding, ChildRounding);
|
||||
assert_field_offset!(child_border_size, ChildBorderSize);
|
||||
assert_field_offset!(popup_rounding, PopupRounding);
|
||||
assert_field_offset!(popup_border_size, PopupBorderSize);
|
||||
assert_field_offset!(frame_padding, FramePadding);
|
||||
assert_field_offset!(frame_rounding, FrameRounding);
|
||||
assert_field_offset!(frame_border_size, FrameBorderSize);
|
||||
assert_field_offset!(item_spacing, ItemSpacing);
|
||||
assert_field_offset!(item_inner_spacing, ItemInnerSpacing);
|
||||
assert_field_offset!(touch_extra_padding, TouchExtraPadding);
|
||||
assert_field_offset!(indent_spacing, IndentSpacing);
|
||||
assert_field_offset!(columns_min_spacing, ColumnsMinSpacing);
|
||||
assert_field_offset!(scrollbar_size, ScrollbarSize);
|
||||
assert_field_offset!(scrollbar_rounding, ScrollbarRounding);
|
||||
assert_field_offset!(grab_min_size, GrabMinSize);
|
||||
assert_field_offset!(grab_rounding, GrabRounding);
|
||||
assert_field_offset!(log_slider_deadzone, LogSliderDeadzone);
|
||||
assert_field_offset!(tab_rounding, TabRounding);
|
||||
assert_field_offset!(tab_border_size, TabBorderSize);
|
||||
assert_field_offset!(tab_min_width_for_close_button, TabMinWidthForCloseButton);
|
||||
assert_field_offset!(color_button_position, ColorButtonPosition);
|
||||
assert_field_offset!(button_text_align, ButtonTextAlign);
|
||||
assert_field_offset!(selectable_text_align, SelectableTextAlign);
|
||||
assert_field_offset!(display_window_padding, DisplayWindowPadding);
|
||||
assert_field_offset!(display_safe_area_padding, DisplaySafeAreaPadding);
|
||||
assert_field_offset!(mouse_cursor_scale, MouseCursorScale);
|
||||
assert_field_offset!(anti_aliased_lines, AntiAliasedLines);
|
||||
assert_field_offset!(anti_aliased_lines_use_tex, AntiAliasedLinesUseTex);
|
||||
assert_field_offset!(anti_aliased_fill, AntiAliasedFill);
|
||||
assert_field_offset!(curve_tessellation_tol, CurveTessellationTol);
|
||||
assert_field_offset!(circle_tesselation_max_error, CircleTessellationMaxError);
|
||||
assert_field_offset!(colors, Colors);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_style_color_variants() {
|
||||
for (idx, &value) in StyleColor::VARIANTS.iter().enumerate() {
|
||||
assert_eq!(idx, value as usize);
|
||||
}
|
||||
}
|
||||
@@ -1,879 +0,0 @@
|
||||
use std::ffi::CStr;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::sys;
|
||||
use crate::{Id, ImColor32, Ui};
|
||||
|
||||
bitflags! {
|
||||
/// Flags passed to `begin_table` methods.
|
||||
///
|
||||
/// Important! Sizing policies have complex and subtle side effects, more so than you would expect.
|
||||
/// Read comments/demos carefully + experiment with live demos to get acquainted with them.
|
||||
/// - The DEFAULT sizing policies are:
|
||||
/// - Default to [SizingFixedFit] if [ScrollX] is on, or if host window has (WindowFlags::AlwaysAutoResize)[crate::WindowFlags::AlwaysAutoResize].
|
||||
/// - Default to [SizingStretchSame] if [ScrollX] is off.
|
||||
/// - When [ScrollX] is off:
|
||||
/// - Table defaults to [SizingStretchSame] -> all Columns defaults to [TableColumnFlags::WidthStretch] with same weight.
|
||||
/// - Columns sizing policy allowed: [Stretch] (default), [Fixed]/Auto.
|
||||
/// - [Fixed] Columns will generally obtain their requested width (unless the table cannot fit them all).
|
||||
/// - [Stretch] Columns will share the remaining width.
|
||||
/// - Mixed [Fixed]/[Stretch] columns is possible but has various side-effects on resizing behaviors.
|
||||
/// The typical use of mixing sizing policies is: any number of LEADING [Fixed] columns, followed by one or two TRAILING [Stretch] columns.
|
||||
/// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing).
|
||||
/// - When [ScrollX] is on:
|
||||
/// - Table defaults to [SizingFixedFit] -> all Columns defaults to [TableColumnFlags::WidthFixed]
|
||||
/// - Columns sizing policy allowed: [Fixed]/Auto mostly.
|
||||
/// - [Fixed] Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed.
|
||||
/// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop.
|
||||
/// - Using [Stretch] columns OFTEN DOES NOT MAKE SENSE if [ScrollX] is on, UNLESS you have specified a value for `inner_width` in BeginTable().
|
||||
/// If you specify a value for `inner_width` then effectively the scrolling space is known and [Stretch] or mixed [Fixed]/[Stretch] columns become meaningful again.
|
||||
/// - Read on documentation at the top of imgui_tables.cpp for more details.
|
||||
#[repr(transparent)]
|
||||
pub struct TableFlags: u32 {
|
||||
// Features
|
||||
|
||||
/// Enable resizing columns.
|
||||
const RESIZABLE = sys::ImGuiTableFlags_Resizable;
|
||||
/// Enable reordering columns in header row, though you must set up a header row
|
||||
/// with `begin_table_header` or `table_setup_column`.
|
||||
const REORDERABLE =sys::ImGuiTableFlags_Reorderable;
|
||||
/// Enable hiding/disabling columns in context menu.
|
||||
const HIDEABLE = sys::ImGuiTableFlags_Hideable;
|
||||
/// Enable sorting. See `table_get_sort_specs` to object sort specs. Also see [SortMulti]
|
||||
/// and [SortTristate].
|
||||
const SORTABLE = sys::ImGuiTableFlags_Sortable;
|
||||
/// Disable persisting columns order, width, and sort settings in the .ini file.
|
||||
const NO_SAVED_SETTINGS = sys::ImGuiTableFlags_NoSavedSettings;
|
||||
/// Right-click on columns body/contents will display table context menu.
|
||||
/// By default you can only right click in a headers row.
|
||||
const CONTEXT_MENU_IN_BODY = sys::ImGuiTableFlags_ContextMenuInBody;
|
||||
|
||||
// Decorations
|
||||
|
||||
/// Set each RowBg color with [table_row_bg] or [table_row_bg_alt] (equivalent of calling
|
||||
/// `table_set_bg_color` with `ROW_BG0` on each row manually)
|
||||
const ROW_BG = sys::ImGuiTableFlags_RowBg;
|
||||
/// Draw horizontal borders between rows.
|
||||
const BORDERS_INNER_H = sys::ImGuiTableFlags_BordersInnerH;
|
||||
/// Draw horizontal borders at the top and bottom.
|
||||
const BORDERS_OUTER_H = sys::ImGuiTableFlags_BordersOuterH;
|
||||
/// Draw vertical borders between columns.
|
||||
const BORDERS_INNER_V = sys::ImGuiTableFlags_BordersInnerV;
|
||||
/// Draw vertical borders on the left and right sides.
|
||||
const BORDERS_OUTER_V = sys::ImGuiTableFlags_BordersOuterV;
|
||||
/// Draw all horizontal borders (this is just [BORDERS_INNER_H] | [BORDERS_OUTER_H]).
|
||||
const BORDERS_H = sys::ImGuiTableFlags_BordersH;
|
||||
/// Draw all vertical borders (this is just [BORDERS_INNER_V] | [BORDERS_OUTER_V]).
|
||||
const BORDERS_V = sys::ImGuiTableFlags_BordersV;
|
||||
/// Draw all inner borders (this is just [BORDERS_INNER_H] | [BORDERS_INNER_V]).
|
||||
const BORDERS_INNER = sys::ImGuiTableFlags_BordersInner;
|
||||
/// Draw all outer borders (this is just [BORDERS_OUTER_H] | [BORDERS_OUTER_V]).
|
||||
const BORDERS_OUTER = sys::ImGuiTableFlags_BordersOuter;
|
||||
/// Draw all borders (this is just [BORDERS_INNER] | [BORDERS_OUTER]).
|
||||
const BORDERS = sys::ImGuiTableFlags_Borders;
|
||||
/// **ALPHA** Disable vertical borders in columns Body (borders will always appears in Headers).
|
||||
/// May move to Style
|
||||
const NO_BORDERS_IN_BODY = sys::ImGuiTableFlags_NoBordersInBody;
|
||||
/// **ALPHA** Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers).
|
||||
/// May move to style
|
||||
const NO_BORDERS_IN_BODY_UNTIL_RESIZE = sys::ImGuiTableFlags_NoBordersInBodyUntilResize;
|
||||
|
||||
// Sizing Policy (read above for defaults)
|
||||
|
||||
/// Columns default to [WidthFixed] or [WidthAuto] (if resizable or not resizable),
|
||||
/// matching contents width.
|
||||
const SIZING_FIXED_FIT = sys::ImGuiTableFlags_SizingFixedFit;
|
||||
/// Columns default to [WidthFixed] or [WidthAuto] (if resizable or not resizable),
|
||||
/// matching the maximum contents width of all columns.
|
||||
/// Implicitly enable [NoKeepColumnsVisible].
|
||||
const SIZING_FIXED_SAME = sys::ImGuiTableFlags_SizingFixedSame;
|
||||
/// Columns default to [WidthStretch] with default weights proportional to each columns
|
||||
/// contents widths.
|
||||
const SIZING_STRETCH_PROP = sys::ImGuiTableFlags_SizingStretchProp;
|
||||
/// Columns default to [WidthStretch] with default weights all equal, unless overridden by
|
||||
/// a column's `TableHeader`.
|
||||
const SIZING_STRETCH_SAME = sys::ImGuiTableFlags_SizingStretchSame;
|
||||
|
||||
// Sizing Extra Options
|
||||
|
||||
/// Make outer width auto-fit to columns, overriding outer_size.x value. Only available when
|
||||
/// [ScrollX]/[ScrollY] are disabled and [Stretch] columns are not used.
|
||||
const NO_HOST_EXTEND_X = sys::ImGuiTableFlags_NoHostExtendX;
|
||||
/// Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).
|
||||
/// Only available when [ScrollX]/[ScrollY] are disabled.
|
||||
/// Data below the limit will be clipped and not visible.
|
||||
const NO_HOST_EXTEND_Y = sys::ImGuiTableFlags_NoHostExtendY;
|
||||
/// Disable keeping column always minimally visible when [ScrollX] is off and table
|
||||
/// gets too small. Not recommended if columns are resizable.
|
||||
const NO_KEEP_COLUMNS_VISIBLE = sys::ImGuiTableFlags_NoKeepColumnsVisible;
|
||||
/// Disable distributing remainder width to stretched columns (width allocation on a 100-wide
|
||||
/// table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33).
|
||||
/// With larger number of columns, resizing will appear to be less smooth.
|
||||
const PRECISE_WIDTHS = sys::ImGuiTableFlags_PreciseWidths;
|
||||
|
||||
// Clipping
|
||||
|
||||
/// Disable clipping rectangle for every individual columns (reduce draw command count, items will
|
||||
/// be able to overflow into other columns). Generally incompatible with [table_setup_scroll_freeze].
|
||||
const NO_CLIP = sys::ImGuiTableFlags_NoClip;
|
||||
|
||||
// Padding
|
||||
|
||||
/// Default if [BordersOuterV] is on. Enable outer-most padding. Generally desirable if you have headers.
|
||||
const PAD_OUTER_X = sys::ImGuiTableFlags_PadOuterX;
|
||||
/// Default if [BordersOuterV] is off. Disable outer-most padding.
|
||||
const NO_PAD_OUTER_X = sys::ImGuiTableFlags_NoPadOuterX;
|
||||
/// Disable inner padding between columns (double inner padding if [BordersOuterV] is on, single
|
||||
/// inner padding if BordersOuterV is off).
|
||||
const NO_PAD_INNER_X = sys::ImGuiTableFlags_NoPadInnerX;
|
||||
|
||||
// Scrolling
|
||||
|
||||
/// Enable horizontal scrolling. Require 'outer_size' parameter of [begin_table] to specify the
|
||||
/// container size. Changes default sizing policy. Because this create a child window,
|
||||
/// [ScrollY] is currently generally recommended when using [ScrollX].
|
||||
const SCROLL_X = sys::ImGuiTableFlags_ScrollX;
|
||||
/// Enable vertical scrolling. Require 'outer_size' parameter of [begin_table] to specify the
|
||||
/// container size.
|
||||
const SCROLL_Y = sys::ImGuiTableFlags_ScrollY;
|
||||
|
||||
// Sorting
|
||||
|
||||
/// Hold shift when clicking headers to sort on multiple column. [table_get_sort_specs] may return specs where `[spec_count] > 1`.
|
||||
const SORT_MULTI = sys::ImGuiTableFlags_SortMulti;
|
||||
/// Allow no sorting, disable default sorting. `table_get_sort_specs` may return specs where `[specs_count] == 0`.
|
||||
const SORT_TRISTATE = sys::ImGuiTableFlags_SortTristate;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags for [table_next_row_with_flags].
|
||||
#[repr(transparent)]
|
||||
pub struct TableRowFlags: u32 {
|
||||
/// Identify header row (set default background color + width of its contents
|
||||
/// accounted different for auto column width)
|
||||
const HEADERS = sys::ImGuiTableRowFlags_Headers;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags for [TableColumnSetup] and [table_setup_column_with].
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
pub struct TableColumnFlags: u32 {
|
||||
// Input configuration flags
|
||||
|
||||
/// Default as a hidden/disabled column.
|
||||
const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide;
|
||||
/// Default as a sorting column.
|
||||
const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort;
|
||||
/// Column will stretch. Preferable with horizontal scrolling disabled (default
|
||||
/// if table sizing policy is [ImGuiTableFlags::SizingStretchSame] or
|
||||
/// [ImGuiTableFlags::SizingStretchProp]).
|
||||
const WIDTH_STRETCH = sys::ImGuiTableColumnFlags_WidthStretch;
|
||||
/// Column will not stretch. Preferable with horizontal scrolling enabled (default
|
||||
/// if table sizing policy is [ImGuiTableFlags::SizingFixedFit] and table is resizable).
|
||||
const WIDTH_FIXED = sys::ImGuiTableColumnFlags_WidthFixed;
|
||||
/// Disable manual resizing.
|
||||
const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize;
|
||||
/// Disable manual reordering this column, this will also prevent other columns from
|
||||
/// crossing over this column.
|
||||
const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder;
|
||||
/// Disable ability to hide/disable this column.
|
||||
const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide;
|
||||
/// Disable clipping for this column (all [NO_CLIP] columns will render in a same
|
||||
/// draw command).
|
||||
const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip;
|
||||
/// Disable ability to sort on this field (even if [ImGuiTableFlags::Sortable] is
|
||||
/// set on the table).
|
||||
const NO_SORT = sys::ImGuiTableColumnFlags_NoSort;
|
||||
/// Disable ability to sort in the ascending direction.
|
||||
const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending;
|
||||
/// Disable ability to sort in the descending direction.
|
||||
const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending;
|
||||
/// Disable header text width contribution to automatic column width.
|
||||
const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth;
|
||||
/// Make the initial sort direction Ascending when first sorting on this column (default).
|
||||
const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending;
|
||||
/// Make the initial sort direction Descending when first sorting on this column.
|
||||
const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending;
|
||||
/// Use current Indent value when entering cell (default for column 0).
|
||||
const INDENT_ENABLE = sys::ImGuiTableColumnFlags_IndentEnable;
|
||||
/// Ignore current Indent value when entering cell (default for columns > 0).
|
||||
/// Indentation changes _within_ the cell will still be honored.
|
||||
const INDENT_DISABLE = sys::ImGuiTableColumnFlags_IndentDisable;
|
||||
|
||||
// Output status flags, read-only via [table_get_column_flags]
|
||||
|
||||
/// Status: is enabled == not hidden by user/api (referred to as "Hide" in
|
||||
/// [DefaultHide] and [NoHide]) flags.
|
||||
const IS_ENABLED = sys::ImGuiTableColumnFlags_IsEnabled;
|
||||
/// Status: is visible == is enabled AND not clipped by scrolling.
|
||||
const IS_VISIBLE = sys::ImGuiTableColumnFlags_IsVisible;
|
||||
/// Status: is currently part of the sort specs
|
||||
const IS_SORTED = sys::ImGuiTableColumnFlags_IsSorted;
|
||||
/// Status: is hovered by mouse
|
||||
const IS_HOVERED = sys::ImGuiTableColumnFlags_IsHovered;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Enum for [table_set_bg_color].
|
||||
/// Background colors are rendering in 3 layers:
|
||||
/// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set.
|
||||
/// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set.
|
||||
/// - Layer 2: draw with CellBg color if set.
|
||||
/// The purpose of the two row/columns layers is to let you decide if a background color
|
||||
/// changes should override or blend with the existing color.
|
||||
/// When using [TableFlags::RowBg] on the table, each row has the RowBg0 color automatically
|
||||
/// set for odd/even rows.
|
||||
/// If you set the color of RowBg0 target, your color will override the existing RowBg0 color.
|
||||
/// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color.
|
||||
#[repr(transparent)]
|
||||
pub struct TableBgTarget: u32 {
|
||||
/// Set row background color 0 (generally used for background, automatically set when
|
||||
/// [TableFlags::RowBg] is used)
|
||||
const ROW_BG0 = sys::ImGuiTableBgTarget_RowBg0;
|
||||
/// Set row background color 1 (generally used for selection marking)
|
||||
const ROW_BG1 = sys::ImGuiTableBgTarget_RowBg1;
|
||||
/// Set cell background color (top-most color)
|
||||
const CELL_BG = sys::ImGuiTableBgTarget_CellBg;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum TableSortDirection {
|
||||
Ascending,
|
||||
Descending,
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Begins a table with no flags and with standard sizing constraints.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_header](Self::begin_table_header) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// Nb: we take `column` as a usize, but it will be converted with `as i32` to an i32.
|
||||
/// If this makes a difference to you, you are probably trying to make too many columns.
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column_count: usize,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_with_flags(str_id, column_count, TableFlags::empty())
|
||||
}
|
||||
|
||||
/// Begins a table with flags and standard sizing constraints.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_header](Self::begin_table_header) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// Nb: we take `column` as a usize, but it will be converted with `as i32` to an i32.
|
||||
/// If this makes a difference to you, you are probably trying to make too many columns.
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table_with_flags(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column_count: usize,
|
||||
flags: TableFlags,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_with_sizing(str_id, column_count, flags, [0.0, 0.0], 0.0)
|
||||
}
|
||||
|
||||
/// Begins a table with all flags and sizing constraints. This is the base method,
|
||||
/// and gives users the most flexibility.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_header](Self::begin_table_header) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// Nb: we take `column` as a usize, but it will be converted with `as i32` to an i32.
|
||||
/// If this makes a difference to you, you are probably trying to make too many columns.
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table_with_sizing(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column: usize,
|
||||
flags: TableFlags,
|
||||
outer_size: [f32; 2],
|
||||
inner_width: f32,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
let should_render = unsafe {
|
||||
sys::igBeginTable(
|
||||
self.scratch_txt(str_id),
|
||||
column as i32,
|
||||
flags.bits() as i32,
|
||||
outer_size.into(),
|
||||
inner_width,
|
||||
)
|
||||
};
|
||||
|
||||
// todo: once msrv is 1.54, convert this to .then(||)
|
||||
if should_render {
|
||||
Some(TableToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Begins a table with no flags and with standard sizing constraints.
|
||||
///
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
#[cfg(feature = "min-const-generics")]
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table_header<'a, Name: AsRef<str>, const N: usize>(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column_data: [TableColumnSetup<'a, Name>; N],
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty())
|
||||
}
|
||||
|
||||
/// Begins a table with flags and standard sizing constraints.
|
||||
///
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
#[cfg(feature = "min-const-generics")]
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table_header_with_flags<'a, Name: AsRef<str>, const N: usize>(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column_data: [TableColumnSetup<'a, Name>; N],
|
||||
flags: TableFlags,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0)
|
||||
}
|
||||
|
||||
/// Begins a table with all flags and sizing constraints. This is the base method,
|
||||
/// and gives users the most flexibility.
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
#[cfg(feature = "min-const-generics")]
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table_header_with_sizing<'a, Name: AsRef<str>, const N: usize>(
|
||||
&self,
|
||||
str_id: impl AsRef<str>,
|
||||
column_data: [TableColumnSetup<'a, Name>; N],
|
||||
flags: TableFlags,
|
||||
outer_size: [f32; 2],
|
||||
inner_width: f32,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_with_sizing(str_id, N, flags, outer_size, inner_width)
|
||||
.map(|data| {
|
||||
for value in column_data {
|
||||
self.table_setup_column_with(value);
|
||||
}
|
||||
self.table_headers_row();
|
||||
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down) with no flags,
|
||||
/// and with the next row having a standard computed height.
|
||||
///
|
||||
/// If your table was made with [begin_table], this **must** be called
|
||||
/// before rendering any cells (along with [table_next_column]).
|
||||
/// If your table was made with [begin_table_header], this does not need to be called,
|
||||
/// though [table_next_column] still should be.
|
||||
///
|
||||
/// [begin_table]: Self::begin_table
|
||||
/// [begin_table_header]: Self::begin_table_header
|
||||
/// [table_next_column]: Self::table_next_column
|
||||
#[inline]
|
||||
pub fn table_next_row(&self) {
|
||||
self.table_next_row_with_flags(TableRowFlags::empty());
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down), with the given flags,
|
||||
/// and with the next row having a standard computed height.
|
||||
///
|
||||
/// Setting a flag here will make the next row a "header" now, which may
|
||||
/// require setup of column data.
|
||||
///
|
||||
/// See [table_next_row](Self::table_next_row) for information on how moving rows work. To set the row
|
||||
/// with a given height, see [table_next_row_with_height](Self::table_next_row_with_height).
|
||||
#[inline]
|
||||
pub fn table_next_row_with_flags(&self, flags: TableRowFlags) {
|
||||
self.table_next_row_with_height(flags, 0.0);
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down), with the given flags,
|
||||
/// and with the given minimum height.
|
||||
///
|
||||
/// See [table_next_row](Self::table_next_row) for information on how moving rows work.
|
||||
#[inline]
|
||||
pub fn table_next_row_with_height(&self, flags: TableRowFlags, min_row_height: f32) {
|
||||
unsafe {
|
||||
sys::igTableNextRow(flags.bits() as i32, min_row_height);
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves onto the next column. If at `column_count`, this will move to the next row.
|
||||
/// In this way, you can use this function as an iterator over each cell in the table.
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # let mut ctx = imgui::Context::create();
|
||||
/// # { let ui = ctx.frame();
|
||||
/// if let Some(_t) = ui.begin_table("Basic-Table", 2) {
|
||||
/// // we have to call next_row because we didn't make headers..
|
||||
/// ui.table_next_row();
|
||||
///
|
||||
/// // you always have to call this to start...
|
||||
/// // take advantage of this in loops!
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 0, y: 0");
|
||||
///
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 1, y: 0");
|
||||
///
|
||||
/// // notice that we go down a row here too.
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 0, y: 1");
|
||||
///
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 1, y: 1");
|
||||
/// }
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// This functions returns true if the given column is **visible.** It is not
|
||||
/// marked as must use, as you can still render commands into the not-visible column,
|
||||
/// though you can choose to not as an optimization.
|
||||
pub fn table_next_column(&self) -> bool {
|
||||
unsafe { sys::igTableNextColumn() }
|
||||
}
|
||||
|
||||
/// Moves onto the given column.
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # let mut ctx = imgui::Context::create();
|
||||
/// # { let ui = ctx.frame();
|
||||
/// if let Some(_t) = ui.begin_table("Basic-Table", 2) {
|
||||
/// // we have to call next_row because we didn't make headers..
|
||||
/// ui.table_next_row();
|
||||
///
|
||||
/// for i in 0..2 {
|
||||
/// ui.table_set_column_index(i);
|
||||
/// ui.text(format!("x: {}", i));
|
||||
/// }
|
||||
///
|
||||
/// // oops I just remembered, i need to add something on idx 0!
|
||||
/// ui.table_set_column_index(0);
|
||||
/// // if i uncomment this line, we'll write on top of our previous "x: 0"
|
||||
/// // line:
|
||||
/// // ui.text("hello from the future on top of the past");
|
||||
/// // so we do a .newline();
|
||||
/// ui.new_line();
|
||||
/// ui.text("hello from the future");
|
||||
///
|
||||
/// // imgui will understand this and row spacing will be adjusted automatically.
|
||||
/// }
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// This functions returns true if the given column is **visible.** It is not
|
||||
/// marked as must use, as you can still render commands into the not-visible column,
|
||||
/// though you can choose to not as an optimization.
|
||||
///
|
||||
/// # Panics
|
||||
/// If `column_index >= ui.table_column_count`, this function will panic. In `debug` releases,
|
||||
/// we will panic on the Rust side, for a nicer error message, though in release, we will
|
||||
/// panic in C++, which will result in an ugly stack overflow.
|
||||
pub fn table_set_column_index(&self, column_index: usize) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let size = self.table_column_count() as usize;
|
||||
if column_index >= size {
|
||||
panic!(
|
||||
"column_index >= self.table_get_column_count().\
|
||||
Requested {}, but only have {} columns.",
|
||||
column_index, size
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { sys::igTableSetColumnIndex(column_index as i32) }
|
||||
}
|
||||
|
||||
/// Specify label per column, with no flags and default sizing. You can avoid calling
|
||||
/// this method entirely by using [begin_table_header](Self::begin_table_header).
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # let mut ctx = imgui::Context::create();
|
||||
/// # { let ui = ctx.frame();
|
||||
/// if let Some(_t) = ui.begin_table("My Table", 2) {
|
||||
/// ui.table_setup_column("One");
|
||||
/// ui.table_setup_column("Two");
|
||||
/// ui.table_setup_column("Three");
|
||||
/// ui.table_headers_row();
|
||||
///
|
||||
/// // call next_column/set_column_index and proceed like normal.
|
||||
/// // the above code is the equivalent of just using `begin_table_header`
|
||||
/// // but does allow for some columns to have headers and others to not
|
||||
/// }
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// Along with [table_headers_row](Self::table_headers_row), this method is used to create a header
|
||||
/// row and automatically submit a table header for each column.
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::CONTEXT_MENU_IN_BODY].
|
||||
pub fn table_setup_column(&self, str_id: impl AsRef<str>) {
|
||||
self.table_setup_column_with(TableColumnSetup::new(str_id))
|
||||
}
|
||||
|
||||
/// Specify label per column, with data given in [TableColumnSetup]. You can avoid calling
|
||||
/// this method entirely by using [begin_table_header](Self::begin_table_header).
|
||||
///
|
||||
/// See [table_setup_column](Self::table_setup_column) for an example of how to setup columns
|
||||
/// yourself.
|
||||
///
|
||||
/// Along with [table_headers_row](Self::table_headers_row), this method is used to create a header
|
||||
/// row and automatically submit a table header for each column.
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::CONTEXT_MENU_IN_BODY].
|
||||
pub fn table_setup_column_with<N: AsRef<str>>(&self, data: TableColumnSetup<'_, N>) {
|
||||
unsafe {
|
||||
sys::igTableSetupColumn(
|
||||
self.scratch_txt(data.name),
|
||||
data.flags.bits() as i32,
|
||||
data.init_width_or_weight,
|
||||
data.user_id.as_imgui_id(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks columns/rows so they stay visible when scrolled. Generally, you will be calling this
|
||||
/// so that the header column is always visible (though go wild if you want). You can avoid
|
||||
/// calling this entirely by passing `true` to [begin_table_header](Self::begin_table_header).
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # let mut ctx = imgui::Context::create();
|
||||
/// # { let ui = ctx.frame();
|
||||
/// const COLUMN_COUNT: usize = 3;
|
||||
/// if let Some(_t) = ui.begin_table("scroll-freeze-example", COLUMN_COUNT) {
|
||||
/// // locks the header row. Notice how we need to call it BEFORE `table_headers_row`.
|
||||
/// ui.table_setup_scroll_freeze(1, COLUMN_COUNT);
|
||||
/// ui.table_setup_column("One");
|
||||
/// ui.table_setup_column("Two");
|
||||
/// ui.table_setup_column("Three");
|
||||
/// ui.table_headers_row();
|
||||
/// }
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// Nb: we take `locked_columns` and `locked_rows` as a `usize`, but it will be converted
|
||||
/// with `as i32` to an i32. If this makes a difference to you, you are probably
|
||||
/// trying to make too many columns.
|
||||
pub fn table_setup_scroll_freeze(&self, locked_columns: usize, locked_rows: usize) {
|
||||
unsafe {
|
||||
sys::igTableSetupScrollFreeze(locked_columns as i32, locked_rows as i32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Along with [table_setup_column](Self::table_setup_column), this method is used
|
||||
/// to create a header row and automatically submit a table header for each column.
|
||||
///
|
||||
/// For an example of using this method, see [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::CONTEXT_MENU_IN_BODY].
|
||||
///
|
||||
/// You may manually submit headers using [table_next_column] + [table_header] calls, but this is
|
||||
/// only useful in some advanced use cases (e.g. adding custom widgets in header row).
|
||||
/// See [table_header](Self::table_header) for more information.
|
||||
///
|
||||
/// [table_next_column]: Self::table_next_column
|
||||
/// [table_header]: Self::table_header
|
||||
pub fn table_headers_row(&self) {
|
||||
unsafe {
|
||||
sys::igTableHeadersRow();
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this function to manually declare a column cell to be a header.
|
||||
///
|
||||
/// You generally should avoid using this outside of specific cases,
|
||||
/// such as custom widgets. Instead, use [table_headers_row](Self::table_headers_row)
|
||||
/// and [table_setup_column](Self::table_setup_column).
|
||||
pub fn table_header(&self, label: impl AsRef<str>) {
|
||||
unsafe {
|
||||
sys::igTableHeader(self.scratch_txt(label));
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the numbers of columns in the current table.
|
||||
pub fn table_column_count(&self) -> usize {
|
||||
unsafe { sys::igTableGetColumnCount() as usize }
|
||||
}
|
||||
|
||||
/// Gets the current column index in the current table.
|
||||
pub fn table_column_index(&self) -> usize {
|
||||
unsafe { sys::igTableGetColumnIndex() as usize }
|
||||
}
|
||||
|
||||
/// Gets the current row index in the current table.
|
||||
pub fn table_row_index(&self) -> usize {
|
||||
unsafe { sys::igTableGetRowIndex() as usize }
|
||||
}
|
||||
|
||||
/// Gets the name of the current column. If there is no currently bound name
|
||||
/// for this column, we will return an empty string.
|
||||
///
|
||||
/// Use [table_column_name_with_column](Self::table_column_name_with_column)
|
||||
/// for arbitrary indices.
|
||||
pub fn table_column_name(&mut self) -> &str {
|
||||
unsafe {
|
||||
// imgui uses utf8...though that is a continuous process there.
|
||||
CStr::from_ptr(sys::igTableGetColumnName(-1))
|
||||
.to_str()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the name of a given column. If there is no currently bound name
|
||||
/// for this column, we will return an empty string.
|
||||
///
|
||||
/// Use [table_column_name](Self::table_column_name) for the current column.
|
||||
pub fn table_column_name_with_column(&mut self, column: usize) -> &str {
|
||||
unsafe {
|
||||
// imgui uses utf8...though that is a continuous process there.
|
||||
CStr::from_ptr(sys::igTableGetColumnName(column as i32))
|
||||
.to_str()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the flags on the current column in the current table.
|
||||
pub fn table_column_flags(&self) -> TableColumnFlags {
|
||||
unsafe {
|
||||
TableColumnFlags::from_bits(sys::igTableGetColumnFlags(-1) as u32)
|
||||
.expect("bad column flags")
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the flags on the given column in the current table. To get the current column's
|
||||
/// flags without having to call [table_column_index](Self::table_column_index), use
|
||||
/// [table_column_flags](Self::table_column_flags).
|
||||
pub fn table_column_flags_with_column(&self, column_n: usize) -> TableColumnFlags {
|
||||
unsafe {
|
||||
TableColumnFlags::from_bits(sys::igTableGetColumnFlags(column_n as i32) as u32)
|
||||
.expect("bad column flags")
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the given background color for this column. See [TableBgTarget]
|
||||
/// for more information on how colors work for tables.
|
||||
///
|
||||
/// Use [table_set_bg_color_with_column](Self::table_set_bg_color_with_column) to set
|
||||
/// for arbitrary indices.
|
||||
pub fn table_set_bg_color(&self, target: TableBgTarget, color: impl Into<ImColor32>) {
|
||||
unsafe {
|
||||
sys::igTableSetBgColor(target.bits() as i32, color.into().into(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the given background color for any column. See [TableBgTarget]
|
||||
/// for more information on how colors work for tables.
|
||||
///
|
||||
/// Use [table_set_bg_color](Self::table_set_bg_color) for the current column.
|
||||
pub fn table_set_bg_color_with_column(
|
||||
&self,
|
||||
target: TableBgTarget,
|
||||
color: impl Into<ImColor32>,
|
||||
column_index: usize,
|
||||
) {
|
||||
unsafe {
|
||||
sys::igTableSetBgColor(
|
||||
target.bits() as i32,
|
||||
color.into().into(),
|
||||
column_index as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Change user accessible enabled/disabled state of the current column.
|
||||
///
|
||||
/// Set to false to hide the column. Users can use the context menu to change
|
||||
/// this themselves by right-clicking in headers, or right-clicking in columns body
|
||||
/// if [TableFlags::CONTEXT_MENU_IN_BODY].
|
||||
///
|
||||
/// Use [table_set_enabled_with_column](Self::table_set_enabled_with_column) to set
|
||||
/// for arbitrary indices.
|
||||
pub fn table_set_enabled(&self, enabled: bool) {
|
||||
unsafe { sys::igTableSetColumnEnabled(-1, enabled) }
|
||||
}
|
||||
|
||||
/// Change user accessible enabled/disabled state of the current column.
|
||||
///
|
||||
/// Set to false to hide the column. Users can use the context menu to change
|
||||
/// this themselves by right-clicking in headers, or right-clicking in columns body
|
||||
/// if [TableFlags::CONTEXT_MENU_IN_BODY].
|
||||
pub fn table_set_enabled_with_column(&self, enabled: bool, column_idx: usize) {
|
||||
unsafe { sys::igTableSetColumnEnabled(column_idx as i32, enabled) }
|
||||
}
|
||||
|
||||
/// Gets the sorting data for a table. This will be `None` when not sorting.
|
||||
///
|
||||
/// See the examples folder for how to use the sorting API.
|
||||
pub fn table_sort_specs_mut(&self) -> Option<TableSortSpecsMut<'_>> {
|
||||
unsafe {
|
||||
let value = sys::igTableGetSortSpecs();
|
||||
if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(TableSortSpecsMut(value, PhantomData))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct containing all the data needed to setup a table column header
|
||||
/// via [begin_table_header](Ui::begin_table_header) or [table_setup_column](Ui::table_setup_column).
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TableColumnSetup<'a, Name> {
|
||||
/// The name of column to be displayed to users.
|
||||
pub name: Name,
|
||||
/// The flags this column will have.
|
||||
pub flags: TableColumnFlags,
|
||||
/// The width or weight of the given column.
|
||||
pub init_width_or_weight: f32,
|
||||
/// A user_id, primarily used in sorting operations.
|
||||
pub user_id: Id<'a>,
|
||||
}
|
||||
|
||||
impl<'a, Name: AsRef<str>> TableColumnSetup<'a, Name> {
|
||||
pub fn new(name: Name) -> Self {
|
||||
Self {
|
||||
name,
|
||||
flags: TableColumnFlags::empty(),
|
||||
init_width_or_weight: 0.0,
|
||||
user_id: Id::Int(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around table sort specs.
|
||||
///
|
||||
/// To use this simply, use [conditional_sort] and provide a closure --
|
||||
/// if you should sort your data, then the closure will be ran and imgui
|
||||
/// will be informed that your data is sorted.
|
||||
///
|
||||
/// For manual control (such as if sorting can fail), use [should_sort] to
|
||||
/// check if you should sort your data, sort your data using [specs] for information
|
||||
/// on how to sort it, and then [set_sorted] to indicate that the data is sorted.
|
||||
///
|
||||
/// [conditional_sort]: Self::conditional_sort
|
||||
/// [should_sort]: Self::should_sort
|
||||
/// [specs]: Self::specs
|
||||
/// [set_sorted]: Self::set_sorted
|
||||
pub struct TableSortSpecsMut<'ui>(*mut sys::ImGuiTableSortSpecs, PhantomData<Ui<'ui>>);
|
||||
|
||||
impl TableSortSpecsMut<'_> {
|
||||
/// Gets the specs for a given sort. In most scenarios, this will be a slice of 1 entry.
|
||||
pub fn specs(&self) -> Specs<'_> {
|
||||
let value =
|
||||
unsafe { std::slice::from_raw_parts((*self.0).Specs, (*self.0).SpecsCount as usize) };
|
||||
|
||||
Specs(value)
|
||||
}
|
||||
|
||||
/// Returns true if the data should be sorted.
|
||||
pub fn should_sort(&self) -> bool {
|
||||
unsafe { (*self.0).SpecsDirty }
|
||||
}
|
||||
|
||||
/// Sets the internal flag that the data has been sorted.
|
||||
pub fn set_sorted(&mut self) {
|
||||
unsafe {
|
||||
(*self.0).SpecsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide a closure, which will receive the Specs for a sort.
|
||||
///
|
||||
/// If you should sort the data, the closure will run, and ImGui will be
|
||||
/// told that the data has been sorted.
|
||||
///
|
||||
/// If you need manual control over sorting, consider using [should_sort], [specs],
|
||||
/// and [set_sorted] yourself.
|
||||
///
|
||||
/// [should_sort]: Self::should_sort
|
||||
/// [specs]: Self::specs
|
||||
/// [set_sorted]: Self::set_sorted
|
||||
pub fn conditional_sort(mut self, mut f: impl FnMut(Specs<'_>)) {
|
||||
let is_dirty = self.should_sort();
|
||||
|
||||
if is_dirty {
|
||||
f(self.specs());
|
||||
}
|
||||
|
||||
self.set_sorted();
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around a slice of [TableColumnSortSpecs].
|
||||
///
|
||||
/// This slice may be 0 if [TableFlags::SORT_TRISTATE] is true, may be > 1 is [TableFlags::SORT_MULTI] is true,
|
||||
/// but is generally == 1.
|
||||
///
|
||||
/// Consume this struct as an iterator.
|
||||
pub struct Specs<'a>(&'a [sys::ImGuiTableColumnSortSpecs]);
|
||||
|
||||
impl<'a> Specs<'a> {
|
||||
pub fn iter(self) -> impl Iterator<Item = TableColumnSortSpecs<'a>> {
|
||||
self.0.iter().map(|v| TableColumnSortSpecs(v))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TableColumnSortSpecs<'a>(&'a sys::ImGuiTableColumnSortSpecs);
|
||||
impl<'a> TableColumnSortSpecs<'a> {
|
||||
/// User id of the column (if specified by a TableSetupColumn() call)
|
||||
pub fn column_user_id(&self) -> sys::ImGuiID {
|
||||
self.0.ColumnUserID
|
||||
}
|
||||
|
||||
/// Index of the column
|
||||
pub fn column_idx(&self) -> usize {
|
||||
self.0.ColumnIndex as usize
|
||||
}
|
||||
|
||||
/// Index within parent [Specs] slice where this was found -- always stored in order starting
|
||||
/// from 0, tables sorted on a single criteria will always have a 0 here.
|
||||
///
|
||||
/// Generally, you don't need to access this, as it's the same as calling `specs.iter().enumerate()`.
|
||||
pub fn sort_order(&self) -> usize {
|
||||
self.0.SortOrder as usize
|
||||
}
|
||||
|
||||
/// Gets the sort direction for the given column. This will nearly always be `Some` if you
|
||||
/// can access it.
|
||||
pub fn sort_direction(&self) -> Option<TableSortDirection> {
|
||||
match self.0.SortDirection() {
|
||||
0 => None,
|
||||
1 => Some(TableSortDirection::Ascending),
|
||||
2 => Some(TableSortDirection::Descending),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a table which can be rendered onto, ending with `.end()`
|
||||
/// or by dropping.
|
||||
pub struct TableToken<'ui>;
|
||||
|
||||
/// Ends the table.
|
||||
drop { sys::igEndTable() }
|
||||
);
|
||||
@@ -1,23 +0,0 @@
|
||||
use parking_lot::{ReentrantMutex, ReentrantMutexGuard};
|
||||
use std::ptr;
|
||||
|
||||
use crate::context::Context;
|
||||
|
||||
pub static TEST_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(());
|
||||
|
||||
pub fn test_ctx() -> (ReentrantMutexGuard<'static, ()>, Context) {
|
||||
let guard = TEST_MUTEX.lock();
|
||||
let mut ctx = Context::create();
|
||||
ctx.io_mut().ini_filename = ptr::null();
|
||||
(guard, ctx)
|
||||
}
|
||||
|
||||
pub fn test_ctx_initialized() -> (ReentrantMutexGuard<'static, ()>, Context) {
|
||||
let (guard, mut ctx) = test_ctx();
|
||||
let io = ctx.io_mut();
|
||||
io.display_size = [1024.0, 768.0];
|
||||
io.delta_time = 1.0 / 60.0;
|
||||
io.mouse_pos = [0.0, 0.0];
|
||||
ctx.fonts().build_rgba32_texture();
|
||||
(guard, ctx)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#[macro_export]
|
||||
/// This is a macro used internally by imgui-rs to create StackTokens
|
||||
/// representing various global state in DearImGui.
|
||||
///
|
||||
/// These tokens can either be allowed to drop or dropped manually
|
||||
/// by called `end` on them. Preventing this token from dropping,
|
||||
/// or moving this token out of the block it was made in can have
|
||||
/// unintended side effects, including failed asserts in the DearImGui C++.
|
||||
///
|
||||
/// In general, if you're looking at this, don't overthink these -- just slap
|
||||
/// a '_token` as their binding name and allow them to drop.
|
||||
macro_rules! create_token {
|
||||
(
|
||||
$(#[$struct_meta:meta])*
|
||||
$v:vis struct $token_name:ident<'ui>;
|
||||
|
||||
$(#[$end_meta:meta])*
|
||||
drop { $on_drop:expr }
|
||||
) => {
|
||||
#[must_use]
|
||||
$(#[$struct_meta])*
|
||||
pub struct $token_name<'a>($crate::__core::marker::PhantomData<crate::Ui<'a>>);
|
||||
|
||||
impl<'a> $token_name<'a> {
|
||||
/// Creates a new token type.
|
||||
pub(crate) fn new(_: &crate::Ui<'a>) -> Self {
|
||||
Self(std::marker::PhantomData)
|
||||
}
|
||||
|
||||
$(#[$end_meta])*
|
||||
#[inline]
|
||||
pub fn end(self) {
|
||||
// left empty for drop
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $token_name<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { $on_drop }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user