mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
Compare commits
893 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad6bd1d23 | ||
|
|
510ffd41d8 | ||
|
|
4f00591c4e | ||
|
|
5b65ed87cd | ||
|
|
b0121c422d | ||
|
|
a9e9fad222 | ||
|
|
b5fc07acc7 | ||
|
|
140ebfdb92 | ||
|
|
37d0179de1 | ||
|
|
823d4b0fe2 | ||
|
|
dd1eacf4f0 | ||
|
|
86c33dd686 | ||
|
|
c6757cc61b | ||
|
|
a38cf284dd | ||
|
|
575b8e3f7f | ||
|
|
bc443f47f1 | ||
|
|
b631bcc0db | ||
|
|
5ccd92ece6 | ||
|
|
2f3c8868a7 | ||
|
|
6f7b5e8005 | ||
|
|
10d1e4b798 | ||
|
|
9d5934df14 | ||
|
|
be507de6c1 | ||
|
|
e5d3c08821 | ||
|
|
027b4ab7da | ||
|
|
fefea0d7ec | ||
|
|
33f30bfd19 | ||
|
|
e9d4b9961a | ||
|
|
b94248fe79 | ||
|
|
225975e0dd | ||
|
|
eac7492143 | ||
|
|
b3c40bf448 | ||
|
|
02f7cd77f4 | ||
|
|
7f8f3aa99b | ||
|
|
0bcdc14909 | ||
|
|
526c25a02b | ||
|
|
f48da9dab1 | ||
|
|
2e8dfda12e | ||
|
|
63da576d85 | ||
|
|
0ab4206540 | ||
|
|
212ae90401 | ||
|
|
d4e5d0be45 | ||
|
|
3520a0f1fb | ||
|
|
036090a947 | ||
|
|
dc570c683a | ||
|
|
9f85d34c91 | ||
|
|
16bf1fb6c3 | ||
|
|
47c4d508e0 | ||
|
|
e5d9060623 | ||
|
|
fdf28fc385 | ||
|
|
9015a4d56b | ||
|
|
38301454a6 | ||
|
|
9b3a22c4ca | ||
|
|
548dbc3649 | ||
|
|
3474129812 | ||
|
|
63193feebe | ||
|
|
51f22bfe75 | ||
|
|
7d0f7e1c8e | ||
|
|
dd8ab242fb | ||
|
|
60f3428da7 | ||
|
|
c6fec0a131 | ||
|
|
fdc43fc0d3 | ||
|
|
0b880aa335 | ||
|
|
74f50ec992 | ||
|
|
1bdf4532db | ||
|
|
f97783ddef | ||
|
|
1024d6fc07 | ||
|
|
3ec59d0c58 | ||
|
|
c43249316c | ||
|
|
ed5180ffd6 | ||
|
|
e9ec769340 | ||
|
|
5e16ff8dff | ||
|
|
364b6631ea | ||
|
|
48a18e53e3 | ||
|
|
bcc8282d73 | ||
|
|
15017ed49c | ||
|
|
50d36fe91b | ||
|
|
23e67a2908 | ||
|
|
0dab1b73cc | ||
|
|
3c086a92e2 | ||
|
|
647d72514b | ||
|
|
15328b4fd7 | ||
|
|
b49a498f9c | ||
|
|
8d14d5f87c | ||
|
|
a6db352ecd | ||
|
|
ccbb26c176 | ||
|
|
8f6af73541 | ||
|
|
a59f17fdb2 | ||
|
|
14222e40ad | ||
|
|
7d48bf06fe | ||
|
|
1d06a2c2e8 | ||
|
|
cf141f0e55 | ||
|
|
9113c31612 | ||
|
|
00b4e0a6fd | ||
|
|
e3cac95d37 | ||
|
|
64d850c583 | ||
|
|
2fe1b9e726 | ||
|
|
1315d847b9 | ||
|
|
b5954102b6 | ||
|
|
1c8ba0c538 | ||
|
|
be18317a6d | ||
|
|
88d2b8266e | ||
|
|
949ca5ddff | ||
|
|
3eb53b9648 | ||
|
|
e4a03ede1f | ||
|
|
cb65dc0e9d | ||
|
|
8ec907050e | ||
|
|
15ba00a902 | ||
|
|
89d0c301c2 | ||
|
|
2f47466f3b | ||
|
|
d70eca9774 | ||
|
|
95ce92fa18 | ||
|
|
b3db52b2ed | ||
|
|
c40912013d | ||
|
|
1c08e98c1c | ||
|
|
3f202a7cdc | ||
|
|
6f3aea8fc1 | ||
|
|
0896143838 | ||
|
|
ea94899a28 | ||
|
|
d2109cef86 | ||
|
|
cda146366c | ||
|
|
678b879a01 | ||
|
|
4c885c5e7b | ||
|
|
d5002b1c33 | ||
|
|
4f8b6d6b28 | ||
|
|
66dab41539 | ||
|
|
9e4940228d | ||
|
|
cbb11ebb03 | ||
|
|
073a25f381 | ||
|
|
40592ab876 | ||
|
|
bbfe624b51 | ||
|
|
a2af9e4c65 | ||
|
|
0123a8895f | ||
|
|
53854a4d13 | ||
|
|
4fdd44858f | ||
|
|
3c58879ce5 | ||
|
|
a7c6a881b3 | ||
|
|
ef065d31a0 | ||
|
|
d059d6b448 | ||
|
|
2d0a6f1bec | ||
|
|
a3cc5a1938 | ||
|
|
435068515a | ||
|
|
956001dbd7 | ||
|
|
460f0d9dee | ||
|
|
5155ec93c9 | ||
|
|
8bb8883e22 | ||
|
|
ffb7a6dfbb | ||
|
|
176de6f245 | ||
|
|
11f9740dbf | ||
|
|
42a91ba26c | ||
|
|
234003e2b1 | ||
|
|
534384438b | ||
|
|
ab51f35d5d | ||
|
|
511a4044d7 | ||
|
|
821efaff40 | ||
|
|
91bc994532 | ||
|
|
1323b46ac7 | ||
|
|
3a8b30ca8e | ||
|
|
923d58519f | ||
|
|
eabb1f84f6 | ||
|
|
cfbe44b946 | ||
|
|
81c35eab46 | ||
|
|
a1c7c29113 | ||
|
|
1293e2a074 | ||
|
|
b5deca7f22 | ||
|
|
604ba236c0 | ||
|
|
14df490b2a | ||
|
|
dd2f73e8ad | ||
|
|
56bfdc8ef9 | ||
|
|
91dbf1e144 | ||
|
|
e07ae90d09 | ||
|
|
5ef0c9aae1 | ||
|
|
aefed7c481 | ||
|
|
0d66d9f9a3 | ||
|
|
d0ffc4f979 | ||
|
|
f149d2b7cd | ||
|
|
21a12b8dd4 | ||
|
|
6c8b8e8949 | ||
|
|
539737d1c5 | ||
|
|
33ff5828da | ||
|
|
1fb0783808 | ||
|
|
b5e7aa8553 | ||
|
|
1d3ce76b27 | ||
|
|
0101171159 | ||
|
|
8b8ed0b9ff | ||
|
|
413b60e630 | ||
|
|
10b2a94c70 | ||
|
|
e337e5bbd8 | ||
|
|
6e55e0a183 | ||
|
|
8ee1d26935 | ||
|
|
80bdf69eaf | ||
|
|
18e838bffd | ||
|
|
d95b1b0ec4 | ||
|
|
d16a3c117b | ||
|
|
d04ec982ab | ||
|
|
cce99c803e | ||
|
|
19ed538573 | ||
|
|
a1f78345e6 | ||
|
|
f8c7ccf064 | ||
|
|
4d5242cd61 | ||
|
|
7ad176f98d | ||
|
|
57df7d28b5 | ||
|
|
f784ff2c84 | ||
|
|
a0f6affb68 | ||
|
|
0c679167fa | ||
|
|
4fe707e519 | ||
|
|
d83704b7cb | ||
|
|
2177ee45cc | ||
|
|
ccd4f99aea | ||
|
|
cd6b55c846 | ||
|
|
d923c8df81 | ||
|
|
59879f493e | ||
|
|
06cab0d4b5 | ||
|
|
a16db38a6f | ||
|
|
de93e19a80 | ||
|
|
47bb7d0de7 | ||
|
|
896e808db4 | ||
|
|
6fe6d1ffa0 | ||
|
|
4c6f7a66e2 | ||
|
|
4b5646ec88 | ||
|
|
66a5f350da | ||
|
|
f9e34cbab7 | ||
|
|
634f7b5ba3 | ||
|
|
7dbc6ff8a3 | ||
|
|
afccdc4749 | ||
|
|
c98ec041d4 | ||
|
|
9e0c62092e | ||
|
|
9aea006f50 | ||
|
|
c16c3759cf | ||
|
|
cbc1fe27ef | ||
|
|
f57dbf94c8 | ||
|
|
c0f15d2e6f | ||
|
|
cb525fafb6 | ||
|
|
5cae3a8141 | ||
|
|
8594e78287 | ||
|
|
5b8f922273 | ||
|
|
847b41752c | ||
|
|
7c08489cb3 | ||
|
|
605c77ecbc | ||
|
|
fd0c2a5cd1 | ||
|
|
a80790fc8e | ||
|
|
206d449d0d | ||
|
|
2323dc099f | ||
|
|
642583479f | ||
|
|
082e5842d0 | ||
|
|
c67ba02839 | ||
|
|
4c6cb7618f | ||
|
|
c15100f129 | ||
|
|
6dfb3cc84e | ||
|
|
18d8c7d086 | ||
|
|
ab3adf4ae3 | ||
|
|
7e6619af00 | ||
|
|
a7e2a10403 | ||
|
|
3a784375d0 | ||
|
|
b8c9433259 | ||
|
|
815d9d6012 | ||
|
|
feb91aa056 | ||
|
|
cd264586ca | ||
|
|
c6d561f2df | ||
|
|
6167c5f855 | ||
|
|
1a31cb96b8 | ||
|
|
9b8df64c35 | ||
|
|
a47565afec | ||
|
|
c2ee815cbe | ||
|
|
e45a2df6b6 | ||
|
|
a19979c233 | ||
|
|
e2a297fa40 | ||
|
|
df13b338b2 | ||
|
|
da9d7a0dee | ||
|
|
0374c65159 | ||
|
|
71b1e07ba6 | ||
|
|
c3781dc4b5 | ||
|
|
dc92d0913c | ||
|
|
a5adf29001 | ||
|
|
8861bfe4fa | ||
|
|
c8d280f418 | ||
|
|
09c98359af | ||
|
|
6f8a7471c2 | ||
|
|
4c141fe47c | ||
|
|
b37ff348fb | ||
|
|
09798d33b0 | ||
|
|
717ab95fbe | ||
|
|
3f616e3608 | ||
|
|
c590157561 | ||
|
|
2b50431081 | ||
|
|
6d38e44f91 | ||
|
|
9bc656a5c5 | ||
|
|
700bb9b567 | ||
|
|
8ccda81d9a | ||
|
|
3818790ced | ||
|
|
c34ce389a4 | ||
|
|
15718cdb46 | ||
|
|
10746a454a | ||
|
|
f0fd02e81f | ||
|
|
bfaac6d164 | ||
|
|
a909f1012a | ||
|
|
201581a07c | ||
|
|
8cef5ecf7e | ||
|
|
2c1075f471 | ||
|
|
1f5e08fdc6 | ||
|
|
c0408045ef | ||
|
|
c58f5a6ca7 | ||
|
|
ae445c9343 | ||
|
|
ad7ff2ba0b | ||
|
|
4b7ef6e853 | ||
|
|
87f2acc2d9 | ||
|
|
ec2fef02ed | ||
|
|
ebe0d74dbe | ||
|
|
029dc51f8b | ||
|
|
3fc85cd7b2 | ||
|
|
a46bdef079 | ||
|
|
3de489f693 | ||
|
|
eddb9eee46 | ||
|
|
5b0c96cd6d | ||
|
|
15ac77107f | ||
|
|
a7c906091c | ||
|
|
de870c546c | ||
|
|
2f3427e6ad | ||
|
|
203426bd55 | ||
|
|
16242080e0 | ||
|
|
57655d8859 | ||
|
|
62ffd57108 | ||
|
|
8db05f47b5 | ||
|
|
c684761eef | ||
|
|
0a8ece8c9c | ||
|
|
01058bde1b | ||
|
|
9c2c03cddb | ||
|
|
f0778a83a0 | ||
|
|
b86ae1f122 | ||
|
|
dfd6831b02 | ||
|
|
a4ddc13c1a | ||
|
|
fd63a1b7c2 | ||
|
|
d83c3689d0 | ||
|
|
d52bf9d318 | ||
|
|
80f56dec15 | ||
|
|
358c226b96 | ||
|
|
9de9983416 | ||
|
|
c9da4fcaf1 | ||
|
|
932ca6f9d4 | ||
|
|
4487c9985c | ||
|
|
a53ce99977 | ||
|
|
5444719895 | ||
|
|
b66139281d | ||
|
|
8925c27eb9 | ||
|
|
99be346387 | ||
|
|
81d46ba8ee | ||
|
|
ef4c467b20 | ||
|
|
44d196fb8c | ||
|
|
867c4fff58 | ||
|
|
5643546117 | ||
|
|
549832ba96 | ||
|
|
a8744b2bb4 | ||
|
|
e292d3444c | ||
|
|
ee6a1da709 | ||
|
|
8c15bc746b | ||
|
|
aebb083180 | ||
|
|
5438549b6d | ||
|
|
0077708235 | ||
|
|
2fd99ec9f3 | ||
|
|
0d266c4990 | ||
|
|
0982675b5f | ||
|
|
3bac5d3c80 | ||
|
|
58338f4848 | ||
|
|
9c261d3a3f | ||
|
|
5441ac6640 | ||
|
|
015b04a29a | ||
|
|
12ec0abf54 | ||
|
|
c8d461cdee | ||
|
|
faecffeadd | ||
|
|
b3c76c21b4 | ||
|
|
1697735162 | ||
|
|
ecb94bac6d | ||
|
|
7ebeacf16e | ||
|
|
d0079ab66b | ||
|
|
147e400bd6 | ||
|
|
c44905ea5e | ||
|
|
98b9df06fe | ||
|
|
02473080a5 | ||
|
|
c6beb9dc0a | ||
|
|
dcce14b122 | ||
|
|
a2ac24ac74 | ||
|
|
600f812f45 | ||
|
|
e945f46f25 | ||
|
|
c78c653b0a | ||
|
|
e0b3663239 | ||
|
|
3cc9c98040 | ||
|
|
ec8213b891 | ||
|
|
ae61383742 | ||
|
|
cc90a2ad75 | ||
|
|
28634cda56 | ||
|
|
3b71fcd690 | ||
|
|
5923ac65df | ||
|
|
faffc9393d | ||
|
|
6da220f36c | ||
|
|
21d78671d6 | ||
|
|
af5a0ec0b7 | ||
|
|
ff214455a3 | ||
|
|
3e941e3e42 | ||
|
|
2f876d553f | ||
|
|
b208017117 | ||
|
|
a1dab94a61 | ||
|
|
e55b2afd60 | ||
|
|
535c3ddf6c | ||
|
|
3008d99fcd | ||
|
|
fd37339e2f | ||
|
|
e29eca203c | ||
|
|
f1fd6dcdd2 | ||
|
|
2975ed2eae | ||
|
|
5a27d03faa | ||
|
|
8bcf9dbcaf | ||
|
|
56ebd26361 | ||
|
|
b0426b81a7 | ||
|
|
368fbcdeb0 | ||
|
|
30747b7776 | ||
|
|
4eb4ddf5d8 | ||
|
|
b1d24680b2 | ||
|
|
ef38f3805e | ||
|
|
2f5ca20ca4 | ||
|
|
f29d3d84d4 | ||
|
|
02132c5fcd | ||
|
|
7057e3c6ad | ||
|
|
a8f4c8e843 | ||
|
|
a2b6e66a13 | ||
|
|
e3b3cc2896 | ||
|
|
a5b2c50f24 | ||
|
|
5ebdf64d30 | ||
|
|
2640ab2e8b | ||
|
|
e29436da04 | ||
|
|
7b35325f9a | ||
|
|
f2ab7fafcf | ||
|
|
e3cda9905a | ||
|
|
a8423f7741 | ||
|
|
5a9e620c17 | ||
|
|
9f41ec3986 | ||
|
|
5a2c0672d4 | ||
|
|
38d853b5b2 | ||
|
|
5166d4bb0f | ||
|
|
2ffd5437a9 | ||
|
|
797830ff96 | ||
|
|
008ecabd21 | ||
|
|
2cdcde8a5e | ||
|
|
e7ec3988e2 | ||
|
|
093dd9f3ef | ||
|
|
b491202ec7 | ||
|
|
8603ca827e | ||
|
|
6b148a59da | ||
|
|
de6d45fee6 | ||
|
|
65e2071937 | ||
|
|
8a6242d9ea | ||
|
|
82294b68eb | ||
|
|
c232de1996 | ||
|
|
dc18c8178d | ||
|
|
6662714277 | ||
|
|
c404a0d1a9 | ||
|
|
990da2b412 | ||
|
|
1b974379c8 | ||
|
|
835faf9773 | ||
|
|
80deecb73e | ||
|
|
64328ab9cc | ||
|
|
eafad942e7 | ||
|
|
eb5a3168b9 | ||
|
|
ac8225d8fb | ||
|
|
6f71e4ada0 | ||
|
|
7ed90cddf8 | ||
|
|
283ba83cef | ||
|
|
468c66e842 | ||
|
|
f22862b0a4 | ||
|
|
9e731cb67a | ||
|
|
7f911b61a2 | ||
|
|
cace4a9bfd | ||
|
|
0992e97a1a | ||
|
|
eee101f279 | ||
|
|
4b9f204951 | ||
|
|
019804407b | ||
|
|
65b54ced7a | ||
|
|
a308114b2f | ||
|
|
41da023bdd | ||
|
|
19fcb6a82c | ||
|
|
14c837ad05 | ||
|
|
9da634e225 | ||
|
|
0d91116e62 | ||
|
|
a31a8a03c1 | ||
|
|
e8d5210606 | ||
|
|
7b11e29122 | ||
|
|
df7f693cf4 | ||
|
|
14ddc2f629 | ||
|
|
6669d0e59d | ||
|
|
8d80176a79 | ||
|
|
e1dc302592 | ||
|
|
84dbe39185 | ||
|
|
4af2c31dab | ||
|
|
332f05b6e1 | ||
|
|
8b4786ad18 | ||
|
|
7e8aaffb92 | ||
|
|
7720d42584 | ||
|
|
293b76f04b | ||
|
|
a1b0c0bbd4 | ||
|
|
46d3204bc3 | ||
|
|
c25ff57b61 | ||
|
|
71e61f8f27 | ||
|
|
6914a6132c | ||
|
|
b72916187a | ||
|
|
7c9bbe6aef | ||
|
|
27eeb0a636 | ||
|
|
cf436962f8 | ||
|
|
7fb7a1ac85 | ||
|
|
15a714faed | ||
|
|
ea2412d3a7 | ||
|
|
40321856f2 | ||
|
|
262ae7865b | ||
|
|
84cc86bef7 | ||
|
|
1ba27730d6 | ||
|
|
6568cee2e8 | ||
|
|
5496a60f62 | ||
|
|
5c7378cf94 | ||
|
|
fe15f44e96 | ||
|
|
273d762cd3 | ||
|
|
211030b5b6 | ||
|
|
212c553904 | ||
|
|
dffe4f4451 | ||
|
|
fd99af5fe6 | ||
|
|
aee539bbef | ||
|
|
e7cdc9cf8c | ||
|
|
2443547b3b | ||
|
|
8424300b5f | ||
|
|
81822cf7f6 | ||
|
|
907956994f | ||
|
|
9246cc0607 | ||
|
|
9f81d147d1 | ||
|
|
b9bd26b2fb | ||
|
|
1838174678 | ||
|
|
0880a3380c | ||
|
|
2aad301938 | ||
|
|
e18e8e3158 | ||
|
|
ff55cc1a2a | ||
|
|
d081b9e182 | ||
|
|
5e5b9f0990 | ||
|
|
97577e835e | ||
|
|
732ca8be56 | ||
|
|
1381a34752 | ||
|
|
dd96712c2a | ||
|
|
2ad0aba382 | ||
|
|
8e77eb0519 | ||
|
|
049dae6584 | ||
|
|
1fffc67d13 | ||
|
|
8500781cd5 | ||
|
|
6a8bf2acc5 | ||
|
|
c45a769aa3 | ||
|
|
16d2e27d05 | ||
|
|
10c948d33c | ||
|
|
7ccd32dfbd | ||
|
|
99c99b9218 | ||
|
|
e0b0617ad2 | ||
|
|
5add723852 | ||
|
|
14ec6f6471 | ||
|
|
c4a1341aa9 | ||
|
|
fc68dfd7bc | ||
|
|
436fc545c0 | ||
|
|
023d781daf | ||
|
|
576c0048d0 | ||
|
|
4f79cdad50 | ||
|
|
954cae8738 | ||
|
|
b203ad63ee | ||
|
|
a560be11ed | ||
|
|
506a1e6b62 | ||
|
|
626601f6aa | ||
|
|
9ad32125c0 | ||
|
|
ebd6375672 | ||
|
|
502731d3b0 | ||
|
|
283535c429 | ||
|
|
5cef1f6730 | ||
|
|
7d14fbe739 | ||
|
|
e9e1e350eb | ||
|
|
566e42cc40 | ||
|
|
0abfb5922a | ||
|
|
4af8d2f1c5 | ||
|
|
d2d4f73834 | ||
|
|
53fce4e81d | ||
|
|
08c439b46e | ||
|
|
934eb9fc1d | ||
|
|
fd208a3879 | ||
|
|
10b131e111 | ||
|
|
c4c6faa943 | ||
|
|
c7a8d1e1b7 | ||
|
|
b36ac1b824 | ||
|
|
bc6cb492f1 | ||
|
|
ce503cedc3 | ||
|
|
c900c9cc82 | ||
|
|
87b73f26f5 | ||
|
|
221a18c119 | ||
|
|
be529655d6 | ||
|
|
2a0403a988 | ||
|
|
815e23b930 | ||
|
|
f1c08e7769 | ||
|
|
571f028ca3 | ||
|
|
16d51fe6b4 | ||
|
|
ddf9ed06ab | ||
|
|
1907f80024 | ||
|
|
8c0ccdd227 | ||
|
|
dc098025b6 | ||
|
|
c11222b5c7 | ||
|
|
03bc6eb69b | ||
|
|
1aa339de02 | ||
|
|
531bb2a968 | ||
|
|
800dbf3ba9 | ||
|
|
ff545e6ecd | ||
|
|
961fe38c7e | ||
|
|
19426394e2 | ||
|
|
069a4e8f0b | ||
|
|
a76b02b828 | ||
|
|
fbb9bf5f0c | ||
|
|
f632c355e8 | ||
|
|
e75caf5833 | ||
|
|
b0c8f2cefd | ||
|
|
2136d9f13d | ||
|
|
83fdeb7e0c | ||
|
|
26c77b3118 | ||
|
|
578d445ecb | ||
|
|
3bbc9517af | ||
|
|
a4d7f278cf | ||
|
|
bf0ffc6ac2 | ||
|
|
ace07cd9cb | ||
|
|
a341179426 | ||
|
|
298f0dfd63 | ||
|
|
b8f953cd26 | ||
|
|
a9cfe69ba7 | ||
|
|
b3e0b99e8d | ||
|
|
5bd40baed2 | ||
|
|
d3a70b8bb2 | ||
|
|
71e698603d | ||
|
|
659ead903c | ||
|
|
070c435f40 | ||
|
|
b668a526e3 | ||
|
|
01287d0669 | ||
|
|
ff481d759f | ||
|
|
71248f1708 | ||
|
|
0a0f834f23 | ||
|
|
06cad7ecd8 | ||
|
|
ceba3e2f95 | ||
|
|
61c2fd8794 | ||
|
|
db933fee4f | ||
|
|
2656c2dc40 | ||
|
|
01cfe33865 | ||
|
|
d79a31cc79 | ||
|
|
9efab8b892 | ||
|
|
aae845247a | ||
|
|
3f45a9a75f | ||
|
|
c9016155ae | ||
|
|
1019e8f4af | ||
|
|
8e423b4552 | ||
|
|
0e288c955c | ||
|
|
465dc8a66c | ||
|
|
7e5c599cc0 | ||
|
|
a961001a4b | ||
|
|
0a181f6407 | ||
|
|
27a347db34 | ||
|
|
b228dbb2df | ||
|
|
09cffc4340 | ||
|
|
e79880d305 | ||
|
|
34266761d1 | ||
|
|
77f17eaa3e | ||
|
|
ac70342cb3 | ||
|
|
d2f16dcaf3 | ||
|
|
abcce2bf68 | ||
|
|
514487074b | ||
|
|
f014e2473f | ||
|
|
80981f7027 | ||
|
|
8e6e971b51 | ||
|
|
4bd3b889dc | ||
|
|
464787dc1e | ||
|
|
a2541a9659 | ||
|
|
099dd87241 | ||
|
|
38eb914420 | ||
|
|
162215b1cf | ||
|
|
c6883f7a92 | ||
|
|
584286b794 | ||
|
|
a48713b7ca | ||
|
|
8f10c2d8bf | ||
|
|
5c0de9aa1c | ||
|
|
5553fd6538 | ||
|
|
e3ed47b37c | ||
|
|
976353d770 | ||
|
|
6fc216dff5 | ||
|
|
3f3961d255 | ||
|
|
875637bc6d | ||
|
|
395333cb3d | ||
|
|
870d039541 | ||
|
|
e8c8bece3f | ||
|
|
bd2f5dd6fe | ||
|
|
73f78d47ae | ||
|
|
8f60755f02 | ||
|
|
44c455419b | ||
|
|
129bc9b3ae | ||
|
|
08ba7dd065 | ||
|
|
dd2cf50a39 | ||
|
|
06eeced5b2 | ||
|
|
be23e5709d | ||
|
|
2735185eb9 | ||
|
|
41dd0acfa3 | ||
|
|
115a2df2b0 | ||
|
|
fcbb3aeed1 | ||
|
|
e9cb85127a | ||
|
|
c9c703fe98 | ||
|
|
0141dfbea2 | ||
|
|
fb7dafbc39 | ||
|
|
0660f9a511 | ||
|
|
a39ae5a8c5 | ||
|
|
03e22e3dbf | ||
|
|
d5e9fd0e5c | ||
|
|
141138ebea | ||
|
|
9026efeb26 | ||
|
|
2ab023beb0 | ||
|
|
8e471fd720 | ||
|
|
13cbbd8bc1 | ||
|
|
b08ccc9767 | ||
|
|
801a7023a4 | ||
|
|
dd06b554da | ||
|
|
23f0504b30 | ||
|
|
262d172cde | ||
|
|
be81cb7876 | ||
|
|
aaf9bd33cb | ||
|
|
7381e2141f | ||
|
|
3923d941c1 | ||
|
|
d134c33499 | ||
|
|
a2b615d4a7 | ||
|
|
37ecd9bd4f | ||
|
|
2e1acb7871 | ||
|
|
2250185487 | ||
|
|
97a1bf90a4 | ||
|
|
73cb63c9f9 | ||
|
|
f61f6b6006 | ||
|
|
7d3ffbc45a | ||
|
|
93ac6fa88a | ||
|
|
09d19a13b7 | ||
|
|
9eaee8d2c4 | ||
|
|
4da0c342f8 | ||
|
|
70fed22737 | ||
|
|
acb62e347a | ||
|
|
78d06d82d6 | ||
|
|
4777bdd250 | ||
|
|
266e9d92d5 | ||
|
|
54c14d0dc8 | ||
|
|
d59d353c2e | ||
|
|
204da2175b | ||
|
|
a8f659f2ac | ||
|
|
a878ebc368 | ||
|
|
152f235ca1 | ||
|
|
d094709dc8 | ||
|
|
97d5792341 | ||
|
|
9429ba7d48 | ||
|
|
af89dd13c1 | ||
|
|
60c6c5b37a | ||
|
|
5ed40cab1d | ||
|
|
1bebfe9cf2 | ||
|
|
e2618c37a2 | ||
|
|
f2ab848c46 | ||
|
|
93b82c0e97 | ||
|
|
4ac5ad06f2 | ||
|
|
a3788038bb | ||
|
|
12af2de99e | ||
|
|
225b722b1b | ||
|
|
1d9c8ca65e | ||
|
|
e51ffe2a1c | ||
|
|
c706a79f74 | ||
|
|
2608061d48 | ||
|
|
df1634de3d | ||
|
|
4aeabea3fe | ||
|
|
eb30f9d5bf | ||
|
|
de718f847c | ||
|
|
8ee6588d46 | ||
|
|
7c25f087fb | ||
|
|
d0b0f098d9 | ||
|
|
8835e20bfc | ||
|
|
92258f3ba3 | ||
|
|
1bda7595dd | ||
|
|
60557fc8c8 | ||
|
|
1a4a7831f6 | ||
|
|
d1415a8c53 | ||
|
|
0d4f33ac6e | ||
|
|
87100bef7b | ||
|
|
958dfa8ae9 | ||
|
|
d3752573e7 | ||
|
|
cfd07cbcc8 | ||
|
|
33e6ce1673 | ||
|
|
00ccda83f9 | ||
|
|
8d66cce6eb | ||
|
|
ba35fb7525 | ||
|
|
4fd2b24b10 | ||
|
|
5f7a33b085 | ||
|
|
65bc5b1f31 | ||
|
|
dd155e9f89 | ||
|
|
5c4ef3b0f5 | ||
|
|
2129a48cc8 | ||
|
|
c0f2784599 | ||
|
|
fee00b2acb | ||
|
|
ae8093313e | ||
|
|
5a4e321f78 | ||
|
|
9d1ed241b9 | ||
|
|
b63cd241d2 | ||
|
|
1e4f2d85a2 | ||
|
|
5cb7be4a64 | ||
|
|
0cd9068c0e | ||
|
|
9d6afe3bde | ||
|
|
52702b5267 | ||
|
|
cd144ff067 | ||
|
|
dd9784b3f2 | ||
|
|
d781b3d4a7 | ||
|
|
790f490674 | ||
|
|
004a5cb765 | ||
|
|
408b2d8376 | ||
|
|
3aa53ff3be | ||
|
|
73b642799d | ||
|
|
b522500379 | ||
|
|
f736ed401f | ||
|
|
c02f824d74 | ||
|
|
6f9a61de56 | ||
|
|
4cebeda37a | ||
|
|
4275005a64 | ||
|
|
5f40ab130e | ||
|
|
7489526eb7 | ||
|
|
e439d91763 | ||
|
|
793969e39b | ||
|
|
9f7ffe8d77 | ||
|
|
eecb867227 | ||
|
|
bff9f135e6 | ||
|
|
03627281d7 | ||
|
|
c83b4093f0 | ||
|
|
7f9f22df3e | ||
|
|
fd48582a9f | ||
|
|
e5761128f9 | ||
|
|
87dd5a9ebb | ||
|
|
11950f8b4d | ||
|
|
f2ddfadc9d | ||
|
|
b1a7983f18 | ||
|
|
b319cb278b | ||
|
|
78e3d781fc | ||
|
|
34834917b0 | ||
|
|
9446c287e9 | ||
|
|
31b0cf396e | ||
|
|
00bb13c230 | ||
|
|
3bf09ee731 | ||
|
|
5b07941c4c | ||
|
|
23c30ec46d | ||
|
|
22c06300f1 | ||
|
|
37cca1b106 | ||
|
|
f0a49c806e | ||
|
|
a1d5f65588 | ||
|
|
b6789e14a4 | ||
|
|
c72ee30a25 | ||
|
|
686d667c4f | ||
|
|
26d603db5d | ||
|
|
409840aef9 | ||
|
|
1f3c264afe | ||
|
|
cd69d9a1a7 | ||
|
|
a000c8fd99 | ||
|
|
84d05603ef | ||
|
|
9d046ecd1d | ||
|
|
030e1809f3 | ||
|
|
5853bd4a96 | ||
|
|
10695ff51b | ||
|
|
f421659fea | ||
|
|
df4f51eff3 | ||
|
|
7e61d6a850 | ||
|
|
0910bd23c4 | ||
|
|
5a29753912 | ||
|
|
a467356437 | ||
|
|
094967f52a | ||
|
|
757b0812ba | ||
|
|
8f4f5d8c92 | ||
|
|
4e266483ba | ||
|
|
7433dc9cf3 | ||
|
|
409a773e36 | ||
|
|
48bdd5c3df | ||
|
|
5796057a75 | ||
|
|
c8248e91ca | ||
|
|
7317ce44e7 | ||
|
|
10e2a5b1eb | ||
|
|
e675d1b7e2 | ||
|
|
499c4dadd5 | ||
|
|
f550f84acd | ||
|
|
8021f1a7fc | ||
|
|
d50fe606ee | ||
|
|
281f014aa0 | ||
|
|
2f6da3e84a | ||
|
|
f9accc2a7a | ||
|
|
fe15078bbd | ||
|
|
27d4b5eba7 | ||
|
|
e378576632 | ||
|
|
74909da110 | ||
|
|
655bf112ac | ||
|
|
5c3638a5a4 | ||
|
|
2459a3654b | ||
|
|
e9a3456cf5 |
228
.editorconfig
228
.editorconfig
@@ -6,3 +6,231 @@ insert_final_newline = true
|
||||
charset = latin1
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
ij_java_align_multiline_annotation_parameters = false
|
||||
ij_java_align_multiline_array_initializer_expression = false
|
||||
ij_java_align_multiline_assignment = false
|
||||
ij_java_align_multiline_binary_operation = false
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_extends_list = false
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_parameters = false
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parenthesized_expression = false
|
||||
ij_java_align_multiline_resources = false
|
||||
ij_java_align_multiline_ternary_operation = false
|
||||
ij_java_align_multiline_text_blocks = false
|
||||
ij_java_align_multiline_throws_list = false
|
||||
ij_java_align_subsequent_simple_methods = false
|
||||
ij_java_align_throws_keyword = false
|
||||
ij_java_annotation_parameter_wrap = off
|
||||
ij_java_array_initializer_new_line_after_left_brace = false
|
||||
ij_java_array_initializer_right_brace_on_new_line = false
|
||||
ij_java_array_initializer_wrap = normal
|
||||
ij_java_assert_statement_colon_on_next_line = false
|
||||
ij_java_assert_statement_wrap = off
|
||||
ij_java_assignment_wrap = off
|
||||
ij_java_binary_operation_sign_on_next_line = false
|
||||
ij_java_binary_operation_wrap = off
|
||||
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||
ij_java_blank_lines_after_class_header = 0
|
||||
ij_java_blank_lines_after_imports = 1
|
||||
ij_java_blank_lines_after_package = 1
|
||||
ij_java_blank_lines_around_class = 1
|
||||
ij_java_blank_lines_around_field = 0
|
||||
ij_java_blank_lines_around_field_in_interface = 0
|
||||
ij_java_blank_lines_around_initializer = 1
|
||||
ij_java_blank_lines_around_method = 1
|
||||
ij_java_blank_lines_around_method_in_interface = 1
|
||||
ij_java_blank_lines_before_class_end = 0
|
||||
ij_java_blank_lines_before_imports = 1
|
||||
ij_java_blank_lines_before_method_body = 0
|
||||
ij_java_blank_lines_before_package = 0
|
||||
ij_java_block_brace_style = next_line_if_wrapped
|
||||
ij_java_block_comment_at_first_column = true
|
||||
ij_java_call_parameters_new_line_after_left_paren = false
|
||||
ij_java_call_parameters_right_paren_on_new_line = false
|
||||
ij_java_call_parameters_wrap = normal
|
||||
ij_java_case_statement_on_separate_line = true
|
||||
ij_java_catch_on_new_line = false
|
||||
ij_java_class_annotation_wrap = split_into_lines
|
||||
ij_java_class_brace_style = next_line
|
||||
ij_java_class_count_to_use_import_on_demand = 99
|
||||
ij_java_class_names_in_javadoc = 1
|
||||
ij_java_do_not_indent_top_level_class_members = false
|
||||
ij_java_do_not_wrap_after_single_annotation = false
|
||||
ij_java_do_while_brace_force = never
|
||||
ij_java_doc_add_blank_line_after_description = true
|
||||
ij_java_doc_add_blank_line_after_param_comments = false
|
||||
ij_java_doc_add_blank_line_after_return = false
|
||||
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||
ij_java_doc_align_exception_comments = true
|
||||
ij_java_doc_align_param_comments = true
|
||||
ij_java_doc_do_not_wrap_if_one_line = false
|
||||
ij_java_doc_enable_formatting = true
|
||||
ij_java_doc_enable_leading_asterisks = true
|
||||
ij_java_doc_indent_on_continuation = false
|
||||
ij_java_doc_keep_empty_lines = true
|
||||
ij_java_doc_keep_empty_parameter_tag = true
|
||||
ij_java_doc_keep_empty_return_tag = true
|
||||
ij_java_doc_keep_empty_throws_tag = true
|
||||
ij_java_doc_keep_invalid_tags = true
|
||||
ij_java_doc_param_description_on_new_line = false
|
||||
ij_java_doc_preserve_line_breaks = false
|
||||
ij_java_doc_use_throws_not_exception_tag = true
|
||||
ij_java_else_on_new_line = false
|
||||
ij_java_enum_constants_wrap = off
|
||||
ij_java_extends_keyword_wrap = split_into_lines
|
||||
ij_java_extends_list_wrap = normal
|
||||
ij_java_field_annotation_wrap = split_into_lines
|
||||
ij_java_finally_on_new_line = false
|
||||
ij_java_for_brace_force = never
|
||||
ij_java_for_statement_new_line_after_left_paren = false
|
||||
ij_java_for_statement_right_paren_on_new_line = false
|
||||
ij_java_for_statement_wrap = off
|
||||
ij_java_generate_final_locals = false
|
||||
ij_java_generate_final_parameters = false
|
||||
ij_java_if_brace_force = never
|
||||
ij_java_imports_layout = java.**,javax.**,*,$*
|
||||
ij_java_indent_case_from_switch = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_insert_override_annotation = true
|
||||
ij_java_keep_blank_lines_before_right_brace = 1
|
||||
ij_java_keep_blank_lines_between_package_declaration_and_header = 1
|
||||
ij_java_keep_blank_lines_in_code = 1
|
||||
ij_java_keep_blank_lines_in_declarations = 1
|
||||
ij_java_keep_control_statement_in_one_line = false
|
||||
ij_java_keep_first_column_comment = false
|
||||
ij_java_keep_indents_on_empty_lines = false
|
||||
ij_java_keep_line_breaks = false
|
||||
ij_java_keep_multiple_expressions_in_one_line = false
|
||||
ij_java_keep_simple_blocks_in_one_line = false
|
||||
ij_java_keep_simple_classes_in_one_line = false
|
||||
ij_java_keep_simple_lambdas_in_one_line = false
|
||||
ij_java_keep_simple_methods_in_one_line = false
|
||||
ij_java_label_indent_absolute = false
|
||||
ij_java_label_indent_size = 0
|
||||
ij_java_lambda_brace_style = end_of_line
|
||||
ij_java_layout_static_imports_separately = true
|
||||
ij_java_line_comment_add_space = false
|
||||
ij_java_line_comment_at_first_column = true
|
||||
ij_java_method_annotation_wrap = split_into_lines
|
||||
ij_java_method_brace_style = next_line_if_wrapped
|
||||
ij_java_method_call_chain_wrap = normal
|
||||
ij_java_method_parameters_new_line_after_left_paren = false
|
||||
ij_java_method_parameters_right_paren_on_new_line = false
|
||||
ij_java_method_parameters_wrap = normal
|
||||
ij_java_modifier_list_wrap = false
|
||||
ij_java_names_count_to_use_import_on_demand = 3
|
||||
ij_java_parameter_annotation_wrap = off
|
||||
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_java_place_assignment_sign_on_next_line = false
|
||||
ij_java_prefer_longer_names = true
|
||||
ij_java_prefer_parameters_wrap = false
|
||||
ij_java_repeat_synchronized = true
|
||||
ij_java_replace_instanceof_and_cast = false
|
||||
ij_java_replace_null_check = true
|
||||
ij_java_replace_sum_lambda_with_method_ref = true
|
||||
ij_java_resource_list_new_line_after_left_paren = false
|
||||
ij_java_resource_list_right_paren_on_new_line = false
|
||||
ij_java_resource_list_wrap = normal
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
ij_java_space_after_colon = true
|
||||
ij_java_space_after_comma = true
|
||||
ij_java_space_after_comma_in_type_arguments = true
|
||||
ij_java_space_after_for_semicolon = true
|
||||
ij_java_space_after_quest = true
|
||||
ij_java_space_after_type_cast = true
|
||||
ij_java_space_before_annotation_array_initializer_left_brace = true
|
||||
ij_java_space_before_annotation_parameter_list = false
|
||||
ij_java_space_before_array_initializer_left_brace = true
|
||||
ij_java_space_before_catch_keyword = true
|
||||
ij_java_space_before_catch_left_brace = true
|
||||
ij_java_space_before_catch_parentheses = false
|
||||
ij_java_space_before_class_left_brace = true
|
||||
ij_java_space_before_colon = true
|
||||
ij_java_space_before_colon_in_foreach = true
|
||||
ij_java_space_before_comma = false
|
||||
ij_java_space_before_do_left_brace = true
|
||||
ij_java_space_before_else_keyword = true
|
||||
ij_java_space_before_else_left_brace = true
|
||||
ij_java_space_before_finally_keyword = true
|
||||
ij_java_space_before_finally_left_brace = true
|
||||
ij_java_space_before_for_left_brace = true
|
||||
ij_java_space_before_for_parentheses = false
|
||||
ij_java_space_before_for_semicolon = false
|
||||
ij_java_space_before_if_left_brace = true
|
||||
ij_java_space_before_if_parentheses = false
|
||||
ij_java_space_before_method_call_parentheses = false
|
||||
ij_java_space_before_method_left_brace = true
|
||||
ij_java_space_before_method_parentheses = false
|
||||
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||
ij_java_space_before_quest = true
|
||||
ij_java_space_before_switch_left_brace = true
|
||||
ij_java_space_before_switch_parentheses = false
|
||||
ij_java_space_before_synchronized_left_brace = true
|
||||
ij_java_space_before_synchronized_parentheses = false
|
||||
ij_java_space_before_try_left_brace = true
|
||||
ij_java_space_before_try_parentheses = false
|
||||
ij_java_space_before_type_parameter_list = false
|
||||
ij_java_space_before_while_keyword = true
|
||||
ij_java_space_before_while_left_brace = true
|
||||
ij_java_space_before_while_parentheses = false
|
||||
ij_java_space_inside_one_line_enum_braces = false
|
||||
ij_java_space_within_empty_array_initializer_braces = false
|
||||
ij_java_space_within_empty_method_call_parentheses = false
|
||||
ij_java_space_within_empty_method_parentheses = false
|
||||
ij_java_spaces_around_additive_operators = true
|
||||
ij_java_spaces_around_assignment_operators = true
|
||||
ij_java_spaces_around_bitwise_operators = true
|
||||
ij_java_spaces_around_equality_operators = true
|
||||
ij_java_spaces_around_lambda_arrow = true
|
||||
ij_java_spaces_around_logical_operators = true
|
||||
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||
ij_java_spaces_around_multiplicative_operators = true
|
||||
ij_java_spaces_around_relational_operators = true
|
||||
ij_java_spaces_around_shift_operators = true
|
||||
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||
ij_java_spaces_around_unary_operator = false
|
||||
ij_java_spaces_within_angle_brackets = false
|
||||
ij_java_spaces_within_annotation_parentheses = true
|
||||
ij_java_spaces_within_array_initializer_braces = true
|
||||
ij_java_spaces_within_braces = false
|
||||
ij_java_spaces_within_brackets = false
|
||||
ij_java_spaces_within_cast_parentheses = false
|
||||
ij_java_spaces_within_catch_parentheses = true
|
||||
ij_java_spaces_within_for_parentheses = true
|
||||
ij_java_spaces_within_if_parentheses = true
|
||||
ij_java_spaces_within_method_call_parentheses = true
|
||||
ij_java_spaces_within_method_parentheses = true
|
||||
ij_java_spaces_within_parentheses = false
|
||||
ij_java_spaces_within_switch_parentheses = true
|
||||
ij_java_spaces_within_synchronized_parentheses = true
|
||||
ij_java_spaces_within_try_parentheses = true
|
||||
ij_java_spaces_within_while_parentheses = true
|
||||
ij_java_special_else_if_treatment = true
|
||||
ij_java_subclass_name_suffix = Impl
|
||||
ij_java_ternary_operation_signs_on_next_line = true
|
||||
ij_java_ternary_operation_wrap = on_every_item
|
||||
ij_java_test_name_suffix = Test
|
||||
ij_java_throws_keyword_wrap = normal
|
||||
ij_java_throws_list_wrap = normal
|
||||
ij_java_use_external_annotations = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_relative_indents = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_variable_annotation_wrap = off
|
||||
ij_java_visibility = public
|
||||
ij_java_while_brace_force = never
|
||||
ij_java_while_on_new_line = false
|
||||
ij_java_wrap_comments = false
|
||||
ij_java_wrap_first_method_in_call_chain = false
|
||||
ij_java_wrap_long_lines = false
|
||||
|
||||
157
.github/workflows/ci.yml
vendored
Normal file
157
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
# https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
tags:
|
||||
- '[0-9]*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
# test against
|
||||
# - Java 1.8 (minimum requirement)
|
||||
# - Java 9 (first version with JPMS)
|
||||
# - Java LTS versions (11, 17, ...)
|
||||
# - lastest Java version(s)
|
||||
java:
|
||||
- 1.8
|
||||
- 9
|
||||
- 11 # LTS
|
||||
- 14
|
||||
- 15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- name: Setup Java ${{ matrix.java }}
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: matrix.java == '11'
|
||||
with:
|
||||
name: FlatLaf-build-artifacts
|
||||
path: |
|
||||
flatlaf-core/build/libs
|
||||
flatlaf-demo/build/libs
|
||||
flatlaf-extras/build/libs
|
||||
flatlaf-intellij-themes/build/libs
|
||||
flatlaf-jide-oss/build/libs
|
||||
flatlaf-swingx/build/libs
|
||||
!**/*-javadoc.jar
|
||||
!**/*-sources.jar
|
||||
|
||||
|
||||
snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: |
|
||||
github.event_name == 'push' &&
|
||||
github.ref == 'refs/heads/master' &&
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Publish snapshot to oss.sonatype.org
|
||||
run: ./gradlew publish -Dorg.gradle.internal.publish.checksums.insecure=true
|
||||
env:
|
||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: |
|
||||
github.event_name == 'push' &&
|
||||
startsWith( github.ref, 'refs/tags/' ) &&
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache Gradle wrapper
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Release a new stable version to Maven Central
|
||||
run: ./gradlew publish :flatlaf-demo:build -Drelease=true
|
||||
env:
|
||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
|
||||
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
|
||||
|
||||
- name: Upload demo
|
||||
uses: sebastianpopp/ftp-action@releases/v2
|
||||
with:
|
||||
host: ${{ secrets.FTP_SERVER }}
|
||||
user: ${{ secrets.FTP_USERNAME }}
|
||||
password: ${{ secrets.FTP_PASSWORD }}
|
||||
forceSsl: true
|
||||
localDir: "flatlaf-demo/build/libs"
|
||||
remoteDir: "."
|
||||
options: "--only-newer --no-recursion --verbose=1"
|
||||
29
.travis.yml
29
.travis.yml
@@ -1,29 +0,0 @@
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- openjdk8
|
||||
- openjdk9
|
||||
- openjdk11
|
||||
- openjdk13
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
before_install:
|
||||
- ./gradlew --version
|
||||
- java -version
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: ./gradlew bintrayUpload
|
||||
skip_cleanup: true # to upload artifacts created during the build
|
||||
on:
|
||||
branch: master
|
||||
jdk: openjdk11
|
||||
tags: true
|
||||
670
CHANGELOG.md
670
CHANGELOG.md
@@ -1,6 +1,676 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 1.0
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Extras: UI Inspector: Tooltip is no longer limited to window bounds.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- TabbedPane: Custom `TabbedPane.selectedForeground` color did not work when
|
||||
`TabbedPane.foreground` has also custom color. (issue #257)
|
||||
- FileChooser: Fixed display of date in details view if current user is selected
|
||||
in "Look in" combobox. (Windows 10 only; issue #249)
|
||||
- Table: Fixed wrong grid line thickness in dragged column on HiDPI screens on
|
||||
Java 9+. (issue #236)
|
||||
- PopupFactory: Fixed `NullPointerException` when `PopupFactory.getPopup()` is
|
||||
invoked with parameter `owner` set to `null`.
|
||||
|
||||
|
||||
## 1.0-rc3
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Extras:
|
||||
- UI Inspector: Use HTML in tooltip. Display color value in same format as
|
||||
used in FlatLaf properties files. Added color preview.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Label and ToolTip: Fixed font sizes for `<code>`, `<kbd>`, `<big>`, `<small>`
|
||||
and `<samp>` tags in HTML text.
|
||||
- Fixed color of `<address>` tag in HTML text.
|
||||
- IntelliJ Themes: Fixed table header background when dragging column in "Dark
|
||||
Flat" and "Light Flat" themes.
|
||||
- CheckBox: Fixed background of check boxes in JIDE `CheckBoxTree`. (regression
|
||||
in 1.0-rc2)
|
||||
|
||||
|
||||
## 1.0-rc2
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Button:
|
||||
- In "Flat Light" theme, use a slightly thinner border for focused buttons
|
||||
(because they already have light blue background).
|
||||
- In "Flat Dark" theme, use slightly wider border for focused buttons.
|
||||
- CheckBox and RadioButton: In "Flat Dark" theme, use blueish background for
|
||||
focused components.
|
||||
- Tree: Support disabling wide selection per component. (set client property
|
||||
`JTree.wideSelection` to `false`). (PR #245)
|
||||
- Tree: Support disabling selection painting per component. Then the tree cell
|
||||
renderer is responsible for selection painting. (set client property
|
||||
`JTree.paintSelection` to `false`).
|
||||
- JIDE Common Layer: Support `JidePopupMenu`.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Button: Fixed behavior of <kbd>Enter</kbd> key on focused button on Windows
|
||||
and Linux, which now clicks the focused button (instead of the default
|
||||
button).
|
||||
- On Windows, this is a regression in 1.0-rc1.
|
||||
- On macOS, the <kbd>Enter</kbd> key always clicks the default button, which
|
||||
is the platform behavior.
|
||||
- On all platforms, the default button can be always clicked with
|
||||
<kbd>Ctrl+Enter</kbd> keys, even if another button is focused.
|
||||
- CheckBox and RadioButton: Fill component background as soon as background
|
||||
color is different to default background color, even if component is not
|
||||
opaque (which is the default). This paints selection if using the component as
|
||||
cell renderer a Table, Tree or List.
|
||||
- TextComponents: Border of focused non-editable text components had wrong
|
||||
color.
|
||||
- Custom window decorations: Fixed top window border in dark themes when running
|
||||
in JetBrains Runtime.
|
||||
|
||||
|
||||
## 1.0-rc1
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Button: Disabled `Button.defaultButtonFollowsFocus` on Windows (as on other
|
||||
platforms). If you like to keep the old behavior in your application, use:
|
||||
`if(SystemInfo.isWindows)
|
||||
UIManager.put("Button.defaultButtonFollowsFocus",true);`.
|
||||
- ComboBox, Spinner and SplitPaneDivider: Added pressed feedback to arrow
|
||||
buttons.
|
||||
- Slider: Support per component custom thumb and track colors via
|
||||
`JSlider.setForeground(Color)` and `JSlider.setBackground(Color)`.
|
||||
- Slider: Improved thumb hover and pressed colors.
|
||||
- TextComponent: Clip placeholder text if it does not fit into visible area. (PR
|
||||
#229)
|
||||
- macOS: Improved font rendering on macOS when using JetBrains Runtime. (PRs
|
||||
#237, #239 and #241)
|
||||
- Extras: UI defaults inspector:
|
||||
- Support embedding UI defaults inspector panel into any window. See
|
||||
`FlatUIDefaultsInspector.createInspectorPanel()`.
|
||||
- Copy selected keys and values into clipboard via context menu.
|
||||
- Support wildcard matching in filter (`*` matches any number of characters,
|
||||
`?` matches a single character, `^` beginning of line, `$` end of line).
|
||||
- IntelliJ Themes:
|
||||
- Added hover and pressed feedback to Button, CheckBox, RadioButton and
|
||||
ToggleButton. (issue #176)
|
||||
- Added "Material Theme UI Lite / Moonlight" theme.
|
||||
- Updated "Dracula", "Gradianto" and "Material Theme UI Lite" themes.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Button and ToggleButton: Threat Unicode surrogate character pair as single
|
||||
character and make button square. (issue #234)
|
||||
- Button and ToggleButton: ToolBar buttons now respect explicitly set background
|
||||
color. If no background color is set, then the button background is not
|
||||
painted anymore. (issue #191)
|
||||
- ToggleButton: Tab style buttons (client property `JButton.buttonType` is
|
||||
`tab`) now respect explicitly set background color.
|
||||
- TabbedPane: Fixed `IndexOutOfBoundsException` when using tooltip text on close
|
||||
buttons and closing last/rightmost tab. (issue #235)
|
||||
- TabbedPane: Fixed scrolling tabs with touchpads and high-resolution mouse
|
||||
wheels.
|
||||
- Extras: Added missing export of package
|
||||
`com.formdev.flatlaf.extras.components` to Java 9 module descriptor.
|
||||
- JIDE Common Layer:
|
||||
- Invoke `LookAndFeelFactory.installJideExtension()` when using FlatLaf UI
|
||||
delegates. (issue #230)
|
||||
- RangeSlider: Fixed slider focused colors in IntelliJ themes.
|
||||
- IntelliJ Themes:
|
||||
- Fixed menu item check colors.
|
||||
- Fixed `MenuItem.underlineSelectionColor`.
|
||||
- Fixed List, Tree and Table `selectionInactiveForeground` in light Arc
|
||||
themes.
|
||||
- Fixed List and Table background colors in Material UI Lite themes.
|
||||
- Fixed menu accelerator colors in Monocai theme. (issue #243)
|
||||
|
||||
|
||||
## 0.46
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Slider and JIDE RangeSlider: Clicking on track now immediately moves the thumb
|
||||
to mouse location and starts dragging the thumb. Use `UIManager.put(
|
||||
"Slider.scrollOnTrackClick", true )` to enable old behavior that scrolls the
|
||||
thumb when clicking on track.
|
||||
- Slider: Snap to ticks is now done while dragging the thumb. Use
|
||||
`UIManager.put( "Slider.snapToTicksOnReleased", true )` to enable old behavior
|
||||
that snaps to ticks on mouse released.
|
||||
- Extras: Added standard component extension classes that provides easy access
|
||||
to FlatLaf specific client properties (see package
|
||||
`com.formdev.flatlaf.extras.components`).
|
||||
- Extras: Renamed tri-state check box class from
|
||||
`com.formdev.flatlaf.extras.TriStateCheckBox` to
|
||||
`com.formdev.flatlaf.extras.components.FlatTriStateCheckBox`. Also
|
||||
changed/improved API and added javadoc.
|
||||
- Extras: Renamed SVG utility class from `com.formdev.flatlaf.extras.SVGUtils`
|
||||
to `com.formdev.flatlaf.extras.FlatSVGUtils`.
|
||||
- IntelliJ Themes: Added flag whether a theme is dark to
|
||||
`FlatAllIJThemes.INFOS`. (issue #221)
|
||||
- JIDE Common Layer: Support `TristateCheckBox`.
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Slider: Fixed painting of colored track if `JSlider.inverted` is `true`.
|
||||
- Table and TableHeader: Fixed missing right vertical grid line if using table
|
||||
as row header in scroll pane. (issues #152 and #46)
|
||||
- TableHeader: Fixed position of column separators in right-to-left component
|
||||
orientation.
|
||||
- ToolTip: Fixed drop shadow for wide tooltips on Windows and Java 9+. (issue
|
||||
#224)
|
||||
- SwingX: Fixed striping background highlighting color (e.g. alternating table
|
||||
rows) in dark themes.
|
||||
- Fixed: If text antialiasing is disabled (in OS system settings or via
|
||||
`-Dawt.useSystemAAFontSettings=off`), then some components still did use
|
||||
antialiasing to render text (not-editable ComboBox, ProgressBar, Slider,
|
||||
TabbedPane and multiline ToolTip). (issue #227)
|
||||
|
||||
|
||||
## 0.45
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Slider: New design, added hover and pressed feedback and improved customizing.
|
||||
(PR #214)
|
||||
- JIDE Common Layer: Support `RangeSlider`. (PR #209)
|
||||
- IntelliJ Themes:
|
||||
- Added "Gradianto Nature Green" theme.
|
||||
- Updated "Arc Dark", "Cyan", "Dark purple", "Gradianto", "Gray", "Gruvbox"
|
||||
and "One Dark" themes.
|
||||
- TabbedPane: Support hiding tab area if it contains only one tab. (set client
|
||||
property `JTabbedPane.hideTabAreaWithOneTab` to `true`)
|
||||
- MenuBar: Support different underline menu selection style UI defaults for
|
||||
`MenuBar` and `MenuItem`. (PR #217; issue #216)
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Table: Do not paint last vertical grid line if auto-resize mode is not off.
|
||||
(issue #46)
|
||||
- Table: Fixed unstable grid line thickness when scaled on HiDPI screens. (issue
|
||||
#152)
|
||||
- TabbedPane: No longer add (internal) tab close button component as child to
|
||||
`JTabbedPane`. (issue #219)
|
||||
- Custom window decorations: Title bar was not hidden if window is in
|
||||
full-screen mode. (issue #212)
|
||||
|
||||
|
||||
## 0.44
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TabbedPane: In scroll tab layout, added "Show Hidden Tabs" button to trailing
|
||||
side of tab area. If pressed, it shows a popup menu that contains (partly)
|
||||
hidden tabs and selecting one activates that tab. (PR #190; issue #40)
|
||||
- TabbedPane: Support forward/backward scroll arrow buttons on both sides of tab
|
||||
area. Backward button on left side, forward button on right side. Not
|
||||
applicable scroll buttons are hidden. (PR #211; issue #40)
|
||||
- TabbedPane: Support specifying default tab layout policy for all tabbed panes
|
||||
in the application via UI value `TabbedPane.tabLayoutPolicy`. E.g. invoke
|
||||
`UIManager.put( "TabbedPane.tabLayoutPolicy", "scroll" );` to use scroll
|
||||
layout.
|
||||
- TabbedPane: Support tab scrolling with mouse wheel (in scroll tab layout). (PR
|
||||
#187; issue #40)
|
||||
- TabbedPane: Repeat scrolling as long as scroll arrow buttons are pressed. (PR
|
||||
#187; issue #40)
|
||||
- TabbedPane: Support adding custom components to left and right sides of tab
|
||||
area. (set client property `JTabbedPane.leadingComponent` or
|
||||
`JTabbedPane.trailingComponent` to a `java.awt.Component`) (PR #192; issue
|
||||
#40)
|
||||
- TabbedPane: Support closable tabs. (PR #193; issues #31 and #40)
|
||||
- TabbedPane: Support minimum or maximum tab widths. (set client property
|
||||
`JTabbedPane.minimumTabWidth` or `JTabbedPane.maximumTabWidth` to an integer)
|
||||
(PR #199)
|
||||
- TabbedPane: Support alignment of tab area. (set client property
|
||||
`JTabbedPane.tabAreaAlignment` to `"leading"`, `"trailing"`, `"center"` or
|
||||
`"fill"`) (PR #199)
|
||||
- TabbedPane: Support horizontal alignment of tab title and icon. (set client
|
||||
property `JTabbedPane.tabAlignment` to `SwingConstants.LEADING`,
|
||||
`SwingConstants.TRAILING` or `SwingConstants.CENTER`)
|
||||
- TabbedPane: Support equal and compact tab width modes. (set client property
|
||||
`JTabbedPane.tabWidthMode` to `"preferred"`, `"equal"` or `"compact"`) (PR
|
||||
#199)
|
||||
- TabbedPane: Support left, right, top and bottom tab icon placement. (set
|
||||
client property `JTabbedPane.tabIconPlacement` to `SwingConstants.LEADING`,
|
||||
`SwingConstants.TRAILING`, `SwingConstants.TOP` or `SwingConstants.BOTTOM`)
|
||||
(PR #199)
|
||||
- Support painting separator line between window title and content (use UI value
|
||||
`TitlePane.borderColor`). (issue #184)
|
||||
- Extras: `FlatSVGIcon` now allows specifying icon width and height in
|
||||
constructors. (issue #196)
|
||||
- SplitPane: Hide not applicable expand/collapse buttons. Added tooltips to
|
||||
expand/collapse buttons. (issue #198)
|
||||
- SplitPane: Added grip to divider. Can be disabled with `UIManager.put(
|
||||
"SplitPaneDivider.style", "plain" )`. (issue #179)
|
||||
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Not visible menu bar is now ignored in layout.
|
||||
- Popups using `JToolTip` components did not respect their location. (issue
|
||||
#188; regression in 0.42 in fix for #164)
|
||||
- IntelliJ Themes: Added suffix "(Material)" to names of all Material UI Lite
|
||||
themes to avoid duplicate theme names. (issue #201)
|
||||
- Extras: `FlatSVGIcon` icons were not painted in disabled labels and disabled
|
||||
tabs. (issue #205)
|
||||
|
||||
|
||||
## 0.43
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TabbedPane: Made tabs separator color lighter in dark themes so that it is
|
||||
easier to recognize the tabbed pane.
|
||||
- TabbedPane: Added top and bottom tab insets to avoid that large tab icons are
|
||||
painted over active tab underline.
|
||||
- TabbedPane: Support hiding separator between tabs and content area (set client
|
||||
property `JTabbedPane.showContentSeparator` to `false`).
|
||||
- CheckBoxMenuItem and RadioButtonMenuItem: Improved checkmark background colors
|
||||
of selected menu items that have also an icon. This makes it is easier to
|
||||
recognize selected menu items.
|
||||
- Windows: Made scaling compatible with Windows OS scaling, which distinguish
|
||||
between "screen scaling" and "text scaling". (issue #175)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- ComboBox: If using own `JTextField` as editor, default text field border is
|
||||
now removed to avoid duplicate border.
|
||||
- ComboBox: Limit popup width to screen width for very long items. (issue #182)
|
||||
- FileChooser: Fixed localizing special Windows folders (e.g. "Documents") and
|
||||
enabled hiding known file extensions (if enabled in Windows Explorer). (issue
|
||||
#178)
|
||||
- Spinner: Fixed `NullPointerException` in case that arrow buttons were removed
|
||||
to create button-less spinner. (issue #181)
|
||||
|
||||
|
||||
## 0.42
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Demo: Improved "SplitPane & Tabs" and "Data Components" tabs.
|
||||
- Demo: Menu items "File > Open" and "File > Save As" now show file choosers.
|
||||
- InternalFrame: Support draggable border for resizing frame inside of the
|
||||
visible frame border. (issue #121)
|
||||
- `FlatUIDefaultsInspector` added (see [FlatLaf Extras](flatlaf-extras)). A
|
||||
simple UI defaults inspector that shows a window with all UI defaults used in
|
||||
current theme (look and feel).
|
||||
- Made disabled text color slightly lighter in dark themes for better
|
||||
readability. (issue #174)
|
||||
- PasswordField: Support disabling Caps Lock warning icon. (issue #172)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- TextComponents: Fixed text color of disabled text components in dark themes.
|
||||
- Custom window decorations: Fixed wrong window placement when moving window to
|
||||
another screen with different scaling factor. (issue #166)
|
||||
- Custom window decorations: Fixed wrong window bounds when resizing window to
|
||||
another screen with different scaling factor. (issue #166)
|
||||
- Fixed occasional wrong positioning of heavy weight popups when using multiple
|
||||
screens with different scaling factors. (issue #166)
|
||||
- ToolTip: Avoid that tooltip hides owner component. (issue #164)
|
||||
|
||||
|
||||
## 0.41
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Added API to register packages or folders where FlatLaf searches for
|
||||
application specific properties files with custom UI defaults (see
|
||||
`FlatLaf.registerCustomDefaultsSource(...)` methods).
|
||||
- Demo: Show hint popups to guide users to some features of the FlatLaf Demo
|
||||
application.
|
||||
- Extras: `FlatSVGIcon` now allows specifying `ClassLoader` that is used to load
|
||||
SVG file. (issue #163)
|
||||
- Smoother transition from old to new theme, independent of UI complexity, when
|
||||
using animated theme change (see [FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Button: "selected" state was not shown. (issue #161)
|
||||
- TextArea: Update background color property if enabled or editable state
|
||||
changes in the same way as Swing does it for all other text components. (issue
|
||||
#147)
|
||||
- Demo: Fixed restoring last used theme on startup. (regression in 0.39)
|
||||
- Custom window decorations: Fixed iconify, maximize and close icon colors if
|
||||
window is inactive.
|
||||
- Custom window decorations: Fixed title pane background color in IntelliJ
|
||||
themes if window is inactive.
|
||||
- Fixed sub-pixel text rendering in animated theme change (see
|
||||
[FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
#### Other Changes
|
||||
|
||||
- Extras: Updated dependency
|
||||
[svgSalamander](https://github.com/JFormDesigner/svgSalamander) to version
|
||||
1.1.2.3.
|
||||
|
||||
|
||||
## 0.40
|
||||
|
||||
#### New features
|
||||
|
||||
- Table: Detect whether component is used in cell editor and automatically
|
||||
disable round border style and reduce cell editor outer border width (used for
|
||||
focus indicator) to zero. (issue #148)
|
||||
- ComboBox, Spinner and TextField: Support disabling round border style per
|
||||
component, if globally enabled (set client property `JComponent.roundRect` to
|
||||
`false`). (issue #148)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Embedded menu bar did not always respond to mouse
|
||||
events after adding menus and when running in JetBrains Runtime. (issue #151)
|
||||
- IntelliJ Themes: Fixed NPE in Solarized themes on scroll bar hover.
|
||||
|
||||
|
||||
## 0.39
|
||||
|
||||
#### New features
|
||||
|
||||
- Animated theme change (see [FlatLaf Extras](flatlaf-extras)). Used in Demo.
|
||||
- Demo: Added combo box above themes list to show only light or dark themes.
|
||||
- IntelliJ Themes:
|
||||
- Added "Arc Dark", "Arc Dark - Orange", "Carbon" and "Cobalt 2" themes.
|
||||
- Replaced "Solarized" themes with much better ones from 4lex4.
|
||||
- Updated "Arc", "One Dark" and "Vuesion" themes.
|
||||
- ScrollPane: Enable/disable smooth scrolling per component if client property
|
||||
"JScrollPane.smoothScrolling" is set to a `Boolean` on `JScrollPane`.
|
||||
- ScrollBar: Increased minimum thumb size on macOS and Linux from 8 to 18
|
||||
pixels. On Windows, it is now 10 pixels. (issue #131)
|
||||
- Button: Support specifying button border width.
|
||||
- ComboBox: Changed maximum row count of popup list to 15 (was 20). Set UI value
|
||||
`ComboBox.maximumRowCount` to any integer to use a different value.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Custom window decorations: Fixed maximized window bounds when programmatically
|
||||
maximizing window. E.g. restoring window state at startup. (issue #129)
|
||||
- InternalFrame: Title pane height was too small when iconify, maximize and
|
||||
close buttons are hidden. (issue #132)
|
||||
- ToolTip: Do not show empty tooltip component if tooltip text is an empty
|
||||
string. (issue #134)
|
||||
- ToolTip: Fixed truncated text in HTML formatted tooltip on HiDPI displays.
|
||||
(issue #142)
|
||||
- ComboBox: Fixed width of popup, which was too small if popup is wider than
|
||||
combo box and vertical scroll bar is visible. (issue #137)
|
||||
- MenuItem on macOS: Removed plus characters from accelerator text and made
|
||||
modifier key order conform with macOS standard. (issue #141)
|
||||
- FileChooser: Fixed too small text field when renaming a file/directory in Flat
|
||||
IntelliJ/Darcula themes. (issue #143)
|
||||
- IntelliJ Themes: Fixed text colors in ProgressBar. (issue #138)
|
||||
|
||||
|
||||
## 0.38
|
||||
|
||||
- Hide focus indicator when window is inactive.
|
||||
- Custom window decorations: Improved/fixed window border color in dark themes.
|
||||
- Custom window decorations: Hide window border if window is maximized.
|
||||
- Custom window decorations: Center title if menu bar is embedded.
|
||||
- Custom window decorations: Cursor of components (e.g. TextField) was not
|
||||
changed. (issue #125)
|
||||
- CheckBox: Fixed colors in light IntelliJ themes. (issue #126; regression in
|
||||
0.37)
|
||||
- InternalFrame: Use default icon in internal frames. (issue #122)
|
||||
|
||||
|
||||
## 0.37
|
||||
|
||||
- Custom window decorations (Windows 10 only; PR #108; issues #47 and #82)
|
||||
support:
|
||||
- dark window title panes
|
||||
- embedding menu bar into window title pane
|
||||
- native Windows 10 borders and behavior when running in
|
||||
[JetBrains Runtime 11](https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime)
|
||||
or later (the JRE that IntelliJ IDEA uses)
|
||||
- CheckBox and RadioButton: Support changing selected icon style from outline to
|
||||
filled (as in FlatLaf IntelliJ theme) with `UIManager.put(
|
||||
"CheckBox.icon.style", "filled" );`.
|
||||
- Button and ToggleButton: Support disabled background color (use UI values
|
||||
`Button.disabledBackground` and `ToggleButton.disabledBackground`). (issue
|
||||
#112)
|
||||
- Button and ToggleButton: Support making buttons square (set client property
|
||||
`JButton.squareSize` to `true`). (issue #118)
|
||||
- ScrollBar: Support pressed track, thumb and button colors (use UI values
|
||||
`ScrollBar.pressedTrackColor`, `ScrollBar.pressedThumbColor` and
|
||||
`ScrollBar.pressedButtonBackground`). (issue #115)
|
||||
- ComboBox: Support changing arrow button style (set UI value
|
||||
`ComboBox.buttonStyle` to `auto` (default), `button` or `none`). (issue #114)
|
||||
- Spinner: Support changing arrows button style (set UI value
|
||||
`Spinner.buttonStyle` to `button` (default) or `none`).
|
||||
- TableHeader: Support top/bottom/left positioned sort arrow when using
|
||||
[Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113)
|
||||
- Button, CheckBox, RadioButton and ToggleButton: Do not paint focus indicator
|
||||
if `AbstractButton.isFocusPainted()` returns `false`.
|
||||
- ComboBox: Increase maximum row count of popup list to 20 (was 8). Set UI value
|
||||
`ComboBox.maximumRowCount` to any integer to use a different value.
|
||||
- Fixed/improved vertical position of text when scaled on HiDPI screens on
|
||||
Windows.
|
||||
- IntelliJ Themes: Updated Gradianto Themes.
|
||||
- IntelliJ Themes: Fixed menu bar and menu item margins in all Material UI Lite
|
||||
themes.
|
||||
|
||||
|
||||
## 0.36
|
||||
|
||||
- ScrollBar: Made styling more flexible by supporting insets and arc for track
|
||||
and thumb. (issue #103)
|
||||
- ScrollBar: Use round thumb on macOS and Linux to make it look similar to
|
||||
native platform scroll bars. (issue #103)
|
||||
- ComboBox: Minimum width is now 72 pixels (was ~50 for non-editable and ~130
|
||||
for editable comboboxes).
|
||||
- ComboBox: Support custom borders in combobox editors. (issue #102)
|
||||
- Button: Support non-square icon-only buttons. (issue #110)
|
||||
- Ubuntu Linux: Fixed poorly rendered font. (issue #105)
|
||||
- macOS Catalina: Use Helvetica Neue font.
|
||||
- `FlatInspector` added (see [FlatLaf Extras](flatlaf-extras)).
|
||||
|
||||
|
||||
## 0.35
|
||||
|
||||
- Added drop shadows to popup menus, combobox popups, tooltips and internal
|
||||
frames. (issue #94)
|
||||
- Support different component border colors to indicate errors, warnings or
|
||||
custom state (set client property `JComponent.outline` to `error`, `warning`
|
||||
or any `java.awt.Color`).
|
||||
- Button and ToggleButton: Support round button style (set client property
|
||||
`JButton.buttonType` to `roundRect`).
|
||||
- ComboBox, Spinner and TextField: Support round border style (set client
|
||||
property `JComponent.roundRect` to `true`).
|
||||
- Paint nicely rounded buttons, comboboxes, spinners and text fields when
|
||||
setting `Button.arc`, `Component.arc` or `TextComponent.arc` to a large value
|
||||
(e.g. 1000).
|
||||
- Added Java 9 module descriptor to `flatlaf-extras-<version>.jar` and
|
||||
`flatlaf-swingx-<version>.jar`.
|
||||
- CheckBox and RadioButton: Flag `opaque` is no longer ignored when checkbox or
|
||||
radio button is used as table cell renderer. (issue #77)
|
||||
- FileChooser: Use system icons. (issue #100)
|
||||
- FileChooser: Fixed missing labels in file chooser when running on Java 9 or
|
||||
later. (issue #98)
|
||||
- PasswordField: Do not apply minimum width if `columns` property is greater
|
||||
than zero.
|
||||
|
||||
|
||||
## 0.34
|
||||
|
||||
- Menus: New menu item renderer brings stable left margins, right aligned
|
||||
accelerators and larger gap between text and accelerator. This makes menus
|
||||
look more modern and more similar to native platform menus.
|
||||
- New underline menu selection style that displays selected menu items similar
|
||||
to tabs (to enable use `UIManager.put( "MenuItem.selectionType", "underline"
|
||||
);`).
|
||||
- Menus: Fixed text color of selected menu items that use HTML. (issue #87)
|
||||
- Menus: On Windows, pressing <kbd>F10</kbd> now activates the menu bar without
|
||||
showing a menu popup (as usual on Windows platform). On other platforms the
|
||||
first menu popup is shown.
|
||||
- Menus: On Windows, releasing <kbd>Alt</kbd> key now activates the menu bar (as
|
||||
usual on Windows platform). (issue #43)
|
||||
- Menus: Fixed inconsistent left padding in menu items. (issue #3)
|
||||
- Menus: Fixed: Setting `iconTextGap` property on a menu item did increase left
|
||||
and right margins. (issue #54)
|
||||
- Hide mnemonics if window is deactivated (e.g. <kbd>Alt+Tab</kbd> to another
|
||||
window). (issue #43)
|
||||
- macOS: Enabled drop shadows for popup menus and combobox popups. (issue #94)
|
||||
- macOS: Fixed NPE if using `JMenuBar` in `JInternalFrame` and macOS screen menu
|
||||
bar is enabled (with `-Dapple.laf.useScreenMenuBar=true`). (issue #90)
|
||||
|
||||
|
||||
## 0.33
|
||||
|
||||
- Improved creation of disabled grayscale icons used in disabled buttons, labels
|
||||
and tabs. They now have more contrast and are lighter in light themes and
|
||||
darker in dark themes. (issue #70)
|
||||
- IntelliJ Themes: Fixed ComboBox size and Spinner border in all Material UI
|
||||
Lite themes and limit tree row height in all Material UI Lite themes and some
|
||||
other themes.
|
||||
- IntelliJ Themes: Material UI Lite themes did not work when using
|
||||
[IntelliJ Themes Pack](flatlaf-intellij-themes) addon. (PR #88, issue #89)
|
||||
- IntelliJ Themes: Added Java 9 module descriptor to
|
||||
`flatlaf-intellij-themes-<version>.jar`.
|
||||
|
||||
|
||||
## 0.32
|
||||
|
||||
- New [IntelliJ Themes Pack](flatlaf-intellij-themes) addon bundles many popular
|
||||
open-source 3rd party themes from JetBrains Plugins Repository into a JAR and
|
||||
provides Java classes to use them.
|
||||
- IntelliJ Themes: Fixed button and toggle button colors. (issue #86)
|
||||
- Updated IntelliJ Themes in demo to the latest versions.
|
||||
- ToggleButton: Compute selected background color based on current component
|
||||
background. (issue #32)
|
||||
|
||||
|
||||
## 0.31
|
||||
|
||||
- Focus indication border (or background) no longer hidden when temporary
|
||||
loosing focus (e.g. showing a popup menu).
|
||||
- List, Table and Tree: Item selection color of focused components no longer
|
||||
change from blue to gray when temporary loosing focus (e.g. showing a popup
|
||||
menu).
|
||||
|
||||
|
||||
## 0.30
|
||||
|
||||
- Windows: Fixed rendering of Unicode characters. Previously not all Unicode
|
||||
characters were rendered on Windows. (issue #81)
|
||||
|
||||
|
||||
## 0.29
|
||||
|
||||
- Linux: Fixed scaling if `GDK_SCALE` environment variable is set or if running
|
||||
on JetBrains Runtime. (issue #69)
|
||||
- Tree: Fixed repainting wide selection on focus gained/lost.
|
||||
- ComboBox: No longer ignore `JComboBox.prototypeDisplayValue` when computing
|
||||
popup width. (issue #80)
|
||||
- Support changing default font used for all components with automatic scaling
|
||||
UI if using larger font. Use `UIManager.put( "defaultFont", myFont );`
|
||||
- No longer use system property `sun.java2d.uiScale`. (Java 8 only)
|
||||
- Support specifying custom scale factor in system property `flatlaf.uiScale`
|
||||
also for Java 9 and later.
|
||||
- Demo: Support using own FlatLaf themes (`.properties` files) that are located
|
||||
in working directory of Demo application. Shown in the "Themes" list under
|
||||
category "Current Directory".
|
||||
|
||||
|
||||
## 0.28
|
||||
|
||||
- PasswordField: Warn about enabled Caps Lock.
|
||||
- TabbedPane: Support <kbd>Ctrl+TAB</kbd> / <kbd>Ctrl+Shift+TAB</kbd> to switch
|
||||
to next / previous tab.
|
||||
- TextField, FormattedTextField and PasswordField: Support round borders (see UI
|
||||
default value `TextComponent.arc`). (issue #65)
|
||||
- IntelliJ Themes: Added Gradianto themes to demo.
|
||||
- Button, CheckBox and RadioButton: Fixed NPE when button has children. (PR #68)
|
||||
- ScrollBar: Improved colors.
|
||||
- Reviewed (and tested) all key bindings on Windows and macOS. Linux key
|
||||
bindings are equal to Windows key bindings. macOS key bindings are slightly
|
||||
different for platform specific behavior.
|
||||
- UI default values are no longer based on Metal/Aqua UI defaults.
|
||||
|
||||
|
||||
## 0.27
|
||||
|
||||
- Support `JInternalFrame` and `JDesktopPane`. (issues #39 and #11)
|
||||
- Table: Support positioning the column sort arrow in header right, left, top or
|
||||
bottom. (issue #34)
|
||||
- ProgressBar: Fixed visual artifacts in indeterminate mode, on HiDPI screens at
|
||||
125%, 150% and 175% scaling, when the progress moves around.
|
||||
- TabbedPane: New option to allow tab separators to take full height (to enable
|
||||
use `UIManager.put( "TabbedPane.tabSeparatorsFullHeight", true );`). (issue
|
||||
#59, PR #62)
|
||||
- CheckBox and RadioButton: Do not fill background if `contentAreaFilled` is
|
||||
`false`. (issue #58, PR #63)
|
||||
- ToggleButton: Make toggle button square if it has an icon but no text or text
|
||||
is "..." or a single character.
|
||||
- ToolBar: No longer use special rollover border for buttons in toolbar. (issue
|
||||
#36)
|
||||
- ToolBar: Added empty space around buttons in toolbar and toolbar itself (see
|
||||
UI default values `Button.toolbar.spacingInsets` and `ToolBar.borderMargins`).
|
||||
(issue #56)
|
||||
- Fixed "illegal reflective access operation" warning on macOS when using Java
|
||||
12 or later. (issue #60, PR #61)
|
||||
|
||||
|
||||
## 0.26
|
||||
|
||||
- Menus:
|
||||
- Changed menu bar and popup menu background colors (made brighter in light
|
||||
themes and darker in dark themes).
|
||||
- Highlight items in menu bar on mouse hover. (issue #49)
|
||||
- Popup menus now have empty space at the top and bottom.
|
||||
- Menu items now have larger left and right margins.
|
||||
- Made `JMenu`, `JMenuItem`, `JCheckBoxMenuItem` and `JRadioButtonMenuItem`
|
||||
non-opaque.
|
||||
- TextField, FormattedTextField and PasswordField: Select all text when a text
|
||||
field gains focus for the first time and selection was not set explicitly.
|
||||
This can be configured to newer or always select all text on focus gain (see
|
||||
UI default value `TextComponent.selectAllOnFocusPolicy`).
|
||||
- ProgressBar: Made progress bar paint smooth in indeterminate mode.
|
||||
|
||||
|
||||
## 0.25.1
|
||||
|
||||
Re-release of 0.25 because of problems with Maven Central.
|
||||
|
||||
|
||||
## 0.25
|
||||
|
||||
- Hide menu mnemonics by default and show them only when <kbd>Alt</kbd> key is
|
||||
pressed. (issue #43)
|
||||
- Menu: Fixed vertical alignment of sub-menus. (issue #42)
|
||||
- TabbedPane: In scroll-tab-layout, the cropped line is now hidden. (issue #40)
|
||||
- Tree: UI default value `Tree.textBackground` now has a valid color and is no
|
||||
longer `null`.
|
||||
- Tree on macOS: Fixed <kbd>Left</kbd> and <kbd>Right</kbd> keys to collapse or
|
||||
expand nodes.
|
||||
- ComboBox on macOS: Fixed keyboard navigation and show/hide popup.
|
||||
- Button and ToggleButton: Support per component minimum height (set client
|
||||
property `JComponent.minimumHeight` to an integer). (issue #44)
|
||||
- Button and ToggleButton: Do not apply minimum width if button border was
|
||||
changed (is no longer an instance of `FlatButtonBorder`).
|
||||
- ToggleButton: Renamed toggle button type "underline" to "tab" (value of client
|
||||
property `JButton.buttonType` is now `tab`).
|
||||
- ToggleButton: Support per component styling for tab-style toggle buttons with
|
||||
client properties `JToggleButton.tab.underlineHeight` (integer),
|
||||
`JToggleButton.tab.underlineColor` (Color) and
|
||||
`JToggleButton.tab.selectedBackground` (Color). (issue #45)
|
||||
- ToggleButton: No longer use focus width for tab-style toggle buttons to
|
||||
compute component size, which reduces/fixes component size in "Flat IntelliJ"
|
||||
and "Flat Darcula" themes.
|
||||
- TabbedPane: Support per component tab height (set client property
|
||||
`JTabbedPane.tabHeight` to an integer).
|
||||
- ProgressBar: Support square painting (set client property
|
||||
`JProgressBar.square` to `true`) and larger height even if no string is
|
||||
painted (set client property `JProgressBar.largeHeight` to `true`).
|
||||
|
||||
|
||||
## 0.24
|
||||
|
||||
- Support smooth scrolling with touchpads and high precision mouse wheels.
|
||||
|
||||
127
README.md
127
README.md
@@ -11,19 +11,18 @@ scales on **HiDPI** displays and runs on Java 8 or newer.
|
||||
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
|
||||
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
IntelliJ Platform Themes
|
||||
------------------------
|
||||
|
||||
FlatLaf can use 3rd party themes created for IntelliJ Platform:
|
||||
FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
||||
[IntelliJ Themes Pack](flatlaf-intellij-themes)):
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Demo
|
||||
@@ -38,23 +37,38 @@ Requires Java 8 or newer.
|
||||
Download
|
||||
--------
|
||||
|
||||
FlatLaf binaries are available on **JCenter** and **Maven Central**.
|
||||
FlatLaf binaries are available on **Maven Central**.
|
||||
|
||||
If you use Maven or Gradle, add a dependency with following coordinates to your
|
||||
build script:
|
||||
|
||||
groupId: com.formdev
|
||||
artifactId: flatlaf
|
||||
version: 0.24
|
||||
version: (see button below)
|
||||
|
||||
Otherwise download `flatlaf-<version>.jar` here:
|
||||
|
||||
[](https://bintray.com/jformdesigner/flatlaf/flatlaf/_latestVersion)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf)
|
||||
|
||||
|
||||
### Snapshots
|
||||
|
||||
FlatLaf snapshot binaries are available on
|
||||
[Sonatype OSSRH](https://oss.sonatype.org/content/repositories/snapshots/com/formdev/flatlaf/).
|
||||
To access the latest snapshot, change the FlatLaf version in your dependencies
|
||||
to `<version>-SNAPSHOT` (e.g. `0.27-SNAPSHOT`) and add the repository
|
||||
`https://oss.sonatype.org/content/repositories/snapshots/` to your build (see
|
||||
[Maven](https://maven.apache.org/guides/mini/guide-multiple-repositories.html)
|
||||
and
|
||||
[Gradle](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:declaring_custom_repository)
|
||||
docs).
|
||||
|
||||
|
||||
Addons
|
||||
------
|
||||
|
||||
- [IntelliJ Themes Pack](flatlaf-intellij-themes)
|
||||
- [Extras](flatlaf-extras)
|
||||
- [SwingX](flatlaf-swingx)
|
||||
- [JIDE Common Layer](flatlaf-jide-oss)
|
||||
|
||||
@@ -64,3 +78,98 @@ Documentation
|
||||
|
||||
For more information and documentation visit
|
||||
[FlatLaf Home](https://www.formdev.com/flatlaf/)
|
||||
|
||||
|
||||
Buzz
|
||||
----
|
||||
|
||||
- [What others say about FlatLaf on Twitter](https://twitter.com/search?f=live&q=flatlaf)
|
||||
- [FlatLaf announcement on Reddit](https://www.reddit.com/r/java/comments/dl0hu3/flatlaf_flat_look_and_feel/)
|
||||
|
||||
|
||||
Applications using FlatLaf
|
||||
--------------------------
|
||||
|
||||
- [Apache NetBeans](https://netbeans.apache.org/) 11.3 - IDE for Java, PHP, HTML
|
||||
and much more
|
||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
||||
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
||||
-  [DbVisualizer](https://www.dbvis.com/) 12.0
|
||||
(**commercial**) - the universal database tool for developers, analysts and
|
||||
DBAs
|
||||
-  [MagicPlot](https://magicplot.com/) 3.0
|
||||
(**commercial**) - Software for nonlinear fitting, plotting and data analysis
|
||||
- 
|
||||
[Thermo-Calc](https://thermocalc.com/products/thermo-calc/) 2021a
|
||||
(**commercial**) - Thermodynamics and Properties Software
|
||||
- [OWASP ZAP](https://www.zaproxy.org/) 2.10 - the worlds most widely used web
|
||||
app scanner
|
||||
- 
|
||||
[Burp Suite Professional and Community Edition](https://portswigger.net/burp/pro)
|
||||
2020.11.2 (**commercial**) - the leading software for web security testing
|
||||
- 
|
||||
[BurpCustomizer](https://github.com/CoreyD97/BurpCustomizer) - adds more
|
||||
FlatLaf themes to Burp Suite
|
||||
- [JOSM](https://josm.openstreetmap.de/) - an extensible editor for
|
||||
[OpenStreetMap](https://www.openstreetmap.org/) (requires FlatLaf JOSM plugin)
|
||||
- [jAlbum](https://jalbum.net/) 21 (**commercial**) - creates photo album
|
||||
websites
|
||||
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (**commercial**)
|
||||
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
|
||||
checks your website
|
||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
|
||||
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
|
||||
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5 - a turn-based sci-fi board
|
||||
game
|
||||
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
||||
0.13.b024 - GUI builder for
|
||||
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI
|
||||
framework for embedded displays
|
||||
- [Rest Suite](https://github.com/supanadit/restsuite) - Rest API testing
|
||||
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy) - advanced
|
||||
gamepad mapping software
|
||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote) - remote Linux SSH
|
||||
connections manager
|
||||
- [jEnTunnel](https://github.com/ggrandes/jentunnel) - manage SSH Tunnels made
|
||||
easy
|
||||
- [mendelson AS2](https://sourceforge.net/projects/mec-as2/),
|
||||
[AS4](https://sourceforge.net/projects/mendelson-as4/) and
|
||||
[OFTP2](https://sourceforge.net/projects/mendelson-oftp2/) (open-source) and
|
||||
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
||||
[AS4](https://mendelson-e-c.com/as4/) and
|
||||
[OFTP2](https://mendelson-e-c.com/oftp2) (**commercial**)
|
||||
-  [IGMAS+](https://www.gfz-potsdam.de/igmas) -
|
||||
Interactive Gravity and Magnetic Application System
|
||||
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2 - GIS and scientific
|
||||
computation environment for meteorological community
|
||||
- [lsfusion platform](https://github.com/lsfusion/platform) 4 - information
|
||||
systems development platform
|
||||
- [JPass](https://github.com/gaborbata/jpass) - password manager with strong
|
||||
encryption
|
||||
- [Jes - Die Java-E<>R](https://www.jes-eur.de)
|
||||
- [Mapton](https://mapton.org/) 2.0
|
||||
([source code](https://github.com/trixon/mapton)) - some kind of map
|
||||
application (based on NetBeans platform)
|
||||
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE) -
|
||||
IDE for Pseudo-Assembler
|
||||
- [Linotte](https://github.com/cpc6128/LangageLinotte) 3.1 - French programming
|
||||
language created to learn programming
|
||||
- [MEKA](https://github.com/Waikato/meka) 1.9.3 - multi-label classifiers and
|
||||
evaluation procedures using the Weka machine learning framework
|
||||
- [Shutter Encoder](https://www.shutterencoder.com/) 14.2
|
||||
([source code](https://github.com/paulpacifico/shutter-encoder)) -
|
||||
professional video converter and compression tool (screenshots show **old**
|
||||
look)
|
||||
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis) - analyze
|
||||
sound files in time or frequency domain
|
||||
- [RemoteLight](https://github.com/Drumber/RemoteLight) - multifunctional LED
|
||||
control software
|
||||
- [ThunderFocus](https://github.com/marcocipriani01/ThunderFocus) -
|
||||
Arduino-based telescope focuser
|
||||
- [Novel-Grabber](https://github.com/Flameish/Novel-Grabber) - download novels
|
||||
from any webnovel and lightnovel site
|
||||
- [lectureStudio](https://www.lecturestudio.org/) 4.3.1060 - digitize your
|
||||
lectures with ease
|
||||
- [Android Tool](https://github.com/fast-geek/Android-Tool) - makes popular adb
|
||||
and fastboot commands easier to use
|
||||
- and more...
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* https://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,
|
||||
@@ -14,11 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
version = "0.24"
|
||||
val releaseVersion = "1.0"
|
||||
val developmentVersion = "1.1-SNAPSHOT"
|
||||
|
||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||
|
||||
allprojects {
|
||||
version = rootProject.version
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +38,28 @@ println( "FlatLaf Version: ${version}" )
|
||||
println( "Gradle ${gradle.gradleVersion} at ${gradle.gradleHomeDir}" )
|
||||
println( "Java ${System.getProperty( "java.version" )}" )
|
||||
println()
|
||||
|
||||
|
||||
allprojects {
|
||||
tasks {
|
||||
withType<JavaCompile>().configureEach {
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
|
||||
options.encoding = "ISO-8859-1"
|
||||
}
|
||||
|
||||
withType<Jar>().configureEach {
|
||||
// manifest for all created JARs
|
||||
manifest.attributes(mapOf(
|
||||
"Implementation-Vendor" to "FormDev Software GmbH",
|
||||
"Implementation-Copyright" to "Copyright (C) 2019-${java.time.LocalDate.now().year} FormDev Software GmbH. All rights reserved.",
|
||||
"Implementation-Version" to project.version))
|
||||
|
||||
// add META-INF/LICENSE to all created JARs
|
||||
from("${rootDir}/LICENSE") {
|
||||
into("META-INF")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
buildSrc/build.gradle.kts
Normal file
24
buildSrc/build.gradle.kts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
// required for kotlin-dsl or embedded-kotlin plugins
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
80
buildSrc/src/main/java/ReorderJarEntries.java
Normal file
80
buildSrc/src/main/java/ReorderJarEntries.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* Reorders entries in a JAR file so that .properties files are placed before .class files,
|
||||
* which is necessary to workaround an issue in NetBeans 11.3 (and older).
|
||||
* See issues #13 and #93.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class ReorderJarEntries
|
||||
{
|
||||
public static void reorderJarEntries( File jarFile )
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream( (int) jarFile.length() + 1000 );
|
||||
|
||||
try( ZipOutputStream zipOutStream = new ZipOutputStream( outStream ) ) {
|
||||
// 1st pass: copy .properties files
|
||||
copyFiles( zipOutStream, jarFile, name -> name.endsWith( ".properties" ) );
|
||||
|
||||
// 2st pass: copy other files
|
||||
copyFiles( zipOutStream, jarFile, name -> !name.endsWith( ".properties" ) );
|
||||
}
|
||||
|
||||
// replace JAR
|
||||
Files.write( jarFile.toPath(), outStream.toByteArray(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
|
||||
}
|
||||
|
||||
private static void copyFiles( ZipOutputStream dest, File jarFile, Predicate<String> filter )
|
||||
throws IOException
|
||||
{
|
||||
try( ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream( jarFile ) ) ) {
|
||||
ZipEntry entry;
|
||||
while( (entry = zipInputStream.getNextEntry()) != null ) {
|
||||
if( filter.test( entry.getName() ) ) {
|
||||
dest.putNextEntry( entry );
|
||||
copyFile( zipInputStream, dest );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyFile( InputStream src, OutputStream dest )
|
||||
throws IOException
|
||||
{
|
||||
byte[] buf = new byte[8*1024];
|
||||
int len;
|
||||
while( (len = src.read( buf )) > 0 )
|
||||
dest.write( buf, 0, len );
|
||||
dest.flush();
|
||||
}
|
||||
}
|
||||
44
buildSrc/src/main/kotlin/flatlaf-java9.gradle.kts
Normal file
44
buildSrc/src/main/kotlin/flatlaf-java9.gradle.kts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "java9" ) {
|
||||
java {
|
||||
setSrcDirs( listOf( "src/main/java9" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
named<JavaCompile>( "compileJava9Java" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes( "Multi-Release" to "true" )
|
||||
|
||||
into( "META-INF/versions/9" ) {
|
||||
from( sourceSets["java9"].output )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
buildSrc/src/main/kotlin/flatlaf-module-info.gradle.kts
Normal file
64
buildSrc/src/main/kotlin/flatlaf-module-info.gradle.kts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
open class ModuleInfoExtension {
|
||||
var paths: ArrayList<String> = ArrayList()
|
||||
|
||||
fun dependsOn( vararg paths: String ) {
|
||||
this.paths.addAll( paths )
|
||||
}
|
||||
}
|
||||
|
||||
val extension = project.extensions.create<ModuleInfoExtension>( "flatlafModuleInfo" )
|
||||
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "module-info" ) {
|
||||
java {
|
||||
// include "src/main/java" here to get compile errors if classes are
|
||||
// used from other modules that are not specified in module dependencies
|
||||
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
named<JavaCompile>( "compileModuleInfoJava" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
|
||||
dependsOn( extension.paths )
|
||||
|
||||
options.compilerArgs.add( "--module-path" )
|
||||
options.compilerArgs.add( configurations.runtimeClasspath.get().asPath )
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes( "Multi-Release" to "true" )
|
||||
|
||||
into( "META-INF/versions/9" ) {
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
buildSrc/src/main/kotlin/flatlaf-publish.gradle.kts
Normal file
112
buildSrc/src/main/kotlin/flatlaf-publish.gradle.kts
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
|
||||
open class PublishExtension {
|
||||
var artifactId: String? = null
|
||||
var name: String? = null
|
||||
var description: String? = null
|
||||
}
|
||||
|
||||
val extension = project.extensions.create<PublishExtension>( "flatlafPublish" )
|
||||
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
signing
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>( "maven" ) {
|
||||
afterEvaluate {
|
||||
artifactId = extension.artifactId
|
||||
}
|
||||
groupId = "com.formdev"
|
||||
|
||||
from( components["java"] )
|
||||
|
||||
pom {
|
||||
afterEvaluate {
|
||||
this@pom.name.set( extension.name )
|
||||
this@pom.description.set( extension.description )
|
||||
}
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set( "The Apache License, Version 2.0" )
|
||||
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name.set( "Karl Tauber" )
|
||||
organization.set( "FormDev Software GmbH" )
|
||||
organizationUrl.set( "https://www.formdev.com/" )
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set( "scm:git:git://github.com/JFormDesigner/FlatLaf.git" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system.set( "GitHub" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "OSSRH"
|
||||
|
||||
val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||
val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
url = uri( if( java.lang.Boolean.getBoolean( "release" ) ) releasesRepoUrl else snapshotsRepoUrl )
|
||||
|
||||
credentials {
|
||||
// get from gradle.properties
|
||||
val ossrhUsername: String? by project
|
||||
val ossrhPassword: String? by project
|
||||
|
||||
username = System.getenv( "OSSRH_USERNAME" ) ?: ossrhUsername
|
||||
password = System.getenv( "OSSRH_PASSWORD" ) ?: ossrhPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
// get from gradle.properties
|
||||
val signingKey: String? by project
|
||||
val signingPassword: String? by project
|
||||
|
||||
val key = System.getenv( "SIGNING_KEY" ) ?: signingKey
|
||||
val password = System.getenv( "SIGNING_PASSWORD" ) ?: signingPassword
|
||||
|
||||
useInMemoryPgpKeys( key, password )
|
||||
sign( publishing.publications["maven"] )
|
||||
}
|
||||
|
||||
// disable signing of snapshots
|
||||
tasks.withType<Sign>().configureEach {
|
||||
onlyIf { java.lang.Boolean.getBoolean( "release" ) }
|
||||
}
|
||||
377
flatlaf-core/.settings/org.eclipse.jdt.core.prefs
Normal file
377
flatlaf-core/.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,377 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_with_spaces=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_record_components=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=33
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=32
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=32
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=next_line_on_wrap
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=1
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.lineSplit=120
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.text_block_indentation=0
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
|
||||
3
flatlaf-core/.settings/org.eclipse.jdt.ui.prefs
Normal file
3
flatlaf-core/.settings/org.eclipse.jdt.ui.prefs
Normal file
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_FlatLaf
|
||||
formatter_settings_version=19
|
||||
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* https://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,
|
||||
@@ -14,134 +14,48 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id( "com.jfrog.bintray" ) version "1.8.4"
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
sourceSets {
|
||||
create( "module-info" ) {
|
||||
java {
|
||||
// include "src/main/java" here to get compile errors if classes are
|
||||
// used from other modules that are not specified in module dependencies
|
||||
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
|
||||
}
|
||||
}
|
||||
}
|
||||
`flatlaf-module-info`
|
||||
`flatlaf-java9`
|
||||
`flatlaf-publish`
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks {
|
||||
assemble {
|
||||
dependsOn(
|
||||
"sourcesJar",
|
||||
"javadocJar"
|
||||
)
|
||||
}
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
named<JavaCompile>( "compileModuleInfoJava" ) {
|
||||
sourceCompatibility = "9"
|
||||
targetCompatibility = "9"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
|
||||
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
|
||||
from( sourceSets["module-info"].output ) {
|
||||
include( "module-info.class" )
|
||||
}
|
||||
doLast {
|
||||
ReorderJarEntries.reorderJarEntries( outputs.files.singleFile );
|
||||
}
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options {
|
||||
this as StandardJavadocDocletOptions
|
||||
use( true )
|
||||
tags = listOf( "uiDefault", "clientProperty" )
|
||||
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
|
||||
}
|
||||
isFailOnError = false
|
||||
}
|
||||
|
||||
register( "sourcesJar", Jar::class ) {
|
||||
named<Jar>("sourcesJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveClassifier.set( "sources" )
|
||||
|
||||
from( sourceSets.main.get().allJava )
|
||||
}
|
||||
|
||||
register( "javadocJar", Jar::class ) {
|
||||
named<Jar>("javadocJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveClassifier.set( "javadoc" )
|
||||
|
||||
from( javadoc )
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>( "maven" ) {
|
||||
artifactId = "flatlaf"
|
||||
groupId = "com.formdev"
|
||||
|
||||
from( components["java"] )
|
||||
|
||||
artifact( tasks["sourcesJar"] )
|
||||
artifact( tasks["javadocJar"] )
|
||||
|
||||
pom {
|
||||
name.set( "FlatLaf" )
|
||||
description.set( "Flat Look and Feel" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set( "The Apache License, Version 2.0" )
|
||||
url.set( "http://www.apache.org/licenses/LICENSE-2.0.txt" )
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name.set( "Karl Tauber" )
|
||||
organization.set( "FormDev Software GmbH" )
|
||||
organizationUrl.set( "https://www.formdev.com/" )
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = System.getenv( "BINTRAY_USER" ) ?: System.getProperty( "bintray.user" )
|
||||
key = System.getenv( "BINTRAY_KEY" ) ?: System.getProperty( "bintray.key" )
|
||||
|
||||
setPublications( "maven" )
|
||||
|
||||
with( pkg ) {
|
||||
repo = "flatlaf"
|
||||
name = "flatlaf"
|
||||
setLicenses( "Apache-2.0" )
|
||||
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
|
||||
|
||||
with( version ) {
|
||||
name = project.version.toString()
|
||||
}
|
||||
|
||||
publish = true
|
||||
}
|
||||
flatlafPublish {
|
||||
artifactId = "flatlaf"
|
||||
name = "FlatLaf"
|
||||
description = "Flat Look and Feel"
|
||||
}
|
||||
|
||||
@@ -16,20 +16,31 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
/**
|
||||
* Defines/documents own client properties used in FlatLaf.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public interface FlatClientProperties
|
||||
{
|
||||
//---- JButton ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies type of a button.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong> {@link #BUTTON_TYPE_SQUARE} and {@link #BUTTON_TYPE_HELP}
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #BUTTON_TYPE_SQUARE},
|
||||
* {@link #BUTTON_TYPE_ROUND_RECT},
|
||||
* {@link #BUTTON_TYPE_TAB},
|
||||
* {@link #BUTTON_TYPE_HELP} or
|
||||
* {@link BUTTON_TYPE_TOOLBAR_BUTTON}
|
||||
*/
|
||||
String BUTTON_TYPE = "JButton.buttonType";
|
||||
|
||||
@@ -43,13 +54,22 @@ public interface FlatClientProperties
|
||||
String BUTTON_TYPE_SQUARE = "square";
|
||||
|
||||
/**
|
||||
* Paint the toggle button in underline style.
|
||||
* Paint the button with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
*
|
||||
* @see #BUTTON_TYPE
|
||||
*/
|
||||
String BUTTON_TYPE_ROUND_RECT = "roundRect";
|
||||
|
||||
/**
|
||||
* Paint the toggle button in tab style.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JToggleButton}
|
||||
*
|
||||
* @see #TOGGLE_BUTTON_TYPE
|
||||
* @see #BUTTON_TYPE
|
||||
*/
|
||||
String BUTTON_TYPE_UNDERLINE = "underline";
|
||||
String BUTTON_TYPE_TAB = "tab";
|
||||
|
||||
/**
|
||||
* Paint a help button (circle with question mark).
|
||||
@@ -60,6 +80,15 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String BUTTON_TYPE_HELP = "help";
|
||||
|
||||
/**
|
||||
* Paint the button in toolbar style.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
|
||||
*
|
||||
* @see #BUTTON_TYPE
|
||||
*/
|
||||
String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarButton";
|
||||
|
||||
/**
|
||||
* Specifies selected state of a checkbox.
|
||||
* <p>
|
||||
@@ -76,14 +105,143 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SELECTED_STATE_INDETERMINATE = "indeterminate";
|
||||
|
||||
/**
|
||||
* Specifies whether the button preferred size will be made square (quadratically).
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SQUARE_SIZE = "JButton.squareSize";
|
||||
|
||||
//---- JComponent ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies minimum width of a component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton} and {@link javax.swing.text.JTextComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton},
|
||||
* {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner} and {@link javax.swing.text.JTextComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String MINIMUM_WIDTH = "JComponent.minimumWidth";
|
||||
|
||||
/**
|
||||
* Specifies minimum height of a component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String MINIMUM_HEIGHT = "JComponent.minimumHeight";
|
||||
|
||||
/**
|
||||
* Paint the component with round edges.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField}, {@link javax.swing.JFormattedTextField} and {@link javax.swing.JPasswordField}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String COMPONENT_ROUND_RECT = "JComponent.roundRect";
|
||||
|
||||
/**
|
||||
* Specifies the outline color of the component border.
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton}, {@link javax.swing.JComboBox},
|
||||
* {@link javax.swing.JFormattedTextField}, {@link javax.swing.JPasswordField},
|
||||
* {@link javax.swing.JScrollPane}, {@link javax.swing.JSpinner},
|
||||
* {@link javax.swing.JTextField} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String} or {@link java.awt.Color} or {@link java.awt.Color}[2]<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #OUTLINE_ERROR},
|
||||
* {@link #OUTLINE_WARNING},
|
||||
* any color (type {@link java.awt.Color}) or
|
||||
* an array of two colors (type {@link java.awt.Color}[2]) where the first color
|
||||
* is for focused state and the second for unfocused state
|
||||
*/
|
||||
String OUTLINE = "JComponent.outline";
|
||||
|
||||
/**
|
||||
* Paint the component border in another color (usually reddish) to indicate an error.
|
||||
*
|
||||
* @see #OUTLINE
|
||||
*/
|
||||
String OUTLINE_ERROR = "error";
|
||||
|
||||
/**
|
||||
* Paint the component border in another color (usually yellowish) to indicate a warning.
|
||||
*
|
||||
* @see #OUTLINE
|
||||
*/
|
||||
String OUTLINE_WARNING = "warning";
|
||||
|
||||
/**
|
||||
* Specifies a callback that is invoked to check whether a component is permanent focus owner.
|
||||
* Used to paint focus indicators.
|
||||
* <p>
|
||||
* May be useful in special cases for custom components.
|
||||
* <p>
|
||||
* Use a {@link java.util.function.Predicate} that receives the component as parameter:
|
||||
* <pre>{@code
|
||||
* myComponent.putClientProperty( "JComponent.focusOwner",
|
||||
* (Predicate<JComponent>) c -> {
|
||||
* return ...; // check here
|
||||
* } );
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.util.function.Predicate}<javax.swing.JComponent>
|
||||
*/
|
||||
String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner";
|
||||
|
||||
//---- Popup --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether a drop shadow is painted if the component is shown in a popup
|
||||
* or if the component is the owner of another component that is shown in a popup.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String POPUP_DROP_SHADOW_PAINTED = "Popup.dropShadowPainted";
|
||||
|
||||
/**
|
||||
* Specifies whether a heavy weight window should be used if the component is shown in a popup
|
||||
* or if the component is the owner of another component that is shown in a popup.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight";
|
||||
|
||||
//---- JProgressBar -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the progress bar has always the larger height even if no string is painted.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JProgressBar}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String PROGRESS_BAR_LARGE_HEIGHT = "JProgressBar.largeHeight";
|
||||
|
||||
/**
|
||||
* Specifies whether the progress bar is paint with square edges.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JProgressBar}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String PROGRESS_BAR_SQUARE = "JProgressBar.square";
|
||||
|
||||
//---- JRootPane ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the menu bar is embedded into the title pane if custom
|
||||
* window decorations are enabled. Default is {@code true}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
|
||||
|
||||
//---- JScrollBar / JScrollPane -------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether the decrease/increase arrow buttons of a scrollbar are shown.
|
||||
* <p>
|
||||
@@ -92,6 +250,16 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons";
|
||||
|
||||
/**
|
||||
* Specifies whether the scroll pane uses smooth scrolling.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JScrollPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
|
||||
|
||||
//---- JTabbedPane --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether separators are shown between tabs.
|
||||
* <p>
|
||||
@@ -100,6 +268,14 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TABBED_PANE_SHOW_TAB_SEPARATORS = "JTabbedPane.showTabSeparators";
|
||||
|
||||
/**
|
||||
* Specifies whether the separator between tabs area and content area should be shown.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TABBED_PANE_SHOW_CONTENT_SEPARATOR = "JTabbedPane.showContentSeparator";
|
||||
|
||||
/**
|
||||
* Specifies whether a full border is painted around a tabbed pane.
|
||||
* <p>
|
||||
@@ -108,14 +284,438 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder";
|
||||
|
||||
/**
|
||||
* Specifies whether the tab area should be hidden if it contains only one tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB = "JTabbedPane.hideTabAreaWithOneTab";
|
||||
|
||||
/**
|
||||
* Specifies the minimum width of a tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String TABBED_PANE_MINIMUM_TAB_WIDTH = "JTabbedPane.minimumTabWidth";
|
||||
|
||||
/**
|
||||
* Specifies the maximum width of a tab.
|
||||
* <p>
|
||||
* Applied only if tab does not have a custom tab component
|
||||
* (see {@link javax.swing.JTabbedPane#setTabComponentAt(int, java.awt.Component)}).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String TABBED_PANE_MAXIMUM_TAB_WIDTH = "JTabbedPane.maximumTabWidth";
|
||||
|
||||
/**
|
||||
* Specifies the minimum height of a tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_INSETS
|
||||
*/
|
||||
String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight";
|
||||
|
||||
/**
|
||||
* Specifies the insets of a tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_HEIGHT
|
||||
*/
|
||||
String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets";
|
||||
|
||||
/**
|
||||
* Specifies the insets of the tab area.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||
*/
|
||||
String TABBED_PANE_TAB_AREA_INSETS = "JTabbedPane.tabAreaInsets";
|
||||
|
||||
/**
|
||||
* Specifies whether tabs are closable.
|
||||
* If set to {@code true} on a tabbed pane component, all tabs in that tabbed pane are closable.
|
||||
* To make individual tabs closable, set it to {@code true} on a tab content component.
|
||||
* <p>
|
||||
* Note that you have to specify a callback (see {@link #TABBED_PANE_TAB_CLOSABLE})
|
||||
* that is invoked when the user clicks a tab close button.
|
||||
* The callback is responsible for closing the tab.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSE_CALLBACK
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSABLE = "JTabbedPane.tabClosable";
|
||||
|
||||
/**
|
||||
* Specifies the tooltip text used for tab close buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSABLE
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JTabbedPane.tabCloseToolTipText";
|
||||
|
||||
/**
|
||||
* Specifies the callback that is invoked when a tab close button is clicked.
|
||||
* The callback is responsible for closing the tab.
|
||||
* <p>
|
||||
* Either use a {@link java.util.function.IntConsumer} that receives the tab index as parameter:
|
||||
* <pre>{@code
|
||||
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
|
||||
* (IntConsumer) tabIndex -> {
|
||||
* // close tab here
|
||||
* } );
|
||||
* }</pre>
|
||||
* Or use a {@link java.util.function.BiConsumer}<javax.swing.JTabbedPane, Integer>
|
||||
* that receives the tabbed pane and the tab index as parameters:
|
||||
* <pre>{@code
|
||||
* myTabbedPane.putClientProperty( "JTabbedPane.tabCloseCallback",
|
||||
* (BiConsumer<JTabbedPane, Integer>) (tabbedPane, tabIndex) -> {
|
||||
* // close tab here
|
||||
* } );
|
||||
* }</pre>
|
||||
* If you need to check whether a modifier key (e.g. Alt or Shift) was pressed
|
||||
* while the user clicked the tab close button, use {@link java.awt.EventQueue#getCurrentEvent}
|
||||
* to get current event, check whether it is a {@link java.awt.event.MouseEvent}
|
||||
* and invoke its methods. E.g.
|
||||
* <pre>{@code
|
||||
* AWTEvent e = EventQueue.getCurrentEvent();
|
||||
* boolean shift = (e instanceof MouseEvent) ? ((MouseEvent)e).isShiftDown() : false;
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.util.function.IntConsumer}
|
||||
* or {@link java.util.function.BiConsumer}<javax.swing.JTabbedPane, Integer>
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_CLOSABLE
|
||||
*/
|
||||
String TABBED_PANE_TAB_CLOSE_CALLBACK = "JTabbedPane.tabCloseCallback";
|
||||
|
||||
/**
|
||||
* Specifies the display policy for the "more tabs" button,
|
||||
* which shows a popup menu with the (partly) hidden tabs.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_POLICY_NEVER} or
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED}
|
||||
*/
|
||||
String TABBED_PANE_TABS_POPUP_POLICY = "JTabbedPane.tabsPopupPolicy";
|
||||
|
||||
/**
|
||||
* Specifies the display policy for the forward/backward scroll arrow buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_POLICY_NEVER},
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED} or
|
||||
* {@link #TABBED_PANE_POLICY_AS_NEEDED_SINGLE}
|
||||
*/
|
||||
String TABBED_PANE_SCROLL_BUTTONS_POLICY = "JTabbedPane.scrollButtonsPolicy";
|
||||
|
||||
/**
|
||||
* Display never.
|
||||
*
|
||||
* @see #TABBED_PANE_TABS_POPUP_POLICY
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_NEVER = "never";
|
||||
|
||||
/**
|
||||
* Display only when needed.
|
||||
* <p>
|
||||
* If used for {@link #TABBED_PANE_SCROLL_BUTTONS_POLICY}, both scroll arrow buttons
|
||||
* are either shown or hidden. Buttons are disabled if scrolling in that
|
||||
* direction is not applicable.
|
||||
*
|
||||
* @see #TABBED_PANE_TABS_POPUP_POLICY
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_AS_NEEDED = "asNeeded";
|
||||
|
||||
/**
|
||||
* Display single button only when needed.
|
||||
* <p>
|
||||
* If scroll button placement is trailing, then this option is ignored
|
||||
* and both buttons are shown or hidden as needed.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_POLICY
|
||||
*/
|
||||
String TABBED_PANE_POLICY_AS_NEEDED_SINGLE = "asNeededSingle";
|
||||
|
||||
/**
|
||||
* Specifies the placement of the forward/backward scroll arrow buttons.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_PLACEMENT_BOTH} or
|
||||
* {@link #TABBED_PANE_PLACEMENT_TRAILING}
|
||||
*/
|
||||
String TABBED_PANE_SCROLL_BUTTONS_PLACEMENT = "JTabbedPane.scrollButtonsPlacement";
|
||||
|
||||
/**
|
||||
* The forward/backward scroll arrow buttons are placed on both sides of the tab area.
|
||||
* The backward scroll button at the left/top side.
|
||||
* The forward scroll button at the right/bottom side.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
|
||||
*/
|
||||
String TABBED_PANE_PLACEMENT_BOTH = "both";
|
||||
|
||||
/**
|
||||
* The forward/backward scroll arrow buttons are placed on the trailing side of the tab area.
|
||||
*
|
||||
* @see #TABBED_PANE_SCROLL_BUTTONS_PLACEMENT
|
||||
*/
|
||||
String TABBED_PANE_PLACEMENT_TRAILING = "trailing";
|
||||
|
||||
/**
|
||||
* Specifies the alignment of the tab area.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING} (default)
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#CENTER},
|
||||
* {@link #TABBED_PANE_ALIGN_LEADING} (default),
|
||||
* {@link #TABBED_PANE_ALIGN_TRAILING},
|
||||
* {@link #TABBED_PANE_ALIGN_CENTER} or
|
||||
* {@link #TABBED_PANE_ALIGN_FILL}
|
||||
*/
|
||||
String TABBED_PANE_TAB_AREA_ALIGNMENT = "JTabbedPane.tabAreaAlignment";
|
||||
|
||||
/**
|
||||
* Specifies the horizontal alignment of the tab title and icon.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}
|
||||
* or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING},
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#CENTER} (default),
|
||||
* {@link #TABBED_PANE_ALIGN_LEADING},
|
||||
* {@link #TABBED_PANE_ALIGN_TRAILING} or
|
||||
* {@link #TABBED_PANE_ALIGN_CENTER} (default)
|
||||
*/
|
||||
String TABBED_PANE_TAB_ALIGNMENT = "JTabbedPane.tabAlignment";
|
||||
|
||||
/**
|
||||
* Align to the leading edge.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_LEADING = "leading";
|
||||
|
||||
/**
|
||||
* Align to the trailing edge.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_TRAILING = "trailing";
|
||||
|
||||
/**
|
||||
* Align to center.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
* @see #TABBED_PANE_TAB_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_CENTER = "center";
|
||||
|
||||
/**
|
||||
* Stretch to fill all available space.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_AREA_ALIGNMENT
|
||||
*/
|
||||
String TABBED_PANE_ALIGN_FILL = "fill";
|
||||
|
||||
/**
|
||||
* Specifies how the tabs should be sized.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_PREFERRED} (default),
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_EQUAL} or
|
||||
* {@link #TABBED_PANE_TAB_WIDTH_MODE_COMPACT}
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode";
|
||||
|
||||
/**
|
||||
* Tab width is adjusted to tab icon and title.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_PREFERRED = "preferred";
|
||||
|
||||
/**
|
||||
* All tabs in a tabbed pane has same width.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal";
|
||||
|
||||
/**
|
||||
* Unselected tabs are smaller because they show only the tab icon, but no tab title.
|
||||
* Selected tabs show both.
|
||||
*
|
||||
* @see #TABBED_PANE_TAB_WIDTH_MODE
|
||||
*/
|
||||
String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact";
|
||||
|
||||
/**
|
||||
* Specifies the tab icon placement (relative to tab title).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING} (default),
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#TOP} or
|
||||
* {@link SwingConstants#BOTTOM}
|
||||
*/
|
||||
String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement";
|
||||
|
||||
/**
|
||||
* Specifies a component that will be placed at the leading edge of the tabs area.
|
||||
* <p>
|
||||
* For top and bottom tab placement, the layed out component size will be
|
||||
* the preferred component width and the tab area height.<br>
|
||||
* For left and right tab placement, the layed out component size will be
|
||||
* the tab area width and the preferred component height.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Component}
|
||||
*/
|
||||
String TABBED_PANE_LEADING_COMPONENT = "JTabbedPane.leadingComponent";
|
||||
|
||||
/**
|
||||
* Specifies a component that will be placed at the trailing edge of the tabs area.
|
||||
* <p>
|
||||
* For top and bottom tab placement, the layed out component size will be
|
||||
* the available horizontal space (minimum is preferred component width) and the tab area height.<br>
|
||||
* For left and right tab placement, the layed out component size will be
|
||||
* the tab area width and the available vertical space (minimum is preferred component height).
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Component}
|
||||
*/
|
||||
String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent";
|
||||
|
||||
//---- JTextField ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies whether all text is selected when the text component gains focus.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
|
||||
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
|
||||
*/
|
||||
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
|
||||
|
||||
/**
|
||||
* Never select all text when the text component gains focus.
|
||||
*
|
||||
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
||||
*/
|
||||
String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never";
|
||||
|
||||
/**
|
||||
* Select all text when the text component gains focus for the first time
|
||||
* and selection was not modified (is at end of text).
|
||||
* This is the default.
|
||||
*
|
||||
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
||||
*/
|
||||
String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once";
|
||||
|
||||
/**
|
||||
* Always select all text when the text component gains focus.
|
||||
*
|
||||
* @see #SELECT_ALL_ON_FOCUS_POLICY
|
||||
*/
|
||||
String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always";
|
||||
|
||||
/**
|
||||
* Placeholder text that is only painted if the text field is empty.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} or {@link javax.swing.JComboBox}<br>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses) or {@link javax.swing.JComboBox}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.String}
|
||||
*/
|
||||
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
|
||||
|
||||
//---- JToggleButton ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Height of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*/
|
||||
String TAB_BUTTON_UNDERLINE_HEIGHT = "JToggleButton.tab.underlineHeight";
|
||||
|
||||
/**
|
||||
* Color of underline if toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Color}
|
||||
*/
|
||||
String TAB_BUTTON_UNDERLINE_COLOR = "JToggleButton.tab.underlineColor";
|
||||
|
||||
/**
|
||||
* Background color if selected and toggle button type is {@link #BUTTON_TYPE_TAB}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Color}
|
||||
*/
|
||||
String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground";
|
||||
|
||||
//---- JTree --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Override if a tree shows a wide selection. Default is {@code true}.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTree}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TREE_WIDE_SELECTION = "JTree.wideSelection";
|
||||
|
||||
/**
|
||||
* Specifies whether tree item selection is painted. Default is {@code true}.
|
||||
* If set to {@code false}, then the tree cell renderer is responsible for painting selection.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTree}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String TREE_PAINT_SELECTION = "JTree.paintSelection";
|
||||
|
||||
//---- helper methods -----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component has the given value.
|
||||
*/
|
||||
@@ -131,4 +731,31 @@ public interface FlatClientProperties
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Boolean) ? (boolean) value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component is a {@link Boolean} and returns its value.
|
||||
* If the client property is not set, or not a {@link Boolean}, defaultValue is returned.
|
||||
*/
|
||||
static Boolean clientPropertyBooleanStrict( JComponent c, String key, Boolean defaultValue ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Boolean) ? (Boolean) value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component is an integer and returns its value.
|
||||
* If the client property is not set, or not an integer, defaultValue is returned.
|
||||
*/
|
||||
static int clientPropertyInt( JComponent c, String key, int defaultValue ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Integer) ? (int) value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client property of a component is a color and returns its value.
|
||||
* If the client property is not set, or not a color, defaultValue is returned.
|
||||
*/
|
||||
static Color clientPropertyColor( JComponent c, String key, Color defaultValue ) {
|
||||
Object value = c.getClientProperty( key );
|
||||
return (value instanceof Color) ? (Color) value : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,25 +18,32 @@ package com.formdev.flatlaf;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a dark color scheme and looks like Darcula LaF.
|
||||
*
|
||||
* The UI defaults are loaded from FlatDarculaLaf.properties, FlatDarkLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatDarculaLaf.properties},
|
||||
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDarculaLaf
|
||||
extends FlatDarkLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Darcula";
|
||||
|
||||
public static boolean install() {
|
||||
return install( new FlatDarculaLaf() );
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatDarculaLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Darcula";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Darcula Look and Feel";
|
||||
return "FlatLaf Darcula Look and Feel";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,28 +16,46 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a dark color scheme.
|
||||
*
|
||||
* The UI defaults are loaded from FlatDarkLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDarkLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Dark";
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to this LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install() {
|
||||
return install( new FlatDarkLaf() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this look and feel to the set of available look and feels.
|
||||
* <p>
|
||||
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||
* to query available LaFs and display them to the user in a combobox.
|
||||
*/
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatDarkLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Dark";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Dark Look and Feel";
|
||||
return "FlatLaf Dark Look and Feel";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.io.InputStream;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIDefaults;
|
||||
|
||||
/**
|
||||
* Addon for FlatLaf UI defaults.
|
||||
@@ -50,6 +52,13 @@ public abstract class FlatDefaultsAddon
|
||||
return addonClass.getResourceAsStream( propertiesName );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows modifying UI defaults after loading UI defaults.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
public void afterDefaultsLoading( LookAndFeel laf, UIDefaults defaults ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority used to sort addon loading.
|
||||
* The order is only important if you want overwrite UI defaults of other addons.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
/**
|
||||
* Default color palette for action icons and object icons.
|
||||
* <p>
|
||||
* The idea is to use only this well defined set of colors in SVG icons and
|
||||
* then they are replaced at runtime to dark variants or to other theme colors.
|
||||
* Then a single SVG icon (light variant) can be used for dark themes too.
|
||||
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
|
||||
* <p>
|
||||
* Use the {@code *_DARK} colors only in {@code *_dark.svg} files.
|
||||
* <p>
|
||||
* The colors are based on IntelliJ Platform
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
|
||||
* and
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
|
||||
* <p>
|
||||
* These colors may be changed by IntelliJ Platform themes.
|
||||
* <p>
|
||||
* You may use these colors also in your application (outside of SVG icons), but do
|
||||
* not use the RGB values defined in this enum.<br>
|
||||
* Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public enum FlatIconColors
|
||||
{
|
||||
// colors for action icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#action-icons
|
||||
ACTIONS_RED ( 0xDB5860, "Actions.Red", true, false ),
|
||||
ACTIONS_RED_DARK ( 0xC75450, "Actions.Red", false, true ),
|
||||
ACTIONS_YELLOW ( 0xEDA200, "Actions.Yellow", true, false ),
|
||||
ACTIONS_YELLOW_DARK ( 0xF0A732, "Actions.Yellow", false, true ),
|
||||
ACTIONS_GREEN ( 0x59A869, "Actions.Green", true, false ),
|
||||
ACTIONS_GREEN_DARK ( 0x499C54, "Actions.Green", false, true ),
|
||||
ACTIONS_BLUE ( 0x389FD6, "Actions.Blue", true, false ),
|
||||
ACTIONS_BLUE_DARK ( 0x3592C4, "Actions.Blue", false, true ),
|
||||
ACTIONS_GREY ( 0x6E6E6E, "Actions.Grey", true, false ),
|
||||
ACTIONS_GREY_DARK ( 0xAFB1B3, "Actions.Grey", false, true ),
|
||||
ACTIONS_GREYINLINE ( 0x7F8B91, "Actions.GreyInline", true, false ),
|
||||
ACTIONS_GREYINLINE_DARK ( 0x7F8B91, "Actions.GreyInline", false, true ),
|
||||
|
||||
// colors for object icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#noun-icons
|
||||
OBJECTS_GREY ( 0x9AA7B0, "Objects.Grey" ),
|
||||
OBJECTS_BLUE ( 0x40B6E0, "Objects.Blue" ),
|
||||
OBJECTS_GREEN ( 0x62B543, "Objects.Green" ),
|
||||
OBJECTS_YELLOW ( 0xF4AF3D, "Objects.Yellow" ),
|
||||
OBJECTS_YELLOW_DARK ( 0xD9A343, "Objects.YellowDark" ),
|
||||
OBJECTS_PURPLE ( 0xB99BF8, "Objects.Purple" ),
|
||||
OBJECTS_PINK ( 0xF98B9E, "Objects.Pink" ),
|
||||
OBJECTS_RED ( 0xF26522, "Objects.Red" ),
|
||||
OBJECTS_RED_STATUS ( 0xE05555, "Objects.RedStatus" ),
|
||||
OBJECTS_GREEN_ANDROID ( 0xA4C639, "Objects.GreenAndroid" ),
|
||||
OBJECTS_BLACK_TEXT ( 0x231F20, "Objects.BlackText" );
|
||||
|
||||
public final int rgb;
|
||||
public final String key;
|
||||
|
||||
public final boolean light;
|
||||
public final boolean dark;
|
||||
|
||||
FlatIconColors( int rgb, String key ) {
|
||||
this( rgb, key, true, true );
|
||||
}
|
||||
|
||||
FlatIconColors( int rgb, String key, boolean light, boolean dark ) {
|
||||
this.rgb = rgb;
|
||||
this.key = key;
|
||||
this.light = light;
|
||||
this.dark = dark;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,660 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIDefaults.LazyValue;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.InputMapUIResource;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import static javax.swing.text.DefaultEditorKit.*;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class FlatInputMaps
|
||||
{
|
||||
static void initInputMaps( UIDefaults defaults ) {
|
||||
initBasicInputMaps( defaults );
|
||||
initTextComponentInputMaps( defaults );
|
||||
|
||||
if( SystemInfo.isMacOS )
|
||||
initMacInputMaps( defaults );
|
||||
}
|
||||
|
||||
private static void initBasicInputMaps( UIDefaults defaults ) {
|
||||
if( SystemInfo.isMacOS ) {
|
||||
defaults.put( "Button.focusInputMap", new UIDefaults.LazyInputMap( new Object[] {
|
||||
"SPACE", "pressed",
|
||||
"released SPACE", "released"
|
||||
} ) );
|
||||
}
|
||||
|
||||
modifyInputMap( defaults, "ComboBox.ancestorInputMap",
|
||||
"SPACE", "spacePopup",
|
||||
|
||||
"UP", mac( "selectPrevious2", "selectPrevious" ),
|
||||
"DOWN", mac( "selectNext2", "selectNext" ),
|
||||
"KP_UP", mac( "selectPrevious2", "selectPrevious" ),
|
||||
"KP_DOWN", mac( "selectNext2", "selectNext" ),
|
||||
|
||||
mac( "alt UP", null ), "togglePopup",
|
||||
mac( "alt DOWN", null ), "togglePopup",
|
||||
mac( "alt KP_UP", null ), "togglePopup",
|
||||
mac( "alt KP_DOWN", null ), "togglePopup"
|
||||
);
|
||||
|
||||
if( !SystemInfo.isMacOS ) {
|
||||
modifyInputMap( defaults, "FileChooser.ancestorInputMap",
|
||||
"F2", "editFileName",
|
||||
"BACK_SPACE", "Go Up"
|
||||
);
|
||||
}
|
||||
|
||||
// join ltr and rtl bindings to fix up/down/etc keys in right-to-left component orientation
|
||||
Object[] bindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings" );
|
||||
Object[] rtlBindings = (Object[]) defaults.get( "PopupMenu.selectedWindowInputMapBindings.RightToLeft" );
|
||||
if( bindings != null && rtlBindings != null ) {
|
||||
Object[] newBindings = new Object[bindings.length + rtlBindings.length];
|
||||
System.arraycopy( bindings, 0, newBindings, 0, bindings.length );
|
||||
System.arraycopy( rtlBindings, 0, newBindings, bindings.length, rtlBindings.length );
|
||||
defaults.put( "PopupMenu.selectedWindowInputMapBindings.RightToLeft", newBindings );
|
||||
}
|
||||
|
||||
modifyInputMap( defaults, "TabbedPane.ancestorInputMap",
|
||||
"ctrl TAB", "navigateNext",
|
||||
"shift ctrl TAB", "navigatePrevious"
|
||||
);
|
||||
|
||||
// swap Home/End with Ctrl+Home/End to make it consistent with List and Tree
|
||||
modifyInputMap( () -> {
|
||||
return UIManager.getBoolean( "Table.consistentHomeEndKeyBehavior" );
|
||||
},
|
||||
defaults, "Table.ancestorInputMap",
|
||||
"HOME", "selectFirstRow",
|
||||
"END", "selectLastRow",
|
||||
"shift HOME", "selectFirstRowExtendSelection",
|
||||
"shift END", "selectLastRowExtendSelection",
|
||||
mac( "ctrl HOME", null ), "selectFirstColumn",
|
||||
mac( "ctrl END", null ), "selectLastColumn",
|
||||
mac( "shift ctrl HOME", null ), "selectFirstColumnExtendSelection",
|
||||
mac( "shift ctrl END", null ), "selectLastColumnExtendSelection"
|
||||
);
|
||||
|
||||
if( !SystemInfo.isMacOS ) {
|
||||
modifyInputMap( defaults, "Tree.focusInputMap",
|
||||
"ADD", "expand",
|
||||
"SUBTRACT", "collapse"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initTextComponentInputMaps( UIDefaults defaults ) {
|
||||
Object[] commonTextComponentBindings = {
|
||||
// move caret one character (without selecting text)
|
||||
"LEFT", backwardAction,
|
||||
"RIGHT", forwardAction,
|
||||
"KP_LEFT", backwardAction,
|
||||
"KP_RIGHT", forwardAction,
|
||||
|
||||
// move caret one character and select text
|
||||
"shift LEFT", selectionBackwardAction,
|
||||
"shift RIGHT", selectionForwardAction,
|
||||
"shift KP_LEFT", selectionBackwardAction,
|
||||
"shift KP_RIGHT", selectionForwardAction,
|
||||
|
||||
// move caret to word (without selecting text)
|
||||
mac( "ctrl LEFT", "alt LEFT" ), previousWordAction,
|
||||
mac( "ctrl RIGHT", "alt RIGHT" ), nextWordAction,
|
||||
mac( "ctrl KP_LEFT", "alt KP_LEFT" ), previousWordAction,
|
||||
mac( "ctrl KP_RIGHT", "alt KP_RIGHT" ), nextWordAction,
|
||||
|
||||
// move caret to word and select text
|
||||
mac( "ctrl shift LEFT", "shift alt LEFT" ), selectionPreviousWordAction,
|
||||
mac( "ctrl shift RIGHT", "shift alt RIGHT" ), selectionNextWordAction,
|
||||
mac( "ctrl shift KP_LEFT", "shift alt KP_LEFT" ), selectionPreviousWordAction,
|
||||
mac( "ctrl shift KP_RIGHT", "shift alt KP_RIGHT" ), selectionNextWordAction,
|
||||
|
||||
// move caret to line begin/end (without selecting text)
|
||||
mac( "HOME", "meta LEFT" ), beginLineAction,
|
||||
mac( "END", "meta RIGHT" ), endLineAction,
|
||||
|
||||
// move caret to line begin/end and select text
|
||||
mac( "shift HOME", "shift meta LEFT" ), selectionBeginLineAction,
|
||||
mac( "shift END", "shift meta RIGHT" ), selectionEndLineAction,
|
||||
|
||||
// select all/none
|
||||
mac( "ctrl A", "meta A" ), selectAllAction,
|
||||
mac( "ctrl BACK_SLASH", "meta BACK_SLASH" ), "unselect", // DefaultEditorKit.unselectAction
|
||||
|
||||
// delete previous/next character
|
||||
"BACK_SPACE", deletePrevCharAction,
|
||||
"shift BACK_SPACE", deletePrevCharAction,
|
||||
"ctrl H", deletePrevCharAction,
|
||||
"DELETE", deleteNextCharAction,
|
||||
|
||||
// delete previous/next word
|
||||
mac( "ctrl BACK_SPACE", "alt BACK_SPACE" ), deletePrevWordAction,
|
||||
mac( "ctrl DELETE", "alt DELETE" ), deleteNextWordAction,
|
||||
|
||||
// clipboard
|
||||
mac( "ctrl X", "meta X" ), cutAction,
|
||||
mac( "ctrl C", "meta C" ), copyAction,
|
||||
mac( "ctrl V", "meta V" ), pasteAction,
|
||||
"CUT", cutAction,
|
||||
"COPY", copyAction,
|
||||
"PASTE", pasteAction,
|
||||
mac( "shift DELETE", null ), cutAction,
|
||||
mac( "control INSERT", null ), copyAction,
|
||||
mac( "shift INSERT", null ), pasteAction,
|
||||
|
||||
// misc
|
||||
"control shift O", "toggle-componentOrientation", // DefaultEditorKit.toggleComponentOrientation
|
||||
};
|
||||
|
||||
Object[] macCommonTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret one character (without selecting text)
|
||||
"ctrl B", backwardAction,
|
||||
"ctrl F", forwardAction,
|
||||
|
||||
// move caret to document begin/end (without selecting text)
|
||||
"HOME", beginAction,
|
||||
"END", endAction,
|
||||
"meta UP", beginAction,
|
||||
"meta DOWN", endAction,
|
||||
"meta KP_UP", beginAction,
|
||||
"meta KP_DOWN", endAction,
|
||||
"ctrl P", beginAction,
|
||||
"ctrl N", endAction,
|
||||
"ctrl V", endAction,
|
||||
|
||||
// move caret to line begin/end (without selecting text)
|
||||
"meta KP_LEFT", beginLineAction,
|
||||
"meta KP_RIGHT", endLineAction,
|
||||
"ctrl A", beginLineAction,
|
||||
"ctrl E", endLineAction,
|
||||
|
||||
// move caret to document begin/end and select text
|
||||
"shift meta UP", selectionBeginAction,
|
||||
"shift meta DOWN", selectionEndAction,
|
||||
"shift meta KP_UP", selectionBeginAction,
|
||||
"shift meta KP_DOWN", selectionEndAction,
|
||||
"shift HOME", selectionBeginAction,
|
||||
"shift END", selectionEndAction,
|
||||
|
||||
// move caret to line begin/end and select text
|
||||
"shift meta KP_LEFT", selectionBeginLineAction,
|
||||
"shift meta KP_RIGHT", selectionEndLineAction,
|
||||
"shift UP", selectionBeginLineAction,
|
||||
"shift DOWN", selectionEndLineAction,
|
||||
"shift KP_UP", selectionBeginLineAction,
|
||||
"shift KP_DOWN", selectionEndLineAction,
|
||||
|
||||
// delete previous/next word
|
||||
"ctrl W", deletePrevWordAction,
|
||||
"ctrl D", deleteNextCharAction,
|
||||
} : null;
|
||||
|
||||
Object[] singleLineTextComponentBindings = {
|
||||
"ENTER", JTextField.notifyAction,
|
||||
};
|
||||
|
||||
Object[] macSingleLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret to line begin/end (without selecting text)
|
||||
"UP", beginLineAction,
|
||||
"DOWN", endLineAction,
|
||||
"KP_UP", beginLineAction,
|
||||
"KP_DOWN", endLineAction,
|
||||
} : null;
|
||||
|
||||
Object[] formattedTextComponentBindings = {
|
||||
// reset
|
||||
"ESCAPE", "reset-field-edit",
|
||||
|
||||
// increment/decrement
|
||||
"UP", "increment",
|
||||
"DOWN", "decrement",
|
||||
"KP_UP", "increment",
|
||||
"KP_DOWN", "decrement",
|
||||
};
|
||||
|
||||
Object[] passwordTextComponentBindings = {
|
||||
// move caret to line begin/end (without selecting text)
|
||||
mac( "ctrl LEFT", "alt LEFT" ), beginLineAction,
|
||||
mac( "ctrl RIGHT", "alt RIGHT" ), endLineAction,
|
||||
mac( "ctrl KP_LEFT", "alt KP_LEFT" ), beginLineAction,
|
||||
mac( "ctrl KP_RIGHT", "alt KP_RIGHT" ), endLineAction,
|
||||
|
||||
// move caret to line begin/end and select text
|
||||
mac( "ctrl shift LEFT", "shift alt LEFT" ), selectionBeginLineAction,
|
||||
mac( "ctrl shift RIGHT", "shift alt RIGHT" ), selectionEndLineAction,
|
||||
mac( "ctrl shift KP_LEFT", "shift alt KP_LEFT" ), selectionBeginLineAction,
|
||||
mac( "ctrl shift KP_RIGHT", "shift alt KP_RIGHT" ), selectionEndLineAction,
|
||||
|
||||
// delete previous/next word
|
||||
mac( "ctrl BACK_SPACE", "alt BACK_SPACE" ), null,
|
||||
mac( "ctrl DELETE", "alt DELETE" ), null,
|
||||
};
|
||||
|
||||
Object[] multiLineTextComponentBindings = {
|
||||
// move caret one line (without selecting text)
|
||||
"UP", upAction,
|
||||
"DOWN", downAction,
|
||||
"KP_UP", upAction,
|
||||
"KP_DOWN", downAction,
|
||||
|
||||
// move caret one line and select text
|
||||
"shift UP", selectionUpAction,
|
||||
"shift DOWN", selectionDownAction,
|
||||
"shift KP_UP", selectionUpAction,
|
||||
"shift KP_DOWN", selectionDownAction,
|
||||
|
||||
// move caret one page (without selecting text)
|
||||
"PAGE_UP", pageUpAction,
|
||||
"PAGE_DOWN", pageDownAction,
|
||||
|
||||
// move caret one page and select text
|
||||
"shift PAGE_UP", "selection-page-up", // DefaultEditorKit.selectionPageUpAction
|
||||
"shift PAGE_DOWN", "selection-page-down", // DefaultEditorKit.selectionPageDownAction
|
||||
mac( "ctrl shift PAGE_UP", "shift meta PAGE_UP" ), "selection-page-left", // DefaultEditorKit.selectionPageLeftAction
|
||||
mac( "ctrl shift PAGE_DOWN", "shift meta PAGE_DOWN" ), "selection-page-right", // DefaultEditorKit.selectionPageRightAction
|
||||
|
||||
// move caret to document begin/end (without selecting text)
|
||||
mac( "ctrl HOME", "meta UP" ), beginAction,
|
||||
mac( "ctrl END", "meta DOWN" ), endAction,
|
||||
|
||||
// move caret to document begin/end and select text
|
||||
mac( "ctrl shift HOME", "shift meta UP" ), selectionBeginAction,
|
||||
mac( "ctrl shift END", "shift meta DOWN" ), selectionEndAction,
|
||||
|
||||
// misc
|
||||
"ENTER", insertBreakAction,
|
||||
"TAB", insertTabAction,
|
||||
|
||||
// links
|
||||
mac( "ctrl T", "meta T" ), "next-link-action",
|
||||
mac( "ctrl shift T", "shift meta T" ), "previous-link-action",
|
||||
mac( "ctrl SPACE", "meta SPACE" ), "activate-link-action",
|
||||
};
|
||||
|
||||
Object[] macMultiLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
|
||||
// move caret one line (without selecting text)
|
||||
"ctrl N", downAction,
|
||||
"ctrl P", upAction,
|
||||
|
||||
// move caret to beginning/end of paragraph and select text
|
||||
"shift alt UP", selectionBeginParagraphAction,
|
||||
"shift alt DOWN", selectionEndParagraphAction,
|
||||
"shift alt KP_UP", selectionBeginParagraphAction,
|
||||
"shift alt KP_DOWN", selectionEndParagraphAction,
|
||||
|
||||
// move caret one page (without selecting text)
|
||||
"ctrl V", pageDownAction,
|
||||
} : null;
|
||||
|
||||
defaults.put( "TextField.focusInputMap", new LazyInputMapEx(
|
||||
commonTextComponentBindings,
|
||||
macCommonTextComponentBindings,
|
||||
singleLineTextComponentBindings,
|
||||
macSingleLineTextComponentBindings
|
||||
) );
|
||||
defaults.put( "FormattedTextField.focusInputMap", new LazyInputMapEx(
|
||||
commonTextComponentBindings,
|
||||
macCommonTextComponentBindings,
|
||||
singleLineTextComponentBindings,
|
||||
macSingleLineTextComponentBindings,
|
||||
formattedTextComponentBindings
|
||||
) );
|
||||
defaults.put( "PasswordField.focusInputMap", new LazyInputMapEx(
|
||||
commonTextComponentBindings,
|
||||
macCommonTextComponentBindings,
|
||||
singleLineTextComponentBindings,
|
||||
macSingleLineTextComponentBindings,
|
||||
passwordTextComponentBindings
|
||||
) );
|
||||
|
||||
Object multiLineInputMap = new LazyInputMapEx(
|
||||
commonTextComponentBindings,
|
||||
macCommonTextComponentBindings,
|
||||
multiLineTextComponentBindings,
|
||||
macMultiLineTextComponentBindings
|
||||
);
|
||||
defaults.put( "TextArea.focusInputMap", multiLineInputMap );
|
||||
defaults.put( "TextPane.focusInputMap", multiLineInputMap );
|
||||
defaults.put( "EditorPane.focusInputMap", multiLineInputMap );
|
||||
}
|
||||
|
||||
private static void initMacInputMaps( UIDefaults defaults ) {
|
||||
// list
|
||||
modifyInputMap( defaults, "List.focusInputMap",
|
||||
"meta A", "selectAll",
|
||||
"meta C", "copy",
|
||||
"meta V", "paste",
|
||||
"meta X", "cut",
|
||||
|
||||
// let parent scroll pane do the macOS typical scrolling without changing selection
|
||||
"HOME", null,
|
||||
"END", null,
|
||||
"PAGE_UP", null,
|
||||
"PAGE_DOWN", null,
|
||||
|
||||
"ctrl A", null,
|
||||
"ctrl BACK_SLASH", null,
|
||||
"ctrl C", null,
|
||||
"ctrl DOWN", null,
|
||||
"ctrl END", null,
|
||||
"ctrl HOME", null,
|
||||
"ctrl INSERT", null,
|
||||
"ctrl KP_DOWN", null,
|
||||
"ctrl KP_LEFT", null,
|
||||
"ctrl KP_RIGHT", null,
|
||||
"ctrl KP_UP", null,
|
||||
"ctrl LEFT", null,
|
||||
"ctrl PAGE_DOWN", null,
|
||||
"ctrl PAGE_UP", null,
|
||||
"ctrl RIGHT", null,
|
||||
"ctrl SLASH", null,
|
||||
"ctrl SPACE", null,
|
||||
"ctrl UP", null,
|
||||
"ctrl V", null,
|
||||
"ctrl X", null,
|
||||
"SPACE", null,
|
||||
"shift ctrl DOWN", null,
|
||||
"shift ctrl END", null,
|
||||
"shift ctrl HOME", null,
|
||||
"shift ctrl KP_DOWN", null,
|
||||
"shift ctrl KP_LEFT", null,
|
||||
"shift ctrl KP_RIGHT", null,
|
||||
"shift ctrl KP_UP", null,
|
||||
"shift ctrl LEFT", null,
|
||||
"shift ctrl PAGE_DOWN", null,
|
||||
"shift ctrl PAGE_UP", null,
|
||||
"shift ctrl RIGHT", null,
|
||||
"shift ctrl SPACE", null,
|
||||
"shift ctrl UP", null,
|
||||
"shift DELETE", null,
|
||||
"shift INSERT", null,
|
||||
"shift SPACE", null
|
||||
);
|
||||
modifyInputMap( defaults, "List.focusInputMap.RightToLeft",
|
||||
"ctrl KP_LEFT", null,
|
||||
"ctrl KP_RIGHT", null,
|
||||
"ctrl LEFT", null,
|
||||
"ctrl RIGHT", null,
|
||||
"shift ctrl KP_LEFT", null,
|
||||
"shift ctrl KP_RIGHT", null,
|
||||
"shift ctrl LEFT", null,
|
||||
"shift ctrl RIGHT", null
|
||||
);
|
||||
|
||||
// scrollpane
|
||||
modifyInputMap( defaults, "ScrollPane.ancestorInputMap",
|
||||
"END", "scrollEnd",
|
||||
"HOME", "scrollHome",
|
||||
|
||||
"ctrl END", null,
|
||||
"ctrl HOME", null,
|
||||
"ctrl PAGE_DOWN", null,
|
||||
"ctrl PAGE_UP", null
|
||||
);
|
||||
modifyInputMap( defaults, "ScrollPane.ancestorInputMap.RightToLeft",
|
||||
"ctrl PAGE_DOWN", null,
|
||||
"ctrl PAGE_UP", null
|
||||
);
|
||||
|
||||
// tabbedpane
|
||||
modifyInputMap( defaults, "TabbedPane.ancestorInputMap",
|
||||
"ctrl UP", null,
|
||||
"ctrl KP_UP", null
|
||||
);
|
||||
modifyInputMap( defaults, "TabbedPane.focusInputMap",
|
||||
"ctrl DOWN", null,
|
||||
"ctrl KP_DOWN", null
|
||||
);
|
||||
|
||||
// table
|
||||
modifyInputMap( defaults, "Table.ancestorInputMap",
|
||||
"alt TAB", "focusHeader",
|
||||
"shift alt TAB", "focusHeader",
|
||||
"meta A", "selectAll",
|
||||
"meta C", "copy",
|
||||
"meta V", "paste",
|
||||
"meta X", "cut",
|
||||
|
||||
// let parent scroll pane do the macOS typical scrolling without changing selection
|
||||
"HOME", null,
|
||||
"END", null,
|
||||
"PAGE_UP", null,
|
||||
"PAGE_DOWN", null,
|
||||
|
||||
"ctrl A", null,
|
||||
"ctrl BACK_SLASH", null,
|
||||
"ctrl C", null,
|
||||
"ctrl DOWN", null,
|
||||
"ctrl END", null,
|
||||
"ctrl HOME", null,
|
||||
"ctrl INSERT", null,
|
||||
"ctrl KP_DOWN", null,
|
||||
"ctrl KP_LEFT", null,
|
||||
"ctrl KP_RIGHT", null,
|
||||
"ctrl KP_UP", null,
|
||||
"ctrl LEFT", null,
|
||||
"ctrl PAGE_DOWN", null,
|
||||
"ctrl PAGE_UP", null,
|
||||
"ctrl RIGHT", null,
|
||||
"ctrl SLASH", null,
|
||||
"ctrl SPACE", null,
|
||||
"ctrl UP", null,
|
||||
"ctrl V", null,
|
||||
"ctrl X", null,
|
||||
"F2", null,
|
||||
"F8", null,
|
||||
"SPACE", null,
|
||||
"shift ctrl DOWN", null,
|
||||
"shift ctrl END", null,
|
||||
"shift ctrl HOME", null,
|
||||
"shift ctrl KP_DOWN", null,
|
||||
"shift ctrl KP_LEFT", null,
|
||||
"shift ctrl KP_RIGHT", null,
|
||||
"shift ctrl KP_UP", null,
|
||||
"shift ctrl LEFT", null,
|
||||
"shift ctrl PAGE_DOWN", null,
|
||||
"shift ctrl PAGE_UP", null,
|
||||
"shift ctrl RIGHT", null,
|
||||
"shift ctrl SPACE", null,
|
||||
"shift ctrl UP", null,
|
||||
"shift DELETE", null,
|
||||
"shift INSERT", null,
|
||||
"shift SPACE", null
|
||||
);
|
||||
modifyInputMap( defaults, "Table.ancestorInputMap.RightToLeft",
|
||||
"ctrl KP_LEFT", null,
|
||||
"ctrl KP_RIGHT", null,
|
||||
"ctrl LEFT", null,
|
||||
"ctrl RIGHT", null,
|
||||
"shift ctrl KP_LEFT", null,
|
||||
"shift ctrl KP_RIGHT", null,
|
||||
"shift ctrl LEFT", null,
|
||||
"shift ctrl RIGHT", null
|
||||
);
|
||||
|
||||
// tree node expanding/collapsing
|
||||
modifyInputMap( defaults, "Tree.focusInputMap",
|
||||
"LEFT", "selectParent",
|
||||
"RIGHT", "selectChild",
|
||||
"KP_LEFT", "selectParent",
|
||||
"KP_RIGHT", "selectChild",
|
||||
"shift LEFT", "selectParent",
|
||||
"shift RIGHT", "selectChild",
|
||||
"shift KP_LEFT", "selectParent",
|
||||
"shift KP_RIGHT", "selectChild",
|
||||
"alt LEFT", "selectParent",
|
||||
"alt RIGHT", "selectChild",
|
||||
"alt KP_LEFT", "selectParent",
|
||||
"alt KP_RIGHT", "selectChild",
|
||||
|
||||
"shift HOME", "selectFirstExtendSelection",
|
||||
"shift END", "selectLastExtendSelection",
|
||||
|
||||
"meta A", "selectAll",
|
||||
"meta C", "copy",
|
||||
"meta V", "paste",
|
||||
"meta X", "cut",
|
||||
|
||||
// let parent scroll pane do the macOS typical scrolling without changing selection
|
||||
"HOME", null,
|
||||
"END", null,
|
||||
"PAGE_UP", null,
|
||||
"PAGE_DOWN", null,
|
||||
|
||||
"ctrl LEFT", null,
|
||||
"ctrl RIGHT", null,
|
||||
"ctrl KP_LEFT", null,
|
||||
"ctrl KP_RIGHT", null,
|
||||
|
||||
"ctrl A", null,
|
||||
"ctrl BACK_SLASH", null,
|
||||
"ctrl C", null,
|
||||
"ctrl DOWN", null,
|
||||
"ctrl END", null,
|
||||
"ctrl HOME", null,
|
||||
"ctrl INSERT", null,
|
||||
"ctrl KP_DOWN", null,
|
||||
"ctrl KP_UP", null,
|
||||
"ctrl PAGE_DOWN", null,
|
||||
"ctrl PAGE_UP", null,
|
||||
"ctrl SLASH", null,
|
||||
"ctrl SPACE", null,
|
||||
"ctrl UP", null,
|
||||
"ctrl V", null,
|
||||
"ctrl X", null,
|
||||
"F2", null,
|
||||
"SPACE", null,
|
||||
"shift ctrl DOWN", null,
|
||||
"shift ctrl END", null,
|
||||
"shift ctrl HOME", null,
|
||||
"shift ctrl KP_DOWN", null,
|
||||
"shift ctrl KP_UP", null,
|
||||
"shift ctrl PAGE_DOWN", null,
|
||||
"shift ctrl PAGE_UP", null,
|
||||
"shift ctrl SPACE", null,
|
||||
"shift ctrl UP", null,
|
||||
"shift DELETE", null,
|
||||
"shift INSERT", null,
|
||||
"shift PAGE_DOWN", null,
|
||||
"shift PAGE_UP", null,
|
||||
"shift SPACE", null
|
||||
);
|
||||
defaults.put( "Tree.focusInputMap.RightToLeft", new UIDefaults.LazyInputMap( new Object[] {
|
||||
"LEFT", "selectChild",
|
||||
"RIGHT", "selectParent",
|
||||
"KP_LEFT", "selectChild",
|
||||
"KP_RIGHT", "selectParent",
|
||||
"shift LEFT", "selectChild",
|
||||
"shift RIGHT", "selectParent",
|
||||
"shift KP_LEFT", "selectChild",
|
||||
"shift KP_RIGHT", "selectParent",
|
||||
"alt LEFT", "selectChild",
|
||||
"alt RIGHT", "selectParent",
|
||||
"alt KP_LEFT", "selectChild",
|
||||
"alt KP_RIGHT", "selectParent"
|
||||
} ) );
|
||||
}
|
||||
|
||||
private static void modifyInputMap( UIDefaults defaults, String key, Object... bindings ) {
|
||||
modifyInputMap( null, defaults, key, bindings );
|
||||
}
|
||||
|
||||
private static void modifyInputMap( BooleanSupplier condition, UIDefaults defaults, String key, Object... bindings ) {
|
||||
// Note: not using `defaults.get(key)` here because this would resolve a lazy value
|
||||
defaults.put( key, new LazyModifyInputMap( condition, defaults.remove( key ), bindings ) );
|
||||
}
|
||||
|
||||
private static <T> T mac( T value, T macValue ) {
|
||||
return SystemInfo.isMacOS ? macValue : value;
|
||||
}
|
||||
|
||||
//---- class LazyInputMapEx -----------------------------------------------
|
||||
|
||||
/**
|
||||
* Lazily creates a input map.
|
||||
* Similar to {@link UIDefaults.LazyInputMap}, but can use multiple bindings arrays.
|
||||
*/
|
||||
private static class LazyInputMapEx
|
||||
implements LazyValue
|
||||
{
|
||||
private final Object[][] bindingsArray;
|
||||
|
||||
LazyInputMapEx( Object[]... bindingsArray ) {
|
||||
this.bindingsArray = bindingsArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createValue( UIDefaults table ) {
|
||||
InputMap inputMap = new InputMapUIResource();
|
||||
for( Object[] bindings : bindingsArray )
|
||||
LookAndFeel.loadKeyBindings( inputMap, bindings );
|
||||
return inputMap;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class LazyModifyInputMap -------------------------------------------
|
||||
|
||||
/**
|
||||
* Takes a (lazy) base input map and lazily applies modifications to it specified in bindings.
|
||||
*/
|
||||
private static class LazyModifyInputMap
|
||||
implements LazyValue
|
||||
{
|
||||
private final BooleanSupplier condition;
|
||||
private final Object baseInputMap;
|
||||
private final Object[] bindings;
|
||||
|
||||
LazyModifyInputMap( BooleanSupplier condition, Object baseInputMap, Object[] bindings ) {
|
||||
this.condition = condition;
|
||||
this.baseInputMap = baseInputMap;
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createValue( UIDefaults table ) {
|
||||
// get base input map
|
||||
InputMap inputMap = (baseInputMap instanceof LazyValue)
|
||||
? (InputMap) ((LazyValue)baseInputMap).createValue( table )
|
||||
: (InputMap) baseInputMap;
|
||||
|
||||
if( condition != null && !condition.getAsBoolean() )
|
||||
return inputMap;
|
||||
|
||||
// modify input map (replace or remove)
|
||||
for( int i = 0; i < bindings.length; i += 2 ) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke( (String) bindings[i] );
|
||||
if( bindings[i + 1] != null )
|
||||
inputMap.put( keyStroke, bindings[i + 1] );
|
||||
else
|
||||
inputMap.remove( keyStroke );
|
||||
}
|
||||
|
||||
return inputMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,25 +18,32 @@ package com.formdev.flatlaf;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
|
||||
*
|
||||
* The UI defaults are loaded from FlatIntelliJLaf.properties, FlatLightLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatIntelliJLaf.properties},
|
||||
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatIntelliJLaf
|
||||
extends FlatLightLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf IntelliJ";
|
||||
|
||||
public static boolean install() {
|
||||
return install( new FlatIntelliJLaf() );
|
||||
}
|
||||
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatIntelliJLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat IntelliJ";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat IntelliJ Look and Feel";
|
||||
return "FlatLaf IntelliJ Look and Feel";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,34 +18,51 @@ package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.KeyEventPostProcessor;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.ImageFilter;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIDefaults.ActiveValue;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
||||
import com.formdev.flatlaf.ui.JBRCustomDecorations;
|
||||
import com.formdev.flatlaf.util.GrayFilter;
|
||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -58,17 +75,29 @@ public abstract class FlatLaf
|
||||
extends BasicLookAndFeel
|
||||
{
|
||||
static final Logger LOG = Logger.getLogger( FlatLaf.class.getName() );
|
||||
private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
|
||||
|
||||
private BasicLookAndFeel base;
|
||||
private static List<Object> customDefaultsSources;
|
||||
|
||||
private String desktopPropertyName;
|
||||
private String desktopPropertyName2;
|
||||
private PropertyChangeListener desktopPropertyListener;
|
||||
|
||||
private KeyEventPostProcessor mnemonicListener;
|
||||
private static boolean showMnemonics;
|
||||
private static boolean aquaLoaded;
|
||||
private static boolean updateUIPending;
|
||||
|
||||
private PopupFactory oldPopupFactory;
|
||||
private MnemonicHandler mnemonicHandler;
|
||||
|
||||
private Consumer<UIDefaults> postInitialization;
|
||||
|
||||
private Boolean oldFrameWindowDecorated;
|
||||
private Boolean oldDialogWindowDecorated;
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to the given LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install( LookAndFeel newLookAndFeel ) {
|
||||
try {
|
||||
UIManager.setLookAndFeel( newLookAndFeel );
|
||||
@@ -79,6 +108,16 @@ public abstract class FlatLaf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given look and feel to the set of available look and feels.
|
||||
* <p>
|
||||
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||
* to query available LaFs and display them to the user in a combobox.
|
||||
*/
|
||||
public static void installLafInfo( String lafName, Class<? extends LookAndFeel> lafClass ) {
|
||||
UIManager.installLookAndFeel( new UIManager.LookAndFeelInfo( lafName, lafClass.getName() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the look and feel identifier.
|
||||
* <p>
|
||||
@@ -94,6 +133,45 @@ public abstract class FlatLaf
|
||||
|
||||
public abstract boolean isDark();
|
||||
|
||||
/**
|
||||
* Checks whether the current look and feel is dark.
|
||||
*/
|
||||
public static boolean isLafDark() {
|
||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||
return lookAndFeel instanceof FlatLaf && ((FlatLaf)lookAndFeel).isDark();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether FlatLaf supports custom window decorations.
|
||||
* This depends on the operating system and on the used Java runtime.
|
||||
* <p>
|
||||
* To use custom window decorations in your application, enable them with
|
||||
* following code (before creating any frames or dialogs). Then custom window
|
||||
* decorations are only enabled if this method returns {@code true}.
|
||||
* <pre>
|
||||
* JFrame.setDefaultLookAndFeelDecorated( true );
|
||||
* JDialog.setDefaultLookAndFeelDecorated( true );
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns {@code true} on Windows 10, {@code false} otherwise.
|
||||
* <p>
|
||||
* Return also {@code false} if running on Windows 10 in
|
||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
||||
* and JBR supports custom window decorations. In this case, JBR custom decorations
|
||||
* are enabled if {@link JFrame#isDefaultLookAndFeelDecorated()} or
|
||||
* {@link JDialog#isDefaultLookAndFeelDecorated()} return {@code true}.
|
||||
*/
|
||||
@Override
|
||||
public boolean getSupportsWindowDecorations() {
|
||||
if( SystemInfo.isJetBrainsJVM_11_orLater &&
|
||||
SystemInfo.isWindows_10_orLater &&
|
||||
JBRCustomDecorations.isSupported() )
|
||||
return false;
|
||||
|
||||
return SystemInfo.isWindows_10_orLater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeLookAndFeel() {
|
||||
return false;
|
||||
@@ -104,40 +182,76 @@ public abstract class FlatLaf
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getDisabledIcon( JComponent component, Icon icon ) {
|
||||
if( icon instanceof DisabledIconProvider )
|
||||
return ((DisabledIconProvider)icon).getDisabledIcon();
|
||||
|
||||
if( icon instanceof ImageIcon ) {
|
||||
Object grayFilter = UIManager.get( "Component.grayFilter" );
|
||||
ImageFilter filter = (grayFilter instanceof ImageFilter)
|
||||
? (ImageFilter) grayFilter
|
||||
: GrayFilter.createDisabledIconFilter( isDark() ); // fallback
|
||||
|
||||
Function<Image, Image> mapper = img -> {
|
||||
ImageProducer producer = new FilteredImageSource( img.getSource(), filter );
|
||||
return Toolkit.getDefaultToolkit().createImage( producer );
|
||||
};
|
||||
|
||||
Image image = ((ImageIcon)icon).getImage();
|
||||
return new ImageIconUIResource( MultiResolutionImageSupport.map( image, mapper ) );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
getBase().initialize();
|
||||
if( SystemInfo.isMacOS )
|
||||
initializeAqua();
|
||||
|
||||
super.initialize();
|
||||
|
||||
// make sure that a plain popup factory is used (otherwise sub-menu rendering
|
||||
// is "jittery" on Mac, where AquaLookAndFeel installs its own popup factory)
|
||||
if( PopupFactory.getSharedInstance().getClass() != PopupFactory.class )
|
||||
PopupFactory.setSharedInstance( new PopupFactory() );
|
||||
// install popup factory
|
||||
oldPopupFactory = PopupFactory.getSharedInstance();
|
||||
PopupFactory.setSharedInstance( new FlatPopupFactory() );
|
||||
|
||||
// add mnemonic listener
|
||||
mnemonicListener = e -> {
|
||||
checkShowMnemonics( e );
|
||||
return false;
|
||||
};
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( mnemonicListener );
|
||||
// install mnemonic handler
|
||||
mnemonicHandler = new MnemonicHandler();
|
||||
mnemonicHandler.install();
|
||||
|
||||
// listen to desktop property changes to update UI if system font or scaling changes
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
// Windows 10 allows increasing font size independent of scaling:
|
||||
// Settings > Ease of Access > Display > Make text bigger (100% - 225%)
|
||||
desktopPropertyName = "win.messagebox.font";
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
} else if( SystemInfo.isLinux ) {
|
||||
// Linux/Gnome allows changing font in "Tweaks" app
|
||||
desktopPropertyName = "gnome.Gtk/FontName";
|
||||
|
||||
// Linux/Gnome allows extra scaling and larger text:
|
||||
// Settings > Devices > Displays > Scale (100% or 200%)
|
||||
// Settings > Universal access > Large Text (off or on, 125%)
|
||||
desktopPropertyName = "gnome.Xft/DPI";
|
||||
// "Tweaks" app > Fonts > Scaling Factor (0,5 - 3)
|
||||
desktopPropertyName2 = "gnome.Xft/DPI";
|
||||
}
|
||||
if( desktopPropertyName != null ) {
|
||||
desktopPropertyListener = e -> {
|
||||
reSetLookAndFeel();
|
||||
String propertyName = e.getPropertyName();
|
||||
if( desktopPropertyName.equals( propertyName ) || propertyName.equals( desktopPropertyName2 ) )
|
||||
reSetLookAndFeel();
|
||||
else if( DESKTOPFONTHINTS.equals( propertyName ) ) {
|
||||
if( UIManager.getLookAndFeel() instanceof FlatLaf ) {
|
||||
putAATextInfo( UIManager.getLookAndFeelDefaults() );
|
||||
updateUILater();
|
||||
}
|
||||
}
|
||||
};
|
||||
Toolkit.getDefaultToolkit().addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
if( desktopPropertyName2 != null )
|
||||
toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
|
||||
toolkit.addPropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
|
||||
}
|
||||
|
||||
// Following code should be ideally in initialize(), but needs color from UI defaults.
|
||||
@@ -148,152 +262,264 @@ public abstract class FlatLaf
|
||||
Color linkColor = defaults.getColor( "Component.linkColor" );
|
||||
if( linkColor != null ) {
|
||||
new HTMLEditorKit().getStyleSheet().addRule(
|
||||
String.format( "a { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
|
||||
String.format( "a, address { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
|
||||
}
|
||||
};
|
||||
|
||||
// enable/disable window decorations, but only if system property is either
|
||||
// "true" or "false"; in other cases it is not changed
|
||||
Boolean useWindowDecorations = FlatSystemProperties.getBooleanStrict( FlatSystemProperties.USE_WINDOW_DECORATIONS, null );
|
||||
if( useWindowDecorations != null ) {
|
||||
oldFrameWindowDecorated = JFrame.isDefaultLookAndFeelDecorated();
|
||||
oldDialogWindowDecorated = JDialog.isDefaultLookAndFeelDecorated();
|
||||
JFrame.setDefaultLookAndFeelDecorated( useWindowDecorations );
|
||||
JDialog.setDefaultLookAndFeelDecorated( useWindowDecorations );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninitialize() {
|
||||
// remove desktop property listener
|
||||
if( desktopPropertyListener != null ) {
|
||||
Toolkit.getDefaultToolkit().removePropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.removePropertyChangeListener( desktopPropertyName, desktopPropertyListener );
|
||||
if( desktopPropertyName2 != null )
|
||||
toolkit.removePropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
|
||||
toolkit.removePropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
|
||||
desktopPropertyName = null;
|
||||
desktopPropertyName2 = null;
|
||||
desktopPropertyListener = null;
|
||||
}
|
||||
|
||||
// remove mnemonic listener
|
||||
if( mnemonicListener != null ) {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( mnemonicListener );
|
||||
mnemonicListener = null;
|
||||
// uninstall popup factory
|
||||
if( oldPopupFactory != null ) {
|
||||
PopupFactory.setSharedInstance( oldPopupFactory );
|
||||
oldPopupFactory = null;
|
||||
}
|
||||
|
||||
// uninstall mnemonic handler
|
||||
if( mnemonicHandler != null ) {
|
||||
mnemonicHandler.uninstall();
|
||||
mnemonicHandler = null;
|
||||
}
|
||||
|
||||
// restore default link color
|
||||
new HTMLEditorKit().getStyleSheet().addRule( "a { color: blue; }" );
|
||||
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
|
||||
postInitialization = null;
|
||||
|
||||
if( base != null )
|
||||
base.uninitialize();
|
||||
// restore enable/disable window decorations
|
||||
if( oldFrameWindowDecorated != null ) {
|
||||
JFrame.setDefaultLookAndFeelDecorated( oldFrameWindowDecorated );
|
||||
JDialog.setDefaultLookAndFeelDecorated( oldDialogWindowDecorated );
|
||||
oldFrameWindowDecorated = null;
|
||||
oldDialogWindowDecorated = null;
|
||||
}
|
||||
|
||||
super.uninitialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/create base LaF. This is used to grab base UI defaults from different LaFs.
|
||||
* E.g. on Mac from system dependent LaF, otherwise from Metal LaF.
|
||||
* Initialize Aqua LaF on macOS, which is required for using Mac screen menubar.
|
||||
* (at least on Java 8, since 9 it seems to work without it)
|
||||
* <p>
|
||||
* This loads the native library "osxui" and initializes JRSUI.
|
||||
* Because both are not unloaded/uninitialized, Aqua LaF is initialized only once.
|
||||
*/
|
||||
private BasicLookAndFeel getBase() {
|
||||
if( base == null ) {
|
||||
if( SystemInfo.IS_MAC ) {
|
||||
// use Mac Aqua LaF as base
|
||||
String aquaLafClassName = "com.apple.laf.AquaLookAndFeel";
|
||||
try {
|
||||
base = (BasicLookAndFeel) Class.forName( aquaLafClassName ).newInstance();
|
||||
} catch( Exception ex ) {
|
||||
LOG.log( Level.SEVERE, "FlatLaf: Failed to initialize base look and feel '" + aquaLafClassName + "'.", ex );
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
private void initializeAqua() {
|
||||
if( aquaLoaded )
|
||||
return;
|
||||
|
||||
aquaLoaded = true;
|
||||
|
||||
// create macOS Aqua LaF
|
||||
String aquaLafClassName = "com.apple.laf.AquaLookAndFeel";
|
||||
BasicLookAndFeel aquaLaf;
|
||||
try {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
Method m = UIManager.class.getMethod( "createLookAndFeel", String.class );
|
||||
aquaLaf = (BasicLookAndFeel) m.invoke( null, "Mac OS X" );
|
||||
} else
|
||||
base = new MetalLookAndFeel();
|
||||
aquaLaf = (BasicLookAndFeel) Class.forName( aquaLafClassName ).newInstance();
|
||||
} catch( Exception ex ) {
|
||||
LOG.log( Level.SEVERE, "FlatLaf: Failed to initialize Aqua look and feel '" + aquaLafClassName + "'.", ex );
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return base;
|
||||
|
||||
// remember popup factory because aquaLaf.initialize() installs its own
|
||||
// factory, which makes sub-menu rendering "jittery"
|
||||
PopupFactory oldPopupFactory = PopupFactory.getSharedInstance();
|
||||
|
||||
// initialize Aqua LaF
|
||||
aquaLaf.initialize();
|
||||
aquaLaf.uninitialize();
|
||||
|
||||
// restore popup factory
|
||||
PopupFactory.setSharedInstance( oldPopupFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIDefaults getDefaults() {
|
||||
UIDefaults defaults = getBase().getDefaults();
|
||||
UIDefaults defaults = super.getDefaults();
|
||||
|
||||
// add Metal resource bundle, which is required for FlatFileChooserUI
|
||||
defaults.addResourceBundle( "com.sun.swing.internal.plaf.metal.resources.metal" );
|
||||
// add flag that indicates whether the LaF is light or dark
|
||||
// (can be queried without using FlatLaf API)
|
||||
defaults.put( "laf.dark", isDark() );
|
||||
|
||||
// initialize some defaults (for overriding) that are used in basic UI delegates,
|
||||
// but are not set in MetalLookAndFeel or BasicLookAndFeel
|
||||
Color control = defaults.getColor( "control" );
|
||||
defaults.put( "EditorPane.disabledBackground", control );
|
||||
defaults.put( "EditorPane.inactiveBackground", control );
|
||||
defaults.put( "FormattedTextField.disabledBackground", control );
|
||||
defaults.put( "PasswordField.disabledBackground", control );
|
||||
defaults.put( "TextArea.disabledBackground", control );
|
||||
defaults.put( "TextArea.inactiveBackground", control );
|
||||
defaults.put( "TextField.disabledBackground", control );
|
||||
defaults.put( "TextPane.disabledBackground", control );
|
||||
defaults.put( "TextPane.inactiveBackground", control );
|
||||
// add resource bundle for localized texts
|
||||
defaults.addResourceBundle( "com.formdev.flatlaf.resources.Bundle" );
|
||||
|
||||
// initialize some own defaults (for overriding)
|
||||
defaults.put( "Spinner.disabledBackground", control );
|
||||
defaults.put( "Spinner.disabledForeground", control );
|
||||
|
||||
// remember MenuBarUI from Mac Aqua LaF if Mac screen menubar is enabled
|
||||
boolean useScreenMenuBar = SystemInfo.IS_MAC && "true".equals( System.getProperty( "apple.laf.useScreenMenuBar" ) );
|
||||
Object aquaMenuBarUI = useScreenMenuBar ? defaults.get( "MenuBarUI" ) : null;
|
||||
// initialize some defaults (for overriding) that are used in UI delegates,
|
||||
// but are not set in BasicLookAndFeel
|
||||
putDefaults( defaults, defaults.getColor( "control" ),
|
||||
"Button.disabledBackground",
|
||||
"EditorPane.disabledBackground",
|
||||
"EditorPane.inactiveBackground",
|
||||
"FormattedTextField.disabledBackground",
|
||||
"PasswordField.disabledBackground",
|
||||
"Spinner.disabledBackground",
|
||||
"TextArea.disabledBackground",
|
||||
"TextArea.inactiveBackground",
|
||||
"TextField.disabledBackground",
|
||||
"TextPane.disabledBackground",
|
||||
"TextPane.inactiveBackground",
|
||||
"ToggleButton.disabledBackground" );
|
||||
putDefaults( defaults, defaults.getColor( "textInactiveText" ),
|
||||
"Button.disabledText",
|
||||
"CheckBox.disabledText",
|
||||
"CheckBoxMenuItem.disabledForeground",
|
||||
"Menu.disabledForeground",
|
||||
"MenuItem.disabledForeground",
|
||||
"RadioButton.disabledText",
|
||||
"RadioButtonMenuItem.disabledForeground",
|
||||
"Spinner.disabledForeground",
|
||||
"ToggleButton.disabledText" );
|
||||
putDefaults( defaults, defaults.getColor( "textText" ),
|
||||
"DesktopIcon.foreground" );
|
||||
|
||||
initFonts( defaults );
|
||||
initIconColors( defaults, isDark() );
|
||||
FlatInputMaps.initInputMaps( defaults );
|
||||
|
||||
// get addons and sort them by priority
|
||||
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
|
||||
List<FlatDefaultsAddon> addons = new ArrayList<>();
|
||||
for( FlatDefaultsAddon addon : addonLoader )
|
||||
addons.add( addon );
|
||||
addons.sort( (addon1, addon2) -> addon1.getPriority() - addon2.getPriority() );
|
||||
|
||||
// load defaults from properties
|
||||
List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading();
|
||||
if( lafClassesForDefaultsLoading != null )
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, defaults );
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
else
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), defaults );
|
||||
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults );
|
||||
|
||||
// use Aqua MenuBarUI if Mac screen menubar is enabled
|
||||
if( useScreenMenuBar )
|
||||
defaults.put( "MenuBarUI", aquaMenuBarUI );
|
||||
if( SystemInfo.isMacOS && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
|
||||
defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" );
|
||||
|
||||
invokePostInitialization( defaults );
|
||||
// add defaults necessary for AquaMenuBarUI
|
||||
defaults.put( "MenuBar.backgroundPainter", BorderFactory.createEmptyBorder() );
|
||||
}
|
||||
|
||||
return defaults;
|
||||
}
|
||||
// initialize text antialiasing
|
||||
putAATextInfo( defaults );
|
||||
|
||||
// apply additional defaults (e.g. from IntelliJ themes)
|
||||
applyAdditionalDefaults( defaults );
|
||||
|
||||
// allow addons modifying UI defaults
|
||||
for( FlatDefaultsAddon addon : addons )
|
||||
addon.afterDefaultsLoading( this, defaults );
|
||||
|
||||
// add user scale factor to allow layout managers (e.g. MigLayout) to use it
|
||||
defaults.put( "laf.scaleFactor", (ActiveValue) t -> {
|
||||
return UIScale.getUserScaleFactor();
|
||||
} );
|
||||
|
||||
void invokePostInitialization( UIDefaults defaults ) {
|
||||
if( postInitialization != null ) {
|
||||
postInitialization.accept( defaults );
|
||||
postInitialization = null;
|
||||
}
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
List<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
void applyAdditionalDefaults( UIDefaults defaults ) {
|
||||
}
|
||||
|
||||
protected List<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Properties getAdditionalDefaults() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initFonts( UIDefaults defaults ) {
|
||||
FontUIResource uiFont = null;
|
||||
|
||||
if( SystemInfo.IS_WINDOWS ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
||||
if( winFont != null )
|
||||
uiFont = new FontUIResource( winFont );
|
||||
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() );
|
||||
|
||||
} else if( SystemInfo.IS_MAC ) {
|
||||
Font font = defaults.getFont( "Label.font" );
|
||||
|
||||
if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) {
|
||||
} else if( SystemInfo.isMacOS ) {
|
||||
String fontName;
|
||||
if( SystemInfo.isMacOS_10_15_Catalina_orLater ) {
|
||||
if (SystemInfo.isJetBrainsJVM_11_orLater) {
|
||||
// See https://youtrack.jetbrains.com/issue/JBR-1915
|
||||
fontName = ".AppleSystemUIFont";
|
||||
} else {
|
||||
// use Helvetica Neue font
|
||||
fontName = "Helvetica Neue";
|
||||
}
|
||||
} else if( SystemInfo.isMacOS_10_11_ElCapitan_orLater ) {
|
||||
// use San Francisco Text font
|
||||
font = new FontUIResource( ".SF NS Text", font.getStyle(), font.getSize() );
|
||||
fontName = ".SF NS Text";
|
||||
} else {
|
||||
// default font on older systems (see com.apple.laf.AquaFonts)
|
||||
fontName = "Lucida Grande";
|
||||
}
|
||||
|
||||
uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
uiFont = createCompositeFont( fontName, Font.PLAIN, 13 );
|
||||
|
||||
} else if( SystemInfo.IS_LINUX ) {
|
||||
} else if( SystemInfo.isLinux ) {
|
||||
Font font = LinuxFontPolicy.getFont();
|
||||
uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
}
|
||||
|
||||
// fallback
|
||||
if( uiFont == null )
|
||||
return;
|
||||
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
||||
|
||||
// increase font size if system property "flatlaf.uiScale" is set
|
||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||
|
||||
// use active value for all fonts to allow changing fonts in all components
|
||||
// (similar as in Nimbus L&F) with:
|
||||
// UIManager.put( "defaultFont", myFont );
|
||||
Object activeFont = new ActiveFont( 1 );
|
||||
|
||||
// override fonts
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).endsWith( ".font" ) )
|
||||
defaults.put( key, uiFont );
|
||||
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
|
||||
defaults.put( key, activeFont );
|
||||
}
|
||||
defaults.put( "MenuItem.acceleratorFont", uiFont );
|
||||
|
||||
// use smaller font for progress bar
|
||||
defaults.put( "ProgressBar.font", UIScale.scaleFont( uiFont, 0.85f ) );
|
||||
defaults.put( "ProgressBar.font", new ActiveFont( 0.85f ) );
|
||||
|
||||
// set default font
|
||||
defaults.put( "defaultFont", uiFont );
|
||||
}
|
||||
|
||||
static FontUIResource createCompositeFont( String family, int style, int size ) {
|
||||
// using StyleContext.getFont() here because it uses
|
||||
// sun.font.FontUtilities.getCompositeFontUIResource()
|
||||
// and creates a composite font that is able to display all Unicode characters
|
||||
Font font = StyleContext.getDefaultStyleContext().getFont( family, style, size );
|
||||
return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,30 +535,138 @@ public abstract class FlatLaf
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
|
||||
* and
|
||||
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
|
||||
* <p>
|
||||
* These colors may be changed by IntelliJ Platform themes.
|
||||
*/
|
||||
public static void initIconColors( UIDefaults defaults, boolean dark ) {
|
||||
// colors for action icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#action-icons
|
||||
defaults.put( "Actions.Red", new ColorUIResource( !dark ? 0xDB5860 : 0xC75450 ) );
|
||||
defaults.put( "Actions.Yellow", new ColorUIResource( !dark ? 0xEDA200 : 0xF0A732 ) );
|
||||
defaults.put( "Actions.Green", new ColorUIResource( !dark ? 0x59A869 : 0x499C54 ) );
|
||||
defaults.put( "Actions.Blue", new ColorUIResource( !dark ? 0x389FD6 : 0x3592C4 ) );
|
||||
defaults.put( "Actions.Grey", new ColorUIResource( !dark ? 0x6E6E6E : 0xAFB1B3 ) );
|
||||
defaults.put( "Actions.GreyInline", new ColorUIResource( !dark ? 0x7F8B91 : 0x7F8B91 ) );
|
||||
for( FlatIconColors c : FlatIconColors.values() ) {
|
||||
if( c.light == !dark || c.dark == dark )
|
||||
defaults.put( c.key, new ColorUIResource( c.rgb ) );
|
||||
}
|
||||
}
|
||||
|
||||
// colors for object icons
|
||||
// see https://jetbrains.design/intellij/principles/icons/#noun-icons
|
||||
defaults.put( "Objects.Grey", new ColorUIResource( 0x9AA7B0 ) );
|
||||
defaults.put( "Objects.Blue", new ColorUIResource( 0x40B6E0 ) );
|
||||
defaults.put( "Objects.Green", new ColorUIResource( 0x62B543 ) );
|
||||
defaults.put( "Objects.Yellow", new ColorUIResource( 0xF4AF3D ) );
|
||||
defaults.put( "Objects.YellowDark", new ColorUIResource( 0xD9A343 ) );
|
||||
defaults.put( "Objects.Purple", new ColorUIResource( 0xB99BF8 ) );
|
||||
defaults.put( "Objects.Pink", new ColorUIResource( 0xF98B9E ) );
|
||||
defaults.put( "Objects.Red", new ColorUIResource( 0xF26522 ) );
|
||||
defaults.put( "Objects.RedStatus", new ColorUIResource( 0xE05555 ) );
|
||||
defaults.put( "Objects.GreenAndroid", new ColorUIResource( 0xA4C639 ) );
|
||||
defaults.put( "Objects.BlackText", new ColorUIResource( 0x231F20 ) );
|
||||
private void putAATextInfo( UIDefaults defaults ) {
|
||||
if ( SystemInfo.isMacOS && SystemInfo.isJetBrainsJVM ) {
|
||||
// The awt.font.desktophints property suggests sub-pixel anti-aliasing
|
||||
// which renders text with too much weight on macOS in the JetBrains JRE.
|
||||
// Use greyscale anti-aliasing instead.
|
||||
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
|
||||
} else if( SystemInfo.isJava_9_orLater ) {
|
||||
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
|
||||
if( desktopHints instanceof Map ) {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
|
||||
Object aaHint = hints.get( RenderingHints.KEY_TEXT_ANTIALIASING );
|
||||
if( aaHint != null &&
|
||||
aaHint != RenderingHints.VALUE_TEXT_ANTIALIAS_OFF &&
|
||||
aaHint != RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT )
|
||||
{
|
||||
defaults.put( RenderingHints.KEY_TEXT_ANTIALIASING, aaHint );
|
||||
defaults.put( RenderingHints.KEY_TEXT_LCD_CONTRAST,
|
||||
hints.get( RenderingHints.KEY_TEXT_LCD_CONTRAST ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Java 8
|
||||
try {
|
||||
Object key = Class.forName( "sun.swing.SwingUtilities2" )
|
||||
.getField( "AA_TEXT_PROPERTY_KEY" )
|
||||
.get( null );
|
||||
Object value = Class.forName( "sun.swing.SwingUtilities2$AATextInfo" )
|
||||
.getMethod( "getAATextInfo", boolean.class )
|
||||
.invoke( null, true );
|
||||
defaults.put( key, value );
|
||||
} catch( Exception ex ) {
|
||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void putDefaults( UIDefaults defaults, Object value, String... keys ) {
|
||||
for( String key : keys )
|
||||
defaults.put( key, value );
|
||||
}
|
||||
|
||||
static List<Object> getCustomDefaultsSources() {
|
||||
return customDefaultsSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a package where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* This can be used to specify application specific UI defaults that override UI values
|
||||
* of existing themes or to define own UI values used in custom controls.
|
||||
* <p>
|
||||
* There may be multiple properties files in that package for multiple themes.
|
||||
* The properties file name must match the used theme class names.
|
||||
* E.g. {@code FlatLightLaf.properties} for class {@link FlatLightLaf}
|
||||
* or {@code FlatDarkLaf.properties} for class {@link FlatDarkLaf}.
|
||||
* {@code FlatLaf.properties} is loaded first for all themes.
|
||||
* <p>
|
||||
* These properties files are loaded after theme and addon properties files
|
||||
* and can therefore override all UI defaults.
|
||||
* <p>
|
||||
* Invoke this method before setting the look and feel.
|
||||
*
|
||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( String packageName ) {
|
||||
registerCustomDefaultsSource( packageName, null );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( String packageName ) {
|
||||
unregisterCustomDefaultsSource( packageName, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a package where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* See {@link #registerCustomDefaultsSource(String)} for details.
|
||||
*
|
||||
* @param packageName a package name (e.g. "com.myapp.resources")
|
||||
* @param classLoader a class loader used to find resources, or {@code null}
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( String packageName, ClassLoader classLoader ) {
|
||||
if( customDefaultsSources == null )
|
||||
customDefaultsSources = new ArrayList<>();
|
||||
customDefaultsSources.add( packageName );
|
||||
customDefaultsSources.add( classLoader );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( String packageName, ClassLoader classLoader ) {
|
||||
if( customDefaultsSources == null )
|
||||
return;
|
||||
|
||||
int size = customDefaultsSources.size();
|
||||
for( int i = 0; i < size - 1; i++ ) {
|
||||
Object source = customDefaultsSources.get( i );
|
||||
if( packageName.equals( source ) && customDefaultsSources.get( i + 1 ) == classLoader ) {
|
||||
customDefaultsSources.remove( i + 1 );
|
||||
customDefaultsSources.remove( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a folder where FlatLaf searches for properties files with custom UI defaults.
|
||||
* <p>
|
||||
* See {@link #registerCustomDefaultsSource(String)} for details.
|
||||
*
|
||||
* @param folder a folder
|
||||
*/
|
||||
public static void registerCustomDefaultsSource( File folder ) {
|
||||
if( customDefaultsSources == null )
|
||||
customDefaultsSources = new ArrayList<>();
|
||||
customDefaultsSources.add( folder );
|
||||
}
|
||||
|
||||
public static void unregisterCustomDefaultsSource( File folder ) {
|
||||
if( customDefaultsSources == null )
|
||||
return;
|
||||
|
||||
customDefaultsSources.remove( folder );
|
||||
}
|
||||
|
||||
private static void reSetLookAndFeel() {
|
||||
@@ -356,7 +690,7 @@ public abstract class FlatLaf
|
||||
}
|
||||
|
||||
/**
|
||||
* Update UI of all application windows.
|
||||
* Update UI of all application windows immediately.
|
||||
* Invoke after changing LaF.
|
||||
*/
|
||||
public static void updateUI() {
|
||||
@@ -364,73 +698,115 @@ public abstract class FlatLaf
|
||||
SwingUtilities.updateComponentTreeUI( w );
|
||||
}
|
||||
|
||||
public static boolean isShowMnemonics() {
|
||||
return showMnemonics || !UIManager.getBoolean( "Component.hideMnemonics" );
|
||||
}
|
||||
/**
|
||||
* Update UI of all application windows later.
|
||||
*/
|
||||
public static void updateUILater() {
|
||||
synchronized( FlatLaf.class ) {
|
||||
if( updateUIPending )
|
||||
return;
|
||||
|
||||
private static void checkShowMnemonics( KeyEvent e ) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if( SystemInfo.IS_MAC ) {
|
||||
// Ctrl+Alt keys must be pressed on Mac
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( e.getID() == KeyEvent.KEY_PRESSED && e.isControlDown() && e.isAltDown() );
|
||||
} else {
|
||||
// Alt key must be pressed on Windows and Linux
|
||||
if( keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( e.getID() == KeyEvent.KEY_PRESSED );
|
||||
updateUIPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void showMnemonics( boolean show ) {
|
||||
if( show == showMnemonics )
|
||||
return;
|
||||
|
||||
showMnemonics = show;
|
||||
|
||||
// check whether it is necessary to repaint
|
||||
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
|
||||
return;
|
||||
|
||||
// get focus owner
|
||||
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
|
||||
if( focusOwner == null )
|
||||
return;
|
||||
|
||||
// get focused window
|
||||
Window window = SwingUtilities.windowForComponent( focusOwner );
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
// repaint components with mnemonics in focused window
|
||||
repaintMnemonics( window );
|
||||
}
|
||||
|
||||
private static void repaintMnemonics( Container container ) {
|
||||
for( Component c : container.getComponents() ) {
|
||||
if( hasMnemonic( c ) )
|
||||
c.repaint();
|
||||
|
||||
if( c instanceof Container )
|
||||
repaintMnemonics( (Container) c );
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasMnemonic( Component c ) {
|
||||
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof JTabbedPane ) {
|
||||
JTabbedPane tabPane = (JTabbedPane) c;
|
||||
int tabCount = tabPane.getTabCount();
|
||||
for( int i = 0; i < tabCount; i++ ) {
|
||||
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
|
||||
return true;
|
||||
EventQueue.invokeLater( () -> {
|
||||
updateUI();
|
||||
synchronized( FlatLaf.class ) {
|
||||
updateUIPending = false;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public static boolean isShowMnemonics() {
|
||||
return MnemonicHandler.isShowMnemonics();
|
||||
}
|
||||
|
||||
public static void showMnemonics( Component c ) {
|
||||
MnemonicHandler.showMnemonics( true, c );
|
||||
}
|
||||
|
||||
public static void hideMnemonics() {
|
||||
MnemonicHandler.showMnemonics( false, null );
|
||||
}
|
||||
|
||||
// do not allow overriding to avoid issues in FlatUIUtils.createSharedUI()
|
||||
@Override
|
||||
public final boolean equals( Object obj ) {
|
||||
return super.equals( obj );
|
||||
}
|
||||
|
||||
// do not allow overriding to avoid issues in FlatUIUtils.createSharedUI()
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
//---- class ActiveFont ---------------------------------------------------
|
||||
|
||||
private static class ActiveFont
|
||||
implements ActiveValue
|
||||
{
|
||||
private final float scaleFactor;
|
||||
|
||||
// cache (scaled) font
|
||||
private Font font;
|
||||
private Font lastDefaultFont;
|
||||
|
||||
ActiveFont( float scaleFactor ) {
|
||||
this.scaleFactor = scaleFactor;
|
||||
}
|
||||
|
||||
return false;
|
||||
@Override
|
||||
public Object createValue( UIDefaults table ) {
|
||||
Font defaultFont = UIManager.getFont( "defaultFont" );
|
||||
|
||||
if( lastDefaultFont != defaultFont ) {
|
||||
lastDefaultFont = defaultFont;
|
||||
|
||||
if( scaleFactor != 1 ) {
|
||||
// scale font
|
||||
int newFontSize = Math.round( defaultFont.getSize() * scaleFactor );
|
||||
font = new FontUIResource( defaultFont.deriveFont( (float) newFontSize ) );
|
||||
} else {
|
||||
// make sure that font is a UIResource for LaF switching
|
||||
font = (defaultFont instanceof UIResource)
|
||||
? defaultFont
|
||||
: new FontUIResource( defaultFont );
|
||||
}
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ImageIconUIResource ------------------------------------------
|
||||
|
||||
private static class ImageIconUIResource
|
||||
extends ImageIcon
|
||||
implements UIResource
|
||||
{
|
||||
ImageIconUIResource( Image image ) {
|
||||
super( image );
|
||||
}
|
||||
}
|
||||
|
||||
//---- interface DisabledIconProvider -------------------------------------
|
||||
|
||||
/**
|
||||
* A provider for disabled icons.
|
||||
* <p>
|
||||
* This is intended to be implemented by {@link javax.swing.Icon} implementations
|
||||
* that provide the ability to paint disabled state.
|
||||
* <p>
|
||||
* Used in {@link FlatLaf#getDisabledIcon(JComponent, Icon)} to create a disabled icon from an enabled icon.
|
||||
*/
|
||||
public interface DisabledIconProvider
|
||||
{
|
||||
/**
|
||||
* Returns an icon with a disabled appearance.
|
||||
*
|
||||
* @return a disabled icon
|
||||
*/
|
||||
Icon getDisabledIcon();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,28 +16,46 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* A Flat LaF that has a light color scheme.
|
||||
*
|
||||
* The UI defaults are loaded from FlatLightLaf.properties and FlatLaf.properties
|
||||
* <p>
|
||||
* The UI defaults are loaded from {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatLightLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
public static boolean install( ) {
|
||||
public static final String NAME = "FlatLaf Light";
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to this LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
*/
|
||||
public static boolean install() {
|
||||
return install( new FlatLightLaf() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this look and feel to the set of available look and feels.
|
||||
* <p>
|
||||
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
|
||||
* to query available LaFs and display them to the user in a combobox.
|
||||
*/
|
||||
public static void installLafInfo() {
|
||||
installLafInfo( NAME, FlatLightLaf.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Flat Light";
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Flat Light Look and Feel";
|
||||
return "FlatLaf Light Look and Feel";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
|
||||
* <p>
|
||||
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
|
||||
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
|
||||
* {@code intellij} or {@code darcula}.
|
||||
* <p>
|
||||
* The properties are applied after loading the base theme and may overwrite base properties.
|
||||
* All features of FlatLaf properties files are available.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPropertiesLaf
|
||||
extends FlatLaf
|
||||
{
|
||||
private final String name;
|
||||
private final String baseTheme;
|
||||
private final boolean dark;
|
||||
private final Properties properties;
|
||||
|
||||
public FlatPropertiesLaf( String name, File propertiesFile )
|
||||
throws IOException
|
||||
{
|
||||
this( name, new FileInputStream( propertiesFile ) );
|
||||
}
|
||||
|
||||
public FlatPropertiesLaf( String name, InputStream in )
|
||||
throws IOException
|
||||
{
|
||||
this( name, loadProperties( in ) );
|
||||
}
|
||||
|
||||
private static Properties loadProperties( InputStream in )
|
||||
throws IOException
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
try( InputStream in2 = in ) {
|
||||
properties.load( in2 );
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public FlatPropertiesLaf( String name, Properties properties ) {
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
|
||||
baseTheme = properties.getProperty( "@baseTheme", "light" );
|
||||
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDark() {
|
||||
return dark;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
lafClasses.add( FlatLaf.class );
|
||||
switch( baseTheme.toLowerCase() ) {
|
||||
default:
|
||||
case "light":
|
||||
lafClasses.add( FlatLightLaf.class );
|
||||
break;
|
||||
|
||||
case "dark":
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
break;
|
||||
|
||||
case "intellij":
|
||||
lafClasses.add( FlatLightLaf.class );
|
||||
lafClasses.add( FlatIntelliJLaf.class );
|
||||
break;
|
||||
|
||||
case "darcula":
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
lafClasses.add( FlatDarculaLaf.class );
|
||||
break;
|
||||
}
|
||||
return lafClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties getAdditionalDefaults() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
/**
|
||||
* Defines/documents own system properties used in FlatLaf.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public interface FlatSystemProperties
|
||||
{
|
||||
/**
|
||||
* Specifies a custom scale factor used to scale the UI.
|
||||
* <p>
|
||||
* If Java runtime scales (Java 9 or later), this scale factor is applied on top
|
||||
* of the Java system scale factor. Java 8 does not scale and this scale factor
|
||||
* replaces the user scale factor that FlatLaf computes based on the font.
|
||||
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
|
||||
* which has the same syntax as this one.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
|
||||
*/
|
||||
String UI_SCALE = "flatlaf.uiScale";
|
||||
|
||||
/**
|
||||
* Specifies whether user scaling mode is enabled.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled";
|
||||
|
||||
/**
|
||||
* Specifies whether Ubuntu font should be used on Ubuntu Linux.
|
||||
* By default, if not running in a JetBrains Runtime, the Liberation Sans font
|
||||
* is used because there are rendering issues (in Java) with Ubuntu fonts.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code false}
|
||||
*/
|
||||
String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont";
|
||||
|
||||
/**
|
||||
* Specifies whether custom look and feel window decorations should be used
|
||||
* when creating {@code JFrame} or {@code JDialog}.
|
||||
* <p>
|
||||
* If this system property is set, FlatLaf invokes {@link JFrame#setDefaultLookAndFeelDecorated(boolean)}
|
||||
* and {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} on LaF initialization.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> none
|
||||
*/
|
||||
String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations";
|
||||
|
||||
/**
|
||||
* Specifies whether JetBrains Runtime custom window decorations should be used
|
||||
* when creating {@code JFrame} or {@code JDialog}.
|
||||
* Requires that the application runs in a
|
||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
|
||||
* (based on OpenJDK).
|
||||
* <p>
|
||||
* Setting this to {@code true} forces using JetBrains Runtime custom window decorations
|
||||
* even if they are not enabled by the application.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||
|
||||
/**
|
||||
* Specifies whether menubar is embedded into custom window decorations.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
|
||||
|
||||
/**
|
||||
* Specifies whether animations are enabled.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String ANIMATION = "flatlaf.animation";
|
||||
|
||||
/**
|
||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*/
|
||||
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
|
||||
|
||||
/**
|
||||
* Checks whether a system property is set and returns {@code true} if its value
|
||||
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
||||
* If the system property is not set, {@code defaultValue} is returned.
|
||||
*/
|
||||
static boolean getBoolean( String key, boolean defaultValue ) {
|
||||
String value = System.getProperty( key );
|
||||
return (value != null) ? Boolean.parseBoolean( value ) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a system property is set and returns {@code Boolean.TRUE} if its value
|
||||
* is {@code "true"} (case-insensitive) or returns {@code Boolean.FALSE} if its value
|
||||
* is {@code "false"} (case-insensitive). Otherwise {@code defaultValue} is returned.
|
||||
*/
|
||||
static Boolean getBooleanStrict( String key, Boolean defaultValue ) {
|
||||
String value = System.getProperty( key );
|
||||
if( "true".equalsIgnoreCase( value ) )
|
||||
return Boolean.TRUE;
|
||||
if( "false".equalsIgnoreCase( value ) )
|
||||
return Boolean.FALSE;
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -56,6 +57,8 @@ public class IntelliJTheme
|
||||
public final boolean dark;
|
||||
public final String author;
|
||||
|
||||
private final boolean isMaterialUILite;
|
||||
|
||||
private final Map<String, String> colors;
|
||||
private final Map<String, Object> ui;
|
||||
private final Map<String, Object> icons;
|
||||
@@ -86,7 +89,7 @@ public class IntelliJTheme
|
||||
* Using a buffered input stream is not necessary.
|
||||
*/
|
||||
public static FlatLaf createLaf( InputStream in )
|
||||
throws IOException, ParseException
|
||||
throws IOException
|
||||
{
|
||||
return createLaf( new IntelliJTheme( in ) );
|
||||
}
|
||||
@@ -106,17 +109,21 @@ public class IntelliJTheme
|
||||
*/
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public IntelliJTheme( InputStream in )
|
||||
throws IOException, ParseException
|
||||
throws IOException
|
||||
{
|
||||
Map<String, Object> json;
|
||||
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 ) ) {
|
||||
json = (Map<String, Object>) Json.parse( reader );
|
||||
} catch( ParseException ex ) {
|
||||
throw new IOException( ex.getMessage(), ex );
|
||||
}
|
||||
|
||||
name = (String) json.get( "name" );
|
||||
dark = Boolean.parseBoolean( (String) json.get( "dark" ) );
|
||||
author = (String) json.get( "author" );
|
||||
|
||||
isMaterialUILite = author.equals( "Mallowigi" );
|
||||
|
||||
colors = (Map<String, String>) json.get( "colors" );
|
||||
ui = (Map<String, Object>) json.get( "ui" );
|
||||
icons = (Map<String, Object>) json.get( "icons" );
|
||||
@@ -132,6 +139,8 @@ public class IntelliJTheme
|
||||
defaults.put( "Button.paintShadow", true );
|
||||
defaults.put( "Button.shadowWidth", dark ? 2 : 1 );
|
||||
|
||||
Map<Object, Object> themeSpecificDefaults = removeThemeSpecificDefaults( defaults );
|
||||
|
||||
loadNamedColors( defaults );
|
||||
|
||||
// convert Json "ui" structure to UI defaults
|
||||
@@ -143,6 +152,20 @@ public class IntelliJTheme
|
||||
applyColorPalette( defaults );
|
||||
applyCheckBoxColors( defaults );
|
||||
|
||||
// copy values
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
|
||||
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
|
||||
|
||||
// IDEA does not paint button background if disabled, but FlatLaf does
|
||||
Object panelBackground = defaults.get( "Panel.background" );
|
||||
defaults.put( "Button.disabledBackground", panelBackground );
|
||||
defaults.put( "ToggleButton.disabledBackground", panelBackground );
|
||||
|
||||
// fix Button borders
|
||||
copyIfNotSet( defaults, "Button.focusedBorderColor", "Component.focusedBorderColor", uiKeys );
|
||||
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
|
||||
// IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
|
||||
Object helpButtonBackground = defaults.get( "Button.startBackground" );
|
||||
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
|
||||
@@ -152,7 +175,7 @@ public class IntelliJTheme
|
||||
helpButtonBorderColor = defaults.get( "Button.borderColor" );
|
||||
defaults.put( "HelpButton.background", helpButtonBackground );
|
||||
defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
|
||||
defaults.put( "HelpButton.disabledBackground", defaults.get( "Panel.background" ) );
|
||||
defaults.put( "HelpButton.disabledBackground", panelBackground );
|
||||
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
|
||||
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
|
||||
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
|
||||
@@ -183,6 +206,55 @@ public class IntelliJTheme
|
||||
if( !uiKeys.contains( "Spinner.background" ) )
|
||||
defaults.put( "Spinner.background", textFieldBackground );
|
||||
}
|
||||
|
||||
// fix ToggleButton
|
||||
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
|
||||
defaults.put( "ToggleButton.startBackground", defaults.get( "Button.startBackground" ) );
|
||||
if( !uiKeys.contains( "ToggleButton.endBackground" ) && !uiKeys.contains( "*.endBackground" ) )
|
||||
defaults.put( "ToggleButton.endBackground", defaults.get( "Button.endBackground" ) );
|
||||
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
|
||||
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
|
||||
|
||||
// fix List and Table background colors in Material UI Lite themes
|
||||
if( isMaterialUILite ) {
|
||||
defaults.put( "List.background", defaults.get( "Tree.background" ) );
|
||||
defaults.put( "Table.background", defaults.get( "Tree.background" ) );
|
||||
}
|
||||
|
||||
// limit tree row height
|
||||
int rowHeight = defaults.getInt( "Tree.rowHeight" );
|
||||
if( rowHeight > 22 )
|
||||
defaults.put( "Tree.rowHeight", 22 );
|
||||
|
||||
// apply theme specific UI defaults at the end to allow overwriting
|
||||
defaults.putAll( themeSpecificDefaults );
|
||||
}
|
||||
|
||||
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
|
||||
// search for theme specific UI defaults keys
|
||||
ArrayList<String> themeSpecificKeys = new ArrayList<>();
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).startsWith( "[" ) )
|
||||
themeSpecificKeys.add( (String) key );
|
||||
}
|
||||
|
||||
// remove theme specific UI defaults and remember only those for current theme
|
||||
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
|
||||
String currentThemePrefix = '[' + name.replace( ' ', '_' ) + ']';
|
||||
String currentAuthorPrefix = "[author-" + author.replace( ' ', '_' ) + ']';
|
||||
String allThemesPrefix = "[*]";
|
||||
String[] prefixes = { currentThemePrefix, currentAuthorPrefix, allThemesPrefix };
|
||||
for( String key : themeSpecificKeys ) {
|
||||
Object value = defaults.remove( key );
|
||||
for( String prefix : prefixes ) {
|
||||
if( key.startsWith( prefix ) ) {
|
||||
themeSpecificDefaults.put( key.substring( prefix.length() ), value );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return themeSpecificDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +272,7 @@ public class IntelliJTheme
|
||||
if( color != null ) {
|
||||
String key = e.getKey();
|
||||
namedColors.put( key, color );
|
||||
defaults.put( "ColorPalette." + e.getKey(), color );
|
||||
defaults.put( "ColorPalette." + key, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,8 +286,15 @@ public class IntelliJTheme
|
||||
for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
|
||||
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
|
||||
} else {
|
||||
if( "".equals( value ) )
|
||||
return; // ignore empty value
|
||||
|
||||
uiKeys.add( key );
|
||||
|
||||
// fix ComboBox size and Spinner border in all Material UI Lite themes
|
||||
if( isMaterialUILite && (key.equals( "ComboBox.padding" ) || key.equals( "Spinner.border" )) )
|
||||
return; // ignore
|
||||
|
||||
// map keys
|
||||
key = uiKeyMapping.getOrDefault( key, key );
|
||||
if( key.isEmpty() )
|
||||
@@ -270,7 +349,7 @@ public class IntelliJTheme
|
||||
// (e.g. set ComboBox.buttonEditableBackground to *.background
|
||||
// because it is mapped from ComboBox.ArrowButton.background)
|
||||
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
|
||||
if( km.endsWith( tail ) && !noWildcardReplace.contains( k ) && !((String)k).startsWith( "CheckBox.icon." ) )
|
||||
if( km.endsWith( tail ) && !((String)k).startsWith( "CheckBox.icon." ) )
|
||||
defaults.put( k, uiValue );
|
||||
}
|
||||
}
|
||||
@@ -324,7 +403,7 @@ public class IntelliJTheme
|
||||
}
|
||||
|
||||
/**
|
||||
* Because IDEA uses SVGs for check boxes and radio buttons the colors for
|
||||
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for
|
||||
* this two components are specified in "icons > ColorPalette".
|
||||
* FlatLaf uses vector icons and expects colors for the two components in UI defaults.
|
||||
*/
|
||||
@@ -362,6 +441,10 @@ public class IntelliJTheme
|
||||
|
||||
String newKey = checkboxKeyMapping.get( key );
|
||||
if( newKey != null ) {
|
||||
String checkBoxIconPrefix = "CheckBox.icon.";
|
||||
if( !dark && newKey.startsWith( checkBoxIconPrefix ) )
|
||||
newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) );
|
||||
|
||||
ColorUIResource color = toColor( (String) value );
|
||||
if( color != null ) {
|
||||
defaults.put( newKey, color );
|
||||
@@ -392,27 +475,51 @@ public class IntelliJTheme
|
||||
}
|
||||
}
|
||||
|
||||
// remove hover and pressed colors
|
||||
// update hover, pressed and focused colors
|
||||
if( checkboxModified ) {
|
||||
defaults.remove( "CheckBox.icon.hoverBorderColor" );
|
||||
defaults.remove( "CheckBox.icon.focusedBackground" );
|
||||
defaults.remove( "CheckBox.icon.hoverBackground" );
|
||||
defaults.remove( "CheckBox.icon.pressedBackground" );
|
||||
defaults.remove( "CheckBox.icon.selectedHoverBackground" );
|
||||
defaults.remove( "CheckBox.icon.selectedPressedBackground" );
|
||||
}
|
||||
// for non-filled checkbox/radiobutton used in dark themes
|
||||
defaults.remove( "CheckBox.icon.focusWidth" );
|
||||
defaults.put( "CheckBox.icon.hoverBorderColor", defaults.get( "CheckBox.icon.focusedBorderColor" ) );
|
||||
|
||||
// copy values
|
||||
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
|
||||
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
|
||||
// for filled checkbox/radiobutton used in light themes
|
||||
defaults.remove( "CheckBox.icon[filled].focusWidth" );
|
||||
defaults.put( "CheckBox.icon[filled].hoverBorderColor", defaults.get( "CheckBox.icon[filled].focusedBorderColor" ) );
|
||||
defaults.put( "CheckBox.icon[filled].selectedFocusedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) );
|
||||
|
||||
if( dark ) {
|
||||
// IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg,
|
||||
// radioFocused.svg and radioSelectedFocused.svg
|
||||
// use opacity=".65" for the border
|
||||
// --> add alpha to focused border colors
|
||||
String[] focusedBorderColorKeys = new String[] {
|
||||
"CheckBox.icon.focusedBorderColor",
|
||||
"CheckBox.icon.selectedFocusedBorderColor",
|
||||
"CheckBox.icon[filled].focusedBorderColor",
|
||||
"CheckBox.icon[filled].selectedFocusedBorderColor",
|
||||
};
|
||||
for( String key : focusedBorderColorKeys ) {
|
||||
Color color = defaults.getColor( key );
|
||||
if( color != null ) {
|
||||
defaults.put( key, new ColorUIResource( new Color(
|
||||
(color.getRGB() & 0xffffff) | 0xa6000000, true ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyIfNotSet( UIDefaults defaults, String destKey, String srcKey, Set<String> uiKeys ) {
|
||||
if( !uiKeys.contains( destKey ) )
|
||||
defaults.put( destKey, defaults.get( srcKey ) );
|
||||
}
|
||||
|
||||
/** Rename UI default keys (key --> value). */
|
||||
private static Map<String, String> uiKeyMapping = new HashMap<>();
|
||||
/** Copy UI default keys (value --> key). */
|
||||
private static Map<String, String> uiKeyCopying = new HashMap<>();
|
||||
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
|
||||
private static Map<String, String> checkboxDuplicateColors = new HashMap<>();
|
||||
private static Set<String> noWildcardReplace = new HashSet<>();
|
||||
|
||||
static {
|
||||
// ComboBox
|
||||
@@ -423,14 +530,36 @@ public class IntelliJTheme
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
|
||||
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
|
||||
|
||||
// Component
|
||||
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
|
||||
uiKeyMapping.put( "Component.errorFocusColor", "Component.error.focusedBorderColor" );
|
||||
uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" );
|
||||
uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" );
|
||||
|
||||
// Link
|
||||
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
|
||||
|
||||
// Menu
|
||||
uiKeyMapping.put( "Menu.border", "Menu.margin" );
|
||||
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
|
||||
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
|
||||
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
|
||||
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
|
||||
uiKeyCopying.put( "MenuItem.underlineSelectionColor", "TabbedPane.underlineColor" );
|
||||
|
||||
// IDEA uses List.selectionBackground also for menu selection
|
||||
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "MenuItem.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
|
||||
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
|
||||
|
||||
// ProgressBar
|
||||
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
|
||||
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
|
||||
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
|
||||
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
|
||||
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
|
||||
|
||||
// ScrollBar
|
||||
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
|
||||
@@ -441,22 +570,30 @@ public class IntelliJTheme
|
||||
|
||||
// Slider
|
||||
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
|
||||
uiKeyCopying.put( "Slider.trackValueColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
|
||||
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
|
||||
|
||||
// TitlePane
|
||||
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
|
||||
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
|
||||
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
|
||||
|
||||
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
|
||||
uiKeyInverseMapping.put( e.getValue(), e.getKey() );
|
||||
|
||||
uiKeyCopying.put( "ToggleButton.underline.underlineColor", "TabbedPane.underlineColor" );
|
||||
uiKeyCopying.put( "ToggleButton.underline.disabledUnderlineColor", "TabbedPane.disabledUnderlineColor" );
|
||||
uiKeyCopying.put( "ToggleButton.underline.selectedBackground", "TabbedPane.selectedBackground" );
|
||||
uiKeyCopying.put( "ToggleButton.underline.hoverBackground", "TabbedPane.hoverColor" );
|
||||
uiKeyCopying.put( "ToggleButton.underline.focusBackground", "TabbedPane.focusColor" );
|
||||
uiKeyCopying.put( "ToggleButton.tab.underlineColor", "TabbedPane.underlineColor" );
|
||||
uiKeyCopying.put( "ToggleButton.tab.disabledUnderlineColor", "TabbedPane.disabledUnderlineColor" );
|
||||
uiKeyCopying.put( "ToggleButton.tab.selectedBackground", "TabbedPane.selectedBackground" );
|
||||
uiKeyCopying.put( "ToggleButton.tab.hoverBackground", "TabbedPane.hoverColor" );
|
||||
uiKeyCopying.put( "ToggleButton.tab.focusBackground", "TabbedPane.focusColor" );
|
||||
|
||||
checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" );
|
||||
checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusedColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" );
|
||||
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
|
||||
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );
|
||||
@@ -470,16 +607,6 @@ public class IntelliJTheme
|
||||
Map.Entry<String, String>[] entries = checkboxDuplicateColors.entrySet().toArray( new Map.Entry[checkboxDuplicateColors.size()] );
|
||||
for( Map.Entry<String, String> e : entries )
|
||||
checkboxDuplicateColors.put( e.getValue(), e.getKey() );
|
||||
|
||||
// because FlatLaf uses Button.background and Button.borderColor,
|
||||
// but IDEA uses Button.startBackground and Button.startBorderColor,
|
||||
// our default button background and border colors may be replaced by
|
||||
// wildcard *.background and *.borderColor colors
|
||||
noWildcardReplace.add( "Button.background" );
|
||||
noWildcardReplace.add( "Button.borderColor" );
|
||||
noWildcardReplace.add( "Button.default.background" );
|
||||
noWildcardReplace.add( "Button.default.borderColor" );
|
||||
noWildcardReplace.add( "ToggleButton.background" );
|
||||
}
|
||||
|
||||
//---- class ThemeLaf -----------------------------------------------------
|
||||
@@ -500,7 +627,7 @@ public class IntelliJTheme
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return theme.name;
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -513,19 +640,12 @@ public class IntelliJTheme
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIDefaults getDefaults() {
|
||||
UIDefaults defaults = super.getDefaults();
|
||||
void applyAdditionalDefaults( UIDefaults defaults ) {
|
||||
theme.applyProperties( defaults );
|
||||
super.invokePostInitialization( defaults );
|
||||
return defaults;
|
||||
}
|
||||
|
||||
@Override
|
||||
void invokePostInitialization( UIDefaults defaults ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
lafClasses.add( FlatLaf.class );
|
||||
lafClasses.add( theme.dark ? FlatDarkLaf.class : FlatLightLaf.class );
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
import java.io.BufferedReader;
|
||||
@@ -28,9 +29,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.text.StyleContext;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -38,7 +39,7 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
class LinuxFontPolicy
|
||||
{
|
||||
static Font getFont() {
|
||||
return SystemInfo.IS_KDE ? getKDEFont() : getGnomeFont();
|
||||
return SystemInfo.isKDE ? getKDEFont() : getGnomeFont();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,6 +74,13 @@ class LinuxFontPolicy
|
||||
family = family.isEmpty() ? word : (family + ' ' + word);
|
||||
}
|
||||
|
||||
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
|
||||
// --> use Liberation Sans font
|
||||
if( family.startsWith( "Ubuntu" ) &&
|
||||
!SystemInfo.isJetBrainsJVM &&
|
||||
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_UBUNTU_FONT, false ) )
|
||||
family = "Liberation Sans";
|
||||
|
||||
// scale font size
|
||||
double dsize = size * getGnomeFontScale();
|
||||
size = (int) (dsize + 0.5);
|
||||
@@ -88,9 +96,7 @@ class LinuxFontPolicy
|
||||
}
|
||||
|
||||
private static Font createFont( String family, int style, int size, double dsize ) {
|
||||
// using StyleContext.getFont() here because it uses
|
||||
// sun.font.FontUtilities.getCompositeFontUIResource()
|
||||
Font font = new StyleContext().getFont( family, style, size );
|
||||
Font font = FlatLaf.createCompositeFont( family, style, size );
|
||||
|
||||
// set font size in floating points
|
||||
font = font.deriveFont( style, (float) dsize );
|
||||
@@ -99,6 +105,10 @@ class LinuxFontPolicy
|
||||
}
|
||||
|
||||
private static double getGnomeFontScale() {
|
||||
// do not scale font here if JRE scales
|
||||
if( isSystemScaling() )
|
||||
return 96. / 72.;
|
||||
|
||||
// see class com.sun.java.swing.plaf.gtk.PangoFonts background information
|
||||
|
||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" );
|
||||
@@ -168,7 +178,7 @@ class LinuxFontPolicy
|
||||
|
||||
// font dpi
|
||||
int dpi = 96;
|
||||
if( forceFontDPI != null ) {
|
||||
if( forceFontDPI != null && !isSystemScaling() ) {
|
||||
try {
|
||||
dpi = Integer.parseInt( forceFontDPI );
|
||||
if( dpi <= 0 )
|
||||
@@ -247,4 +257,15 @@ class LinuxFontPolicy
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the JRE scales, which is the case if:
|
||||
* - environment variable GDK_SCALE is set and running on Java 9 or later
|
||||
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
|
||||
*/
|
||||
private static boolean isSystemScaling() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
return UIScale.getSystemScaleFactor( gc ) > 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.KeyEventPostProcessor;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Show/hide mnemonics.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class MnemonicHandler
|
||||
implements KeyEventPostProcessor, ChangeListener
|
||||
{
|
||||
private static boolean showMnemonics;
|
||||
private static WeakReference<Window> lastShowMnemonicWindow;
|
||||
private static WindowListener windowListener;
|
||||
|
||||
static boolean isShowMnemonics() {
|
||||
return showMnemonics || !UIManager.getBoolean( "Component.hideMnemonics" );
|
||||
}
|
||||
|
||||
void install() {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( this );
|
||||
MenuSelectionManager.defaultManager().addChangeListener( this );
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( this );
|
||||
MenuSelectionManager.defaultManager().removeChangeListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean postProcessKeyEvent( KeyEvent e ) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if( SystemInfo.isMacOS ) {
|
||||
// Ctrl+Alt keys must be pressed on Mac
|
||||
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() );
|
||||
} else {
|
||||
// Alt key must be pressed on Windows and Linux
|
||||
if( SystemInfo.isWindows )
|
||||
return processKeyEventOnWindows( e );
|
||||
|
||||
if( keyCode == KeyEvent.VK_ALT )
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldShowMnemonics( KeyEvent e ) {
|
||||
return e.getID() == KeyEvent.KEY_PRESSED ||
|
||||
MenuSelectionManager.defaultManager().getSelectedPath().length > 0;
|
||||
}
|
||||
|
||||
private static int altPressedEventCount;
|
||||
private static boolean selectMenuOnAltReleased;
|
||||
|
||||
/**
|
||||
* Special Alt key behavior on Windows.
|
||||
*
|
||||
* Press-and-release Alt key selects first menu (if available) and moves focus
|
||||
* temporary to menu bar. If menu bar has focus (some menu is selected),
|
||||
* pressing Alt key unselects menu and moves focus back to permanent focus owner.
|
||||
*/
|
||||
private boolean processKeyEventOnWindows( KeyEvent e ) {
|
||||
if( e.getKeyCode() != KeyEvent.VK_ALT ) {
|
||||
selectMenuOnAltReleased = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( e.getID() == KeyEvent.KEY_PRESSED ) {
|
||||
altPressedEventCount++;
|
||||
|
||||
if( altPressedEventCount == 1 && !e.isConsumed() ) {
|
||||
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
|
||||
selectMenuOnAltReleased = (menuSelectionManager.getSelectedPath().length == 0);
|
||||
|
||||
// if menu is selected when Alt key is pressed then clear menu selection
|
||||
if( !selectMenuOnAltReleased )
|
||||
menuSelectionManager.clearSelectedPath();
|
||||
}
|
||||
|
||||
// show mnemonics
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
|
||||
// avoid that the system menu of the window gets focus
|
||||
e.consume();
|
||||
return true;
|
||||
|
||||
} else if( e.getID() == KeyEvent.KEY_RELEASED ) {
|
||||
altPressedEventCount = 0;
|
||||
|
||||
boolean mnemonicsShown = false;
|
||||
if( selectMenuOnAltReleased && !e.isConsumed() ) {
|
||||
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
|
||||
if( menuSelectionManager.getSelectedPath().length == 0 ) {
|
||||
// get menu bar and first menu
|
||||
Component c = e.getComponent();
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( c );
|
||||
Window window = (rootPane != null) ? SwingUtilities.getWindowAncestor( rootPane ) : null;
|
||||
JMenuBar menuBar = (rootPane != null) ? rootPane.getJMenuBar() : null;
|
||||
if( menuBar == null && window instanceof JFrame )
|
||||
menuBar = ((JFrame)window).getJMenuBar();
|
||||
JMenu firstMenu = (menuBar != null) ? menuBar.getMenu( 0 ) : null;
|
||||
|
||||
// select first menu and show mnemonics
|
||||
if( firstMenu != null ) {
|
||||
menuSelectionManager.setSelectedPath( new MenuElement[] { menuBar, firstMenu } );
|
||||
showMnemonics( true, c );
|
||||
mnemonicsShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectMenuOnAltReleased = false;
|
||||
|
||||
// hide mnemonics
|
||||
if( !mnemonicsShown )
|
||||
showMnemonics( shouldShowMnemonics( e ), e.getComponent() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath();
|
||||
if( selectedPath.length == 0 && altPressedEventCount == 0 ) {
|
||||
// hide mnemonics when menu selection was canceled
|
||||
showMnemonics( false, null );
|
||||
}
|
||||
}
|
||||
|
||||
static void showMnemonics( boolean show, Component c ) {
|
||||
if( show == showMnemonics )
|
||||
return;
|
||||
|
||||
showMnemonics = show;
|
||||
|
||||
// check whether it is necessary to repaint
|
||||
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
|
||||
return;
|
||||
|
||||
if( show ) {
|
||||
// get root pane
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( c );
|
||||
if( rootPane == null )
|
||||
return;
|
||||
|
||||
// get window
|
||||
Window window = SwingUtilities.getWindowAncestor( rootPane );
|
||||
if( window == null )
|
||||
return;
|
||||
|
||||
// repaint components with mnemonics in focused window
|
||||
repaintMnemonics( window );
|
||||
|
||||
// hide mnemonics if window is deactivated (e.g. Alt+Tab to another window)
|
||||
windowListener = new WindowAdapter() {
|
||||
@Override
|
||||
public void windowDeactivated( WindowEvent e ) {
|
||||
altPressedEventCount = 0;
|
||||
selectMenuOnAltReleased = false;
|
||||
|
||||
// use invokeLater() to avoid that the listener is removed
|
||||
// while the listener queue is iterated to fire this event
|
||||
EventQueue.invokeLater( () -> {
|
||||
showMnemonics( false, null );
|
||||
} );
|
||||
}
|
||||
};
|
||||
window.addWindowListener( windowListener );
|
||||
|
||||
lastShowMnemonicWindow = new WeakReference<>( window );
|
||||
} else if( lastShowMnemonicWindow != null ) {
|
||||
Window window = lastShowMnemonicWindow.get();
|
||||
if( window != null ) {
|
||||
repaintMnemonics( window );
|
||||
|
||||
if( windowListener != null ) {
|
||||
window.removeWindowListener( windowListener );
|
||||
windowListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastShowMnemonicWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void repaintMnemonics( Container container ) {
|
||||
for( Component c : container.getComponents() ) {
|
||||
if( !c.isVisible() )
|
||||
continue;
|
||||
|
||||
if( hasMnemonic( c ) )
|
||||
c.repaint();
|
||||
|
||||
if( c instanceof Container )
|
||||
repaintMnemonics( (Container) c );
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasMnemonic( Component c ) {
|
||||
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
|
||||
return true;
|
||||
|
||||
if( c instanceof JTabbedPane ) {
|
||||
JTabbedPane tabPane = (JTabbedPane) c;
|
||||
int tabCount = tabPane.getTabCount();
|
||||
for( int i = 0; i < tabCount; i++ ) {
|
||||
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -19,16 +19,19 @@ package com.formdev.flatlaf;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.UIDefaults;
|
||||
@@ -41,7 +44,9 @@ import javax.swing.plaf.InsetsUIResource;
|
||||
import com.formdev.flatlaf.ui.FlatEmptyBorder;
|
||||
import com.formdev.flatlaf.ui.FlatLineBorder;
|
||||
import com.formdev.flatlaf.util.ColorFunctions;
|
||||
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.GrayFilter;
|
||||
import com.formdev.flatlaf.util.HSLColor;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
@@ -63,13 +68,15 @@ class UIDefaultsLoader
|
||||
private static final String TYPE_PREFIX = "{";
|
||||
private static final String TYPE_PREFIX_END = "}";
|
||||
private static final String VARIABLE_PREFIX = "@";
|
||||
@Deprecated
|
||||
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
|
||||
private static final String PROPERTY_PREFIX = "$";
|
||||
private static final String OPTIONAL_PREFIX = "?";
|
||||
private static final String GLOBAL_PREFIX = "*.";
|
||||
private static final String WILDCARD_PREFIX = "*.";
|
||||
|
||||
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, UIDefaults defaults ) {
|
||||
private static int parseColorDepth;
|
||||
|
||||
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons,
|
||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||
{
|
||||
// determine classes in class hierarchy in reverse order
|
||||
ArrayList<Class<?>> lafClasses = new ArrayList<>();
|
||||
for( Class<?> lafClass = lookAndFeelClass;
|
||||
@@ -79,10 +86,12 @@ class UIDefaultsLoader
|
||||
lafClasses.add( 0, lafClass );
|
||||
}
|
||||
|
||||
loadDefaultsFromProperties( lafClasses, defaults );
|
||||
loadDefaultsFromProperties( lafClasses, addons, additionalDefaults, dark, defaults );
|
||||
}
|
||||
|
||||
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, UIDefaults defaults ) {
|
||||
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons,
|
||||
Properties additionalDefaults, boolean dark, UIDefaults defaults )
|
||||
{
|
||||
try {
|
||||
// load core properties files
|
||||
Properties properties = new Properties();
|
||||
@@ -94,15 +103,8 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
// get addons and sort them by priority
|
||||
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
|
||||
List<FlatDefaultsAddon> addonList = new ArrayList<>();
|
||||
for( FlatDefaultsAddon addon : addonLoader )
|
||||
addonList.add( addon );
|
||||
addonList.sort( (addon1, addon2) -> addon1.getPriority() - addon2.getPriority() );
|
||||
|
||||
// load properties from addons
|
||||
for( FlatDefaultsAddon addon : addonList ) {
|
||||
for( FlatDefaultsAddon addon : addons ) {
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
try( InputStream in = addon.getDefaults( lafClass ) ) {
|
||||
if( in != null )
|
||||
@@ -113,26 +115,84 @@ class UIDefaultsLoader
|
||||
|
||||
// collect addon class loaders
|
||||
List<ClassLoader> addonClassLoaders = new ArrayList<>();
|
||||
for( FlatDefaultsAddon addon : addonList ) {
|
||||
for( FlatDefaultsAddon addon : addons ) {
|
||||
ClassLoader addonClassLoader = addon.getClass().getClassLoader();
|
||||
if( !addonClassLoaders.contains( addonClassLoader ) )
|
||||
addonClassLoaders.add( addonClassLoader );
|
||||
}
|
||||
|
||||
// load custom properties files (usually provided by applications)
|
||||
List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources();
|
||||
int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0;
|
||||
for( int i = 0; i < size; i++ ) {
|
||||
Object source = customDefaultsSources.get( i );
|
||||
if( source instanceof String && i + 1 < size ) {
|
||||
// load from package in classloader
|
||||
String packageName = (String) source;
|
||||
ClassLoader classLoader = (ClassLoader) customDefaultsSources.get( ++i );
|
||||
|
||||
// use class loader also for instantiating classes specified in values
|
||||
if( classLoader != null && !addonClassLoaders.contains( classLoader ) )
|
||||
addonClassLoaders.add( classLoader );
|
||||
|
||||
packageName = packageName.replace( '.', '/' );
|
||||
if( classLoader == null )
|
||||
classLoader = FlatLaf.class.getClassLoader();
|
||||
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
String propertiesName = packageName + '/' + lafClass.getSimpleName() + ".properties";
|
||||
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
|
||||
if( in != null )
|
||||
properties.load( in );
|
||||
}
|
||||
}
|
||||
} else if( source instanceof File ) {
|
||||
// load from folder
|
||||
File folder = (File) source;
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
File propertiesFile = new File( folder, lafClass.getSimpleName() + ".properties" );
|
||||
if( !propertiesFile.isFile() )
|
||||
continue;
|
||||
|
||||
try( InputStream in = new FileInputStream( propertiesFile ) ) {
|
||||
properties.load( in );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add additional defaults
|
||||
if( additionalDefaults != null )
|
||||
properties.putAll( additionalDefaults );
|
||||
|
||||
// collect all platform specific keys (but do not modify properties)
|
||||
ArrayList<String> platformSpecificKeys = new ArrayList<>();
|
||||
for( Object key : properties.keySet() ) {
|
||||
if( ((String)key).startsWith( "[" ) )
|
||||
platformSpecificKeys.add( (String) key );
|
||||
for( Object okey : properties.keySet() ) {
|
||||
String key = (String) okey;
|
||||
if( key.startsWith( "[" ) &&
|
||||
(key.startsWith( "[win]" ) ||
|
||||
key.startsWith( "[mac]" ) ||
|
||||
key.startsWith( "[linux]" ) ||
|
||||
key.startsWith( "[light]" ) ||
|
||||
key.startsWith( "[dark]" )) )
|
||||
platformSpecificKeys.add( key );
|
||||
}
|
||||
|
||||
// remove platform specific properties and re-add only properties
|
||||
// for current platform, but with platform prefix removed
|
||||
if( !platformSpecificKeys.isEmpty() ) {
|
||||
// handle light/dark specific properties
|
||||
String lightOrDarkPrefix = dark ? "[dark]" : "[light]";
|
||||
for( String key : platformSpecificKeys ) {
|
||||
if( key.startsWith( lightOrDarkPrefix ) )
|
||||
properties.put( key.substring( lightOrDarkPrefix.length() ), properties.remove( key ) );
|
||||
}
|
||||
|
||||
// handle platform specific properties
|
||||
String platformPrefix =
|
||||
SystemInfo.IS_WINDOWS ? "[win]" :
|
||||
SystemInfo.IS_MAC ? "[mac]" :
|
||||
SystemInfo.IS_LINUX ? "[linux]" : "[unknown]";
|
||||
SystemInfo.isWindows ? "[win]" :
|
||||
SystemInfo.isMacOS ? "[mac]" :
|
||||
SystemInfo.isLinux ? "[linux]" : "[unknown]";
|
||||
for( String key : platformSpecificKeys ) {
|
||||
Object value = properties.remove( key );
|
||||
if( key.startsWith( platformPrefix ) )
|
||||
@@ -140,45 +200,48 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
// get (and remove) wildcard replacements, which override all other defaults that end with same suffix
|
||||
HashMap<String, String> wildcards = new HashMap<>();
|
||||
Iterator<Entry<Object, Object>> it = properties.entrySet().iterator();
|
||||
while( it.hasNext() ) {
|
||||
Entry<Object, Object> e = it.next();
|
||||
String key = (String) e.getKey();
|
||||
if( key.startsWith( WILDCARD_PREFIX ) ) {
|
||||
wildcards.put( key.substring( WILDCARD_PREFIX.length() ), (String) e.getValue() );
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// override UI defaults with wildcard replacements
|
||||
for( Object key : defaults.keySet() ) {
|
||||
int dot;
|
||||
if( !(key instanceof String) ||
|
||||
properties.containsKey( key ) ||
|
||||
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
|
||||
continue;
|
||||
|
||||
String wildcardKey = ((String)key).substring( dot + 1 );
|
||||
String wildcardValue = wildcards.get( wildcardKey );
|
||||
if( wildcardValue != null )
|
||||
properties.put( key, wildcardValue );
|
||||
}
|
||||
|
||||
Function<String, String> propertiesGetter = key -> {
|
||||
return properties.getProperty( key );
|
||||
};
|
||||
Function<String, String> resolver = value -> {
|
||||
return resolveValue( properties, value );
|
||||
return resolveValue( value, propertiesGetter );
|
||||
};
|
||||
|
||||
// get globals, which override all other defaults that end with same suffix
|
||||
HashMap<String, Object> globals = new HashMap<>();
|
||||
// parse and add properties to UI defaults
|
||||
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
|
||||
String key = (String) e.getKey();
|
||||
if( !key.startsWith( GLOBAL_PREFIX ) )
|
||||
if( key.startsWith( VARIABLE_PREFIX ) )
|
||||
continue;
|
||||
|
||||
String value = resolveValue( properties, (String) e.getValue() );
|
||||
String value = resolveValue( (String) e.getValue(), propertiesGetter );
|
||||
try {
|
||||
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver, addonClassLoaders ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
logParseError( Level.SEVERE, key, value, ex );
|
||||
}
|
||||
}
|
||||
|
||||
// override UI defaults with globals
|
||||
for( Object key : defaults.keySet() ) {
|
||||
if( key instanceof String && ((String)key).contains( "." ) ) {
|
||||
String skey = (String) key;
|
||||
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
|
||||
Object globalValue = globals.get( globalKey );
|
||||
if( globalValue != null )
|
||||
defaults.put( key, globalValue );
|
||||
}
|
||||
}
|
||||
|
||||
// add non-global properties to UI defaults
|
||||
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
|
||||
String key = (String) e.getKey();
|
||||
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
|
||||
continue;
|
||||
|
||||
String value = resolveValue( properties, (String) e.getValue() );
|
||||
try {
|
||||
defaults.put( key, parseValue( key, value, resolver, addonClassLoaders ) );
|
||||
defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) );
|
||||
} catch( RuntimeException ex ) {
|
||||
logParseError( Level.SEVERE, key, value, ex );
|
||||
}
|
||||
@@ -192,25 +255,22 @@ class UIDefaultsLoader
|
||||
FlatLaf.LOG.log( level, "FlatLaf: Failed to parse: '" + key + '=' + value + '\'', ex );
|
||||
}
|
||||
|
||||
private static String resolveValue( Properties properties, String value ) {
|
||||
static String resolveValue( String value, Function<String, String> propertiesGetter ) {
|
||||
value = value.trim();
|
||||
String value0 = value;
|
||||
|
||||
if( value.startsWith( PROPERTY_PREFIX ) )
|
||||
value = value.substring( PROPERTY_PREFIX.length() );
|
||||
else if( !value.startsWith( VARIABLE_PREFIX ) )
|
||||
return value;
|
||||
|
||||
// for compatibility
|
||||
if( value.startsWith( REF_PREFIX ) ) {
|
||||
FlatLaf.LOG.log( Level.WARNING, "FlatLaf: Usage of '@@' in .properties files is deprecated. Use '$' instead." );
|
||||
value = value.substring( REF_PREFIX.length() );
|
||||
}
|
||||
|
||||
boolean optional = false;
|
||||
if( value.startsWith( OPTIONAL_PREFIX ) ) {
|
||||
value = value.substring( OPTIONAL_PREFIX.length() );
|
||||
optional = true;
|
||||
}
|
||||
|
||||
String newValue = properties.getProperty( value );
|
||||
String newValue = propertiesGetter.apply( value );
|
||||
if( newValue == null ) {
|
||||
if( optional )
|
||||
return "null";
|
||||
@@ -218,28 +278,40 @@ class UIDefaultsLoader
|
||||
throw new IllegalArgumentException( "variable or property '" + value + "' not found" );
|
||||
}
|
||||
|
||||
return resolveValue( properties, newValue );
|
||||
if( newValue.equals( value0 ) )
|
||||
throw new IllegalArgumentException( "endless recursion in variable or property '" + value + "'" );
|
||||
|
||||
return resolveValue( newValue, propertiesGetter );
|
||||
}
|
||||
|
||||
private enum ValueType { UNKNOWN, STRING, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, SCALEDINTEGER, INSTANCE, CLASS }
|
||||
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
|
||||
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
|
||||
|
||||
private static ValueType[] tempResultValueType = new ValueType[1];
|
||||
|
||||
static Object parseValue( String key, String value ) {
|
||||
return parseValue( key, value, v -> v, Collections.emptyList() );
|
||||
return parseValue( key, value, null, v -> v, Collections.emptyList() );
|
||||
}
|
||||
|
||||
private static Object parseValue( String key, String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
||||
static Object parseValue( String key, String value, ValueType[] resultValueType,
|
||||
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
|
||||
{
|
||||
if( resultValueType == null )
|
||||
resultValueType = tempResultValueType;
|
||||
|
||||
value = value.trim();
|
||||
|
||||
// null, false, true
|
||||
switch( value ) {
|
||||
case "null": return null;
|
||||
case "false": return false;
|
||||
case "true": return true;
|
||||
case "null": resultValueType[0] = ValueType.NULL; return null;
|
||||
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
|
||||
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
|
||||
}
|
||||
|
||||
// check for function "lazy"
|
||||
// Syntax: lazy(uiKey)
|
||||
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
|
||||
resultValueType[0] = ValueType.LAZY;
|
||||
String uiKey = value.substring( 5, value.length() - 1 ).trim();
|
||||
return (LazyValue) t -> {
|
||||
return lazyUIManagerGet( uiKey );
|
||||
@@ -271,7 +343,12 @@ class UIDefaultsLoader
|
||||
|
||||
// determine value type from key
|
||||
if( valueType == ValueType.UNKNOWN ) {
|
||||
if( key.endsWith( "ground" ) || key.endsWith( "Color" ) )
|
||||
if( key.endsWith( "UI" ) )
|
||||
valueType = ValueType.STRING;
|
||||
else if( key.endsWith( "Color" ) ||
|
||||
(key.endsWith( "ground" ) &&
|
||||
(key.endsWith( ".background" ) || key.endsWith( "Background" ) ||
|
||||
key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ))) )
|
||||
valueType = ValueType.COLOR;
|
||||
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
|
||||
valueType = ValueType.BORDER;
|
||||
@@ -284,13 +361,18 @@ class UIDefaultsLoader
|
||||
valueType = ValueType.DIMENSION;
|
||||
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
|
||||
valueType = ValueType.INTEGER;
|
||||
else if( key.endsWith( "UI" ) )
|
||||
valueType = ValueType.STRING;
|
||||
else if( key.endsWith( "Char" ) )
|
||||
valueType = ValueType.CHARACTER;
|
||||
else if( key.endsWith( "grayFilter" ) )
|
||||
valueType = ValueType.GRAYFILTER;
|
||||
}
|
||||
|
||||
resultValueType[0] = valueType;
|
||||
|
||||
// parse value
|
||||
switch( valueType ) {
|
||||
case STRING: return value;
|
||||
case CHARACTER: return parseCharacter( value );
|
||||
case INTEGER: return parseInteger( value, true );
|
||||
case FLOAT: return parseFloat( value, true );
|
||||
case BORDER: return parseBorder( value, resolver, addonClassLoaders );
|
||||
@@ -299,42 +381,54 @@ class UIDefaultsLoader
|
||||
case DIMENSION: return parseDimension( value );
|
||||
case COLOR: return parseColorOrFunction( value, resolver, true );
|
||||
case SCALEDINTEGER: return parseScaledInteger( value );
|
||||
case SCALEDFLOAT: return parseScaledFloat( value );
|
||||
case SCALEDINSETS: return parseScaledInsets( value );
|
||||
case SCALEDDIMENSION:return parseScaledDimension( value );
|
||||
case INSTANCE: return parseInstance( value, addonClassLoaders );
|
||||
case CLASS: return parseClass( value, addonClassLoaders );
|
||||
case GRAYFILTER: return parseGrayFilter( value );
|
||||
case UNKNOWN:
|
||||
default:
|
||||
// colors
|
||||
Object color = parseColorOrFunction( value, resolver, false );
|
||||
if( color != null )
|
||||
if( color != null ) {
|
||||
resultValueType[0] = ValueType.COLOR;
|
||||
return color;
|
||||
}
|
||||
|
||||
// integer
|
||||
Integer integer = parseInteger( value, false );
|
||||
if( integer != null )
|
||||
if( integer != null ) {
|
||||
resultValueType[0] = ValueType.INTEGER;
|
||||
return integer;
|
||||
}
|
||||
|
||||
// float
|
||||
Float f = parseFloat( value, false );
|
||||
if( f != null )
|
||||
if( f != null ) {
|
||||
resultValueType[0] = ValueType.FLOAT;
|
||||
return f;
|
||||
}
|
||||
|
||||
// string
|
||||
resultValueType[0] = ValueType.STRING;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseBorder( String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) {
|
||||
if( value.indexOf( ',' ) >= 0 ) {
|
||||
// top,left,bottom,right[,lineColor]
|
||||
// top,left,bottom,right[,lineColor[,lineThickness]]
|
||||
List<String> parts = split( value, ',' );
|
||||
Insets insets = parseInsets( value );
|
||||
ColorUIResource lineColor = (parts.size() == 5)
|
||||
ColorUIResource lineColor = (parts.size() >= 5)
|
||||
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver, true )
|
||||
: null;
|
||||
float lineThickness = (parts.size() >= 6) ? parseFloat( parts.get( 5 ), true ) : 1f;
|
||||
|
||||
return (LazyValue) t -> {
|
||||
return (lineColor != null)
|
||||
? new FlatLineBorder( insets, lineColor )
|
||||
? new FlatLineBorder( insets, lineColor, lineThickness )
|
||||
: new FlatEmptyBorder( insets );
|
||||
};
|
||||
} else
|
||||
@@ -488,13 +582,27 @@ class UIDefaultsLoader
|
||||
if( params.isEmpty() )
|
||||
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
|
||||
|
||||
switch( function ) {
|
||||
case "rgb": return parseColorRgbOrRgba( false, params );
|
||||
case "rgba": return parseColorRgbOrRgba( true, params );
|
||||
case "hsl": return parseColorHslOrHsla( false, params );
|
||||
case "hsla": return parseColorHslOrHsla( true, params );
|
||||
case "lighten": return parseColorLightenOrDarken( true, params, resolver, reportError );
|
||||
case "darken": return parseColorLightenOrDarken( false, params, resolver, reportError );
|
||||
if( parseColorDepth > 100 )
|
||||
throw new IllegalArgumentException( "endless recursion in color function '" + value + "'" );
|
||||
|
||||
parseColorDepth++;
|
||||
try {
|
||||
switch( function ) {
|
||||
case "rgb": return parseColorRgbOrRgba( false, params, resolver, reportError );
|
||||
case "rgba": return parseColorRgbOrRgba( true, params, resolver, reportError );
|
||||
case "hsl": return parseColorHslOrHsla( false, params );
|
||||
case "hsla": return parseColorHslOrHsla( true, params );
|
||||
case "lighten": return parseColorHSLIncreaseDecrease( 2, true, params, resolver, reportError );
|
||||
case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError );
|
||||
case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError );
|
||||
case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError );
|
||||
case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError );
|
||||
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
|
||||
case "fade": return parseColorFade( params, resolver, reportError );
|
||||
case "spin": return parseColorSpin( params, resolver, reportError );
|
||||
}
|
||||
} finally {
|
||||
parseColorDepth--;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
|
||||
@@ -502,16 +610,29 @@ class UIDefaultsLoader
|
||||
|
||||
/**
|
||||
* Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha)
|
||||
* - red: an integer 0-255
|
||||
* - green: an integer 0-255
|
||||
* - blue: an integer 0-255
|
||||
* - alpha: an integer 0-255
|
||||
* - red: an integer 0-255 or a percentage 0-100%
|
||||
* - green: an integer 0-255 or a percentage 0-100%
|
||||
* - blue: an integer 0-255 or a percentage 0-100%
|
||||
* - alpha: an integer 0-255 or a percentage 0-100%
|
||||
*/
|
||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params ) {
|
||||
int red = parseInteger( params.get( 0 ), 0, 255 );
|
||||
int green = parseInteger( params.get( 1 ), 0, 255 );
|
||||
int blue = parseInteger( params.get( 2 ), 0, 255 );
|
||||
int alpha = hasAlpha ? parseInteger( params.get( 3 ), 0, 255 ) : 255;
|
||||
private static ColorUIResource parseColorRgbOrRgba( boolean hasAlpha, List<String> params,
|
||||
Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
if( hasAlpha && params.size() == 2 ) {
|
||||
// syntax rgba(color,alpha), which allows adding alpha to any color
|
||||
// NOTE: this syntax is deprecated
|
||||
// use fade(color,alpha) instead
|
||||
String colorStr = params.get( 0 );
|
||||
int alpha = parseInteger( params.get( 1 ), 0, 255, true );
|
||||
|
||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
||||
return new ColorUIResource( new Color( ((alpha & 0xff) << 24) | (color.getRGB() & 0xffffff), true ) );
|
||||
}
|
||||
|
||||
int red = parseInteger( params.get( 0 ), 0, 255, true );
|
||||
int green = parseInteger( params.get( 1 ), 0, 255, true );
|
||||
int blue = parseInteger( params.get( 2 ), 0, 255, true );
|
||||
int alpha = hasAlpha ? parseInteger( params.get( 3 ), 0, 255, true ) : 255;
|
||||
|
||||
return hasAlpha
|
||||
? new ColorUIResource( new Color( red, green, blue, alpha ) )
|
||||
@@ -526,7 +647,7 @@ class UIDefaultsLoader
|
||||
* - alpha: a percentage 0-100%
|
||||
*/
|
||||
private static ColorUIResource parseColorHslOrHsla( boolean hasAlpha, List<String> params ) {
|
||||
int hue = parseInteger( params.get( 0 ), 0, 360 );
|
||||
int hue = parseInteger( params.get( 0 ), 0, 360, false );
|
||||
int saturation = parsePercentage( params.get( 1 ) );
|
||||
int lightness = parsePercentage( params.get( 2 ) );
|
||||
int alpha = hasAlpha ? parsePercentage( params.get( 3 ) ) : 100;
|
||||
@@ -536,35 +657,38 @@ class UIDefaultsLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: lighten([color,]amount[,options]) or darken([color,]amount[,options])
|
||||
* Syntax: lighten(color,amount[,options]) or darken(color,amount[,options]) or
|
||||
* saturate(color,amount[,options]) or desaturate(color,amount[,options]) or
|
||||
* fadein(color,amount[,options]) or fadeout(color,amount[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - amount: percentage 0-100%
|
||||
* - options: [relative] [autoInverse] [lazy]
|
||||
* - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
|
||||
*/
|
||||
private static Object parseColorLightenOrDarken( boolean lighten, List<String> params,
|
||||
Function<String, String> resolver, boolean reportError )
|
||||
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
|
||||
List<String> params, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
boolean isDerived = params.get( 0 ).endsWith( "%" );
|
||||
String colorStr = isDerived ? null : params.get( 0 );
|
||||
int nextParam = isDerived ? 0 : 1;
|
||||
int amount = parsePercentage( params.get( nextParam++ ) );
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parsePercentage( params.get( 1 ) );
|
||||
boolean relative = false;
|
||||
boolean autoInverse = false;
|
||||
boolean lazy = false;
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > nextParam ) {
|
||||
String options = params.get( nextParam++ );
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
relative = options.contains( "relative" );
|
||||
autoInverse = options.contains( "autoInverse" );
|
||||
lazy = options.contains( "lazy" );
|
||||
derived = options.contains( "derived" );
|
||||
|
||||
// use autoInverse by default for derived colors, except if noAutoInverse is set
|
||||
if( derived && !options.contains( "noAutoInverse" ) )
|
||||
autoInverse = true;
|
||||
}
|
||||
|
||||
ColorFunctions.ColorFunction function = lighten
|
||||
? new ColorFunctions.Lighten( amount, relative, autoInverse )
|
||||
: new ColorFunctions.Darken( amount, relative, autoInverse );
|
||||
|
||||
if( isDerived )
|
||||
return new DerivedColor( function );
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease(
|
||||
hslIndex, increase, amount, relative, autoInverse );
|
||||
|
||||
if( lazy ) {
|
||||
return (LazyValue) t -> {
|
||||
@@ -575,8 +699,84 @@ class UIDefaultsLoader
|
||||
};
|
||||
}
|
||||
|
||||
ColorUIResource color = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError );
|
||||
return new ColorUIResource( ColorFunctions.applyFunctions( color, function ) );
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: fade(color,amount[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - amount: percentage 0-100%
|
||||
* - options: [derived]
|
||||
*/
|
||||
private static Object parseColorFade( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parsePercentage( params.get( 1 ) );
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
derived = options.contains( "derived" );
|
||||
}
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.Fade( amount );
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: spin(color,angle[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - angle: number of degrees to rotate
|
||||
* - options: [derived]
|
||||
*/
|
||||
private static Object parseColorSpin( List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
String colorStr = params.get( 0 );
|
||||
int amount = parseInteger( params.get( 1 ), true );
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
derived = options.contains( "derived" );
|
||||
}
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
// parse base color
|
||||
String resolvedColorStr = resolver.apply( colorStr );
|
||||
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
|
||||
if( baseColor == null )
|
||||
return null;
|
||||
|
||||
// apply this function to base color
|
||||
Color newColor = ColorFunctions.applyFunctions( baseColor, function );
|
||||
|
||||
if( derived ) {
|
||||
ColorFunction[] functions;
|
||||
if( baseColor instanceof DerivedColor && resolvedColorStr == colorStr ) {
|
||||
// if the base color is also derived, join the color functions
|
||||
// but only if base color function is specified directly in this function
|
||||
ColorFunction[] baseFunctions = ((DerivedColor)baseColor).getFunctions();
|
||||
functions = new ColorFunction[baseFunctions.length + 1];
|
||||
System.arraycopy( baseFunctions, 0, functions, 0, baseFunctions.length );
|
||||
functions[baseFunctions.length] = function;
|
||||
} else
|
||||
functions = new ColorFunction[] { function };
|
||||
|
||||
return new DerivedColor( newColor, functions );
|
||||
}
|
||||
|
||||
return new ColorUIResource( newColor );
|
||||
}
|
||||
|
||||
private static int parsePercentage( String value ) {
|
||||
@@ -595,7 +795,18 @@ class UIDefaultsLoader
|
||||
return val;
|
||||
}
|
||||
|
||||
private static Integer parseInteger( String value, int min, int max ) {
|
||||
private static Character parseCharacter( String value ) {
|
||||
if( value.length() != 1 )
|
||||
throw new IllegalArgumentException( "invalid character '" + value + "'" );
|
||||
return value.charAt( 0 );
|
||||
}
|
||||
|
||||
private static Integer parseInteger( String value, int min, int max, boolean allowPercentage ) {
|
||||
if( allowPercentage && value.endsWith( "%" ) ) {
|
||||
int percent = parsePercentage( value );
|
||||
return (max * percent) / 100;
|
||||
}
|
||||
|
||||
Integer integer = parseInteger( value, true );
|
||||
if( integer.intValue() < min || integer.intValue() > max )
|
||||
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
|
||||
@@ -629,6 +840,42 @@ class UIDefaultsLoader
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledFloat( String value ) {
|
||||
float val = parseFloat( value, true );
|
||||
return (ActiveValue) t -> {
|
||||
return UIScale.scale( val );
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledInsets( String value ) {
|
||||
Insets insets = parseInsets( value );
|
||||
return (ActiveValue) t -> {
|
||||
return UIScale.scale( insets );
|
||||
};
|
||||
}
|
||||
|
||||
private static ActiveValue parseScaledDimension( String value ) {
|
||||
Dimension dimension = parseDimension( value );
|
||||
return (ActiveValue) t -> {
|
||||
return UIScale.scale( dimension );
|
||||
};
|
||||
}
|
||||
|
||||
private static Object parseGrayFilter( String value ) {
|
||||
List<String> numbers = split( value, ',' );
|
||||
try {
|
||||
int brightness = Integer.parseInt( numbers.get( 0 ) );
|
||||
int contrast = Integer.parseInt( numbers.get( 1 ) );
|
||||
int alpha = Integer.parseInt( numbers.get( 2 ) );
|
||||
|
||||
return (LazyValue) t -> {
|
||||
return new GrayFilter( brightness, contrast, alpha );
|
||||
};
|
||||
} catch( NumberFormatException ex ) {
|
||||
throw new IllegalArgumentException( "invalid gray filter '" + value + "'" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string and trim parts.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.util.AnimatedIcon;
|
||||
|
||||
/**
|
||||
* Base class for animated icons that scales width and height, creates and initializes
|
||||
* a scaled graphics context for icon painting.
|
||||
* <p>
|
||||
* Subclasses do not need to scale icon painting.
|
||||
* <p>
|
||||
* This class does not store any state information (needed for animation) in its instance.
|
||||
* Instead a client property is set on the painted component.
|
||||
* This makes it possible to use a share icon instance for multiple components.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public abstract class FlatAnimatedIcon
|
||||
extends FlatAbstractIcon
|
||||
implements AnimatedIcon
|
||||
{
|
||||
public FlatAnimatedIcon( int width, int height, Color color ) {
|
||||
super( width, height, color );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
super.paintIcon( c, g, x, y );
|
||||
AnimatedIcon.AnimationSupport.saveIconLocation( this, c, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
AnimatedIcon.AnimationSupport.paintIcon( this, c, g, 0, 0 );
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "ascendingSort" icon for {@link javax.swing.table.JTableHeader}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Table.sortIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -35,7 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatAscendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatAscendingSortIcon() {
|
||||
@@ -47,7 +47,7 @@ public class FlatAscendingSortIcon
|
||||
g.setColor( sortIconColor );
|
||||
if( chevron ) {
|
||||
// chevron arrow
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,5, 5,1, 9,5 );
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 );
|
||||
g.setStroke( new BasicStroke( 1f ) );
|
||||
g.draw( path );
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "caps lock" icon for {@link javax.swing.JPasswordField}.
|
||||
*
|
||||
* @uiDefault PasswordField.capsLockIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatCapsLockIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
public FlatCapsLockIcon() {
|
||||
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
||||
<rect width="6" height="2" x="5" y="12" fill="#FFF"/>
|
||||
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
*/
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
||||
path.append( new Rectangle2D.Float( 5, 12, 6, 2 ), false );
|
||||
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
|
||||
g.fill( path );
|
||||
}
|
||||
}
|
||||
@@ -36,25 +36,29 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
* is painted outside of the icon bounds. Make sure that the checkbox
|
||||
* has margins, which are equal or greater than focusWidth.
|
||||
*
|
||||
* @uiDefault CheckBox.icon.style String optional; "outline"/null (default) or "filled"
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault CheckBox.icon.focusedColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault CheckBox.icon.focusWidth int optional; defaults to Component.focusWidth
|
||||
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault CheckBox.icon.borderColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBorderColor Color
|
||||
* @uiDefault CheckBox.icon.selectedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.focusedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.background Color
|
||||
* @uiDefault CheckBox.icon.disabledBackground Color
|
||||
* @uiDefault CheckBox.icon.focusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.pressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedBorderColor Color
|
||||
* @uiDefault CheckBox.icon.selectedBackground Color
|
||||
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.checkmarkColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBorderColor Color
|
||||
* @uiDefault CheckBox.icon.disabledBackground Color
|
||||
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault CheckBox.icon.focusedBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.focusedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional; CheckBox.icon.focusedBorderColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.selectedFocusedBackground Color optional; CheckBox.icon.focusedBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.selectedFocusedCheckmarkColor Color optional; CheckBox.icon.checkmarkColor is used if not specified
|
||||
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
|
||||
* @uiDefault CheckBox.icon.hoverBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional; CheckBox.icon.hoverBackground is used if not specified
|
||||
* @uiDefault CheckBox.icon.pressedBackground Color optional
|
||||
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional; CheckBox.icon.pressedBackground is used if not specified
|
||||
* @uiDefault CheckBox.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -62,27 +66,62 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatCheckBoxIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
public final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusedColor",
|
||||
protected final String style = UIManager.getString( "CheckBox.icon.style" );
|
||||
public final int focusWidth = getUIInt( "CheckBox.icon.focusWidth",
|
||||
UIManager.getInt( "Component.focusWidth" ), style );
|
||||
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor",
|
||||
UIManager.getColor( "Component.focusColor" ) );
|
||||
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" );
|
||||
protected final Color selectedBorderColor = UIManager.getColor( "CheckBox.icon.selectedBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "CheckBox.icon.focusedBorderColor" );
|
||||
protected final Color hoverBorderColor = UIManager.getColor( "CheckBox.icon.hoverBorderColor" );
|
||||
protected final Color selectedFocusedBorderColor = UIManager.getColor( "CheckBox.icon.selectedFocusedBorderColor" );
|
||||
protected final Color background = UIManager.getColor( "CheckBox.icon.background" );
|
||||
protected final Color disabledBackground = UIManager.getColor( "CheckBox.icon.disabledBackground" );
|
||||
protected final Color focusedBackground = UIManager.getColor( "CheckBox.icon.focusedBackground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "CheckBox.icon.hoverBackground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "CheckBox.icon.pressedBackground" );
|
||||
protected final Color selectedBackground = UIManager.getColor( "CheckBox.icon.selectedBackground" );
|
||||
protected final Color selectedHoverBackground = UIManager.getColor( "CheckBox.icon.selectedHoverBackground" );
|
||||
protected final Color selectedPressedBackground = UIManager.getColor( "CheckBox.icon.selectedPressedBackground" );
|
||||
protected final Color checkmarkColor = UIManager.getColor( "CheckBox.icon.checkmarkColor" );
|
||||
protected final Color disabledCheckmarkColor = UIManager.getColor( "CheckBox.icon.disabledCheckmarkColor" );
|
||||
// enabled
|
||||
protected final Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
|
||||
protected final Color background = getUIColor( "CheckBox.icon.background", style );
|
||||
protected final Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
|
||||
protected final Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
|
||||
protected final Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
|
||||
|
||||
// disabled
|
||||
protected final Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
|
||||
protected final Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
|
||||
protected final Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
|
||||
|
||||
// focused
|
||||
protected final Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
|
||||
protected final Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
|
||||
protected final Color selectedFocusedBorderColor = getUIColor( "CheckBox.icon.selectedFocusedBorderColor", style );
|
||||
protected final Color selectedFocusedBackground = getUIColor( "CheckBox.icon.selectedFocusedBackground", style );
|
||||
protected final Color selectedFocusedCheckmarkColor = getUIColor( "CheckBox.icon.selectedFocusedCheckmarkColor", style );
|
||||
|
||||
// hover
|
||||
protected final Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
|
||||
protected final Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
|
||||
protected final Color selectedHoverBackground = getUIColor( "CheckBox.icon.selectedHoverBackground", style );
|
||||
|
||||
// pressed
|
||||
protected final Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
|
||||
protected final Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style );
|
||||
|
||||
protected static Color getUIColor( String key, String style ) {
|
||||
if( style != null ) {
|
||||
Color color = UIManager.getColor( styleKey( key, style ) );
|
||||
if( color != null )
|
||||
return color;
|
||||
}
|
||||
return UIManager.getColor( key );
|
||||
}
|
||||
|
||||
protected static int getUIInt( String key, int defaultValue, String style ) {
|
||||
if( style != null ) {
|
||||
Object value = UIManager.get( styleKey( key, style ) );
|
||||
if( value instanceof Integer )
|
||||
return (Integer) value;
|
||||
}
|
||||
return FlatUIUtils.getUIInt( key, defaultValue );
|
||||
}
|
||||
|
||||
private static String styleKey( String key, String style ) {
|
||||
return key.replace( ".icon.", ".icon[" + style + "]." );
|
||||
}
|
||||
|
||||
static final int ICON_SIZE = 15;
|
||||
|
||||
@@ -91,73 +130,108 @@ public class FlatCheckBoxIcon
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g2 ) {
|
||||
boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
|
||||
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
boolean indeterminate = isIndeterminate( c );
|
||||
boolean selected = indeterminate || isSelected( c );
|
||||
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
// paint focused border
|
||||
if( c.hasFocus() && focusWidth > 0 ) {
|
||||
g2.setColor( focusColor );
|
||||
paintFocusBorder( g2 );
|
||||
if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g.setColor( getFocusColor( c ) );
|
||||
paintFocusBorder( c, g );
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.setColor( FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null ) );
|
||||
paintBorder( g2 );
|
||||
g.setColor( getBorderColor( c, selected ) );
|
||||
paintBorder( c, g );
|
||||
|
||||
// paint background
|
||||
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
focusedBackground,
|
||||
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
|
||||
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ),
|
||||
background );
|
||||
paintBackground( g2 );
|
||||
Color bg = FlatUIUtils.deriveColor( getBackground( c, selected ),
|
||||
selected ? selectedBackground : background );
|
||||
if( bg.getAlpha() < 255 ) {
|
||||
// fill background with default color before filling with non-opaque background
|
||||
g.setColor( selected ? selectedBackground : background );
|
||||
paintBackground( c, g );
|
||||
}
|
||||
g.setColor( bg );
|
||||
paintBackground( c, g );
|
||||
|
||||
// paint checkmark
|
||||
if( selected || indeterminate ) {
|
||||
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor );
|
||||
g.setColor( getCheckmarkColor( c, selected, isFocused ) );
|
||||
if( indeterminate )
|
||||
paintIndeterminate( g2 );
|
||||
paintIndeterminate( c, g );
|
||||
else
|
||||
paintCheckmark( g2 );
|
||||
paintCheckmark( c, g );
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintFocusBorder( Graphics2D g2 ) {
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE - 1 + (focusWidth * 2);
|
||||
int arcwh = arc + (focusWidth * 2);
|
||||
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
|
||||
g.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintBorder( Graphics2D g2 ) {
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
int arcwh = arc;
|
||||
g2.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
|
||||
g.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics2D g2 ) {
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
int arcwh = arc - 1;
|
||||
g2.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
|
||||
g.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
|
||||
}
|
||||
|
||||
protected void paintCheckmark( Graphics2D g2 ) {
|
||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||
Path2D.Float path = new Path2D.Float();
|
||||
path.moveTo( 4.5f, 7.5f );
|
||||
path.lineTo( 6.6f, 10f );
|
||||
path.lineTo( 11.25f, 3.5f );
|
||||
|
||||
g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||
g2.draw( path );
|
||||
g.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
|
||||
g.draw( path );
|
||||
}
|
||||
|
||||
protected void paintIndeterminate( Graphics2D g2 ) {
|
||||
g2.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
|
||||
protected void paintIndeterminate( Component c, Graphics2D g ) {
|
||||
g.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
|
||||
}
|
||||
|
||||
protected boolean isIndeterminate( Component c ) {
|
||||
return c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
|
||||
}
|
||||
|
||||
protected boolean isSelected( Component c ) {
|
||||
return c instanceof AbstractButton && ((AbstractButton)c).isSelected();
|
||||
}
|
||||
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return focusColor;
|
||||
}
|
||||
|
||||
protected Color getBorderColor( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
selected && selectedFocusedBorderColor != null ? selectedFocusedBorderColor : focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null );
|
||||
}
|
||||
|
||||
protected Color getBackground( Component c, boolean selected ) {
|
||||
return FlatButtonUI.buttonStateColor( c,
|
||||
selected ? selectedBackground : background,
|
||||
disabledBackground,
|
||||
(selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
|
||||
(selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
|
||||
(selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
protected Color getCheckmarkColor( Component c, boolean selected, boolean isFocused ) {
|
||||
return c.isEnabled()
|
||||
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
|
||||
? selectedFocusedCheckmarkColor
|
||||
: checkmarkColor)
|
||||
: disabledCheckmarkColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ import javax.swing.UIManager;
|
||||
*
|
||||
* @uiDefault MenuItemCheckBox.icon.checkmarkColor Color
|
||||
* @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionType String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -39,7 +40,7 @@ public class FlatCheckBoxMenuItemIcon
|
||||
{
|
||||
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
|
||||
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
|
||||
|
||||
public FlatCheckBoxMenuItemIcon() {
|
||||
super( 15, 15, null );
|
||||
@@ -66,10 +67,15 @@ public class FlatCheckBoxMenuItemIcon
|
||||
g2.draw( path );
|
||||
}
|
||||
|
||||
private Color getCheckmarkColor( Component c ) {
|
||||
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() )
|
||||
protected Color getCheckmarkColor( Component c ) {
|
||||
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() )
|
||||
return selectionForeground;
|
||||
|
||||
return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "descendingSort" icon for {@link javax.swing.table.JTableHeader}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Table.sortIconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -35,7 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatDescendingSortIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
|
||||
|
||||
public FlatDescendingSortIcon() {
|
||||
@@ -47,7 +47,7 @@ public class FlatDescendingSortIcon
|
||||
g.setColor( sortIconColor );
|
||||
if( chevron ) {
|
||||
// chevron arrow
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 9,1 );
|
||||
Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 );
|
||||
g.setStroke( new BasicStroke( 1f ) );
|
||||
g.draw( path );
|
||||
} else {
|
||||
|
||||
@@ -31,6 +31,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault HelpButton.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||
* @uiDefault HelpButton.borderWidth int optional; default is 1
|
||||
* @uiDefault HelpButton.borderColor Color
|
||||
* @uiDefault HelpButton.disabledBorderColor Color
|
||||
* @uiDefault HelpButton.focusedBorderColor Color
|
||||
@@ -50,6 +52,8 @@ public class FlatHelpButtonIcon
|
||||
{
|
||||
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) );
|
||||
protected final int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 );
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
|
||||
@@ -82,14 +86,20 @@ public class FlatHelpButtonIcon
|
||||
*/
|
||||
|
||||
boolean enabled = c.isEnabled();
|
||||
boolean focused = c.hasFocus();
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||
|
||||
// paint focused border
|
||||
if( focused ) {
|
||||
float xy = 0.5f;
|
||||
float wh = iconSize - 1;
|
||||
|
||||
// paint outer focus border
|
||||
if( focused && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g2.setColor( focusColor );
|
||||
g2.fill( new Ellipse2D.Float( 0.5f, 0.5f, iconSize - 1, iconSize - 1 ) );
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||
}
|
||||
|
||||
xy += focusWidth;
|
||||
wh -= (focusWidth * 2);
|
||||
|
||||
// paint border
|
||||
g2.setColor( FlatButtonUI.buttonStateColor( c,
|
||||
borderColor,
|
||||
@@ -97,16 +107,28 @@ public class FlatHelpButtonIcon
|
||||
focusedBorderColor,
|
||||
hoverBorderColor,
|
||||
null ) );
|
||||
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||
|
||||
xy += borderWidth;
|
||||
wh -= (borderWidth * 2);
|
||||
|
||||
// paint inner focus border
|
||||
if( innerFocusWidth > 0 && focused && FlatButtonUI.isFocusPainted( c ) ) {
|
||||
g2.setColor( focusColor );
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||
|
||||
xy += innerFocusWidth;
|
||||
wh -= (innerFocusWidth * 2);
|
||||
}
|
||||
|
||||
// paint background
|
||||
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
|
||||
g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
|
||||
background,
|
||||
disabledBackground,
|
||||
focusedBackground,
|
||||
hoverBackground,
|
||||
pressedBackground ), background );
|
||||
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
|
||||
pressedBackground ), background ) );
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, wh, wh ) );
|
||||
|
||||
// paint question mark
|
||||
Path2D q = new Path2D.Float();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2019 FormDev Software GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* Base class for internal frame icons.
|
||||
*
|
||||
* @uiDefault InternalFrame.buttonSize Dimension
|
||||
* @uiDefault InternalFrame.buttonHoverBackground Color
|
||||
* @uiDefault InternalFrame.buttonPressedBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public abstract class FlatInternalFrameAbstractIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
private final Color hoverBackground;
|
||||
private final Color pressedBackground;
|
||||
|
||||
public FlatInternalFrameAbstractIcon() {
|
||||
this( UIManager.getDimension( "InternalFrame.buttonSize" ),
|
||||
UIManager.getColor( "InternalFrame.buttonHoverBackground" ),
|
||||
UIManager.getColor( "InternalFrame.buttonPressedBackground" ) );
|
||||
}
|
||||
|
||||
public FlatInternalFrameAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
|
||||
super( size.width, size.height, null );
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
}
|
||||
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||
if( background != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,30 +17,45 @@
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
|
||||
/**
|
||||
* "close" icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @uiDefault InternalFrame.iconColor Color
|
||||
* @uiDefault InternalFrame.buttonSize Dimension
|
||||
* @uiDefault InternalFrame.closeHoverBackground Color
|
||||
* @uiDefault InternalFrame.closePressedBackground Color
|
||||
* @uiDefault InternalFrame.closeHoverForeground Color
|
||||
* @uiDefault InternalFrame.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameCloseIcon
|
||||
extends FlatAbstractIcon
|
||||
extends FlatInternalFrameAbstractIcon
|
||||
{
|
||||
private final Color hoverForeground = UIManager.getColor( "InternalFrame.closeHoverForeground" );
|
||||
private final Color pressedForeground = UIManager.getColor( "InternalFrame.closePressedForeground" );
|
||||
|
||||
public FlatInternalFrameCloseIcon() {
|
||||
super( 16, 16, UIManager.getColor( "InternalFrame.iconColor" ) );
|
||||
super( UIManager.getDimension( "InternalFrame.buttonSize" ),
|
||||
UIManager.getColor( "InternalFrame.closeHoverBackground" ),
|
||||
UIManager.getColor( "InternalFrame.closePressedBackground" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
float mx = 8;
|
||||
float my = 8;
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground ) );
|
||||
|
||||
float mx = width / 2;
|
||||
float my = height / 2;
|
||||
float r = 3.25f;
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
|
||||
@@ -18,24 +18,23 @@ package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* "iconify" icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @uiDefault InternalFrame.iconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameIconifyIcon
|
||||
extends FlatAbstractIcon
|
||||
extends FlatInternalFrameAbstractIcon
|
||||
{
|
||||
public FlatInternalFrameIconifyIcon() {
|
||||
super( 16, 16, UIManager.getColor( "InternalFrame.iconColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
g.fillRect( 3, 8, 10, 1 );
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( c.getForeground() );
|
||||
g.fillRect( (width / 2) - 4, height / 2, 8, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,25 +18,24 @@ package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "maximize" icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @uiDefault InternalFrame.iconColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameMaximizeIcon
|
||||
extends FlatAbstractIcon
|
||||
extends FlatInternalFrameAbstractIcon
|
||||
{
|
||||
public FlatInternalFrameMaximizeIcon() {
|
||||
super( 16, 16, UIManager.getColor( "InternalFrame.iconColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
g.fill( FlatUIUtils.createRectangle( 3, 3, 10, 10, 1 ) );
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( c.getForeground() );
|
||||
g.fill( FlatUIUtils.createRectangle( (width / 2) - 4, (height / 2) - 4, 8, 8, 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,30 +21,32 @@ import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "minimize" (actually "restore") icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @uiDefault InternalFrame.iconColor Color
|
||||
* "restore" (or "minimize") icon for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameMinimizeIcon
|
||||
extends FlatAbstractIcon
|
||||
public class FlatInternalFrameRestoreIcon
|
||||
extends FlatInternalFrameAbstractIcon
|
||||
{
|
||||
public FlatInternalFrameMinimizeIcon() {
|
||||
super( 16, 16, UIManager.getColor( "InternalFrame.iconColor" ) );
|
||||
public FlatInternalFrameRestoreIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
Path2D r1 = FlatUIUtils.createRectangle( 5, 3, 8, 8, 1 );
|
||||
Path2D r2 = FlatUIUtils.createRectangle( 3, 5, 8, 8, 1 );
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( c.getForeground() );
|
||||
|
||||
int x = (width / 2) - 4;
|
||||
int y = (height / 2) - 4;
|
||||
Path2D r1 = FlatUIUtils.createRectangle( x + 1, y - 1, 8, 8, 1 );
|
||||
Path2D r2 = FlatUIUtils.createRectangle( x - 1, y + 1, 8, 8, 1 );
|
||||
|
||||
Area area = new Area( r1 );
|
||||
area.subtract( new Area( new Rectangle2D.Float( 3, 5, 8, 8 ) ) );
|
||||
area.subtract( new Area( new Rectangle2D.Float( x - 1, y + 1, 8, 8 ) ) );
|
||||
g.fill( area );
|
||||
|
||||
g.fill( r2 );
|
||||
@@ -28,17 +28,18 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "arrow" icon for {@link javax.swing.JMenu}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Menu.icon.arrowColor Color
|
||||
* @uiDefault Menu.icon.disabledArrowColor Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault MenuItem.selectionType String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuArrowIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
|
||||
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
|
||||
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
|
||||
@@ -64,10 +65,15 @@ public class FlatMenuArrowIcon
|
||||
}
|
||||
}
|
||||
|
||||
private Color getArrowColor( Component c ) {
|
||||
if( c instanceof JMenu && ((JMenu)c).isSelected() )
|
||||
protected Color getArrowColor( Component c ) {
|
||||
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
|
||||
return selectionForeground;
|
||||
|
||||
return c.isEnabled() ? arrowColor : disabledArrowColor;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* Icon for {@link javax.swing.JRadioButton}.
|
||||
@@ -34,28 +34,28 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
public class FlatRadioButtonIcon
|
||||
extends FlatCheckBoxIcon
|
||||
{
|
||||
protected final int centerDiameter = FlatUIUtils.getUIInt( "RadioButton.icon.centerDiameter", 8 );
|
||||
protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
|
||||
|
||||
@Override
|
||||
protected void paintFocusBorder( Graphics2D g2 ) {
|
||||
protected void paintFocusBorder( Component c, Graphics2D g ) {
|
||||
// the outline focus border is painted outside of the icon
|
||||
int wh = ICON_SIZE + (focusWidth * 2);
|
||||
g2.fillOval( -focusWidth, -focusWidth, wh, wh );
|
||||
g.fillOval( -focusWidth, -focusWidth, wh, wh );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder( Graphics2D g2 ) {
|
||||
g2.fillOval( 0, 0, 15, 15 );
|
||||
protected void paintBorder( Component c, Graphics2D g ) {
|
||||
g.fillOval( 0, 0, 15, 15 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics2D g2 ) {
|
||||
g2.fillOval( 1, 1, 13, 13 );
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
g.fillOval( 1, 1, 13, 13 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintCheckmark( Graphics2D g2 ) {
|
||||
protected void paintCheckmark( Component c, Graphics2D g ) {
|
||||
float xy = (ICON_SIZE - centerDiameter) / 2f;
|
||||
g2.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
|
||||
g.fill( new Ellipse2D.Float( xy, xy, centerDiameter, centerDiameter ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "close" icon for closable tabs in {@link javax.swing.JTabbedPane}.
|
||||
*
|
||||
* @uiDefault TabbedPane.closeSize Dimension
|
||||
* @uiDefault TabbedPane.closeArc int
|
||||
* @uiDefault TabbedPane.closeCrossPlainSize float
|
||||
* @uiDefault TabbedPane.closeCrossFilledSize float
|
||||
* @uiDefault TabbedPane.closeCrossLineWidth float
|
||||
* @uiDefault TabbedPane.closeBackground Color
|
||||
* @uiDefault TabbedPane.closeForeground Color
|
||||
* @uiDefault TabbedPane.closeHoverBackground Color
|
||||
* @uiDefault TabbedPane.closeHoverForeground Color
|
||||
* @uiDefault TabbedPane.closePressedBackground Color
|
||||
* @uiDefault TabbedPane.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTabbedPaneCloseIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected final Dimension size = UIManager.getDimension( "TabbedPane.closeSize" );
|
||||
protected final int arc = UIManager.getInt( "TabbedPane.closeArc" );
|
||||
protected final float crossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
|
||||
protected final float crossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", crossPlainSize );
|
||||
protected final float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
|
||||
protected final Color background = UIManager.getColor( "TabbedPane.closeBackground" );
|
||||
protected final Color foreground = UIManager.getColor( "TabbedPane.closeForeground" );
|
||||
protected final Color hoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
|
||||
protected final Color hoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
|
||||
protected final Color pressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
|
||||
protected final Color pressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
|
||||
|
||||
public FlatTabbedPaneCloseIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
// paint background
|
||||
Color bg = FlatButtonUI.buttonStateColor( c, background, null, null, hoverBackground, pressedBackground );
|
||||
if( bg != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) );
|
||||
g.fillRoundRect( (width - size.width) / 2, (height - size.height) / 2,
|
||||
size.width, size.height, arc, arc );
|
||||
}
|
||||
|
||||
// set cross color
|
||||
Color fg = FlatButtonUI.buttonStateColor( c, foreground, null, null, hoverForeground, pressedForeground );
|
||||
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
|
||||
|
||||
float mx = width / 2;
|
||||
float my = height / 2;
|
||||
float r = ((bg != null) ? crossFilledSize : crossPlainSize) / 2;
|
||||
|
||||
// paint cross
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Line2D.Float( mx - r, my - r, mx + r, my + r ), false );
|
||||
path.append( new Line2D.Float( mx - r, my + r, mx + r, my - r ), false );
|
||||
g.setStroke( new BasicStroke( closeCrossLineWidth ) );
|
||||
g.draw( path );
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
/**
|
||||
* "collapsed" icon for {@link javax.swing.JTree}.
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Tree.icon.collapsedColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -41,7 +41,7 @@ public class FlatTreeCollapsedIcon
|
||||
|
||||
FlatTreeCollapsedIcon( Color color ) {
|
||||
super( 11, 11, color );
|
||||
chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
|
||||
chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Base class for window icons.
|
||||
*
|
||||
* @uiDefault TitlePane.buttonSize Dimension
|
||||
* @uiDefault TitlePane.buttonHoverBackground Color
|
||||
* @uiDefault TitlePane.buttonPressedBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public abstract class FlatWindowAbstractIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
private final Color hoverBackground;
|
||||
private final Color pressedBackground;
|
||||
|
||||
public FlatWindowAbstractIcon() {
|
||||
this( UIManager.getDimension( "TitlePane.buttonSize" ),
|
||||
UIManager.getColor( "TitlePane.buttonHoverBackground" ),
|
||||
UIManager.getColor( "TitlePane.buttonPressedBackground" ) );
|
||||
}
|
||||
|
||||
public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) {
|
||||
super( size.width, size.height, null );
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( getForeground( c ) );
|
||||
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
|
||||
}
|
||||
|
||||
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||
if( background != null ) {
|
||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
}
|
||||
}
|
||||
|
||||
protected Color getForeground( Component c ) {
|
||||
return c.getForeground();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
|
||||
/**
|
||||
* "close" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @uiDefault TitlePane.closeHoverBackground Color
|
||||
* @uiDefault TitlePane.closePressedBackground Color
|
||||
* @uiDefault TitlePane.closeHoverForeground Color
|
||||
* @uiDefault TitlePane.closePressedForeground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowCloseIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" );
|
||||
private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" );
|
||||
|
||||
public FlatWindowCloseIcon() {
|
||||
super( UIManager.getDimension( "TitlePane.buttonSize" ),
|
||||
UIManager.getColor( "TitlePane.closeHoverBackground" ),
|
||||
UIManager.getColor( "TitlePane.closePressedBackground" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int ix2 = ix + iwh - 1;
|
||||
int iy2 = iy + iwh - 1;
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Line2D.Float( ix, iy, ix2, iy2 ), false );
|
||||
path.append( new Line2D.Float( ix, iy2, ix2, iy ), false );
|
||||
g.setStroke( new BasicStroke( thickness ) );
|
||||
g.draw( path );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getForeground( Component c ) {
|
||||
return FlatButtonUI.buttonStateColor( c, c.getForeground(), null, null, hoverForeground, pressedForeground );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
/**
|
||||
* "iconify" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowIconifyIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowIconifyIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iw = (int) (10 * scaleFactor);
|
||||
int ih = (int) scaleFactor;
|
||||
int ix = x + ((width - iw) / 2);
|
||||
int iy = y + ((height - ih) / 2);
|
||||
|
||||
g.fillRect( ix, iy, iw, ih );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "maximize" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowMaximizeIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowMaximizeIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
g.fill( FlatUIUtils.createRectangle( ix, iy, iwh, iwh, thickness ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.icons;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "restore" icon for windows (frames and dialogs).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatWindowRestoreIcon
|
||||
extends FlatWindowAbstractIcon
|
||||
{
|
||||
public FlatWindowRestoreIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
int iwh = (int) (10 * scaleFactor);
|
||||
int ix = x + ((width - iwh) / 2);
|
||||
int iy = y + ((height - iwh) / 2);
|
||||
int thickness = (int) scaleFactor;
|
||||
|
||||
int rwh = (int) (8 * scaleFactor);
|
||||
int ro2 = iwh - rwh;
|
||||
|
||||
Path2D r1 = FlatUIUtils.createRectangle( ix + ro2, iy, rwh, rwh, thickness );
|
||||
Path2D r2 = FlatUIUtils.createRectangle( ix, iy + ro2, rwh, rwh, thickness );
|
||||
|
||||
Area area = new Area( r1 );
|
||||
area.subtract( new Area( new Rectangle2D.Float( ix, iy + ro2, rwh, rwh ) ) );
|
||||
g.fill( area );
|
||||
|
||||
g.fill( r2 );
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
@@ -26,6 +27,7 @@ import java.awt.Shape;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicArrowButton;
|
||||
|
||||
@@ -40,33 +42,40 @@ public class FlatArrowButton
|
||||
{
|
||||
public static final int DEFAULT_ARROW_WIDTH = 8;
|
||||
|
||||
private final boolean chevron;
|
||||
private final Color foreground;
|
||||
private final Color disabledForeground;
|
||||
private final Color hoverForeground;
|
||||
private final Color hoverBackground;
|
||||
protected final boolean chevron;
|
||||
protected final Color foreground;
|
||||
protected final Color disabledForeground;
|
||||
protected final Color hoverForeground;
|
||||
protected final Color hoverBackground;
|
||||
protected final Color pressedForeground;
|
||||
protected final Color pressedBackground;
|
||||
|
||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||
private int xOffset = 0;
|
||||
private int yOffset = 0;
|
||||
|
||||
private boolean hover;
|
||||
private boolean pressed;
|
||||
|
||||
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground )
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
|
||||
|
||||
this.chevron = "chevron".equals( type );
|
||||
this.chevron = FlatUIUtils.isChevron( type );
|
||||
this.foreground = foreground;
|
||||
this.disabledForeground = disabledForeground;
|
||||
this.hoverForeground = hoverForeground;
|
||||
this.hoverBackground = hoverBackground;
|
||||
this.pressedForeground = pressedForeground;
|
||||
this.pressedBackground = pressedBackground;
|
||||
|
||||
setOpaque( false );
|
||||
setBorder( null );
|
||||
|
||||
if( hoverForeground != null || hoverBackground != null ) {
|
||||
if( hoverForeground != null || hoverBackground != null ||
|
||||
pressedForeground != null || pressedBackground != null )
|
||||
{
|
||||
addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
@@ -79,6 +88,18 @@ public class FlatArrowButton
|
||||
hover = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
pressed = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
pressed = false;
|
||||
repaint();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -95,6 +116,10 @@ public class FlatArrowButton
|
||||
return hover;
|
||||
}
|
||||
|
||||
protected boolean isPressed() {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public int getXOffset() {
|
||||
return xOffset;
|
||||
}
|
||||
@@ -111,6 +136,14 @@ public class FlatArrowButton
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return background;
|
||||
}
|
||||
|
||||
protected Color deriveForeground( Color foreground ) {
|
||||
return FlatUIUtils.deriveColor( foreground, this.foreground );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return scale( super.getPreferredSize() );
|
||||
@@ -123,47 +156,78 @@ public class FlatArrowButton
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
boolean enabled = isEnabled();
|
||||
// paint hover or pressed background
|
||||
if( isEnabled() ) {
|
||||
Color background = (pressedBackground != null && isPressed())
|
||||
? pressedBackground
|
||||
: (hoverBackground != null && isHover()
|
||||
? hoverBackground
|
||||
: null);
|
||||
|
||||
// paint hover background
|
||||
if( enabled && isHover() && hoverBackground != null ) {
|
||||
g.setColor( hoverBackground );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
if( background != null ) {
|
||||
g.setColor( deriveBackground( background ) );
|
||||
paintBackground( (Graphics2D) g );
|
||||
}
|
||||
}
|
||||
|
||||
// paint arrow
|
||||
g.setColor( deriveForeground( isEnabled()
|
||||
? (pressedForeground != null && isPressed()
|
||||
? pressedForeground
|
||||
: (hoverForeground != null && isHover()
|
||||
? hoverForeground
|
||||
: foreground))
|
||||
: disabledForeground ) );
|
||||
paintArrow( (Graphics2D) g );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics2D g ) {
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
protected void paintArrow( Graphics2D g ) {
|
||||
int direction = getDirection();
|
||||
boolean vert = (direction == NORTH || direction == SOUTH);
|
||||
|
||||
// compute width/height
|
||||
int w = scale( arrowWidth + (chevron ? 0 : 1) );
|
||||
int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) );
|
||||
|
||||
// rotate width/height
|
||||
int rw = vert ? w : h;
|
||||
int rh = vert ? h : w;
|
||||
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
|
||||
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
|
||||
|
||||
// optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane)
|
||||
if( x + rw >= width && x > 0 )
|
||||
x--;
|
||||
if( y + rh >= height && y > 0 )
|
||||
y--;
|
||||
// chevron lines end 1px outside of width/height
|
||||
if( chevron ) {
|
||||
// add 1px to width/height for position calculation only
|
||||
rw++;
|
||||
rh++;
|
||||
}
|
||||
|
||||
int x = Math.round( (getWidth() - rw) / 2f + scale( (float) xOffset ) );
|
||||
int y = Math.round( (getHeight() - rh) / 2f + scale( (float) yOffset ) );
|
||||
|
||||
// move arrow for round borders
|
||||
Container parent = getParent();
|
||||
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
|
||||
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
|
||||
|
||||
// paint arrow
|
||||
g.setColor( enabled
|
||||
? (isHover() && hoverForeground != null ? hoverForeground : foreground)
|
||||
: disabledForeground );
|
||||
g.translate( x, y );
|
||||
/*debug
|
||||
debugPaint( g, vert, rw, rh );
|
||||
debug*/
|
||||
Shape arrowShape = createArrowShape( direction, chevron, w, h );
|
||||
if( chevron ) {
|
||||
g2.setStroke( new BasicStroke( scale( 1f ) ) );
|
||||
g2.draw( arrowShape );
|
||||
g.setStroke( new BasicStroke( scale( 1f ) ) );
|
||||
g.draw( arrowShape );
|
||||
} else {
|
||||
// triangle
|
||||
g2.fill( arrowShape );
|
||||
g.fill( arrowShape );
|
||||
}
|
||||
g.translate( -x, -y );
|
||||
}
|
||||
@@ -177,4 +241,22 @@ public class FlatArrowButton
|
||||
default: return new Path2D.Float();
|
||||
}
|
||||
}
|
||||
|
||||
/*debug
|
||||
private void debugPaint( Graphics g, boolean vert, int w, int h ) {
|
||||
Color oldColor = g.getColor();
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( 0, 0, w - 1, h - 1 );
|
||||
|
||||
int xy1 = -2;
|
||||
int xy2 = h + 1;
|
||||
for( int i = 0; i < 20; i++ ) {
|
||||
g.drawRect( vert ? 0 : xy1, vert ? xy1 : 0, 0, 0 );
|
||||
g.drawRect( vert ? 0 : xy2, vert ? xy2 : 0, 0, 0 );
|
||||
xy1 -= 2;
|
||||
xy2 += 2;
|
||||
}
|
||||
g.setColor( oldColor );
|
||||
}
|
||||
debug*/
|
||||
}
|
||||
|
||||
@@ -35,24 +35,31 @@ import javax.swing.JViewport;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicBorders;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
|
||||
/**
|
||||
* Border for various components (e.g. {@link javax.swing.JTextField}).
|
||||
*
|
||||
* There is empty space around the component border, if Component.focusWidth is greater than zero,
|
||||
* which is used to paint focus border.
|
||||
* which is used to paint outer focus border.
|
||||
*
|
||||
* Because there is empty space (if focus border is not painted),
|
||||
* Because there is empty space (if outer focus border is not painted),
|
||||
* UI delegates that use this border (or subclasses) must invoke
|
||||
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Component.focusedBorderColor Color
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Component.focusedBorderColor Color
|
||||
*
|
||||
* @uiDefault Component.error.borderColor Color
|
||||
* @uiDefault Component.error.focusedBorderColor Color
|
||||
* @uiDefault Component.warning.borderColor Color
|
||||
* @uiDefault Component.warning.focusedBorderColor Color
|
||||
* @uiDefault Component.custom.borderColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -61,35 +68,79 @@ public class FlatBorder
|
||||
{
|
||||
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
|
||||
protected final float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 );
|
||||
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
|
||||
protected final Color borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
protected final Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
protected final Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
|
||||
|
||||
protected final Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" );
|
||||
protected final Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
|
||||
protected final Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
|
||||
protected final Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
|
||||
protected final Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float focusWidth = isCellEditor ? 0 : getFocusWidth();
|
||||
float borderWidth = getBorderWidth( c );
|
||||
float arc = isCellEditor ? 0 : getArc( c );
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float borderWidth = scale( (float) getBorderWidth( c ) );
|
||||
float arc = scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
|
||||
if( isFocused( c ) ) {
|
||||
g2.setColor( getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height, focusWidth,
|
||||
getLineWidth() + scale( innerFocusWidth ), arc );
|
||||
// paint outer border
|
||||
if( outlineColor != null || isFocused( c ) ) {
|
||||
float innerWidth = !isCellEditor( c ) && !(c instanceof JScrollPane)
|
||||
? (outlineColor != null ? innerOutlineWidth : getInnerFocusWidth( c ))
|
||||
: 0;
|
||||
|
||||
if( focusWidth > 0 || innerWidth > 0 ) {
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height,
|
||||
focusWidth, borderWidth + scale( innerWidth ), arc );
|
||||
}
|
||||
}
|
||||
|
||||
g2.setPaint( getBorderColor( c ) );
|
||||
// paint border
|
||||
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the outline color of the component border specified in client property
|
||||
* {@link FlatClientProperties#OUTLINE}.
|
||||
*/
|
||||
protected Color getOutlineColor( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return null;
|
||||
|
||||
Object outline = ((JComponent)c).getClientProperty( FlatClientProperties.OUTLINE );
|
||||
if( outline instanceof String ) {
|
||||
switch( (String) outline ) {
|
||||
case FlatClientProperties.OUTLINE_ERROR:
|
||||
return isFocused( c ) ? errorFocusedBorderColor : errorBorderColor;
|
||||
|
||||
case FlatClientProperties.OUTLINE_WARNING:
|
||||
return isFocused( c ) ? warningFocusedBorderColor : warningBorderColor;
|
||||
}
|
||||
} else if( outline instanceof Color ) {
|
||||
Color color = (Color) outline;
|
||||
// use color functions to compute color for unfocused state
|
||||
if( !isFocused( c ) && customBorderColor instanceof DerivedColor )
|
||||
color = ((DerivedColor)customBorderColor).derive( color );
|
||||
return color;
|
||||
} else if( outline instanceof Color[] && ((Color[])outline).length >= 2 )
|
||||
return ((Color[])outline)[isFocused( c ) ? 0 : 1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return focusColor;
|
||||
}
|
||||
@@ -109,7 +160,7 @@ public class FlatBorder
|
||||
return false;
|
||||
}
|
||||
|
||||
return c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable());
|
||||
return c.isEnabled();
|
||||
}
|
||||
|
||||
protected boolean isFocused( Component c ) {
|
||||
@@ -117,7 +168,7 @@ public class FlatBorder
|
||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
||||
Component view = (viewport != null) ? viewport.getView() : null;
|
||||
if( view != null ) {
|
||||
if( view.hasFocus() )
|
||||
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
||||
return true;
|
||||
|
||||
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
||||
@@ -131,49 +182,88 @@ public class FlatBorder
|
||||
return false;
|
||||
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
|
||||
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? editorComponent.hasFocus() : false;
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
} else if( c instanceof JSpinner ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return true;
|
||||
|
||||
JComponent editor = ((JSpinner)c).getEditor();
|
||||
if( editor instanceof JSpinner.DefaultEditor ) {
|
||||
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
||||
if( textField != null )
|
||||
return textField.hasFocus();
|
||||
return FlatUIUtils.isPermanentFocusOwner( textField );
|
||||
}
|
||||
return false;
|
||||
} else
|
||||
return c.hasFocus();
|
||||
return FlatUIUtils.isPermanentFocusOwner( c );
|
||||
}
|
||||
|
||||
protected boolean isTableCellEditor( Component c ) {
|
||||
return FlatUIUtils.isTableCellEditor( c );
|
||||
protected boolean isCellEditor( Component c ) {
|
||||
return FlatUIUtils.isCellEditor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
boolean isCellEditor = isTableCellEditor( c );
|
||||
float ow = (isCellEditor ? 0 : getFocusWidth()) + getLineWidth();
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float ow = focusWidth + scale( (float) getLineWidth( c ) );
|
||||
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
insets.top = Math.round( scale( (float) insets.top ) + ow );
|
||||
insets.left = Math.round( scale( (float) insets.left ) + ow );
|
||||
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
|
||||
insets.right = Math.round( scale( (float) insets.right ) + ow );
|
||||
|
||||
if( isCellEditor( c ) ) {
|
||||
// remove top and bottom insets if used as cell editor
|
||||
insets.top = insets.bottom = 0;
|
||||
|
||||
// remove right/left insets to avoid that text is truncated (e.g. in file chooser)
|
||||
if( c.getComponentOrientation().isLeftToRight() )
|
||||
insets.right = 0;
|
||||
else
|
||||
insets.left = 0;
|
||||
}
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
protected float getFocusWidth() {
|
||||
return scale( (float) focusWidth );
|
||||
/**
|
||||
* Returns the (unscaled) thickness of the outer focus border.
|
||||
*/
|
||||
protected int getFocusWidth( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
return focusWidth;
|
||||
}
|
||||
|
||||
protected float getLineWidth() {
|
||||
return scale( 1f );
|
||||
/**
|
||||
* Returns the (unscaled) thickness of the inner focus border.
|
||||
*/
|
||||
protected float getInnerFocusWidth( Component c ) {
|
||||
return innerFocusWidth;
|
||||
}
|
||||
|
||||
protected float getBorderWidth( Component c ) {
|
||||
return getLineWidth();
|
||||
/**
|
||||
* Returns the (unscaled) line thickness used to compute the border insets.
|
||||
* This may be different to {@link #getBorderWidth}.
|
||||
*/
|
||||
protected int getLineWidth( Component c ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected float getArc( Component c ) {
|
||||
/**
|
||||
* Returns the (unscaled) line thickness used to paint the border.
|
||||
* This may be different to {@link #getLineWidth}.
|
||||
*/
|
||||
protected int getBorderWidth( Component c ) {
|
||||
return getLineWidth( c );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (unscaled) arc diameter of the border.
|
||||
*/
|
||||
protected int getArc( Component c ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JButton}.
|
||||
@@ -42,7 +42,11 @@ import javax.swing.plaf.UIResource;
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
* @uiDefault Button.default.focusedBorderColor Color
|
||||
* @uiDefault Button.default.focusColor Color
|
||||
* @uiDefault Button.borderWidth int
|
||||
* @uiDefault Button.default.borderWidth int
|
||||
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||
* @uiDefault Button.toolbar.margin Insets
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -60,13 +64,20 @@ public class FlatButtonBorder
|
||||
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
|
||||
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
||||
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
||||
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
protected final int arc = UIManager.getInt( "Button.arc" );
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( FlatButtonUI.isContentAreaFilled( c ) && !FlatButtonUI.isHelpButton( c ) && !FlatToggleButtonUI.isUnderlineButton( c ) )
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
if( FlatButtonUI.isContentAreaFilled( c ) &&
|
||||
!FlatButtonUI.isToolBarButton( c ) &&
|
||||
!FlatButtonUI.isHelpButton( c ) &&
|
||||
!FlatToggleButtonUI.isTabButton( c ) )
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,6 +85,11 @@ public class FlatButtonBorder
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFocused( Component c ) {
|
||||
return FlatButtonUI.isFocusPainted( c ) && super.isFocused( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Paint getBorderColor( Component c ) {
|
||||
boolean def = FlatButtonUI.isDefaultButton( c );
|
||||
@@ -95,22 +111,50 @@ public class FlatButtonBorder
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
if( FlatButtonUI.isToolBarButton( c ) ) {
|
||||
// In toolbars, use button margin only if explicitly set.
|
||||
// Otherwise use toolbar margin specified in UI defaults.
|
||||
Insets margin = (c instanceof AbstractButton)
|
||||
? ((AbstractButton)c).getMargin()
|
||||
: null;
|
||||
|
||||
// use smaller left and right insets for icon-only buttons (so that they are square)
|
||||
if( FlatButtonUI.isIconOnlyButton( c ) && ((JButton)c).getMargin() instanceof UIResource )
|
||||
insets.left = insets.right = Math.min( insets.top, insets.bottom );
|
||||
FlatUIUtils.setInsets( insets, UIScale.scale( FlatUIUtils.addInsets( toolbarSpacingInsets,
|
||||
(margin != null && !(margin instanceof UIResource)) ? margin : toolbarMargin ) ) );
|
||||
} else {
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
|
||||
// use smaller left and right insets for icon-only or single-character buttons (so that they are square)
|
||||
if( FlatButtonUI.isIconOnlyOrSingleCharacterButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
|
||||
insets.left = insets.right = Math.min( insets.top, insets.bottom );
|
||||
}
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? scale( (float) defaultBorderWidth ) : super.getBorderWidth( c );
|
||||
protected int getFocusWidth( Component c ) {
|
||||
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getArc( Component c ) {
|
||||
return FlatButtonUI.isSquareButton( c ) ? 0 : scale( (float) arc );
|
||||
protected float getInnerFocusWidth( Component c ) {
|
||||
return buttonInnerFocusWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBorderWidth( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
switch( FlatButtonUI.getButtonType( c ) ) {
|
||||
case FlatButtonUI.TYPE_SQUARE: return 0;
|
||||
case FlatButtonUI.TYPE_ROUND_RECT: return Short.MAX_VALUE;
|
||||
default: return arc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,19 +26,22 @@ import java.awt.FontMetrics;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -57,8 +60,6 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatButtonUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Button.arc int
|
||||
* @uiDefault Button.minimumWidth int
|
||||
* @uiDefault Button.iconTextGap int
|
||||
* @uiDefault Button.startBackground Color optional; if set, a gradient paint is used and Button.background is ignored
|
||||
@@ -66,7 +67,11 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.focusedBackground Color optional
|
||||
* @uiDefault Button.hoverBackground Color optional
|
||||
* @uiDefault Button.pressedBackground Color optional
|
||||
* @uiDefault Button.selectedBackground Color
|
||||
* @uiDefault Button.selectedForeground Color
|
||||
* @uiDefault Button.disabledBackground Color optional
|
||||
* @uiDefault Button.disabledText Color
|
||||
* @uiDefault Button.disabledSelectedBackground Color
|
||||
* @uiDefault Button.default.background Color
|
||||
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
|
||||
* @uiDefault Button.default.endBackground Color optional; if set, a gradient paint is used
|
||||
@@ -79,25 +84,32 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.shadowWidth int default is 2
|
||||
* @uiDefault Button.shadowColor Color optional
|
||||
* @uiDefault Button.default.shadowColor Color optional
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.toolbar.hoverBackground Color
|
||||
* @uiDefault Button.toolbar.pressedBackground Color
|
||||
* @uiDefault Button.toolbar.selectedBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatButtonUI
|
||||
extends BasicButtonUI
|
||||
{
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected int iconTextGap;
|
||||
|
||||
protected Color background;
|
||||
protected Color foreground;
|
||||
|
||||
protected Color startBackground;
|
||||
protected Color endBackground;
|
||||
protected Color focusedBackground;
|
||||
protected Color hoverBackground;
|
||||
protected Color pressedBackground;
|
||||
protected Color selectedBackground;
|
||||
protected Color selectedForeground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledText;
|
||||
protected Color disabledSelectedBackground;
|
||||
|
||||
protected Color defaultBackground;
|
||||
protected Color defaultEndBackground;
|
||||
@@ -111,19 +123,17 @@ public class FlatButtonUI
|
||||
protected Color shadowColor;
|
||||
protected Color defaultShadowColor;
|
||||
|
||||
protected Insets toolbarSpacingInsets;
|
||||
protected Color toolbarHoverBackground;
|
||||
protected Color toolbarPressedBackground;
|
||||
protected Color toolbarSelectedBackground;
|
||||
|
||||
private Icon helpButtonIcon;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatButtonUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatButtonUI.class, FlatButtonUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,17 +143,22 @@ public class FlatButtonUI
|
||||
if( !defaults_initialized ) {
|
||||
String prefix = getPropertyPrefix();
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Button.arc" );
|
||||
minimumWidth = UIManager.getInt( prefix + "minimumWidth" );
|
||||
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
|
||||
|
||||
background = UIManager.getColor( prefix + "background" );
|
||||
foreground = UIManager.getColor( prefix + "foreground" );
|
||||
|
||||
startBackground = UIManager.getColor( prefix + "startBackground" );
|
||||
endBackground = UIManager.getColor( prefix + "endBackground" );
|
||||
focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
|
||||
hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
|
||||
pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
|
||||
selectedBackground = UIManager.getColor( prefix + "selectedBackground" );
|
||||
selectedForeground = UIManager.getColor( prefix + "selectedForeground" );
|
||||
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
|
||||
|
||||
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
|
||||
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
|
||||
@@ -163,8 +178,10 @@ public class FlatButtonUI
|
||||
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
|
||||
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
|
||||
|
||||
toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
|
||||
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
|
||||
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
|
||||
|
||||
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
|
||||
|
||||
@@ -180,7 +197,7 @@ public class FlatButtonUI
|
||||
LookAndFeel.installProperty( b, "opaque", false );
|
||||
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
|
||||
|
||||
MigLayoutVisualPadding.install( b, focusWidth );
|
||||
MigLayoutVisualPadding.install( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,34 +208,81 @@ public class FlatButtonUI
|
||||
defaults_initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicButtonListener createButtonListener( AbstractButton b ) {
|
||||
return new FlatButtonListener( b );
|
||||
}
|
||||
|
||||
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case SQUARE_SIZE:
|
||||
case MINIMUM_WIDTH:
|
||||
case MINIMUM_HEIGHT:
|
||||
b.revalidate();
|
||||
break;
|
||||
|
||||
case BUTTON_TYPE:
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isContentAreaFilled( Component c ) {
|
||||
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
|
||||
}
|
||||
|
||||
public static boolean isFocusPainted( Component c ) {
|
||||
return !(c instanceof AbstractButton) || ((AbstractButton)c).isFocusPainted();
|
||||
}
|
||||
|
||||
static boolean isDefaultButton( Component c ) {
|
||||
return c instanceof JButton && ((JButton)c).isDefaultButton();
|
||||
}
|
||||
|
||||
static boolean isIconOnlyButton( Component c ) {
|
||||
if( !(c instanceof JButton) )
|
||||
/**
|
||||
* Returns true if the button has an icon but no text,
|
||||
* or it it does not have an icon and the text is either "..." or one character.
|
||||
*/
|
||||
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
|
||||
if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
|
||||
return false;
|
||||
|
||||
Icon icon = ((JButton)c).getIcon();
|
||||
String text = ((JButton)c).getText();
|
||||
Icon icon = ((AbstractButton)c).getIcon();
|
||||
String text = ((AbstractButton)c).getText();
|
||||
return (icon != null && (text == null || text.isEmpty())) ||
|
||||
(icon == null && text != null && ("...".equals( text ) || text.length() == 1));
|
||||
(icon == null && text != null &&
|
||||
("...".equals( text ) ||
|
||||
text.length() == 1 ||
|
||||
(text.length() == 2 && Character.isSurrogatePair( text.charAt( 0 ), text.charAt( 1 ) ))));
|
||||
}
|
||||
|
||||
static boolean isSquareButton( Component c ) {
|
||||
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_SQUARE );
|
||||
static final int TYPE_OTHER = -1;
|
||||
static final int TYPE_SQUARE = 0;
|
||||
static final int TYPE_ROUND_RECT = 1;
|
||||
|
||||
static int getButtonType( Component c ) {
|
||||
if( !(c instanceof AbstractButton) )
|
||||
return TYPE_OTHER;
|
||||
|
||||
Object value = ((AbstractButton)c).getClientProperty( BUTTON_TYPE );
|
||||
if( !(value instanceof String) )
|
||||
return TYPE_OTHER;
|
||||
|
||||
switch( (String) value ) {
|
||||
case BUTTON_TYPE_SQUARE: return TYPE_SQUARE;
|
||||
case BUTTON_TYPE_ROUND_RECT: return TYPE_ROUND_RECT;
|
||||
default: return TYPE_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isHelpButton( Component c ) {
|
||||
return c instanceof JButton && clientPropertyEquals( (JButton) c, BUTTON_TYPE, BUTTON_TYPE_HELP );
|
||||
}
|
||||
|
||||
static boolean isToolBarButton( JComponent c ) {
|
||||
return c.getParent() instanceof JToolBar;
|
||||
static boolean isToolBarButton( Component c ) {
|
||||
return c.getParent() instanceof JToolBar ||
|
||||
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,39 +304,61 @@ public class FlatButtonUI
|
||||
|
||||
protected void paintBackground( Graphics g, JComponent c ) {
|
||||
Color background = getBackground( c );
|
||||
if( background != null ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
if( background == null )
|
||||
return;
|
||||
|
||||
Border border = c.getBorder();
|
||||
float focusWidth = (border instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||
float arc = ((border instanceof FlatButtonBorder && !isSquareButton( c )) || isToolBarButton( c ))
|
||||
? scale( (float) this.arc ) : 0;
|
||||
boolean def = isDefaultButton( c );
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
// paint shadow
|
||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||
if( shadowColor != null && shadowWidth > 0 && focusWidth > 0 && !c.hasFocus() && c.isEnabled() ) {
|
||||
g2.setColor( shadowColor );
|
||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||
c.getWidth() - focusWidth * 2, c.getHeight() - focusWidth * 2, arc, arc ) );
|
||||
}
|
||||
boolean isToolBarButton = isToolBarButton( c );
|
||||
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// paint background
|
||||
Color startBg = def ? defaultBackground : startBackground;
|
||||
Color endBg = def ? defaultEndBackground : endBackground;
|
||||
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
|
||||
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, c.getHeight(), endBg ) );
|
||||
else
|
||||
FlatUIUtils.setColor( g2, background, def ? defaultBackground : c.getBackground() );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
boolean def = isDefaultButton( c );
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
|
||||
if( isToolBarButton ) {
|
||||
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||
x += spacing.left;
|
||||
y += spacing.top;
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
}
|
||||
|
||||
// paint shadow
|
||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
|
||||
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) && c.isEnabled() )
|
||||
{
|
||||
g2.setColor( shadowColor );
|
||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
||||
}
|
||||
|
||||
// paint background
|
||||
Color startBg = def ? defaultBackground : startBackground;
|
||||
Color endBg = def ? defaultEndBackground : endBackground;
|
||||
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
|
||||
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
|
||||
else
|
||||
g2.setColor( FlatUIUtils.deriveColor( background, getBackgroundBase( c, def ) ) );
|
||||
|
||||
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
|
||||
if( isHelpButton( b ) )
|
||||
@@ -289,7 +375,7 @@ public class FlatButtonUI
|
||||
}
|
||||
}
|
||||
|
||||
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText );
|
||||
paintText( g, b, textRect, text, getForeground( b ) );
|
||||
}
|
||||
|
||||
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
|
||||
@@ -302,8 +388,19 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
protected Color getBackground( JComponent c ) {
|
||||
if( ((AbstractButton)c).isSelected() ) {
|
||||
// in toolbar use same colors for disabled and enabled because
|
||||
// we assume that toolbar icon is shown disabled
|
||||
boolean toolBarButton = isToolBarButton( c );
|
||||
return buttonStateColor( c,
|
||||
toolBarButton ? toolbarSelectedBackground : selectedBackground,
|
||||
toolBarButton ? toolbarSelectedBackground : disabledSelectedBackground,
|
||||
null, null,
|
||||
toolBarButton ? toolbarPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
if( !c.isEnabled() )
|
||||
return null;
|
||||
return disabledBackground;
|
||||
|
||||
// toolbar button
|
||||
if( isToolBarButton( c ) ) {
|
||||
@@ -313,19 +410,37 @@ public class FlatButtonUI
|
||||
if( model.isRollover() )
|
||||
return toolbarHoverBackground;
|
||||
|
||||
// use background of toolbar
|
||||
return c.getParent().getBackground();
|
||||
// use component background if explicitly set
|
||||
Color bg = c.getBackground();
|
||||
if( isCustomBackground( bg ) )
|
||||
return bg;
|
||||
|
||||
// do not paint background
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return buttonStateColor( c,
|
||||
def ? defaultBackground : c.getBackground(),
|
||||
getBackgroundBase( c, def ),
|
||||
null,
|
||||
def ? defaultFocusedBackground : focusedBackground,
|
||||
isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground),
|
||||
def ? defaultHoverBackground : hoverBackground,
|
||||
def ? defaultPressedBackground : pressedBackground );
|
||||
}
|
||||
|
||||
protected Color getBackgroundBase( JComponent c, boolean def ) {
|
||||
// use component background if explicitly set
|
||||
Color bg = c.getBackground();
|
||||
if( isCustomBackground( bg ) )
|
||||
return bg;
|
||||
|
||||
return def ? defaultBackground : bg;
|
||||
}
|
||||
|
||||
protected boolean isCustomBackground( Color bg ) {
|
||||
return bg != background && (startBackground == null || bg != startBackground);
|
||||
}
|
||||
|
||||
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
|
||||
Color focusedColor, Color hoverColor, Color pressedColor )
|
||||
{
|
||||
@@ -340,15 +455,30 @@ public class FlatButtonUI
|
||||
if( hoverColor != null && b != null && b.getModel().isRollover() )
|
||||
return hoverColor;
|
||||
|
||||
if( focusedColor != null && c.hasFocus() )
|
||||
if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return focusedColor;
|
||||
|
||||
return enabledColor;
|
||||
}
|
||||
|
||||
protected Color getForeground( JComponent c ) {
|
||||
if( !c.isEnabled() )
|
||||
return disabledText;
|
||||
|
||||
if( ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
|
||||
return selectedForeground;
|
||||
|
||||
// use component foreground if explicitly set
|
||||
Color fg = c.getForeground();
|
||||
if( isCustomForeground( fg ) )
|
||||
return fg;
|
||||
|
||||
boolean def = isDefaultButton( c );
|
||||
return def ? defaultForeground : c.getForeground();
|
||||
return def ? defaultForeground : fg;
|
||||
}
|
||||
|
||||
protected boolean isCustomForeground( Color fg ) {
|
||||
return fg != foreground;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -357,14 +487,43 @@ public class FlatButtonUI
|
||||
return new Dimension( helpButtonIcon.getIconWidth(), helpButtonIcon.getIconHeight() );
|
||||
|
||||
Dimension prefSize = super.getPreferredSize( c );
|
||||
if( prefSize == null )
|
||||
return null;
|
||||
|
||||
// make button square if it is a icon-only button
|
||||
// or apply minimum width, if not in toolbar and not a icon-only button
|
||||
if( isIconOnlyButton( c ) )
|
||||
// make square or apply minimum width/height
|
||||
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
|
||||
if( clientPropertyBoolean( c, SQUARE_SIZE, false ) ) {
|
||||
// make button square (increase width or height so that they are equal)
|
||||
prefSize.width = prefSize.height = Math.max( prefSize.width, prefSize.height );
|
||||
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
|
||||
// make single-character-no-icon button square (increase width)
|
||||
prefSize.width = Math.max( prefSize.width, prefSize.height );
|
||||
else if( !isToolBarButton( c ) )
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) + (focusWidth * 2) ) );
|
||||
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
||||
// apply minimum width/height
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) );
|
||||
}
|
||||
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
//---- class FlatButtonListener -------------------------------------------
|
||||
|
||||
protected class FlatButtonListener
|
||||
extends BasicButtonListener
|
||||
{
|
||||
private final AbstractButton b;
|
||||
|
||||
protected FlatButtonListener( AbstractButton b ) {
|
||||
super( b );
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatButtonUI.this.propertyChange( b, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
130
flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
Normal file
130
flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
/**
|
||||
* Caret that can select all text on focus gained.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatCaret
|
||||
extends DefaultCaret
|
||||
implements UIResource
|
||||
{
|
||||
private final String selectAllOnFocusPolicy;
|
||||
private final boolean selectAllOnMouseClick;
|
||||
|
||||
private boolean wasFocused;
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
|
||||
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
this.selectAllOnMouseClick = selectAllOnMouseClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install( JTextComponent c ) {
|
||||
super.install( c );
|
||||
|
||||
// the dot and mark are lost when switching LaF
|
||||
// --> move dot to end of text so that all text may be selected when it gains focus
|
||||
Document doc = c.getDocument();
|
||||
if( doc != null && getDot() == 0 && getMark() == 0 ) {
|
||||
int length = doc.getLength();
|
||||
if( length > 0 )
|
||||
setDot( length );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
selectAllOnFocusGained();
|
||||
wasTemporaryLost = false;
|
||||
wasFocused = true;
|
||||
|
||||
super.focusGained( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
wasTemporaryLost = e.isTemporary();
|
||||
super.focusLost( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
isMousePressed = true;
|
||||
super.mousePressed( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isMousePressed = false;
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
protected void selectAllOnFocusGained() {
|
||||
JTextComponent c = getComponent();
|
||||
Document doc = c.getDocument();
|
||||
if( doc == null || !c.isEnabled() || !c.isEditable() )
|
||||
return;
|
||||
|
||||
Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
|
||||
if( selectAllOnFocusPolicy == null )
|
||||
selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
|
||||
|
||||
if( SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
|
||||
return;
|
||||
|
||||
if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {
|
||||
// policy is "once" (or null or unknown)
|
||||
|
||||
// was already focused?
|
||||
if( wasFocused )
|
||||
return;
|
||||
|
||||
// check whether selection was modified before gaining focus
|
||||
int dot = getDot();
|
||||
int mark = getMark();
|
||||
if( dot != mark || dot != doc.getLength() )
|
||||
return;
|
||||
}
|
||||
|
||||
// select all
|
||||
if( c instanceof JFormattedTextField ) {
|
||||
EventQueue.invokeLater( () -> {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
} );
|
||||
} else {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
|
||||
@@ -27,29 +29,34 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
*
|
||||
* <!-- BasicCheckBoxMenuItemUI -->
|
||||
*
|
||||
* @uiDefault CheckBoxMenuItem.font Font
|
||||
* @uiDefault CheckBoxMenuItem.background Color
|
||||
* @uiDefault CheckBoxMenuItem.foreground Color
|
||||
* @uiDefault CheckBoxMenuItem.disabledForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionBackground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault CheckBoxMenuItem.border Border
|
||||
* @uiDefault CheckBoxMenuItem.borderPainted boolean
|
||||
* @uiDefault CheckBoxMenuItem.margin Insets
|
||||
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.checkIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.opaque boolean
|
||||
* @uiDefault CheckBoxMenuItem.evenHeight boolean
|
||||
* @uiDefault CheckBoxMenuItem.font Font
|
||||
* @uiDefault CheckBoxMenuItem.background Color
|
||||
* @uiDefault CheckBoxMenuItem.foreground Color
|
||||
* @uiDefault CheckBoxMenuItem.disabledForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionBackground Color
|
||||
* @uiDefault CheckBoxMenuItem.selectionForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
|
||||
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault CheckBoxMenuItem.border Border
|
||||
* @uiDefault CheckBoxMenuItem.borderPainted boolean
|
||||
* @uiDefault CheckBoxMenuItem.margin Insets
|
||||
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.checkIcon Icon
|
||||
* @uiDefault CheckBoxMenuItem.opaque boolean
|
||||
*
|
||||
* <!-- FlatCheckBoxMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatCheckBoxMenuItemUI
|
||||
extends BasicCheckBoxMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatCheckBoxMenuItemUI();
|
||||
}
|
||||
@@ -58,20 +65,30 @@ public class FlatCheckBoxMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
public class FlatCheckBoxUI
|
||||
extends FlatRadioButtonUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatCheckBoxUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, FlatCheckBoxUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicColorChooserUI;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JColorChooser}.
|
||||
@@ -43,21 +40,4 @@ public class FlatColorChooserUI
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatColorChooserUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
if( UIScale.getUserScaleFactor() != 1f ) {
|
||||
// temporary scale swatch sizes
|
||||
Dimension swatchSize = UIManager.getDimension( "ColorChooser.swatchesSwatchSize" );
|
||||
Dimension swatchSize2 = UIManager.getDimension( "ColorChooser.swatchesRecentSwatchSize" );
|
||||
UIManager.put( "ColorChooser.swatchesSwatchSize", UIScale.scale( swatchSize ) );
|
||||
UIManager.put( "ColorChooser.swatchesRecentSwatchSize", UIScale.scale( swatchSize2 ) );
|
||||
|
||||
super.installUI( c );
|
||||
|
||||
UIManager.put( "ColorChooser.swatchesSwatchSize", null );
|
||||
UIManager.put( "ColorChooser.swatchesRecentSwatchSize", null );
|
||||
} else
|
||||
super.installUI( c );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,24 +24,36 @@ import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ComboBoxEditor;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingConstants;
|
||||
@@ -54,6 +66,7 @@ import javax.swing.plaf.basic.BasicComboPopup;
|
||||
import javax.swing.plaf.basic.ComboPopup;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -70,9 +83,11 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatComboBoxUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.arc int
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault ComboBox.minimumWidth int
|
||||
* @uiDefault ComboBox.editorColumns int
|
||||
* @uiDefault ComboBox.maximumRowCount int
|
||||
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -84,14 +99,16 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault ComboBox.buttonArrowColor Color
|
||||
* @uiDefault ComboBox.buttonDisabledArrowColor Color
|
||||
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
||||
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatComboBoxUI
|
||||
extends BasicComboBoxUI
|
||||
{
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected int editorColumns;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
@@ -106,9 +123,11 @@ public class FlatComboBoxUI
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color buttonHoverArrowColor;
|
||||
protected Color buttonPressedArrowColor;
|
||||
|
||||
private MouseListener hoverListener;
|
||||
private boolean hover;
|
||||
protected boolean hover;
|
||||
protected boolean pressed;
|
||||
|
||||
private WeakReference<Component> lastRendererComponent;
|
||||
|
||||
@@ -120,13 +139,36 @@ public class FlatComboBoxUI
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
hoverListener = new FlatUIUtils.HoverListener( null, h -> {
|
||||
if( !comboBox.isEditable() ) {
|
||||
hover = h;
|
||||
if( arrowButton != null )
|
||||
hoverListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
hover = true;
|
||||
repaintArrowButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
hover = false;
|
||||
repaintArrowButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
pressed = true;
|
||||
repaintArrowButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
pressed = false;
|
||||
repaintArrowButton();
|
||||
}
|
||||
|
||||
private void repaintArrowButton() {
|
||||
if( arrowButton != null && !comboBox.isEditable() )
|
||||
arrowButton.repaint();
|
||||
}
|
||||
} );
|
||||
};
|
||||
comboBox.addMouseListener( hoverListener );
|
||||
}
|
||||
|
||||
@@ -144,8 +186,9 @@ public class FlatComboBoxUI
|
||||
|
||||
LookAndFeel.installProperty( comboBox, "opaque", false );
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Component.arc" );
|
||||
minimumWidth = UIManager.getInt( "ComboBox.minimumWidth" );
|
||||
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
|
||||
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
@@ -160,11 +203,17 @@ public class FlatComboBoxUI
|
||||
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
||||
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
||||
|
||||
// set maximumRowCount
|
||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
|
||||
comboBox.setMaximumRowCount( maximumRowCount );
|
||||
|
||||
// scale
|
||||
padding = UIScale.scale( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( comboBox, focusWidth );
|
||||
MigLayoutVisualPadding.install( comboBox );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,6 +232,7 @@ public class FlatComboBoxUI
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
buttonHoverArrowColor = null;
|
||||
buttonPressedArrowColor = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( comboBox );
|
||||
}
|
||||
@@ -243,6 +293,10 @@ public class FlatComboBoxUI
|
||||
editor.applyComponentOrientation( o );
|
||||
} else if( editor != null && FlatClientProperties.PLACEHOLDER_TEXT.equals( propertyName ) )
|
||||
editor.repaint();
|
||||
else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) )
|
||||
comboBox.repaint();
|
||||
else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) )
|
||||
comboBox.revalidate();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -252,17 +306,33 @@ public class FlatComboBoxUI
|
||||
return new FlatComboPopup( comboBox );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComboBoxEditor createEditor() {
|
||||
ComboBoxEditor comboBoxEditor = super.createEditor();
|
||||
|
||||
Component editor = comboBoxEditor.getEditorComponent();
|
||||
if( editor instanceof JTextField ) {
|
||||
JTextField textField = (JTextField) editor;
|
||||
textField.setColumns( editorColumns );
|
||||
|
||||
// assign a non-null and non-javax.swing.plaf.UIResource border to the text field,
|
||||
// otherwise it is replaced with default text field border when switching LaF
|
||||
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
|
||||
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
|
||||
// instead of "border instanceof javax.swing.plaf.UIResource"
|
||||
textField.setBorder( BorderFactory.createEmptyBorder() );
|
||||
}
|
||||
|
||||
return comboBoxEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureEditor() {
|
||||
super.configureEditor();
|
||||
|
||||
// assign a non-javax.swing.plaf.UIResource border to the text field,
|
||||
// otherwise it is replaced with default text field border when switching LaF
|
||||
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
|
||||
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
|
||||
// instead of "border instanceof javax.swing.plaf.UIResource"
|
||||
if( editor instanceof JTextComponent )
|
||||
((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() );
|
||||
// remove default text field border from editor
|
||||
if( editor instanceof JTextField && ((JTextField)editor).getBorder() instanceof FlatTextBorder )
|
||||
((JTextField)editor).setBorder( BorderFactory.createEmptyBorder() );
|
||||
|
||||
// explicitly make non-opaque
|
||||
if( editor instanceof JComponent )
|
||||
@@ -271,59 +341,64 @@ public class FlatComboBoxUI
|
||||
editor.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||
|
||||
updateEditorColors();
|
||||
|
||||
// macOS
|
||||
if( SystemInfo.isMacOS && editor instanceof JTextComponent ) {
|
||||
// delegate actions from editor text field to combobox, which is necessary
|
||||
// because text field on macOS already handle those keys
|
||||
InputMap inputMap = ((JTextComponent)editor).getInputMap();
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "UP" ) );
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "KP_UP" ) );
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "DOWN" ) );
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "KP_DOWN" ) );
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "HOME" ) );
|
||||
new EditorDelegateAction( inputMap, KeyStroke.getKeyStroke( "END" ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEditorColors() {
|
||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||
// is used, then the editor is updated after the combobox and the
|
||||
// colors are again replaced with default colors
|
||||
boolean enabled = editor.isEnabled();
|
||||
editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent)
|
||||
? comboBox.getForeground()
|
||||
: disabledForeground ) );
|
||||
if( editor instanceof JTextComponent )
|
||||
((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
|
||||
boolean isTextComponent = editor instanceof JTextComponent;
|
||||
editor.setForeground( FlatUIUtils.nonUIResource( getForeground( isTextComponent || editor.isEnabled() ) ) );
|
||||
|
||||
if( isTextComponent )
|
||||
((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JButton createArrowButton() {
|
||||
return new FlatArrowButton( SwingConstants.SOUTH, arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null )
|
||||
{
|
||||
@Override
|
||||
protected boolean isHover() {
|
||||
return super.isHover() || (!comboBox.isEditable() ? hover : false);
|
||||
}
|
||||
};
|
||||
return new FlatComboBoxButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
|
||||
int arrowX = arrowButton.getX();
|
||||
int arrowWidth = arrowButton.getWidth();
|
||||
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
|
||||
boolean enabled = comboBox.isEnabled();
|
||||
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint background
|
||||
g2.setColor( enabled
|
||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : c.getBackground())
|
||||
: getDisabledBackground( comboBox ) );
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow button background
|
||||
if( enabled ) {
|
||||
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground );
|
||||
g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
@@ -334,13 +409,16 @@ public class FlatComboBoxUI
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow button
|
||||
if( comboBox.isEditable() ) {
|
||||
if( paintButton ) {
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) );
|
||||
}
|
||||
|
||||
// avoid that the "current value" renderer is invoked with enabled antialiasing
|
||||
FlatUIUtils.resetRenderingHints( g2, oldRenderingHints );
|
||||
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
@@ -357,8 +435,8 @@ public class FlatComboBoxUI
|
||||
uninstallCellPaddingBorder( c );
|
||||
|
||||
boolean enabled = comboBox.isEnabled();
|
||||
c.setForeground( enabled ? comboBox.getForeground() : disabledForeground );
|
||||
c.setBackground( enabled ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
|
||||
c.setBackground( getBackground( enabled ) );
|
||||
c.setForeground( getForeground( enabled ) );
|
||||
|
||||
boolean shouldValidate = (c instanceof JPanel);
|
||||
if( padding != null )
|
||||
@@ -375,12 +453,24 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
public void paintCurrentValueBackground( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
||||
g.setColor( comboBox.isEnabled() ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
|
||||
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
// not necessary because already painted in update()
|
||||
}
|
||||
|
||||
private Color getDisabledBackground( JComponent c ) {
|
||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground;
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground())
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground);
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
return enabled ? comboBox.getForeground() : disabledForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
Dimension minimumSize = super.getMinimumSize( c );
|
||||
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) );
|
||||
return minimumSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -403,6 +493,18 @@ public class FlatComboBoxUI
|
||||
|
||||
Dimension displaySize = super.getDisplaySize();
|
||||
|
||||
// recalculate width without hardcoded 100 under special conditions
|
||||
if( displaySize.width == 100 + padding.left + padding.right &&
|
||||
comboBox.isEditable() &&
|
||||
comboBox.getItemCount() == 0 &&
|
||||
comboBox.getPrototypeDisplayValue() == null )
|
||||
{
|
||||
int width = getDefaultSize().width;
|
||||
width = Math.max( width, editor.getPreferredSize().width );
|
||||
width += padding.left + padding.right;
|
||||
displaySize = new Dimension( width, displaySize.height );
|
||||
}
|
||||
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
return displaySize;
|
||||
}
|
||||
@@ -438,15 +540,43 @@ public class FlatComboBoxUI
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatComboBoxButton -------------------------------------------
|
||||
|
||||
protected class FlatComboBoxButton
|
||||
extends FlatArrowButton
|
||||
{
|
||||
protected FlatComboBoxButton() {
|
||||
this( SwingConstants.SOUTH, arrowType, buttonArrowColor, buttonDisabledArrowColor,
|
||||
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
}
|
||||
|
||||
protected FlatComboBoxButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
super( direction, type, foreground, disabledForeground,
|
||||
hoverForeground, hoverBackground, pressedForeground, pressedBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isHover() {
|
||||
return super.isHover() || (!comboBox.isEditable() ? hover : false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPressed() {
|
||||
return super.isPressed() || (!comboBox.isEditable() ? pressed : false);
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatComboPopup -----------------------------------------------
|
||||
|
||||
@SuppressWarnings( { "rawtypes", "unchecked" } )
|
||||
private class FlatComboPopup
|
||||
protected class FlatComboPopup
|
||||
extends BasicComboPopup
|
||||
{
|
||||
private CellPaddingBorder paddingBorder;
|
||||
|
||||
FlatComboPopup( JComboBox combo ) {
|
||||
protected FlatComboPopup( JComboBox combo ) {
|
||||
super( combo );
|
||||
|
||||
// BasicComboPopup listens to JComboBox.componentOrientation and updates
|
||||
@@ -461,18 +591,37 @@ public class FlatComboBoxUI
|
||||
|
||||
@Override
|
||||
protected Rectangle computePopupBounds( int px, int py, int pw, int ph ) {
|
||||
// get maximum display size of all items, ignoring prototype value
|
||||
Object prototype = comboBox.getPrototypeDisplayValue();
|
||||
if( prototype != null )
|
||||
comboBox.setPrototypeDisplayValue( null );
|
||||
Dimension displaySize = getDisplaySize();
|
||||
if( prototype != null )
|
||||
comboBox.setPrototypeDisplayValue( prototype );
|
||||
// get maximum display width of all items
|
||||
int displayWidth = getDisplaySize().width;
|
||||
|
||||
// add border insets
|
||||
for( Border border : new Border[] { scroller.getViewportBorder(), scroller.getBorder() } ) {
|
||||
if( border != null ) {
|
||||
Insets borderInsets = border.getBorderInsets( null );
|
||||
displayWidth += borderInsets.left + borderInsets.right;
|
||||
}
|
||||
}
|
||||
|
||||
// add width of vertical scroll bar
|
||||
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
|
||||
if( verticalScrollBar != null )
|
||||
displayWidth += verticalScrollBar.getPreferredSize().width;
|
||||
|
||||
// make popup wider if necessary
|
||||
if( displaySize.width > pw ) {
|
||||
int diff = displaySize.width - pw;
|
||||
pw = displaySize.width;
|
||||
if( displayWidth > pw ) {
|
||||
// limit popup width to screen width
|
||||
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
|
||||
if( gc != null ) {
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||
displayWidth = Math.min( displayWidth, screenBounds.width - screenInsets.left - screenInsets.right );
|
||||
} else {
|
||||
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
displayWidth = Math.min( displayWidth, screenSize.width );
|
||||
}
|
||||
|
||||
int diff = displayWidth - pw;
|
||||
pw = displayWidth;
|
||||
|
||||
if( !comboBox.getComponentOrientation().isLeftToRight() )
|
||||
px -= diff;
|
||||
@@ -608,4 +757,31 @@ public class FlatComboBoxUI
|
||||
rendererBorder.paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class EditorDelegateAction -----------------------------------------
|
||||
|
||||
/**
|
||||
* Delegates actions from editor text field to combobox.
|
||||
*/
|
||||
private class EditorDelegateAction
|
||||
extends AbstractAction
|
||||
{
|
||||
private final KeyStroke keyStroke;
|
||||
|
||||
EditorDelegateAction( InputMap inputMap, KeyStroke keyStroke ) {
|
||||
this.keyStroke = keyStroke;
|
||||
|
||||
// add to input map
|
||||
inputMap.put( keyStroke, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e ) {
|
||||
ActionListener action = comboBox.getActionForKeyStroke( keyStroke );
|
||||
if( action != null ) {
|
||||
action.actionPerformed( new ActionEvent( comboBox, e.getID(),
|
||||
e.getActionCommand(), e.getWhen(), e.getModifiers() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.beans.PropertyVetoException;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicDesktopIconUI;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame.JDesktopIcon}.
|
||||
*
|
||||
* <!-- BasicDesktopIconUI -->
|
||||
*
|
||||
* @uiDefault DesktopIcon.border Border
|
||||
*
|
||||
* <!-- FlatDesktopIconUI -->
|
||||
*
|
||||
* @uiDefault DesktopIcon.background Color
|
||||
* @uiDefault DesktopIcon.foreground Color
|
||||
* @uiDefault DesktopIcon.iconSize Dimension
|
||||
* @uiDefault DesktopIcon.closeSize Dimension
|
||||
* @uiDefault DesktopIcon.closeIcon Icon
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDesktopIconUI
|
||||
extends BasicDesktopIconUI
|
||||
{
|
||||
private Dimension iconSize;
|
||||
private Dimension closeSize;
|
||||
|
||||
private JLabel dockIcon;
|
||||
private JButton closeButton;
|
||||
private JToolTip titleTip;
|
||||
private ActionListener closeListener;
|
||||
private MouseInputListener mouseInputListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatDesktopIconUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
dockIcon = null;
|
||||
closeButton = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents() {
|
||||
dockIcon = new JLabel();
|
||||
dockIcon.setHorizontalAlignment( SwingConstants.CENTER );
|
||||
|
||||
closeButton = new JButton();
|
||||
closeButton.setIcon( UIManager.getIcon( "DesktopIcon.closeIcon" ) );
|
||||
closeButton.setFocusable( false );
|
||||
closeButton.setBorder( BorderFactory.createEmptyBorder() );
|
||||
closeButton.setOpaque( true );
|
||||
closeButton.setBackground( FlatUIUtils.nonUIResource( desktopIcon.getBackground() ) );
|
||||
closeButton.setForeground( FlatUIUtils.nonUIResource( desktopIcon.getForeground() ) );
|
||||
closeButton.setVisible( false );
|
||||
|
||||
desktopIcon.setLayout( new FlatDesktopIconLayout() );
|
||||
desktopIcon.add( closeButton );
|
||||
desktopIcon.add( dockIcon );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallComponents() {
|
||||
hideTitleTip();
|
||||
|
||||
desktopIcon.remove( dockIcon );
|
||||
desktopIcon.remove( closeButton );
|
||||
desktopIcon.setLayout( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
LookAndFeel.installColors( desktopIcon, "DesktopIcon.background", "DesktopIcon.foreground" );
|
||||
|
||||
iconSize = UIManager.getDimension( "DesktopIcon.iconSize" );
|
||||
closeSize = UIManager.getDimension( "DesktopIcon.closeSize" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
closeListener = e -> {
|
||||
if( frame.isClosable() )
|
||||
frame.doDefaultCloseAction();
|
||||
};
|
||||
closeButton.addActionListener( closeListener );
|
||||
closeButton.addMouseListener( mouseInputListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
closeButton.removeActionListener( closeListener );
|
||||
closeButton.removeMouseListener( mouseInputListener );
|
||||
closeListener = null;
|
||||
mouseInputListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseInputListener createMouseInputListener() {
|
||||
mouseInputListener = new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
if( frame.isIcon() && desktopIcon.contains( e.getX(), e.getY() ) ) {
|
||||
hideTitleTip();
|
||||
closeButton.setVisible( false );
|
||||
|
||||
try {
|
||||
frame.setIcon( false );
|
||||
} catch( PropertyVetoException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
showTitleTip();
|
||||
if( frame.isClosable() )
|
||||
closeButton.setVisible( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
hideTitleTip();
|
||||
closeButton.setVisible( false );
|
||||
}
|
||||
};
|
||||
return mouseInputListener;
|
||||
}
|
||||
|
||||
private void showTitleTip() {
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( desktopIcon );
|
||||
if( rootPane == null )
|
||||
return;
|
||||
|
||||
if( titleTip == null ) {
|
||||
titleTip = new JToolTip();
|
||||
rootPane.getLayeredPane().add( titleTip, JLayeredPane.POPUP_LAYER );
|
||||
}
|
||||
titleTip.setTipText( frame.getTitle() );
|
||||
titleTip.setSize( titleTip.getPreferredSize() );
|
||||
|
||||
int tx = (desktopIcon.getWidth() - titleTip.getWidth()) / 2;
|
||||
int ty = -(titleTip.getHeight() + UIScale.scale( 4 ));
|
||||
Point pt = SwingUtilities.convertPoint( desktopIcon, tx, ty, titleTip.getParent() );
|
||||
if( pt.x + titleTip.getWidth() > rootPane.getWidth() )
|
||||
pt.x = rootPane.getWidth() - titleTip.getWidth();
|
||||
if( pt.x < 0 )
|
||||
pt.x = 0;
|
||||
titleTip.setLocation( pt );
|
||||
titleTip.repaint();
|
||||
}
|
||||
|
||||
private void hideTitleTip() {
|
||||
if( titleTip == null )
|
||||
return;
|
||||
|
||||
titleTip.setVisible( false );
|
||||
titleTip.getParent().remove( titleTip );
|
||||
titleTip = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return UIScale.scale( iconSize );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return getPreferredSize( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize( JComponent c ) {
|
||||
return getPreferredSize( c );
|
||||
}
|
||||
|
||||
void updateDockIcon() {
|
||||
// use invoke later to make sure that components are updated when switching LaF
|
||||
EventQueue.invokeLater( () -> {
|
||||
if( dockIcon != null )
|
||||
updateDockIconLater();
|
||||
} );
|
||||
}
|
||||
|
||||
private void updateDockIconLater() {
|
||||
// make sure that frame is not selected
|
||||
if( frame.isSelected() ) {
|
||||
try {
|
||||
frame.setSelected( false );
|
||||
} catch( PropertyVetoException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// paint internal frame to buffered image
|
||||
int frameWidth = Math.max( frame.getWidth(), 1 );
|
||||
int frameHeight = Math.max( frame.getHeight(), 1 );
|
||||
BufferedImage frameImage = new BufferedImage( frameWidth, frameHeight, BufferedImage.TYPE_INT_ARGB );
|
||||
Graphics2D g = frameImage.createGraphics();
|
||||
try {
|
||||
//TODO fix missing internal frame header when switching LaF
|
||||
frame.paint( g );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
// compute preview size (keep ratio; also works with non-square preview)
|
||||
Insets insets = desktopIcon.getInsets();
|
||||
int previewWidth = UIScale.scale( iconSize.width ) - insets.left - insets.right;
|
||||
int previewHeight = UIScale.scale( iconSize.height ) - insets.top - insets.bottom;
|
||||
float frameRatio = ((float) frameHeight / (float) frameWidth);
|
||||
if( ((float) previewWidth / (float) frameWidth) > ((float) previewHeight / (float) frameHeight) )
|
||||
previewWidth = Math.round( previewHeight / frameRatio );
|
||||
else
|
||||
previewHeight = Math.round( previewWidth * frameRatio );
|
||||
|
||||
// scale preview
|
||||
Image previewImage = frameImage.getScaledInstance( previewWidth, previewHeight, Image.SCALE_SMOOTH );
|
||||
dockIcon.setIcon( new ImageIcon( previewImage ) );
|
||||
}
|
||||
|
||||
//---- class DockIcon -----------------------------------------------------
|
||||
|
||||
private class FlatDesktopIconLayout
|
||||
implements LayoutManager
|
||||
{
|
||||
@Override public void addLayoutComponent( String name, Component comp ) {}
|
||||
@Override public void removeLayoutComponent( Component comp ) {}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize( Container parent ) {
|
||||
return dockIcon.getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize( Container parent ) {
|
||||
return dockIcon.getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer( Container parent ) {
|
||||
Insets insets = parent.getInsets();
|
||||
|
||||
// dock icon
|
||||
dockIcon.setBounds( insets.left, insets.top,
|
||||
parent.getWidth() - insets.left - insets.right,
|
||||
parent.getHeight() - insets.top - insets.bottom );
|
||||
|
||||
// close button in upper right corner
|
||||
Dimension cSize = UIScale.scale( closeSize );
|
||||
closeButton.setBounds( parent.getWidth() - cSize.width, 0, cSize.width, cSize.height );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import javax.swing.DefaultDesktopManager;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicDesktopPaneUI;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JDesktopPane}.
|
||||
*
|
||||
* <!-- BasicDesktopPaneUI -->
|
||||
*
|
||||
* @uiDefault Desktop.background Color
|
||||
* @uiDefault Desktop.minOnScreenInsets Insets
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDesktopPaneUI
|
||||
extends BasicDesktopPaneUI
|
||||
{
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatDesktopPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDesktopManager() {
|
||||
desktopManager = desktop.getDesktopManager();
|
||||
if( desktopManager == null ) {
|
||||
desktopManager = new FlatDesktopManager();
|
||||
desktop.setDesktopManager( desktopManager );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatDesktopManager -------------------------------------------
|
||||
|
||||
private class FlatDesktopManager
|
||||
extends DefaultDesktopManager
|
||||
implements UIResource
|
||||
{
|
||||
@Override
|
||||
public void iconifyFrame( JInternalFrame f ) {
|
||||
super.iconifyFrame( f );
|
||||
|
||||
((FlatDesktopIconUI)f.getDesktopIcon().getUI()).updateDockIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.image.BufferedImage;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Paints a drop shadow border around the component.
|
||||
* Supports 1-sided, 2-side, 3-sided or 4-sided drop shadows.
|
||||
* <p>
|
||||
* The shadow insets allow specifying drop shadow thickness for each side.
|
||||
* A zero or negative value hides the drop shadow on that side.
|
||||
* A negative value can be used to indent the drop shadow on corners.
|
||||
* E.g. -4 on left indents drop shadow at top-left and bottom-left corners by 4 pixels.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatDropShadowBorder
|
||||
extends FlatEmptyBorder
|
||||
{
|
||||
private final Color shadowColor;
|
||||
private final Insets shadowInsets;
|
||||
private final float shadowOpacity;
|
||||
|
||||
private final int shadowSize;
|
||||
private Image shadowImage;
|
||||
private Color lastShadowColor;
|
||||
private double lastSystemScaleFactor;
|
||||
private float lastUserScaleFactor;
|
||||
|
||||
public FlatDropShadowBorder() {
|
||||
this( null );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor ) {
|
||||
this( shadowColor, 4, 0.5f );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor, int shadowSize, float shadowOpacity ) {
|
||||
this( shadowColor, new Insets( -shadowSize, -shadowSize, shadowSize, shadowSize ), shadowOpacity );
|
||||
}
|
||||
|
||||
public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) {
|
||||
super( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ),
|
||||
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
|
||||
this.shadowColor = shadowColor;
|
||||
this.shadowInsets = shadowInsets;
|
||||
this.shadowOpacity = shadowOpacity;
|
||||
|
||||
shadowSize = Math.max(
|
||||
Math.max( shadowInsets.left, shadowInsets.right ),
|
||||
Math.max( shadowInsets.top, shadowInsets.bottom ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( shadowSize <= 0 )
|
||||
return;
|
||||
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
Color shadowColor = (this.shadowColor != null) ? this.shadowColor : g.getColor();
|
||||
int shadowSize = scale( this.shadowSize, scaleFactor );
|
||||
|
||||
// create and cache shadow image
|
||||
float userScaleFactor = UIScale.getUserScaleFactor();
|
||||
if( shadowImage == null ||
|
||||
!shadowColor.equals( lastShadowColor ) ||
|
||||
lastSystemScaleFactor != scaleFactor ||
|
||||
lastUserScaleFactor != userScaleFactor )
|
||||
{
|
||||
shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity,
|
||||
(float) (scaleFactor * userScaleFactor) );
|
||||
lastShadowColor = shadowColor;
|
||||
lastSystemScaleFactor = scaleFactor;
|
||||
lastUserScaleFactor = userScaleFactor;
|
||||
}
|
||||
|
||||
/*debug
|
||||
int m = shadowImage.getWidth( null );
|
||||
Color oldColor = g.getColor();
|
||||
g.setColor( Color.lightGray );
|
||||
g.drawRect( x - m - 1, y - m - 1, m + 1, m + 1 );
|
||||
g.setColor( Color.white );
|
||||
g.fillRect( x - m, y - m, m, m );
|
||||
g.drawImage( shadowImage, x - m, y - m, null );
|
||||
g.setColor( oldColor );
|
||||
debug*/
|
||||
|
||||
int left = scale( shadowInsets.left, scaleFactor );
|
||||
int right = scale( shadowInsets.right, scaleFactor );
|
||||
int top = scale( shadowInsets.top, scaleFactor );
|
||||
int bottom = scale( shadowInsets.bottom, scaleFactor );
|
||||
|
||||
// shadow outer coordinates
|
||||
int x1o = x - Math.min( left, 0 );
|
||||
int y1o = y - Math.min( top, 0 );
|
||||
int x2o = x + width + Math.min( right, 0 );
|
||||
int y2o = y + height + Math.min( bottom, 0 );
|
||||
|
||||
// shadow inner coordinates
|
||||
int x1i = x1o + shadowSize;
|
||||
int y1i = y1o + shadowSize;
|
||||
int x2i = x2o - shadowSize;
|
||||
int y2i = y2o - shadowSize;
|
||||
|
||||
int wh = (shadowSize * 2) - 1;
|
||||
int center = shadowSize - 1;
|
||||
|
||||
// left-top edge
|
||||
if( left > 0 || top > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y1o, x1i, y1i,
|
||||
0, 0, center, center, null );
|
||||
}
|
||||
|
||||
// top shadow
|
||||
if( top > 0 ) {
|
||||
g.drawImage( shadowImage, x1i, y1o, x2i, y1i,
|
||||
center, 0, center + 1, center, null );
|
||||
}
|
||||
|
||||
// right-top edge
|
||||
if( right > 0 || top > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y1o, x2o, y1i,
|
||||
center, 0, wh, center, null );
|
||||
}
|
||||
|
||||
// left shadow
|
||||
if( left > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y1i, x1i, y2i,
|
||||
0, center, center, center + 1, null );
|
||||
}
|
||||
|
||||
// right shadow
|
||||
if( right > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y1i, x2o, y2i,
|
||||
center, center, wh, center + 1, null );
|
||||
}
|
||||
|
||||
// left-bottom edge
|
||||
if( left > 0 || bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x1o, y2i, x1i, y2o,
|
||||
0, center, center, wh, null );
|
||||
}
|
||||
|
||||
// bottom shadow
|
||||
if( bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x1i, y2i, x2i, y2o,
|
||||
center, center, center + 1, wh, null );
|
||||
}
|
||||
|
||||
// right-bottom edge
|
||||
if( right > 0 || bottom > 0 ) {
|
||||
g.drawImage( shadowImage, x2i, y2i, x2o, y2o,
|
||||
center, center, wh, wh, null );
|
||||
}
|
||||
}
|
||||
|
||||
private int scale( int value, double scaleFactor ) {
|
||||
return (int) Math.ceil( UIScale.scale( value ) * scaleFactor );
|
||||
}
|
||||
|
||||
private static BufferedImage createShadowImage( Color shadowColor, int shadowSize,
|
||||
float shadowOpacity, float scaleFactor )
|
||||
{
|
||||
int shadowRGB = shadowColor.getRGB() & 0xffffff;
|
||||
int shadowAlpha = (int) (255 * shadowOpacity);
|
||||
Color startColor = new Color( shadowRGB | ((shadowAlpha & 0xff) << 24), true );
|
||||
Color midColor = new Color( shadowRGB | (((shadowAlpha / 2) & 0xff) << 24), true );
|
||||
Color endColor = new Color( shadowRGB, true );
|
||||
|
||||
/*debug
|
||||
startColor = Color.red;
|
||||
midColor = Color.green;
|
||||
endColor = Color.blue;
|
||||
debug*/
|
||||
|
||||
int wh = (shadowSize * 2) - 1;
|
||||
int center = shadowSize - 1;
|
||||
|
||||
RadialGradientPaint p = new RadialGradientPaint( center, center,
|
||||
shadowSize - (0.75f * scaleFactor),
|
||||
new float[] { 0, 0.35f, 1 },
|
||||
new Color[] { startColor, midColor, endColor } );
|
||||
|
||||
BufferedImage image = new BufferedImage( wh, wh, BufferedImage.TYPE_INT_ARGB );
|
||||
|
||||
Graphics2D g = image.createGraphics();
|
||||
try {
|
||||
g.setPaint( p );
|
||||
g.fillRect( 0, 0, wh, wh );
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
@@ -26,6 +28,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
|
||||
@@ -83,26 +87,45 @@ public class FlatEditorPaneUI
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
c.revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ) );
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ) );
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size ) {
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
minimumWidth = FlatUIUtils.minimumWidth( c, minimumWidth );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -50,10 +50,15 @@ public class FlatEmptyBorder
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets.left = scale( left );
|
||||
boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
|
||||
insets.left = scale( leftToRight ? left : right );
|
||||
insets.top = scale( top );
|
||||
insets.right = scale( right );
|
||||
insets.right = scale( leftToRight ? right : left );
|
||||
insets.bottom = scale( bottom );
|
||||
return insets;
|
||||
}
|
||||
|
||||
public Insets getUnscaledBorderInsets() {
|
||||
return super.getBorderInsets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,32 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -86,6 +107,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault FileChooser.folderNameLabelText String
|
||||
* @uiDefault FileChooser.filesOfTypeLabelMnemonic String
|
||||
* @uiDefault FileChooser.filesOfTypeLabelText String
|
||||
*
|
||||
* @uiDefault FileChooser.upFolderToolTipText String
|
||||
* @uiDefault FileChooser.upFolderAccessibleName String
|
||||
* @uiDefault FileChooser.homeFolderToolTipText String
|
||||
@@ -97,11 +119,27 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault FileChooser.detailsViewButtonToolTipText String
|
||||
* @uiDefault FileChooser.detailsViewButtonAccessibleName String
|
||||
*
|
||||
* <!-- FilePane -->
|
||||
*
|
||||
* @uiDefault FileChooser.fileNameHeaderText String
|
||||
* @uiDefault FileChooser.fileSizeHeaderText String
|
||||
* @uiDefault FileChooser.fileTypeHeaderText String
|
||||
* @uiDefault FileChooser.fileDateHeaderText String
|
||||
* @uiDefault FileChooser.fileAttrHeaderText String
|
||||
*
|
||||
* @uiDefault FileChooser.viewMenuLabelText String
|
||||
* @uiDefault FileChooser.refreshActionLabelText String
|
||||
* @uiDefault FileChooser.newFolderActionLabelText String
|
||||
* @uiDefault FileChooser.listViewActionLabelText String
|
||||
* @uiDefault FileChooser.detailsViewActionLabelText String
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatFileChooserUI
|
||||
extends MetalFileChooserUI
|
||||
{
|
||||
private final FlatFileView fileView = new FlatFileView();
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatFileChooserUI( (JFileChooser) c );
|
||||
}
|
||||
@@ -110,6 +148,108 @@ public class FlatFileChooserUI
|
||||
super( filechooser );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installComponents( JFileChooser fc ) {
|
||||
super.installComponents( fc );
|
||||
|
||||
patchUI( fc );
|
||||
}
|
||||
|
||||
private void patchUI( JFileChooser fc ) {
|
||||
// turn top-right buttons into toolbar buttons
|
||||
Component topPanel = fc.getComponent( 0 );
|
||||
if( (topPanel instanceof JPanel) &&
|
||||
(((JPanel)topPanel).getLayout() instanceof BorderLayout) )
|
||||
{
|
||||
Component topButtonPanel = ((JPanel)topPanel).getComponent( 0 );
|
||||
if( (topButtonPanel instanceof JPanel) &&
|
||||
(((JPanel)topButtonPanel).getLayout() instanceof BoxLayout) )
|
||||
{
|
||||
Insets margin = UIManager.getInsets( "Button.margin" );
|
||||
Component[] comps = ((JPanel)topButtonPanel).getComponents();
|
||||
for( int i = comps.length - 1; i >= 0; i-- ) {
|
||||
Component c = comps[i];
|
||||
if( c instanceof JButton || c instanceof JToggleButton ) {
|
||||
AbstractButton b = (AbstractButton)c;
|
||||
b.putClientProperty( FlatClientProperties.BUTTON_TYPE,
|
||||
FlatClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON );
|
||||
b.setMargin( margin );
|
||||
b.setFocusable( false );
|
||||
} else if( c instanceof Box.Filler )
|
||||
((JPanel)topButtonPanel).remove( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// increase maximum row count of directory combo box popup list
|
||||
try {
|
||||
Component directoryComboBox = ((JPanel)topPanel).getComponent( 2 );
|
||||
if( directoryComboBox instanceof JComboBox ) {
|
||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||
if( maximumRowCount > 0 )
|
||||
((JComboBox<?>)directoryComboBox).setMaximumRowCount( maximumRowCount );
|
||||
}
|
||||
} catch( ArrayIndexOutOfBoundsException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel createDetailsView( JFileChooser fc ) {
|
||||
JPanel p = super.createDetailsView( fc );
|
||||
|
||||
if( !SystemInfo.isWindows )
|
||||
return p;
|
||||
|
||||
// find scroll pane
|
||||
JScrollPane scrollPane = null;
|
||||
for( Component c : p.getComponents() ) {
|
||||
if( c instanceof JScrollPane ) {
|
||||
scrollPane = (JScrollPane) c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( scrollPane == null )
|
||||
return p;
|
||||
|
||||
// get scroll view, which should be a table
|
||||
Component view = scrollPane.getViewport().getView();
|
||||
if( !(view instanceof JTable) )
|
||||
return p;
|
||||
|
||||
JTable table = (JTable) view;
|
||||
|
||||
// on Windows 10, the date may contain left-to-right (0x200e) and right-to-left (0x200f)
|
||||
// mark characters (see https://en.wikipedia.org/wiki/Left-to-right_mark)
|
||||
// when the "current user" item is selected in the "look in" combobox
|
||||
// --> remove them
|
||||
TableCellRenderer defaultRenderer = table.getDefaultRenderer( Object.class );
|
||||
table.setDefaultRenderer( Object.class, new TableCellRenderer() {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
|
||||
boolean hasFocus, int row, int column )
|
||||
{
|
||||
// remove left-to-right and right-to-left mark characters
|
||||
if( value instanceof String && ((String)value).startsWith( "\u200e" ) ) {
|
||||
String str = (String) value;
|
||||
char[] buf = new char[str.length()];
|
||||
int j = 0;
|
||||
for( int i = 0; i < buf.length; i++ ) {
|
||||
char ch = str.charAt( i );
|
||||
if( ch != '\u200e' && ch != '\u200f' )
|
||||
buf[j++] = ch;
|
||||
}
|
||||
value = new String( buf, 0, j );
|
||||
}
|
||||
|
||||
return defaultRenderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return UIScale.scale( super.getPreferredSize( c ) );
|
||||
@@ -119,4 +259,50 @@ public class FlatFileChooserUI
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return UIScale.scale( super.getMinimumSize( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileView getFileView( JFileChooser fc ) {
|
||||
return fileView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearIconCache() {
|
||||
fileView.clearIconCache();
|
||||
}
|
||||
|
||||
//---- class FlatFileView -------------------------------------------------
|
||||
|
||||
private class FlatFileView
|
||||
extends BasicFileView
|
||||
{
|
||||
@Override
|
||||
public Icon getIcon( File f ) {
|
||||
// get cached icon
|
||||
Icon icon = getCachedIcon( f );
|
||||
if( icon != null )
|
||||
return icon;
|
||||
|
||||
// get system icon
|
||||
if( f != null ) {
|
||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||
|
||||
if( icon != null ) {
|
||||
if( icon instanceof ImageIcon )
|
||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||
cacheIcon( f, icon );
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
// get default icon
|
||||
icon = super.getIcon( f );
|
||||
|
||||
if( icon instanceof ImageIcon ) {
|
||||
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||
cacheIcon( f, icon );
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,13 @@ import javax.swing.plaf.ComponentUI;
|
||||
*
|
||||
* <!-- FlatTextFieldUI -->
|
||||
*
|
||||
* @uiDefault TextComponent.arc int
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.LayoutManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
|
||||
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF internal frame title bar.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameTitlePane
|
||||
extends BasicInternalFrameTitlePane
|
||||
{
|
||||
private JLabel titleLabel;
|
||||
private JPanel buttonPanel;
|
||||
|
||||
public FlatInternalFrameTitlePane( JInternalFrame f ) {
|
||||
super( f );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
LookAndFeel.installBorder( this, "InternalFrameTitlePane.border" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
return new FlatPropertyChangeHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutManager createLayout() {
|
||||
return new BorderLayout( UIScale.scale( 4 ), 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createButtons() {
|
||||
super.createButtons();
|
||||
|
||||
iconButton.setContentAreaFilled( false );
|
||||
maxButton.setContentAreaFilled( false );
|
||||
closeButton.setContentAreaFilled( false );
|
||||
|
||||
Border emptyBorder = BorderFactory.createEmptyBorder();
|
||||
iconButton.setBorder( emptyBorder );
|
||||
maxButton.setBorder( emptyBorder );
|
||||
closeButton.setBorder( emptyBorder );
|
||||
|
||||
updateButtonsVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSubComponents() {
|
||||
titleLabel = new JLabel( frame.getTitle() );
|
||||
titleLabel.setFont( FlatUIUtils.nonUIResource( getFont() ) );
|
||||
titleLabel.setMinimumSize( new Dimension( UIScale.scale( 32 ), 1 ) );
|
||||
updateFrameIcon();
|
||||
updateColors();
|
||||
|
||||
buttonPanel = new JPanel() {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
int height = size.height;
|
||||
// use height of invisible buttons to always have same title pane height
|
||||
if( !iconButton.isVisible() )
|
||||
height = Math.max( height, iconButton.getPreferredSize().height );
|
||||
if( !maxButton.isVisible() )
|
||||
height = Math.max( height, maxButton.getPreferredSize().height );
|
||||
if( !closeButton.isVisible() )
|
||||
height = Math.max( height, closeButton.getPreferredSize().height );
|
||||
return new Dimension( size.width, height );
|
||||
}
|
||||
};
|
||||
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
|
||||
buttonPanel.setOpaque( false );
|
||||
|
||||
buttonPanel.add( iconButton );
|
||||
buttonPanel.add( maxButton );
|
||||
buttonPanel.add( closeButton );
|
||||
|
||||
add( titleLabel, BorderLayout.CENTER );
|
||||
add( buttonPanel, BorderLayout.LINE_END );
|
||||
}
|
||||
|
||||
protected void updateFrameIcon() {
|
||||
Icon frameIcon = frame.getFrameIcon();
|
||||
if( frameIcon != null && (frameIcon.getIconWidth() == 0 || frameIcon.getIconHeight() == 0) )
|
||||
frameIcon = null;
|
||||
else if( frameIcon instanceof ImageIcon )
|
||||
frameIcon = new ScaledImageIcon( (ImageIcon) frameIcon );
|
||||
titleLabel.setIcon( frameIcon );
|
||||
}
|
||||
|
||||
protected void updateColors() {
|
||||
Color background = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTitleColor : notSelectedTitleColor );
|
||||
Color foreground = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTextColor : notSelectedTextColor );
|
||||
|
||||
titleLabel.setForeground( foreground );
|
||||
iconButton.setBackground( background );
|
||||
iconButton.setForeground( foreground );
|
||||
maxButton.setBackground( background );
|
||||
maxButton.setForeground( foreground );
|
||||
closeButton.setBackground( background );
|
||||
closeButton.setForeground( foreground );
|
||||
}
|
||||
|
||||
protected void updateButtonsVisibility() {
|
||||
iconButton.setVisible( frame.isIconifiable() );
|
||||
maxButton.setVisible( frame.isMaximizable() );
|
||||
closeButton.setVisible( frame.isClosable() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing because FlatLaf internal frames do not have system menus.
|
||||
*/
|
||||
@Override
|
||||
protected void assembleSystemMenu() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing because FlatLaf internal frames do not have system menus.
|
||||
*/
|
||||
@Override
|
||||
protected void showSystemMenu() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent( Graphics g ) {
|
||||
paintTitleBackground( g );
|
||||
}
|
||||
|
||||
//---- class FlatPropertyChangeHandler ------------------------------------
|
||||
|
||||
protected class FlatPropertyChangeHandler
|
||||
extends PropertyChangeHandler
|
||||
{
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case JInternalFrame.TITLE_PROPERTY:
|
||||
titleLabel.setText( frame.getTitle() );
|
||||
break;
|
||||
|
||||
case JInternalFrame.FRAME_ICON_PROPERTY:
|
||||
updateFrameIcon();
|
||||
break;
|
||||
|
||||
case JInternalFrame.IS_SELECTED_PROPERTY:
|
||||
updateColors();
|
||||
break;
|
||||
|
||||
case "iconable":
|
||||
case "maximizable":
|
||||
case "closable":
|
||||
updateButtonsVisibility();
|
||||
enableActions();
|
||||
revalidate();
|
||||
repaint();
|
||||
|
||||
// do not invoke super.propertyChange() because this adds/removes the buttons
|
||||
return;
|
||||
|
||||
case "componentOrientation":
|
||||
applyComponentOrientation( frame.getComponentOrientation() );
|
||||
break;
|
||||
}
|
||||
|
||||
super.propertyChange( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame}.
|
||||
*
|
||||
* <!-- BasicInternalFrameUI -->
|
||||
*
|
||||
* @uiDefault control Color
|
||||
* @uiDefault InternalFrame.icon Icon
|
||||
* @uiDefault InternalFrame.border Border
|
||||
* @uiDefault InternalFrame.layoutTitlePaneAtOrigin boolean
|
||||
*
|
||||
* <!-- BasicInternalFrameTitlePane -->
|
||||
*
|
||||
* @uiDefault InternalFrame.titleFont Font
|
||||
* @uiDefault InternalFrame.icon Icon
|
||||
* @uiDefault InternalFrame.maximizeIcon Icon
|
||||
* @uiDefault InternalFrame.minimizeIcon Icon
|
||||
* @uiDefault InternalFrame.iconifyIcon Icon
|
||||
* @uiDefault InternalFrame.closeIcon Icon
|
||||
* @uiDefault InternalFrame.activeTitleBackground Color
|
||||
* @uiDefault InternalFrame.activeTitleForeground Color
|
||||
* @uiDefault InternalFrame.inactiveTitleBackground Color
|
||||
* @uiDefault InternalFrame.inactiveTitleForeground Color
|
||||
* @uiDefault InternalFrame.closeButtonToolTip String
|
||||
* @uiDefault InternalFrame.iconButtonToolTip String
|
||||
* @uiDefault InternalFrame.restoreButtonToolTip String
|
||||
* @uiDefault InternalFrame.maxButtonToolTip String
|
||||
* @uiDefault InternalFrameTitlePane.closeButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.minimizeButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.restoreButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.maximizeButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.moveButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.sizeButtonText String
|
||||
* @uiDefault InternalFrameTitlePane.closeButton.mnemonic Integer
|
||||
* @uiDefault InternalFrameTitlePane.minimizeButton.mnemonic Integer
|
||||
* @uiDefault InternalFrameTitlePane.restoreButton.mnemonic Integer
|
||||
* @uiDefault InternalFrameTitlePane.maximizeButton.mnemonic Integer
|
||||
* @uiDefault InternalFrameTitlePane.moveButton.mnemonic Integer
|
||||
* @uiDefault InternalFrameTitlePane.sizeButton.mnemonic Integer
|
||||
*
|
||||
* <!-- FlatInternalFrameUI -->
|
||||
*
|
||||
* @uiDefault InternalFrame.activeBorderColor Color
|
||||
* @uiDefault InternalFrame.inactiveBorderColor Color
|
||||
* @uiDefault InternalFrame.borderLineWidth int
|
||||
* @uiDefault InternalFrame.borderMargins Insets
|
||||
*
|
||||
* <!-- FlatInternalFrameTitlePane -->
|
||||
*
|
||||
* @uiDefault InternalFrameTitlePane.border Border
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatInternalFrameUI
|
||||
extends BasicInternalFrameUI
|
||||
{
|
||||
protected FlatWindowResizer windowResizer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatInternalFrameUI( (JInternalFrame) c );
|
||||
}
|
||||
|
||||
public FlatInternalFrameUI( JInternalFrame b ) {
|
||||
super( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
LookAndFeel.installProperty( frame, "opaque", false );
|
||||
|
||||
windowResizer = createWindowResizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
if( windowResizer != null ) {
|
||||
windowResizer.uninstall();
|
||||
windowResizer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createNorthPane( JInternalFrame w ) {
|
||||
return new FlatInternalFrameTitlePane( w );
|
||||
}
|
||||
|
||||
protected FlatWindowResizer createWindowResizer() {
|
||||
return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager );
|
||||
}
|
||||
|
||||
//---- class FlatInternalFrameBorder --------------------------------------
|
||||
|
||||
public static class FlatInternalFrameBorder
|
||||
extends FlatEmptyBorder
|
||||
{
|
||||
private final Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
|
||||
private final Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
|
||||
private final int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
|
||||
private final boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" );
|
||||
|
||||
private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder(
|
||||
UIManager.getColor( "InternalFrame.activeDropShadowColor" ),
|
||||
UIManager.getInsets( "InternalFrame.activeDropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "InternalFrame.activeDropShadowOpacity", 0.5f ) );
|
||||
private final FlatDropShadowBorder inactiveDropShadowBorder = new FlatDropShadowBorder(
|
||||
UIManager.getColor( "InternalFrame.inactiveDropShadowColor" ),
|
||||
UIManager.getInsets( "InternalFrame.inactiveDropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "InternalFrame.inactiveDropShadowOpacity", 0.5f ) );
|
||||
|
||||
public FlatInternalFrameBorder() {
|
||||
super( UIManager.getInsets( "InternalFrame.borderMargins" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) {
|
||||
insets.left = scale( Math.min( borderLineWidth, left ) );
|
||||
insets.top = scale( Math.min( borderLineWidth, top ) );
|
||||
insets.right = scale( Math.min( borderLineWidth, right ) );
|
||||
insets.bottom = scale( Math.min( borderLineWidth, bottom ) );
|
||||
return insets;
|
||||
}
|
||||
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
JInternalFrame f = (JInternalFrame) c;
|
||||
|
||||
Insets insets = getBorderInsets( c );
|
||||
float lineWidth = scale( (float) borderLineWidth );
|
||||
|
||||
float rx = x + insets.left - lineWidth;
|
||||
float ry = y + insets.top - lineWidth;
|
||||
float rwidth = width - insets.left - insets.right + (lineWidth * 2);
|
||||
float rheight = height - insets.top - insets.bottom + (lineWidth * 2);
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( f.isSelected() ? activeBorderColor : inactiveBorderColor );
|
||||
|
||||
// paint drop shadow
|
||||
if( dropShadowPainted ) {
|
||||
FlatDropShadowBorder dropShadowBorder = f.isSelected()
|
||||
? activeDropShadowBorder : inactiveDropShadowBorder;
|
||||
|
||||
Insets dropShadowInsets = dropShadowBorder.getBorderInsets();
|
||||
dropShadowBorder.paintBorder( c, g2,
|
||||
(int) rx - dropShadowInsets.left,
|
||||
(int) ry - dropShadowInsets.top,
|
||||
(int) rwidth + dropShadowInsets.left + dropShadowInsets.right,
|
||||
(int) rheight + dropShadowInsets.top + dropShadowInsets.bottom );
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.fill( FlatUIUtils.createRectangle( rx, ry, rwidth, rheight, lineWidth ) );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,12 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
@@ -30,6 +34,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -54,12 +59,8 @@ public class FlatLabelUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatLabelUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatLabelUI.class, FlatLabelUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,23 +99,37 @@ public class FlatLabelUI
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether text contains HTML headings and adds a special CSS rule to
|
||||
* re-calculate heading font sizes based on current component font size.
|
||||
* Checks whether text contains HTML tags that use "absolute-size" keywords
|
||||
* (e.g. "x-large") for font-size in default style sheet
|
||||
* (see javax/swing/text/html/default.css).
|
||||
* If yes, adds a special CSS rule (BASE_SIZE) to the HTML text, which
|
||||
* re-calculates font sizes based on current component font size.
|
||||
*/
|
||||
static void updateHTMLRenderer( JComponent c, String text, boolean always ) {
|
||||
if( BasicHTML.isHTMLString( text ) &&
|
||||
c.getClientProperty( "html.disable" ) != Boolean.TRUE &&
|
||||
text.contains( "<h" ) &&
|
||||
(text.contains( "<h1" ) || text.contains( "<h2" ) || text.contains( "<h3" ) ||
|
||||
text.contains( "<h4" ) || text.contains( "<h5" ) || text.contains( "<h6" )) )
|
||||
needsFontBaseSize( text ) )
|
||||
{
|
||||
int headIndex = text.indexOf( "<head>" );
|
||||
|
||||
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
||||
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
|
||||
if( headIndex < 0 )
|
||||
style = "<head>" + style + "</head>";
|
||||
|
||||
int insertIndex = headIndex >= 0 ? (headIndex + "<head>".length()) : "<html>".length();
|
||||
String lowerText = text.toLowerCase();
|
||||
int headIndex;
|
||||
int styleIndex;
|
||||
|
||||
int insertIndex;
|
||||
if( (headIndex = lowerText.indexOf( "<head>" )) >= 0 ) {
|
||||
// there is a <head> tag --> insert after <head> tag
|
||||
insertIndex = headIndex + "<head>".length();
|
||||
} else if( (styleIndex = lowerText.indexOf( "<style>" )) >= 0 ) {
|
||||
// there is a <style> tag --> insert before <style> tag
|
||||
insertIndex = styleIndex;
|
||||
} else {
|
||||
// no <head> or <style> tag --> insert <head> tag after <html> tag
|
||||
style = "<head>" + style + "</head>";
|
||||
insertIndex = "<html>".length();
|
||||
}
|
||||
|
||||
text = text.substring( 0, insertIndex )
|
||||
+ style
|
||||
+ text.substring( insertIndex );
|
||||
@@ -124,6 +139,55 @@ public class FlatLabelUI
|
||||
BasicHTML.updateRenderer( c, text );
|
||||
}
|
||||
|
||||
private static Set<String> tagsUseFontSizeSet;
|
||||
|
||||
private static boolean needsFontBaseSize( String text ) {
|
||||
if( tagsUseFontSizeSet == null ) {
|
||||
// tags that use font-size in javax/swing/text/html/default.css
|
||||
tagsUseFontSizeSet = new HashSet<>( Arrays.asList(
|
||||
"h1", "h2", "h3", "h4", "h5", "h6", "code", "kbd", "big", "small", "samp" ) );
|
||||
}
|
||||
|
||||
// search for tags in HTML text
|
||||
int textLength = text.length();
|
||||
for( int i = 6; i < textLength - 1; i++ ) {
|
||||
if( text.charAt( i ) == '<' ) {
|
||||
switch( text.charAt( i + 1 ) ) {
|
||||
// first letters of tags in tagsUseFontSizeSet
|
||||
case 'b': case 'B':
|
||||
case 'c': case 'C':
|
||||
case 'h': case 'H':
|
||||
case 'k': case 'K':
|
||||
case 's': case 'S':
|
||||
int tagBegin = i + 1;
|
||||
for( i += 2; i < textLength; i++ ) {
|
||||
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
||||
String tag = text.substring( tagBegin, i ).toLowerCase();
|
||||
if( tagsUseFontSizeSet.contains( tag ) )
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Graphics createGraphicsHTMLTextYCorrection( Graphics g, JComponent c ) {
|
||||
return (c.getClientProperty( BasicHTML.propertyKey ) != null)
|
||||
? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g )
|
||||
: g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
super.paint( createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -26,9 +26,9 @@ import java.awt.Insets;
|
||||
/**
|
||||
* Line border for various components.
|
||||
*
|
||||
* Paints a scaled 1px thick line around the component.
|
||||
* The line thickness is not included in the border insets.
|
||||
* The insets should be at least 1,1,1,1.
|
||||
* Paints a scaled (usually 1px thick) line around the component.
|
||||
* The line thickness is not added to the border insets.
|
||||
* The insets should be at least have line thickness (usually 1,1,1,1).
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -36,10 +36,24 @@ public class FlatLineBorder
|
||||
extends FlatEmptyBorder
|
||||
{
|
||||
private final Color lineColor;
|
||||
private final float lineThickness;
|
||||
|
||||
public FlatLineBorder( Insets insets, Color lineColor ) {
|
||||
this( insets, lineColor, 1f );
|
||||
}
|
||||
|
||||
public FlatLineBorder( Insets insets, Color lineColor, float lineThickness ) {
|
||||
super( insets );
|
||||
this.lineColor = lineColor;
|
||||
this.lineThickness = lineThickness;
|
||||
}
|
||||
|
||||
public Color getLineColor() {
|
||||
return lineColor;
|
||||
}
|
||||
|
||||
public float getLineThickness() {
|
||||
return lineThickness;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +62,7 @@ public class FlatLineBorder
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( lineColor );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( 1f ), 0f );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( lineThickness ), 0f );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import javax.swing.JComponent;
|
||||
@@ -81,7 +82,7 @@ public class FlatListUI
|
||||
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
|
||||
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
|
||||
|
||||
toggleSelectionColors( list.hasFocus() );
|
||||
toggleSelectionColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,13 +101,17 @@ public class FlatListUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
super.focusGained( e );
|
||||
toggleSelectionColors( true );
|
||||
toggleSelectionColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
super.focusLost( e );
|
||||
toggleSelectionColors( false );
|
||||
|
||||
// use invokeLater for the case that the window is deactivated
|
||||
EventQueue.invokeLater( () -> {
|
||||
toggleSelectionColors();
|
||||
} );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -120,8 +125,11 @@ public class FlatListUI
|
||||
* already used in applications. Then either the inactive colors are not used,
|
||||
* or the application has to be changed to extend a FlatLaf renderer.
|
||||
*/
|
||||
private void toggleSelectionColors( boolean focused ) {
|
||||
if( focused ) {
|
||||
private void toggleSelectionColors() {
|
||||
if( list == null )
|
||||
return;
|
||||
|
||||
if( FlatUIUtils.isPermanentFocusOwner( list ) ) {
|
||||
if( list.getSelectionBackground() == selectionInactiveBackground )
|
||||
list.setSelectionBackground( selectionBackground );
|
||||
if( list.getSelectionForeground() == selectionInactiveForeground )
|
||||
|
||||
@@ -29,13 +29,26 @@ import javax.swing.plaf.basic.BasicBorders;
|
||||
public class FlatMarginBorder
|
||||
extends BasicBorders.MarginBorder
|
||||
{
|
||||
private final int left, right, top, bottom;
|
||||
|
||||
public FlatMarginBorder() {
|
||||
left = right = top = bottom = 0;
|
||||
}
|
||||
|
||||
public FlatMarginBorder( Insets insets ) {
|
||||
left = insets.left;
|
||||
top = insets.top;
|
||||
right = insets.right;
|
||||
bottom = insets.bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
insets.top = scale( insets.top );
|
||||
insets.left = scale( insets.left );
|
||||
insets.bottom = scale( insets.bottom );
|
||||
insets.right = scale( insets.right );
|
||||
insets.top = scale( insets.top + top );
|
||||
insets.left = scale( insets.left + left );
|
||||
insets.bottom = scale( insets.bottom + bottom );
|
||||
insets.right = scale( insets.right + right );
|
||||
return insets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
@@ -40,16 +38,8 @@ public class FlatMenuBarBorder
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
float lineHeight = scale( (float) 1 );
|
||||
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( borderColor );
|
||||
g2.fill( new Rectangle2D.Float( x, y + height - lineHeight, width, lineHeight ) );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
float lineHeight = scale( (float) 1 );
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,9 +16,20 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.plaf.ActionMapUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuBarUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
|
||||
@@ -38,4 +49,45 @@ public class FlatMenuBarUI
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuBarUI();
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: This class is not used on macOS if screen menu bar is enabled.
|
||||
* Do not add any functionality here.
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void installKeyboardActions() {
|
||||
super.installKeyboardActions();
|
||||
|
||||
ActionMap map = SwingUtilities.getUIActionMap( menuBar );
|
||||
if( map == null ) {
|
||||
map = new ActionMapUIResource();
|
||||
SwingUtilities.replaceUIActionMap( menuBar, map );
|
||||
}
|
||||
map.put( "takeFocus", new TakeFocus() );
|
||||
}
|
||||
|
||||
//---- class TakeFocus ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Activates the menu bar and shows mnemonics.
|
||||
* On Windows, the popup of the first menu is not shown.
|
||||
* On other platforms, the popup of the first menu is shown.
|
||||
*/
|
||||
private static class TakeFocus
|
||||
extends AbstractAction
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e ) {
|
||||
JMenuBar menuBar = (JMenuBar) e.getSource();
|
||||
JMenu menu = menuBar.getMenu( 0 );
|
||||
if( menu != null ) {
|
||||
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.isWindows
|
||||
? new MenuElement[] { menuBar, menu }
|
||||
: new MenuElement[] { menuBar, menu, menu.getPopupMenu() } );
|
||||
|
||||
FlatLaf.showMnemonics( menuBar );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JMenu}, {@link javax.swing.JMenuItem},
|
||||
* {@link javax.swing.JCheckBoxMenuItem} and {@link javax.swing.JRadioButtonMenuItem}.
|
||||
*
|
||||
* @uiDefault MenuBar.itemMargins Insets
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemBorder
|
||||
extends FlatMarginBorder
|
||||
{
|
||||
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c.getParent() instanceof JMenuBar ) {
|
||||
insets.top = scale( menuBarItemMargins.top );
|
||||
insets.left = scale( menuBarItemMargins.left );
|
||||
insets.bottom = scale( menuBarItemMargins.bottom );
|
||||
insets.right = scale( menuBarItemMargins.right );
|
||||
return insets;
|
||||
} else
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* Renderer for menu items.
|
||||
*
|
||||
* @uiDefault MenuItem.minimumWidth int
|
||||
* @uiDefault MenuItem.minimumIconSize Dimension
|
||||
* @uiDefault MenuItem.textAcceleratorGap int
|
||||
* @uiDefault MenuItem.textNoAcceleratorGap int
|
||||
* @uiDefault MenuItem.acceleratorArrowGap int
|
||||
* @uiDefault MenuItem.checkBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
|
||||
* @uiDefault MenuItem.underlineSelectionColor Color
|
||||
* @uiDefault MenuItem.underlineSelectionHeight int
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemRenderer
|
||||
{
|
||||
protected final JMenuItem menuItem;
|
||||
protected final Icon checkIcon;
|
||||
protected final Icon arrowIcon;
|
||||
protected final Font acceleratorFont;
|
||||
protected final String acceleratorDelimiter;
|
||||
|
||||
protected final int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
|
||||
protected final Dimension minimumIconSize;
|
||||
protected final int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
|
||||
protected final int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 );
|
||||
protected final int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 );
|
||||
|
||||
protected final Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
|
||||
protected final Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
|
||||
|
||||
protected final Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
|
||||
protected final Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
|
||||
protected final Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
|
||||
protected final int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
|
||||
|
||||
protected final Color selectionBackground = UIManager.getColor( "MenuItem.selectionBackground" );
|
||||
|
||||
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
{
|
||||
this.menuItem = menuItem;
|
||||
this.checkIcon = checkIcon;
|
||||
this.arrowIcon = arrowIcon;
|
||||
this.acceleratorFont = acceleratorFont;
|
||||
this.acceleratorDelimiter = acceleratorDelimiter;
|
||||
|
||||
Dimension minimumIconSize = UIManager.getDimension( "MenuItem.minimumIconSize" );
|
||||
this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 );
|
||||
}
|
||||
|
||||
protected Dimension getPreferredMenuItemSize() {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
|
||||
|
||||
Rectangle viewRect = new Rectangle( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE );
|
||||
Rectangle iconRect = new Rectangle();
|
||||
Rectangle textRect = new Rectangle();
|
||||
|
||||
// layout icon and text
|
||||
SwingUtilities.layoutCompoundLabel( menuItem,
|
||||
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
|
||||
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
|
||||
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
|
||||
viewRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
|
||||
|
||||
// union icon and text rectangles
|
||||
Rectangle labelRect = iconRect.union( textRect );
|
||||
width += labelRect.width;
|
||||
height = Math.max( labelRect.height, height );
|
||||
|
||||
// accelerator size
|
||||
String accelText = getAcceleratorText();
|
||||
if( accelText != null ) {
|
||||
// gap between text and accelerator
|
||||
width += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
|
||||
|
||||
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
|
||||
width += SwingUtilities.computeStringWidth( accelFm, accelText );
|
||||
height = Math.max( accelFm.getHeight(), height );
|
||||
}
|
||||
|
||||
// arrow size
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
// gap between text and arrow
|
||||
if( accelText == null )
|
||||
width += scale( textNoAcceleratorGap );
|
||||
|
||||
// gap between accelerator and arrow
|
||||
width += scale( acceleratorArrowGap );
|
||||
|
||||
width += arrowIcon.getIconWidth();
|
||||
height = Math.max( arrowIcon.getIconHeight(), height );
|
||||
}
|
||||
|
||||
// add insets
|
||||
Insets insets = menuItem.getInsets();
|
||||
width += insets.left + insets.right;
|
||||
height += insets.top + insets.bottom;
|
||||
|
||||
// minimum width
|
||||
if( !isTopLevelMenu ) {
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( menuItem, this.minimumWidth );
|
||||
width = Math.max( width, scale( minimumWidth ) );
|
||||
}
|
||||
|
||||
return new Dimension( width, height );
|
||||
}
|
||||
|
||||
private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
|
||||
Rectangle accelRect, Rectangle arrowRect, Rectangle labelRect )
|
||||
{
|
||||
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
|
||||
|
||||
// layout arrow
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
arrowRect.width = arrowIcon.getIconWidth();
|
||||
arrowRect.height = arrowIcon.getIconHeight();
|
||||
} else
|
||||
arrowRect.setSize( 0, 0 );
|
||||
arrowRect.y = viewRect.y + centerOffset( viewRect.height, arrowRect.height );
|
||||
|
||||
// layout accelerator
|
||||
String accelText = getAcceleratorText();
|
||||
if( accelText != null ) {
|
||||
FontMetrics accelFm = menuItem.getFontMetrics( acceleratorFont );
|
||||
accelRect.width = SwingUtilities.computeStringWidth( accelFm, accelText );
|
||||
accelRect.height = accelFm.getHeight();
|
||||
|
||||
accelRect.y = viewRect.y + centerOffset( viewRect.height, accelRect.height );
|
||||
} else
|
||||
accelRect.setBounds( 0, 0, 0, 0 );
|
||||
|
||||
// compute horizontal positions of accelerator and arrow
|
||||
int accelArrowGap = !isTopLevelMenu ? scale( acceleratorArrowGap ) : 0;
|
||||
if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// left-to-right
|
||||
arrowRect.x = viewRect.x + viewRect.width - arrowRect.width;
|
||||
accelRect.x = arrowRect.x - accelArrowGap - accelRect.width;
|
||||
} else {
|
||||
// right-to-left
|
||||
arrowRect.x = viewRect.x;
|
||||
accelRect.x = arrowRect.x + accelArrowGap + arrowRect.width;
|
||||
}
|
||||
|
||||
// width of accelerator, arrow and gap
|
||||
int accelArrowWidth = accelRect.width + arrowRect.width;
|
||||
if( accelText != null )
|
||||
accelArrowWidth += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
if( accelText == null )
|
||||
accelArrowWidth += scale( textNoAcceleratorGap );
|
||||
accelArrowWidth += scale( acceleratorArrowGap );
|
||||
}
|
||||
|
||||
// label rectangle is view rectangle subtracted by accelerator, arrow and gap
|
||||
labelRect.setBounds( viewRect );
|
||||
labelRect.width -= accelArrowWidth;
|
||||
if( !menuItem.getComponentOrientation().isLeftToRight() )
|
||||
labelRect.x += accelArrowWidth;
|
||||
|
||||
// layout icon and text
|
||||
SwingUtilities.layoutCompoundLabel( menuItem,
|
||||
menuItem.getFontMetrics( menuItem.getFont() ), menuItem.getText(), getIconForLayout(),
|
||||
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
|
||||
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
|
||||
labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
|
||||
}
|
||||
|
||||
private static int centerOffset( int wh1, int wh2 ) {
|
||||
return (wh1 / 2) - (wh2 / 2);
|
||||
}
|
||||
|
||||
protected void paintMenuItem( Graphics g, Color selectionBackground, Color selectionForeground,
|
||||
Color disabledForeground, Color acceleratorForeground, Color acceleratorSelectionForeground )
|
||||
{
|
||||
Rectangle viewRect = new Rectangle( menuItem.getWidth(), menuItem.getHeight() );
|
||||
|
||||
// subtract insets
|
||||
Insets insets = menuItem.getInsets();
|
||||
viewRect.x += insets.left;
|
||||
viewRect.y += insets.top;
|
||||
viewRect.width -= (insets.left + insets.right);
|
||||
viewRect.height -= (insets.top + insets.bottom);
|
||||
|
||||
Rectangle iconRect = new Rectangle();
|
||||
Rectangle textRect = new Rectangle();
|
||||
Rectangle accelRect = new Rectangle();
|
||||
Rectangle arrowRect = new Rectangle();
|
||||
Rectangle labelRect = new Rectangle();
|
||||
|
||||
layout( viewRect, iconRect, textRect, accelRect, arrowRect, labelRect );
|
||||
|
||||
/*debug
|
||||
g.setColor( Color.green ); g.drawRect( viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1 );
|
||||
g.setColor( Color.red ); g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
|
||||
g.setColor( Color.blue ); g.drawRect( iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1 );
|
||||
g.setColor( Color.cyan ); g.drawRect( textRect.x, textRect.y, textRect.width - 1, textRect.height - 1 );
|
||||
g.setColor( Color.magenta ); g.drawRect( accelRect.x, accelRect.y, accelRect.width - 1, accelRect.height - 1 );
|
||||
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
|
||||
debug*/
|
||||
|
||||
boolean underlineSelection = isUnderlineSelection();
|
||||
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
|
||||
if( underlineSelection && isArmedOrSelected( menuItem ) )
|
||||
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground );
|
||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||
if( !isTopLevelMenu( menuItem ) )
|
||||
paintArrowIcon( g, arrowRect, arrowIcon );
|
||||
}
|
||||
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
boolean armedOrSelected = isArmedOrSelected( menuItem );
|
||||
if( menuItem.isOpaque() || armedOrSelected ) {
|
||||
// paint background
|
||||
g.setColor( armedOrSelected
|
||||
? deriveBackground( selectionBackground )
|
||||
: menuItem.getBackground() );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
||||
int width = menuItem.getWidth();
|
||||
int height = menuItem.getHeight();
|
||||
|
||||
int underlineHeight = scale( underlineSelectionHeight );
|
||||
g.setColor( underlineSelectionColor );
|
||||
if( isTopLevelMenu( menuItem ) ) {
|
||||
// paint underline at bottom
|
||||
g.fillRect( 0, height - underlineHeight, width, underlineHeight );
|
||||
} else if( menuItem.getComponentOrientation().isLeftToRight() ) {
|
||||
// paint underline at left side
|
||||
g.fillRect( 0, 0, underlineHeight, height );
|
||||
} else {
|
||||
// paint underline at right side
|
||||
g.fillRect( width - underlineHeight, 0, underlineHeight, height );
|
||||
}
|
||||
}
|
||||
|
||||
protected Color deriveBackground( Color background ) {
|
||||
if( !(background instanceof DerivedColor) )
|
||||
return background;
|
||||
|
||||
Color baseColor = menuItem.isOpaque()
|
||||
? menuItem.getBackground()
|
||||
: FlatUIUtils.getParentBackground( menuItem );
|
||||
|
||||
return FlatUIUtils.deriveColor( background, baseColor );
|
||||
}
|
||||
|
||||
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground ) {
|
||||
// if checkbox/radiobutton menu item is selected and also has a custom icon,
|
||||
// then use filled icon background to indicate selection (instead of using checkIcon)
|
||||
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {
|
||||
Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) );
|
||||
g.setColor( FlatUIUtils.deriveColor( checkBackground, selectionBackground ) );
|
||||
g.fillRect( r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
paintIcon( g, menuItem, icon, iconRect );
|
||||
}
|
||||
|
||||
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
|
||||
View htmlView = (View) menuItem.getClientProperty( BasicHTML.propertyKey );
|
||||
if( htmlView != null ) {
|
||||
paintHTMLText( g, menuItem, textRect, htmlView, isUnderlineSelection() ? null : selectionForeground );
|
||||
return;
|
||||
}
|
||||
|
||||
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
|
||||
Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground();
|
||||
|
||||
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(),
|
||||
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
|
||||
}
|
||||
|
||||
protected void paintAccelerator( Graphics g, Rectangle accelRect, String accelText,
|
||||
Color foreground, Color selectionForeground, Color disabledForeground )
|
||||
{
|
||||
paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont,
|
||||
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
|
||||
}
|
||||
|
||||
protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) {
|
||||
paintIcon( g, menuItem, arrowIcon, arrowRect );
|
||||
}
|
||||
|
||||
protected static void paintIcon( Graphics g, JMenuItem menuItem, Icon icon, Rectangle iconRect ) {
|
||||
if( icon == null )
|
||||
return;
|
||||
|
||||
// center because the real icon may be smaller than dimension in iconRect
|
||||
int x = iconRect.x + centerOffset( iconRect.width, icon.getIconWidth() );
|
||||
int y = iconRect.y + centerOffset( iconRect.height, icon.getIconHeight() );
|
||||
|
||||
// paint
|
||||
icon.paintIcon( menuItem, g, x, y );
|
||||
}
|
||||
|
||||
protected static void paintText( Graphics g, JMenuItem menuItem,
|
||||
Rectangle textRect, String text, int mnemonicIndex, Font font,
|
||||
Color foreground, Color selectionForeground, Color disabledForeground )
|
||||
{
|
||||
if( text == null || text.isEmpty() )
|
||||
return;
|
||||
|
||||
FontMetrics fm = menuItem.getFontMetrics( font );
|
||||
|
||||
Font oldFont = g.getFont();
|
||||
g.setFont( font );
|
||||
g.setColor( !menuItem.isEnabled()
|
||||
? disabledForeground
|
||||
: (isArmedOrSelected( menuItem )
|
||||
? selectionForeground
|
||||
: foreground) );
|
||||
|
||||
FlatUIUtils.drawStringUnderlineCharAt( menuItem, g, text, mnemonicIndex,
|
||||
textRect.x, textRect.y + fm.getAscent() );
|
||||
|
||||
g.setFont( oldFont );
|
||||
}
|
||||
|
||||
protected static void paintHTMLText( Graphics g, JMenuItem menuItem,
|
||||
Rectangle textRect, View htmlView, Color selectionForeground )
|
||||
{
|
||||
if( isArmedOrSelected( menuItem ) && selectionForeground != null )
|
||||
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
|
||||
|
||||
htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect );
|
||||
}
|
||||
|
||||
protected static boolean isArmedOrSelected( JMenuItem menuItem ) {
|
||||
return menuItem.isArmed() || (menuItem instanceof JMenu && menuItem.isSelected());
|
||||
}
|
||||
|
||||
protected static boolean isTopLevelMenu( JMenuItem menuItem ) {
|
||||
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
|
||||
private Icon getIconForPainting() {
|
||||
Icon icon = menuItem.getIcon();
|
||||
|
||||
if( icon == null && checkIcon != null && !isTopLevelMenu( menuItem ) )
|
||||
return checkIcon;
|
||||
|
||||
if( icon == null )
|
||||
return null;
|
||||
|
||||
if( !menuItem.isEnabled() )
|
||||
return menuItem.getDisabledIcon();
|
||||
|
||||
if( menuItem.getModel().isPressed() && menuItem.isArmed() ) {
|
||||
Icon pressedIcon = menuItem.getPressedIcon();
|
||||
if( pressedIcon != null )
|
||||
return pressedIcon;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private Icon getIconForLayout() {
|
||||
Icon icon = menuItem.getIcon();
|
||||
|
||||
if( isTopLevelMenu( menuItem ) )
|
||||
return (icon != null) ? new MinSizeIcon( icon ) : null;
|
||||
|
||||
return new MinSizeIcon( (icon != null) ? icon : checkIcon );
|
||||
}
|
||||
|
||||
private KeyStroke cachedAccelerator;
|
||||
private String cachedAcceleratorText;
|
||||
private boolean cachedAcceleratorLeftToRight;
|
||||
|
||||
private String getAcceleratorText() {
|
||||
KeyStroke accelerator = menuItem.getAccelerator();
|
||||
if( accelerator == null )
|
||||
return null;
|
||||
|
||||
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
|
||||
|
||||
if( accelerator == cachedAccelerator && leftToRight == cachedAcceleratorLeftToRight )
|
||||
return cachedAcceleratorText;
|
||||
|
||||
cachedAccelerator = accelerator;
|
||||
cachedAcceleratorText = getTextForAccelerator( accelerator );
|
||||
cachedAcceleratorLeftToRight = leftToRight;
|
||||
|
||||
return cachedAcceleratorText;
|
||||
}
|
||||
|
||||
protected String getTextForAccelerator( KeyStroke accelerator ) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// modifiers
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if( modifiers != 0 ) {
|
||||
if( SystemInfo.isMacOS ) {
|
||||
if( leftToRight )
|
||||
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
|
||||
} else
|
||||
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
|
||||
}
|
||||
|
||||
// key
|
||||
int keyCode = accelerator.getKeyCode();
|
||||
if( keyCode != 0 )
|
||||
buf.append( KeyEvent.getKeyText( keyCode ) );
|
||||
else
|
||||
buf.append( accelerator.getKeyChar() );
|
||||
|
||||
// modifiers if right-to-left on macOS
|
||||
if( modifiers != 0 && !leftToRight && SystemInfo.isMacOS )
|
||||
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String getMacOSModifiersExText( int modifiers, boolean leftToRight ) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if( (modifiers & InputEvent.CTRL_DOWN_MASK) != 0 )
|
||||
buf.append( controlGlyph );
|
||||
if( (modifiers & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0 )
|
||||
buf.append( optionGlyph );
|
||||
if( (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 )
|
||||
buf.append( shiftGlyph );
|
||||
if( (modifiers & InputEvent.META_DOWN_MASK) != 0 )
|
||||
buf.append( commandGlyph );
|
||||
|
||||
// reverse order for right-to-left
|
||||
if( !leftToRight )
|
||||
buf.reverse();
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final char
|
||||
controlGlyph = 0x2303,
|
||||
optionGlyph = 0x2325,
|
||||
shiftGlyph = 0x21E7,
|
||||
commandGlyph = 0x2318;
|
||||
|
||||
//---- class MinSizeIcon --------------------------------------------------
|
||||
|
||||
private class MinSizeIcon
|
||||
implements Icon
|
||||
{
|
||||
private final Icon delegate;
|
||||
|
||||
MinSizeIcon( Icon delegate ) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
int iconWidth = (delegate != null) ? delegate.getIconWidth() : 0;
|
||||
return Math.max( iconWidth, scale( minimumIconSize.width ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
int iconHeight = (delegate != null) ? delegate.getIconHeight() : 0;
|
||||
return Math.max( iconHeight, scale( minimumIconSize.height ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||
}
|
||||
}
|
||||
|
||||
//---- class GraphicsProxyWithTextColor -----------------------------------
|
||||
|
||||
private static class GraphicsProxyWithTextColor
|
||||
extends Graphics2DProxy
|
||||
{
|
||||
private final Color textColor;
|
||||
|
||||
GraphicsProxyWithTextColor( Graphics2D delegate, Color textColor ) {
|
||||
super( delegate );
|
||||
this.textColor = textColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( str, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, float x, float y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( str, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( iterator, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawString( iterator, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawChars( char[] data, int offset, int length, int x, int y ) {
|
||||
Paint oldPaint = getPaint();
|
||||
setPaint( textColor );
|
||||
super.drawChars( data, offset, length, x, y );
|
||||
setPaint( oldPaint );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
|
||||
@@ -27,29 +29,34 @@ import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
*
|
||||
* <!-- BasicMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.font Font
|
||||
* @uiDefault MenuItem.background Color
|
||||
* @uiDefault MenuItem.foreground Color
|
||||
* @uiDefault MenuItem.disabledForeground Color
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorForeground Color
|
||||
* @uiDefault MenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault MenuItem.border Border
|
||||
* @uiDefault MenuItem.borderPainted boolean
|
||||
* @uiDefault MenuItem.margin Insets
|
||||
* @uiDefault MenuItem.arrowIcon Icon
|
||||
* @uiDefault MenuItem.checkIcon Icon
|
||||
* @uiDefault MenuItem.opaque boolean
|
||||
* @uiDefault MenuItem.evenHeight boolean
|
||||
* @uiDefault MenuItem.font Font
|
||||
* @uiDefault MenuItem.background Color
|
||||
* @uiDefault MenuItem.foreground Color
|
||||
* @uiDefault MenuItem.disabledForeground Color
|
||||
* @uiDefault MenuItem.selectionBackground Color
|
||||
* @uiDefault MenuItem.selectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorForeground Color
|
||||
* @uiDefault MenuItem.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault MenuItem.border Border
|
||||
* @uiDefault MenuItem.borderPainted boolean
|
||||
* @uiDefault MenuItem.margin Insets
|
||||
* @uiDefault MenuItem.arrowIcon Icon
|
||||
* @uiDefault MenuItem.checkIcon Icon
|
||||
* @uiDefault MenuItem.opaque boolean
|
||||
*
|
||||
* <!-- FlatMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuItemUI
|
||||
extends BasicMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuItemUI();
|
||||
}
|
||||
@@ -58,20 +65,30 @@ public class FlatMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,19 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuUI;
|
||||
|
||||
@@ -27,32 +37,45 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
*
|
||||
* <!-- BasicMenuUI -->
|
||||
*
|
||||
* @uiDefault Menu.font Font
|
||||
* @uiDefault Menu.background Color
|
||||
* @uiDefault Menu.foreground Color
|
||||
* @uiDefault Menu.disabledForeground Color
|
||||
* @uiDefault Menu.selectionBackground Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault Menu.acceleratorForeground Color
|
||||
* @uiDefault Menu.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault Menu.border Border
|
||||
* @uiDefault Menu.borderPainted boolean
|
||||
* @uiDefault Menu.margin Insets
|
||||
* @uiDefault Menu.arrowIcon Icon
|
||||
* @uiDefault Menu.checkIcon Icon
|
||||
* @uiDefault Menu.opaque boolean
|
||||
* @uiDefault Menu.evenHeight boolean
|
||||
* @uiDefault Menu.crossMenuMnemonic boolean default is false
|
||||
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
|
||||
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
|
||||
* @uiDefault Menu.font Font
|
||||
* @uiDefault Menu.background Color
|
||||
* @uiDefault Menu.foreground Color
|
||||
* @uiDefault Menu.disabledForeground Color
|
||||
* @uiDefault Menu.selectionBackground Color
|
||||
* @uiDefault Menu.selectionForeground Color
|
||||
* @uiDefault Menu.acceleratorForeground Color
|
||||
* @uiDefault Menu.acceleratorSelectionForeground Color
|
||||
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
|
||||
* @uiDefault MenuItem.acceleratorDelimiter String
|
||||
* @uiDefault Menu.border Border
|
||||
* @uiDefault Menu.borderPainted boolean
|
||||
* @uiDefault Menu.margin Insets
|
||||
* @uiDefault Menu.arrowIcon Icon
|
||||
* @uiDefault Menu.checkIcon Icon
|
||||
* @uiDefault Menu.opaque boolean
|
||||
* @uiDefault Menu.crossMenuMnemonic boolean default is false
|
||||
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
|
||||
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
|
||||
*
|
||||
* <!-- FlatMenuUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
* @uiDefault MenuBar.hoverBackground Color
|
||||
*
|
||||
* <!-- FlatMenuRenderer -->
|
||||
*
|
||||
* @uiDefault MenuBar.underlineSelectionBackground Color
|
||||
* @uiDefault MenuBar.underlineSelectionColor Color
|
||||
* @uiDefault MenuBar.underlineSelectionHeight int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatMenuUI
|
||||
extends BasicMenuUI
|
||||
{
|
||||
private Color hoverBackground;
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatMenuUI();
|
||||
}
|
||||
@@ -61,20 +84,108 @@ public class FlatMenuUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
menuItem.setRolloverEnabled( true );
|
||||
|
||||
hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
hoverBackground = null;
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseInputListener createMouseInputListener( JComponent c ) {
|
||||
return new BasicMenuUI.MouseInputHandler() {
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
super.mouseEntered( e );
|
||||
rollover( e, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
super.mouseExited( e );
|
||||
rollover( e, false );
|
||||
}
|
||||
|
||||
private void rollover( MouseEvent e, boolean rollover ) {
|
||||
JMenu menu = (JMenu) e.getSource();
|
||||
if( menu.isTopLevelMenu() && menu.isRolloverEnabled() ) {
|
||||
menu.getModel().setRollover( rollover );
|
||||
menu.repaint();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
// avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare
|
||||
// same code is in BasicMenuUI since Java 10
|
||||
// see https://bugs.openjdk.java.net/browse/JDK-8178430
|
||||
return ((JMenu)menuItem).isTopLevelMenu() ? c.getPreferredSize() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
|
||||
//---- class FlatMenuRenderer ---------------------------------------------
|
||||
|
||||
protected class FlatMenuRenderer
|
||||
extends FlatMenuItemRenderer
|
||||
{
|
||||
protected final Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
|
||||
protected final Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
|
||||
protected final int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
|
||||
|
||||
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
|
||||
Font acceleratorFont, String acceleratorDelimiter )
|
||||
{
|
||||
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g, Color selectionBackground ) {
|
||||
if( isUnderlineSelection() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
selectionBackground = menuBarUnderlineSelectionBackground;
|
||||
|
||||
ButtonModel model = menuItem.getModel();
|
||||
if( model.isRollover() && !model.isArmed() && !model.isSelected() &&
|
||||
model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() )
|
||||
{
|
||||
g.setColor( deriveBackground( hoverBackground ) );
|
||||
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
|
||||
} else
|
||||
super.paintBackground( g, selectionBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
|
||||
if( ((JMenu)menuItem).isTopLevelMenu() ) {
|
||||
underlineSelectionColor = menuBarUnderlineSelectionColor;
|
||||
underlineSelectionHeight = menuBarUnderlineSelectionHeight;
|
||||
}
|
||||
|
||||
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPanelUI;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPanel}.
|
||||
*
|
||||
* <!-- BasicPanelUI -->
|
||||
*
|
||||
* @uiDefault Panel.font Font unused
|
||||
* @uiDefault Panel.background Color only used if opaque
|
||||
* @uiDefault Panel.foreground Color
|
||||
* @uiDefault Panel.border Border
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPanelUI
|
||||
extends BasicPanelUI
|
||||
{
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return FlatUIUtils.createSharedUI( FlatPanelUI.class, FlatPanelUI::new );
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,25 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPasswordFieldUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||
@@ -51,22 +57,27 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
*
|
||||
* <!-- FlatPasswordFieldUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault PasswordField.placeholderForeground Color
|
||||
* @uiDefault PasswordField.showCapsLock boolean
|
||||
* @uiDefault PasswordField.capsLockIcon Icon
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPasswordFieldUI
|
||||
extends BasicPasswordFieldUI
|
||||
{
|
||||
protected int focusWidth;
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
protected boolean showCapsLock;
|
||||
protected Icon capsLockIcon;
|
||||
|
||||
private FocusListener focusListener;
|
||||
private KeyListener capsLockListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatPasswordFieldUI();
|
||||
@@ -76,19 +87,16 @@ public class FlatPasswordFieldUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// use other echoChar on Mac because the default is too large in SF font
|
||||
if( SystemInfo.IS_MAC )
|
||||
LookAndFeel.installProperty( getComponent(), "echoChar", '\u2022' );
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
|
||||
MigLayoutVisualPadding.install( getComponent(), focusWidth );
|
||||
MigLayoutVisualPadding.install( getComponent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,6 +104,7 @@ public class FlatPasswordFieldUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
placeholderForeground = null;
|
||||
capsLockIcon = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
||||
}
|
||||
@@ -105,7 +114,23 @@ public class FlatPasswordFieldUI
|
||||
super.installListeners();
|
||||
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
|
||||
capsLockListener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed( KeyEvent e ) {
|
||||
repaint( e );
|
||||
}
|
||||
@Override
|
||||
public void keyReleased( KeyEvent e ) {
|
||||
repaint( e );
|
||||
}
|
||||
private void repaint( KeyEvent e ) {
|
||||
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK )
|
||||
e.getComponent().repaint();
|
||||
}
|
||||
};
|
||||
|
||||
getComponent().addFocusListener( focusListener );
|
||||
getComponent().addKeyListener( capsLockListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,22 +138,44 @@ public class FlatPasswordFieldUI
|
||||
super.uninstallListeners();
|
||||
|
||||
getComponent().removeFocusListener( focusListener );
|
||||
getComponent().removeKeyListener( capsLockListener );
|
||||
focusListener = null;
|
||||
capsLockListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ),
|
||||
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
if( FlatClientProperties.PLACEHOLDER_TEXT.equals( e.getPropertyName() ) )
|
||||
getComponent().repaint();
|
||||
FlatTextFieldUI.propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), focusWidth, isIntelliJTheme );
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
super.paintSafely( g );
|
||||
paintCapsLock( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
if( !showCapsLock )
|
||||
return;
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
|
||||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
||||
return;
|
||||
|
||||
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
|
||||
int x = c.getWidth() - capsLockIcon.getIconWidth() - y;
|
||||
capsLockIcon.paintIcon( c, g, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,18 +185,11 @@ public class FlatPasswordFieldUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ), c );
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ), c );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
|
||||
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
|
||||
return size;
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,508 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.JWindow;
|
||||
import javax.swing.Popup;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* A popup factory that adds drop shadows to popups on Windows.
|
||||
* On macOS and Linux, heavy weight popups (without drop shadow) are produced and the
|
||||
* operating system automatically adds drop shadows.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPopupFactory
|
||||
extends PopupFactory
|
||||
{
|
||||
private Method java8getPopupMethod;
|
||||
private Method java9getPopupMethod;
|
||||
|
||||
@Override
|
||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
Point pt = fixToolTipLocation( contents, x, y );
|
||||
if( pt != null ) {
|
||||
x = pt.x;
|
||||
y = pt.y;
|
||||
}
|
||||
|
||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
||||
|
||||
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) )
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
|
||||
|
||||
// macOS and Linux adds drop shadow to heavy weight popups
|
||||
if( SystemInfo.isMacOS || SystemInfo.isLinux )
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||
|
||||
// create drop shadow popup
|
||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a popup for the screen that the owner component is on.
|
||||
* <p>
|
||||
* PopupFactory caches heavy weight popup windows and reuses them.
|
||||
* On a dual screen setup, if the popup owner has moved from one screen to the other one,
|
||||
* then the cached heavy weight popup window may be connected to the wrong screen.
|
||||
* If the two screens use different scaling factors, then the popup location and size
|
||||
* is scaled when the popup becomes visible, which shows the popup in the wrong location
|
||||
* (or on wrong screen). The re-scaling is done in WWindowPeer.setBounds() (Java 9+).
|
||||
* <p>
|
||||
* To fix this, dispose popup windows that are on wrong screen and get new popup.
|
||||
* <p>
|
||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||
*/
|
||||
private Popup getPopupForScreenOfOwner( Component owner, Component contents, int x, int y, boolean forceHeavyWeight )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for(;;) {
|
||||
// create new or get cached popup
|
||||
Popup popup = forceHeavyWeight
|
||||
? getHeavyWeightPopup( owner, contents, x, y )
|
||||
: super.getPopup( owner, contents, x, y );
|
||||
|
||||
// get heavy weight popup window; is null for non-heavy weight popup
|
||||
Window popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
|
||||
// check whether heavy weight popup window is on same screen as owner component
|
||||
if( popupWindow == null ||
|
||||
owner == null ||
|
||||
popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() )
|
||||
return popup;
|
||||
|
||||
// remove contents component from popup window
|
||||
if( popupWindow instanceof JWindow )
|
||||
((JWindow)popupWindow).getContentPane().removeAll();
|
||||
|
||||
// dispose unused popup
|
||||
// (do not invoke popup.hide() because this would cache the popup window)
|
||||
popupWindow.dispose();
|
||||
|
||||
// avoid endless loop (should newer happen; PopupFactory cache size is 5)
|
||||
if( ++count > 10 )
|
||||
return popup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the given popup and, if necessary, fixes the location of a heavy weight popup window.
|
||||
* <p>
|
||||
* On a dual screen setup, where screens use different scale factors, it may happen
|
||||
* that the window location changes when showing a heavy weight popup window.
|
||||
* E.g. when opening an dialog on the secondary screen and making combobox popup visible.
|
||||
* <p>
|
||||
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
|
||||
*/
|
||||
private static void showPopupAndFixLocation( Popup popup, Window popupWindow ) {
|
||||
if( popupWindow != null ) {
|
||||
// remember location of heavy weight popup window
|
||||
int x = popupWindow.getX();
|
||||
int y = popupWindow.getY();
|
||||
|
||||
popup.show();
|
||||
|
||||
// restore popup window location if it has changed
|
||||
// (probably scaled when screens use different scale factors)
|
||||
if( popupWindow.getX() != x || popupWindow.getY() != y )
|
||||
popupWindow.setLocation( x, y );
|
||||
} else
|
||||
popup.show();
|
||||
}
|
||||
|
||||
private boolean isOptionEnabled( Component owner, Component contents, String clientKey, String uiKey ) {
|
||||
if( owner instanceof JComponent ) {
|
||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) owner, clientKey, null );
|
||||
if( b != null )
|
||||
return b;
|
||||
}
|
||||
|
||||
if( contents instanceof JComponent ) {
|
||||
Boolean b = FlatClientProperties.clientPropertyBooleanStrict( (JComponent) contents, clientKey, null );
|
||||
if( b != null )
|
||||
return b;
|
||||
}
|
||||
|
||||
return UIManager.getBoolean( uiKey );
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no API in Java 8 to force creation of heavy weight popups,
|
||||
* but it is possible with reflection. Java 9 provides a new method.
|
||||
*
|
||||
* When changing FlatLaf system requirements to Java 9+,
|
||||
* then this method can be replaced with:
|
||||
* return getPopup( owner, contents, x, y, true );
|
||||
*/
|
||||
private Popup getHeavyWeightPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
try {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
if( java9getPopupMethod == null ) {
|
||||
java9getPopupMethod = PopupFactory.class.getDeclaredMethod(
|
||||
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class );
|
||||
}
|
||||
return (Popup) java9getPopupMethod.invoke( this, owner, contents, x, y, true );
|
||||
} else {
|
||||
// Java 8
|
||||
if( java8getPopupMethod == null ) {
|
||||
java8getPopupMethod = PopupFactory.class.getDeclaredMethod(
|
||||
"getPopup", Component.class, Component.class, int.class, int.class, int.class );
|
||||
java8getPopupMethod.setAccessible( true );
|
||||
}
|
||||
return (Popup) java8getPopupMethod.invoke( this, owner, contents, x, y, /*HEAVY_WEIGHT_POPUP*/ 2 );
|
||||
}
|
||||
} catch( NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex ) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||
* In case that the tooltip would be partly outside of the screen,
|
||||
* ToolTipManagerthe changes the location so that the entire tooltip fits on screen.
|
||||
* But this can place the tooltip under the mouse location and hide the owner component.
|
||||
* <p>
|
||||
* This method checks whether the current mouse location is within tooltip bounds
|
||||
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
||||
*/
|
||||
private Point fixToolTipLocation( Component contents, int x, int y ) {
|
||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
||||
return null;
|
||||
|
||||
Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
|
||||
Dimension tipSize = contents.getPreferredSize();
|
||||
|
||||
// check whether mouse location is within tooltip bounds
|
||||
Rectangle tipBounds = new Rectangle( x, y, tipSize.width, tipSize.height );
|
||||
if( !tipBounds.contains( mouseLocation ) )
|
||||
return null;
|
||||
|
||||
// place tooltip above mouse location
|
||||
return new Point( x, mouseLocation.y - tipSize.height - UIScale.scale( 20 ) );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromToolTipManager() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( StackTraceElement stackTraceElement : stackTrace ) {
|
||||
if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) &&
|
||||
"showTipWindow".equals( stackTraceElement.getMethodName() ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
|
||||
private class NonFlashingPopup
|
||||
extends Popup
|
||||
{
|
||||
private Popup delegate;
|
||||
private Component contents;
|
||||
|
||||
// heavy weight
|
||||
protected Window popupWindow;
|
||||
private Color oldPopupWindowBackground;
|
||||
|
||||
NonFlashingPopup( Popup delegate, Component contents ) {
|
||||
this.delegate = delegate;
|
||||
this.contents = contents;
|
||||
|
||||
popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
if( popupWindow != null ) {
|
||||
// heavy weight popup
|
||||
|
||||
// fix background flashing which may occur on some platforms
|
||||
// (e.g. macOS and Linux) when using dark theme
|
||||
oldPopupWindowBackground = popupWindow.getBackground();
|
||||
popupWindow.setBackground( contents.getBackground() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if( delegate != null ) {
|
||||
showPopupAndFixLocation( delegate, popupWindow );
|
||||
|
||||
// increase tooltip size if necessary because it may be too small on HiDPI screens
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8213535
|
||||
if( contents instanceof JToolTip && popupWindow == null ) {
|
||||
Container parent = contents.getParent();
|
||||
if( parent instanceof JPanel ) {
|
||||
Dimension prefSize = parent.getPreferredSize();
|
||||
if( !prefSize.equals( parent.getSize() ) ) {
|
||||
Container mediumWeightPanel = SwingUtilities.getAncestorOfClass( Panel.class, parent );
|
||||
Container c = (mediumWeightPanel != null)
|
||||
? mediumWeightPanel // medium weight popup
|
||||
: parent; // light weight popup
|
||||
c.setSize( prefSize );
|
||||
c.validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if( delegate != null ) {
|
||||
delegate.hide();
|
||||
delegate = null;
|
||||
contents = null;
|
||||
}
|
||||
|
||||
if( popupWindow != null ) {
|
||||
// restore background so that it can not affect other LaFs (when switching)
|
||||
// because popup windows are cached and reused
|
||||
popupWindow.setBackground( oldPopupWindowBackground );
|
||||
popupWindow = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class DropShadowPopup ----------------------------------------------
|
||||
|
||||
private class DropShadowPopup
|
||||
extends NonFlashingPopup
|
||||
{
|
||||
private final Component owner;
|
||||
|
||||
// light weight
|
||||
private JComponent lightComp;
|
||||
private Border oldBorder;
|
||||
private boolean oldOpaque;
|
||||
|
||||
// medium weight
|
||||
private boolean mediumWeightShown;
|
||||
private Panel mediumWeightPanel;
|
||||
private JPanel dropShadowPanel;
|
||||
private ComponentListener mediumPanelListener;
|
||||
|
||||
// heavy weight
|
||||
private Popup dropShadowDelegate;
|
||||
private Window dropShadowWindow;
|
||||
private Color oldDropShadowWindowBackground;
|
||||
|
||||
DropShadowPopup( Popup delegate, Component owner, Component contents ) {
|
||||
super( delegate, contents );
|
||||
this.owner = owner;
|
||||
|
||||
Dimension size = contents.getPreferredSize();
|
||||
if( size.width <= 0 || size.height <= 0 )
|
||||
return;
|
||||
|
||||
if( popupWindow != null ) {
|
||||
// heavy weight popup
|
||||
|
||||
// Since Java has a problem with sub-pixel text rendering on translucent
|
||||
// windows, we can not make the popup window translucent for the drop shadow.
|
||||
// (see https://bugs.openjdk.java.net/browse/JDK-8215980)
|
||||
// The solution is to create a second translucent window that paints
|
||||
// the drop shadow and is positioned behind the popup window.
|
||||
|
||||
// create panel that paints the drop shadow
|
||||
JPanel dropShadowPanel = new JPanel();
|
||||
dropShadowPanel.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel.setOpaque( false );
|
||||
|
||||
// set preferred size of drop shadow panel
|
||||
Dimension prefSize = popupWindow.getPreferredSize();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setPreferredSize( new Dimension(
|
||||
prefSize.width + insets.left + insets.right,
|
||||
prefSize.height + insets.top + insets.bottom ) );
|
||||
|
||||
// create heavy weight popup for drop shadow
|
||||
int x = popupWindow.getX() - insets.left;
|
||||
int y = popupWindow.getY() - insets.top;
|
||||
dropShadowDelegate = getPopupForScreenOfOwner( owner, dropShadowPanel, x, y, true );
|
||||
|
||||
// make drop shadow popup window translucent
|
||||
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
|
||||
if( dropShadowWindow != null ) {
|
||||
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
||||
dropShadowWindow.setBackground( new Color( 0, true ) );
|
||||
}
|
||||
} else {
|
||||
mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
|
||||
if( mediumWeightPanel != null ) {
|
||||
// medium weight popup
|
||||
dropShadowPanel = new JPanel();
|
||||
dropShadowPanel.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel.setOpaque( false );
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
} else {
|
||||
// light weight popup
|
||||
Container p = contents.getParent();
|
||||
if( !(p instanceof JComponent) )
|
||||
return;
|
||||
|
||||
lightComp = (JComponent) p;
|
||||
oldBorder = lightComp.getBorder();
|
||||
oldOpaque = lightComp.isOpaque();
|
||||
lightComp.setBorder( createDropShadowBorder() );
|
||||
lightComp.setOpaque( false );
|
||||
lightComp.setSize( lightComp.getPreferredSize() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Border createDropShadowBorder() {
|
||||
return new FlatDropShadowBorder(
|
||||
UIManager.getColor( "Popup.dropShadowColor" ),
|
||||
UIManager.getInsets( "Popup.dropShadowInsets" ),
|
||||
FlatUIUtils.getUIFloat( "Popup.dropShadowOpacity", 0.5f ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if( dropShadowDelegate != null )
|
||||
showPopupAndFixLocation( dropShadowDelegate, dropShadowWindow );
|
||||
|
||||
if( mediumWeightPanel != null )
|
||||
showMediumWeightDropShadow();
|
||||
|
||||
super.show();
|
||||
|
||||
// fix location of light weight popup in case it has left or top drop shadow
|
||||
if( lightComp != null ) {
|
||||
Insets insets = lightComp.getInsets();
|
||||
if( insets.left != 0 || insets.top != 0 )
|
||||
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if( dropShadowDelegate != null ) {
|
||||
dropShadowDelegate.hide();
|
||||
dropShadowDelegate = null;
|
||||
}
|
||||
|
||||
if( mediumWeightPanel != null ) {
|
||||
hideMediumWeightDropShadow();
|
||||
dropShadowPanel = null;
|
||||
mediumWeightPanel = null;
|
||||
}
|
||||
|
||||
super.hide();
|
||||
|
||||
if( dropShadowWindow != null ) {
|
||||
dropShadowWindow.setBackground( oldDropShadowWindowBackground );
|
||||
dropShadowWindow = null;
|
||||
}
|
||||
|
||||
if( lightComp != null ) {
|
||||
lightComp.setBorder( oldBorder );
|
||||
lightComp.setOpaque( oldOpaque );
|
||||
lightComp = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void showMediumWeightDropShadow() {
|
||||
if( mediumWeightShown )
|
||||
return;
|
||||
|
||||
mediumWeightShown = true;
|
||||
|
||||
if( owner == null )
|
||||
return;
|
||||
|
||||
Window window = SwingUtilities.windowForComponent( owner );
|
||||
if( !(window instanceof RootPaneContainer) )
|
||||
return;
|
||||
|
||||
dropShadowPanel.setVisible( false );
|
||||
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
|
||||
|
||||
mediumPanelListener = new ComponentListener() {
|
||||
@Override
|
||||
public void componentShown( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setVisible( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setVisible( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null ) {
|
||||
Point location = mediumWeightPanel.getLocation();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
}
|
||||
};
|
||||
mediumWeightPanel.addComponentListener( mediumPanelListener );
|
||||
}
|
||||
|
||||
private void hideMediumWeightDropShadow() {
|
||||
mediumWeightPanel.removeComponentListener( mediumPanelListener );
|
||||
|
||||
Container parent = dropShadowPanel.getParent();
|
||||
if( parent != null ) {
|
||||
Rectangle bounds = dropShadowPanel.getBounds();
|
||||
parent.remove( dropShadowPanel );
|
||||
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Border for {@link javax.swing.JPopupMenu}.
|
||||
@@ -33,4 +38,18 @@ public class FlatPopupMenuBorder
|
||||
super( UIManager.getInsets( "PopupMenu.borderInsets" ),
|
||||
UIManager.getColor( "PopupMenu.borderColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( c instanceof Container &&
|
||||
((Container)c).getComponentCount() > 0 &&
|
||||
((Container)c).getComponent( 0 ) instanceof JScrollPane )
|
||||
{
|
||||
// e.g. for combobox popups
|
||||
insets.left = insets.top = insets.right = insets.bottom = UIScale.scale( 1 );
|
||||
return insets;
|
||||
}
|
||||
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
public class FlatPopupMenuSeparatorUI
|
||||
extends FlatSeparatorUI
|
||||
{
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatPopupMenuSeparatorUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, FlatPopupMenuSeparatorUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
@@ -23,12 +24,14 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicProgressBarUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -60,6 +63,8 @@ public class FlatProgressBarUI
|
||||
protected Dimension horizontalSize;
|
||||
protected Dimension verticalSize;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatProgressBarUI();
|
||||
}
|
||||
@@ -75,11 +80,35 @@ public class FlatProgressBarUI
|
||||
verticalSize = UIManager.getDimension( "ProgressBar.verticalSize" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = e -> {
|
||||
switch( e.getPropertyName() ) {
|
||||
case PROGRESS_BAR_LARGE_HEIGHT:
|
||||
case PROGRESS_BAR_SQUARE:
|
||||
progressBar.revalidate();
|
||||
progressBar.repaint();
|
||||
break;
|
||||
}
|
||||
};
|
||||
progressBar.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
progressBar.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
Dimension size = super.getPreferredSize( c );
|
||||
|
||||
if( progressBar.isStringPainted() ) {
|
||||
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, false ) ) {
|
||||
// recalculate progress height/width to make it smaller
|
||||
Insets insets = progressBar.getInsets();
|
||||
FontMetrics fm = progressBar.getFontMetrics( progressBar.getFont() );
|
||||
@@ -122,9 +151,11 @@ public class FlatProgressBarUI
|
||||
return;
|
||||
|
||||
boolean horizontal = (progressBar.getOrientation() == JProgressBar.HORIZONTAL);
|
||||
int arc = Math.min( UIScale.scale( this.arc ), horizontal ? height : width );
|
||||
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, false )
|
||||
? 0
|
||||
: Math.min( UIScale.scale( this.arc ), horizontal ? height : width );
|
||||
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
// paint track
|
||||
RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float( x, y, width, height, arc, arc );
|
||||
@@ -132,6 +163,7 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( trackShape );
|
||||
|
||||
// paint progress
|
||||
int amountFull = 0;
|
||||
if( progressBar.isIndeterminate() ) {
|
||||
boxRect = getBox( boxRect );
|
||||
if( boxRect != null ) {
|
||||
@@ -139,11 +171,8 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( new RoundRectangle2D.Float( boxRect.x, boxRect.y,
|
||||
boxRect.width, boxRect.height, arc, arc ) );
|
||||
}
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, 0, insets );
|
||||
} else {
|
||||
int amountFull = getAmountFull( insets, width, height );
|
||||
amountFull = getAmountFull( insets, width, height );
|
||||
|
||||
RoundRectangle2D.Float progressShape = horizontal
|
||||
? new RoundRectangle2D.Float( c.getComponentOrientation().isLeftToRight() ? x : x + (width - amountFull),
|
||||
@@ -158,9 +187,31 @@ public class FlatProgressBarUI
|
||||
((Graphics2D)g).fill( area );
|
||||
} else
|
||||
((Graphics2D)g).fill( progressShape );
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, amountFull, insets );
|
||||
}
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
|
||||
if( progressBar.isStringPainted() )
|
||||
paintString( g, x, y, width, height, amountFull, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintString( Graphics g, int x, int y, int width, int height, int amountFull, Insets b ) {
|
||||
super.paintString( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), x, y, width, height, amountFull, b );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAnimationIndex( int newValue ) {
|
||||
super.setAnimationIndex( newValue );
|
||||
|
||||
// On HiDPI screens at 125%, 150% and 175% scaling, it occurs that antialiased painting
|
||||
// may paint one pixel outside of the clipping area. This results in visual artifacts
|
||||
// in indeterminate mode when the progress moves around.
|
||||
// Unfortunately it is not safe to invoke getBox() from here (may throw NPE),
|
||||
// which makes it impractical to get progress box and repaint increased box.
|
||||
// Only solution is to repaint whole progress bar.
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( progressBar.getGraphicsConfiguration() );
|
||||
if( (int) systemScaleFactor != systemScaleFactor )
|
||||
progressBar.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
|
||||
@@ -43,13 +45,18 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
* @uiDefault RadioButtonMenuItem.arrowIcon Icon
|
||||
* @uiDefault RadioButtonMenuItem.checkIcon Icon
|
||||
* @uiDefault RadioButtonMenuItem.opaque boolean
|
||||
* @uiDefault RadioButtonMenuItem.evenHeight boolean
|
||||
*
|
||||
* <!-- FlatRadioButtonMenuItemUI -->
|
||||
*
|
||||
* @uiDefault MenuItem.iconTextGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatRadioButtonMenuItemUI
|
||||
extends BasicRadioButtonMenuItemUI
|
||||
{
|
||||
private FlatMenuItemRenderer renderer;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatRadioButtonMenuItemUI();
|
||||
}
|
||||
@@ -58,20 +65,30 @@ public class FlatRadioButtonMenuItemUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
// scale
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
LookAndFeel.installProperty( menuItem, "iconTextGap", FlatUIUtils.getUIInt( "MenuItem.iconTextGap", 4 ) );
|
||||
|
||||
renderer = createRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale defaultTextIconGap again if iconTextGap property has changed.
|
||||
*/
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener( c );
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
if( e.getPropertyName() == "iconTextGap" )
|
||||
defaultTextIconGap = scale( defaultTextIconGap );
|
||||
};
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
renderer = null;
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
|
||||
return renderer.getPreferredMenuItemSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
renderer.paintMenuItem( g, selectionBackground, selectionForeground, disabledForeground,
|
||||
acceleratorForeground, acceleratorSelectionForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,10 @@ import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonUI;
|
||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -59,14 +57,12 @@ public class FlatRadioButtonUI
|
||||
protected int iconTextGap;
|
||||
protected Color disabledText;
|
||||
|
||||
private Color defaultBackground;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatRadioButtonUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, FlatRadioButtonUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,6 +75,8 @@ public class FlatRadioButtonUI
|
||||
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
|
||||
disabledText = UIManager.getColor( prefix + "disabledText" );
|
||||
|
||||
defaultBackground = UIManager.getColor( prefix + "background" );
|
||||
|
||||
defaults_initialized = true;
|
||||
}
|
||||
|
||||
@@ -101,6 +99,8 @@ public class FlatRadioButtonUI
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
Dimension size = super.getPreferredSize( c );
|
||||
if( size == null )
|
||||
return null;
|
||||
|
||||
// small insets fix
|
||||
int focusWidth = getIconFocusWidth( c );
|
||||
@@ -118,11 +118,12 @@ public class FlatRadioButtonUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
// fill background even if opaque if
|
||||
// - used as cell renderer (because of selection background)
|
||||
// fill background even if not opaque if
|
||||
// - contentAreaFilled is true and
|
||||
// - if background was explicitly set to a non-UIResource color
|
||||
if( !c.isOpaque() &&
|
||||
(c.getParent() instanceof CellRendererPane || !(c.getBackground() instanceof UIResource)) )
|
||||
((AbstractButton)c).isContentAreaFilled() &&
|
||||
!defaultBackground.equals( c.getBackground() ) )
|
||||
{
|
||||
g.setColor( c.getBackground() );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
@@ -151,7 +152,7 @@ public class FlatRadioButtonUI
|
||||
}
|
||||
}
|
||||
|
||||
super.paint( g, c );
|
||||
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright 2020 FormDev Software GmbH
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.LayoutManager2;
|
||||
import java.awt.Window;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.BorderUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicRootPaneUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}.
|
||||
*
|
||||
* <!-- FlatRootPaneUI -->
|
||||
*
|
||||
* @uiDefault RootPane.border Border
|
||||
* @uiDefault RootPane.activeBorderColor Color
|
||||
* @uiDefault RootPane.inactiveBorderColor Color
|
||||
* @uiDefault TitlePane.borderColor Color optional
|
||||
*
|
||||
* <!-- FlatWindowResizer -->
|
||||
*
|
||||
* @uiDefault RootPane.borderDragThickness int
|
||||
* @uiDefault RootPane.cornerDragWidth int
|
||||
* @uiDefault RootPane.honorFrameMinimumSizeOnResize boolean
|
||||
* @uiDefault RootPane.honorDialogMinimumSizeOnResize boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatRootPaneUI
|
||||
extends BasicRootPaneUI
|
||||
{
|
||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
||||
static final boolean canUseJBRCustomDecorations
|
||||
= SystemInfo.isJetBrainsJVM_11_orLater && SystemInfo.isWindows_10_orLater;
|
||||
|
||||
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
|
||||
|
||||
protected JRootPane rootPane;
|
||||
protected FlatTitlePane titlePane;
|
||||
protected FlatWindowResizer windowResizer;
|
||||
|
||||
private LayoutManager oldLayout;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatRootPaneUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
rootPane = (JRootPane) c;
|
||||
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
else
|
||||
installBorder();
|
||||
|
||||
if( canUseJBRCustomDecorations )
|
||||
JBRCustomDecorations.install( rootPane );
|
||||
}
|
||||
|
||||
protected void installBorder() {
|
||||
if( borderColor != null ) {
|
||||
Border b = rootPane.getBorder();
|
||||
if( b == null || b instanceof UIResource )
|
||||
rootPane.setBorder( new FlatWindowTitleBorder( borderColor ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
uninstallClientDecorations();
|
||||
rootPane = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults( JRootPane c ) {
|
||||
super.installDefaults( c );
|
||||
|
||||
// Update background color of JFrame or JDialog parent to avoid bad border
|
||||
// on HiDPI screens when switching from light to dark Laf.
|
||||
// The background of JFrame is initialized in JFrame.frameInit() and
|
||||
// the background of JDialog in JDialog.dialogInit(),
|
||||
// but it was not updated when switching Laf.
|
||||
Container parent = c.getParent();
|
||||
if( parent instanceof JFrame || parent instanceof JDialog ) {
|
||||
Color background = parent.getBackground();
|
||||
if( background == null || background instanceof UIResource )
|
||||
parent.setBackground( UIManager.getColor( "control" ) );
|
||||
}
|
||||
|
||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
||||
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
|
||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
||||
}
|
||||
|
||||
protected void installClientDecorations() {
|
||||
boolean isJBRSupported = canUseJBRCustomDecorations && JBRCustomDecorations.isSupported();
|
||||
|
||||
// install border
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE && !isJBRSupported )
|
||||
LookAndFeel.installBorder( rootPane, "RootPane.border" );
|
||||
else
|
||||
LookAndFeel.uninstallBorder( rootPane );
|
||||
|
||||
// install title pane
|
||||
setTitlePane( createTitlePane() );
|
||||
|
||||
// install layout
|
||||
oldLayout = rootPane.getLayout();
|
||||
rootPane.setLayout( createRootLayout() );
|
||||
|
||||
// install window resizer
|
||||
if( !isJBRSupported )
|
||||
windowResizer = createWindowResizer();
|
||||
}
|
||||
|
||||
protected void uninstallClientDecorations() {
|
||||
LookAndFeel.uninstallBorder( rootPane );
|
||||
setTitlePane( null );
|
||||
|
||||
if( windowResizer != null ) {
|
||||
windowResizer.uninstall();
|
||||
windowResizer = null;
|
||||
}
|
||||
|
||||
if( oldLayout != null ) {
|
||||
rootPane.setLayout( oldLayout );
|
||||
oldLayout = null;
|
||||
}
|
||||
|
||||
if( rootPane.getWindowDecorationStyle() == JRootPane.NONE ) {
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
protected FlatRootLayout createRootLayout() {
|
||||
return new FlatRootLayout();
|
||||
}
|
||||
|
||||
protected FlatWindowResizer createWindowResizer() {
|
||||
return new FlatWindowResizer.WindowResizer( rootPane );
|
||||
}
|
||||
|
||||
protected FlatTitlePane createTitlePane() {
|
||||
return new FlatTitlePane( rootPane );
|
||||
}
|
||||
|
||||
// layer title pane under frame content layer to allow placing menu bar over title pane
|
||||
protected final static Integer TITLE_PANE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 1;
|
||||
|
||||
protected void setTitlePane( FlatTitlePane newTitlePane ) {
|
||||
JLayeredPane layeredPane = rootPane.getLayeredPane();
|
||||
|
||||
if( titlePane != null )
|
||||
layeredPane.remove( titlePane );
|
||||
|
||||
if( newTitlePane != null )
|
||||
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
|
||||
|
||||
titlePane = newTitlePane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "windowDecorationStyle":
|
||||
uninstallClientDecorations();
|
||||
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
|
||||
installClientDecorations();
|
||||
else
|
||||
installBorder();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MENU_BAR_EMBEDDED:
|
||||
if( titlePane != null ) {
|
||||
titlePane.menuBarChanged();
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatRootLayout -----------------------------------------------
|
||||
|
||||
protected class FlatRootLayout
|
||||
implements LayoutManager2
|
||||
{
|
||||
@Override public void addLayoutComponent( String name, Component comp ) {}
|
||||
@Override public void addLayoutComponent( Component comp, Object constraints ) {}
|
||||
@Override public void removeLayoutComponent( Component comp ) {}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize( Container parent ) {
|
||||
return computeLayoutSize( parent, c -> c.getPreferredSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize( Container parent ) {
|
||||
return computeLayoutSize( parent, c -> c.getMinimumSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension maximumLayoutSize( Container parent ) {
|
||||
return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
|
||||
}
|
||||
|
||||
private Dimension computeLayoutSize( Container parent, Function<Component, Dimension> getSizeFunc ) {
|
||||
JRootPane rootPane = (JRootPane) parent;
|
||||
|
||||
Dimension titlePaneSize = (titlePane != null)
|
||||
? getSizeFunc.apply( titlePane )
|
||||
: new Dimension();
|
||||
Dimension contentSize = (rootPane.getContentPane() != null)
|
||||
? getSizeFunc.apply( rootPane.getContentPane() )
|
||||
: rootPane.getSize();
|
||||
|
||||
int width = Math.max( titlePaneSize.width, contentSize.width );
|
||||
int height = titlePaneSize.height + contentSize.height;
|
||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
Dimension menuBarSize = (menuBar != null && menuBar.isVisible())
|
||||
? getSizeFunc.apply( menuBar )
|
||||
: new Dimension();
|
||||
|
||||
width = Math.max( width, menuBarSize.width );
|
||||
height += menuBarSize.height;
|
||||
}
|
||||
|
||||
Insets insets = rootPane.getInsets();
|
||||
|
||||
return new Dimension(
|
||||
width + insets.left + insets.right,
|
||||
height + insets.top + insets.bottom );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer( Container parent ) {
|
||||
JRootPane rootPane = (JRootPane) parent;
|
||||
boolean isFullScreen = FlatUIUtils.isFullScreen( rootPane );
|
||||
|
||||
Insets insets = rootPane.getInsets();
|
||||
int x = insets.left;
|
||||
int y = insets.top;
|
||||
int width = rootPane.getWidth() - insets.left - insets.right;
|
||||
int height = rootPane.getHeight() - insets.top - insets.bottom;
|
||||
|
||||
if( rootPane.getLayeredPane() != null )
|
||||
rootPane.getLayeredPane().setBounds( x, y, width, height );
|
||||
if( rootPane.getGlassPane() != null )
|
||||
rootPane.getGlassPane().setBounds( x, y, width, height );
|
||||
|
||||
int nextY = 0;
|
||||
if( !isFullScreen && titlePane != null ) {
|
||||
Dimension prefSize = titlePane.getPreferredSize();
|
||||
titlePane.setBounds( 0, 0, width, prefSize.height );
|
||||
nextY += prefSize.height;
|
||||
}
|
||||
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
if( menuBar != null && menuBar.isVisible() ) {
|
||||
if( !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded() ) {
|
||||
titlePane.validate();
|
||||
menuBar.setBounds( titlePane.getMenuBarBounds() );
|
||||
} else {
|
||||
Dimension prefSize = menuBar.getPreferredSize();
|
||||
menuBar.setBounds( 0, nextY, width, prefSize.height );
|
||||
nextY += prefSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
Container contentPane = rootPane.getContentPane();
|
||||
if( contentPane != null )
|
||||
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
|
||||
|
||||
if( titlePane != null )
|
||||
titlePane.menuBarLayouted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateLayout( Container parent ) {
|
||||
if( titlePane != null )
|
||||
titlePane.menuBarChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentX( Container target ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentY( Container target ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatWindowBorder ---------------------------------------------
|
||||
|
||||
public static class FlatWindowBorder
|
||||
extends BorderUIResource.EmptyBorderUIResource
|
||||
{
|
||||
protected final Color activeBorderColor = UIManager.getColor( "RootPane.activeBorderColor" );
|
||||
protected final Color inactiveBorderColor = UIManager.getColor( "RootPane.inactiveBorderColor" );
|
||||
protected final Color baseBorderColor = UIManager.getColor( "Panel.background" );
|
||||
|
||||
public FlatWindowBorder() {
|
||||
super( 1, 1, 1, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
if( isWindowMaximized( c ) || FlatUIUtils.isFullScreen( c ) ) {
|
||||
// hide border if window is maximized
|
||||
insets.top = insets.left = insets.bottom = insets.right = 0;
|
||||
return insets;
|
||||
} else
|
||||
return super.getBorderInsets( c, insets );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( isWindowMaximized( c ) || FlatUIUtils.isFullScreen( c ) )
|
||||
return;
|
||||
|
||||
Container parent = c.getParent();
|
||||
boolean active = parent instanceof Window ? ((Window)parent).isActive() : false;
|
||||
|
||||
g.setColor( FlatUIUtils.deriveColor( active ? activeBorderColor : inactiveBorderColor, baseBorderColor ) );
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||
}
|
||||
|
||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||
g.drawRect( x, y, width - 1, height - 1 );
|
||||
}
|
||||
|
||||
protected boolean isWindowMaximized( Component c ) {
|
||||
Container parent = c.getParent();
|
||||
return parent instanceof Frame
|
||||
? (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatWindowTitleBorder ----------------------------------------
|
||||
|
||||
private static class FlatWindowTitleBorder
|
||||
extends BorderUIResource.EmptyBorderUIResource
|
||||
{
|
||||
private final Color borderColor;
|
||||
|
||||
FlatWindowTitleBorder( Color borderColor ) {
|
||||
super( 0, 0, 0, 0 );
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( showBorder( c ) ) {
|
||||
float lineHeight = UIScale.scale( (float) 1 );
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y, width, lineHeight );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
insets.set( showBorder( c ) ? 1 : 0, 0, 0, 0 );
|
||||
return insets;
|
||||
}
|
||||
|
||||
private boolean showBorder( Component c ) {
|
||||
Container parent = c.getParent();
|
||||
return
|
||||
(parent instanceof JFrame &&
|
||||
(((JFrame)parent).getJMenuBar() == null ||
|
||||
!((JFrame)parent).getJMenuBar().isVisible())) ||
|
||||
parent instanceof JDialog;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
@@ -33,7 +32,11 @@ public class FlatRoundBorder
|
||||
protected final int arc = UIManager.getInt( "Component.arc" );
|
||||
|
||||
@Override
|
||||
protected float getArc( Component c ) {
|
||||
return scale( (float) arc );
|
||||
protected int getArc( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,15 +19,19 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Objects;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicScrollBarUI;
|
||||
@@ -50,29 +54,49 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatScrollBarUI -->
|
||||
*
|
||||
* @uiDefault ScrollBar.hoverTrackColor Color
|
||||
* @uiDefault ScrollBar.hoverThumbColor Color
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault ScrollBar.trackInsets Insets
|
||||
* @uiDefault ScrollBar.thumbInsets Insets
|
||||
* @uiDefault ScrollBar.trackArc int
|
||||
* @uiDefault ScrollBar.thumbArc int
|
||||
* @uiDefault ScrollBar.hoverTrackColor Color optional
|
||||
* @uiDefault ScrollBar.hoverThumbColor Color optional
|
||||
* @uiDefault ScrollBar.hoverThumbWithTrack boolean
|
||||
* @uiDefault ScrollBar.pressedTrackColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbColor Color optional
|
||||
* @uiDefault ScrollBar.pressedThumbWithTrack boolean
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault ScrollBar.showButtons boolean
|
||||
* @uiDefault ScrollBar.buttonArrowColor Color
|
||||
* @uiDefault ScrollBar.buttonDisabledArrowColor Color
|
||||
* @uiDefault ScrollBar.hoverButtonBackground Color optional
|
||||
* @uiDefault ScrollBar.pressedButtonBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatScrollBarUI
|
||||
extends BasicScrollBarUI
|
||||
{
|
||||
protected Insets trackInsets;
|
||||
protected Insets thumbInsets;
|
||||
protected int trackArc;
|
||||
protected int thumbArc;
|
||||
protected Color hoverTrackColor;
|
||||
protected Color hoverThumbColor;
|
||||
protected boolean hoverThumbWithTrack;
|
||||
protected Color pressedTrackColor;
|
||||
protected Color pressedThumbColor;
|
||||
protected boolean pressedThumbWithTrack;
|
||||
|
||||
protected boolean showButtons;
|
||||
protected String arrowType;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color hoverButtonBackground;
|
||||
protected Color pressedButtonBackground;
|
||||
|
||||
private MouseAdapter hoverListener;
|
||||
private boolean hoverTrack;
|
||||
private boolean hoverThumb;
|
||||
protected boolean hoverTrack;
|
||||
protected boolean hoverThumb;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatScrollBarUI();
|
||||
@@ -100,24 +124,46 @@ public class FlatScrollBarUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
|
||||
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
|
||||
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
|
||||
thumbArc = UIManager.getInt( "ScrollBar.thumbArc" );
|
||||
hoverTrackColor = UIManager.getColor( "ScrollBar.hoverTrackColor" );
|
||||
hoverThumbColor = UIManager.getColor( "ScrollBar.hoverThumbColor" );
|
||||
hoverThumbWithTrack = UIManager.getBoolean( "ScrollBar.hoverThumbWithTrack" );
|
||||
pressedTrackColor = UIManager.getColor( "ScrollBar.pressedTrackColor" );
|
||||
pressedThumbColor = UIManager.getColor( "ScrollBar.pressedThumbColor" );
|
||||
pressedThumbWithTrack = UIManager.getBoolean( "ScrollBar.pressedThumbWithTrack" );
|
||||
|
||||
showButtons = UIManager.getBoolean( "ScrollBar.showButtons" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
buttonArrowColor = UIManager.getColor( "ScrollBar.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ScrollBar.buttonDisabledArrowColor" );
|
||||
hoverButtonBackground = UIManager.getColor( "ScrollBar.hoverButtonBackground" );
|
||||
pressedButtonBackground = UIManager.getColor( "ScrollBar.pressedButtonBackground" );
|
||||
|
||||
// fallback (e.g. when used in NetBeans GUI builder)
|
||||
if( trackInsets == null )
|
||||
trackInsets = new Insets( 0, 0, 0, 0 );
|
||||
if( thumbInsets == null )
|
||||
thumbInsets = new Insets( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
trackInsets = null;
|
||||
thumbInsets = null;
|
||||
hoverTrackColor = null;
|
||||
hoverThumbColor = null;
|
||||
pressedTrackColor = null;
|
||||
pressedThumbColor = null;
|
||||
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
hoverButtonBackground = null;
|
||||
pressedButtonBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,9 +173,24 @@ public class FlatScrollBarUI
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
if( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS.equals( e.getPropertyName() ) ) {
|
||||
scrollbar.revalidate();
|
||||
scrollbar.repaint();
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS:
|
||||
scrollbar.revalidate();
|
||||
scrollbar.repaint();
|
||||
break;
|
||||
|
||||
case "componentOrientation":
|
||||
// this is missing in BasicScrollBarUI.Handler.propertyChange()
|
||||
InputMap inputMap = (InputMap) UIManager.get( "ScrollBar.ancestorInputMap" );
|
||||
if( !scrollbar.getComponentOrientation().isLeftToRight() ) {
|
||||
InputMap rtlInputMap = (InputMap) UIManager.get( "ScrollBar.ancestorInputMap.RightToLeft" );
|
||||
if( rtlInputMap != null ) {
|
||||
rtlInputMap.setParent( inputMap );
|
||||
inputMap = rtlInputMap;
|
||||
}
|
||||
}
|
||||
SwingUtilities.replaceUIInputMap( scrollbar, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap );
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -142,50 +203,62 @@ public class FlatScrollBarUI
|
||||
|
||||
@Override
|
||||
protected JButton createDecreaseButton( int orientation ) {
|
||||
return createArrowButton( orientation );
|
||||
return new FlatScrollBarButton( orientation );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JButton createIncreaseButton( int orientation ) {
|
||||
return createArrowButton( orientation );
|
||||
return new FlatScrollBarButton( orientation );
|
||||
}
|
||||
|
||||
private JButton createArrowButton( int orientation ) {
|
||||
FlatArrowButton button = new FlatArrowButton( orientation,
|
||||
arrowType, buttonArrowColor, buttonDisabledArrowColor, null, hoverTrackColor )
|
||||
{
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if( isShowButtons() ) {
|
||||
int w = UIScale.scale( scrollBarWidth );
|
||||
return new Dimension( w, w );
|
||||
} else
|
||||
return new Dimension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return isShowButtons() ? super.getMinimumSize() : new Dimension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return isShowButtons() ? super.getMaximumSize() : new Dimension();
|
||||
}
|
||||
};
|
||||
button.setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
|
||||
button.setFocusable( false );
|
||||
button.setRequestFocusEnabled( false );
|
||||
return button;
|
||||
}
|
||||
|
||||
private boolean isShowButtons() {
|
||||
protected boolean isShowButtons() {
|
||||
Object showButtons = scrollbar.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
|
||||
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane )
|
||||
showButtons = ((JScrollPane)scrollbar.getParent()).getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
|
||||
return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
super.paint( g, c );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
|
||||
g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) );
|
||||
paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) {
|
||||
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() )
|
||||
return;
|
||||
|
||||
g.setColor( getThumbColor( c, hoverThumb || (hoverThumbWithTrack && hoverTrack),
|
||||
isPressed && (hoverThumb || (pressedThumbWithTrack && hoverTrack)) ) );
|
||||
paintTrackOrThumb( g, c, thumbBounds, thumbInsets, thumbArc );
|
||||
}
|
||||
|
||||
protected void paintTrackOrThumb( Graphics g, JComponent c, Rectangle bounds, Insets insets, int arc ) {
|
||||
// rotate insets for horizontal orientation because they are given for vertical orientation
|
||||
if( scrollbar.getOrientation() == JScrollBar.HORIZONTAL )
|
||||
insets = new Insets( insets.right, insets.top, insets.left, insets.bottom );
|
||||
|
||||
// subtract insets from bounds
|
||||
bounds = FlatUIUtils.subtractInsets( bounds, UIScale.scale( insets ) );
|
||||
|
||||
if( arc <= 0 ) {
|
||||
// paint rectangle
|
||||
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
} else {
|
||||
// paint round rectangle
|
||||
arc = Math.min( UIScale.scale( arc ), Math.min( bounds.width, bounds.height ) );
|
||||
g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, arc, arc );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintDecreaseHighlight( Graphics g ) {
|
||||
// do not paint
|
||||
@@ -196,29 +269,33 @@ public class FlatScrollBarUI
|
||||
// do not paint
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
|
||||
g.setColor( hoverTrack ? hoverTrackColor : trackColor );
|
||||
g.fillRect( trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height );
|
||||
protected Color getTrackColor( JComponent c, boolean hover, boolean pressed ) {
|
||||
Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
|
||||
return (pressed && pressedTrackColor != null)
|
||||
? FlatUIUtils.deriveColor( pressedTrackColor, trackColor )
|
||||
: ((hover && hoverTrackColor != null)
|
||||
? FlatUIUtils.deriveColor( hoverTrackColor, trackColor )
|
||||
: trackColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) {
|
||||
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() )
|
||||
return;
|
||||
|
||||
g.setColor( hoverThumb ? hoverThumbColor : thumbColor );
|
||||
g.fillRect( thumbBounds.x, thumbBounds.y, thumbBounds.width, thumbBounds.height );
|
||||
protected Color getThumbColor( JComponent c, boolean hover, boolean pressed ) {
|
||||
Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
|
||||
Color thumbColor = FlatUIUtils.deriveColor( this.thumbColor, trackColor );
|
||||
return (pressed && pressedThumbColor != null)
|
||||
? FlatUIUtils.deriveColor( pressedThumbColor, thumbColor )
|
||||
: ((hover && hoverThumbColor != null)
|
||||
? FlatUIUtils.deriveColor( hoverThumbColor, thumbColor )
|
||||
: thumbColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getMinimumThumbSize() {
|
||||
return UIScale.scale( super.getMinimumThumbSize() );
|
||||
return UIScale.scale( FlatUIUtils.addInsets( super.getMinimumThumbSize(), thumbInsets ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getMaximumThumbSize() {
|
||||
return UIScale.scale( super.getMaximumThumbSize() );
|
||||
return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) );
|
||||
}
|
||||
|
||||
//---- class ScrollBarHoverListener ---------------------------------------
|
||||
@@ -246,11 +323,14 @@ public class FlatScrollBarUI
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
isPressed = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isPressed = false;
|
||||
repaint();
|
||||
|
||||
update( e.getX(), e.getY() );
|
||||
}
|
||||
|
||||
@@ -269,4 +349,50 @@ public class FlatScrollBarUI
|
||||
scrollbar.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatScrollBarButton ------------------------------------------
|
||||
|
||||
protected class FlatScrollBarButton
|
||||
extends FlatArrowButton
|
||||
{
|
||||
protected FlatScrollBarButton( int direction ) {
|
||||
this( direction, arrowType, buttonArrowColor, buttonDisabledArrowColor,
|
||||
null, hoverButtonBackground, null, pressedButtonBackground );
|
||||
}
|
||||
|
||||
protected FlatScrollBarButton( int direction, String type, Color foreground, Color disabledForeground,
|
||||
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
|
||||
{
|
||||
super( direction, type, foreground, disabledForeground,
|
||||
hoverForeground, hoverBackground, pressedForeground, pressedBackground );
|
||||
|
||||
setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
|
||||
setFocusable( false );
|
||||
setRequestFocusEnabled( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color deriveBackground( Color background ) {
|
||||
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if( isShowButtons() ) {
|
||||
int w = UIScale.scale( scrollBarWidth );
|
||||
return new Dimension( w, w );
|
||||
} else
|
||||
return new Dimension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return isShowButtons() ? super.getMinimumSize() : new Dimension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return isShowButtons() ? super.getMaximumSize() : new Dimension();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Smooth scrolling code partly based on code from IntelliJ IDEA Community Edition,
|
||||
* which is licensed under the Apache 2.0 license. Copyright 2000-2016 JetBrains s.r.o.
|
||||
* See: https://github.com/JetBrains/intellij-community/blob/31e1b5a8e43219b9571951bab6457cfb3012e3ef/platform/platform-api/src/com/intellij/ui/components/SmoothScrollPane.java#L141-L185
|
||||
*
|
||||
*/
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
@@ -83,7 +77,7 @@ public class FlatScrollPaneUI
|
||||
int focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
|
||||
|
||||
MigLayoutVisualPadding.install( scrollpane, focusWidth );
|
||||
MigLayoutVisualPadding.install( scrollpane );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,10 +108,7 @@ public class FlatScrollPaneUI
|
||||
return new BasicScrollPaneUI.MouseWheelHandler() {
|
||||
@Override
|
||||
public void mouseWheelMoved( MouseWheelEvent e ) {
|
||||
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow
|
||||
// applications to turn smooth scrolling on or off at any time
|
||||
// (e.g. in application options dialog).
|
||||
if( UIManager.getBoolean( "ScrollPane.smoothScrolling" ) &&
|
||||
if( isSmoothScrollingEnabled() &&
|
||||
scrollpane.isWheelScrollingEnabled() &&
|
||||
e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL &&
|
||||
e.getPreciseWheelRotation() != 0 &&
|
||||
@@ -130,7 +121,16 @@ public class FlatScrollPaneUI
|
||||
};
|
||||
}
|
||||
|
||||
private static final double EPSILON = 1e-5d;
|
||||
protected boolean isSmoothScrollingEnabled() {
|
||||
Object smoothScrolling = scrollpane.getClientProperty( FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING );
|
||||
if( smoothScrolling instanceof Boolean )
|
||||
return (Boolean) smoothScrolling;
|
||||
|
||||
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow
|
||||
// applications to turn smooth scrolling on or off at any time
|
||||
// (e.g. in application options dialog).
|
||||
return UIManager.getBoolean( "ScrollPane.smoothScrolling" );
|
||||
}
|
||||
|
||||
private void mouseWheelMovedSmooth( MouseWheelEvent e ) {
|
||||
// return if there is no viewport
|
||||
@@ -152,24 +152,22 @@ public class FlatScrollPaneUI
|
||||
// get precise wheel rotation
|
||||
double rotation = e.getPreciseWheelRotation();
|
||||
|
||||
// get unit and block increment
|
||||
// get unit increment
|
||||
int unitIncrement;
|
||||
int blockIncrement;
|
||||
int orientation = scrollbar.getOrientation();
|
||||
Component view = viewport.getView();
|
||||
if( view instanceof Scrollable ) {
|
||||
Scrollable scrollable = (Scrollable) view;
|
||||
|
||||
// Use (0, 0) view position to obtain constant unit increment of first item
|
||||
// (which might otherwise be variable on smaller-than-unit scrolling).
|
||||
// Use (0, 0) view position to obtain a constant unit increment of first item.
|
||||
// Unit increment may be different for each item.
|
||||
Rectangle visibleRect = new Rectangle( viewport.getViewSize() );
|
||||
unitIncrement = scrollable.getScrollableUnitIncrement( visibleRect, orientation, 1 );
|
||||
blockIncrement = scrollable.getScrollableBlockIncrement( visibleRect, orientation, 1 );
|
||||
|
||||
if( unitIncrement > 0 ) {
|
||||
// For the case that the first item (e.g. in a list) is larger
|
||||
// than the other items, get the unit increment of the second item
|
||||
// and use the smaller one.
|
||||
// than the other items (e.g. themes list in FlatLaf Demo),
|
||||
// get the unit increment of the second item and use the smaller one.
|
||||
if( orientation == SwingConstants.VERTICAL ) {
|
||||
visibleRect.y += unitIncrement;
|
||||
visibleRect.height -= unitIncrement;
|
||||
@@ -184,52 +182,58 @@ public class FlatScrollPaneUI
|
||||
} else {
|
||||
int direction = rotation < 0 ? -1 : 1;
|
||||
unitIncrement = scrollbar.getUnitIncrement( direction );
|
||||
blockIncrement = scrollbar.getBlockIncrement( direction );
|
||||
}
|
||||
|
||||
// limit scroll amount (number of units to scroll) for small viewports
|
||||
// (e.g. vertical scrolling in file chooser)
|
||||
int scrollAmount = e.getScrollAmount();
|
||||
// get viewport width/height (the visible width/height)
|
||||
int viewportWH = (orientation == SwingConstants.VERTICAL)
|
||||
? viewport.getHeight()
|
||||
: viewport.getWidth();
|
||||
if( unitIncrement * scrollAmount > viewportWH )
|
||||
scrollAmount = Math.max( viewportWH / unitIncrement, 1 );
|
||||
|
||||
// limit scroll increment to viewport width/height
|
||||
// - if scroll amount is set to a large value in OS settings
|
||||
// - for large unit increments in small viewports (e.g. horizontal scrolling in file chooser)
|
||||
int scrollIncrement = Math.min( unitIncrement * e.getScrollAmount(), viewportWH );
|
||||
|
||||
// compute relative delta
|
||||
double delta = rotation * scrollAmount * unitIncrement;
|
||||
boolean adjustDelta = Math.abs( rotation ) < (1.0 + EPSILON);
|
||||
double adjustedDelta = adjustDelta
|
||||
? Math.max( -blockIncrement, Math.min( delta, blockIncrement ) )
|
||||
: delta;
|
||||
double delta = rotation * scrollIncrement;
|
||||
int idelta = (int) Math.round( delta );
|
||||
|
||||
// scroll at least one pixel to avoid "hanging"
|
||||
// - for "super-low-speed" scrolling (move fingers very slowly on trackpad)
|
||||
// - if unit increment is very small (e.g. 1 if scroll view does not implement
|
||||
// javax.swing.Scrollable interface)
|
||||
if( idelta == 0 ) {
|
||||
if( rotation > 0 )
|
||||
idelta = 1;
|
||||
else if( rotation < 0 )
|
||||
idelta = -1;
|
||||
}
|
||||
|
||||
// compute new value
|
||||
int value = scrollbar.getValue();
|
||||
double minDelta = scrollbar.getMinimum() - value;
|
||||
double maxDelta = scrollbar.getMaximum() - scrollbar.getModel().getExtent() - value;
|
||||
double boundedDelta = Math.max( minDelta, Math.min( adjustedDelta, maxDelta ) );
|
||||
int newValue = value + (int) Math.round( boundedDelta );
|
||||
int minValue = scrollbar.getMinimum();
|
||||
int maxValue = scrollbar.getMaximum() - scrollbar.getModel().getExtent();
|
||||
int newValue = Math.max( minValue, Math.min( value + idelta, maxValue ) );
|
||||
|
||||
// set new value
|
||||
if( newValue != value )
|
||||
scrollbar.setValue( newValue );
|
||||
|
||||
/*debug
|
||||
System.out.println( String.format( "%4d %9f / %4d %4d / %12f %5s %12f / %4d %4d %4d / %12f %12f %12f / %4d",
|
||||
System.out.println( String.format( "%s %4d %9f / %3d * %d = %3d [%3d] / %8.2f %5d / %4d --> %4d [%d, %d]",
|
||||
(orientation == SwingConstants.VERTICAL) ? "V" : "H",
|
||||
e.getWheelRotation(),
|
||||
e.getPreciseWheelRotation(),
|
||||
unitIncrement,
|
||||
blockIncrement,
|
||||
e.getScrollAmount(),
|
||||
scrollIncrement,
|
||||
viewportWH,
|
||||
delta,
|
||||
adjustDelta,
|
||||
adjustedDelta,
|
||||
idelta,
|
||||
value,
|
||||
scrollbar.getMinimum(),
|
||||
scrollbar.getMaximum(),
|
||||
minDelta,
|
||||
maxDelta,
|
||||
boundedDelta,
|
||||
newValue ) );
|
||||
newValue,
|
||||
minValue,
|
||||
maxValue ) );
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,8 @@ public class FlatSeparatorUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static ComponentUI instance;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
if( instance == null )
|
||||
instance = new FlatSeparatorUI();
|
||||
return instance;
|
||||
return FlatUIUtils.createSharedUI( FlatSeparatorUI.class, FlatSeparatorUI::new );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,17 +18,23 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSliderUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -49,29 +55,49 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* <!-- FlatSliderUI -->
|
||||
*
|
||||
* @uiDefault Slider.trackWidth int
|
||||
* @uiDefault Slider.thumbWidth int
|
||||
* @uiDefault Slider.thumbSize Dimension
|
||||
* @uiDefault Slider.focusWidth int
|
||||
* @uiDefault Slider.trackValueColor Color optional; defaults to Slider.thumbColor
|
||||
* @uiDefault Slider.trackColor Color
|
||||
* @uiDefault Slider.thumbColor Color
|
||||
* @uiDefault Slider.thumbBorderColor Color optional; if null, no border is painted
|
||||
* @uiDefault Slider.focusedColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault Slider.hoverColor Color optional; defaults to Slider.focusedColor
|
||||
* @uiDefault Slider.disabledForeground Color used for track and thumb is disabled
|
||||
* @uiDefault Slider.focusedThumbBorderColor Color optional; defaults to Component.focusedBorderColor
|
||||
* @uiDefault Slider.hoverThumbColor Color optional
|
||||
* @uiDefault Slider.pressedThumbColor Color optional
|
||||
* @uiDefault Slider.disabledTrackColor Color
|
||||
* @uiDefault Slider.disabledThumbColor Color
|
||||
* @uiDefault Slider.disabledThumbBorderColor Color optional; defaults to Component.disabledBorderColor
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatSliderUI
|
||||
extends BasicSliderUI
|
||||
{
|
||||
private int trackWidth;
|
||||
private int thumbWidth;
|
||||
protected int trackWidth;
|
||||
protected Dimension thumbSize;
|
||||
protected int focusWidth;
|
||||
|
||||
private Color trackColor;
|
||||
private Color thumbColor;
|
||||
private Color focusColor;
|
||||
private Color hoverColor;
|
||||
private Color disabledForeground;
|
||||
protected Color trackValueColor;
|
||||
protected Color trackColor;
|
||||
protected Color thumbColor;
|
||||
protected Color thumbBorderColor;
|
||||
protected Color focusBaseColor;
|
||||
protected Color focusedColor;
|
||||
protected Color focusedThumbBorderColor;
|
||||
protected Color hoverThumbColor;
|
||||
protected Color pressedThumbColor;
|
||||
protected Color disabledTrackColor;
|
||||
protected Color disabledThumbColor;
|
||||
protected Color disabledThumbBorderColor;
|
||||
|
||||
private MouseListener hoverListener;
|
||||
private boolean hover;
|
||||
private Color defaultBackground;
|
||||
private Color defaultForeground;
|
||||
|
||||
protected boolean thumbHover;
|
||||
protected boolean thumbPressed;
|
||||
|
||||
private Object[] oldRenderingHints;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSliderUI();
|
||||
@@ -81,24 +107,6 @@ public class FlatSliderUI
|
||||
super( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners( JSlider slider ) {
|
||||
super.installListeners( slider );
|
||||
|
||||
hoverListener = new FlatUIUtils.HoverListener( slider, h -> {
|
||||
hover = h;
|
||||
} );
|
||||
slider.addMouseListener( hoverListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JSlider slider ) {
|
||||
super.uninstallListeners( slider );
|
||||
|
||||
slider.removeMouseListener( hoverListener );
|
||||
hoverListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults( JSlider slider ) {
|
||||
super.installDefaults( slider );
|
||||
@@ -106,24 +114,71 @@ public class FlatSliderUI
|
||||
LookAndFeel.installProperty( slider, "opaque", false );
|
||||
|
||||
trackWidth = UIManager.getInt( "Slider.trackWidth" );
|
||||
thumbWidth = UIManager.getInt( "Slider.thumbWidth" );
|
||||
thumbSize = UIManager.getDimension( "Slider.thumbSize" );
|
||||
if( thumbSize == null ) {
|
||||
// fallback for compatibility with old versions
|
||||
int thumbWidth = UIManager.getInt( "Slider.thumbWidth" );
|
||||
thumbSize = new Dimension( thumbWidth, thumbWidth );
|
||||
}
|
||||
focusWidth = FlatUIUtils.getUIInt( "Slider.focusWidth", 4 );
|
||||
|
||||
trackValueColor = FlatUIUtils.getUIColor( "Slider.trackValueColor", "Slider.thumbColor" );
|
||||
trackColor = UIManager.getColor( "Slider.trackColor" );
|
||||
thumbColor = UIManager.getColor( "Slider.thumbColor" );
|
||||
focusColor = FlatUIUtils.getUIColor( "Slider.focusedColor", "Component.focusColor" );
|
||||
hoverColor = FlatUIUtils.getUIColor( "Slider.hoverColor", focusColor );
|
||||
disabledForeground = UIManager.getColor( "Slider.disabledForeground" );
|
||||
thumbBorderColor = UIManager.getColor( "Slider.thumbBorderColor" );
|
||||
focusBaseColor = UIManager.getColor( "Component.focusColor" );
|
||||
focusedColor = FlatUIUtils.getUIColor( "Slider.focusedColor", focusBaseColor );
|
||||
focusedThumbBorderColor = FlatUIUtils.getUIColor( "Slider.focusedThumbBorderColor", "Component.focusedBorderColor" );
|
||||
hoverThumbColor = UIManager.getColor( "Slider.hoverThumbColor" );
|
||||
pressedThumbColor = UIManager.getColor( "Slider.pressedThumbColor" );
|
||||
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
|
||||
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
|
||||
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
|
||||
|
||||
defaultBackground = UIManager.getColor( "Slider.background" );
|
||||
defaultForeground = UIManager.getColor( "Slider.foreground" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults( JSlider slider ) {
|
||||
super.uninstallDefaults( slider );
|
||||
|
||||
trackValueColor = null;
|
||||
trackColor = null;
|
||||
thumbColor = null;
|
||||
focusColor = null;
|
||||
hoverColor = null;
|
||||
disabledForeground = null;
|
||||
thumbBorderColor = null;
|
||||
focusBaseColor = null;
|
||||
focusedColor = null;
|
||||
focusedThumbBorderColor = null;
|
||||
hoverThumbColor = null;
|
||||
pressedThumbColor = null;
|
||||
disabledTrackColor = null;
|
||||
disabledThumbColor = null;
|
||||
disabledThumbBorderColor = null;
|
||||
|
||||
defaultBackground = null;
|
||||
defaultForeground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrackListener createTrackListener( JSlider slider ) {
|
||||
return new FlatTrackListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline( JComponent c, int width, int height ) {
|
||||
if( c == null )
|
||||
throw new NullPointerException();
|
||||
if( width < 0 || height < 0 )
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
// no baseline for vertical orientation
|
||||
if( slider.getOrientation() == JSlider.VERTICAL )
|
||||
return -1;
|
||||
|
||||
// compute a baseline so that the track is vertically centered
|
||||
FontMetrics fm = slider.getFontMetrics( slider.getFont() );
|
||||
return trackRect.y + Math.round( (trackRect.height - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,14 +208,50 @@ public class FlatSliderUI
|
||||
|
||||
@Override
|
||||
protected Dimension getThumbSize() {
|
||||
return new Dimension( UIScale.scale( thumbWidth ), UIScale.scale( thumbWidth ) );
|
||||
return calcThumbSize( slider, thumbSize, focusWidth );
|
||||
}
|
||||
|
||||
public static Dimension calcThumbSize( JSlider slider, Dimension thumbSize, int focusWidth ) {
|
||||
int fw = UIScale.scale( focusWidth );
|
||||
int w = UIScale.scale( thumbSize.width ) + fw + fw;
|
||||
int h = UIScale.scale( thumbSize.height ) + fw + fw;
|
||||
return (slider.getOrientation() == JSlider.HORIZONTAL)
|
||||
? new Dimension( w, h )
|
||||
: new Dimension( h, w );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
FlatUIUtils.setRenderingHints( (Graphics2D) g );
|
||||
oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
/*debug
|
||||
g.setColor( Color.gray );
|
||||
g.drawRect( 0, 0, c.getWidth() - 1, c.getHeight() - 1 );
|
||||
g.setColor( Color.orange );
|
||||
g.drawRect( focusRect.x, focusRect.y, focusRect.width - 1, focusRect.height - 1 );
|
||||
g.setColor( Color.magenta );
|
||||
g.drawRect( contentRect.x, contentRect.y, contentRect.width - 1, contentRect.height - 1 );
|
||||
g.setColor( Color.blue );
|
||||
g.drawRect( trackRect.x, trackRect.y, trackRect.width - 1, trackRect.height - 1 );
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( thumbRect.x, thumbRect.y, thumbRect.width - 1, thumbRect.height - 1 );
|
||||
g.setColor( Color.green );
|
||||
g.drawRect( tickRect.x, tickRect.y, tickRect.width - 1, tickRect.height - 1 );
|
||||
g.setColor( Color.red );
|
||||
g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
|
||||
debug*/
|
||||
|
||||
super.paint( g, c );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
oldRenderingHints = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintLabels( Graphics g ) {
|
||||
FlatUIUtils.runWithoutRenderingHints( g, oldRenderingHints, () -> {
|
||||
super.paintLabels( g );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,50 +292,326 @@ public class FlatSliderUI
|
||||
}
|
||||
|
||||
if( coloredTrack != null ) {
|
||||
FlatUIUtils.setColor( g, slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor), thumbColor );
|
||||
if( slider.getInverted() ) {
|
||||
RoundRectangle2D temp = track;
|
||||
track = coloredTrack;
|
||||
coloredTrack = temp;
|
||||
}
|
||||
|
||||
g.setColor( getTrackValueColor() );
|
||||
((Graphics2D)g).fill( coloredTrack );
|
||||
}
|
||||
|
||||
g.setColor( enabled ? trackColor : disabledForeground );
|
||||
g.setColor( enabled ? getTrackColor() : disabledTrackColor );
|
||||
((Graphics2D)g).fill( track );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintThumb( Graphics g ) {
|
||||
FlatUIUtils.setColor( g, slider.isEnabled()
|
||||
? (slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor))
|
||||
: disabledForeground,
|
||||
thumbColor );
|
||||
Color thumbColor = getThumbColor();
|
||||
Color color = stateColor( slider, thumbHover, thumbPressed,
|
||||
thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor );
|
||||
color = FlatUIUtils.deriveColor( color, thumbColor );
|
||||
|
||||
if( isRoundThumb() )
|
||||
g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height );
|
||||
else {
|
||||
double w = thumbRect.width;
|
||||
double h = thumbRect.height;
|
||||
double wh = w / 2;
|
||||
Color foreground = slider.getForeground();
|
||||
Color borderColor = (thumbBorderColor != null && foreground == defaultForeground)
|
||||
? stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null )
|
||||
: null;
|
||||
|
||||
Path2D thumb = FlatUIUtils.createPath( 0,0, w,0, w,(h - wh), wh,h, 0,(h - wh) );
|
||||
Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor,
|
||||
(foreground != defaultForeground) ? foreground : focusBaseColor );
|
||||
|
||||
paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth );
|
||||
}
|
||||
|
||||
public static void paintThumb( Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb,
|
||||
Color thumbColor, Color thumbBorderColor, Color focusedColor, int focusWidth )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintThumbImpl( g, slider, x2, y2, width2, height2,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor,
|
||||
(float) (focusWidth * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintThumbImpl( g, slider, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
roundThumb, thumbColor, thumbBorderColor, focusedColor, focusWidth );
|
||||
|
||||
}
|
||||
|
||||
private static void paintThumbImpl( Graphics g, JSlider slider, int x, int y, int width, int height,
|
||||
boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float focusWidth )
|
||||
{
|
||||
int fw = Math.round( UIScale.scale( focusWidth ) );
|
||||
int tx = x + fw;
|
||||
int ty = y + fw;
|
||||
int tw = width - fw - fw;
|
||||
int th = height - fw - fw;
|
||||
boolean focused = FlatUIUtils.isPermanentFocusOwner( slider );
|
||||
|
||||
if( roundThumb ) {
|
||||
// paint thumb focus border
|
||||
if( focused ) {
|
||||
g.setColor( focusedColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( x, y, width, height ) );
|
||||
}
|
||||
|
||||
if( thumbBorderColor != null ) {
|
||||
// paint thumb border
|
||||
g.setColor( thumbBorderColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
g.setColor( thumbColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx + lw, ty + lw,
|
||||
tw - lw - lw, th - lw - lw ) );
|
||||
} else {
|
||||
// paint thumb background
|
||||
g.setColor( thumbColor );
|
||||
((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
|
||||
}
|
||||
} else {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
g2.translate( thumbRect.x, thumbRect.y );
|
||||
g2.translate( x, y );
|
||||
if( slider.getOrientation() == JSlider.VERTICAL ) {
|
||||
if( slider.getComponentOrientation().isLeftToRight() ) {
|
||||
g2.translate( 0, thumbRect.height );
|
||||
g2.translate( 0, height );
|
||||
g2.rotate( Math.toRadians( 270 ) );
|
||||
} else {
|
||||
g2.translate( thumbRect.width, 0 );
|
||||
g2.translate( width, 0 );
|
||||
g2.rotate( Math.toRadians( 90 ) );
|
||||
}
|
||||
|
||||
// rotate thumb width/height
|
||||
int temp = tw;
|
||||
tw = th;
|
||||
th = temp;
|
||||
}
|
||||
|
||||
// paint thumb focus border
|
||||
if( focused ) {
|
||||
g2.setColor( focusedColor );
|
||||
g2.fill( createDirectionalThumbShape( 0, 0,
|
||||
tw + fw + fw, th + fw + fw + (fw * 0.4142f), fw ) );
|
||||
}
|
||||
|
||||
if( thumbBorderColor != null ) {
|
||||
// paint thumb border
|
||||
g2.setColor( thumbBorderColor );
|
||||
g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
|
||||
|
||||
// paint thumb background
|
||||
float lw = UIScale.scale( 1f );
|
||||
g2.setColor( thumbColor );
|
||||
g2.fill( createDirectionalThumbShape( fw + lw, fw + lw,
|
||||
tw - lw - lw, th - lw - lw - (lw * 0.4142f), 0 ) );
|
||||
} else {
|
||||
// paint thumb background
|
||||
g2.setColor( thumbColor );
|
||||
g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
|
||||
}
|
||||
g2.fill( thumb );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRoundThumb() {
|
||||
public static Shape createRoundThumbShape( float x, float y, float w, float h ) {
|
||||
if( w == h )
|
||||
return new Ellipse2D.Float( x, y, w, h );
|
||||
else {
|
||||
float arc = Math.min( w, h );
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
}
|
||||
|
||||
public static Shape createDirectionalThumbShape( float x, float y, float w, float h, float arc ) {
|
||||
float wh = w / 2;
|
||||
|
||||
Path2D path = new Path2D.Float();
|
||||
path.moveTo( x + wh, y + h );
|
||||
path.lineTo( x, y + (h - wh) );
|
||||
path.lineTo( x, y + arc );
|
||||
path.quadTo( x, y, x + arc, y );
|
||||
path.lineTo( x + (w - arc), y );
|
||||
path.quadTo( x + w, y, x + w, y + arc );
|
||||
path.lineTo( x + w, y + (h - wh) );
|
||||
path.closePath();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
protected Color getTrackValueColor() {
|
||||
Color foreground = slider.getForeground();
|
||||
return (foreground != defaultForeground) ? foreground : trackValueColor;
|
||||
}
|
||||
|
||||
protected Color getTrackColor() {
|
||||
Color backround = slider.getBackground();
|
||||
return (backround != defaultBackground) ? backround : trackColor;
|
||||
}
|
||||
|
||||
protected Color getThumbColor() {
|
||||
Color foreground = slider.getForeground();
|
||||
return (foreground != defaultForeground) ? foreground : thumbColor;
|
||||
}
|
||||
|
||||
public static Color stateColor( JSlider slider, boolean hover, boolean pressed,
|
||||
Color enabledColor, Color disabledColor, Color focusedColor, Color hoverColor, Color pressedColor )
|
||||
{
|
||||
if( disabledColor != null && !slider.isEnabled() )
|
||||
return disabledColor;
|
||||
if( pressedColor != null && pressed )
|
||||
return pressedColor;
|
||||
if( hoverColor != null && hover )
|
||||
return hoverColor;
|
||||
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( slider ) )
|
||||
return focusedColor;
|
||||
return enabledColor;
|
||||
}
|
||||
|
||||
protected boolean isRoundThumb() {
|
||||
return !slider.getPaintTicks() && !slider.getPaintLabels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThumbLocation( int x, int y ) {
|
||||
if( !isRoundThumb() ) {
|
||||
// the needle of the directional thumb is painted outside of thumbRect
|
||||
// --> must increase repaint rectangle
|
||||
|
||||
// set new thumb location and compute union of old and new thumb bounds
|
||||
Rectangle r = new Rectangle( thumbRect );
|
||||
thumbRect.setLocation( x, y );
|
||||
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, r );
|
||||
|
||||
// increase union rectangle for repaint
|
||||
int extra = (int) Math.ceil( UIScale.scale( focusWidth ) * 0.4142f );
|
||||
if( slider.getOrientation() == JSlider.HORIZONTAL )
|
||||
r.height += extra;
|
||||
else {
|
||||
r.width += extra;
|
||||
if( !slider.getComponentOrientation().isLeftToRight() )
|
||||
r.x -= extra;
|
||||
}
|
||||
|
||||
slider.repaint( r );
|
||||
} else
|
||||
super.setThumbLocation( x, y );
|
||||
}
|
||||
|
||||
//---- class FlatTrackListener --------------------------------------------
|
||||
|
||||
protected class FlatTrackListener
|
||||
extends TrackListener
|
||||
{
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ) {
|
||||
setThumbHover( isOverThumb( e ) );
|
||||
super.mouseEntered( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
setThumbHover( false );
|
||||
super.mouseExited( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved( MouseEvent e ) {
|
||||
setThumbHover( isOverThumb( e ) );
|
||||
super.mouseMoved( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
setThumbPressed( isOverThumb( e ) );
|
||||
|
||||
if( !slider.isEnabled() )
|
||||
return;
|
||||
|
||||
// use "old" behavior when clicking on track
|
||||
if( UIManager.getBoolean( "Slider.scrollOnTrackClick" ) ) {
|
||||
super.mousePressed( e );
|
||||
return;
|
||||
}
|
||||
|
||||
// "new" behavior set thumb to mouse location when clicking on track
|
||||
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
// clicked on thumb --> let super class do the work
|
||||
calculateGeometry();
|
||||
if( thumbRect.contains( x, y ) ) {
|
||||
super.mousePressed( e );
|
||||
return;
|
||||
}
|
||||
|
||||
if( UIManager.getBoolean( "Slider.onlyLeftMouseButtonDrag" ) &&
|
||||
!SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
// move the mouse event coordinates to the center of the thumb
|
||||
int tx = thumbRect.x + (thumbRect.width / 2) - x;
|
||||
int ty = thumbRect.y + (thumbRect.height / 2) - y;
|
||||
e.translatePoint( tx, ty );
|
||||
|
||||
// invoke super mousePressed() to start dragging thumb
|
||||
super.mousePressed( e );
|
||||
|
||||
// move the mouse event coordinates back to current mouse location
|
||||
e.translatePoint( -tx, -ty );
|
||||
|
||||
// invoke mouseDragged() to update thumb location
|
||||
mouseDragged( e );
|
||||
|
||||
setThumbPressed( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
setThumbPressed( false );
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
super.mouseDragged( e );
|
||||
|
||||
if( isDragging() &&
|
||||
slider.getSnapToTicks() &&
|
||||
slider.isEnabled() &&
|
||||
!UIManager.getBoolean( "Slider.snapToTicksOnReleased" ) )
|
||||
{
|
||||
calculateThumbLocation();
|
||||
slider.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbHover( boolean hover ) {
|
||||
if( hover != thumbHover ) {
|
||||
thumbHover = hover;
|
||||
slider.repaint( thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbPressed( boolean pressed ) {
|
||||
if( pressed != thumbPressed ) {
|
||||
thumbPressed = pressed;
|
||||
slider.repaint( thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isOverThumb( MouseEvent e ) {
|
||||
return e != null && slider.isEnabled() && thumbRect.contains( e.getX(), e.getY() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}.
|
||||
@@ -56,10 +57,9 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
*
|
||||
* <!-- FlatSpinnerUI -->
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.arc int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Spinner.buttonStyle String button (default) or none
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -69,6 +69,7 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
* @uiDefault Spinner.buttonArrowColor Color
|
||||
* @uiDefault Spinner.buttonDisabledArrowColor Color
|
||||
* @uiDefault Spinner.buttonHoverArrowColor Color
|
||||
* @uiDefault Spinner.buttonPressedArrowColor Color
|
||||
* @uiDefault Spinner.padding Insets
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -78,9 +79,8 @@ public class FlatSpinnerUI
|
||||
{
|
||||
private Handler handler;
|
||||
|
||||
protected int focusWidth;
|
||||
protected int arc;
|
||||
protected int minimumWidth;
|
||||
protected String buttonStyle;
|
||||
protected String arrowType;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color borderColor;
|
||||
@@ -91,6 +91,7 @@ public class FlatSpinnerUI
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color buttonHoverArrowColor;
|
||||
protected Color buttonPressedArrowColor;
|
||||
protected Insets padding;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
@@ -103,9 +104,8 @@ public class FlatSpinnerUI
|
||||
|
||||
LookAndFeel.installProperty( spinner, "opaque", false );
|
||||
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
arc = UIManager.getInt( "Component.arc" );
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
|
||||
arrowType = UIManager.getString( "Component.arrowType" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
borderColor = UIManager.getColor( "Component.borderColor" );
|
||||
@@ -116,12 +116,13 @@ public class FlatSpinnerUI
|
||||
buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "Spinner.buttonHoverArrowColor" );
|
||||
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
|
||||
padding = UIManager.getInsets( "Spinner.padding" );
|
||||
|
||||
// scale
|
||||
padding = scale( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( spinner, focusWidth );
|
||||
MigLayoutVisualPadding.install( spinner );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,6 +137,7 @@ public class FlatSpinnerUI
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
buttonHoverArrowColor = null;
|
||||
buttonPressedArrowColor = null;
|
||||
padding = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( spinner );
|
||||
@@ -146,6 +148,7 @@ public class FlatSpinnerUI
|
||||
super.installListeners();
|
||||
|
||||
addEditorFocusListener( spinner.getEditor() );
|
||||
spinner.addFocusListener( getHandler() );
|
||||
spinner.addPropertyChangeListener( getHandler() );
|
||||
}
|
||||
|
||||
@@ -154,6 +157,7 @@ public class FlatSpinnerUI
|
||||
super.uninstallListeners();
|
||||
|
||||
removeEditorFocusListener( spinner.getEditor() );
|
||||
spinner.removeFocusListener( getHandler() );
|
||||
spinner.removePropertyChangeListener( getHandler() );
|
||||
|
||||
handler = null;
|
||||
@@ -206,17 +210,27 @@ public class FlatSpinnerUI
|
||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||
// is used, then the text field is updated after the spinner and the
|
||||
// colors are again replaced with default colors
|
||||
textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) );
|
||||
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
|
||||
textField.setForeground( FlatUIUtils.nonUIResource( getForeground( true ) ) );
|
||||
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private JTextField getEditorTextField( JComponent editor ) {
|
||||
private static JTextField getEditorTextField( JComponent editor ) {
|
||||
return editor instanceof JSpinner.DefaultEditor
|
||||
? ((JSpinner.DefaultEditor)editor).getTextField()
|
||||
: null;
|
||||
}
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? spinner.getBackground()
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground);
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
return enabled ? spinner.getForeground() : disabledForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutManager createLayout() {
|
||||
return getHandler();
|
||||
@@ -234,7 +248,7 @@ public class FlatSpinnerUI
|
||||
|
||||
private Component createArrowButton( int direction, String name ) {
|
||||
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null );
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
button.setName( name );
|
||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1 : -1 );
|
||||
if( direction == SwingConstants.NORTH )
|
||||
@@ -246,48 +260,55 @@ public class FlatSpinnerUI
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
float arc = FlatUIUtils.getBorderArc( c );
|
||||
|
||||
// fill background if opaque to avoid garbage if user sets opaque to true
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
|
||||
if( c.isOpaque() && (focusWidth > 0 || arc > 0) )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
|
||||
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
|
||||
Component nextButton = getHandler().nextButton;
|
||||
int arrowX = nextButton.getX();
|
||||
int arrowWidth = nextButton.getWidth();
|
||||
boolean enabled = spinner.isEnabled();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint background
|
||||
g2.setColor( enabled
|
||||
? c.getBackground()
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground) );
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow buttons background
|
||||
if( enabled ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
else
|
||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
g2.setClip( oldClip );
|
||||
// paint button background and separator
|
||||
boolean paintButton = !"none".equals( buttonStyle );
|
||||
Handler handler = getHandler();
|
||||
if( paintButton && (handler.nextButton != null || handler.previousButton != null) ) {
|
||||
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
|
||||
int arrowX = button.getX();
|
||||
int arrowWidth = button.getWidth();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
|
||||
// paint arrow buttons background
|
||||
if( enabled ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
else
|
||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
g2.setClip( oldClip );
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow buttons
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow buttons
|
||||
g2.setColor( enabled ? borderColor : disabledBorderColor );
|
||||
float lw = scale( 1f );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
|
||||
paint( g, c );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
//---- class Handler ------------------------------------------------------
|
||||
@@ -328,8 +349,9 @@ public class FlatSpinnerUI
|
||||
// the arrows width is the same as the inner height so that the arrows area is square
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( spinner, FlatSpinnerUI.this.minimumWidth );
|
||||
int innerHeight = editorSize.height + padding.top + padding.bottom;
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( spinner );
|
||||
return new Dimension(
|
||||
Math.max( insets.left + insets.right + editorSize.width + padding.left + padding.right + innerHeight, scale( minimumWidth + (focusWidth * 2) ) ),
|
||||
Math.max( insets.left + insets.right + editorSize.width + padding.left + padding.right + innerHeight, scale( minimumWidth ) + Math.round( focusWidth * 2 ) ),
|
||||
insets.top + insets.bottom + innerHeight );
|
||||
}
|
||||
|
||||
@@ -346,7 +368,7 @@ public class FlatSpinnerUI
|
||||
|
||||
if( nextButton == null && previousButton == null ) {
|
||||
if( editor != null )
|
||||
editor.setBounds( r );
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -368,12 +390,14 @@ public class FlatSpinnerUI
|
||||
if( editor != null )
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) );
|
||||
|
||||
int nextHeight = Math.round( buttonsRect.height / 2f );
|
||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||
if( nextButton != null )
|
||||
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
|
||||
if( previousButton != null ) {
|
||||
previousButton.setBounds( buttonsRect.x, buttonsRect.y + nextHeight,
|
||||
buttonsRect.width, buttonsRect.height - nextHeight );
|
||||
// for precise layout of arrows, the "previous" button has the same height
|
||||
// as the "next" button and may overlap on uneven buttonsRect.height
|
||||
int previousY = buttonsRect.y + buttonsRect.height - nextHeight;
|
||||
previousButton.setBounds( buttonsRect.x, previousY, buttonsRect.width, nextHeight );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +406,13 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
spinner.repaint();
|
||||
|
||||
// if spinner gained focus, transfer it to the editor text field
|
||||
if( e.getComponent() == spinner ) {
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
if( textField != null )
|
||||
textField.requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -398,6 +429,14 @@ public class FlatSpinnerUI
|
||||
case "enabled":
|
||||
updateEditorColors();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
spinner.repaint();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
spinner.revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
@@ -42,10 +48,16 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
*
|
||||
* <!-- FlatSplitPaneUI -->
|
||||
*
|
||||
* @uiDefault Component.arrowType String triangle (default) or chevron
|
||||
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||
* @uiDefault SplitPane.continuousLayout boolean
|
||||
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color
|
||||
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
|
||||
* @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color
|
||||
* @uiDefault SplitPaneDivider.style String grip (default) or plain
|
||||
* @uiDefault SplitPaneDivider.gripColor Color
|
||||
* @uiDefault SplitPaneDivider.gripDotCount int
|
||||
* @uiDefault SplitPaneDivider.gripDotSize int
|
||||
* @uiDefault SplitPaneDivider.gripGap int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -54,8 +66,9 @@ public class FlatSplitPaneUI
|
||||
{
|
||||
protected String arrowType;
|
||||
private Boolean continuousLayout;
|
||||
private Color oneTouchArrowColor;
|
||||
private Color oneTouchHoverArrowColor;
|
||||
protected Color oneTouchArrowColor;
|
||||
protected Color oneTouchHoverArrowColor;
|
||||
protected Color oneTouchPressedArrowColor;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatSplitPaneUI();
|
||||
@@ -69,12 +82,22 @@ public class FlatSplitPaneUI
|
||||
// used in there on LaF switching
|
||||
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
|
||||
oneTouchHoverArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchHoverArrowColor" );
|
||||
oneTouchPressedArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchPressedArrowColor" );
|
||||
|
||||
super.installDefaults();
|
||||
|
||||
continuousLayout = (Boolean) UIManager.get( "SplitPane.continuousLayout" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
oneTouchArrowColor = null;
|
||||
oneTouchHoverArrowColor = null;
|
||||
oneTouchPressedArrowColor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContinuousLayout() {
|
||||
return super.isContinuousLayout() || (continuousLayout != null && Boolean.TRUE.equals( continuousLayout ));
|
||||
@@ -87,11 +110,19 @@ public class FlatSplitPaneUI
|
||||
|
||||
//---- class FlatSplitPaneDivider -----------------------------------------
|
||||
|
||||
private class FlatSplitPaneDivider
|
||||
protected class FlatSplitPaneDivider
|
||||
extends BasicSplitPaneDivider
|
||||
{
|
||||
public FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
|
||||
protected final String style = UIManager.getString( "SplitPaneDivider.style" );
|
||||
protected final Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
|
||||
protected final int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
|
||||
protected final int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
|
||||
protected final int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 );
|
||||
|
||||
protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
|
||||
super( ui );
|
||||
|
||||
setLayout( new FlatDividerLayout() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,16 +140,67 @@ public class FlatSplitPaneUI
|
||||
return new FlatOneTouchButton( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case JSplitPane.DIVIDER_LOCATION_PROPERTY:
|
||||
// necessary to show/hide one-touch buttons on expand/collapse
|
||||
revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
super.paint( g );
|
||||
|
||||
if( "plain".equals( style ) )
|
||||
return;
|
||||
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
g.setColor( gripColor );
|
||||
paintGrip( g, 0, 0, getWidth(), getHeight() );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
protected void paintGrip( Graphics g, int x, int y, int width, int height ) {
|
||||
FlatUIUtils.paintGrip( g, x, y, width, height,
|
||||
splitPane.getOrientation() == JSplitPane.VERTICAL_SPLIT,
|
||||
gripDotCount, gripDotSize, gripGap, true );
|
||||
}
|
||||
|
||||
protected boolean isLeftCollapsed() {
|
||||
int location = splitPane.getDividerLocation();
|
||||
Insets insets = splitPane.getInsets();
|
||||
return (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? location == insets.top
|
||||
: location == insets.left;
|
||||
}
|
||||
|
||||
protected boolean isRightCollapsed() {
|
||||
int location = splitPane.getDividerLocation();
|
||||
Insets insets = splitPane.getInsets();
|
||||
return (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? location == (splitPane.getHeight() - getHeight() - insets.bottom)
|
||||
: location == (splitPane.getWidth() - getWidth() - insets.right);
|
||||
}
|
||||
|
||||
//---- class FlatOneTouchButton ---------------------------------------
|
||||
|
||||
private class FlatOneTouchButton
|
||||
protected class FlatOneTouchButton
|
||||
extends FlatArrowButton
|
||||
{
|
||||
private final boolean left;
|
||||
protected final boolean left;
|
||||
|
||||
public FlatOneTouchButton( boolean left ) {
|
||||
super( SwingConstants.NORTH, arrowType, oneTouchArrowColor, null, oneTouchHoverArrowColor, null );
|
||||
protected FlatOneTouchButton( boolean left ) {
|
||||
super( SwingConstants.NORTH, arrowType, oneTouchArrowColor, null,
|
||||
oneTouchHoverArrowColor, null, oneTouchPressedArrowColor, null );
|
||||
setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
|
||||
ToolTipManager.sharedInstance().registerComponent( this );
|
||||
|
||||
this.left = left;
|
||||
}
|
||||
@@ -129,7 +211,67 @@ public class FlatSplitPaneUI
|
||||
? (left ? SwingConstants.NORTH : SwingConstants.SOUTH)
|
||||
: (left ? SwingConstants.WEST : SwingConstants.EAST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText( MouseEvent e ) {
|
||||
String key = (orientation == JSplitPane.VERTICAL_SPLIT)
|
||||
? (left
|
||||
? (isRightCollapsed()
|
||||
? "SplitPaneDivider.expandBottomToolTipText"
|
||||
: "SplitPaneDivider.collapseTopToolTipText")
|
||||
: (isLeftCollapsed()
|
||||
? "SplitPaneDivider.expandTopToolTipText"
|
||||
: "SplitPaneDivider.collapseBottomToolTipText"))
|
||||
: (left
|
||||
? (isRightCollapsed()
|
||||
? "SplitPaneDivider.expandRightToolTipText"
|
||||
: "SplitPaneDivider.collapseLeftToolTipText")
|
||||
: (isLeftCollapsed()
|
||||
? "SplitPaneDivider.expandLeftToolTipText"
|
||||
: "SplitPaneDivider.collapseRightToolTipText"));
|
||||
|
||||
// get text from client property
|
||||
Object value = splitPane.getClientProperty( key );
|
||||
if( value instanceof String )
|
||||
return (String) value;
|
||||
|
||||
// get text from bundle
|
||||
return UIManager.getString( key, getLocale() );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatDividerLayout ----------------------------------------
|
||||
|
||||
protected class FlatDividerLayout
|
||||
extends DividerLayout
|
||||
{
|
||||
@Override
|
||||
public void layoutContainer( Container c ) {
|
||||
super.layoutContainer( c );
|
||||
|
||||
if( leftButton == null || rightButton == null || !splitPane.isOneTouchExpandable() )
|
||||
return;
|
||||
|
||||
// increase side of buttons, which makes them easier to hit by the user
|
||||
// and avoids cut arrows at small divider sizes
|
||||
int extraSize = UIScale.scale( 4 );
|
||||
if( orientation == JSplitPane.VERTICAL_SPLIT ) {
|
||||
leftButton.setSize( leftButton.getWidth() + extraSize, leftButton.getHeight() );
|
||||
rightButton.setBounds( leftButton.getX() + leftButton.getWidth(), rightButton.getY(),
|
||||
rightButton.getWidth() + extraSize, rightButton.getHeight() );
|
||||
} else {
|
||||
leftButton.setSize( leftButton.getWidth(), leftButton.getHeight() + extraSize );
|
||||
rightButton.setBounds( rightButton.getX(), leftButton.getY() + leftButton.getHeight(),
|
||||
rightButton.getWidth(), rightButton.getHeight() + extraSize );
|
||||
}
|
||||
|
||||
// hide buttons if not applicable
|
||||
boolean leftCollapsed = isLeftCollapsed();
|
||||
if( leftCollapsed )
|
||||
rightButton.setLocation( leftButton.getLocation() );
|
||||
leftButton.setVisible( !leftCollapsed );
|
||||
rightButton.setVisible( !isRightCollapsed() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,7 +86,7 @@ public class FlatTableCellBorder
|
||||
/**
|
||||
* Checks whether at least one selected cell is editable.
|
||||
*/
|
||||
private boolean isSelectionEditable( JTable table ) {
|
||||
protected boolean isSelectionEditable( JTable table ) {
|
||||
if( table.getRowSelectionAllowed() ) {
|
||||
int columnCount = table.getColumnCount();
|
||||
int[] selectedRows = table.getSelectedRows();
|
||||
|
||||
@@ -22,13 +22,21 @@ import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Objects;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
@@ -49,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TableHeader.separatorColor Color
|
||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||
* @uiDefault TableHeader.height int
|
||||
* @uiDefault TableHeader.sortIconPosition String right (default), left, top or bottom
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -58,6 +67,7 @@ public class FlatTableHeaderUI
|
||||
protected Color separatorColor;
|
||||
protected Color bottomSeparatorColor;
|
||||
protected int height;
|
||||
protected int sortIconPosition;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTableHeaderUI();
|
||||
@@ -70,6 +80,13 @@ public class FlatTableHeaderUI
|
||||
separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
|
||||
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||
height = UIManager.getInt( "TableHeader.height" );
|
||||
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) {
|
||||
default:
|
||||
case "right": sortIconPosition = SwingConstants.RIGHT; break;
|
||||
case "left": sortIconPosition = SwingConstants.LEFT; break;
|
||||
case "top": sortIconPosition = SwingConstants.TOP; break;
|
||||
case "bottom": sortIconPosition = SwingConstants.BOTTOM; break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,10 +99,13 @@ public class FlatTableHeaderUI
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
if( header.getColumnModel().getColumnCount() <= 0 )
|
||||
return;
|
||||
|
||||
// do not paint borders if JTableHeader.setDefaultRenderer() was used
|
||||
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
|
||||
boolean paintBorders = isSystemDefaultRenderer( defaultRenderer );
|
||||
if( !paintBorders && header.getColumnModel().getColumnCount() > 0 ) {
|
||||
if( !paintBorders ) {
|
||||
// check whether the renderer delegates to the system default renderer
|
||||
Component rendererComponent = defaultRenderer.getTableCellRendererComponent(
|
||||
header.getTable(), "", false, false, -1, 0 );
|
||||
@@ -95,8 +115,22 @@ public class FlatTableHeaderUI
|
||||
if( paintBorders )
|
||||
paintColumnBorders( g, c );
|
||||
|
||||
// temporary use own default renderer if necessary
|
||||
FlatTableCellHeaderRenderer sortIconRenderer = null;
|
||||
if( sortIconPosition != SwingConstants.RIGHT ) {
|
||||
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
|
||||
header.setDefaultRenderer( sortIconRenderer );
|
||||
}
|
||||
|
||||
// paint header
|
||||
super.paint( g, c );
|
||||
|
||||
// restore default renderer
|
||||
if( sortIconRenderer != null ) {
|
||||
sortIconRenderer.reset();
|
||||
header.setDefaultRenderer( sortIconRenderer.delegate );
|
||||
}
|
||||
|
||||
if( paintBorders )
|
||||
paintDraggedColumnBorders( g, c );
|
||||
}
|
||||
@@ -107,7 +141,7 @@ public class FlatTableHeaderUI
|
||||
rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" );
|
||||
}
|
||||
|
||||
private void paintColumnBorders( Graphics g, JComponent c ) {
|
||||
protected void paintColumnBorders( Graphics g, JComponent c ) {
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
float lineWidth = UIScale.scale( 1f );
|
||||
@@ -115,6 +149,9 @@ public class FlatTableHeaderUI
|
||||
float bottomLineIndent = lineWidth * 3;
|
||||
TableColumnModel columnModel = header.getColumnModel();
|
||||
int columnCount = columnModel.getColumnCount();
|
||||
int sepCount = columnCount;
|
||||
if( hideLastVerticalLine() )
|
||||
sepCount--;
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
@@ -127,23 +164,30 @@ public class FlatTableHeaderUI
|
||||
// paint column separator lines
|
||||
g2.setColor( separatorColor );
|
||||
|
||||
int sepCount = columnCount;
|
||||
if( header.getTable().getAutoResizeMode() != JTable.AUTO_RESIZE_OFF && !isVerticalScrollBarVisible() )
|
||||
sepCount--;
|
||||
float y = topLineIndent;
|
||||
float h = height - bottomLineIndent;
|
||||
|
||||
if( header.getComponentOrientation().isLeftToRight() ) {
|
||||
int x = 0;
|
||||
for( int i = 0; i < sepCount; i++ ) {
|
||||
x += columnModel.getColumn( i ).getWidth();
|
||||
g2.fill( new Rectangle2D.Float( x - lineWidth, topLineIndent, lineWidth, height - bottomLineIndent ) );
|
||||
g2.fill( new Rectangle2D.Float( x - lineWidth, y, lineWidth, h ) );
|
||||
}
|
||||
|
||||
// paint trailing separator (on right side)
|
||||
if( !hideTrailingVerticalLine() )
|
||||
g2.fill( new Rectangle2D.Float( header.getWidth() - lineWidth, y, lineWidth, h ) );
|
||||
} else {
|
||||
int x = width;
|
||||
Rectangle cellRect = header.getHeaderRect( 0 );
|
||||
int x = cellRect.x + cellRect.width;
|
||||
for( int i = 0; i < sepCount; i++ ) {
|
||||
x -= columnModel.getColumn( i ).getWidth();
|
||||
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0),
|
||||
topLineIndent, lineWidth, height - bottomLineIndent ) );
|
||||
g2.fill( new Rectangle2D.Float( x - (i < sepCount - 1 ? lineWidth : 0), y, lineWidth, h ) );
|
||||
}
|
||||
|
||||
// paint trailing separator (on left side)
|
||||
if( !hideTrailingVerticalLine() )
|
||||
g2.fill( new Rectangle2D.Float( 0, y, lineWidth, h ) );
|
||||
}
|
||||
} finally {
|
||||
g2.dispose();
|
||||
@@ -200,19 +244,106 @@ public class FlatTableHeaderUI
|
||||
return size;
|
||||
}
|
||||
|
||||
private boolean isVerticalScrollBarVisible() {
|
||||
JScrollPane scrollPane = getScrollPane();
|
||||
return (scrollPane != null && scrollPane.getVerticalScrollBar() != null)
|
||||
? scrollPane.getVerticalScrollBar().isVisible()
|
||||
: false;
|
||||
protected boolean hideLastVerticalLine() {
|
||||
Container viewport = header.getParent();
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
Rectangle cellRect = header.getHeaderRect( header.getColumnModel().getColumnCount() - 1 );
|
||||
|
||||
// using component orientation of scroll pane here because it is also used in FlatTableUI
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||
? cellRect.x + cellRect.width >= viewport.getWidth()
|
||||
: cellRect.x <= 0;
|
||||
}
|
||||
|
||||
private JScrollPane getScrollPane() {
|
||||
Container parent = header.getParent();
|
||||
if( parent == null )
|
||||
return null;
|
||||
protected boolean hideTrailingVerticalLine() {
|
||||
Container viewport = header.getParent();
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
parent = parent.getParent();
|
||||
return (parent instanceof JScrollPane) ? (JScrollPane) parent : null;
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
return viewport == scrollPane.getColumnHeader() &&
|
||||
scrollPane.getCorner( ScrollPaneConstants.UPPER_TRAILING_CORNER ) == null;
|
||||
}
|
||||
|
||||
//---- class FlatTableCellHeaderRenderer ----------------------------------
|
||||
|
||||
/**
|
||||
* A delegating header renderer that is only used to paint sort arrows at
|
||||
* top, bottom or left position.
|
||||
*/
|
||||
private class FlatTableCellHeaderRenderer
|
||||
implements TableCellRenderer, Border, UIResource
|
||||
{
|
||||
private final TableCellRenderer delegate;
|
||||
|
||||
private JLabel l;
|
||||
private int oldHorizontalTextPosition = -1;
|
||||
private Border origBorder;
|
||||
private Icon sortIcon;
|
||||
|
||||
FlatTableCellHeaderRenderer( TableCellRenderer delegate ) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
|
||||
boolean hasFocus, int row, int column )
|
||||
{
|
||||
Component c = delegate.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
|
||||
if( !(c instanceof JLabel) )
|
||||
return c;
|
||||
|
||||
l = (JLabel) c;
|
||||
|
||||
if( sortIconPosition == SwingConstants.LEFT ) {
|
||||
if( oldHorizontalTextPosition < 0 )
|
||||
oldHorizontalTextPosition = l.getHorizontalTextPosition();
|
||||
l.setHorizontalTextPosition( SwingConstants.RIGHT );
|
||||
} else {
|
||||
// top or bottom
|
||||
sortIcon = l.getIcon();
|
||||
origBorder = l.getBorder();
|
||||
l.setIcon( null );
|
||||
l.setBorder( this );
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 )
|
||||
l.setHorizontalTextPosition( oldHorizontalTextPosition );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( origBorder != null )
|
||||
origBorder.paintBorder( c, g, x, y, width, height );
|
||||
|
||||
if( sortIcon != null ) {
|
||||
int xi = x + ((width - sortIcon.getIconWidth()) / 2);
|
||||
int yi = (sortIconPosition == SwingConstants.TOP)
|
||||
? y + UIScale.scale( 1 )
|
||||
: y + height - sortIcon.getIconHeight()
|
||||
- 1 // for gap
|
||||
- (int) (1 * UIScale.getUserScaleFactor()); // for bottom border
|
||||
sortIcon.paintIcon( c, g, xi, yi );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c ) {
|
||||
return (origBorder != null) ? origBorder.getBorderInsets( c ) : new Insets( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBorderOpaque() {
|
||||
return (origBorder != null) ? origBorder.isBorderOpaque() : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,25 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -68,6 +79,10 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Table.cellFocusColor Color
|
||||
* @uiDefault Table.showCellFocusIndicator boolean
|
||||
*
|
||||
* <!-- FlatInputMaps -->
|
||||
*
|
||||
* @uiDefault Table.consistentHomeEndKeyBehavior boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTableUI
|
||||
@@ -90,16 +105,6 @@ public class FlatTableUI
|
||||
return new FlatTableUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -113,7 +118,7 @@ public class FlatTableUI
|
||||
selectionInactiveBackground = UIManager.getColor( "Table.selectionInactiveBackground" );
|
||||
selectionInactiveForeground = UIManager.getColor( "Table.selectionInactiveForeground" );
|
||||
|
||||
toggleSelectionColors( table.hasFocus() );
|
||||
toggleSelectionColors();
|
||||
|
||||
int rowHeight = FlatUIUtils.getUIInt( "Table.rowHeight", 16 );
|
||||
if( rowHeight > 0 )
|
||||
@@ -160,13 +165,17 @@ public class FlatTableUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
super.focusGained( e );
|
||||
toggleSelectionColors( true );
|
||||
toggleSelectionColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
super.focusLost( e );
|
||||
toggleSelectionColors( false );
|
||||
|
||||
// use invokeLater for the case that the window is deactivated
|
||||
EventQueue.invokeLater( () -> {
|
||||
toggleSelectionColors();
|
||||
} );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -180,8 +189,11 @@ public class FlatTableUI
|
||||
* already used in applications. Then either the inactive colors are not used,
|
||||
* or the application has to be changed to extend a FlatLaf renderer.
|
||||
*/
|
||||
private void toggleSelectionColors( boolean focused ) {
|
||||
if( focused ) {
|
||||
private void toggleSelectionColors() {
|
||||
if( table == null )
|
||||
return;
|
||||
|
||||
if( FlatUIUtils.isPermanentFocusOwner( table ) ) {
|
||||
if( table.getSelectionBackground() == selectionInactiveBackground )
|
||||
table.setSelectionBackground( selectionBackground );
|
||||
if( table.getSelectionForeground() == selectionInactiveForeground )
|
||||
@@ -193,4 +205,125 @@ public class FlatTableUI
|
||||
table.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
boolean horizontalLines = table.getShowHorizontalLines();
|
||||
boolean verticalLines = table.getShowVerticalLines();
|
||||
if( horizontalLines || verticalLines ) {
|
||||
// fix grid painting issues in BasicTableUI
|
||||
// - do not paint last vertical grid line if line is on right edge of scroll pane
|
||||
// - fix unstable grid line thickness when scaled at 125%, 150%, 175%, 225%, ...
|
||||
// which paints either 1px or 2px lines depending on location
|
||||
// - on Java 9+, fix wrong grid line thickness in dragged column
|
||||
|
||||
boolean hideLastVerticalLine = hideLastVerticalLine();
|
||||
int tableWidth = table.getWidth();
|
||||
JTableHeader header = table.getTableHeader();
|
||||
boolean isDragging = (header != null && header.getDraggedColumn() != null);
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
double lineThickness = (1. / systemScaleFactor) * (int) systemScaleFactor;
|
||||
|
||||
// Java 8 uses drawLine() to paint grid lines
|
||||
// Java 9+ uses fillRect() to paint grid lines (except for dragged column)
|
||||
g = new Graphics2DProxy( (Graphics2D) g ) {
|
||||
@Override
|
||||
public void drawLine( int x1, int y1, int x2, int y2 ) {
|
||||
// do not paint last vertical line
|
||||
if( hideLastVerticalLine && verticalLines &&
|
||||
x1 == x2 && y1 == 0 && x1 == tableWidth - 1 &&
|
||||
wasInvokedFromPaintGrid() )
|
||||
return;
|
||||
|
||||
// on Java 9+, fix wrong grid line thickness in dragged column
|
||||
if( isDragging &&
|
||||
SystemInfo.isJava_9_orLater &&
|
||||
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
|
||||
wasInvokedFromPaintDraggedArea() )
|
||||
{
|
||||
if( y1 == y2 ) {
|
||||
// horizontal grid line
|
||||
super.fill( new Rectangle2D.Double( x1, y1, x2 - x1 + 1, lineThickness ) );
|
||||
} else if( x1 == x2 ) {
|
||||
// vertical grid line
|
||||
super.fill( new Rectangle2D.Double( x1, y1, lineThickness, y2 - y1 + 1 ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
super.drawLine( x1, y1, x2, y2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRect( int x, int y, int width, int height ) {
|
||||
// do not paint last vertical line
|
||||
if( hideLastVerticalLine && verticalLines &&
|
||||
width == 1 && y == 0 && x == tableWidth - 1 &&
|
||||
wasInvokedFromPaintGrid() )
|
||||
return;
|
||||
|
||||
// reduce line thickness to avoid unstable painted line thickness
|
||||
if( lineThickness != 1 ) {
|
||||
if( horizontalLines && height == 1 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, width, lineThickness ) );
|
||||
return;
|
||||
}
|
||||
if( verticalLines && width == 1 && y == 0 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, lineThickness, height ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.fillRect( x, y, width, height );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromPaintGrid() {
|
||||
return wasInvokedFromMethod( "paintGrid" );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromPaintDraggedArea() {
|
||||
return wasInvokedFromMethod( "paintDraggedArea" );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromMethod( String methodName ) {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
|
||||
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) {
|
||||
String methodName2 = stackTrace[i].getMethodName();
|
||||
if( "paintCell".equals( methodName2 ) )
|
||||
return false;
|
||||
if( methodName.equals( methodName2 ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
super.paint( g, c );
|
||||
}
|
||||
|
||||
protected boolean hideLastVerticalLine() {
|
||||
Container viewport = SwingUtilities.getUnwrappedParent( table );
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return false;
|
||||
|
||||
// do not hide last vertical line if table is smaller than viewport
|
||||
if( table.getX() + table.getWidth() < viewport.getWidth() )
|
||||
return false;
|
||||
|
||||
// in left-to-right:
|
||||
// - do not hide last vertical line if table used as row header in scroll pane
|
||||
// in right-to-left:
|
||||
// - hide last vertical line if table used as row header in scroll pane
|
||||
// - do not hide last vertical line if table is in center and scroll pane has row header
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
JViewport rowHeader = scrollPane.getRowHeader();
|
||||
return scrollPane.getComponentOrientation().isLeftToRight()
|
||||
? (viewport != rowHeader)
|
||||
: (viewport == rowHeader || rowHeader == null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
@@ -27,6 +28,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextAreaUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
|
||||
@@ -58,6 +60,7 @@ public class FlatTextAreaUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color background;
|
||||
protected Color disabledBackground;
|
||||
protected Color inactiveBackground;
|
||||
|
||||
@@ -65,12 +68,20 @@ public class FlatTextAreaUI
|
||||
return new FlatTextAreaUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
background = UIManager.getColor( "TextArea.background" );
|
||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||
}
|
||||
@@ -79,46 +90,80 @@ public class FlatTextAreaUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
|
||||
switch( e.getPropertyName() ) {
|
||||
case "editable":
|
||||
case "enabled":
|
||||
updateBackground();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
Color background = c.getBackground();
|
||||
if( !(background instanceof UIResource) )
|
||||
return;
|
||||
|
||||
// do not update background if it currently has a unknown color (assigned from outside)
|
||||
if( background != this.background &&
|
||||
background != disabledBackground &&
|
||||
background != inactiveBackground )
|
||||
return;
|
||||
|
||||
Color newBackground = !c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable()
|
||||
? inactiveBackground
|
||||
: this.background);
|
||||
|
||||
if( newBackground != background )
|
||||
c.setBackground( newBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ) );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( JComponent c, Dimension size ) {
|
||||
// do not apply minimum width if JTextArea.columns is set
|
||||
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
Color background = c.getBackground();
|
||||
g.setColor( !(background instanceof UIResource)
|
||||
? background
|
||||
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
|
||||
? FlatUIUtils.getParentBackground( c )
|
||||
: (!c.isEnabled()
|
||||
? disabledBackground
|
||||
: (!c.isEditable() ? inactiveBackground : background))) );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
}
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getPreferredSize( c ), c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( super.getMinimumSize( c ), c );
|
||||
}
|
||||
|
||||
private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
|
||||
// do not apply minimum width if JTextArea.columns is set
|
||||
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
// issues. E.g. at scale factor 1.5 the first returns 4, but the second 3.
|
||||
int minimumWidth = FlatUIUtils.minimumWidth( getComponent(), this.minimumWidth );
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
|
||||
return size;
|
||||
super.paintBackground( g );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019 FormDev Software GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
/**
|
||||
* Border for various text components (e.g. {@link javax.swing.JTextField}).
|
||||
*
|
||||
* @uiDefault TextComponent.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatTextBorder
|
||||
extends FlatBorder
|
||||
{
|
||||
protected final int arc = UIManager.getInt( "TextComponent.arc" );
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
return 0;
|
||||
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user