mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-19 08:53:30 +00:00
Compare commits
2859
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03195b66bc | ||
|
|
2349aacc3e | ||
|
|
1be7bbe0dc | ||
|
|
ea332d5492 | ||
|
|
aedede7381 | ||
|
|
d4cd46c331 | ||
|
|
62450c3bb1 | ||
|
|
bafba81f56 | ||
|
|
651b445c75 | ||
|
|
5adc3c6a99 | ||
|
|
4914ff8205 | ||
|
|
783205c731 | ||
|
|
00ab2d1f3a | ||
|
|
98dcbdd87a | ||
|
|
4a936a6eef | ||
|
|
ef7ee1b699 | ||
|
|
4e70c1fb10 | ||
|
|
21d4fa5176 | ||
|
|
f16b2e8243 | ||
|
|
4e550a22b0 | ||
|
|
c2404d3c67 | ||
|
|
f1a5467d04 | ||
|
|
512486f2e8 | ||
|
|
f1d95fa883 | ||
|
|
31cf9b8527 | ||
|
|
e0e8e8c6cc | ||
|
|
6653690d0c | ||
|
|
e63f59d33e | ||
|
|
3702c18df5 | ||
|
|
dfe215f34c | ||
|
|
621a559585 | ||
|
|
61317eff71 | ||
|
|
b314a951da | ||
|
|
1a1c105c71 | ||
|
|
3f8ee35ddb | ||
|
|
d2ea74ea14 | ||
|
|
8e1fb771e0 | ||
|
|
bbe5c82700 | ||
|
|
95e3ff3349 | ||
|
|
00c3b2083b | ||
|
|
8549858951 | ||
|
|
4730c3f4b5 | ||
|
|
19ba66fd9d | ||
|
|
589c26192d | ||
|
|
8471aeea1b | ||
|
|
58c39c14a5 | ||
|
|
2cfe45950b | ||
|
|
688671db6a | ||
|
|
1d2e50dfa2 | ||
|
|
7a70036c8f | ||
|
|
ab88a3b236 | ||
|
|
266e14063e | ||
|
|
3af0296779 | ||
|
|
5ff05503a4 | ||
|
|
13e6782cf1 | ||
|
|
24052e6369 | ||
|
|
9b17ce5524 | ||
|
|
e4c2d62eb0 | ||
|
|
27fa37a7e1 | ||
|
|
987da2b812 | ||
|
|
d1611bae12 | ||
|
|
96a3c4b9dd | ||
|
|
8ef40dced5 | ||
|
|
4a6ddb901f | ||
|
|
a5094e0acc | ||
|
|
fffcca592d | ||
|
|
341584c032 | ||
|
|
a1e178d0d7 | ||
|
|
c59687b6e2 | ||
|
|
c2bd9f26a7 | ||
|
|
6d78b9b6df | ||
|
|
0669ce06f2 | ||
|
|
767d9378e3 | ||
|
|
c2d62b7a13 | ||
|
|
10e33298a9 | ||
|
|
ecc88112d5 | ||
|
|
b190063264 | ||
|
|
0c9c0c0239 | ||
|
|
ae333ecb77 | ||
|
|
72a85d11df | ||
|
|
f33ba954f5 | ||
|
|
f642330306 | ||
|
|
ae1a39322e | ||
|
|
29502d10eb | ||
|
|
37550b9fb0 | ||
|
|
efd2ed1960 | ||
|
|
150e44dcd5 | ||
|
|
3a164c8080 | ||
|
|
fb9223c6c3 | ||
|
|
511ce4b07d | ||
|
|
aea3fb5f07 | ||
|
|
5932a07eb2 | ||
|
|
2b07c4b662 | ||
|
|
bc689b91dc | ||
|
|
c6a42781e7 | ||
|
|
c92aedf433 | ||
|
|
7857f92f19 | ||
|
|
9361e5d401 | ||
|
|
6c6f69d4e5 | ||
|
|
e836226174 | ||
|
|
ad1862a253 | ||
|
|
4af137894a | ||
|
|
55aca1fde9 | ||
|
|
53e1e936d9 | ||
|
|
ff1448fb54 | ||
|
|
95fb19f311 | ||
|
|
46d869a62f | ||
|
|
03140dbf64 | ||
|
|
052c96e05a | ||
|
|
9a88f9c324 | ||
|
|
747ea627c9 | ||
|
|
89c0ab405a | ||
|
|
04c2b98ae4 | ||
|
|
24b36cdd95 | ||
|
|
3e83bd2363 | ||
|
|
5c91a08eaf | ||
|
|
edfba15d6f | ||
|
|
48e786e8b5 | ||
|
|
1282f1ac0e | ||
|
|
ee2fb61fdd | ||
|
|
68a113e7ee | ||
|
|
3cf3b76446 | ||
|
|
d7d561d3a9 | ||
|
|
73eeda3c09 | ||
|
|
3d514b5010 | ||
|
|
93fc8d29cc | ||
|
|
145bf65542 | ||
|
|
f21555bb6c | ||
|
|
be072a283f | ||
|
|
9e8d51c94d | ||
|
|
b3051a5bd0 | ||
|
|
a523cfc381 | ||
|
|
6544aff88e | ||
|
|
7c1fdbc720 | ||
|
|
bd84804e32 | ||
|
|
1f2a257bab | ||
|
|
b0684929e2 | ||
|
|
22dc587a8f | ||
|
|
622fcf740e | ||
|
|
77b59c8a18 | ||
|
|
462a18930b | ||
|
|
fb07def5fa | ||
|
|
a03ee6726e | ||
|
|
1ef49ef290 | ||
|
|
76d52e07d4 | ||
|
|
044b0bb0d2 | ||
|
|
472b59ef80 | ||
|
|
6b559ce283 | ||
|
|
c17b806fd5 | ||
|
|
1dcea8fe4c | ||
|
|
d72a52b9ce | ||
|
|
61e01b08e5 | ||
|
|
37756a5853 | ||
|
|
b66690e304 | ||
|
|
ccc6007bab | ||
|
|
3179d56879 | ||
|
|
b631032857 | ||
|
|
49574d1c54 | ||
|
|
b7d7368ce6 | ||
|
|
e221156c11 | ||
|
|
8e346acdce | ||
|
|
7c36fa3f56 | ||
|
|
642e254522 | ||
|
|
72aa1b8416 | ||
|
|
edb1ef7f98 | ||
|
|
92beaba1d6 | ||
|
|
3b61b1c85d | ||
|
|
a529e752b3 | ||
|
|
d9791673df | ||
|
|
a49a20e2c2 | ||
|
|
8570476cff | ||
|
|
d0923efa1a | ||
|
|
eab8fe2d64 | ||
|
|
c9e8b2970b | ||
|
|
1440c156b2 | ||
|
|
ddfa4445ae | ||
|
|
1f501e6429 | ||
|
|
7969f118de | ||
|
|
706166dc5c | ||
|
|
4a8667e0f3 | ||
|
|
094fbcc67c | ||
|
|
d34c47c167 | ||
|
|
7226330514 | ||
|
|
852b2bd5d9 | ||
|
|
3d8ecfad47 | ||
|
|
9e6f1e0dc3 | ||
|
|
4deb7a3f51 | ||
|
|
5b0b030435 | ||
|
|
4edec2df2e | ||
|
|
e0596bdf75 | ||
|
|
6430463b5d | ||
|
|
d9e27e549f | ||
|
|
9f14dac5d2 | ||
|
|
d70199ca58 | ||
|
|
6b1cdbd19c | ||
|
|
5b99757a0d | ||
|
|
6c49116c68 | ||
|
|
68f0cf27df | ||
|
|
89757e35e6 | ||
|
|
24bf09b70c | ||
|
|
0ed2709124 | ||
|
|
a835202db1 | ||
|
|
830fbbab26 | ||
|
|
119e11cfe2 | ||
|
|
511e18b44f | ||
|
|
2f00d93b22 | ||
|
|
973fa1b978 | ||
|
|
79f40d24ae | ||
|
|
fdff92e5c8 | ||
|
|
653dd07162 | ||
|
|
b7968ca4a7 | ||
|
|
2a0a6449e5 | ||
|
|
b7c04d7d16 | ||
|
|
ab4c87e69f | ||
|
|
8257632706 | ||
|
|
3f8821b43b | ||
|
|
f6b8bc0c45 | ||
|
|
0618fa9bb2 | ||
|
|
2e5a483dce | ||
|
|
e608e0dbf3 | ||
|
|
a88e316a94 | ||
|
|
51ffa256ca | ||
|
|
52bd654850 | ||
|
|
0518d479d3 | ||
|
|
a893f3f5c1 | ||
|
|
9c2f37b43f | ||
|
|
0289ba17f1 | ||
|
|
5db94e1e52 | ||
|
|
a4bc08c29e | ||
|
|
b638d8e904 | ||
|
|
251ce7fdad | ||
|
|
a2337a2969 | ||
|
|
0c803e26ca | ||
|
|
ab25fadb1e | ||
|
|
e697f4eca7 | ||
|
|
80158a8982 | ||
|
|
55bcfacf3b | ||
|
|
52b7a82b4d | ||
|
|
471e605871 | ||
|
|
5c635f17a7 | ||
|
|
c27d604780 | ||
|
|
ddaf575719 | ||
|
|
0757f2ea80 | ||
|
|
3f8dfb6516 | ||
|
|
45ee25adc2 | ||
|
|
fcfb3d4083 | ||
|
|
357f8bd684 | ||
|
|
173cd8b4ad | ||
|
|
d2ca5994c8 | ||
|
|
fe04d177af | ||
|
|
2a6b18bc1b | ||
|
|
152cd272f6 | ||
|
|
abbdc139e8 | ||
|
|
7226019b6a | ||
|
|
78ea29bd48 | ||
|
|
5c90d1f769 | ||
|
|
2ecea40fdc | ||
|
|
8d9c11b6f2 | ||
|
|
afd23e3457 | ||
|
|
ddeaad74d0 | ||
|
|
a82472f509 | ||
|
|
4a43e376ed | ||
|
|
9ab82e1e5e | ||
|
|
4b28d0c38b | ||
|
|
1924cd1822 | ||
|
|
730b2dd874 | ||
|
|
1c2b383838 | ||
|
|
0b99f83d6f | ||
|
|
dc5b3f48e8 | ||
|
|
d17671c99e | ||
|
|
b69259e83b | ||
|
|
f2c80dc815 | ||
|
|
cbc281b173 | ||
|
|
472f859bd8 | ||
|
|
e71f650650 | ||
|
|
e64c9d9cd4 | ||
|
|
87a1c6621c | ||
|
|
09f49c4afa | ||
|
|
eba1b2f999 | ||
|
|
8e026279ac | ||
|
|
3605e99914 | ||
|
|
5e9d479cef | ||
|
|
fb20463449 | ||
|
|
f5db73342f | ||
|
|
9b2dc23197 | ||
|
|
067052e1a8 | ||
|
|
441e5fbc05 | ||
|
|
0a2aae3bc2 | ||
|
|
a76c798500 | ||
|
|
c238ebeef4 | ||
|
|
206eddbdbd | ||
|
|
45549cdbcf | ||
|
|
e043b6a8c5 | ||
|
|
677076b89d | ||
|
|
77c9b99f74 | ||
|
|
c8cdda0c18 | ||
|
|
41cd73703e | ||
|
|
607e84c052 | ||
|
|
8416390631 | ||
|
|
6094d25cfb | ||
|
|
c80504efae | ||
|
|
2589033523 | ||
|
|
f74fed5ee0 | ||
|
|
01e295084c | ||
|
|
9f923941a8 | ||
|
|
3aba03eb28 | ||
|
|
1107195ab6 | ||
|
|
b67384cdd1 | ||
|
|
59603b550e | ||
|
|
c52f714149 | ||
|
|
35420732d1 | ||
|
|
7f48b84292 | ||
|
|
5110c5706f | ||
|
|
633511acda | ||
|
|
75d0a69c02 | ||
|
|
e6fe9396f8 | ||
|
|
5c4107835b | ||
|
|
57cc90f89f | ||
|
|
7e08e48a8a | ||
|
|
87719f1161 | ||
|
|
99d7c8d824 | ||
|
|
1caf4f99cf | ||
|
|
78b3887e4a | ||
|
|
bb064aacd5 | ||
|
|
d9e8321d9e | ||
|
|
5f6df95e30 | ||
|
|
ef779c346e | ||
|
|
c1543d4a2f | ||
|
|
9145e27009 | ||
|
|
299f1a9102 | ||
|
|
6eab438778 | ||
|
|
2a623fbb8c | ||
|
|
7bde091f1b | ||
|
|
412baf7872 | ||
|
|
010057d9e1 | ||
|
|
6c7d8df565 | ||
|
|
92598da06f | ||
|
|
601d6f7c6c | ||
|
|
e13cebaa3a | ||
|
|
5724868c5a | ||
|
|
03972f0aec | ||
|
|
6143ec4180 | ||
|
|
c30464ee77 | ||
|
|
1e1e6456cd | ||
|
|
6c46bb4756 | ||
|
|
5ac6b1d1f1 | ||
|
|
9c95c9c6e9 | ||
|
|
4b052e74f1 | ||
|
|
bd6b8e4b7f | ||
|
|
26e8432bb0 | ||
|
|
05f9fd22fe | ||
|
|
8f5bde2797 | ||
|
|
77fe16faec | ||
|
|
38dd776049 | ||
|
|
7e3c4074e4 | ||
|
|
89c8f8e80f | ||
|
|
7397e681f4 | ||
|
|
e7d5afe90e | ||
|
|
2d9d354a05 | ||
|
|
60a686d75c | ||
|
|
89b70843c7 | ||
|
|
9f9044b164 | ||
|
|
617987f4a5 | ||
|
|
5bb338d6ec | ||
|
|
8003d91c4a | ||
|
|
a4ef18ddab | ||
|
|
82e55b4761 | ||
|
|
3a51c386ca | ||
|
|
9868519cc0 | ||
|
|
038c007915 | ||
|
|
ba6350e24d | ||
|
|
1c866931f3 | ||
|
|
b7aff28b5e | ||
|
|
f0897ffdf8 | ||
|
|
f5937a6fad | ||
|
|
7dc77ed609 | ||
|
|
d1bfe62a65 | ||
|
|
f7c8f24bff | ||
|
|
055d63eeb5 | ||
|
|
ef7f92ed15 | ||
|
|
8daa53dd3e | ||
|
|
109003ae12 | ||
|
|
36f1abdbe6 | ||
|
|
50519776e0 | ||
|
|
9e289574ff | ||
|
|
2d96b06d4c | ||
|
|
0c706cfed2 | ||
|
|
3f9e1c6c47 | ||
|
|
58c08cebd7 | ||
|
|
fed0703ecf | ||
|
|
aaed1a934e | ||
|
|
11639af26e | ||
|
|
623ad2b1dc | ||
|
|
ac68fec6b1 | ||
|
|
dad49354aa | ||
|
|
ce4fa3c027 | ||
|
|
02d1a12bf5 | ||
|
|
78cbc3871e | ||
|
|
f9bb882ceb | ||
|
|
87fc6bde1d | ||
|
|
f666367b5d | ||
|
|
81c02f24c6 | ||
|
|
1d01ed92d8 | ||
|
|
1a7ced34a7 | ||
|
|
47ab94b5bc | ||
|
|
bea0778acc | ||
|
|
eeba5087b1 | ||
|
|
7bd8bf02f6 | ||
|
|
378f87a634 | ||
|
|
76dd5383ab | ||
|
|
129ca185e4 | ||
|
|
1f4ef42625 | ||
|
|
eb55e4def6 | ||
|
|
acda834ad9 | ||
|
|
aba3e30d9c | ||
|
|
c9e55ff1dc | ||
|
|
013c5e9e58 | ||
|
|
5e7f3dc24a | ||
|
|
2ffa174900 | ||
|
|
26cbe17218 | ||
|
|
fc8f1dca4e | ||
|
|
6b20a4f8f7 | ||
|
|
091025a304 | ||
|
|
1180789c0c | ||
|
|
ac056d4a06 | ||
|
|
7c196e098a | ||
|
|
c612b13529 | ||
|
|
5f4c79f6c4 | ||
|
|
302cbf641e | ||
|
|
4bc2e9ad44 | ||
|
|
6853c4c212 | ||
|
|
800e15cfd0 | ||
|
|
873f184117 | ||
|
|
3bae5cd5cb | ||
|
|
19300332e8 | ||
|
|
89d88c9644 | ||
|
|
472014b1b1 | ||
|
|
c094420428 | ||
|
|
e948064063 | ||
|
|
bdd3b7d2a5 | ||
|
|
404c37b54c | ||
|
|
ac686a17fa | ||
|
|
bfc5068b5e | ||
|
|
649bee2330 | ||
|
|
593587ea60 | ||
|
|
0ab81a7b32 | ||
|
|
8bf937357c | ||
|
|
1e8b1fda81 | ||
|
|
cba9212150 | ||
|
|
a0a6c42227 | ||
|
|
c245d9de80 | ||
|
|
ca5cd8e09b | ||
|
|
34ac4cd23b | ||
|
|
8598fe8ad9 | ||
|
|
3699a31f28 | ||
|
|
06498672ab | ||
|
|
cd3b92af7a | ||
|
|
e15cc29e2f | ||
|
|
dabeb066de | ||
|
|
c59e7cc456 | ||
|
|
3c16bfef58 | ||
|
|
ec24977d4e | ||
|
|
10b4f57a0e | ||
|
|
75cd5a75e1 | ||
|
|
fb2d0ed170 | ||
|
|
d4e139eaf5 | ||
|
|
49ef1276f6 | ||
|
|
828788b643 | ||
|
|
0ca8d7a258 | ||
|
|
75de49d151 | ||
|
|
d39e1c0c6e | ||
|
|
8e7f201ca8 | ||
|
|
85b2a9b0a0 | ||
|
|
d4e40faecc | ||
|
|
0be913ab18 | ||
|
|
bab30f3b61 | ||
|
|
abb599c556 | ||
|
|
2b6c6e9ab3 | ||
|
|
0db0d744da | ||
|
|
6b9f2d29fc | ||
|
|
2c141a5255 | ||
|
|
4f69a32700 | ||
|
|
3d4c08ad20 | ||
|
|
594d415976 | ||
|
|
ae50fde4e1 | ||
|
|
401461f1f0 | ||
|
|
676c6e106d | ||
|
|
d0a066ccd3 | ||
|
|
340e286277 | ||
|
|
9211d41984 | ||
|
|
686aa457d6 | ||
|
|
1b1431f0d0 | ||
|
|
cbcb46597d | ||
|
|
6644c85978 | ||
|
|
dd781fd86b | ||
|
|
97209846ad | ||
|
|
9744aa79b3 | ||
|
|
801648fcfe | ||
|
|
181fb9edb6 | ||
|
|
9ddbdfb80a | ||
|
|
1cab88181d | ||
|
|
803cc6e402 | ||
|
|
2e0b9f5ea5 | ||
|
|
fe60311072 | ||
|
|
de4a1d1e93 | ||
|
|
de36a2f4d1 | ||
|
|
57f6f3b318 | ||
|
|
8a3eb0d83b | ||
|
|
dd68b37a2a | ||
|
|
96793b39ba | ||
|
|
aa4f91b3b0 | ||
|
|
9ad44e6dc2 | ||
|
|
988b3d27b8 | ||
|
|
043cc13bb3 | ||
|
|
c0ee5f6563 | ||
|
|
f02d0ab1dd | ||
|
|
ff6d17990f | ||
|
|
9be52f639d | ||
|
|
586c419c46 | ||
|
|
73f02cc1bf | ||
|
|
eb27d24923 | ||
|
|
eeb056d509 | ||
|
|
3615912ce0 | ||
|
|
4518dfc0ca | ||
|
|
d5a7e8938d | ||
|
|
3d15844f7c | ||
|
|
62ed21b316 | ||
|
|
a178d43b01 | ||
|
|
ef2152beea | ||
|
|
e6475c1a9e | ||
|
|
091debd2a7 | ||
|
|
e7eff3e585 | ||
|
|
86a90e39d2 | ||
|
|
2887fbb251 | ||
|
|
fa6177b56d | ||
|
|
78524cdde7 | ||
|
|
6077d3f4c3 | ||
|
|
fd3acc456d | ||
|
|
257fe6dd3f | ||
|
|
cbb7cc93e9 | ||
|
|
8b608c5cce | ||
|
|
163fb14d0e | ||
|
|
e4f87bd805 | ||
|
|
864c7d96f1 | ||
|
|
e35e87fb05 | ||
|
|
3246bdbc8b | ||
|
|
710bb5fe1c | ||
|
|
53a52da709 | ||
|
|
4afbfc6e57 | ||
|
|
f7aa9efe13 | ||
|
|
1fce0ee551 | ||
|
|
ee695f9000 | ||
|
|
8f99ebb577 | ||
|
|
5bfafaf241 | ||
|
|
64e1a2ce4b | ||
|
|
27883c5beb | ||
|
|
2772725fe3 | ||
|
|
3f58a64827 | ||
|
|
cb37c7d218 | ||
|
|
45d951071f | ||
|
|
2ac60684fa | ||
|
|
af71742110 | ||
|
|
1adf27427a | ||
|
|
082f78eefa | ||
|
|
a8a9ec0023 | ||
|
|
df4f945bc6 | ||
|
|
ad756a5b86 | ||
|
|
2ca99ba669 | ||
|
|
6443575114 | ||
|
|
52a51d81f1 | ||
|
|
7d20b06e52 | ||
|
|
ad9d8a7200 | ||
|
|
44da699343 | ||
|
|
0a542f9be9 | ||
|
|
8f1601ca55 | ||
|
|
ff0ce164da | ||
|
|
3650c38aa9 | ||
|
|
61d97338e2 | ||
|
|
e27bb4de50 | ||
|
|
4462d8bf22 | ||
|
|
f23a8ac928 | ||
|
|
9e1750ee13 | ||
|
|
5cd284cb36 | ||
|
|
5ea58430fe | ||
|
|
acfbda0d91 | ||
|
|
437e5a62f1 | ||
|
|
bbb5aea77d | ||
|
|
b5d04f84e7 | ||
|
|
93b12eb14f | ||
|
|
0aa67c4cf2 | ||
|
|
1c1affac5c | ||
|
|
0919797edc | ||
|
|
94ac8fd837 | ||
|
|
ecc82b5b51 | ||
|
|
add021fd67 | ||
|
|
2daf309d7d | ||
|
|
20be4a40ea | ||
|
|
7de91da87a | ||
|
|
b8b48b533b | ||
|
|
535f981739 | ||
|
|
0404ac0395 | ||
|
|
f961625f03 | ||
|
|
7909bae065 | ||
|
|
7e6e117b17 | ||
|
|
314e64d7b1 | ||
|
|
8c72e77e0d | ||
|
|
77eb6b358f | ||
|
|
25f86e2542 | ||
|
|
8bc0461463 | ||
|
|
c9dd1ea71d | ||
|
|
85d3529bc3 | ||
|
|
3aac8bb072 | ||
|
|
e9a7e21aca | ||
|
|
fc0e4da33c | ||
|
|
ef3c1315dd | ||
|
|
5c12890faf | ||
|
|
c4fd5e0999 | ||
|
|
d3c56d635d | ||
|
|
c53cb49034 | ||
|
|
d38463c5d9 | ||
|
|
bc4b424f0e | ||
|
|
6bd4f3b7b4 | ||
|
|
d91d83f115 | ||
|
|
584b6ab219 | ||
|
|
04b155dbfb | ||
|
|
ddc5488db7 | ||
|
|
5c6906d5fd | ||
|
|
56fee5d286 | ||
|
|
c4dcab04b6 | ||
|
|
8dd9a96769 | ||
|
|
6864015af6 | ||
|
|
ebaa60e929 | ||
|
|
ac9962c624 | ||
|
|
ccd1773643 | ||
|
|
ac970ff768 | ||
|
|
53ff45425d | ||
|
|
de435c741f | ||
|
|
1dc9a44aec | ||
|
|
0206379315 | ||
|
|
c39adbbbc5 | ||
|
|
061a15d4f7 | ||
|
|
7c2518f027 | ||
|
|
a07459454b | ||
|
|
752f9d2694 | ||
|
|
0a180f9e20 | ||
|
|
6fff2e1c2f | ||
|
|
4266900d2e | ||
|
|
a2a1d84bc0 | ||
|
|
7648c562f1 | ||
|
|
403fd30926 | ||
|
|
17ccddf541 | ||
|
|
c24366fcec | ||
|
|
9a258a6265 | ||
|
|
4542ccbdc2 | ||
|
|
41d8ad2b86 | ||
|
|
a3a2ee118e | ||
|
|
f285efc277 | ||
|
|
fbaf87ec6c | ||
|
|
a005a468a7 | ||
|
|
c8d01549ba | ||
|
|
23af4505dd | ||
|
|
53cb6a5b3e | ||
|
|
765384ace1 | ||
|
|
d39e3e2f69 | ||
|
|
d75124066e | ||
|
|
f4400876da | ||
|
|
c222c5127f | ||
|
|
90d04956e6 | ||
|
|
5d3b918339 | ||
|
|
eba0091764 | ||
|
|
7999cbbea3 | ||
|
|
cee7987b35 | ||
|
|
d475c08024 | ||
|
|
d78f83ae49 | ||
|
|
df694f01e7 | ||
|
|
f5d9cbb11b | ||
|
|
d802588abe | ||
|
|
927d6d2fc6 | ||
|
|
bab7595078 | ||
|
|
1ea9a6c57f | ||
|
|
f479d415d8 | ||
|
|
f41e7be726 | ||
|
|
c1fe28124f | ||
|
|
01a1e506e4 | ||
|
|
e61aebb55d | ||
|
|
bae5bafc62 | ||
|
|
be6cb266de | ||
|
|
6f72edc2d9 | ||
|
|
29f66bdfed | ||
|
|
c1c6f5682c | ||
|
|
a8a74a0246 | ||
|
|
f9b867c3eb | ||
|
|
6c07f9a048 | ||
|
|
573e0acafa | ||
|
|
530c664967 | ||
|
|
12c29c8387 | ||
|
|
6c7f61d90f | ||
|
|
eb6d8d0bb3 | ||
|
|
ef462973c7 | ||
|
|
aa7e49cfde | ||
|
|
186048676a | ||
|
|
0f40721cff | ||
|
|
3799dd92fd | ||
|
|
9ea1a2b1de | ||
|
|
d8b27d122e | ||
|
|
15c3a6eae4 | ||
|
|
4fcc90d53e | ||
|
|
2619a50976 | ||
|
|
de116c95d4 | ||
|
|
47594c9b07 | ||
|
|
1b9098b564 | ||
|
|
b0306eac87 | ||
|
|
125e813d25 | ||
|
|
8e0d4a70f2 | ||
|
|
0556fc68b0 | ||
|
|
e9e2313159 | ||
|
|
dbb2f03a43 | ||
|
|
ed0dc2d887 | ||
|
|
0a93f2d0b0 | ||
|
|
fd581cd65c | ||
|
|
36702bc971 | ||
|
|
0fc3eb38f1 | ||
|
|
73c8e945e9 | ||
|
|
b8420303ba | ||
|
|
532bfcf937 | ||
|
|
f6d892023e | ||
|
|
7f2977f4af | ||
|
|
e246a2753b | ||
|
|
6d06a26c31 | ||
|
|
7cda21b60f | ||
|
|
1db740039b | ||
|
|
df462774aa | ||
|
|
f55fa789c4 | ||
|
|
488541f26e | ||
|
|
b404b1cf50 | ||
|
|
69370aa806 | ||
|
|
b3ddd85b09 | ||
|
|
033221fd01 | ||
|
|
1201fa38a8 | ||
|
|
32059c376e | ||
|
|
511d393c78 | ||
|
|
237601cf29 | ||
|
|
928f14872e | ||
|
|
c6a9adf96c | ||
|
|
cdd00e0bd4 | ||
|
|
2503d13402 | ||
|
|
2d97970d24 | ||
|
|
d8945e53ba | ||
|
|
f18012d07b | ||
|
|
104f8603b9 | ||
|
|
19bb083030 | ||
|
|
ae575a19a0 | ||
|
|
5f94d0a5c2 | ||
|
|
f2fe1a7c17 | ||
|
|
618e6a1604 | ||
|
|
cef294513a | ||
|
|
8550abadef | ||
|
|
25c8b2d631 | ||
|
|
e7b690205e | ||
|
|
2403f8833a | ||
|
|
9f25743b4d | ||
|
|
f1c76f65cf | ||
|
|
7b39533410 | ||
|
|
1fe9c39dd5 | ||
|
|
2b7be2e3f1 | ||
|
|
1ee9a3f279 | ||
|
|
679acfb239 | ||
|
|
3c7ab4b49b | ||
|
|
3f062e1c0a | ||
|
|
0a497d8c3f | ||
|
|
462351f485 | ||
|
|
c4cbb631a9 | ||
|
|
76f2d15b1b | ||
|
|
5d63865ae5 | ||
|
|
ad7c88fb45 | ||
|
|
1af3877758 | ||
|
|
146ce3b12b | ||
|
|
bf67721ac4 | ||
|
|
436f736a8e | ||
|
|
1446e90dd9 | ||
|
|
54716c03d1 | ||
|
|
fad5e97e0a | ||
|
|
8cf79590c5 | ||
|
|
c6aafac6c8 | ||
|
|
94a5995197 | ||
|
|
74081dc981 | ||
|
|
7a593b13a7 | ||
|
|
25dc38b2b1 | ||
|
|
403b12f7b7 | ||
|
|
cd223be88a | ||
|
|
a6a3fca1e7 | ||
|
|
63815eb5c2 | ||
|
|
4444264830 | ||
|
|
255f91f7ca | ||
|
|
700207d29b | ||
|
|
72d96e9a3b | ||
|
|
a55b6de1b4 | ||
|
|
9faac05666 | ||
|
|
7bf408aba0 | ||
|
|
70ee391b33 | ||
|
|
f5eb1158db | ||
|
|
81916d0f45 | ||
|
|
76d77cc244 | ||
|
|
03dccbe613 | ||
|
|
1ccec65619 | ||
|
|
b78e9062a1 | ||
|
|
dc87354702 | ||
|
|
033e8583db | ||
|
|
d46b51fa9a | ||
|
|
dd1dfdcfeb | ||
|
|
c0233c803d | ||
|
|
1fa8c88f6b | ||
|
|
195b109a36 | ||
|
|
994ac3fc8e | ||
|
|
a8ec5cf5e9 | ||
|
|
b4263aa3ec | ||
|
|
6456809a72 | ||
|
|
024c0a3186 | ||
|
|
560b1d48bc | ||
|
|
bb2d860807 | ||
|
|
6f1c0fa4a8 | ||
|
|
35808e7bde | ||
|
|
1b4eeb35b3 | ||
|
|
cee032bbc9 | ||
|
|
9547b70743 | ||
|
|
5df8939d84 | ||
|
|
0b9c689273 | ||
|
|
ac193cd97a | ||
|
|
7355a60f16 | ||
|
|
fb6f6325b5 | ||
|
|
0f767d9dfc | ||
|
|
d1addcab91 | ||
|
|
7a02cd794b | ||
|
|
258cd9209f | ||
|
|
700f6022d9 | ||
|
|
a0f6b815e8 | ||
|
|
54477b8b8f | ||
|
|
6183f8d4e9 | ||
|
|
d98e247665 | ||
|
|
d0cd976246 | ||
|
|
15f6f6a90a | ||
|
|
f18074bf49 | ||
|
|
3f64b74453 | ||
|
|
1c86256f83 | ||
|
|
98105ad4dc | ||
|
|
6bf2d6c1ab | ||
|
|
cebd51aac1 | ||
|
|
42b8b3aa75 | ||
|
|
c0eaf79d25 | ||
|
|
fb2fe3eb63 | ||
|
|
184d63f7eb | ||
|
|
14ebd58c96 | ||
|
|
3edddb8e91 | ||
|
|
d2340dff1a | ||
|
|
d30c6aec7d | ||
|
|
4854b3e08f | ||
|
|
facc748090 | ||
|
|
5c71612e34 | ||
|
|
f00a5fbaf4 | ||
|
|
34769da9cc | ||
|
|
458e6ed531 | ||
|
|
05814e9351 | ||
|
|
b6c0b1b396 | ||
|
|
1a299d85b6 | ||
|
|
1816274ebe | ||
|
|
b02e4c5308 | ||
|
|
12ed42e163 | ||
|
|
6c9c135062 | ||
|
|
6aea0160df | ||
|
|
30edd9e8dd | ||
|
|
7734402e8e | ||
|
|
ace1332ca5 | ||
|
|
baa313e8f8 | ||
|
|
3d9aa24f3c | ||
|
|
c287d457d6 | ||
|
|
7537b27a58 | ||
|
|
1f560c92fc | ||
|
|
74cd11c763 | ||
|
|
ee7d89331b | ||
|
|
5b51077823 | ||
|
|
d2f94d1945 | ||
|
|
0170a099bb | ||
|
|
2b893d0ea1 | ||
|
|
a08da57cbb | ||
|
|
a313fe5a86 | ||
|
|
544de699f6 | ||
|
|
d9d35b7f50 | ||
|
|
7dbec00f0e | ||
|
|
51b9b40c7e | ||
|
|
b2383a084a | ||
|
|
61848c5e24 | ||
|
|
60b2f7d243 | ||
|
|
d2a5e126ae | ||
|
|
9d7d8ddde9 | ||
|
|
249ebeb4aa | ||
|
|
378c14d790 | ||
|
|
30c1093c2f | ||
|
|
b966c8cb0b | ||
|
|
38cddf029b | ||
|
|
6652a27781 | ||
|
|
08b067cfc5 | ||
|
|
4959b84b4c | ||
|
|
d42562fdcb | ||
|
|
1e0aacd811 | ||
|
|
329469fe84 | ||
|
|
93b0c5a7e5 | ||
|
|
9e456fd315 | ||
|
|
8203c71b03 | ||
|
|
80d1e9a9a7 | ||
|
|
3c27e57b19 | ||
|
|
b46b2f048d | ||
|
|
8d403f579c | ||
|
|
12b274ab43 | ||
|
|
986cccb800 | ||
|
|
5da8728d6c | ||
|
|
66c9a1e90a | ||
|
|
a1925e1d0b | ||
|
|
da0910b1e5 | ||
|
|
8dbbe34dfc | ||
|
|
947d552509 | ||
|
|
037bc4ea2b | ||
|
|
cfbef141d8 | ||
|
|
410ad0dc09 | ||
|
|
3d9b42f0c2 | ||
|
|
eeea21c882 | ||
|
|
d94e5480c9 | ||
|
|
a5c8e87e6d | ||
|
|
08f74201b6 | ||
|
|
3a25c683b6 | ||
|
|
fb43f8bf1a | ||
|
|
bf082600c3 | ||
|
|
7596c66703 | ||
|
|
e1bcf6c47e | ||
|
|
ef1d6c78ac | ||
|
|
f36406af08 | ||
|
|
4b7d215d9d | ||
|
|
e09f12dc0b | ||
|
|
efa7406741 | ||
|
|
5a2181c064 | ||
|
|
dda81b12da | ||
|
|
c4bf67d133 | ||
|
|
f355c8679d | ||
|
|
095864de39 | ||
|
|
0eb196e852 | ||
|
|
62e5d8d841 | ||
|
|
2f82fb842d | ||
|
|
f9fa6abbad | ||
|
|
4b55a69150 | ||
|
|
42e12fae24 | ||
|
|
2f55d5130a | ||
|
|
cd4b47b397 | ||
|
|
126cba1e94 | ||
|
|
e4e894fa54 | ||
|
|
65f701d459 | ||
|
|
c2b7cc7964 | ||
|
|
969d1dff2a | ||
|
|
e0fab808b9 | ||
|
|
77031d7082 | ||
|
|
5a0f7ea706 | ||
|
|
9d041c4b62 | ||
|
|
ec4d29c327 | ||
|
|
5f8d8988e3 | ||
|
|
a31912f710 | ||
|
|
e0d42962e7 | ||
|
|
47688bf016 | ||
|
|
39a695959d | ||
|
|
71d45a67b7 | ||
|
|
8dc1369ba3 | ||
|
|
1206654d98 | ||
|
|
1492763d0c | ||
|
|
285fafc464 | ||
|
|
b15cc59b95 | ||
|
|
55cfe31dfe | ||
|
|
dafa6e0310 | ||
|
|
4befe17cab | ||
|
|
2217b560cb | ||
|
|
39d01a1da8 | ||
|
|
4e14ad7821 | ||
|
|
aee5a2cbe4 | ||
|
|
de2d5aec1a | ||
|
|
bea03de562 | ||
|
|
0aeccbb02c | ||
|
|
4e11152e76 | ||
|
|
5059028e8a | ||
|
|
070e6cf848 | ||
|
|
4187fe7261 | ||
|
|
bdec147874 | ||
|
|
189fc76dad | ||
|
|
c0a68005d4 | ||
|
|
8187e4cdc2 | ||
|
|
cc98fd4167 | ||
|
|
422e014eff | ||
|
|
dd4e044608 | ||
|
|
13fad1ca47 | ||
|
|
70aaa29016 | ||
|
|
7dcec9afcf | ||
|
|
608642fc25 | ||
|
|
dd62c08b09 | ||
|
|
315fc21eca | ||
|
|
8cfd3aeda9 | ||
|
|
6061323c36 | ||
|
|
17da8b04bf | ||
|
|
3a948406d5 | ||
|
|
91c52f8ec8 | ||
|
|
6076bbb554 | ||
|
|
f70d3359c4 | ||
|
|
2dbfbe36c3 | ||
|
|
a25bd03566 | ||
|
|
109da1c2cc | ||
|
|
9a48e25bb1 | ||
|
|
a3ade200a9 | ||
|
|
eb1901f03d | ||
|
|
f8c7cdfc28 | ||
|
|
ea58d84b55 | ||
|
|
1360caaa81 | ||
|
|
315a7b9e6a | ||
|
|
79311d107b | ||
|
|
77435fcbd7 | ||
|
|
4395c07648 | ||
|
|
f9cc77382a | ||
|
|
e4fce08eff | ||
|
|
47196cbc55 | ||
|
|
c0bf301434 | ||
|
|
f6671f8561 | ||
|
|
26aab2961b | ||
|
|
c233abe3a4 | ||
|
|
beb3646bef | ||
|
|
eb8330a420 | ||
|
|
7f3c2176f8 | ||
|
|
1d0fdd68f4 | ||
|
|
b26c78828e | ||
|
|
85648c7f11 | ||
|
|
8588f446aa | ||
|
|
d723c5c1c7 | ||
|
|
7897f2489c | ||
|
|
86e2e0a2c3 | ||
|
|
e2349019a3 | ||
|
|
e485044cfb | ||
|
|
72d80e2857 | ||
|
|
79a4733698 | ||
|
|
c64e1daa99 | ||
|
|
d6b4933b05 | ||
|
|
bcf9cee0f8 | ||
|
|
a2960a7997 | ||
|
|
dac9874895 | ||
|
|
a4d374ecb6 | ||
|
|
3e56c8ed8b | ||
|
|
f4c11d14e7 | ||
|
|
dde805931d | ||
|
|
fedc721432 | ||
|
|
b09cb24804 | ||
|
|
80bfeb1a29 | ||
|
|
63ad51a637 | ||
|
|
5ee6232bfc | ||
|
|
b7d399faf7 | ||
|
|
28691bb8a0 | ||
|
|
fd61f35f78 | ||
|
|
0505b59781 | ||
|
|
a3601e5167 | ||
|
|
99f63ab64d | ||
|
|
bb2a9fe180 | ||
|
|
e9c7c7ee4c | ||
|
|
ff7d4f237a | ||
|
|
8bf9f8057e | ||
|
|
27b0f531d7 | ||
|
|
01e96d3086 | ||
|
|
95e7a7c8eb | ||
|
|
bbc2f4766e | ||
|
|
12dde5154f | ||
|
|
5bc3609ad7 | ||
|
|
5c1cdea3c6 | ||
|
|
3da5b3a278 | ||
|
|
9f6460ddae | ||
|
|
f1dcf85d7b | ||
|
|
7b78edf38f | ||
|
|
4a726a0c75 | ||
|
|
5afa7e9fc3 | ||
|
|
75c102f304 | ||
|
|
68f3c10055 | ||
|
|
e9aeda2a34 | ||
|
|
45c7a110b6 | ||
|
|
e438e6aedb | ||
|
|
8dd888bcbd | ||
|
|
5f12291ac4 | ||
|
|
e206d78a52 | ||
|
|
d94a82b0a7 | ||
|
|
3bee3d1701 | ||
|
|
631352e1ef | ||
|
|
f2d5dee49e | ||
|
|
2d578c7cd9 | ||
|
|
b07ff100d1 | ||
|
|
b0c10b2248 | ||
|
|
7b8249442d | ||
|
|
8221339318 | ||
|
|
b773af96b8 | ||
|
|
dbc7808c70 | ||
|
|
77c5000f16 | ||
|
|
56928b6ca0 | ||
|
|
8178dfe7bd | ||
|
|
0db6c667c6 | ||
|
|
2b0a642827 | ||
|
|
f71c0f8cb8 | ||
|
|
3782372f65 | ||
|
|
9e35e42030 | ||
|
|
7a8195e54c | ||
|
|
b50ee28693 | ||
|
|
e134f910aa | ||
|
|
17eb6e47eb | ||
|
|
82ce626d8a | ||
|
|
e063ff5e54 | ||
|
|
5aa98966bc | ||
|
|
fca2746a82 | ||
|
|
7faffc2de7 | ||
|
|
86a8a9dc85 | ||
|
|
c13a0c1c26 | ||
|
|
6ce3c070b8 | ||
|
|
e1cb11da22 | ||
|
|
c628ea34b7 | ||
|
|
33b7c726f6 | ||
|
|
6f3fd424e1 | ||
|
|
b048ce9c8e | ||
|
|
6a1040d659 | ||
|
|
fc05c28231 | ||
|
|
5d165bc6df | ||
|
|
c139b5eabb | ||
|
|
d6dd0e551d | ||
|
|
a84a7bb7c3 | ||
|
|
7195ae6e46 | ||
|
|
3c70b2f033 | ||
|
|
c46340a830 | ||
|
|
8d703b1459 | ||
|
|
f1145ef169 | ||
|
|
a28f9ceeba | ||
|
|
1927bb4798 | ||
|
|
d4c77f9786 | ||
|
|
021f8d0331 | ||
|
|
e7d25550ee | ||
|
|
8227276437 | ||
|
|
38ef76bcdc | ||
|
|
7faa0f60b4 | ||
|
|
faebbb2b8a | ||
|
|
bc9beb1e87 | ||
|
|
f161f723d7 | ||
|
|
6c94550de3 | ||
|
|
b39a45781a | ||
|
|
9273c9ee10 | ||
|
|
e6285914b0 | ||
|
|
7d2eb83a1b | ||
|
|
7e622f1153 | ||
|
|
9b30a634b1 | ||
|
|
e897d2ef81 | ||
|
|
f5b177dda8 | ||
|
|
5f51b5d565 | ||
|
|
8d7753fb40 | ||
|
|
4c6f5744d8 | ||
|
|
43eb2932ba | ||
|
|
59de0e7a4a | ||
|
|
7b204cf910 | ||
|
|
b587a19a0f | ||
|
|
e58420b031 | ||
|
|
24313d6709 | ||
|
|
7acb30b981 | ||
|
|
7454620aa2 | ||
|
|
abb0799817 | ||
|
|
aebd28dbef | ||
|
|
152db9fb8e | ||
|
|
980cd520cd | ||
|
|
373ec8b5a1 | ||
|
|
bacb78e9e8 | ||
|
|
333e112e37 | ||
|
|
818d5d782f | ||
|
|
8774090086 | ||
|
|
0ca65c6d61 | ||
|
|
c38daac646 | ||
|
|
c31f5b1d59 | ||
|
|
2320a56a63 | ||
|
|
07bd91b456 | ||
|
|
803f7c3a4b | ||
|
|
a1926982c6 | ||
|
|
b3306d50eb | ||
|
|
3e6e5f95ec | ||
|
|
df71fb42ac | ||
|
|
fe81a354a3 | ||
|
|
67ba2e49c3 | ||
|
|
8dec42f295 | ||
|
|
5942553370 | ||
|
|
ae5d31746e | ||
|
|
1c1976abbf | ||
|
|
b3465ddf89 | ||
|
|
f67fafdb8e | ||
|
|
ffcac677e0 | ||
|
|
a9d643aa55 | ||
|
|
fa3647e8e5 | ||
|
|
db839f6d6d | ||
|
|
3a85d5b89f | ||
|
|
1575c2bc10 | ||
|
|
57189183d6 | ||
|
|
01c5cf98df | ||
|
|
9ad2995168 | ||
|
|
51fc6518e1 | ||
|
|
530db4e904 | ||
|
|
cd92ebd69c | ||
|
|
5c58552d91 | ||
|
|
584aebf76b | ||
|
|
43a2480699 | ||
|
|
699503042f | ||
|
|
02e71c23de | ||
|
|
c24c3868bb | ||
|
|
5c60819668 | ||
|
|
480a125a20 | ||
|
|
598a6ebaed | ||
|
|
185ad5e747 | ||
|
|
42d7e4312b | ||
|
|
41a741724f | ||
|
|
087e811586 | ||
|
|
fa07bc143e | ||
|
|
e13f5ed730 | ||
|
|
48108cebc9 | ||
|
|
ecac17a00a | ||
|
|
3ba215887c | ||
|
|
edbc1baf32 | ||
|
|
500fa7f314 | ||
|
|
a10dfa4ab4 | ||
|
|
b208571ed7 | ||
|
|
c1ec27045c | ||
|
|
111b12161c | ||
|
|
d23d18933c | ||
|
|
f0e736962d | ||
|
|
b12d1491d4 | ||
|
|
6d1a094b15 | ||
|
|
88d14792a4 | ||
|
|
7780a98abe | ||
|
|
a1248db3e7 | ||
|
|
6fd2d12d3f | ||
|
|
9fab52c044 | ||
|
|
a32f55d64e | ||
|
|
96d2b001ea | ||
|
|
e38d6c9f9e | ||
|
|
be129d243b | ||
|
|
c85355986b | ||
|
|
310c0e8379 | ||
|
|
f0dbffe4f8 | ||
|
|
598a482538 | ||
|
|
a995f3ab52 | ||
|
|
ec5454de44 | ||
|
|
ec55bddbd4 | ||
|
|
808591df56 | ||
|
|
96ae3da1e0 | ||
|
|
4f13df69c7 | ||
|
|
6d305e4a84 | ||
|
|
d3dab982a1 | ||
|
|
2f6adbae3c | ||
|
|
ccdc1eed5a | ||
|
|
65dee154f7 | ||
|
|
662db009de | ||
|
|
d07d8f6857 | ||
|
|
0327f6b1ea | ||
|
|
16dea2ee09 | ||
|
|
5e3fe139fc | ||
|
|
55d41fca05 | ||
|
|
0b7bb29557 | ||
|
|
6b683bd02d | ||
|
|
8f1a498953 | ||
|
|
293ed9065d | ||
|
|
8908fb7ee0 | ||
|
|
2877178b34 | ||
|
|
d527139f48 | ||
|
|
b3d8180541 | ||
|
|
3411c340ab | ||
|
|
4482089712 | ||
|
|
c8ce2343d7 | ||
|
|
d547d04277 | ||
|
|
8f1191733b | ||
|
|
00bdbcf857 | ||
|
|
bf8070c42d | ||
|
|
346a0b84ae | ||
|
|
ad48381744 | ||
|
|
0f30d7744d | ||
|
|
095a978120 | ||
|
|
1b72646772 | ||
|
|
a7b129147f | ||
|
|
6496a6643f | ||
|
|
e172217427 | ||
|
|
8c67eee4c8 | ||
|
|
ca9039b8d5 | ||
|
|
e260632a45 | ||
|
|
678f4fca8a | ||
|
|
5d88d07edc | ||
|
|
08aa591c65 | ||
|
|
f2a8edb29f | ||
|
|
50d7e8dc3d | ||
|
|
8403e36d4d | ||
|
|
2dda326cc4 | ||
|
|
9002a8db04 | ||
|
|
5ec5198dda | ||
|
|
0326b7d7ac | ||
|
|
2f5e7f3b2d | ||
|
|
0e17658269 | ||
|
|
87edda5972 | ||
|
|
ab8c3c2b75 | ||
|
|
44cef002ed | ||
|
|
bc80fe693a | ||
|
|
1898b51dc2 | ||
|
|
a5dcf5958e | ||
|
|
9fba72cbab | ||
|
|
912fdeaf09 | ||
|
|
36c417458d | ||
|
|
f1591e593a | ||
|
|
117ac0f5d6 | ||
|
|
e72a42fd2d | ||
|
|
e6e2f4c22c | ||
|
|
07b6e2b9f1 | ||
|
|
5ab10f4024 | ||
|
|
0ac08456bc | ||
|
|
80a3549ef5 | ||
|
|
770d5eb257 | ||
|
|
b32499f6ec | ||
|
|
d9819d8b3d | ||
|
|
932b825818 | ||
|
|
a0cbc5822e | ||
|
|
2ab50c6b61 | ||
|
|
d7426f6d35 | ||
|
|
8f15266f0a | ||
|
|
936c7190c7 | ||
|
|
3452984b8e | ||
|
|
3e17890528 | ||
|
|
2a7c50d356 | ||
|
|
05bca368c2 | ||
|
|
89c78f6030 | ||
|
|
b59b0259ca | ||
|
|
e46e1b20de | ||
|
|
7089abcef2 | ||
|
|
e6148a97a3 | ||
|
|
9e40033a92 | ||
|
|
08d4e19851 | ||
|
|
dcc0768411 | ||
|
|
f14062c721 | ||
|
|
0508b70658 | ||
|
|
04f8545397 | ||
|
|
633f985360 | ||
|
|
a649a6ebac | ||
|
|
634a8b4532 | ||
|
|
f3709a41e3 | ||
|
|
2bfebfee3c | ||
|
|
76ab5fbf78 | ||
|
|
c0b0c74638 | ||
|
|
6c0b771758 | ||
|
|
2f983fc305 | ||
|
|
3cf0d60f5d | ||
|
|
751e76b453 | ||
|
|
c2f95f7953 | ||
|
|
924b994df2 | ||
|
|
b10de5e82c | ||
|
|
65ffce8db2 | ||
|
|
58aeb2e40f | ||
|
|
141d737ca5 | ||
|
|
d0fd53a2ca | ||
|
|
3e0a6ea2cf | ||
|
|
758ad3eb06 | ||
|
|
b132a66707 | ||
|
|
f241f12ddb | ||
|
|
e1daf9467c | ||
|
|
5457ddb44f | ||
|
|
6fee13b0a5 | ||
|
|
2b17e173f5 | ||
|
|
569d4a5d8b | ||
|
|
51a88a23ac | ||
|
|
f41504ca57 | ||
|
|
bacb7018cb | ||
|
|
671ed3c2fe | ||
|
|
372e994617 | ||
|
|
e4560df62f | ||
|
|
920daf7fde | ||
|
|
ad1a15faaa | ||
|
|
459cf2e380 | ||
|
|
8d058a53fd | ||
|
|
d864ae9fef | ||
|
|
f1eeb61264 | ||
|
|
1418dd8b29 | ||
|
|
0297980ca3 | ||
|
|
5e94aaa2cb | ||
|
|
b929a8fe2e | ||
|
|
8c2f0bacf1 | ||
|
|
0bc02de012 | ||
|
|
411a282063 | ||
|
|
6c4d55622b | ||
|
|
e214bf3581 | ||
|
|
78e29d2bbf | ||
|
|
a93c10b794 | ||
|
|
3240d6f11a | ||
|
|
d5f38fe2f2 | ||
|
|
d4b1680727 | ||
|
|
b04e5760fb | ||
|
|
42c629ca45 | ||
|
|
68f45beb20 | ||
|
|
ea95897bbd | ||
|
|
4d1dc0c949 | ||
|
|
9fc892f723 | ||
|
|
5541381afe | ||
|
|
ed12bae6aa | ||
|
|
1520c1ebab | ||
|
|
790190e5c3 | ||
|
|
24889f7dcd | ||
|
|
8397685430 | ||
|
|
fc411c5c1c | ||
|
|
3a91f43bbb | ||
|
|
5e1f1675b8 | ||
|
|
9946987f69 | ||
|
|
526181a76b | ||
|
|
ce8f8c05e1 | ||
|
|
3844b88f7e | ||
|
|
db3c232173 | ||
|
|
22b77af9d3 | ||
|
|
3e29732e46 | ||
|
|
54e1efd794 | ||
|
|
8809c1634f | ||
|
|
13e1be1f74 | ||
|
|
26a123f5a8 | ||
|
|
f062fda2f7 | ||
|
|
e45e31d223 | ||
|
|
101261ca63 | ||
|
|
4ba9a19b5c | ||
|
|
f8eab7d611 | ||
|
|
40a9f19352 | ||
|
|
4b81e0d8af | ||
|
|
ea37bf8b45 | ||
|
|
c30f8b09b0 | ||
|
|
686f931fb4 | ||
|
|
1fe1e6f265 | ||
|
|
860decdac5 | ||
|
|
d5b90c91f5 | ||
|
|
20d6e365a1 | ||
|
|
e5e50c2220 | ||
|
|
e8da7baee2 | ||
|
|
8ab9e6bac7 | ||
|
|
9129301c89 | ||
|
|
9545e0145f | ||
|
|
15d3e4023b | ||
|
|
205e4dedd1 | ||
|
|
324d796aca | ||
|
|
5b31e8e9d8 | ||
|
|
0afb62ee88 | ||
|
|
1b0d053ab9 | ||
|
|
5871c4f092 | ||
|
|
5d415e6679 | ||
|
|
3a7384ec26 | ||
|
|
1d3a8bcacd | ||
|
|
dd187aef08 | ||
|
|
78b2c4d094 | ||
|
|
32b7a314b1 | ||
|
|
c8d768c59a | ||
|
|
3ef1c9167f | ||
|
|
36cdcbc3c1 | ||
|
|
83876532d0 | ||
|
|
edc824d05e | ||
|
|
9a7869dd40 | ||
|
|
1aa247d4da | ||
|
|
5db9f28b33 | ||
|
|
8599ad4a3c | ||
|
|
448c2a27d4 | ||
|
|
f2f4fa1b98 | ||
|
|
6f43a189c0 | ||
|
|
dd4de9822f | ||
|
|
c9e83e0517 | ||
|
|
4ac63950ad | ||
|
|
7a0b2c958b | ||
|
|
3fcc37e086 | ||
|
|
55181cec8c | ||
|
|
41d259006e | ||
|
|
93e8ec7f06 | ||
|
|
ba1d1c3bac | ||
|
|
fbaff2b75b | ||
|
|
9774e8807b | ||
|
|
b30103c790 | ||
|
|
bb9408b5d0 | ||
|
|
42c3c7bc48 | ||
|
|
464040895c | ||
|
|
525747dc53 | ||
|
|
c61d992559 | ||
|
|
2f79b079fd | ||
|
|
655bc39d85 | ||
|
|
1eb12d4fa0 | ||
|
|
2ab9186259 | ||
|
|
ab61aef985 | ||
|
|
65b3e9f8c1 | ||
|
|
1f57aa1ea5 | ||
|
|
340d827377 | ||
|
|
5cd25e24e4 | ||
|
|
58afc92a26 | ||
|
|
acb9931fe6 | ||
|
|
d4b035ac1a | ||
|
|
403dd5c005 | ||
|
|
7e4e1ec68f | ||
|
|
547764e3c1 | ||
|
|
541a7974e0 | ||
|
|
6bf6f82cad | ||
|
|
7be2325a95 | ||
|
|
fa1f739458 | ||
|
|
20289ff81b | ||
|
|
6d67d30aee | ||
|
|
bd0bd2e087 | ||
|
|
3d79799450 | ||
|
|
c99f9205b7 | ||
|
|
26bb54472f | ||
|
|
73e13fee37 | ||
|
|
205c1ac3b6 | ||
|
|
d317744f05 | ||
|
|
47611b7615 | ||
|
|
6420a51dd0 | ||
|
|
7c17d5bac0 | ||
|
|
0efd7c93c5 | ||
|
|
806be9551c | ||
|
|
b4dd3a9889 | ||
|
|
6b4a1b6758 | ||
|
|
4510b69798 | ||
|
|
84a3ee209a | ||
|
|
d6b0fccbda | ||
|
|
d1e31da2e5 | ||
|
|
923d32ee6d | ||
|
|
4b0fe879cb | ||
|
|
b87aeffcd8 | ||
|
|
88aafec6e3 | ||
|
|
6fe9dae3d6 | ||
|
|
2cb6ddf3ca | ||
|
|
799622a932 | ||
|
|
4c1e22b0f6 | ||
|
|
2283652704 | ||
|
|
33fb2daabf | ||
|
|
c79f59ec05 | ||
|
|
845aaad891 | ||
|
|
3c0b061220 | ||
|
|
af7de73f5c | ||
|
|
1a8a9f0047 | ||
|
|
a3b4e8db44 | ||
|
|
f9e8875803 | ||
|
|
e4c11d9a88 | ||
|
|
6d1d8da101 | ||
|
|
77303e668f | ||
|
|
72725b91c7 | ||
|
|
46f50f55c2 | ||
|
|
5e880f6bfa | ||
|
|
058a73f8a0 | ||
|
|
1ad8d34ecb | ||
|
|
3f9f926c8e | ||
|
|
80cf88dcc1 | ||
|
|
dddc7f348f | ||
|
|
ce45f2e114 | ||
|
|
d22a7c0a63 | ||
|
|
59162155de | ||
|
|
0f347cd0b4 | ||
|
|
1f983db47c | ||
|
|
dc50793733 | ||
|
|
b98329f91c | ||
|
|
587d8fbfa9 | ||
|
|
26a2e9ef53 | ||
|
|
e5ca98a1d3 | ||
|
|
5bd5e9000e | ||
|
|
d566642c98 | ||
|
|
f81ddc60ec | ||
|
|
6e0b20c921 | ||
|
|
0c308b38c5 | ||
|
|
8e0fdf68e4 | ||
|
|
9c7a9b5674 | ||
|
|
0a49e31b30 | ||
|
|
9478206202 | ||
|
|
c86e6f5b88 | ||
|
|
87868acecd | ||
|
|
6d877754da | ||
|
|
dd5521a07c | ||
|
|
3a6a84917b | ||
|
|
cca142ce86 | ||
|
|
fa3567cb9f | ||
|
|
7d22230b13 | ||
|
|
9694c796e3 | ||
|
|
1b7f684ab2 | ||
|
|
fef8f4d29c | ||
|
|
0d7e945623 | ||
|
|
13ea8eae77 | ||
|
|
cdb2ef3ac7 | ||
|
|
f216e0198f | ||
|
|
c5c3698f43 | ||
|
|
299d3b9f60 | ||
|
|
eaaebeaebb | ||
|
|
2ef2d2b9c5 | ||
|
|
da6698b216 | ||
|
|
c9f391dfc1 | ||
|
|
0f62926623 | ||
|
|
a856b4027b | ||
|
|
e2f72ecffc | ||
|
|
d888bcd473 | ||
|
|
0bfd5fa9a3 | ||
|
|
9c05ccef69 | ||
|
|
c7eb2ffe5c | ||
|
|
5281b6df77 | ||
|
|
cd5bb6a309 | ||
|
|
94a44d7af4 | ||
|
|
662050b89f | ||
|
|
3f7f3140eb | ||
|
|
a419694f70 | ||
|
|
0a20f77b08 | ||
|
|
dc11d18161 | ||
|
|
cde83e9d7d | ||
|
|
1476fda014 | ||
|
|
7a875f2db4 | ||
|
|
b868f37da5 | ||
|
|
9bef5a62dd | ||
|
|
d1aff30c9e | ||
|
|
a356dafde0 | ||
|
|
09477384fe | ||
|
|
6b923542e8 | ||
|
|
9722cf718c | ||
|
|
702b973c87 | ||
|
|
472372c9ed | ||
|
|
d358f0d27b | ||
|
|
d66bbd95f0 | ||
|
|
aae498509b | ||
|
|
4987fb5f15 | ||
|
|
b1ed299286 | ||
|
|
679ac3e5b1 | ||
|
|
181ef788a3 | ||
|
|
d2caa0953f | ||
|
|
3f88e02587 | ||
|
|
245da9b422 | ||
|
|
8cc075aff3 | ||
|
|
128a243166 | ||
|
|
0e41365020 | ||
|
|
bd6d5ffbb9 | ||
|
|
de7951f4db | ||
|
|
bdbf1fbb43 | ||
|
|
a7b6010ce2 | ||
|
|
5bba109873 | ||
|
|
d69ae60bcb | ||
|
|
a0277aba2e | ||
|
|
caba631db9 | ||
|
|
5095620005 | ||
|
|
abcdc0875c | ||
|
|
a4e41a57d7 | ||
|
|
e8bb3864e3 | ||
|
|
3e03d52fce | ||
|
|
4f64d466fb | ||
|
|
3102c545ce | ||
|
|
3cd1066a8d | ||
|
|
6494b7ea89 | ||
|
|
f232b327c0 | ||
|
|
204ed1f257 | ||
|
|
2f5d13ac10 | ||
|
|
65a379c8da | ||
|
|
99df5fadbc | ||
|
|
c8e6dca263 | ||
|
|
9dec40eca7 | ||
|
|
92cdb27e23 | ||
|
|
4896043599 | ||
|
|
5f0ddeedd0 | ||
|
|
e679e760ee | ||
|
|
a439688b3c | ||
|
|
0d17757729 | ||
|
|
899bbc2dbc | ||
|
|
57b68880db | ||
|
|
06c59763bc | ||
|
|
71c1d16c06 | ||
|
|
64c1b72481 | ||
|
|
e5742e057d | ||
|
|
a9d6176fd2 | ||
|
|
1b0aa2a9b1 | ||
|
|
a49c230bb2 | ||
|
|
b65749cf70 | ||
|
|
0cf54a6a03 | ||
|
|
4d77277f2d | ||
|
|
8b81506ed3 | ||
|
|
24c6509a61 | ||
|
|
3c32c4160d | ||
|
|
1f912d86e1 | ||
|
|
9c93ab0b6d | ||
|
|
6646a20a5d | ||
|
|
92f471c476 | ||
|
|
4c7ce97650 | ||
|
|
4d1fc994c0 | ||
|
|
c4310c554e | ||
|
|
c603326e58 | ||
|
|
a93e04a44e | ||
|
|
db9e649f6e | ||
|
|
c26aca4686 | ||
|
|
f822268ae1 | ||
|
|
4ebcf40619 | ||
|
|
a884b94ac0 | ||
|
|
194e705982 | ||
|
|
c77ec3bf20 | ||
|
|
0a1857249b | ||
|
|
3be3a1f2e6 | ||
|
|
62f9488829 | ||
|
|
9bcaef192c | ||
|
|
bcb1630f20 | ||
|
|
5f7922d7fd | ||
|
|
66b1d297ba | ||
|
|
eb4780a952 | ||
|
|
34f724a4a4 | ||
|
|
c5b250236f | ||
|
|
e5b122ee61 | ||
|
|
3b20021981 | ||
|
|
a7d1f180a4 | ||
|
|
68374e7c62 | ||
|
|
ba26a97ddc | ||
|
|
2db7ce8da1 | ||
|
|
6958da1adb | ||
|
|
cf48cd0ae5 | ||
|
|
b1b3966d41 | ||
|
|
c171a37f24 | ||
|
|
c13f1991c9 | ||
|
|
da15cc4de7 | ||
|
|
44c686f494 | ||
|
|
03bd5ad426 | ||
|
|
914a3d71c2 | ||
|
|
5c2e0935c6 | ||
|
|
e1ec604655 | ||
|
|
0dad10d6ab | ||
|
|
136138daab | ||
|
|
6efe563a69 | ||
|
|
fd068443aa | ||
|
|
82d0f62d73 | ||
|
|
01ba6ddecd | ||
|
|
769b379a8b | ||
|
|
1b981e0695 | ||
|
|
9798b9fd50 | ||
|
|
10792c0bc6 | ||
|
|
1c61afd3ee | ||
|
|
737ef583ee | ||
|
|
7b4365bd8a | ||
|
|
041fce743e | ||
|
|
ad4904a0ec | ||
|
|
42a1bca64d | ||
|
|
492a5bbb38 | ||
|
|
c40ef22c20 | ||
|
|
783aac561a | ||
|
|
02245c150c | ||
|
|
54a93775e4 | ||
|
|
ca778aac70 | ||
|
|
007ca4c6b0 | ||
|
|
b3dfce7b5a | ||
|
|
c75f1685c5 | ||
|
|
db5b103ab3 | ||
|
|
1925b7b324 | ||
|
|
d39bcfb7bd | ||
|
|
c7770c37d0 | ||
|
|
ca2fb81247 | ||
|
|
b2f1c9e832 | ||
|
|
cff4eebb74 | ||
|
|
a3aab5aeca | ||
|
|
63e5d8f7ea | ||
|
|
e4df7b10f6 | ||
|
|
f39a1e7d03 | ||
|
|
a473f6aa16 | ||
|
|
6907c24690 | ||
|
|
ef3d8a9277 | ||
|
|
1a183b7f17 | ||
|
|
88f7b30128 | ||
|
|
4b38389dc8 | ||
|
|
865a45044f | ||
|
|
7378d06bfd | ||
|
|
55e19de8a1 | ||
|
|
4d7cb06481 | ||
|
|
7179a2995d | ||
|
|
2b853df75b | ||
|
|
ae6bcc2987 | ||
|
|
ed61e5c7f7 | ||
|
|
3581ac5ebd | ||
|
|
1f369b47d7 | ||
|
|
bb9049bef4 | ||
|
|
94f15aba40 | ||
|
|
b16b8388ef | ||
|
|
b1e89e7904 | ||
|
|
f48e2f3b18 | ||
|
|
bd673a3f26 | ||
|
|
51ec699649 | ||
|
|
ed6be510fb | ||
|
|
55f05ba839 | ||
|
|
17c9382a21 | ||
|
|
43c0eda2be | ||
|
|
f2c5515317 | ||
|
|
c1441eb758 | ||
|
|
cf92fb921d | ||
|
|
559ca3e97b | ||
|
|
7c095175ab | ||
|
|
3b2635014c | ||
|
|
755040444a | ||
|
|
59afb012b6 | ||
|
|
7d9a52301c | ||
|
|
50a53181dc | ||
|
|
36f6fec99f | ||
|
|
83eeb488f9 | ||
|
|
5394a35e1a | ||
|
|
0cd68ff8f8 | ||
|
|
e9ae8063db | ||
|
|
1c4e23512b | ||
|
|
51bdfa44b1 | ||
|
|
98d0a397a3 | ||
|
|
1dc060123d | ||
|
|
14349cb583 | ||
|
|
eca959034c | ||
|
|
9844550d6c | ||
|
|
82fcf08d84 | ||
|
|
845a35a9b8 | ||
|
|
0e4751ebee | ||
|
|
56badd44f3 | ||
|
|
399b3fd198 | ||
|
|
43a7ca7fe8 | ||
|
|
b951624ed3 | ||
|
|
1b21f2d1c7 | ||
|
|
43ea0effa2 | ||
|
|
6df9b95dea | ||
|
|
630aa53d98 | ||
|
|
40c81b88d4 | ||
|
|
027a317291 | ||
|
|
81b538556d | ||
|
|
6aece1cf8c | ||
|
|
cd7b9d31c9 | ||
|
|
03a6e6fc6a | ||
|
|
1d1aae03f3 | ||
|
|
b47ad50d42 | ||
|
|
a924fd0e7e | ||
|
|
82ae908e6a | ||
|
|
8e497e2a48 | ||
|
|
cbb4565a48 | ||
|
|
471fbee090 | ||
|
|
d66de937d9 | ||
|
|
3ea230fd17 | ||
|
|
34bc571f80 | ||
|
|
db46804bfe | ||
|
|
2bd0faac2e | ||
|
|
a9a6e58d60 | ||
|
|
b40f980c62 | ||
|
|
12ac781ef8 | ||
|
|
8373ffbf10 | ||
|
|
0233dca884 | ||
|
|
c1a3162a54 | ||
|
|
fc2f5c3615 | ||
|
|
3a5ac9df10 | ||
|
|
63f634af00 | ||
|
|
9cb3eefdc4 | ||
|
|
1c9e9da10f | ||
|
|
71c0ba63ca | ||
|
|
c04d3b2ace | ||
|
|
e8497bb0cc | ||
|
|
3430349dd1 | ||
|
|
fa6a5f75af | ||
|
|
7b9eb4c87c | ||
|
|
808411bc0b | ||
|
|
c3ab510b57 | ||
|
|
cbc653be37 | ||
|
|
e9efe5bbb7 | ||
|
|
a7c234b272 | ||
|
|
bb64d0dd54 | ||
|
|
f82b478a77 | ||
|
|
2028642efe | ||
|
|
9af9bd0c4c | ||
|
|
662bf83a88 | ||
|
|
2d474ccbda | ||
|
|
cec746d632 | ||
|
|
8371ac5b0d | ||
|
|
f248788d14 | ||
|
|
bf202f25dd | ||
|
|
2d2472dbe9 | ||
|
|
3adfa3c2a8 | ||
|
|
bf05155c5e | ||
|
|
d50df6a6fc | ||
|
|
a2b38c8d05 | ||
|
|
d546da8b5f | ||
|
|
7c60ffa88d | ||
|
|
6b235ab083 | ||
|
|
7c4cdef66d | ||
|
|
c0a2da443a | ||
|
|
e53658759b | ||
|
|
6dc4c1c03a | ||
|
|
818c3b6092 | ||
|
|
6e5dee13e1 | ||
|
|
cae78622f6 | ||
|
|
c5db677663 | ||
|
|
c6942daf74 | ||
|
|
ea644a2293 | ||
|
|
01e69ce2b0 | ||
|
|
187a017c4d | ||
|
|
f9ce1d17c8 | ||
|
|
ef4cd6a4a7 | ||
|
|
6a1543cb82 | ||
|
|
80c8dcacb3 | ||
|
|
0ad2dea722 | ||
|
|
dec3c45f6c | ||
|
|
32a73ad4b9 | ||
|
|
452e03b894 | ||
|
|
01bdddaee4 | ||
|
|
f7c82b0920 | ||
|
|
820eeb7752 | ||
|
|
2e25ef6f81 | ||
|
|
5736d2c9cc | ||
|
|
056a1f6a33 | ||
|
|
f96e211cd6 | ||
|
|
0d473cbe18 | ||
|
|
95514b05ca | ||
|
|
a2c0b47908 | ||
|
|
f2528b5e9a | ||
|
|
02f301dae0 | ||
|
|
6c47fc9023 | ||
|
|
f03adf727b | ||
|
|
77684dfe31 | ||
|
|
ee688d9ae4 | ||
|
|
9b16d3624e | ||
|
|
dc622a9bd5 | ||
|
|
2fc75be3dd | ||
|
|
eb883bc51e | ||
|
|
fdc5ed93fc | ||
|
|
148960eecd | ||
|
|
0265fc36fa | ||
|
|
f4c2a0a7f8 | ||
|
|
de3eb861ed | ||
|
|
f5b64b4958 | ||
|
|
20eb59d9b6 | ||
|
|
ca1bb8e634 | ||
|
|
6213c098ce | ||
|
|
31023a1a71 | ||
|
|
b963b9547b | ||
|
|
fa4c0af78d | ||
|
|
ef0e0432a7 | ||
|
|
d16f2b54fe | ||
|
|
a3a3da309c | ||
|
|
fa7b71cabe | ||
|
|
d3490f6a2e | ||
|
|
82dc126952 | ||
|
|
6f90e765d4 | ||
|
|
b1382e8e89 | ||
|
|
0fb739935f | ||
|
|
e49a9f1f06 | ||
|
|
0f5dd99167 | ||
|
|
2f9f3db198 | ||
|
|
00ebc265d8 | ||
|
|
5995b42872 | ||
|
|
9edb0abda0 | ||
|
|
eaa966e72b | ||
|
|
a48df23252 | ||
|
|
3aa8eb9533 | ||
|
|
3ddd1d5f21 | ||
|
|
ea15f0690c | ||
|
|
8751ef7439 | ||
|
|
8c393e3144 | ||
|
|
a3ef2a43ac | ||
|
|
d2b3029f67 | ||
|
|
3e800ec7c8 | ||
|
|
47d963b585 | ||
|
|
397ae3407e | ||
|
|
e407eeea40 | ||
|
|
873232d560 | ||
|
|
47cced540e | ||
|
|
5b4bddc2e0 | ||
|
|
cd511da678 | ||
|
|
c4fbef2dd3 | ||
|
|
92b997fb78 | ||
|
|
05d602c313 | ||
|
|
e1d92bd630 | ||
|
|
373951a75e | ||
|
|
f17898d43d | ||
|
|
129eef79a3 | ||
|
|
e3988e7b84 | ||
|
|
9174338140 | ||
|
|
3f9e2d5d39 | ||
|
|
31449552d1 | ||
|
|
642dc36c41 | ||
|
|
1016c3e22f | ||
|
|
b74d49b0bf | ||
|
|
8b29369b7e | ||
|
|
cb5fe06e58 | ||
|
|
4ebb2baf06 | ||
|
|
0f4a938dfc | ||
|
|
2a16fb5e09 | ||
|
|
c22cf71099 | ||
|
|
c739718710 | ||
|
|
2db9fd9657 | ||
|
|
56b613ff8a | ||
|
|
cd2e9e29d4 | ||
|
|
d1917db47e | ||
|
|
8024f6a804 | ||
|
|
46a0ce8e98 | ||
|
|
c7ccff914f | ||
|
|
8efb6f8808 | ||
|
|
006bf72c17 | ||
|
|
ec3af04f29 | ||
|
|
b45399a045 | ||
|
|
12ed70fec2 | ||
|
|
c3ce0a61b6 | ||
|
|
526e0725d8 | ||
|
|
7e4e0567ef | ||
|
|
ee13978115 | ||
|
|
f5d847f320 | ||
|
|
1df0da7509 | ||
|
|
e4bfd0ef5e | ||
|
|
2e66601c19 | ||
|
|
2484fb85e9 | ||
|
|
5f2fee5a99 | ||
|
|
b2557c38dd | ||
|
|
56acbfc85c | ||
|
|
77f962eed4 | ||
|
|
18a6ecc79a | ||
|
|
c3fc6a087a | ||
|
|
02a47dc7b9 | ||
|
|
30413e6f8f | ||
|
|
6ed7354884 | ||
|
|
94f89acc84 | ||
|
|
392a6cfbca | ||
|
|
e03b6b3824 | ||
|
|
51940cea3d | ||
|
|
5ab346e5d1 | ||
|
|
243024e232 | ||
|
|
e62fd4dc00 | ||
|
|
547522a0a4 | ||
|
|
4fd3ce606a | ||
|
|
ad364b6184 | ||
|
|
3269ba10ec | ||
|
|
b0a7fe4079 | ||
|
|
31afae71d1 | ||
|
|
e7ae969c8e | ||
|
|
fc5bb7417f | ||
|
|
81e6c5c2fa | ||
|
|
e9f73cbb45 | ||
|
|
b36cc8f1e9 | ||
|
|
6f6938deb7 | ||
|
|
b63bddacb0 | ||
|
|
b1d56924e6 | ||
|
|
85d80e7ca0 | ||
|
|
d481d9cca5 | ||
|
|
fe25dbd872 | ||
|
|
0dcc645f22 | ||
|
|
f3090e7827 | ||
|
|
37b9895878 | ||
|
|
d5b4d66272 | ||
|
|
653f706f1b | ||
|
|
d106e6485b | ||
|
|
460a60440a | ||
|
|
9e66c699e1 | ||
|
|
86d2431925 | ||
|
|
d30659c37c | ||
|
|
1402133c32 | ||
|
|
5a99e18d7c | ||
|
|
afe326c1c1 | ||
|
|
e40612a032 | ||
|
|
9c6cca7db6 | ||
|
|
a5283a26ab | ||
|
|
e2020fa7f2 | ||
|
|
de3f6d3e82 | ||
|
|
e7cde2ca5f | ||
|
|
0c7b2ae702 | ||
|
|
1c822901e2 | ||
|
|
0cafb3fac5 | ||
|
|
d8718cc20f | ||
|
|
c484e4afe5 | ||
|
|
e155cca65e | ||
|
|
5cad5b095a | ||
|
|
2dff805d40 | ||
|
|
0afd65539f | ||
|
|
664d5777fd | ||
|
|
9a307269ca | ||
|
|
ab2657b795 | ||
|
|
57d435b6db | ||
|
|
de2e77cc86 | ||
|
|
ee5e22c574 | ||
|
|
1ce6a630d2 | ||
|
|
aee89b1f63 | ||
|
|
0f791be195 | ||
|
|
45248bcb65 | ||
|
|
3c092f36cb | ||
|
|
9a5afb70b5 | ||
|
|
f9275a70af | ||
|
|
8ee443a43c | ||
|
|
26223bb383 | ||
|
|
ea0c5e291f | ||
|
|
8ef7cacdda | ||
|
|
6d956c6138 | ||
|
|
b028e62731 | ||
|
|
fc43ec8185 | ||
|
|
491b5dcd6f | ||
|
|
02bbe0e6f5 | ||
|
|
b827b7ffce | ||
|
|
459374db1c | ||
|
|
97a65059e5 | ||
|
|
d629f4b501 | ||
|
|
f486c02b5e | ||
|
|
d63669ac22 | ||
|
|
ad82b0064a | ||
|
|
58f2d7117a | ||
|
|
735b0f8593 | ||
|
|
2bf012100a | ||
|
|
7abcc42a42 | ||
|
|
4d77e7dd6b | ||
|
|
5678fe3b83 | ||
|
|
f74888419c | ||
|
|
f21dcb8265 | ||
|
|
5bd07716eb | ||
|
|
db63c91f99 | ||
|
|
c37f0cfaa9 | ||
|
|
9621d76faa | ||
|
|
32c252393a | ||
|
|
ef5d1d6e58 | ||
|
|
660d36e001 | ||
|
|
2cc67f23ab | ||
|
|
6fe3054738 | ||
|
|
7811521c08 | ||
|
|
96135c9875 | ||
|
|
0038eab6ab | ||
|
|
a34e8fbc9a | ||
|
|
0399b3daed | ||
|
|
64a15db791 | ||
|
|
49cb446f8b | ||
|
|
82c32d7dee | ||
|
|
9c87c36644 | ||
|
|
be9f5ad951 | ||
|
|
d065a0cbc4 | ||
|
|
02dfa638ca | ||
|
|
bd71e779c3 | ||
|
|
bfd0ceac53 | ||
|
|
ba20936c17 | ||
|
|
4b058a8c56 | ||
|
|
49ba0cab27 | ||
|
|
b9c4f888b9 | ||
|
|
09e3c5ecfc | ||
|
|
b180f06c2a | ||
|
|
90345addce | ||
|
|
328172cfeb | ||
|
|
a75e5d914c | ||
|
|
a783479306 | ||
|
|
ecb557daa5 | ||
|
|
d5e811f9f1 | ||
|
|
3e5a6986f9 | ||
|
|
8e346f18bf | ||
|
|
34c7dededf | ||
|
|
e56cc85e96 | ||
|
|
8d660ff386 | ||
|
|
2e3c658bc8 | ||
|
|
7af50c3951 | ||
|
|
0bbada27f3 | ||
|
|
fcd2b778ea | ||
|
|
cbef08eeff | ||
|
|
6d3f430b24 | ||
|
|
e4516c19d3 | ||
|
|
8eb52f9a88 | ||
|
|
f2956670cd | ||
|
|
18d83b8c50 | ||
|
|
5b7afd72e3 | ||
|
|
643566bbfd | ||
|
|
5e0e61b7e5 | ||
|
|
608480c1d2 | ||
|
|
5979baa874 | ||
|
|
fc2e16dd4e | ||
|
|
73a2823d0b | ||
|
|
804ffb826d | ||
|
|
4bcbe577c6 | ||
|
|
2b1b858776 | ||
|
|
8089f52744 | ||
|
|
3aaa887d68 | ||
|
|
b617d60b60 | ||
|
|
321a5533df | ||
|
|
921fcbdcd0 | ||
|
|
06d0357f74 | ||
|
|
2f7681f881 | ||
|
|
e156badef6 | ||
|
|
ae6d379cce | ||
|
|
a822ec729a | ||
|
|
38370c7f2e | ||
|
|
37f65eb3dd | ||
|
|
9347ce2ede | ||
|
|
c4a839f47a | ||
|
|
43f7dcd08f | ||
|
|
71bfe4dd44 | ||
|
|
5bc44e7190 | ||
|
|
84c1b92fdf | ||
|
|
be6e222d8d | ||
|
|
7db488cdfb | ||
|
|
1a414ac69c | ||
|
|
f82099143f | ||
|
|
93743b11b2 | ||
|
|
a94696e037 | ||
|
|
0255e8980b | ||
|
|
eff9c69069 | ||
|
|
ca8a70a1ee | ||
|
|
903cc8ee83 | ||
|
|
2dccd2f30b | ||
|
|
b775cbb3bf | ||
|
|
79ef6f2f75 | ||
|
|
451ac297d4 | ||
|
|
0fd8a4507c | ||
|
|
13fe318110 | ||
|
|
49c7e7ce2d | ||
|
|
1af7d01d96 | ||
|
|
66c6938df0 | ||
|
|
bb9fb04788 | ||
|
|
f5cf2b2b55 | ||
|
|
b9b396a279 | ||
|
|
a2755221d0 | ||
|
|
3e8afaeae4 | ||
|
|
43169ced69 | ||
|
|
708844857d | ||
|
|
83ec89fa20 | ||
|
|
68b193a782 | ||
|
|
fa5fd1e71c | ||
|
|
abe2e544bb | ||
|
|
e051d02ad3 | ||
|
|
a3796fe128 | ||
|
|
c1e89bd1c3 | ||
|
|
aded1dd4da | ||
|
|
1e39281423 | ||
|
|
d92cc0f365 | ||
|
|
a5e39d1db3 | ||
|
|
7052ce9e63 | ||
|
|
8d036ab1d4 | ||
|
|
48276f989f | ||
|
|
57f2d3e26a | ||
|
|
c4924e4005 | ||
|
|
5c193f49df | ||
|
|
5b2ef77c2c | ||
|
|
371b660b33 | ||
|
|
228a95f776 | ||
|
|
cf93b72edd | ||
|
|
90c60cc5e4 | ||
|
|
e79ab4f47a | ||
|
|
4e946cbb27 | ||
|
|
d5c5070e59 | ||
|
|
50b3aabb76 | ||
|
|
b2fd84192b | ||
|
|
1a7f7cb197 | ||
|
|
ecab61929e | ||
|
|
ab4f0f87ca | ||
|
|
ae5b3c4c2d | ||
|
|
06240d1183 | ||
|
|
f3b3d8d759 | ||
|
|
8420f6ccfe | ||
|
|
f007ecf6c5 | ||
|
|
758a023267 | ||
|
|
fe6a576d84 | ||
|
|
d4f2d99a6b | ||
|
|
cb390325a6 | ||
|
|
1922ef974b | ||
|
|
de495aa1c5 | ||
|
|
cf0b4c8f03 | ||
|
|
aa4a4b07d8 | ||
|
|
75a4d8a2b9 | ||
|
|
b92214461e | ||
|
|
3f4ba87079 | ||
|
|
f1cfa14750 | ||
|
|
b24f5b6ad6 | ||
|
|
3dbce0e800 | ||
|
|
872fd126f4 | ||
|
|
efca50c6ac | ||
|
|
3cf013b25b | ||
|
|
92a5fa19fb | ||
|
|
1fcf13d149 | ||
|
|
bd20050db8 | ||
|
|
ce0233d0a2 | ||
|
|
ce777348b3 | ||
|
|
c052325487 | ||
|
|
0479e9b3f3 | ||
|
|
abdf1156d4 | ||
|
|
9ed30f563a | ||
|
|
d1985bad3b | ||
|
|
c83a4dc8e4 | ||
|
|
5484bbf8bf | ||
|
|
62e8d70d74 | ||
|
|
b2f1477b45 | ||
|
|
7323a5e393 | ||
|
|
f8205cc376 | ||
|
|
1b639ab978 | ||
|
|
4828f7478e | ||
|
|
9646f7039a | ||
|
|
6f921028de | ||
|
|
2508db0550 | ||
|
|
775141b7f7 | ||
|
|
a2d9c1aa72 | ||
|
|
4b639843ec | ||
|
|
464389a862 | ||
|
|
48b3eb259d | ||
|
|
4cebfbcd13 | ||
|
|
1767cf8ad4 | ||
|
|
b1981bb70c | ||
|
|
3dc581efbb | ||
|
|
655cc3256c | ||
|
|
ce69410f49 | ||
|
|
5f0be0cc7f | ||
|
|
dca6347ea9 | ||
|
|
94c4db9072 | ||
|
|
7f63be2cd2 | ||
|
|
1236dea4c5 | ||
|
|
c5c46df613 | ||
|
|
a96269150a | ||
|
|
75e347e8e3 | ||
|
|
d641cc5057 | ||
|
|
bf5b660cb5 | ||
|
|
712dc493ca | ||
|
|
f4fba64ffb | ||
|
|
02430916cb | ||
|
|
e3ad115698 | ||
|
|
c078bb04b2 | ||
|
|
d95e133792 | ||
|
|
a04f1045bc | ||
|
|
cf64145ff3 | ||
|
|
195eca6b09 | ||
|
|
b0ef077e48 | ||
|
|
e40a698d1a | ||
|
|
69c34b1b27 | ||
|
|
4700c2583d | ||
|
|
db6975e07a | ||
|
|
93127489e7 | ||
|
|
83064294ac | ||
|
|
0b64758360 | ||
|
|
4e1a2c04a5 | ||
|
|
8412c1db21 | ||
|
|
18a7a9fdce | ||
|
|
fc90d00354 | ||
|
|
55861a8f44 | ||
|
|
4fbd307163 | ||
|
|
3e4c03852d | ||
|
|
c8a04b998b | ||
|
|
568a652fb4 | ||
|
|
a2c9b5c042 | ||
|
|
fd3a4b069d | ||
|
|
4aaafa6de7 | ||
|
|
97475fb27b | ||
|
|
26e29df657 | ||
|
|
269ab3884a | ||
|
|
d15a853bf7 | ||
|
|
b3f7f440c8 | ||
|
|
6cf79a3c73 | ||
|
|
2c110f7796 | ||
|
|
c298c968f5 | ||
|
|
5feac3a7ff | ||
|
|
215c1c53f5 | ||
|
|
7890085c6c | ||
|
|
aebea0b57f | ||
|
|
8684455ea5 | ||
|
|
12c427a9cf | ||
|
|
7cbb103376 | ||
|
|
d686a0dadf | ||
|
|
eb186f550c | ||
|
|
01b631aea6 | ||
|
|
293114f1a0 | ||
|
|
20b92c03cb | ||
|
|
b6d76eb84e | ||
|
|
25bb51f4a3 | ||
|
|
4a3f51e550 | ||
|
|
d629a13499 | ||
|
|
07c0de71ec | ||
|
|
7470f4ffcf | ||
|
|
81f9748313 | ||
|
|
58928a5000 | ||
|
|
4c44ede945 | ||
|
|
d3c4105429 | ||
|
|
9cf8ec5dd7 | ||
|
|
f5187b1533 | ||
|
|
6230a65a79 | ||
|
|
f13c96839e | ||
|
|
776f68c9dd | ||
|
|
714ed89a4c | ||
|
|
ed307adb22 | ||
|
|
8001688daf | ||
|
|
4c0687b9a5 | ||
|
|
33043dd8af | ||
|
|
0b2b29b7cf | ||
|
|
a41c0a0519 | ||
|
|
026e28114e | ||
|
|
0840719289 | ||
|
|
aad875e113 | ||
|
|
6b059d94ba | ||
|
|
39eeaea7e7 | ||
|
|
81a8e91180 | ||
|
|
4fc6f6f59b | ||
|
|
dd2f573f27 | ||
|
|
ff8ddc431b | ||
|
|
d703945aa3 | ||
|
|
f4aba5f9ea | ||
|
|
393113c3e3 | ||
|
|
f2db18820a | ||
|
|
e04d300e18 | ||
|
|
685f836f41 | ||
|
|
d4f5ad641a | ||
|
|
007d437ee8 | ||
|
|
00e380e8d8 | ||
|
|
56749d9494 | ||
|
|
cf10d37c90 | ||
|
|
f9de34e36d | ||
|
|
aa889be140 | ||
|
|
6da6838bde | ||
|
|
07a0be303f | ||
|
|
ddbe0af290 | ||
|
|
e71f0f44a4 | ||
|
|
39f3bc7100 | ||
|
|
211a145e58 | ||
|
|
d2339b915f | ||
|
|
24c2651745 | ||
|
|
36e95b93b4 | ||
|
|
e7a44e0b15 | ||
|
|
fbdb21ac72 | ||
|
|
c9522cf6ae | ||
|
|
7bf9d334ad | ||
|
|
422ff93dcd | ||
|
|
eee1ea7a09 | ||
|
|
b90e482add | ||
|
|
875b51720b | ||
|
|
5272d4f9e3 | ||
|
|
c980f4f6e3 | ||
|
|
89525330c4 | ||
|
|
806db24c0e | ||
|
|
ba7d6df5a4 | ||
|
|
112301e0e0 | ||
|
|
c07065e457 | ||
|
|
b9e1afae17 | ||
|
|
549b4a9ebf | ||
|
|
fa9a3fb7c4 | ||
|
|
ccb15f278a | ||
|
|
f0fb4b8842 | ||
|
|
dacaf293b2 | ||
|
|
627d0e4e6f | ||
|
|
f32b9e26e0 | ||
|
|
db2b1a0a35 | ||
|
|
f734a60c62 | ||
|
|
9aa815c1ed | ||
|
|
1848f96efa | ||
|
|
51440cc7f7 | ||
|
|
09f100c0c2 | ||
|
|
a8b66abe15 | ||
|
|
03c45a78a9 | ||
|
|
6574d4450f | ||
|
|
d7f0ff84d6 | ||
|
|
5ef4c8e83e | ||
|
|
5ab48c6015 | ||
|
|
9119e08342 | ||
|
|
ce82ce1444 | ||
|
|
bbffd3d113 | ||
|
|
85cff2c0f3 | ||
|
|
9a0c621ad6 | ||
|
|
5c66104d25 | ||
|
|
c642d76e91 | ||
|
|
6d78ed3462 | ||
|
|
437142ed7b | ||
|
|
634c6dd455 | ||
|
|
3652931be8 | ||
|
|
7de3022a4a | ||
|
|
f82e52b7a2 | ||
|
|
c274f27810 | ||
|
|
88954b9bf6 | ||
|
|
f418f9de4c | ||
|
|
57f6ee7f78 | ||
|
|
f8457bd918 | ||
|
|
71c1369365 | ||
|
|
b015a6ea6c | ||
|
|
34072f3947 | ||
|
|
036b82afd9 | ||
|
|
52b5b3f741 | ||
|
|
c2f7f2ad27 | ||
|
|
bc9c78acfe | ||
|
|
7bd27ebd52 | ||
|
|
43ed8be114 | ||
|
|
a896fe7425 | ||
|
|
6c52e4936f | ||
|
|
32657793c8 | ||
|
|
63eb88c6ae | ||
|
|
28520cc493 | ||
|
|
8be05b404c | ||
|
|
96b791b5f9 | ||
|
|
ba9eac3ea4 | ||
|
|
717841877f | ||
|
|
cf06686d67 | ||
|
|
8d7594c96a | ||
|
|
ed36869f1d | ||
|
|
ea3adc44fd | ||
|
|
5fafc97bc0 | ||
|
|
fba900707a | ||
|
|
175a455d75 | ||
|
|
ffcef907b3 | ||
|
|
33317782ea | ||
|
|
3b9a0124fa | ||
|
|
5d5d03fd4c | ||
|
|
148f3172e6 | ||
|
|
972c14225b | ||
|
|
ce86c757cd | ||
|
|
cd6ffba9ac | ||
|
|
ab7209ceba | ||
|
|
63cca6190f | ||
|
|
0f2ec90064 | ||
|
|
4568dfabb9 | ||
|
|
e0772500c9 | ||
|
|
78c5522966 | ||
|
|
2a78da6d07 | ||
|
|
c3505f865e | ||
|
|
3364e6c63b | ||
|
|
a129f2c5c5 | ||
|
|
770b0c7022 | ||
|
|
15a7a0459a | ||
|
|
6490858f43 | ||
|
|
aac6f75025 | ||
|
|
86945218de | ||
|
|
718f79775e | ||
|
|
4261c1768a | ||
|
|
01603185c3 | ||
|
|
4632ba3ae5 | ||
|
|
38d63c3dc9 | ||
|
|
c64e5a5799 | ||
|
|
f1adf24f3b | ||
|
|
856765a775 | ||
|
|
075da34cdb | ||
|
|
7c6ef51cb2 | ||
|
|
1e1297378c | ||
|
|
5ce543002d | ||
|
|
ac53b30f25 | ||
|
|
a5448549b1 | ||
|
|
700b1c50af | ||
|
|
9e1c363a0a | ||
|
|
bbe3065f19 | ||
|
|
1716a0ebca | ||
|
|
ed66339e94 | ||
|
|
441774e61c | ||
|
|
c6fd14afd2 | ||
|
|
27ed9ca7fd | ||
|
|
50fda906bd | ||
|
|
6c7c60037b | ||
|
|
91a429ea77 | ||
|
|
2dbe01e90a | ||
|
|
3d7dd41223 | ||
|
|
a83b9109bf | ||
|
|
fdb079548e | ||
|
|
91495c8595 | ||
|
|
c3e997168a | ||
|
|
c3e6f4f7b6 | ||
|
|
effd837cd0 | ||
|
|
089d564934 | ||
|
|
e600ec95ed | ||
|
|
cbd5853389 | ||
|
|
4e3a086993 | ||
|
|
5f23dfb034 | ||
|
|
90c65c2927 | ||
|
|
7958775c6a | ||
|
|
99f59490a3 | ||
|
|
ff99812c4d | ||
|
|
741ac31ba6 | ||
|
|
f953b4dc0f | ||
|
|
76ce921778 | ||
|
|
4819f3ca15 | ||
|
|
48dd722db9 | ||
|
|
57c2613d37 | ||
|
|
804927f893 | ||
|
|
da82887cc0 | ||
|
|
f151920404 | ||
|
|
02f36a1abe | ||
|
|
c04041f110 | ||
|
|
a4702d48b4 | ||
|
|
ba27a4cc4a | ||
|
|
c28da78294 | ||
|
|
61f6ef4c19 | ||
|
|
d46b9b5aad | ||
|
|
7fc014f5d9 | ||
|
|
b28e0d15d8 | ||
|
|
0cc1679f64 | ||
|
|
e7a0e9ac70 | ||
|
|
025a43ea4e | ||
|
|
050fcf2ab8 | ||
|
|
c9642fcf35 | ||
|
|
79c257642c | ||
|
|
4f9d9d7a1d | ||
|
|
f14ac355f0 | ||
|
|
5111a527b9 | ||
|
|
e0217477ce | ||
|
|
5e3bad2a36 | ||
|
|
26d6450f0a | ||
|
|
5923f7d859 | ||
|
|
57f6a5ca8c | ||
|
|
dd30ffa7ce | ||
|
|
8f5aa0ea16 | ||
|
|
1ddf21a256 | ||
|
|
9d8796c703 | ||
|
|
59a97272bb | ||
|
|
e9d328a309 | ||
|
|
448f2913eb | ||
|
|
d92b630069 | ||
|
|
584955caa8 | ||
|
|
951e81158c | ||
|
|
2a88e598ff | ||
|
|
3e5e88b369 | ||
|
|
4806c52ba6 | ||
|
|
86d186e279 | ||
|
|
5bf5388552 | ||
|
|
c19ed471ca | ||
|
|
9d694a1589 | ||
|
|
4dadf0cb95 | ||
|
|
de4bc67159 | ||
|
|
af37616e48 | ||
|
|
07f7ad0a05 | ||
|
|
fd355636d0 | ||
|
|
e8528271ee | ||
|
|
41ed80e0c4 | ||
|
|
e8fef8104d | ||
|
|
30c48df1f0 | ||
|
|
f14add2791 | ||
|
|
14cb6d21a9 | ||
|
|
eaa607b48d | ||
|
|
0bd2a032bb | ||
|
|
d6961889fb | ||
|
|
51ffd0d64a | ||
|
|
120ac31394 | ||
|
|
4284b97b43 | ||
|
|
d1615567e2 | ||
|
|
9ad3e50511 | ||
|
|
45a59f9aec | ||
|
|
57408d18ae | ||
|
|
372372a0aa | ||
|
|
7f35ff5fe5 | ||
|
|
c28cd8a270 | ||
|
|
3a97db804f | ||
|
|
4a44b35ea5 | ||
|
|
47aafe9042 | ||
|
|
973940fcb2 | ||
|
|
53d94a1d3d | ||
|
|
5dd3c7c8e8 | ||
|
|
a740f60734 | ||
|
|
0c2a13f27f | ||
|
|
da0d3133df | ||
|
|
2b557a0f8d | ||
|
|
7abd9a3db9 | ||
|
|
98b9f57e0e | ||
|
|
e064ccd585 | ||
|
|
b5a63ed3fc | ||
|
|
147edddb90 | ||
|
|
cd19fc7c81 | ||
|
|
b5f9501001 | ||
|
|
8c0cd28f64 | ||
|
|
e8e10d4224 | ||
|
|
3e187df75b | ||
|
|
88d2ed9e93 | ||
|
|
ab5674aa4e | ||
|
|
81e4b6b37b | ||
|
|
b1507952df | ||
|
|
c4ac7cf375 | ||
|
|
c23292db8a | ||
|
|
a350ffeaa1 | ||
|
|
0efb7e67c9 | ||
|
|
a61e0f6cec | ||
|
|
0f5b36e9c5 | ||
|
|
93e7133076 | ||
|
|
2411edd461 | ||
|
|
af83065df5 | ||
|
|
1557c567d4 | ||
|
|
8bdaeab998 | ||
|
|
6825e3f7ce | ||
|
|
4602549ec8 | ||
|
|
a7b2df2450 | ||
|
|
3c0f6d3631 | ||
|
|
7ac37b75f3 | ||
|
|
b1e6d57bf1 | ||
|
|
f19c6a0a5b | ||
|
|
789279fe76 | ||
|
|
39a8d8803a | ||
|
|
f4ce73fc0d | ||
|
|
cac9d9266c | ||
|
|
7e94d02fb7 | ||
|
|
f3913b1dd2 | ||
|
|
50fc716c15 | ||
|
|
50412392f8 | ||
|
|
1b80859022 | ||
|
|
c6bd758793 | ||
|
|
cd4d657815 | ||
|
|
a4852b7a21 | ||
|
|
0b3c06abc0 | ||
|
|
1b351ad5bb | ||
|
|
1a1fc3ef21 | ||
|
|
fa3f18c88b | ||
|
|
904454d737 | ||
|
|
c1fb54ecad | ||
|
|
bd88b28310 | ||
|
|
de2397fa05 | ||
|
|
2513cf0969 | ||
|
|
15e16d86e4 | ||
|
|
26118ee881 | ||
|
|
232cf69006 | ||
|
|
9d2fba308d | ||
|
|
1171c9a0b2 | ||
|
|
9b397245f8 | ||
|
|
59b80ab8f6 | ||
|
|
18258877a8 | ||
|
|
e2b12c730e | ||
|
|
0a85b4b383 | ||
|
|
d5af9806ea | ||
|
|
104761d064 | ||
|
|
59065418ac | ||
|
|
7ccdc50637 | ||
|
|
f8ae61058e | ||
|
|
cc9d896cf8 | ||
|
|
c5637ea29b | ||
|
|
be3c4abbce | ||
|
|
d5c48567b3 | ||
|
|
5b4e7df856 | ||
|
|
23f04b3d09 | ||
|
|
050e3e86e3 | ||
|
|
c21d0c64a0 | ||
|
|
970b176fbf | ||
|
|
9e918cc717 | ||
|
|
4a31467afb | ||
|
|
86f07245d4 | ||
|
|
d51f179c2d | ||
|
|
974942a736 | ||
|
|
31d17cada7 | ||
|
|
647686e68e | ||
|
|
959212a95f | ||
|
|
45df8c0f74 | ||
|
|
1dbd41a746 | ||
|
|
8c43f4f628 | ||
|
|
633445883e | ||
|
|
e6acc3c336 | ||
|
|
90b947a7da | ||
|
|
b6b4015a82 | ||
|
|
2fd8940c02 | ||
|
|
7408710761 | ||
|
|
e4a4dd3219 | ||
|
|
745ad7cc34 | ||
|
|
821f8fea6f | ||
|
|
b0d90bb612 | ||
|
|
b439e0cfa0 | ||
|
|
68952b273b | ||
|
|
df148e4946 | ||
|
|
8b2f2fe24d | ||
|
|
4b8a91fb8c | ||
|
|
ee668df440 | ||
|
|
6cae917058 | ||
|
|
cf99a7bf18 | ||
|
|
727b519750 | ||
|
|
861d093d80 | ||
|
|
c3d2decdec | ||
|
|
d862d701f3 | ||
|
|
883c4a185d | ||
|
|
7eb35ef33d | ||
|
|
1563b0bf55 | ||
|
|
bad731c86f | ||
|
|
5309cc5916 | ||
|
|
f8ef6ab397 | ||
|
|
9e61991ad2 | ||
|
|
c644e8a30f | ||
|
|
45a237af16 | ||
|
|
0450fdb542 | ||
|
|
7d304fbd51 | ||
|
|
33df895709 | ||
|
|
4fb677ed23 | ||
|
|
4f0bd7f461 | ||
|
|
01eecdb698 | ||
|
|
22ef6ca56a | ||
|
|
2e015c9816 | ||
|
|
1d40b5010e | ||
|
|
9d25f1c073 | ||
|
|
2a8de9cb28 | ||
|
|
67767ede17 | ||
|
|
03db4d73ad | ||
|
|
fcb1f4665f | ||
|
|
5ca41a6fff | ||
|
|
e4f71420fc | ||
|
|
d5456ed1db | ||
|
|
e3335c5843 | ||
|
|
77ea0d3ea6 | ||
|
|
23ff035eb3 | ||
|
|
9906173a3f | ||
|
|
c6dd18ce40 | ||
|
|
a31ad2c367 | ||
|
|
7e20422e20 | ||
|
|
bd2f63c232 | ||
|
|
532a874ba6 | ||
|
|
48fa46e0d5 | ||
|
|
f72119f1b6 | ||
|
|
3063d53a2b | ||
|
|
e4163c5da4 | ||
|
|
a34ae45b05 | ||
|
|
d8e4f1150e | ||
|
|
c2534ae6da | ||
|
|
342ea97406 | ||
|
|
6f66c06111 | ||
|
|
aaeffe61a6 | ||
|
|
f5daa96c8e | ||
|
|
67fed5f3d7 | ||
|
|
067e6bf93d | ||
|
|
13dc31dc1f | ||
|
|
7f6bf21270 | ||
|
|
d647258856 | ||
|
|
1eb7ed5e9c | ||
|
|
e78f1b05a7 | ||
|
|
4531b017b3 | ||
|
|
101a03c38d | ||
|
|
e45140b7ea | ||
|
|
41747a7a04 | ||
|
|
e448430d8a | ||
|
|
394b1a1602 | ||
|
|
85abd5a8c3 | ||
|
|
b9e0eb5b76 | ||
|
|
a8eae73b66 | ||
|
|
9edd8d6f66 | ||
|
|
8147f648a1 | ||
|
|
30b1fa9c5b | ||
|
|
fa66c2692f | ||
|
|
1814f6b545 | ||
|
|
9d04ad5097 | ||
|
|
93b48ba973 | ||
|
|
047983d7bf | ||
|
|
ebccbf28a7 | ||
|
|
1dc84f9b58 | ||
|
|
35f3987803 | ||
|
|
b6bd132066 | ||
|
|
3ce2f28303 | ||
|
|
0d9cda8a85 | ||
|
|
f2decc09a5 | ||
|
|
b1c55b23ee | ||
|
|
4622600ab0 | ||
|
|
396358d4e5 | ||
|
|
8b975f50dd | ||
|
|
a1ea371c73 | ||
|
|
acd5442246 | ||
|
|
d176dd0623 | ||
|
|
68310bb479 | ||
|
|
e822966464 | ||
|
|
febce68bc8 | ||
|
|
fadffeedca | ||
|
|
2fc501fe59 | ||
|
|
21aac76ba2 | ||
|
|
fa3ebf2ca7 | ||
|
|
d2bf2539b5 | ||
|
|
8a0acedc94 | ||
|
|
11e5cd4f84 | ||
|
|
27fdb3116c | ||
|
|
b9c0c89a24 | ||
|
|
8078889a09 | ||
|
|
5dd4266ccc | ||
|
|
7d14676bce | ||
|
|
db113da121 | ||
|
|
5b2bfcef7d | ||
|
|
4d266f4ad2 | ||
|
|
b81a325b28 | ||
|
|
09eca10eb6 | ||
|
|
7b86465d7b | ||
|
|
40da5a849d | ||
|
|
ad170ed854 | ||
|
|
8d7c47a5e4 | ||
|
|
d7b5382c32 | ||
|
|
4d8f7c67d4 | ||
|
|
e53337bcdc | ||
|
|
e5d883f97e | ||
|
|
548a55792c | ||
|
|
43f0f2a0fd | ||
|
|
7b1c696810 | ||
|
|
8d69c3764d | ||
|
|
87acd9d7ee | ||
|
|
06391c9de6 | ||
|
|
b42b41216b | ||
|
|
0a1d215560 | ||
|
|
44b6136ce2 | ||
|
|
ba3c6023a8 | ||
|
|
be7f6ae7d1 | ||
|
|
984c7a67f5 | ||
|
|
a4bf6c1f7a | ||
|
|
690ae1a7b6 | ||
|
|
eae9a10a7d | ||
|
|
7c6765b969 | ||
|
|
a6c143a1c7 | ||
|
|
714da0ab3b | ||
|
|
377ec37257 |
@@ -0,0 +1,34 @@
|
|||||||
|
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||||
|
|
||||||
|
name: Node build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [17.x, 18.x, 19.x, 20.x, 21.x]
|
||||||
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'npm'
|
||||||
|
- run: echo "${PWD}/dist/cappuccino/bin" >> $GITHUB_PATH
|
||||||
|
- run: echo "${PWD}/dist/objective-j/bin" >> $GITHUB_PATH
|
||||||
|
- run: npm install
|
||||||
|
- run: npm update
|
||||||
|
- run: jake dist
|
||||||
|
- run: jake test-only
|
||||||
+11
@@ -5,6 +5,7 @@ Demos
|
|||||||
./Aristo
|
./Aristo
|
||||||
WebSite
|
WebSite
|
||||||
.push-package
|
.push-package
|
||||||
|
*.xcodeproj*
|
||||||
*.xcodeproj/*.pbxuser
|
*.xcodeproj/*.pbxuser
|
||||||
*.xcodeproj/*.perspectivev3
|
*.xcodeproj/*.perspectivev3
|
||||||
xcuserdata/
|
xcuserdata/
|
||||||
@@ -15,3 +16,13 @@ xcuserdata/
|
|||||||
Tests/Manual/**/*.xcodeproj
|
Tests/Manual/**/*.xcodeproj
|
||||||
*.sublime-project
|
*.sublime-project
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
*.tm_properties
|
||||||
|
*.idea
|
||||||
|
node_modules
|
||||||
|
*.vscode
|
||||||
|
/dist/objective-j/objj-executable
|
||||||
|
/dist/objective-j/package.json
|
||||||
|
/dist/objective-j/lib
|
||||||
|
/dist/cappuccino/package.json
|
||||||
|
/dist/cappuccino/lib
|
||||||
|
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
.DS_Store
|
||||||
|
Frameworks
|
||||||
|
!/dist/objective-j/Frameworks
|
||||||
|
!/dist/cappuccino-j/Frameworks
|
||||||
|
Build
|
||||||
|
Demos
|
||||||
|
./Aristo
|
||||||
|
WebSite
|
||||||
|
.push-package
|
||||||
|
*.xcodeproj*
|
||||||
|
*.xcodeproj/*.pbxuser
|
||||||
|
*.xcodeproj/*.perspectivev3
|
||||||
|
xcuserdata/
|
||||||
|
!*.xcodeproj/project.pbxproj
|
||||||
|
*.xCodeSupport/
|
||||||
|
*.XcodeSupport/
|
||||||
|
*XcodeSupport/
|
||||||
|
Tests/Manual/**/*.xcodeproj
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
|
*.tm_properties
|
||||||
|
*.idea
|
||||||
|
node_modules
|
||||||
|
*.vscode
|
||||||
|
/dist/objective-j/objj-executable
|
||||||
|
/dist/objective-j/package.json
|
||||||
|
/dist/cappuccino/package.json
|
||||||
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 0.8
|
- 0.8
|
||||||
install: ./bootstrap.sh --quiet --noprompt --directory ./narwhal
|
install: ./bootstrap.sh --noprompt --directory ./narwhal
|
||||||
script: jake test
|
script: jake test
|
||||||
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
||||||
|
|||||||
+7
-2
@@ -20,12 +20,15 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "_CPObject+Theme.j"
|
||||||
@import "_CPToolTip.j"
|
@import "_CPToolTip.j"
|
||||||
@import "CALayer.j"
|
@import "CALayer.j"
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPAccordionView.j"
|
@import "CPAccordionView.j"
|
||||||
@import "CPAlert.j"
|
@import "CPAlert.j"
|
||||||
@import "CPAnimation.j"
|
@import "CPAnimation.j"
|
||||||
|
@import "CPAnimationContext.j"
|
||||||
|
@import "CPAppearance.j"
|
||||||
@import "CPApplication.j"
|
@import "CPApplication.j"
|
||||||
@import "CPArrayController.j"
|
@import "CPArrayController.j"
|
||||||
@import "CPBezierPath.j"
|
@import "CPBezierPath.j"
|
||||||
@@ -59,8 +62,6 @@
|
|||||||
@import "CPDocument.j"
|
@import "CPDocument.j"
|
||||||
@import "CPDocumentController.j"
|
@import "CPDocumentController.j"
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
@import "CPFlashMovie.j"
|
|
||||||
@import "CPFlashView.j"
|
|
||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
@import "CPFontManager.j"
|
@import "CPFontManager.j"
|
||||||
@import "CPGradient.j"
|
@import "CPGradient.j"
|
||||||
@@ -98,14 +99,18 @@
|
|||||||
@import "CPTabView.j"
|
@import "CPTabView.j"
|
||||||
@import "CPText.j"
|
@import "CPText.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
@import "CPTextView.j"
|
||||||
@import "CPTokenField.j"
|
@import "CPTokenField.j"
|
||||||
@import "CPToolbar.j"
|
@import "CPToolbar.j"
|
||||||
@import "CPToolbarItem.j"
|
@import "CPToolbarItem.j"
|
||||||
|
@import "CPTrackingArea.j"
|
||||||
@import "CPTreeNode.j"
|
@import "CPTreeNode.j"
|
||||||
@import "CPUserDefaultsController.j"
|
@import "CPUserDefaultsController.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPViewAnimator.j"
|
||||||
@import "CPViewAnimation.j"
|
@import "CPViewAnimation.j"
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
|
@import "CPVisualEffectView.j"
|
||||||
@import "CPWebView.j"
|
@import "CPWebView.j"
|
||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
|
|||||||
+131
-65
@@ -41,6 +41,10 @@
|
|||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
|
var CPAlertDelegate_alertShowHelp_ = 1 << 0,
|
||||||
|
CPAlertDelegate_alertDidEnd_returnCode_ = 1 << 1;
|
||||||
|
|
||||||
|
@typedef CPAlertStyle
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPAlertStyle
|
@group CPAlertStyle
|
||||||
@@ -59,6 +63,62 @@ CPCriticalAlertStyle = 2;
|
|||||||
|
|
||||||
var bottomHeight = 71;
|
var bottomHeight = 71;
|
||||||
|
|
||||||
|
@protocol CPAlertDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)alertShowHelp:(CPAlert)alert;
|
||||||
|
- (void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPAlertThemeView : CPView
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"alert";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"size": CGSizeMake(400.0, 110.0),
|
||||||
|
@"content-inset": CGInsetMake(15, 15, 15, 50),
|
||||||
|
@"informative-offset": 6,
|
||||||
|
@"button-offset": 10,
|
||||||
|
@"message-text-alignment": CPJustifiedTextAlignment,
|
||||||
|
@"message-text-color": [CPColor blackColor],
|
||||||
|
@"message-text-font": [CPFont boldSystemFontOfSize:13.0],
|
||||||
|
@"message-text-shadow-color": [CPNull null],
|
||||||
|
@"message-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"informative-text-alignment": CPJustifiedTextAlignment,
|
||||||
|
@"informative-text-color": [CPColor blackColor],
|
||||||
|
@"informative-text-font": [CPFont systemFontOfSize:12.0],
|
||||||
|
@"informative-text-shadow-color": [CPNull null],
|
||||||
|
@"informative-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"image-offset": CGPointMake(15, 12),
|
||||||
|
@"information-image": [CPNull null],
|
||||||
|
@"warning-image": [CPNull null],
|
||||||
|
@"error-image": [CPNull null],
|
||||||
|
@"help-image": [CPNull null],
|
||||||
|
@"help-image-left-offset": 15,
|
||||||
|
@"help-image-pressed": [CPNull null],
|
||||||
|
@"suppression-button-y-offset": 0.0,
|
||||||
|
@"suppression-button-x-offset": 0.0,
|
||||||
|
@"default-elements-margin": 3.0,
|
||||||
|
@"suppression-button-text-color": [CPColor blackColor],
|
||||||
|
@"suppression-button-text-font": [CPFont systemFontOfSize:12.0],
|
||||||
|
@"suppression-button-text-shadow-color": [CPNull null],
|
||||||
|
@"suppression-button-text-shadow-offset": 0.0,
|
||||||
|
@"modal-window-button-margin-y": 0.0,
|
||||||
|
@"modal-window-button-margin-x": 0.0,
|
||||||
|
@"standard-window-button-margin-y": 0.0,
|
||||||
|
@"standard-window-button-margin-x": 0.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
|
|
||||||
@@ -83,32 +143,33 @@ var bottomHeight = 71;
|
|||||||
*/
|
*/
|
||||||
@implementation CPAlert : CPObject
|
@implementation CPAlert : CPObject
|
||||||
{
|
{
|
||||||
BOOL _showHelp @accessors(property=showsHelp);
|
BOOL _showHelp @accessors(property=showsHelp);
|
||||||
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
||||||
|
|
||||||
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
||||||
CPString _title @accessors(property=title);
|
CPString _title @accessors(property=title);
|
||||||
CPView _accessoryView @accessors(property=accessoryView);
|
CPView _accessoryView @accessors(property=accessoryView);
|
||||||
CPImage _icon @accessors(property=icon);
|
CPImage _icon @accessors(property=icon);
|
||||||
|
|
||||||
CPArray _buttons @accessors(property=buttons, readonly);
|
CPArray _buttons @accessors(property=buttons, readonly);
|
||||||
CPCheckBox _suppressionButton @accessors(property=suppressionButton, readonly);
|
CPCheckBox _suppressionButton @accessors(property=suppressionButton, readonly);
|
||||||
|
|
||||||
id _delegate @accessors(property=delegate);
|
id <CPAlertDelegate> _delegate @accessors(property=delegate);
|
||||||
id _modalDelegate;
|
id _modalDelegate;
|
||||||
SEL _didEndSelector @accessors(property=didEndSelector);
|
SEL _didEndSelector @accessors(property=didEndSelector);
|
||||||
Function _didEndBlock;
|
Function _didEndBlock;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||||
CPWindow _window @accessors(property=window, readonly);
|
CPWindow _window @accessors(property=window, readonly);
|
||||||
int _defaultWindowStyle;
|
int _defaultWindowStyle;
|
||||||
|
|
||||||
CPImageView _alertImageView;
|
CPImageView _alertImageView;
|
||||||
CPTextField _informativeLabel;
|
CPTextField _informativeLabel;
|
||||||
CPTextField _messageLabel;
|
CPTextField _messageLabel;
|
||||||
CPButton _alertHelpButton;
|
CPButton _alertHelpButton;
|
||||||
|
|
||||||
BOOL _needsLayout;
|
BOOL _needsLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Creating Alerts
|
#pragma mark Creating Alerts
|
||||||
@@ -187,6 +248,30 @@ var bottomHeight = 71;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Delegate
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the delegate of the receiver
|
||||||
|
@param aDelegate the delegate object for the alert.
|
||||||
|
*/
|
||||||
|
- (void)setDelegate:(id <CPAlertDelegate>)aDelegate
|
||||||
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
|
||||||
|
_implementedDelegateMethods |= CPAlertDelegate_alertShowHelp_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||||
|
_implementedDelegateMethods |= CPAlertDelegate_alertDidEnd_returnCode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Accessors
|
#pragma mark Accessors
|
||||||
|
|
||||||
- (CPTheme)theme
|
- (CPTheme)theme
|
||||||
@@ -219,7 +304,7 @@ var bottomHeight = 71;
|
|||||||
[_themeView setValue:aValue forThemeAttribute:aName];
|
[_themeView setValue:aValue forThemeAttribute:aName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState
|
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(ThemeState)aState
|
||||||
{
|
{
|
||||||
[_themeView setValue:aValue forThemeAttribute:aName inState:aState];
|
[_themeView setValue:aValue forThemeAttribute:aName inState:aState];
|
||||||
}
|
}
|
||||||
@@ -696,8 +781,7 @@ var bottomHeight = 71;
|
|||||||
*/
|
*/
|
||||||
- (@action)_showHelp:(id)aSender
|
- (@action)_showHelp:(id)aSender
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
|
[self _sendDelegateAlertShowHelp];
|
||||||
[_delegate alertShowHelp:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -737,62 +821,44 @@ var bottomHeight = 71;
|
|||||||
else if (_modalDelegate)
|
else if (_modalDelegate)
|
||||||
{
|
{
|
||||||
if (_didEndSelector)
|
if (_didEndSelector)
|
||||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
_modalDelegate.isa.objj_msgSend3(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||||
}
|
}
|
||||||
else if (_delegate)
|
else if (_delegate)
|
||||||
{
|
{
|
||||||
if (_didEndSelector)
|
if (_didEndSelector)
|
||||||
objj_msgSend(_delegate, _didEndSelector, self, returnCode);
|
_delegate.isa.objj_msgSend2(_delegate, _didEndSelector, self, returnCode);
|
||||||
else if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
else
|
||||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
[self _sendDelegateAlertDidEndReturnCode:returnCode];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPAlertThemeView : CPView
|
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
@implementation CPAlert (CPAlertDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call the delegate alertDidEnd:returnCode
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateAlertDidEndReturnCode:(int)returnCode
|
||||||
{
|
{
|
||||||
return @"alert";
|
if (!(_implementedDelegateMethods & CPAlertDelegate_alertDidEnd_returnCode_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPDictionary)themeAttributes
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call the delegate alertShowHelp:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateAlertShowHelp
|
||||||
{
|
{
|
||||||
return @{
|
if (!(_implementedDelegateMethods & CPAlertDelegate_alertShowHelp_))
|
||||||
@"size": CGSizeMake(400.0, 110.0),
|
return YES;
|
||||||
@"content-inset": CGInsetMake(15, 15, 15, 50),
|
|
||||||
@"informative-offset": 6,
|
return [_delegate alertShowHelp:self];
|
||||||
@"button-offset": 10,
|
|
||||||
@"message-text-alignment": CPJustifiedTextAlignment,
|
|
||||||
@"message-text-color": [CPColor blackColor],
|
|
||||||
@"message-text-font": [CPFont boldSystemFontOfSize:13.0],
|
|
||||||
@"message-text-shadow-color": [CPNull null],
|
|
||||||
@"message-text-shadow-offset": CGSizeMakeZero(),
|
|
||||||
@"informative-text-alignment": CPJustifiedTextAlignment,
|
|
||||||
@"informative-text-color": [CPColor blackColor],
|
|
||||||
@"informative-text-font": [CPFont systemFontOfSize:12.0],
|
|
||||||
@"informative-text-shadow-color": [CPNull null],
|
|
||||||
@"informative-text-shadow-offset": CGSizeMakeZero(),
|
|
||||||
@"image-offset": CGPointMake(15, 12),
|
|
||||||
@"information-image": [CPNull null],
|
|
||||||
@"warning-image": [CPNull null],
|
|
||||||
@"error-image": [CPNull null],
|
|
||||||
@"help-image": [CPNull null],
|
|
||||||
@"help-image-left-offset": 15,
|
|
||||||
@"help-image-pressed": [CPNull null],
|
|
||||||
@"suppression-button-y-offset": 0.0,
|
|
||||||
@"suppression-button-x-offset": 0.0,
|
|
||||||
@"default-elements-margin": 3.0,
|
|
||||||
@"suppression-button-text-color": [CPColor blackColor],
|
|
||||||
@"suppression-button-text-font": [CPFont systemFontOfSize:12.0],
|
|
||||||
@"suppression-button-text-shadow-color": [CPNull null],
|
|
||||||
@"suppression-button-text-shadow-offset": 0.0,
|
|
||||||
@"modal-window-button-margin-y": 0.0,
|
|
||||||
@"modal-window-button-margin-x": 0.0,
|
|
||||||
@"standard-window-button-margin-y": 0.0,
|
|
||||||
@"standard-window-button-margin-x": 0.0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+111
-33
@@ -26,25 +26,26 @@
|
|||||||
@import "CAMediaTimingFunction.j"
|
@import "CAMediaTimingFunction.j"
|
||||||
|
|
||||||
|
|
||||||
/*
|
@protocol CPAnimationDelegate <CPObject>
|
||||||
@global
|
|
||||||
@group CPAnimationCurve
|
@optional
|
||||||
*/
|
- (BOOL)animationShouldStart:(CPAnimation)animation;
|
||||||
|
- (float)animation:(CPAnimation)animation valueForProgress:(float)progress;
|
||||||
|
- (void)animationDidEnd:(CPAnimation)animation;
|
||||||
|
- (void)animationDidStop:(CPAnimation)animation;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
var CPAnimationDelegate_animationShouldStart_ = 1 << 1,
|
||||||
|
CPAnimationDelegate_animation_valueForProgress_ = 1 << 2,
|
||||||
|
CPAnimationDelegate_animationDidEnd_ = 1 << 3,
|
||||||
|
CPAnimationDelegate_animationDidStop_ = 1 << 4;
|
||||||
|
|
||||||
|
@typedef CPAnimationCurve
|
||||||
CPAnimationEaseInOut = 0;
|
CPAnimationEaseInOut = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPAnimationCurve
|
|
||||||
*/
|
|
||||||
CPAnimationEaseIn = 1;
|
CPAnimationEaseIn = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPAnimationCurve
|
|
||||||
*/
|
|
||||||
CPAnimationEaseOut = 2;
|
CPAnimationEaseOut = 2;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPAnimationCurve
|
|
||||||
*/
|
|
||||||
CPAnimationLinear = 3;
|
CPAnimationLinear = 3;
|
||||||
|
|
||||||
ACTUAL_FRAME_RATE = 0;
|
ACTUAL_FRAME_RATE = 0;
|
||||||
@@ -80,17 +81,18 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
*/
|
*/
|
||||||
@implementation CPAnimation : CPObject
|
@implementation CPAnimation : CPObject
|
||||||
{
|
{
|
||||||
CPTimeInterval _lastTime;
|
CPTimeInterval _lastTime;
|
||||||
CPTimeInterval _duration;
|
CPTimeInterval _duration;
|
||||||
|
|
||||||
CPAnimationCurve _animationCurve;
|
CPAnimationCurve _animationCurve;
|
||||||
CAMediaTimingFunction _timingFunction;
|
CAMediaTimingFunction _timingFunction;
|
||||||
|
|
||||||
float _frameRate;
|
float _frameRate;
|
||||||
float _progress;
|
float _progress;
|
||||||
|
|
||||||
id _delegate;
|
id <CPAnimationDelegate> _delegate;
|
||||||
CPTimer _timer;
|
CPTimer _timer;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -214,9 +216,25 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
Sets the animation's delegate.
|
Sets the animation's delegate.
|
||||||
@param aDelegate the new delegate
|
@param aDelegate the new delegate
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPAnimationDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(animationShouldStart:)])
|
||||||
|
_implementedDelegateMethods |= CPAnimationDelegate_animationShouldStart_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
||||||
|
_implementedDelegateMethods |= CPAnimationDelegate_animationDidEnd_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
|
||||||
|
_implementedDelegateMethods |= CPAnimationDelegate_animationDidStop_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||||
|
_implementedDelegateMethods |= CPAnimationDelegate_animation_valueForProgress_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -227,7 +245,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
- (void)startAnimation
|
- (void)startAnimation
|
||||||
{
|
{
|
||||||
// If we're already animating, or our delegate stops us, animate.
|
// If we're already animating, or our delegate stops us, animate.
|
||||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
|
if (_timer || ![self _sendDelegateAnimationShouldStart])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_progress === 1.0)
|
if (_progress === 1.0)
|
||||||
@@ -236,7 +254,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
ACTUAL_FRAME_RATE = 0;
|
ACTUAL_FRAME_RATE = 0;
|
||||||
_lastTime = new Date();
|
_lastTime = new Date();
|
||||||
|
|
||||||
var timerInterval = _frameRate <= 0.0 ? 0.0001 : 1.0/_frameRate;
|
var timerInterval = _frameRate <= 0.0 ? 0.0001 : 1.0 / _frameRate;
|
||||||
|
|
||||||
_timer = [CPTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
_timer = [CPTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
||||||
}
|
}
|
||||||
@@ -260,8 +278,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
[_timer invalidate];
|
[_timer invalidate];
|
||||||
_timer = nil;
|
_timer = nil;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
[self _sendDelegateAnimationDidEnd];
|
||||||
[_delegate animationDidEnd:self];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,8 +293,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
[_timer invalidate];
|
[_timer invalidate];
|
||||||
_timer = nil;
|
_timer = nil;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
|
[self _sendDelegateAnimationDidStop];
|
||||||
[_delegate animationDidStop:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -313,8 +329,8 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
{
|
{
|
||||||
var t = [self currentProgress];
|
var t = [self currentProgress];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
if ([self _delegateRespondsToAnimationValueForProgress])
|
||||||
return [_delegate animation:self valueForProgress:t];
|
return [self _sendDelegateAnimationValueForProgress:t];
|
||||||
|
|
||||||
if (_animationCurve == CPAnimationLinear)
|
if (_animationCurve == CPAnimationLinear)
|
||||||
return t;
|
return t;
|
||||||
@@ -330,6 +346,68 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPAnimation (CPAnimationDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Check if the delegate responds to animation:valueForProgress:
|
||||||
|
*/
|
||||||
|
- (BOOL)_delegateRespondsToAnimationValueForProgress
|
||||||
|
{
|
||||||
|
return _implementedDelegateMethods & CPAnimationDelegate_animation_valueForProgress_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate animationShouldStart:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateAnimationShouldStart
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationShouldStart_))
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
return [_delegate animationShouldStart:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate animation:valueForProgress:
|
||||||
|
*/
|
||||||
|
- (float)_sendDelegateAnimationValueForProgress:(float)aProgress
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPAnimationDelegate_animation_valueForProgress_))
|
||||||
|
return aProgress;
|
||||||
|
|
||||||
|
return [_delegate animation:self valueForProgress:aProgress];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate animationDidEnd:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateAnimationDidEnd
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationDidEnd_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate animationDidEnd:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate animationDidStop:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateAnimationDidStop
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationDidStop_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate animationDidStop:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
// currently used function to determine time
|
// currently used function to determine time
|
||||||
// 1:1 conversion to js from webkit source files
|
// 1:1 conversion to js from webkit source files
|
||||||
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* CPAppearance.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Antoine Mercadal.
|
||||||
|
* Copyright 2015, Cappuccino Project.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
@import "CPTheme.j"
|
||||||
|
|
||||||
|
CPAppearanceNameAqua = @"CPAppearanceNameAqua";
|
||||||
|
CPAppearanceNameLightContent = @"CPAppearanceNameLightContent";
|
||||||
|
CPAppearanceNameVibrantDark = @"CPAppearanceNameVibrantDark";
|
||||||
|
CPAppearanceNameVibrantLight = @"CPAppearanceNameVibrantLight";
|
||||||
|
|
||||||
|
var _CPAppearanceCurrent = nil,
|
||||||
|
_CPAppearancesRegistry = @{};
|
||||||
|
|
||||||
|
|
||||||
|
@protocol CPAppearanceCustomization <CPObject>
|
||||||
|
|
||||||
|
@required
|
||||||
|
- (CPAppearance)appearance;
|
||||||
|
- (void)setAppearance:(CPAppearance)appearance;
|
||||||
|
- (CPAppearance)effectiveAppearance;
|
||||||
|
- (void)setEffectiveAppearance:(CPAppearance)appearance;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
CPThemeStateAppearanceAqua = CPThemeState("appearance-aqua");
|
||||||
|
CPThemeStateAppearanceLightContent = CPThemeState("appearance-light-content");
|
||||||
|
CPThemeStateAppearanceVibrantLight = CPThemeState("appearance-vibrant-light");
|
||||||
|
CPThemeStateAppearanceVibrantDark = CPThemeState("appearance-vibrant-dark");
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
|
||||||
|
A CPAppareance represents the appearance of an to a subset of UI elements.
|
||||||
|
This is a very lightweight implementation of the NSAppearance system, but
|
||||||
|
We are using it for compliance, and especially for the CPVisualEffectView
|
||||||
|
*/
|
||||||
|
@implementation CPAppearance : CPObject
|
||||||
|
{
|
||||||
|
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||||
|
|
||||||
|
CPString _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Class Methods
|
||||||
|
|
||||||
|
/*! Returns the current default CPAppearance
|
||||||
|
*/
|
||||||
|
+ (CPAppearance)currentAppearance
|
||||||
|
{
|
||||||
|
if (!_CPAppearanceCurrent)
|
||||||
|
_CPAppearanceCurrent = [CPAppearance appearanceNamed:CPAppearanceNameAqua];
|
||||||
|
|
||||||
|
return _CPAppearanceCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Sets the current default CPAppearance
|
||||||
|
@param appearance the new current appearance
|
||||||
|
*/
|
||||||
|
+ (void)setCurrentAppearance:(CPAppearance)anAppearance
|
||||||
|
{
|
||||||
|
_CPAppearanceCurrent = anAppearance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the CPAppearance object with the given name
|
||||||
|
@param name the name of the appearance
|
||||||
|
*/
|
||||||
|
+ (CPAppearance)appearanceNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
if (![_CPAppearancesRegistry containsKey:aName])
|
||||||
|
{
|
||||||
|
[_CPAppearancesRegistry setObject:[[CPAppearance alloc] initWithAppearanceNamed:aName bundle:nil]
|
||||||
|
forKey:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [_CPAppearancesRegistry objectForKey:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Initialization
|
||||||
|
|
||||||
|
/*! Creates a CPAppearance object initialized to the specified appearance file in the specified bundle
|
||||||
|
This method does actually nothing special. It just creates a default appearance object
|
||||||
|
*/
|
||||||
|
- (id)initWithAppearanceNamed:(CPString)aName bundle:(CPBundle)bundle
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_name = aName;
|
||||||
|
_allowsVibrancy = YES;
|
||||||
|
|
||||||
|
if ([_CPAppearancesRegistry containsKey:aName])
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:"Appearance with name '" + aName + "' is already declared."];
|
||||||
|
|
||||||
|
[_CPAppearancesRegistry setObject:self forKey:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Implementation
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)anObject
|
||||||
|
{
|
||||||
|
if (![anObject isKindOfClass:CPAppearance])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return self._name == anObject._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return @"<CPAppearance @" + [self UID] + @" name: " + _name + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CPCoding
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_name = [aCoder decodeObjectForKey:@"_name"];
|
||||||
|
_allowsVibrancy = [aCoder decodeBoolForKey:@"_allowsVibrancy"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_name forKey:@"_name"];
|
||||||
|
[aCoder encodeBool:_allowsVibrancy forKey:@"_allowsVibrancy"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+99
-39
@@ -37,10 +37,32 @@
|
|||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
@import "_CPPopoverWindow.j"
|
@import "_CPPopoverWindow.j"
|
||||||
|
|
||||||
|
@typedef CPModalSession
|
||||||
|
|
||||||
var CPMainCibFile = @"CPMainCibFile",
|
var CPMainCibFile = @"CPMainCibFile",
|
||||||
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
||||||
CPEventModifierFlags = 0;
|
CPEventModifierFlags = 0;
|
||||||
|
|
||||||
|
|
||||||
|
@protocol CPApplicationDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (CPApplicationTerminateReply)applicationShouldTerminate:(CPApplication)sender;
|
||||||
|
- (CPString)applicationShouldTerminateMessage:(CPApplication)sender;
|
||||||
|
- (void)applicationDidBecomeActive:(CPNotification)aNotification;
|
||||||
|
- (void)applicationDidChangeScreenParameters:(CPNotification)aNotification;
|
||||||
|
- (void)applicationDidFinishLaunching:(CPNotification)aNotification;
|
||||||
|
- (void)applicationDidResignActive:(CPNotification)aNotification;
|
||||||
|
- (void)applicationWillBecomeActive:(CPNotification)aNotification;
|
||||||
|
- (void)applicationWillFinishLaunching:(CPNotification)aNotification;
|
||||||
|
- (void)applicationWillResignActive:(CPNotification)aNotification;
|
||||||
|
- (void)applicationWillTerminate:(CPNotification)aNotification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPApplicationDelegate_applicationShouldTerminate_ = 1 << 0,
|
||||||
|
CPApplicationDelegate_applicationShouldTerminateMessage_ = 1 << 1;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPApplication
|
@class CPApplication
|
||||||
@@ -68,36 +90,38 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
*/
|
*/
|
||||||
@implementation CPApplication : CPResponder
|
@implementation CPApplication : CPResponder
|
||||||
{
|
{
|
||||||
CPArray _eventListeners;
|
CPArray _eventListeners;
|
||||||
int _eventListenerInsertionIndex;
|
int _eventListenerInsertionIndex;
|
||||||
|
|
||||||
CPEvent _currentEvent;
|
CPEvent _currentEvent;
|
||||||
CPWindow _lastMouseMoveWindow;
|
CPWindow _lastMouseMoveWindow;
|
||||||
|
|
||||||
CPArray _windows;
|
CPArray _windows;
|
||||||
CPWindow _keyWindow;
|
CPWindow _keyWindow;
|
||||||
CPWindow _mainWindow;
|
CPWindow _mainWindow;
|
||||||
CPWindow _previousKeyWindow;
|
CPWindow _previousKeyWindow;
|
||||||
CPWindow _previousMainWindow;
|
CPWindow _previousMainWindow;
|
||||||
|
|
||||||
CPDocumentController _documentController;
|
CPDocumentController _documentController;
|
||||||
|
|
||||||
CPModalSession _currentSession;
|
CPModalSession _currentSession;
|
||||||
|
|
||||||
//
|
//
|
||||||
id _delegate;
|
id <CPApplicationDelegate> _delegate;
|
||||||
BOOL _finishedLaunching;
|
CPInteger _implementedDelegateMethods;
|
||||||
BOOL _isActive;
|
|
||||||
|
|
||||||
CPDictionary _namedArgs;
|
BOOL _finishedLaunching;
|
||||||
CPArray _args;
|
BOOL _isActive;
|
||||||
CPString _fullArgsString;
|
|
||||||
|
|
||||||
CPImage _applicationIconImage;
|
CPDictionary _namedArgs;
|
||||||
|
CPArray _args;
|
||||||
|
CPString _fullArgsString;
|
||||||
|
|
||||||
CPPanel _aboutPanel;
|
CPImage _applicationIconImage;
|
||||||
|
|
||||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
CPPanel _aboutPanel;
|
||||||
|
|
||||||
|
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -108,7 +132,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
+ (CPApplication)sharedApplication
|
+ (CPApplication)sharedApplication
|
||||||
{
|
{
|
||||||
if (!CPApp)
|
if (!CPApp)
|
||||||
CPApp = [[CPApplication alloc] init];
|
CPApp = [[self alloc] init];
|
||||||
|
|
||||||
return CPApp;
|
return CPApp;
|
||||||
}
|
}
|
||||||
@@ -143,11 +167,13 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
react to these events.
|
react to these events.
|
||||||
@param aDelegate the delegate object
|
@param aDelegate the delegate object
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPApplicationDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate == aDelegate)
|
if (_delegate == aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter],
|
var defaultCenter = [CPNotificationCenter defaultCenter],
|
||||||
delegateNotifications =
|
delegateNotifications =
|
||||||
[
|
[
|
||||||
@@ -188,6 +214,12 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
if ([_delegate respondsToSelector:selector])
|
if ([_delegate respondsToSelector:selector])
|
||||||
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
|
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||||
|
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminate_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(applicationShouldTerminateMessage:)])
|
||||||
|
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminateMessage_
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -409,12 +441,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
{
|
{
|
||||||
// callback method for terminate:
|
// callback method for terminate:
|
||||||
if (didCloseAll)
|
if (didCloseAll)
|
||||||
{
|
[self replyToApplicationShouldTerminate:[self _sendDelegateApplicationShouldTerminate]];
|
||||||
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
|
||||||
[self replyToApplicationShouldTerminate:[_delegate applicationShouldTerminate:self]];
|
|
||||||
else
|
|
||||||
[self replyToApplicationShouldTerminate:YES];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)replyToApplicationShouldTerminate:(BOOL)terminate
|
- (void)replyToApplicationShouldTerminate:(BOOL)terminate
|
||||||
@@ -428,16 +455,22 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
|
|
||||||
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||||
{
|
{
|
||||||
|
if (_isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
[self _willBecomeActive];
|
[self _willBecomeActive];
|
||||||
|
|
||||||
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
||||||
_isActive = YES;
|
_isActive = YES;
|
||||||
|
|
||||||
[self _willResignActive];
|
[self _didBecomeActive];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deactivate
|
- (void)deactivate
|
||||||
{
|
{
|
||||||
|
if (!_isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
[self _willResignActive];
|
[self _willResignActive];
|
||||||
|
|
||||||
[CPPlatform deactivate];
|
[CPPlatform deactivate];
|
||||||
@@ -446,7 +479,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
[self _didResignActive];
|
[self _didResignActive];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)isActive
|
- (BOOL)isActive
|
||||||
{
|
{
|
||||||
return _isActive;
|
return _isActive;
|
||||||
}
|
}
|
||||||
@@ -463,6 +496,15 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
- (void)run
|
- (void)run
|
||||||
{
|
{
|
||||||
[self finishLaunching];
|
[self finishLaunching];
|
||||||
|
[self sendEvent:[CPEvent otherEventWithType:CPAppKitDefined
|
||||||
|
location:CGPointMakeZero()
|
||||||
|
modifierFlags:0
|
||||||
|
timestamp:[CPEvent currentTimestamp]
|
||||||
|
windowNumber:[_keyWindow windowNumber]
|
||||||
|
context:nil
|
||||||
|
subtype:nil
|
||||||
|
data1:nil
|
||||||
|
data2:nil]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing the Event Loop
|
// Managing the Event Loop
|
||||||
@@ -586,11 +628,6 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
|
|
||||||
var theWindow = [anEvent window];
|
var theWindow = [anEvent window];
|
||||||
|
|
||||||
// Check if this is a candidate for key equivalent...
|
|
||||||
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
|
||||||
// The key equivalent was handled.
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ([anEvent type] == CPMouseMoved)
|
if ([anEvent type] == CPMouseMoved)
|
||||||
{
|
{
|
||||||
if (theWindow !== _lastMouseMoveWindow)
|
if (theWindow !== _lastMouseMoveWindow)
|
||||||
@@ -627,6 +664,11 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
|
|
||||||
_eventListenerInsertionIndex = _eventListeners.length;
|
_eventListenerInsertionIndex = _eventListeners.length;
|
||||||
|
|
||||||
|
// Check if this is a candidate for key equivalent...
|
||||||
|
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
||||||
|
// The key equivalent was handled.
|
||||||
|
return;
|
||||||
|
|
||||||
if (theWindow)
|
if (theWindow)
|
||||||
[theWindow sendEvent:anEvent];
|
[theWindow sendEvent:anEvent];
|
||||||
}
|
}
|
||||||
@@ -942,7 +984,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
*/
|
*/
|
||||||
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||||
{
|
{
|
||||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }, shouldDequeue));
|
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { if (aTarget != null) aTarget.isa.objj_msgSend1(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -971,7 +1013,9 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
if (![aWindow attachedSheet])
|
||||||
|
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
||||||
|
|
||||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:didEndSelector contextInfo:contextInfo];
|
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:didEndSelector contextInfo:contextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1158,7 +1202,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
[[self keyWindow] orderFront:self];
|
[[self keyWindow] orderFront:self];
|
||||||
else if ([self mainWindow])
|
else if ([self mainWindow])
|
||||||
[[self mainWindow] makeKeyAndOrderFront:self];
|
[[self mainWindow] makeKeyAndOrderFront:self];
|
||||||
else
|
else if ([self mainMenu])
|
||||||
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
|
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
|
||||||
|
|
||||||
_previousKeyWindow = nil;
|
_previousKeyWindow = nil;
|
||||||
@@ -1176,6 +1220,22 @@ var CPMainCibFile = @"CPMainCibFile",
|
|||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)_sendDelegateApplicationShouldTerminate
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPApplicationDelegate_applicationShouldTerminate_))
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
return [_delegate applicationShouldTerminate:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_sendDelegateApplicationShouldTerminateMessage
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPApplicationDelegate_applicationShouldTerminateMessage_))
|
||||||
|
return @"You have attempted to leave this page. Are you sure you want to exit this page?";
|
||||||
|
|
||||||
|
return [_delegate applicationShouldTerminateMessage:self];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_didResignActive
|
- (void)_didResignActive
|
||||||
{
|
{
|
||||||
if (self._activeMenu)
|
if (self._activeMenu)
|
||||||
@@ -1298,7 +1358,7 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
{
|
{
|
||||||
var action = _CPAppBootstrapperActions.shift();
|
var action = _CPAppBootstrapperActions.shift();
|
||||||
|
|
||||||
if (objj_msgSend(self, action))
|
if (self.isa.objj_msgSend0(self, action))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ CPApplicationWillResignActiveNotification = @"CPApplicationWillResignA
|
|||||||
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||||
CPApplicationDidChangeScreenParametersNotification = @"CPApplicationDidChangeScreenParametersNotification";
|
CPApplicationDidChangeScreenParametersNotification = @"CPApplicationDidChangeScreenParametersNotification";
|
||||||
|
|
||||||
|
@typedef CPApplicationTerminateReply
|
||||||
CPTerminateNow = YES;
|
CPTerminateNow = YES;
|
||||||
CPTerminateCancel = NO;
|
CPTerminateCancel = NO;
|
||||||
CPTerminateLater = -1; // not currently supported
|
CPTerminateLater = -1; // not currently supported
|
||||||
|
|||||||
+26
-27
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPIndexSet.j>
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
@import <Foundation/CPPredicate.j>
|
||||||
@import "CPObjectController.j"
|
@import "CPObjectController.j"
|
||||||
@import "CPKeyValueBinding.j"
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
@@ -219,17 +219,6 @@
|
|||||||
_clearsFilterPredicateOnInsertion = aFlag;
|
_clearsFilterPredicateOnInsertion = aFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether the receiver will always return the multiple values marker when multiple
|
|
||||||
items are selected, even if the items have the same value.
|
|
||||||
|
|
||||||
@return BOOL YES if the receiver always uses the multiple values marker
|
|
||||||
*/
|
|
||||||
- (BOOL)alwaysUsesMultipleValuesMarker
|
|
||||||
{
|
|
||||||
return _alwaysUsesMultipleValuesMarker;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the receiver should always return the multiple values marker when multiple
|
Sets whether the receiver should always return the multiple values marker when multiple
|
||||||
items are selected, even if the items have the same value.
|
items are selected, even if the items have the same value.
|
||||||
@@ -282,7 +271,7 @@
|
|||||||
if (_disableSetContent)
|
if (_disableSetContent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (value === nil)
|
if (value == nil)
|
||||||
value = [];
|
value = [];
|
||||||
|
|
||||||
if (![value isKindOfClass:[CPArray class]])
|
if (![value isKindOfClass:[CPArray class]])
|
||||||
@@ -308,27 +297,18 @@
|
|||||||
class.
|
class.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (_clearsFilterPredicateOnInsertion)
|
|
||||||
[self willChangeValueForKey:@"filterPredicate"];
|
|
||||||
|
|
||||||
// Don't use [super setContent:] as that would fire the contentObject change.
|
// Don't use [super setContent:] as that would fire the contentObject change.
|
||||||
// We need to be in control of when notifications fire.
|
// We need to be in control of when notifications fire.
|
||||||
// Note that if we have a contentArray binding, setting the content does /not/
|
// Note that if we have a contentArray binding, setting the content does /not/
|
||||||
// cause a reverse binding set.
|
// cause a reverse binding set.
|
||||||
_contentObject = value;
|
_contentObject = value;
|
||||||
|
|
||||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
|
[self _rearrangeObjects];
|
||||||
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
|
|
||||||
else
|
|
||||||
[self _rearrangeObjects];
|
|
||||||
|
|
||||||
if ([self preservesSelection])
|
if ([self preservesSelection])
|
||||||
[self __setSelectedObjects:oldSelectedObjects];
|
[self __setSelectedObjects:oldSelectedObjects];
|
||||||
else
|
else
|
||||||
[self __setSelectionIndexes:oldSelectionIndexes];
|
[self __setSelectionIndexes:oldSelectionIndexes];
|
||||||
|
|
||||||
if (_clearsFilterPredicateOnInsertion)
|
|
||||||
[self didChangeValueForKey:@"filterPredicate"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -563,7 +543,7 @@
|
|||||||
*/
|
*/
|
||||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||||
{
|
{
|
||||||
[self _selectionWillChange]
|
[self _selectionWillChange];
|
||||||
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
|
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
|
||||||
[self _selectionDidChange];
|
[self _selectionDidChange];
|
||||||
return r;
|
return r;
|
||||||
@@ -629,6 +609,25 @@
|
|||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
- (void)_selectionWillChange
|
||||||
|
{
|
||||||
|
// Push back all data from the dirty editors before it is too late.
|
||||||
|
|
||||||
|
var editorsCount = [_editors count];
|
||||||
|
|
||||||
|
while (editorsCount--)
|
||||||
|
{
|
||||||
|
var allBindings = [CPBinder allBindingsForObject:_editors[editorsCount]],
|
||||||
|
allKeys = [allBindings allKeys],
|
||||||
|
keysCount = allKeys.length;
|
||||||
|
|
||||||
|
while (keysCount--)
|
||||||
|
[[allBindings objectForKey:allKeys[keysCount]] reverseSetValueFor:allKeys[keysCount]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super _selectionWillChange];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns an array of the selected objects.
|
Returns an array of the selected objects.
|
||||||
@@ -774,7 +773,7 @@
|
|||||||
_filterPredicate = nil;
|
_filterPredicate = nil;
|
||||||
[self _rearrangeObjects];
|
[self _rearrangeObjects];
|
||||||
}
|
}
|
||||||
else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
else if (_filterPredicate == nil || [_filterPredicate evaluateWithObject:object])
|
||||||
{
|
{
|
||||||
// Insert directly into the array.
|
// Insert directly into the array.
|
||||||
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
|
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
|
||||||
@@ -787,7 +786,7 @@
|
|||||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
|
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
else if (_filterPredicate !== nil)
|
else if (_filterPredicate != nil)
|
||||||
...
|
...
|
||||||
// Implies _filterPredicate && ![_filterPredicate evaluateWithObject:object], so the new object does
|
// Implies _filterPredicate && ![_filterPredicate evaluateWithObject:object], so the new object does
|
||||||
// not appear in arrangedObjects and we do not have to update at all.
|
// not appear in arrangedObjects and we do not have to update at all.
|
||||||
@@ -887,7 +886,7 @@
|
|||||||
|
|
||||||
_disableSetContent = NO;
|
_disableSetContent = NO;
|
||||||
|
|
||||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
if (_filterPredicate == nil || [_filterPredicate evaluateWithObject:object])
|
||||||
{
|
{
|
||||||
// selectionIndexes change notification will be fired as a result of the
|
// selectionIndexes change notification will be fired as a result of the
|
||||||
// content change. Don't fire manually.
|
// content change. Don't fire manually.
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ var DefaultLineWidth = 1.0;
|
|||||||
/*!
|
/*!
|
||||||
Cocoa compatibility.
|
Cocoa compatibility.
|
||||||
*/
|
*/
|
||||||
- (void)getLineDash:(CPArrayRef)patternRef count:(NSInteger)count phase:(CGFloatRef)phaseRef
|
- (void)getLineDash:(CPArrayRef)patternRef count:(CPInteger)count phase:(CGFloatRef)phaseRef
|
||||||
{
|
{
|
||||||
return [self getLineDash:patternRef phase:phaseRef];
|
return [self getLineDash:patternRef phase:phaseRef];
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ var DefaultLineWidth = 1.0;
|
|||||||
/*!
|
/*!
|
||||||
Cocoa compatibility.
|
Cocoa compatibility.
|
||||||
*/
|
*/
|
||||||
- (void)setLineDash:(CPArray)aPattern count:(NSInteger)count phase:(CGFloat)aPhase
|
- (void)setLineDash:(CPArray)aPattern count:(CPInteger)count phase:(CGFloat)aPhase
|
||||||
{
|
{
|
||||||
[self setLineDash:aPattern phase:aPhase];
|
[self setLineDash:aPattern phase:aPhase];
|
||||||
}
|
}
|
||||||
|
|||||||
+374
-58
@@ -22,21 +22,25 @@
|
|||||||
|
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import <Foundation/CPGeometry.j>
|
||||||
|
|
||||||
// CPBoxType
|
// CPBoxType
|
||||||
|
@typedef CPBoxType
|
||||||
CPBoxPrimary = 0;
|
CPBoxPrimary = 0;
|
||||||
CPBoxSecondary = 1;
|
CPBoxSecondary = 1; // Deprecated
|
||||||
CPBoxSeparator = 2;
|
CPBoxSeparator = 2;
|
||||||
CPBoxOldStyle = 3;
|
CPBoxOldStyle = 3; // Deprecated
|
||||||
CPBoxCustom = 4;
|
CPBoxCustom = 4;
|
||||||
|
|
||||||
// CPBorderType
|
// CPBorderType
|
||||||
|
@typedef CPBorderType
|
||||||
CPNoBorder = 0;
|
CPNoBorder = 0;
|
||||||
CPLineBorder = 1;
|
CPLineBorder = 1;
|
||||||
CPBezelBorder = 2;
|
CPBezelBorder = 2;
|
||||||
CPGrooveBorder = 3;
|
CPGrooveBorder = 3;
|
||||||
|
|
||||||
// CPTitlePosition
|
// CPTitlePosition
|
||||||
|
@typedef CPTitlePosition
|
||||||
CPNoTitle = 0;
|
CPNoTitle = 0;
|
||||||
CPAboveTop = 1;
|
CPAboveTop = 1;
|
||||||
CPAtTop = 2;
|
CPAtTop = 2;
|
||||||
@@ -55,12 +59,16 @@ CPBelowBottom = 6;
|
|||||||
@implementation CPBox : CPView
|
@implementation CPBox : CPView
|
||||||
{
|
{
|
||||||
CPBoxType _boxType;
|
CPBoxType _boxType;
|
||||||
CPBorderType _borderType;
|
CPBorderType _borderType; // deprecated
|
||||||
CPView _contentView;
|
CPView _contentView;
|
||||||
|
CPView _boxView; // needed for CSS theming, will be transparent for non CSS themes
|
||||||
|
BOOL _transparent @accessors(getter=isTransparent);
|
||||||
|
|
||||||
CPString _title @accessors(getter=title);
|
CPString _title @accessors(getter=title);
|
||||||
int _titlePosition @accessors(getter=titlePosition);
|
int _titlePosition @accessors(getter=titlePosition);
|
||||||
CPTextField _titleView;
|
CPTextField _titleView;
|
||||||
|
|
||||||
|
BOOL _cachedAutoresizesSubviews;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
@@ -87,6 +95,14 @@ CPBelowBottom = 6;
|
|||||||
@"inner-shadow-size": 6.0,
|
@"inner-shadow-size": 6.0,
|
||||||
@"inner-shadow-color": [CPNull null],
|
@"inner-shadow-color": [CPNull null],
|
||||||
@"content-margin": CGSizeMakeZero(),
|
@"content-margin": CGSizeMakeZero(),
|
||||||
|
@"title-font": [CPNull null],
|
||||||
|
@"title-left-offset": 5.0,
|
||||||
|
@"title-top-offset": 0.0,
|
||||||
|
@"title-color": [CPNull null],
|
||||||
|
@"nib2cib-adjustment-primary-frame": CGRectMake(4, -4, -8, -6),
|
||||||
|
@"content-adjustment": CGRectMakeZero(),
|
||||||
|
@"min-y-correction-no-title": 0,
|
||||||
|
@"min-y-correction-title": 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,16 +127,26 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_borderType = CPBezelBorder;
|
_borderType = CPGrooveBorder; // Was CPBezelBorder but Cocoa default is CPGrooveBorder
|
||||||
|
_boxType = CPBoxPrimary;
|
||||||
|
|
||||||
_titlePosition = CPNoTitle;
|
_titlePosition = CPNoTitle;
|
||||||
_titleView = [CPTextField labelWithTitle:@""];
|
_titleView = [CPTextField labelWithTitle:@""];
|
||||||
|
[_titleView setFont:[self titleFont]];
|
||||||
|
[_titleView setTextColor:[self titleColor]];
|
||||||
|
|
||||||
|
_boxView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
|
[_boxView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
[self setAutoresizesSubviews:YES];
|
[self setAutoresizesSubviews:YES];
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_boxView];
|
||||||
|
[_boxView setAutoresizesSubviews:YES];
|
||||||
|
[_boxView addSubview:_contentView];
|
||||||
|
|
||||||
|
[self sizeToFit];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -152,6 +178,8 @@ CPBelowBottom = 6;
|
|||||||
*/
|
*/
|
||||||
- (CPBorderType)borderType
|
- (CPBorderType)borderType
|
||||||
{
|
{
|
||||||
|
CPLog.warn("CPBox borderType is deprecated.");
|
||||||
|
|
||||||
return _borderType;
|
return _borderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +202,8 @@ CPBelowBottom = 6;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_borderType = aBorderType;
|
_borderType = aBorderType;
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -214,13 +243,46 @@ CPBelowBottom = 6;
|
|||||||
*/
|
*/
|
||||||
- (void)setBoxType:(CPBoxType)aBoxType
|
- (void)setBoxType:(CPBoxType)aBoxType
|
||||||
{
|
{
|
||||||
|
if ((aBoxType == CPBoxSecondary) || (aBoxType == CPBoxOldStyle))
|
||||||
|
CPLog.warn("CPBox setBoxType: CPBoxSecondary and CPBoxOldStyle are deprecated.");
|
||||||
|
|
||||||
if (_boxType === aBoxType)
|
if (_boxType === aBoxType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_boxType = aBoxType;
|
_boxType = aBoxType;
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setTransparent:(BOOL)shouldBeTransparent
|
||||||
|
{
|
||||||
|
if (_transparent == shouldBeTransparent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_transparent = shouldBeTransparent;
|
||||||
|
|
||||||
|
[self _manageTitlePositioning];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Style properties which override theme values
|
||||||
|
/*!
|
||||||
|
The borderColor, borderWidth, cornerRadius and fillColor properties for the receiver
|
||||||
|
are only supported for boxes with boxType === CPBoxCustom and borderType === CPLineBorder.
|
||||||
|
Boxes with the Primary boxType have fixed values which are defined by the system theme.
|
||||||
|
Apple does support lineTypes of Groove and Bezel for boxes of type CPBoxCustom, CPBoxSecondary and CPBoxOldStyle,
|
||||||
|
but they are deprecated as of macOS 10.15.
|
||||||
|
|
||||||
|
Cappuccino has supported these in the past but no longer does so - both to simplify CSS-based theming and
|
||||||
|
to avoid the effort needed for supporting something which will be very short-lived.
|
||||||
|
|
||||||
|
These styles can be recreated as custom theme elements by developers, as needed.
|
||||||
|
Additionally, boxes with boxType === CPBoxSeparator (horizontal and vertical lines) have never allowed changing these values.
|
||||||
|
No warnings are generated for separator boxes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark borderColor
|
||||||
- (CPColor)borderColor
|
- (CPColor)borderColor
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"border-color"];
|
return [self valueForThemeAttribute:@"border-color"];
|
||||||
@@ -228,12 +290,25 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (void)setBorderColor:(CPColor)color
|
- (void)setBorderColor:(CPColor)color
|
||||||
{
|
{
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||||
|
{
|
||||||
|
CPLog.warn("CPBox setBorderColor: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setBorderColor. Property is ignored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ([color isEqual:[self borderColor]])
|
if ([color isEqual:[self borderColor]])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self setValue:color forThemeAttribute:@"border-color"];
|
[self setValue:color forThemeAttribute:@"border-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark borderWidth
|
||||||
- (float)borderWidth
|
- (float)borderWidth
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"border-width"];
|
return [self valueForThemeAttribute:@"border-width"];
|
||||||
@@ -241,12 +316,25 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (void)setBorderWidth:(float)width
|
- (void)setBorderWidth:(float)width
|
||||||
{
|
{
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||||
|
{
|
||||||
|
CPLog.warn("CPBox setBorderWidth: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setBorderWidth. Property is ignored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (width === [self borderWidth])
|
if (width === [self borderWidth])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self setValue:width forThemeAttribute:@"border-width"];
|
[self setValue:width forThemeAttribute:@"border-width"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark cornerRadius
|
||||||
- (float)cornerRadius
|
- (float)cornerRadius
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"corner-radius"];
|
return [self valueForThemeAttribute:@"corner-radius"];
|
||||||
@@ -254,12 +342,25 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (void)setCornerRadius:(float)radius
|
- (void)setCornerRadius:(float)radius
|
||||||
{
|
{
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||||
|
{
|
||||||
|
CPLog.warn("CPBox setCornerRadius: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setCornerRadius. Property is ignored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (radius === [self cornerRadius])
|
if (radius === [self cornerRadius])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self setValue:radius forThemeAttribute:@"corner-radius"];
|
[self setValue:radius forThemeAttribute:@"corner-radius"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark fillColor
|
||||||
- (CPColor)fillColor
|
- (CPColor)fillColor
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"background-color"];
|
return [self valueForThemeAttribute:@"background-color"];
|
||||||
@@ -267,6 +368,17 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (void)setFillColor:(CPColor)color
|
- (void)setFillColor:(CPColor)color
|
||||||
{
|
{
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||||
|
{
|
||||||
|
CPLog.warn("CPBox setFillColor: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setFillColor. Property is ignored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ([color isEqual:[self fillColor]])
|
if ([color isEqual:[self fillColor]])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -283,21 +395,20 @@ CPBelowBottom = 6;
|
|||||||
if (aView === _contentView)
|
if (aView === _contentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var borderWidth = [self borderWidth],
|
|
||||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
|
||||||
|
|
||||||
[aView setFrame:CGRectInset([self bounds], contentMargin.width + borderWidth, contentMargin.height + borderWidth)];
|
|
||||||
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
// A nil contentView is allowed (tested in Cocoa 2013-02-22).
|
// A nil contentView is allowed (tested in Cocoa 2013-02-22).
|
||||||
if (!aView)
|
if (!aView)
|
||||||
[_contentView removeFromSuperview];
|
[_contentView removeFromSuperview];
|
||||||
else if (_contentView)
|
else if (_contentView)
|
||||||
[self replaceSubview:_contentView with:aView];
|
[_boxView replaceSubview:_contentView with:aView];
|
||||||
else
|
else
|
||||||
[self addSubview:aView];
|
[_boxView addSubview:aView];
|
||||||
|
|
||||||
_contentView = aView;
|
_contentView = aView;
|
||||||
|
|
||||||
|
[self sizeToFit];
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)contentViewMargins
|
- (CGSize)contentViewMargins
|
||||||
@@ -317,9 +428,14 @@ CPBelowBottom = 6;
|
|||||||
{
|
{
|
||||||
var offset = [self _titleHeightOffset],
|
var offset = [self _titleHeightOffset],
|
||||||
borderWidth = [self borderWidth],
|
borderWidth = [self borderWidth],
|
||||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
contentMargin = [self valueForThemeAttribute:@"content-margin"],
|
||||||
|
contentAdjustment = [self valueForThemeAttribute:@"content-adjustment"],
|
||||||
|
minYCorrection = [self valueForThemeAttribute:(_titlePosition === CPNoTitle ? @"min-y-correction-no-title" : @"min-y-correction-title")];
|
||||||
|
|
||||||
[self setFrame:CGRectInset(aRect, -(contentMargin.width + borderWidth), -(contentMargin.height + offset[0] + borderWidth))];
|
[self setFrame:CGRectMake(aRect.origin.x - contentAdjustment.origin.x - contentMargin.width + borderWidth,
|
||||||
|
aRect.origin.y - contentAdjustment.origin.y - contentMargin.height + borderWidth - minYCorrection,
|
||||||
|
aRect.size.width + 2 * contentMargin.width - contentAdjustment.size.width,
|
||||||
|
aRect.size.height + 2 * contentMargin.height - contentAdjustment.size.height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTitle:(CPString)aTitle
|
- (void)setTitle:(CPString)aTitle
|
||||||
@@ -344,14 +460,42 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (CPFont)titleFont
|
- (CPFont)titleFont
|
||||||
{
|
{
|
||||||
return [_titleView font];
|
if ([self hasThemeAttribute:@"title-font"])
|
||||||
|
return [self valueForThemeAttribute:@"title-font"];
|
||||||
|
else
|
||||||
|
return [_titleView font];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTitleFont:(CPFont)aFont
|
- (void)setTitleFont:(CPFont)aFont
|
||||||
{
|
{
|
||||||
|
if ([aFont isEqual:[self titleFont]])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([self hasThemeAttribute:@"title-font"])
|
||||||
|
[self setValue:aFont forThemeAttribute:@"title-font"];
|
||||||
|
|
||||||
[_titleView setFont:aFont];
|
[_titleView setFont:aFont];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPColor)titleColor
|
||||||
|
{
|
||||||
|
if ([self hasThemeAttribute:@"title-color"])
|
||||||
|
return [self valueForThemeAttribute:@"title-color"];
|
||||||
|
else
|
||||||
|
return [_titleView textColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitleColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([aColor isEqual:[self titleColor]])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([self hasThemeAttribute:@"title-color"])
|
||||||
|
[self setValue:aColor forThemeAttribute:@"title-color"];
|
||||||
|
|
||||||
|
[_titleView setTextColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Return the text field used to display the receiver's title.
|
Return the text field used to display the receiver's title.
|
||||||
|
|
||||||
@@ -362,25 +506,39 @@ CPBelowBottom = 6;
|
|||||||
return _titleView;
|
return _titleView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return the rectangle in which the receiver’s title is drawn.
|
||||||
|
*/
|
||||||
|
- (CGRect)titleRect
|
||||||
|
{
|
||||||
|
return [_titleView frame];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_manageTitlePositioning
|
- (void)_manageTitlePositioning
|
||||||
{
|
{
|
||||||
if (_titlePosition == CPNoTitle)
|
if ((_titlePosition == CPNoTitle) || _transparent)
|
||||||
{
|
{
|
||||||
[_titleView removeFromSuperview];
|
[_titleView removeFromSuperview];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
|
if (_boxType !== CPBoxSeparator)
|
||||||
|
[self sizeToFit];
|
||||||
|
|
||||||
|
[self refreshDisplay];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[_titleView setStringValue:_title];
|
[_titleView setStringValue:_title];
|
||||||
[_titleView sizeToFit];
|
[_titleView sizeToFit];
|
||||||
[self addSubview:_titleView];
|
|
||||||
|
var titleLeftOffset = [self valueForThemeAttribute:@"title-left-offset"],
|
||||||
|
titleTopOffset = [self valueForThemeAttribute:@"title-top-offset"];
|
||||||
|
|
||||||
switch (_titlePosition)
|
switch (_titlePosition)
|
||||||
{
|
{
|
||||||
case CPAtTop:
|
case CPAtTop:
|
||||||
case CPAboveTop:
|
case CPAboveTop:
|
||||||
case CPBelowTop:
|
case CPBelowTop:
|
||||||
[_titleView setFrameOrigin:CGPointMake(5.0, 0.0)];
|
[_titleView setFrameOrigin:CGPointMake(titleLeftOffset, titleTopOffset)]; // FIXME: was 0.0
|
||||||
[_titleView setAutoresizingMask:CPViewNotSizable];
|
[_titleView setAutoresizingMask:CPViewNotSizable];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -388,39 +546,51 @@ CPBelowBottom = 6;
|
|||||||
case CPAtBottom:
|
case CPAtBottom:
|
||||||
case CPBelowBottom:
|
case CPBelowBottom:
|
||||||
var h = [_titleView frameSize].height;
|
var h = [_titleView frameSize].height;
|
||||||
[_titleView setFrameOrigin:CGPointMake(5.0, [self frameSize].height - h)];
|
[_titleView setFrameOrigin:CGPointMake(titleLeftOffset, [self frameSize].height - h - titleTopOffset)];
|
||||||
[_titleView setAutoresizingMask:CPViewMinYMargin];
|
[_titleView setAutoresizingMask:CPViewMinYMargin];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_transparent)
|
||||||
|
[self addSubview:_titleView];
|
||||||
|
|
||||||
[self sizeToFit];
|
[self sizeToFit];
|
||||||
[self setNeedsDisplay:YES];
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sizeToFit
|
- (void)sizeToFit
|
||||||
{
|
{
|
||||||
var contentFrame = [_contentView frame],
|
var offset = [self _titleHeightOffset],
|
||||||
offset = [self _titleHeightOffset],
|
size = [self frameSize];
|
||||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
|
||||||
|
|
||||||
if (!contentFrame)
|
[_boxView setFrame:CGRectMake(0, offset[1], size.width, size.height - offset[0])];
|
||||||
|
|
||||||
|
if (!_contentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_contentView setFrameOrigin:CGPointMake(contentMargin.width, contentMargin.height + offset[1])];
|
var boxSize = [_boxView frameSize],
|
||||||
|
contentMargin = [self valueForThemeAttribute:@"content-margin"],
|
||||||
|
contentAdjustment = [self valueForThemeAttribute:@"content-adjustment"],
|
||||||
|
borderWidth = [self valueForThemeAttribute:@"border-width"],
|
||||||
|
minYCorrection = [self valueForThemeAttribute:(_titlePosition === CPNoTitle ? @"min-y-correction-no-title" : @"min-y-correction-title")];
|
||||||
|
|
||||||
|
[_contentView setFrame:CGRectMake(contentAdjustment.origin.x + contentMargin.width - borderWidth,
|
||||||
|
contentAdjustment.origin.y + contentMargin.height - borderWidth + minYCorrection,
|
||||||
|
boxSize.width - 2 * contentMargin.width + contentAdjustment.size.width,
|
||||||
|
boxSize.height - 2 * contentMargin.height + contentAdjustment.size.height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)_titleHeightOffset
|
- (CPArray)_titleHeightOffset
|
||||||
{
|
{
|
||||||
if (_titlePosition == CPNoTitle)
|
var titleTopOffset = [self valueForThemeAttribute:@"title-top-offset"];
|
||||||
return [0.0, 0.0];
|
|
||||||
|
|
||||||
switch (_titlePosition)
|
switch (_titlePosition)
|
||||||
{
|
{
|
||||||
case CPAtTop:
|
case CPAtTop:
|
||||||
return [[_titleView frameSize].height, [_titleView frameSize].height];
|
return [[_titleView frameSize].height + titleTopOffset, [_titleView frameSize].height + titleTopOffset];
|
||||||
|
|
||||||
case CPAtBottom:
|
case CPAtBottom:
|
||||||
return [[_titleView frameSize].height, 0.0];
|
return [[_titleView frameSize].height + titleTopOffset, 0.0];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [0.0, 0.0];
|
return [0.0, 0.0];
|
||||||
@@ -437,21 +607,24 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
- (void)drawRect:(CGRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
|
if ([self isCSSBased] && (_boxType !== CPBoxCustom))
|
||||||
|
return;
|
||||||
|
|
||||||
var bounds = [self bounds];
|
var bounds = [self bounds];
|
||||||
|
|
||||||
switch (_boxType)
|
if (_boxType === CPBoxSeparator)
|
||||||
{
|
{
|
||||||
case CPBoxSeparator:
|
// NSBox does not include a horizontal flag for the separator type. We have to determine
|
||||||
// NSBox does not include a horizontal flag for the separator type. We have to determine
|
// the type of separator to draw by the width and height of the frame.
|
||||||
// the type of separator to draw by the width and height of the frame.
|
if (CGRectGetWidth(bounds) === 5.0)
|
||||||
if (CGRectGetWidth(bounds) === 5.0)
|
return [self _drawVerticalSeparatorInRect:bounds];
|
||||||
return [self _drawVerticalSeparatorInRect:bounds];
|
else if (CGRectGetHeight(bounds) === 5.0)
|
||||||
else if (CGRectGetHeight(bounds) === 5.0)
|
return [self _drawHorizontalSeparatorInRect:bounds];
|
||||||
return [self _drawHorizontalSeparatorInRect:bounds];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_transparent)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_titlePosition == CPAtTop)
|
if (_titlePosition == CPAtTop)
|
||||||
{
|
{
|
||||||
bounds.origin.y += [_titleView frameSize].height;
|
bounds.origin.y += [_titleView frameSize].height;
|
||||||
@@ -472,9 +645,6 @@ CPBelowBottom = 6;
|
|||||||
switch (_borderType)
|
switch (_borderType)
|
||||||
{
|
{
|
||||||
case CPBezelBorder:
|
case CPBezelBorder:
|
||||||
[self _drawBezelBorderInRect:bounds];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPGrooveBorder:
|
case CPGrooveBorder:
|
||||||
case CPLineBorder:
|
case CPLineBorder:
|
||||||
[self _drawLineBorderInRect:bounds];
|
[self _drawLineBorderInRect:bounds];
|
||||||
@@ -591,11 +761,83 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPBox (CSSTheming)
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if (![self isCSSBased] || (_boxType === CPBoxCustom))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bounds = [self bounds];
|
||||||
|
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
{
|
||||||
|
if (bounds.size.width === 5.0)
|
||||||
|
{
|
||||||
|
// Vertical separator
|
||||||
|
[_boxView setFrame:CGRectMake(2,0,1,bounds.size.height)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Horizontal separator
|
||||||
|
[_boxView setFrame:CGRectMake(0,2,bounds.size.width,1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_boxView setBackgroundColor:[self valueForThemeAttribute:@"border-color"]];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All types of boxes (beside custom which is not covered here) always draw the same way, unless they are CPNoBorder.
|
||||||
|
if ((_borderType !== CPNoBorder) && !_transparent)
|
||||||
|
{
|
||||||
|
[_boxView setBackgroundColor:[self valueForThemeAttribute:@"background-color"]];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No border or transparent
|
||||||
|
[_boxView setBackgroundColor:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isCSSBased
|
||||||
|
{
|
||||||
|
return [[self theme] isCSSBased];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)refreshDisplay
|
||||||
|
{
|
||||||
|
if ([self isCSSBased] && (_boxType !== CPBoxCustom))
|
||||||
|
[self setNeedsLayout:YES];
|
||||||
|
else
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAutoresizesSubviews:(BOOL)flag
|
||||||
|
{
|
||||||
|
// CPBox should always resize its subviews, like in Cocoa, whatever is the corresponding flag set.
|
||||||
|
// We have to keep the flag value as we could have to return it in -autoresizesSubview method.
|
||||||
|
_cachedAutoresizesSubviews = !!flag;
|
||||||
|
[super setAutoresizesSubviews:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)autoresizesSubview
|
||||||
|
{
|
||||||
|
return _cachedAutoresizesSubviews;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
var CPBoxTypeKey = @"CPBoxTypeKey",
|
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||||
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||||
CPBoxTitle = @"CPBoxTitle",
|
CPBoxTitleKey = @"CPBoxTitleKey",
|
||||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
CPBoxTitlePositionKey = @"CPBoxTitlePositionKey",
|
||||||
CPBoxTitleView = @"CPBoxTitleView";
|
CPBoxTitleViewKey = @"CPBoxTitleViewKey",
|
||||||
|
CPBoxContentViewKey = @"CPBoxContentViewKey",
|
||||||
|
CPBoxBoxViewKey = @"CPBoxBoxViewKey";
|
||||||
|
|
||||||
@implementation CPBox (CPCoding)
|
@implementation CPBox (CPCoding)
|
||||||
|
|
||||||
@@ -608,16 +850,56 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
|||||||
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
||||||
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||||
|
|
||||||
_title = [aCoder decodeObjectForKey:CPBoxTitle];
|
_title = [aCoder decodeObjectForKey:CPBoxTitleKey];
|
||||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePositionKey];
|
||||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
|
||||||
|
|
||||||
_contentView = [self subviews][0];
|
// Important : see comment on encodeWithCoder below
|
||||||
|
|
||||||
|
_boxView = [aCoder decodeObjectForKey:CPBoxBoxViewKey];
|
||||||
|
|
||||||
|
if (!_boxView)
|
||||||
|
{
|
||||||
|
// We're coming from nib2cib.
|
||||||
|
|
||||||
|
_boxView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
|
_titleView = [CPTextField labelWithTitle:_title];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We're coming from elsewhere
|
||||||
|
|
||||||
|
_titleView = [aCoder decodeObjectForKey:CPBoxTitleViewKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
_contentView = [aCoder decodeObjectForKey:CPBoxContentViewKey];
|
||||||
|
|
||||||
|
// FIXME: super-mega-hyper-trick : _contentView has a superview which is not normal !
|
||||||
|
// FIXME: (see encodeWithCoder to understand why this is not possible)
|
||||||
|
// FIXME: we fix this by hand. This is horrible so please find a structural solution !
|
||||||
|
|
||||||
|
if (_contentView)
|
||||||
|
_contentView._superview = nil;
|
||||||
|
|
||||||
[self setAutoresizesSubviews:YES];
|
|
||||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
[_boxView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
[_boxView setAutoresizesSubviews:YES];
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
|
||||||
|
if (_contentView)
|
||||||
|
[_boxView setSubviews:@[_contentView]];
|
||||||
|
|
||||||
|
[self addSubview:_boxView];
|
||||||
|
[self addSubview:_titleView];
|
||||||
|
|
||||||
|
if (_boxType === CPBoxSeparator)
|
||||||
|
_titlePosition = CPNoTitle;
|
||||||
|
|
||||||
|
[_titleView setFont:[self titleFont]];
|
||||||
|
[_titleView setTextColor:[self titleColor]];
|
||||||
|
|
||||||
[self _manageTitlePositioning];
|
[self _manageTitlePositioning];
|
||||||
|
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -625,13 +907,47 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
|||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
|
// We have to distinguish between 2 cases :
|
||||||
|
// - we come from nib2cib
|
||||||
|
// - we come from elsewhere
|
||||||
|
//
|
||||||
|
// When coming from nib2cib, we have no _boxView, _contentView, _titleView.
|
||||||
|
// We fix _contentView to be the first (and only) subview.
|
||||||
|
// They will have to be added on decoding.
|
||||||
|
//
|
||||||
|
// When coming from elsewhere, we remove _boxView (and thus _contentView) and _titleView
|
||||||
|
// from the view hierarchy as we'll already encode them via variables.
|
||||||
|
// They will be putted back during decoding. This way, we reduce the space and speed needed for coding.
|
||||||
|
|
||||||
|
var subviews = [self subviews];
|
||||||
|
|
||||||
|
if (!_boxView)
|
||||||
|
{
|
||||||
|
// We're coming from nib2cib.
|
||||||
|
|
||||||
|
_contentView = subviews[0];
|
||||||
|
|
||||||
|
[_contentView removeFromSuperview];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We're coming from elsewhere.
|
||||||
|
|
||||||
|
[_boxView removeFromSuperview];
|
||||||
|
[_titleView removeFromSuperview];
|
||||||
|
}
|
||||||
|
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[self setSubviews:subviews];
|
||||||
|
|
||||||
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
|
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
|
||||||
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
||||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
[aCoder encodeObject:_title forKey:CPBoxTitleKey];
|
||||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePositionKey];
|
||||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
[aCoder encodeConditionalObject:_contentView forKey:CPBoxContentViewKey];
|
||||||
|
[aCoder encodeConditionalObject:_titleView forKey:CPBoxTitleViewKey];
|
||||||
|
[aCoder encodeConditionalObject:_boxView forKey:CPBoxBoxViewKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+253
-71
@@ -20,6 +20,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPIndexSet.j>
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@@ -30,40 +31,84 @@
|
|||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
|
@protocol CPBrowserDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)browser:(CPBrowser)browser acceptDrop:(id)info atRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
||||||
|
- (BOOL)browser:(CPBrowser)browser canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent )event;
|
||||||
|
- (BOOL)browser:(CPBrowser)browser isLeafItem:(id)item;
|
||||||
|
- (BOOL)browser:(CPBrowser)browser shouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)column;
|
||||||
|
- (BOOL)browser:(CPBrowser)browser writeRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column toPasteboard:(CPPasteboard)pasteboard;
|
||||||
|
- (CPDragOperation)browser:(CPBrowser)browser validateDrop:(id)info proposedRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
||||||
|
- (CPImage)browser:(CPBrowser)browser imageValueForItem:(id)anItem;
|
||||||
|
- (CPImage)browser:(CPBrowser)browser draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||||
|
- (CPIndexSet)browser:(CPBrowser)browser selectionIndexesForProposedSelection:(CPIndexSet)proposedSelectionIndexes inColumn:(CPInteger)column;
|
||||||
|
- (CPInteger)browser:(CPBrowser)browser numberOfChildrenOfItem:(id)item;
|
||||||
|
- (CPView)browser:(CPBrowser)browser draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||||
|
- (id)browser:(CPBrowser)browser child:(CPInteger)index ofItem:(id)item;
|
||||||
|
- (id)browser:(CPBrowser)browser objectValueForItem:(id)item;
|
||||||
|
- (id)rootItemForBrowser:(CPBrowser)browser;
|
||||||
|
- (void)browser:(CPBrowser)browser didChangeLastColumn:(CPInteger)oldLastColumn toColumn:(CPInteger)column;
|
||||||
|
- (void)browser:(CPBrowser)browser didResizeColumn:(CPInteger)column;
|
||||||
|
- (void)browserSelectionIsChanging:(CPBrowser)browser;
|
||||||
|
- (void)browserSelectionDidChange:(CPBrowser)browser;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_ = 1 << 1,
|
||||||
|
CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_ = 1 << 2,
|
||||||
|
CPBrowserDelegate_browser_isLeafItem_ = 1 << 3,
|
||||||
|
CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_ = 1 << 4,
|
||||||
|
CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_ = 1 << 5,
|
||||||
|
CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_ = 1 << 6,
|
||||||
|
CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 7,
|
||||||
|
CPBrowserDelegate_browser_imageValueForItem_ = 1 << 8,
|
||||||
|
CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_ = 1 << 9,
|
||||||
|
CPBrowserDelegate_browser_numberOfChildrenOfItem_ = 1 << 10,
|
||||||
|
CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 11,
|
||||||
|
CPBrowserDelegate_browser_child_ofItem_ = 1 << 12,
|
||||||
|
CPBrowserDelegate_browser_objectValueForItem_ = 1 << 13,
|
||||||
|
CPBrowserDelegate_rootItemForBrowser_ = 1 << 14,
|
||||||
|
CPBrowserDelegate_browser_didChangeLastColumn_toColumn_ = 1 << 15,
|
||||||
|
CPBrowserDelegate_browser_didResizeColumn_ = 1 << 16,
|
||||||
|
CPBrowserDelegate_browserSelectionIsChanging_ = 1 << 17,
|
||||||
|
CPBrowserDelegate_browserSelectionDidChange_ = 1 << 18;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPBrowser
|
@class CPBrowser
|
||||||
*/
|
*/
|
||||||
@implementation CPBrowser : CPControl
|
@implementation CPBrowser : CPControl
|
||||||
{
|
{
|
||||||
id _delegate;
|
id <CPBrowserDelegate> _delegate;
|
||||||
CPString _pathSeparator;
|
CPString _pathSeparator;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
CPView _contentView;
|
CPView _contentView;
|
||||||
CPScrollView _horizontalScrollView;
|
CPScrollView _horizontalScrollView;
|
||||||
CPView _prototypeView;
|
CPView _prototypeView;
|
||||||
|
|
||||||
CPArray _tableViews;
|
CPArray _tableViews;
|
||||||
CPArray _tableDelegates;
|
CPArray _tableDelegates;
|
||||||
|
|
||||||
id _rootItem;
|
id _rootItem;
|
||||||
|
|
||||||
BOOL _delegateSupportsImages;
|
BOOL _delegateSupportsImages;
|
||||||
|
|
||||||
SEL _doubleAction @accessors(property=doubleAction);
|
SEL _doubleAction @accessors(property=doubleAction);
|
||||||
|
|
||||||
BOOL _allowsMultipleSelection;
|
BOOL _allowsMultipleSelection;
|
||||||
BOOL _allowsEmptySelection;
|
BOOL _allowsEmptySelection;
|
||||||
|
|
||||||
Class _tableViewClass @accessors(property=tableViewClass);
|
Class _tableViewClass @accessors(property=tableViewClass);
|
||||||
|
|
||||||
float _rowHeight;
|
float _rowHeight;
|
||||||
float _imageWidth;
|
float _imageWidth;
|
||||||
float _leafWidth;
|
float _leafWidth;
|
||||||
float _minColumnWidth;
|
float _minColumnWidth;
|
||||||
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
||||||
|
|
||||||
CPArray _columnWidths;
|
CPArray _columnWidths;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
+ (CPString)defaultThemeClass
|
||||||
@@ -137,10 +182,71 @@
|
|||||||
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDelegate:(id)anObject
|
- (void)setDelegate:(id <CPBrowserDelegate>)anObject
|
||||||
{
|
{
|
||||||
|
if (_delegate === anObject)
|
||||||
|
return;
|
||||||
|
|
||||||
_delegate = anObject;
|
_delegate = anObject;
|
||||||
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
|
_implementedDelegateMethods = 0;
|
||||||
|
_delegateSupportsImages = NO;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:isLeafItem:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_isLeafItem_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:imageValueForItem:)])
|
||||||
|
{
|
||||||
|
_delegateSupportsImages = YES;
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_imageValueForItem_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:numberOfChildrenOfItem:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_numberOfChildrenOfItem_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:child:ofItem:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_child_ofItem_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:objectValueForItem:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_objectValueForItem_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_rootItemForBrowser_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_didChangeLastColumn_toColumn_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_didResizeColumn_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionIsChanging_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||||
|
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionDidChange_;
|
||||||
|
|
||||||
[self loadColumnZero];
|
[self loadColumnZero];
|
||||||
}
|
}
|
||||||
@@ -162,10 +268,7 @@
|
|||||||
|
|
||||||
- (void)loadColumnZero
|
- (void)loadColumnZero
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
_rootItem = [self _sendDelegateRootItemForBrowser];
|
||||||
_rootItem = [_delegate rootItemForBrowser:self];
|
|
||||||
else
|
|
||||||
_rootItem = nil;
|
|
||||||
|
|
||||||
[self setLastColumn:-1];
|
[self setLastColumn:-1];
|
||||||
[self addColumn];
|
[self addColumn];
|
||||||
@@ -190,8 +293,7 @@
|
|||||||
_tableViews = _tableViews.slice(0, indexPlusOne);
|
_tableViews = _tableViews.slice(0, indexPlusOne);
|
||||||
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
[self _sendDelegateBrowserDidChangeLastColumn:oldValue toColumn:columnIndex];
|
||||||
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
|
|
||||||
|
|
||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
@@ -361,17 +463,17 @@
|
|||||||
|
|
||||||
- (id)itemAtRow:(CPInteger)row inColumn:(CPInteger)column
|
- (id)itemAtRow:(CPInteger)row inColumn:(CPInteger)column
|
||||||
{
|
{
|
||||||
return [_tableDelegates[column] childAtIndex:row];
|
return [_tableDelegates[column] childAtIndex:row] || nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isLeafItem:(id)item
|
- (BOOL)isLeafItem:(id)item
|
||||||
{
|
{
|
||||||
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
|
return (_implementedDelegateMethods & CPBrowserDelegate_browser_isLeafItem_) && [_delegate browser:self isLeafItem:item];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)parentForItemsInColumn:(CPInteger)column
|
- (id)parentForItemsInColumn:(CPInteger)column
|
||||||
{
|
{
|
||||||
return [_tableDelegates[column] _item];
|
return [_tableDelegates[column] _item] || nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPSet)selectedItems
|
- (CPSet)selectedItems
|
||||||
@@ -493,9 +595,7 @@
|
|||||||
{
|
{
|
||||||
_columnWidths[column] = aWidth;
|
_columnWidths[column] = aWidth;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
|
[self _sendDelegateBrowserDidResizeColumn:column];
|
||||||
[_delegate browser:self didResizeColumn:column];
|
|
||||||
|
|
||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,15 +710,12 @@
|
|||||||
if (column < 0 || column > [self lastColumn] + 1)
|
if (column < 0 || column > [self lastColumn] + 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
indexSet = [self _sendDelegateBrowserSelectionIndexesForProposedSelection:indexSet inColumn:column];
|
||||||
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
|
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
|
if (![self _sendDelegateBrowserShouldSelectRowIndexes:indexSet inColumn:column])
|
||||||
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
[self _sendDelegateBrowserSelectionIsChanging];
|
||||||
[_delegate browserSelectionIsChanging:self];
|
|
||||||
|
|
||||||
if (column > [self lastColumn])
|
if (column > [self lastColumn])
|
||||||
[self addColumn];
|
[self addColumn];
|
||||||
@@ -629,8 +726,7 @@
|
|||||||
|
|
||||||
[self scrollColumnToVisible:column];
|
[self scrollColumnToVisible:column];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
[self _sendDelegateBrowserSelectionDidChange];
|
||||||
[_delegate browserSelectionDidChange:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundColor:(CPColor)aColor
|
- (void)setBackgroundColor:(CPColor)aColor
|
||||||
@@ -652,30 +748,6 @@
|
|||||||
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
|
||||||
{
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
|
||||||
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
|
||||||
{
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
|
||||||
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
|
||||||
{
|
|
||||||
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
|
||||||
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPBrowser (CPCoding)
|
@implementation CPBrowser (CPCoding)
|
||||||
@@ -860,8 +932,6 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
|
||||||
|
|
||||||
@implementation _CPBrowserTableDelegate : CPObject
|
@implementation _CPBrowserTableDelegate : CPObject
|
||||||
{
|
{
|
||||||
CPBrowser _browser @accessors;
|
CPBrowser _browser @accessors;
|
||||||
@@ -909,7 +979,7 @@
|
|||||||
|
|
||||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation
|
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_)
|
||||||
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
||||||
else
|
else
|
||||||
return NO;
|
return NO;
|
||||||
@@ -917,7 +987,7 @@
|
|||||||
|
|
||||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)operation
|
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)operation
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_)
|
||||||
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||||
else
|
else
|
||||||
return CPDragOperationNone;
|
return CPDragOperationNone;
|
||||||
@@ -925,7 +995,7 @@
|
|||||||
|
|
||||||
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_)
|
||||||
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
||||||
else
|
else
|
||||||
return NO;
|
return NO;
|
||||||
@@ -980,7 +1050,7 @@
|
|||||||
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
||||||
positioned:CPWindowAbove
|
positioned:CPWindowAbove
|
||||||
relativeToEphemeralSubviewNamed:nil],
|
relativeToEphemeralSubviewNamed:nil],
|
||||||
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
|
isHighlighted = [self hasThemeState:CPThemeStateSelectedDataView];
|
||||||
|
|
||||||
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||||
[imageView setImageScaling:CPImageScaleNone];
|
[imageView setImageScaling:CPImageScaleNone];
|
||||||
@@ -1008,3 +1078,115 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPBrowser (CPBrowserDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate rootItemForBrowser:
|
||||||
|
*/
|
||||||
|
- (id)_sendDelegateRootItemForBrowser
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_rootItemForBrowser_))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [_delegate rootItemForBrowser:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browser:didChangeLastColumn:toColumn:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateBrowserDidChangeLastColumn:(CPInteger)lastColumn toColumn:(CPInteger)newColumn
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didChangeLastColumn_toColumn_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate browser:self didChangeLastColumn:lastColumn toColumn:newColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browser:didResizeColumn:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateBrowserDidResizeColumn:(CPInteger)column
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didResizeColumn_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate browser:self didResizeColumn:column];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browserSelectionIsChanging:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateBrowserSelectionIsChanging
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionIsChanging_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate browserSelectionIsChanging:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browser:shouldSelectRowIndexes:inColumn:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateBrowserShouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_))
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
return [_delegate browser:self shouldSelectRowIndexes:anIndexSet inColumn:aColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browser:selectionIndexesForProposedSelection:inColumn:
|
||||||
|
*/
|
||||||
|
- (CPIndexSet)_sendDelegateBrowserSelectionIndexesForProposedSelection:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_))
|
||||||
|
return anIndexSet;
|
||||||
|
|
||||||
|
return [_delegate browser:self selectionIndexesForProposedSelection:anIndexSet inColumn:aColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate browserSelectionDidChange
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateBrowserSelectionDidChange
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionDidChange_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate browserSelectionDidChange:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_)
|
||||||
|
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_)
|
||||||
|
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_)
|
||||||
|
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+263
-171
@@ -29,8 +29,7 @@
|
|||||||
@import "CPWindow_Constants.j"
|
@import "CPWindow_Constants.j"
|
||||||
|
|
||||||
/* @group CPBezelStyle */
|
/* @group CPBezelStyle */
|
||||||
|
@typedef CPBezelStyle
|
||||||
// IB style
|
|
||||||
CPRoundedBezelStyle = 1; // Push
|
CPRoundedBezelStyle = 1; // Push
|
||||||
CPRegularSquareBezelStyle = 2; // Bevel
|
CPRegularSquareBezelStyle = 2; // Bevel
|
||||||
CPThickSquareBezelStyle = 3;
|
CPThickSquareBezelStyle = 3;
|
||||||
@@ -45,10 +44,12 @@ CPTexturedRoundedBezelStyle = 11; // Round Textured
|
|||||||
CPRoundRectBezelStyle = 12; // Round Rect
|
CPRoundRectBezelStyle = 12; // Round Rect
|
||||||
CPRecessedBezelStyle = 13; // Recessed
|
CPRecessedBezelStyle = 13; // Recessed
|
||||||
CPRoundedDisclosureBezelStyle = 14; // Disclosure
|
CPRoundedDisclosureBezelStyle = 14; // Disclosure
|
||||||
|
CPInlineBezelStyle = 15; // Inline
|
||||||
CPHUDBezelStyle = -1;
|
CPHUDBezelStyle = -1;
|
||||||
|
|
||||||
|
|
||||||
/* @group CPButtonType */
|
/* @group CPButtonType */
|
||||||
|
@typedef CPButtonType
|
||||||
CPMomentaryLightButton = 0;
|
CPMomentaryLightButton = 0;
|
||||||
CPPushOnPushOffButton = 1;
|
CPPushOnPushOffButton = 1;
|
||||||
CPToggleButton = 2;
|
CPToggleButton = 2;
|
||||||
@@ -72,13 +73,32 @@ CPPushInCellMask = CPPushInButtonMask;
|
|||||||
CPChangeGrayCellMask = CPGrayButtonMask;
|
CPChangeGrayCellMask = CPGrayButtonMask;
|
||||||
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
||||||
|
|
||||||
CPButtonStateMixed = CPThemeState("mixed");
|
CPButtonStateMixed = CPThemeState("mixed");
|
||||||
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
|
CPButtonStateBezelStyleRounded = CPThemeState("rounded"); // IB style : Push
|
||||||
|
CPButtonStateBezelStyleShadowlessSquare = CPThemeState("square"); // IB style : Square
|
||||||
|
CPButtonStateBezelStyleSmallSquare = CPThemeState("gradient"); // IB style : Gradient
|
||||||
|
CPButtonStateBezelStyleTexturedRounded = CPThemeState("textured-rounded"); // IB style : Textured rounded
|
||||||
|
CPButtonStateBezelStyleRoundRect = CPThemeState("roundRect"); // IB style : Round rect
|
||||||
|
CPButtonStateBezelStyleRecessed = CPThemeState("recessed"); // IB style : Recessed
|
||||||
|
CPButtonStateBezelStyleInline = CPThemeState("inline"); // IB style : Inline
|
||||||
|
CPButtonStateBezelStyleRegularSquare = CPThemeState("bevel"); // IB style : Bevel
|
||||||
|
CPButtonStateBezelStyleTextured = CPThemeState("textured"); // IB style : Textured
|
||||||
|
CPButtonStateBezelStyleDisclosure = CPThemeState("disclosure"); // IB style : Disclosure triangle
|
||||||
|
CPButtonStateBezelStyleRoundedDisclosure = CPThemeState("rounded-disclosure"); // IB style : Rounded disclosure
|
||||||
|
|
||||||
// add all future correspondance between bezel styles and theme state here.
|
// add all future correspondance between bezel styles and theme state here.
|
||||||
var CPButtonBezelStyleStateMap = @{
|
var CPButtonBezelStyleStateMap = @{
|
||||||
CPRoundedBezelStyle: CPButtonStateBezelStyleRounded,
|
CPRoundedBezelStyle: CPButtonStateBezelStyleRounded,
|
||||||
CPRoundRectBezelStyle: [CPNull null],
|
CPShadowlessSquareBezelStyle: CPButtonStateBezelStyleShadowlessSquare,
|
||||||
|
CPSmallSquareBezelStyle: CPButtonStateBezelStyleSmallSquare,
|
||||||
|
CPTexturedRoundedBezelStyle: CPButtonStateBezelStyleTexturedRounded,
|
||||||
|
CPRoundRectBezelStyle: CPButtonStateBezelStyleRoundRect,
|
||||||
|
CPRecessedBezelStyle: CPButtonStateBezelStyleRecessed,
|
||||||
|
CPInlineBezelStyle: CPButtonStateBezelStyleInline,
|
||||||
|
CPRegularSquareBezelStyle: CPButtonStateBezelStyleRegularSquare,
|
||||||
|
CPTexturedSquareBezelStyle: CPButtonStateBezelStyleTextured,
|
||||||
|
CPDisclosureBezelStyle: CPButtonStateBezelStyleDisclosure,
|
||||||
|
CPRoundedDisclosureBezelStyle: CPButtonStateBezelStyleRoundedDisclosure
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @cond IGNORE
|
/// @cond IGNORE
|
||||||
@@ -107,7 +127,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
// NS-style Display Properties
|
// NS-style Display Properties
|
||||||
CPBezelStyle _bezelStyle;
|
CPBezelStyle _bezelStyle;
|
||||||
CPControlSize _controlSize;
|
ThemeState _bezelState;
|
||||||
|
|
||||||
CPString _keyEquivalent;
|
CPString _keyEquivalent;
|
||||||
unsigned _keyEquivalentModifierMask;
|
unsigned _keyEquivalentModifierMask;
|
||||||
@@ -117,7 +137,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
float _periodicDelay;
|
float _periodicDelay;
|
||||||
float _periodicInterval;
|
float _periodicInterval;
|
||||||
|
|
||||||
BOOL _isTracking;
|
BOOL _isHighlighted;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
@@ -154,9 +174,17 @@ CPButtonImageOffset = 3.0;
|
|||||||
return @{
|
return @{
|
||||||
@"image": [CPNull null],
|
@"image": [CPNull null],
|
||||||
@"image-offset": 0.0,
|
@"image-offset": 0.0,
|
||||||
|
@"image-vertical-offset": 0.0,
|
||||||
@"bezel-inset": CGInsetMakeZero(),
|
@"bezel-inset": CGInsetMakeZero(),
|
||||||
@"content-inset": CGInsetMakeZero(),
|
@"content-inset": CGInsetMakeZero(),
|
||||||
@"bezel-color": [CPNull null],
|
@"bezel-color": [CPNull null],
|
||||||
|
@"image-position": CPImageLeft,
|
||||||
|
@"vertical-alignment": CPCenterVerticalTextAlignment,
|
||||||
|
@"alignment": CPCenterTextAlignment,
|
||||||
|
@"image-scaling": CPImageScaleNone,
|
||||||
|
@"invert-image": NO,
|
||||||
|
@"invert-image-on-push": NO,
|
||||||
|
@"image-color": [CPNull null] // If null, image color follows text color
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +199,6 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
// Should we instead override the defaults?
|
|
||||||
[self setValue:CPCenterTextAlignment forThemeAttribute:@"alignment"];
|
|
||||||
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
|
||||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
|
||||||
[self setValue:CPImageScaleNone forThemeAttribute:@"image-scaling"];
|
|
||||||
|
|
||||||
[self setBezelStyle:CPRoundRectBezelStyle];
|
[self setBezelStyle:CPRoundRectBezelStyle];
|
||||||
[self setBordered:YES];
|
[self setBordered:YES];
|
||||||
|
|
||||||
@@ -188,8 +210,6 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
- (void)_init
|
- (void)_init
|
||||||
{
|
{
|
||||||
_controlSize = CPRegularControlSize;
|
|
||||||
|
|
||||||
_keyEquivalent = @"";
|
_keyEquivalent = @"";
|
||||||
_keyEquivalentModifierMask = 0;
|
_keyEquivalentModifierMask = 0;
|
||||||
|
|
||||||
@@ -200,6 +220,20 @@ CPButtonImageOffset = 3.0;
|
|||||||
[self setButtonType:CPMomentaryPushInButton];
|
[self setButtonType:CPMomentaryPushInButton];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Control Size
|
||||||
|
|
||||||
|
- (void)setControlSize:(CPControlSize)aControlSize
|
||||||
|
{
|
||||||
|
[super setControlSize:aControlSize];
|
||||||
|
|
||||||
|
if ([self isBordered])
|
||||||
|
[self _sizeToControlSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
// Setting the state
|
// Setting the state
|
||||||
/*!
|
/*!
|
||||||
Returns a Boolean value indicating whether the button allows a mixed state.
|
Returns a Boolean value indicating whether the button allows a mixed state.
|
||||||
@@ -246,30 +280,6 @@ CPButtonImageOffset = 3.0;
|
|||||||
anObjectValue = CPOnState;
|
anObjectValue = CPOnState;
|
||||||
|
|
||||||
[super setObjectValue:anObjectValue];
|
[super setObjectValue:anObjectValue];
|
||||||
|
|
||||||
switch ([self objectValue])
|
|
||||||
{
|
|
||||||
case CPMixedState:
|
|
||||||
[self unsetThemeState:CPThemeStateSelected];
|
|
||||||
[self setThemeState:CPButtonStateMixed];
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
[self setThemeState:CPThemeStateHighlighted];
|
|
||||||
else
|
|
||||||
[self unsetThemeState:CPThemeStateHighlighted];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPOnState:
|
|
||||||
[self unsetThemeState:CPButtonStateMixed];
|
|
||||||
[self setThemeState:CPThemeStateSelected];
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
[self setThemeState:CPThemeStateHighlighted];
|
|
||||||
else
|
|
||||||
[self unsetThemeState:CPThemeStateHighlighted];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPOffState:
|
|
||||||
[self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed | CPThemeStateHighlighted];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -366,12 +376,21 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
- (void)setImage:(CPImage)anImage
|
- (void)setImage:(CPImage)anImage
|
||||||
{
|
{
|
||||||
[self setValue:anImage forThemeAttribute:@"image"];
|
// This is needed when compiling themes
|
||||||
|
if (!_bezelState)
|
||||||
|
_bezelState = CPThemeStateNormal;
|
||||||
|
|
||||||
|
[self setValue:anImage forThemeAttribute:@"image" inState:_bezelState];
|
||||||
|
// if we omit this, images will disappear as soon as the button becomes disabled
|
||||||
|
[self setValue:anImage forThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateDisabled)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)image
|
- (CPImage)image
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
|
if (!_bezelState)
|
||||||
|
_bezelState = CPThemeStateNormal;
|
||||||
|
|
||||||
|
return [self valueForThemeAttribute:@"image" inState:_bezelState];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -380,7 +399,8 @@ CPButtonImageOffset = 3.0;
|
|||||||
*/
|
*/
|
||||||
- (void)setAlternateImage:(CPImage)anImage
|
- (void)setAlternateImage:(CPImage)anImage
|
||||||
{
|
{
|
||||||
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
[self setValue:anImage forThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateHighlighted)];
|
||||||
|
[self setValue:anImage forThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateSelected)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -388,7 +408,17 @@ CPButtonImageOffset = 3.0;
|
|||||||
*/
|
*/
|
||||||
- (CPImage)alternateImage
|
- (CPImage)alternateImage
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
return [self valueForThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateSelected)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHoveredImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
[self setValue:anImage forThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateHovered)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)hoveredImage
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"image" inState:_bezelState.and(CPThemeStateHovered)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageOffset:(float)theImageOffset
|
- (void)setImageOffset:(float)theImageOffset
|
||||||
@@ -411,11 +441,6 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
_showsStateBy = aMask;
|
_showsStateBy = aMask;
|
||||||
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask) && [self state] != CPOffState)
|
|
||||||
[self setThemeState:CPThemeStateHighlighted];
|
|
||||||
else
|
|
||||||
[self unsetThemeState:CPThemeStateHighlighted];
|
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -432,11 +457,8 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
_highlightsBy = aMask;
|
_highlightsBy = aMask;
|
||||||
|
|
||||||
if ([self hasThemeState:CPThemeStateHighlighted])
|
[self setNeedsDisplay:YES];
|
||||||
{
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
[self setNeedsLayout];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPInteger)highlightsBy
|
- (CPInteger)highlightsBy
|
||||||
@@ -521,9 +543,20 @@ CPButtonImageOffset = 3.0;
|
|||||||
_periodicInterval = anInterval;
|
_periodicInterval = anInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)highlight:(BOOL)shouldHighlight
|
||||||
|
{
|
||||||
|
if (_isHighlighted == shouldHighlight)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isHighlighted = shouldHighlight;
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if ([self isContinuous])
|
if ([self isEnabled] && [self isContinuous])
|
||||||
{
|
{
|
||||||
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
|
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
|
||||||
{
|
{
|
||||||
@@ -543,46 +576,12 @@ CPButtonImageOffset = 3.0;
|
|||||||
[_target performSelector:_action withObject:self];
|
[_target performSelector:_action withObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
|
||||||
{
|
|
||||||
_isTracking = YES;
|
|
||||||
|
|
||||||
var startedTracking = [super startTrackingAt:aPoint];
|
|
||||||
|
|
||||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
|
||||||
{
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
[self highlight:[self state] == CPOffState];
|
|
||||||
else
|
|
||||||
[self highlight:YES];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
[self highlight:[self state] != CPOffState];
|
|
||||||
else
|
|
||||||
[self highlight:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
return startedTracking;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||||
{
|
{
|
||||||
_isTracking = NO;
|
|
||||||
|
|
||||||
if (mouseIsUp && CGRectContainsPoint([self bounds], aPoint))
|
if (mouseIsUp && CGRectContainsPoint([self bounds], aPoint))
|
||||||
[self setNextState];
|
[self setNextState];
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
[self highlight:[self state] != CPOffState];
|
|
||||||
else
|
|
||||||
[self highlight:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self highlight:NO];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
[self invalidateTimers];
|
[self invalidateTimers];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,7 +602,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
var contentInset = [self valueForThemeAttribute:@"content-inset" inState:[self _contentVisualState]];
|
||||||
|
|
||||||
return CGRectInsetByInset(bounds, contentInset);
|
return CGRectInsetByInset(bounds, contentInset);
|
||||||
}
|
}
|
||||||
@@ -630,7 +629,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
size = [contentView frameSize];
|
size = [contentView frameSize];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
|
size = [([self title] || " ") sizeWithFont:[self font]];
|
||||||
|
|
||||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
@@ -686,86 +685,164 @@ CPButtonImageOffset = 3.0;
|
|||||||
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPThemeState)_backgroundVisualState
|
||||||
|
{
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state],
|
||||||
|
buttonIsOn = (currentState !== CPOffState);
|
||||||
|
|
||||||
|
if (_isHighlighted && (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask)))
|
||||||
|
visualState = visualState.and(CPThemeStateHighlighted);
|
||||||
|
else
|
||||||
|
visualState = visualState.without(CPThemeStateHighlighted);
|
||||||
|
|
||||||
|
if (buttonIsOn && (_showsStateBy & (CPPushInCellMask | CPChangeGrayCellMask)))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
else
|
||||||
|
visualState = visualState.without(CPThemeStateSelected);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note : We have to split content and image visual states as, for example, radio buttons don't follow push buttons behavior
|
||||||
|
- (CPThemeState)_contentVisualState
|
||||||
|
{
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state],
|
||||||
|
buttonIsOn = (currentState !== CPOffState);
|
||||||
|
|
||||||
|
// If the button is pushed (_isHighlighted), always add the highlighted state
|
||||||
|
if (_isHighlighted || (((_showsStateBy & CPChangeGrayCellMask) || (_showsStateBy & CPChangeBackgroundCellMask)) && buttonIsOn))
|
||||||
|
visualState = visualState.and(CPThemeStateHighlighted);
|
||||||
|
else
|
||||||
|
visualState = visualState.without(CPThemeStateHighlighted);
|
||||||
|
|
||||||
|
if (buttonIsOn && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
else
|
||||||
|
visualState = visualState.without(CPThemeStateSelected);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPThemeState)_imageVisualState
|
||||||
|
{
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state],
|
||||||
|
buttonIsOn = (currentState !== CPOffState);
|
||||||
|
|
||||||
|
// Remove highlighted & selected theme states
|
||||||
|
visualState = visualState.without(CPThemeStateHighlighted);
|
||||||
|
visualState = visualState.without(CPThemeStateSelected);
|
||||||
|
|
||||||
|
// Note : We have to deal with special case where button is ON, highlightsBy and showsStateBy use content, and button is pushed
|
||||||
|
// BUT this should not be used for disclosure buttons !
|
||||||
|
if (_isHighlighted && buttonIsOn && (_highlightsBy & CPContentsCellMask) && (_showsStateBy & CPContentsCellMask) && (_bezelStyle !== CPDisclosureBezelStyle))
|
||||||
|
return visualState;
|
||||||
|
|
||||||
|
if (_isHighlighted && ((_highlightsBy & CPContentsCellMask) || (_highlightsBy & CPChangeGrayCellMask)))
|
||||||
|
visualState = visualState.and(CPThemeStateHighlighted);
|
||||||
|
|
||||||
|
if (buttonIsOn && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_currentTitle
|
||||||
|
{
|
||||||
|
var buttonIsOn = ([self state] !== CPOffState);
|
||||||
|
|
||||||
|
// Note : We have to deal with special case where button is ON, highlightsBy and showsStateBy use content, and button is pushed
|
||||||
|
if (_isHighlighted && buttonIsOn && (_highlightsBy & CPContentsCellMask) && (_showsStateBy & CPContentsCellMask))
|
||||||
|
return _title;
|
||||||
|
|
||||||
|
else if (_alternateTitle && ((_isHighlighted && (_highlightsBy & CPContentsCellMask)) || (buttonIsOn && (_showsStateBy & CPContentsCellMask))))
|
||||||
|
return _alternateTitle;
|
||||||
|
|
||||||
|
else
|
||||||
|
return _title;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)_currentImage
|
||||||
|
{
|
||||||
|
var visualState = [self _imageVisualState],
|
||||||
|
currentImage = [self valueForThemeAttribute:@"image" inState:visualState],
|
||||||
|
imageColor = [self valueForThemeAttribute:@"image-color" inState:visualState],
|
||||||
|
buttonIsOn = ([self state] !== CPOffState);
|
||||||
|
|
||||||
|
if ([currentImage isMaterialIconImage])
|
||||||
|
{
|
||||||
|
if (([self valueForThemeAttribute:@"invert-image" inState:visualState] || ([self valueForThemeAttribute:@"invert-image-on-push" inState:visualState] && (_isHighlighted || (((_showsStateBy & CPChangeGrayCellMask) || (_showsStateBy & CPChangeBackgroundCellMask)) && buttonIsOn)))))
|
||||||
|
currentImage = [currentImage invertedImage];
|
||||||
|
|
||||||
|
else if (imageColor && [imageColor isKindOfClass:CPColor])
|
||||||
|
// In some buttons, image color doesn't follow text color !
|
||||||
|
currentImage = [currentImage imageVersionWithColor:imageColor];
|
||||||
|
|
||||||
|
else
|
||||||
|
// By default, image color follows text color
|
||||||
|
currentImage = [currentImage imageVersionWithColor:[self valueForThemeAttribute:@"text-color" inState:[self _contentVisualState]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentImage;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
relativeToEphemeralSubviewNamed:@"content-view"],
|
||||||
|
|
||||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||||
|
|
||||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
|
||||||
positioned:CPWindowAbove
|
positioned:CPWindowAbove
|
||||||
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
relativeToEphemeralSubviewNamed:@"bezel-view"],
|
||||||
|
|
||||||
if (contentView)
|
image = [self _currentImage],
|
||||||
{
|
contentVisualState = [self _contentVisualState];
|
||||||
var title = nil,
|
|
||||||
image = nil;
|
|
||||||
|
|
||||||
if (_isTracking)
|
[bezelView setBackgroundColor:[self valueForThemeAttribute:@"bezel-color" inState:[self _backgroundVisualState]]];
|
||||||
{
|
[contentView setText:[self _currentTitle]];
|
||||||
if (_highlightsBy & CPContentsCellMask)
|
[contentView setImage:image];
|
||||||
{
|
|
||||||
if (_showsStateBy & CPContentsCellMask)
|
|
||||||
{
|
|
||||||
title = ([self state] == CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
|
||||||
image = ([self state] == CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
title = [self alternateTitle];
|
|
||||||
image = [self alternateImage];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_showsStateBy & CPContentsCellMask)
|
|
||||||
{
|
|
||||||
title = ([self state] != CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
|
||||||
image = ([self state] != CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
title = _title;
|
|
||||||
image = [self image];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_showsStateBy & CPContentsCellMask)
|
|
||||||
{
|
|
||||||
title = ([self state] != CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
|
||||||
image = ([self state] != CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
title = _title;
|
|
||||||
image = [self image];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[contentView setText:title];
|
[contentView setImageOffset:[self valueForThemeAttribute:@"image-offset" inState:contentVisualState]];
|
||||||
[contentView setImage:image];
|
[contentView setImageVerticalOffset:[self valueForThemeAttribute:@"image-vertical-offset" inState:contentVisualState]];
|
||||||
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
|
|
||||||
|
|
||||||
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
[contentView setFont:[self font]];
|
||||||
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:contentVisualState]];
|
||||||
[contentView setAlignment:[self currentValueForThemeAttribute:@"alignment"]];
|
[contentView setAlignment:[self valueForThemeAttribute:@"alignment" inState:contentVisualState]];
|
||||||
[contentView setVerticalAlignment:[self currentValueForThemeAttribute:@"vertical-alignment"]];
|
[contentView setVerticalAlignment:[self valueForThemeAttribute:@"vertical-alignment" inState:contentVisualState]];
|
||||||
[contentView setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
|
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:contentVisualState]];
|
||||||
[contentView setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
[contentView _setUsesSingleLineMode:YES];
|
||||||
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:contentVisualState]];
|
||||||
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
|
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:contentVisualState]];
|
||||||
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
|
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position"]];
|
||||||
[contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
|
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling"]];
|
||||||
}
|
|
||||||
|
// We don't automatically dim material icon images as the color is driven by the theme
|
||||||
|
[contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled && ![image isMaterialIconImage]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBordered:(BOOL)shouldBeBordered
|
- (void)setBordered:(BOOL)shouldBeBordered
|
||||||
{
|
{
|
||||||
if (shouldBeBordered)
|
if (shouldBeBordered)
|
||||||
|
{
|
||||||
[self setThemeState:CPThemeStateBordered];
|
[self setThemeState:CPThemeStateBordered];
|
||||||
|
|
||||||
|
if (_bezelState)
|
||||||
|
_bezelState = _bezelState.and(CPThemeStateBordered);
|
||||||
|
else
|
||||||
|
_bezelState = CPThemeStateBordered;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
[self unsetThemeState:CPThemeStateBordered];
|
[self unsetThemeState:CPThemeStateBordered];
|
||||||
|
|
||||||
|
if (_bezelState)
|
||||||
|
_bezelState = _bezelState.without(CPThemeStateBordered);
|
||||||
|
else
|
||||||
|
_bezelState = CPThemeStateNormal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isBordered
|
- (BOOL)isBordered
|
||||||
@@ -795,7 +872,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
{
|
{
|
||||||
var selfWindow = [self window];
|
var selfWindow = [self window];
|
||||||
|
|
||||||
if (selfWindow === aWindow || aWindow === nil)
|
if (selfWindow === aWindow || aWindow == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([selfWindow defaultButton] === self)
|
if ([selfWindow defaultButton] === self)
|
||||||
@@ -861,17 +938,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
[self setState:[self nextState]];
|
[self setState:[self nextState]];
|
||||||
|
|
||||||
var shouldHighlight = NO;
|
[self highlight:YES];
|
||||||
|
|
||||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
|
||||||
{
|
|
||||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
|
||||||
shouldHighlight = [self state] == CPOffState;
|
|
||||||
else
|
|
||||||
shouldHighlight = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self highlight:shouldHighlight];
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -883,8 +950,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (shouldHighlight)
|
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,6 +973,22 @@ CPButtonImageOffset = 3.0;
|
|||||||
[self setThemeState:newState];
|
[self setThemeState:newState];
|
||||||
|
|
||||||
_bezelStyle = aBezelStyle;
|
_bezelStyle = aBezelStyle;
|
||||||
|
|
||||||
|
if (_bezelState && newState)
|
||||||
|
{
|
||||||
|
if (currentState)
|
||||||
|
_bezelState =_bezelState.without(currentState);
|
||||||
|
_bezelState = _bezelState.and(newState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_bezelState = newState || CPThemeStateNormal;
|
||||||
|
|
||||||
|
// For disclosure triangle and rounded, we have to move away from
|
||||||
|
// what Xcode tells us as we implement visual behavior with images (so content)
|
||||||
|
// and not background
|
||||||
|
|
||||||
|
if ((_bezelStyle === CPDisclosureBezelStyle) || (_bezelStyle === CPRoundedDisclosureBezelStyle))
|
||||||
|
[self setShowsStateBy:CPContentsCellMask];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned)bezelStyle
|
- (unsigned)bezelStyle
|
||||||
@@ -930,7 +1012,8 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
|
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
|
||||||
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey",
|
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey",
|
||||||
CPButtonHighlightsByKey = @"CPButtonHighlightsByKey",
|
CPButtonHighlightsByKey = @"CPButtonHighlightsByKey",
|
||||||
CPButtonShowsStateByKey = @"CPButtonShowsStateByKey";
|
CPButtonShowsStateByKey = @"CPButtonShowsStateByKey",
|
||||||
|
CPButtonBezelStyleKey = @"CPButtonBezelStyleKey";
|
||||||
|
|
||||||
@implementation CPButton (CPCoding)
|
@implementation CPButton (CPCoding)
|
||||||
|
|
||||||
@@ -979,6 +1062,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
|
|
||||||
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
||||||
|
|
||||||
|
if ([aCoder containsValueForKey:CPButtonIsBorderedKey])
|
||||||
|
[self setBordered:[aCoder decodeBoolForKey:CPButtonIsBorderedKey]];
|
||||||
|
|
||||||
|
if ([aCoder containsValueForKey:CPButtonBezelStyleKey])
|
||||||
|
[self setBezelStyle:[aCoder decodeIntForKey:CPButtonBezelStyleKey]];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
@@ -1013,6 +1102,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
|
|
||||||
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
|
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
|
||||||
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
|
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
|
||||||
|
|
||||||
|
[aCoder encodeBool:[self isBordered] forKey:CPButtonIsBorderedKey];
|
||||||
|
[aCoder encodeInt: [self bezelStyle] forKey:CPButtonBezelStyleKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+41
-11
@@ -26,7 +26,10 @@
|
|||||||
@class CPSplitView
|
@class CPSplitView
|
||||||
|
|
||||||
@global CPPopUpButtonStatePullsDown
|
@global CPPopUpButtonStatePullsDown
|
||||||
|
@global CPKeyValueChangeOldKey
|
||||||
|
@global CPKeyValueChangeNewKey
|
||||||
|
@global CPKeyValueObservingOptionNew
|
||||||
|
@global CPKeyValueObservingOptionOld
|
||||||
|
|
||||||
@implementation CPButtonBar : CPView
|
@implementation CPButtonBar : CPView
|
||||||
{
|
{
|
||||||
@@ -67,7 +70,7 @@
|
|||||||
[button addItemWithTitle:nil];
|
[button addItemWithTitle:nil];
|
||||||
[[button lastItem] setImage:image];
|
[[button lastItem] setImage:image];
|
||||||
[button setImagePosition:CPImageOnly];
|
[button setImagePosition:CPImageOnly];
|
||||||
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset"];
|
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset" inState:CPPopUpButtonStatePullsDown];
|
||||||
|
|
||||||
[button setPullsDown:YES];
|
[button setPullsDown:YES];
|
||||||
|
|
||||||
@@ -109,6 +112,8 @@
|
|||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
|
[super awakeFromCib];
|
||||||
|
|
||||||
var view = [self superview],
|
var view = [self superview],
|
||||||
subview = self;
|
subview = self;
|
||||||
|
|
||||||
@@ -129,10 +134,20 @@
|
|||||||
|
|
||||||
- (void)setButtons:(CPArray)buttons
|
- (void)setButtons:(CPArray)buttons
|
||||||
{
|
{
|
||||||
|
for (var i = [_buttons count] - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
[_buttons[i] removeFromSuperview];
|
||||||
|
[_buttons[i] removeObserver:self forKeyPath:@"hidden"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_buttons = [CPArray arrayWithArray:buttons];
|
_buttons = [CPArray arrayWithArray:buttons];
|
||||||
|
|
||||||
for (var i = 0, count = [_buttons count]; i < count; i++)
|
for (var i = [_buttons count] - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
[_buttons[i] addObserver:self forKeyPath:@"hidden" options:CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld context:nil];
|
||||||
[_buttons[i] setBordered:YES];
|
[_buttons[i] setBordered:YES];
|
||||||
|
}
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -218,8 +233,15 @@
|
|||||||
count = [buttonsNotHidden count];
|
count = [buttonsNotHidden count];
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
if ([buttonsNotHidden[count] isHidden])
|
{
|
||||||
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
var button = buttonsNotHidden[count];
|
||||||
|
|
||||||
|
if ([button isHidden])
|
||||||
|
{
|
||||||
|
[button removeFromSuperview];
|
||||||
|
[buttonsNotHidden removeObject:button];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||||
bounds = [self bounds],
|
bounds = [self bounds],
|
||||||
@@ -250,15 +272,15 @@
|
|||||||
currentButtonOffset += width - 1;
|
currentButtonOffset += width - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
|
[button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered]];
|
||||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
|
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, ]];
|
||||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
|
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered]];
|
||||||
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
|
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
|
||||||
|
|
||||||
// FIXME shouldn't need this
|
// FIXME shouldn't need this
|
||||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
[button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||||
|
|
||||||
[self addSubview:button];
|
[self addSubview:button];
|
||||||
}
|
}
|
||||||
@@ -274,6 +296,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)keyPath ofObject:(id)object change:(CPDictionary)change context:(id)context
|
||||||
|
{
|
||||||
|
if ([change objectForKey:CPKeyValueChangeOldKey] == [change objectForKey:CPKeyValueChangeNewKey])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setFrameSize:(CGSize)aSize
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[super setFrameSize:aSize];
|
[super setFrameSize:aSize];
|
||||||
|
|||||||
+62
-8
@@ -94,21 +94,58 @@ CPCheckBoxImageOffset = 4.0;
|
|||||||
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
|
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)image
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override methods from CPButton
|
||||||
|
|
||||||
|
- (CGSize)_minimumFrameSize
|
||||||
{
|
{
|
||||||
return [self currentValueForThemeAttribute:@"image"];
|
var size = [super _minimumFrameSize],
|
||||||
|
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||||
|
|
||||||
|
if (!contentView && [[self title] length])
|
||||||
|
{
|
||||||
|
var minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
|
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||||
|
|
||||||
|
// Here we always add the min size to the control which is the size of the view of the checkBox
|
||||||
|
size.width += minSize.width + CPCheckBoxImageOffset;
|
||||||
|
|
||||||
|
if (maxSize.width >= 0.0)
|
||||||
|
size.width = MIN(size.width, maxSize.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)alternateImage
|
- (CPThemeState)_contentVisualState
|
||||||
{
|
{
|
||||||
return [self currentValueForThemeAttribute:@"image"];
|
// Note : Behavior differs from CPButton as title doesn't follow the highlightsBy content flag
|
||||||
|
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state];
|
||||||
|
|
||||||
|
if ((currentState !== CPOffState) && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
- (CPThemeState)_imageVisualState
|
||||||
{
|
{
|
||||||
var startedTracking = [super startTrackingAt:aPoint];
|
// Note : Behavior differs from CPButton as we don't force "not selected" theme state
|
||||||
[self highlight:YES];
|
// when button is highglighted and selected
|
||||||
return startedTracking;
|
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state];
|
||||||
|
|
||||||
|
if (_isHighlighted && (_highlightsBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and(CPThemeStateHighlighted);
|
||||||
|
|
||||||
|
if ((currentState !== CPOffState) && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -139,3 +176,20 @@ CPCheckBoxImageOffset = 4.0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPCheckBox (TableDataView)
|
||||||
|
|
||||||
|
// We overide here _CPObject+Theme setValue:forThemeAttribute as CPCheckBox can be used as tableView data view
|
||||||
|
// So, when outside a table data view, setValue:forThemeAttribute should store the value with the CPThemeStateNormal (default behavior)
|
||||||
|
// When inside a table data view, it should store the value with the CPThemeStateTableDataView. If not, the value won't be used if the
|
||||||
|
// theme defined a value for this attribute for state CPThemeStateTableDataView
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName
|
||||||
|
{
|
||||||
|
[super setValue:aValue forThemeAttribute:aName];
|
||||||
|
[super setValue:aValue forThemeAttribute:aName inState:CPThemeStateTableDataView];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+5
-38
@@ -46,49 +46,12 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (_documentView)
|
if (_documentView)
|
||||||
{
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
|
||||||
|
|
||||||
[defaultCenter
|
|
||||||
removeObserver:self
|
|
||||||
name:CPViewFrameDidChangeNotification
|
|
||||||
object:_documentView];
|
|
||||||
|
|
||||||
[defaultCenter
|
|
||||||
removeObserver:self
|
|
||||||
name:CPViewBoundsDidChangeNotification
|
|
||||||
object:_documentView];
|
|
||||||
|
|
||||||
[_documentView removeFromSuperview];
|
[_documentView removeFromSuperview];
|
||||||
}
|
|
||||||
|
|
||||||
_documentView = aView;
|
_documentView = aView;
|
||||||
|
|
||||||
if (_documentView)
|
if (_documentView)
|
||||||
{
|
|
||||||
[self addSubview:_documentView];
|
[self addSubview:_documentView];
|
||||||
[self _observeDocumentView];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_observeDocumentView
|
|
||||||
{
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
|
||||||
|
|
||||||
[_documentView setPostsFrameChangedNotifications:YES];
|
|
||||||
[_documentView setPostsBoundsChangedNotifications:YES];
|
|
||||||
|
|
||||||
[defaultCenter
|
|
||||||
addObserver:self
|
|
||||||
selector:@selector(viewFrameChanged:)
|
|
||||||
name:CPViewFrameDidChangeNotification
|
|
||||||
object:_documentView];
|
|
||||||
|
|
||||||
[defaultCenter
|
|
||||||
addObserver:self
|
|
||||||
selector:@selector(viewBoundsChanged:)
|
|
||||||
name:CPViewBoundsDidChangeNotification
|
|
||||||
object:_documentView];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -230,6 +193,11 @@
|
|||||||
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGRect)documentVisibleRect
|
||||||
|
{
|
||||||
|
return [_documentView visibleRect];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@@ -244,7 +212,6 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
|||||||
// Don't call setDocumentView: here. It calls addSubview:, but it's A) not necessary since the
|
// Don't call setDocumentView: here. It calls addSubview:, but it's A) not necessary since the
|
||||||
// view hierarchy is fully encoded and B) dangerous if the subview is not fully decoded.
|
// view hierarchy is fully encoded and B) dangerous if the subview is not fully decoded.
|
||||||
_documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
|
_documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
|
||||||
[self _observeDocumentView];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
+304
-107
@@ -31,6 +31,37 @@
|
|||||||
@import "CPDragServer_Constants.j"
|
@import "CPDragServer_Constants.j"
|
||||||
@import "CPPasteboard.j"
|
@import "CPPasteboard.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
|
@class _CPCollectionViewDropIndicator
|
||||||
|
|
||||||
|
var CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_ = 1 << 0,
|
||||||
|
CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_ = 1 << 1,
|
||||||
|
CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_ = 1 << 2,
|
||||||
|
CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_ = 1 << 3,
|
||||||
|
CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_ = 1 << 4,
|
||||||
|
CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_ = 1 << 5,
|
||||||
|
CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_ = 1 << 6,
|
||||||
|
CPCollectionViewDelegate_collectionView_menuForItemAtIndex_ = 1 << 7,
|
||||||
|
CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset = 1 << 8;
|
||||||
|
|
||||||
|
|
||||||
|
@protocol CPCollectionViewDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)collectionView:(CPCollectionView)collectionView acceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation;
|
||||||
|
- (BOOL)collectionView:(CPCollectionView)collectionView canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event;
|
||||||
|
- (BOOL)collectionView:(CPCollectionView)collectionView writeItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard;
|
||||||
|
- (CPArray)collectionView:(CPCollectionView)collectionView dragTypesForItemsAtIndexes:(CPIndexSet)indexes;
|
||||||
|
- (CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
|
||||||
|
- (CPDragOperation)collectionView:(CPCollectionView)collectionView validateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation;
|
||||||
|
- (CPMenu)collectionView:(CPCollectionView)collectionView menuForItemAtIndex:(CPInteger)anIndex;
|
||||||
|
- (CPView)collectionView:(CPCollectionView)collectionView draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||||
|
- (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var HORIZONTAL_MARGIN = 2;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -42,10 +73,6 @@
|
|||||||
|
|
||||||
@par Delegate Methods
|
@par Delegate Methods
|
||||||
|
|
||||||
@delegate - (void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
|
||||||
DEPRECATED: Please do not use.
|
|
||||||
@param collectionView the collection view who's selection changed
|
|
||||||
|
|
||||||
@delegate - (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
@delegate - (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||||
Called when the user double-clicks on an item in the collection view.
|
Called when the user double-clicks on an item in the collection view.
|
||||||
@param collectionView the collection view that received the double-click
|
@param collectionView the collection view that received the double-click
|
||||||
@@ -64,56 +91,61 @@
|
|||||||
@param indices the indices to obtain drag types
|
@param indices the indices to obtain drag types
|
||||||
@return an array of drag types (CPString)
|
@return an array of drag types (CPString)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var HORIZONTAL_MARGIN = 2;
|
|
||||||
|
|
||||||
@implementation CPCollectionView : CPView
|
@implementation CPCollectionView : CPView
|
||||||
{
|
{
|
||||||
CPArray _content;
|
CPArray _content;
|
||||||
CPArray _items;
|
CPArray _items;
|
||||||
|
|
||||||
CPData _itemData;
|
CPData _itemData;
|
||||||
CPCollectionViewItem _itemPrototype;
|
CPCollectionViewItem _itemPrototype;
|
||||||
CPCollectionViewItem _itemForDragging;
|
CPCollectionViewItem _itemForDragging;
|
||||||
CPMutableArray _cachedItems;
|
CPMutableArray _cachedItems;
|
||||||
|
|
||||||
unsigned _maxNumberOfRows;
|
unsigned _maxNumberOfRows;
|
||||||
unsigned _maxNumberOfColumns;
|
unsigned _maxNumberOfColumns;
|
||||||
|
|
||||||
CGSize _minItemSize;
|
CGSize _minItemSize;
|
||||||
CGSize _maxItemSize;
|
CGSize _maxItemSize;
|
||||||
|
|
||||||
CPArray _backgroundColors;
|
CPArray _backgroundColors;
|
||||||
|
|
||||||
float _tileWidth;
|
float _tileWidth;
|
||||||
|
|
||||||
BOOL _isSelectable;
|
BOOL _isSelectable;
|
||||||
BOOL _allowsMultipleSelection;
|
BOOL _allowsMultipleSelection;
|
||||||
BOOL _allowsEmptySelection;
|
BOOL _allowsEmptySelection;
|
||||||
CPIndexSet _selectionIndexes;
|
CPIndexSet _selectionIndexes;
|
||||||
|
|
||||||
CGSize _itemSize;
|
CGSize _itemSize;
|
||||||
|
|
||||||
float _horizontalMargin;
|
float _horizontalMargin;
|
||||||
float _verticalMargin;
|
float _verticalMargin;
|
||||||
|
|
||||||
unsigned _numberOfRows;
|
unsigned _numberOfRows;
|
||||||
unsigned _numberOfColumns;
|
unsigned _numberOfColumns;
|
||||||
|
|
||||||
id _delegate;
|
id <CPCollectionViewDelegate> _delegate;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
CPEvent _mouseDownEvent;
|
CPEvent _mouseDownEvent;
|
||||||
|
|
||||||
BOOL _needsMinMaxItemSizeUpdate;
|
BOOL _needsMinMaxItemSizeUpdate;
|
||||||
CGSize _storedFrameSize;
|
CGSize _storedFrameSize;
|
||||||
|
|
||||||
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
|
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
|
||||||
BOOL _lockResizing;
|
|
||||||
|
|
||||||
CPInteger _currentDropIndex;
|
CPInteger _currentDropIndex;
|
||||||
CPDragOperation _currentDragOperation;
|
CPDragOperation _currentDragOperation;
|
||||||
|
|
||||||
_CPCollectionViewDropIndicator _dropView;
|
_CPCollectionViewDropIndicator _dropView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding == CPContentBinding)
|
||||||
|
return [_CPCollectionViewContentBinder class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -158,7 +190,7 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
|
|
||||||
_needsMinMaxItemSizeUpdate = YES;
|
_needsMinMaxItemSizeUpdate = YES;
|
||||||
_uniformSubviewsResizing = NO;
|
_uniformSubviewsResizing = NO;
|
||||||
_lockResizing = NO;
|
_inLiveResize = NO;
|
||||||
|
|
||||||
_currentDropIndex = -1;
|
_currentDropIndex = -1;
|
||||||
_currentDragOperation = CPDragOperationNone;
|
_currentDragOperation = CPDragOperationNone;
|
||||||
@@ -168,6 +200,51 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
[self setAutoresizingMask:0];
|
[self setAutoresizingMask:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Delegate
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the delegate of the receiver
|
||||||
|
@param aDelegate the delegate object for the collectionView.
|
||||||
|
*/
|
||||||
|
- (void)setDelegate:(id <CPCollectionViewDelegate>)aDelegate
|
||||||
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:acceptDrop:index:dropOperation:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:writeItemsAtIndexes:toPasteboard:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:dataForItemsAtIndexes:forType:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_menuForItemAtIndex_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
|
||||||
|
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the item prototype to \c anItem
|
Sets the item prototype to \c anItem
|
||||||
@param anItem the new item prototype.
|
@param anItem the new item prototype.
|
||||||
@@ -315,14 +392,7 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
_isSelectable = isSelectable;
|
_isSelectable = isSelectable;
|
||||||
|
|
||||||
if (!_isSelectable)
|
if (!_isSelectable)
|
||||||
{
|
[self _applySelectionToItems:NO];
|
||||||
var index = CPNotFound,
|
|
||||||
itemCount = [_items count];
|
|
||||||
|
|
||||||
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
|
|
||||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < itemCount)
|
|
||||||
[_items[index] setSelected:NO];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -376,31 +446,18 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
{
|
{
|
||||||
if (!anIndexSet)
|
if (!anIndexSet)
|
||||||
anIndexSet = [CPIndexSet indexSet];
|
anIndexSet = [CPIndexSet indexSet];
|
||||||
|
|
||||||
if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
|
if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var index = CPNotFound,
|
[self _applySelectionToItems:NO];
|
||||||
itemCount = [_items count];
|
|
||||||
|
|
||||||
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
|
|
||||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound && index < itemCount)
|
|
||||||
[_items[index] setSelected:NO];
|
|
||||||
|
|
||||||
_selectionIndexes = anIndexSet;
|
_selectionIndexes = anIndexSet;
|
||||||
|
|
||||||
var index = CPNotFound;
|
[self _applySelectionToItems:YES];
|
||||||
|
|
||||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
|
|
||||||
[_items[index] setSelected:YES];
|
|
||||||
|
|
||||||
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
|
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
|
||||||
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
|
||||||
{
|
|
||||||
CPLog.warn("The delegate method collectionViewDidChangeSelection: is deprecated and will be removed in a future version, please bind to selectionIndexes instead.");
|
|
||||||
[_delegate collectionViewDidChangeSelection:self];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -462,14 +519,14 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
|
|
||||||
- (void)resizeWithOldSuperviewSize:(CGSize)oldBoundsSize
|
- (void)resizeWithOldSuperviewSize:(CGSize)oldBoundsSize
|
||||||
{
|
{
|
||||||
if (_lockResizing)
|
if (_inLiveResize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_lockResizing = YES;
|
_inLiveResize = YES;
|
||||||
|
|
||||||
[self tile];
|
[self tile];
|
||||||
|
|
||||||
_lockResizing = NO;
|
_inLiveResize = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tile
|
- (void)tile
|
||||||
@@ -545,7 +602,7 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
|
|
||||||
height = MAX(height, numberOfRows * (_minItemSize.height + _verticalMargin));
|
height = MAX(height, numberOfRows * (_minItemSize.height + _verticalMargin));
|
||||||
|
|
||||||
var itemSizeHeight = FLOOR(height / numberOfRows);
|
var itemSizeHeight = FLOOR(height / numberOfRows) - _verticalMargin;
|
||||||
|
|
||||||
if (maxItemSizeHeight > 0)
|
if (maxItemSizeHeight > 0)
|
||||||
itemSizeHeight = MIN(itemSizeHeight, maxItemSizeHeight);
|
itemSizeHeight = MIN(itemSizeHeight, maxItemSizeHeight);
|
||||||
@@ -682,7 +739,7 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setMinItemSize:(CGSize)aSize
|
- (void)setMinItemSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
if (aSize === nil || aSize === undefined)
|
if (aSize == nil)
|
||||||
[CPException raise:CPInvalidArgumentException reason:"Invalid value provided for minimum size"];
|
[CPException raise:CPInvalidArgumentException reason:"Invalid value provided for minimum size"];
|
||||||
|
|
||||||
if (CGSizeEqualToSize(_minItemSize, aSize))
|
if (CGSizeEqualToSize(_minItemSize, aSize))
|
||||||
@@ -755,8 +812,8 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
if ([_selectionIndexes count] && [anEvent clickCount] == 2)
|
||||||
[_delegate collectionView:self didDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
|
[self _sendDelegateDidDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
@@ -846,15 +903,6 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
return _verticalMargin;
|
return _verticalMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the collection view's delegate
|
|
||||||
@param aDelegate the new delegate
|
|
||||||
*/
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
|
||||||
{
|
|
||||||
_delegate = aDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the collection view's delegate
|
Returns the collection view's delegate
|
||||||
*/
|
*/
|
||||||
@@ -868,13 +916,13 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPMenu)menuForEvent:(CPEvent)theEvent
|
- (CPMenu)menuForEvent:(CPEvent)theEvent
|
||||||
{
|
{
|
||||||
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
|
if (![self _delegateRespondsToCollectionViewMenuForItemAtIndex])
|
||||||
return [super menuForEvent:theEvent];
|
return [super menuForEvent:theEvent];
|
||||||
|
|
||||||
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||||
index = [self _indexAtPoint:location];
|
index = [self _indexAtPoint:location];
|
||||||
|
|
||||||
return [_delegate collectionView:self menuForItemAtIndex:index];
|
return [self _sendDelegateMenuForItemAtIndex:index];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)_indexAtPoint:(CGPoint)thePoint
|
- (int)_indexAtPoint:(CGPoint)thePoint
|
||||||
@@ -918,6 +966,20 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_applySelectionToItems:(BOOL)select
|
||||||
|
{
|
||||||
|
var numberOfItems = [_items count];
|
||||||
|
|
||||||
|
[_selectionIndexes enumerateIndexesUsingBlock:function(idx, stop)
|
||||||
|
{
|
||||||
|
if (idx < numberOfItems)
|
||||||
|
[[_items objectAtIndex:idx] setSelected:select];
|
||||||
|
else {
|
||||||
|
stop(YES);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPCollectionView (DragAndDrop)
|
@implementation CPCollectionView (DragAndDrop)
|
||||||
@@ -932,7 +994,7 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||||
{
|
{
|
||||||
[aPasteboard setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
[aPasteboard setData:[self _sendDelegateDataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_createDropIndicatorIfNeeded
|
- (void)_createDropIndicatorIfNeeded
|
||||||
@@ -962,24 +1024,23 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
if (![self _delegateRespondsToCollectionViewDragTypesForItemsAtIndexes])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
|
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
|
||||||
if (![_selectionIndexes count])
|
if (![_selectionIndexes count])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
if (![self _sendDelegateCanDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||||
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set up the pasteboard
|
// Set up the pasteboard
|
||||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
var dragTypes = [self _sendDelegateDragTypesForItemsAtIndexes:_selectionIndexes];
|
||||||
|
|
||||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||||
|
|
||||||
var dragImageOffset = CGSizeMakeZero(),
|
var dragImageOffset = CGSizeMakeZero(),
|
||||||
view = [self _draggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
|
view = [self _sendDelegateDraggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
|
||||||
|
|
||||||
[view setFrameSize:_itemSize];
|
[view setFrameSize:_itemSize];
|
||||||
[view setAlphaValue:0.7];
|
[view setAlphaValue:0.7];
|
||||||
@@ -996,14 +1057,6 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
slideBack:YES];
|
slideBack:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)_draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)offset
|
|
||||||
{
|
|
||||||
if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
|
|
||||||
return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
|
||||||
|
|
||||||
return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset
|
- (CPView)draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset
|
||||||
{
|
{
|
||||||
var idx = _content[[indexes firstIndex]];
|
var idx = _content[[indexes firstIndex]];
|
||||||
@@ -1016,14 +1069,6 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
return [_itemForDragging view];
|
return [_itemForDragging view];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
|
|
||||||
{
|
|
||||||
if ([self respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
|
|
||||||
return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPDragOperation)draggingEntered:(id)draggingInfo
|
- (CPDragOperation)draggingEntered:(id)draggingInfo
|
||||||
{
|
{
|
||||||
var dropIndex = -1,
|
var dropIndex = -1,
|
||||||
@@ -1061,16 +1106,14 @@ var HORIZONTAL_MARGIN = 2;
|
|||||||
var result = CPDragOperationMove,
|
var result = CPDragOperationMove,
|
||||||
dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:dropOperation];
|
dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:dropOperation];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
|
if ([self _delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation])
|
||||||
{
|
{
|
||||||
var dropIndexRef2 = @ref(dropIndex);
|
var dropIndexRef2 = @ref(dropIndex);
|
||||||
|
|
||||||
result = [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
|
result = [self _sendDelegateValidateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
|
||||||
|
|
||||||
if (result !== CPDragOperationNone)
|
if (result !== CPDragOperationNone)
|
||||||
{
|
|
||||||
dropIndex = dropIndexRef2();
|
dropIndex = dropIndexRef2();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dropIndexRef(dropIndex);
|
dropIndexRef(dropIndex);
|
||||||
@@ -1104,7 +1147,7 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
|||||||
var result = NO;
|
var result = NO;
|
||||||
|
|
||||||
if (_currentDragOperation && _currentDropIndex !== -1)
|
if (_currentDragOperation && _currentDropIndex !== -1)
|
||||||
result = [_delegate collectionView:self acceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
|
result = [self _sendDelegateAcceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
|
||||||
|
|
||||||
[self draggingEnded:draggingInfo]; // Is this correct ?
|
[self draggingEnded:draggingInfo]; // Is this correct ?
|
||||||
|
|
||||||
@@ -1329,6 +1372,7 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation CPCollectionView (Deprecated)
|
@implementation CPCollectionView (Deprecated)
|
||||||
|
|
||||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||||
@@ -1349,6 +1393,148 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPCollectionView (CPCollectionViewDelegate)
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
Return YES if the delegate implements collectionView:validateDrop:proposedIndex:dropOperation:
|
||||||
|
*/
|
||||||
|
- (BOOL)_delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation
|
||||||
|
{
|
||||||
|
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
Return YES if the delegate implements collectionView:menuForItemAtIndex:
|
||||||
|
*/
|
||||||
|
- (BOOL)_delegateRespondsToCollectionViewMenuForItemAtIndex
|
||||||
|
{
|
||||||
|
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
Return YES if the delegate implements collectionView:dragTypesForItemsAtIndexes:
|
||||||
|
*/
|
||||||
|
- (BOOL)_delegateRespondsToCollectionViewDragTypesForItemsAtIndexes
|
||||||
|
{
|
||||||
|
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:acceptDrop:index:dropOperation:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateAcceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self acceptDrop:draggingInfo index:index dropOperation:dropOperation];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:canDragItemsAtIndexes:withEvent:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateCanDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_))
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:writeItemsAtIndexes:toPasteboard:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateWriteItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self writeItemsAtIndexes:indexes toPasteboard:pasteboard];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:dragTypesForItemsAtIndexes:
|
||||||
|
*/
|
||||||
|
- (CPArray)_sendDelegateDragTypesForItemsAtIndexes:(CPIndexSet)indexes
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return [_delegate collectionView:self dragTypesForItemsAtIndexes:indexes];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:dataForItemsAtIndexes:forType:
|
||||||
|
*/
|
||||||
|
- (CPData)_sendDelegateDataForItemsAtIndexes:(CPIndexSet)indexes forType:(CPString)aType
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self dataForItemsAtIndexes:indexes forType:aType];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:validateDrop:proposedIndex:dropOperation:
|
||||||
|
*/
|
||||||
|
- (CPDragOperation)_sendDelegateValidateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_))
|
||||||
|
return CPDragOperationNone;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:proposedDropIndex dropOperation:proposedDropOperation];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:didDoubleClickOnItemAtIndex:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateDidDoubleClickOnItemAtIndex:(int)index
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self didDoubleClickOnItemAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate collectionView:menuForItemAtIndex:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateMenuForItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [_delegate collectionView:self menuForItemAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate draggingViewForItemsAtIndexes:withEvent:offset:
|
||||||
|
*/
|
||||||
|
- (CPView)_sendDelegateDraggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)dragImageOffset
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset))
|
||||||
|
return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
|
||||||
|
|
||||||
|
return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||||
@@ -1408,3 +1594,14 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation _CPCollectionViewContentBinder : CPBinder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source setContent:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+309
-11
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
@import "CGColor.j"
|
@import "CGColor.j"
|
||||||
|
|
||||||
|
@import "_CPObject+Theme.j"
|
||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
|
|
||||||
@@ -65,7 +66,8 @@ var cachedBlackColor,
|
|||||||
cachedOrangeColor,
|
cachedOrangeColor,
|
||||||
cachedPurpleColor,
|
cachedPurpleColor,
|
||||||
cachedShadowColor,
|
cachedShadowColor,
|
||||||
cachedClearColor;
|
cachedClearColor,
|
||||||
|
cachedThemeColor;
|
||||||
|
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|
||||||
@@ -78,13 +80,37 @@ var cachedBlackColor,
|
|||||||
<p>It also provides some class helper methods that
|
<p>It also provides some class helper methods that
|
||||||
returns instances of commonly used colors.</p>
|
returns instances of commonly used colors.</p>
|
||||||
*/
|
*/
|
||||||
@implementation CPColor : CPObject
|
@implementation CPColor : CPObject <CPTheme>
|
||||||
{
|
{
|
||||||
CPArray _components;
|
CPArray _components;
|
||||||
|
|
||||||
CPImage _patternImage;
|
CPImage _patternImage;
|
||||||
CPString _cssString;
|
CPString _cssString;
|
||||||
}
|
}
|
||||||
|
@global document
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Theming
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return "color";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"alternate-selected-control-color": [CPNull null],
|
||||||
|
@"secondary-selected-control-color": [CPNull null],
|
||||||
|
@"selected-text-background-color": [CPNull null],
|
||||||
|
@"selected-text-inactive-background-color": [CPNull null],
|
||||||
|
@"css-based": NO
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Static methods
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a color in the RGB colorspace, with an alpha value.
|
Creates a color in the RGB colorspace, with an alpha value.
|
||||||
@@ -241,7 +267,7 @@ var cachedBlackColor,
|
|||||||
|
|
||||||
@return an initialized RGB color
|
@return an initialized RGB color
|
||||||
*/
|
*/
|
||||||
+ (CPColor)colorWithHexString:(string)hex
|
+ (CPColor)colorWithHexString:(CPString)hex
|
||||||
{
|
{
|
||||||
var rgba = hexToRGB(hex);
|
var rgba = hexToRGB(hex);
|
||||||
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||||
@@ -436,14 +462,22 @@ var cachedBlackColor,
|
|||||||
return cachedClearColor;
|
return cachedClearColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPColor)_cachedThemeColor
|
||||||
|
{
|
||||||
|
if (!cachedThemeColor)
|
||||||
|
cachedThemeColor = [self colorWithCalibratedWhite:0.0 alpha:0.0];
|
||||||
|
|
||||||
|
return cachedThemeColor;
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPColor)alternateSelectedControlColor
|
+ (CPColor)alternateSelectedControlColor
|
||||||
{
|
{
|
||||||
return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
|
return [[self _cachedThemeColor] valueForThemeAttribute:@"alternate-selected-control-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPColor)secondarySelectedControlColor
|
+ (CPColor)secondarySelectedControlColor
|
||||||
{
|
{
|
||||||
return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
|
return [[self _cachedThemeColor] valueForThemeAttribute:@"secondary-selected-control-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -467,6 +501,16 @@ var cachedBlackColor,
|
|||||||
return [[CPColor alloc] _initWithCSSString: aString];
|
return [[CPColor alloc] _initWithCSSString: aString];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPColor)selectedTextBackgroundColor
|
||||||
|
{
|
||||||
|
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-background-color"] || [CPColor colorWithHexString:"99CCFF"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)_selectedTextBackgroundColorUnfocussed
|
||||||
|
{
|
||||||
|
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-inactive-background-color"] || [CPColor colorWithHexString:"CCCCCC"];
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_initWithCSSString:(CPString)aString
|
- (id)_initWithCSSString:(CPString)aString
|
||||||
{
|
{
|
||||||
@@ -489,6 +533,10 @@ var cachedBlackColor,
|
|||||||
// use it (issue #1413.)
|
// use it (issue #1413.)
|
||||||
[self _initCSSStringFromComponents];
|
[self _initCSSStringFromComponents];
|
||||||
|
|
||||||
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeState = CPThemeStateNormal;
|
||||||
|
[self _loadThemeAttributes];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,6 +550,10 @@ var cachedBlackColor,
|
|||||||
_components = components;
|
_components = components;
|
||||||
|
|
||||||
[self _initCSSStringFromComponents];
|
[self _initCSSStringFromComponents];
|
||||||
|
|
||||||
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeState = CPThemeStateNormal;
|
||||||
|
[self _loadThemeAttributes];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -509,7 +561,11 @@ var cachedBlackColor,
|
|||||||
|
|
||||||
- (void)_initCSSStringFromComponents
|
- (void)_initCSSStringFromComponents
|
||||||
{
|
{
|
||||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
// Fix to avoid a problem when compiling a theme (missing the alpha component as theme compiler doesn't have CSS rgba capability)
|
||||||
|
var hasAlpha = YES;
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||||
|
#endif
|
||||||
|
|
||||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||||
parseInt(_components[0] * 255.0) + ", " +
|
parseInt(_components[0] * 255.0) + ", " +
|
||||||
@@ -528,6 +584,10 @@ var cachedBlackColor,
|
|||||||
_patternImage = anImage;
|
_patternImage = anImage;
|
||||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||||
_components = [0.0, 0.0, 0.0, 1.0];
|
_components = [0.0, 0.0, 0.0, 1.0];
|
||||||
|
|
||||||
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeState = CPThemeStateNormal;
|
||||||
|
[self _loadThemeAttributes];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -744,6 +804,9 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
|||||||
var description = [super description],
|
var description = [super description],
|
||||||
patternImage = [self patternImage];
|
patternImage = [self patternImage];
|
||||||
|
|
||||||
|
if ([self isCSSBased])
|
||||||
|
return description + "\n" + [self cssDictionary]+ "\nBefore:\n" + [self cssBeforeDictionary] + "\nAfter:\n" + [self cssAfterDictionary];
|
||||||
|
|
||||||
if (!patternImage)
|
if (!patternImage)
|
||||||
return description + " " + [self cssString];
|
return description + " " + [self cssString];
|
||||||
|
|
||||||
@@ -813,11 +876,229 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
|||||||
return [CPColor colorWithRed:RAND() green:RAND() blue:RAND() alpha:1.0];
|
return [CPColor colorWithRed:RAND() green:RAND() blue:RAND() alpha:1.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPColor)checkerBoardColor
|
||||||
|
{
|
||||||
|
// Thanks to cocco http://stackoverflow.com/a/18368212/76900.
|
||||||
|
return [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEX////MzMw46qqDAAAAEElEQVQImWNg+M+AFeEQBgB+vw/xfUUZkgAAAABJRU5ErkJggg=="]];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CSS Theming
|
||||||
|
|
||||||
|
// The code below adds support for CSS theming with 100% compatibility with current theming system.
|
||||||
|
// The idea is to extend CPColor (and CPImage) with CSS components and adapt low level UI components to
|
||||||
|
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
|
||||||
|
//
|
||||||
|
// To create a CPColor that uses CSS, simply use the new class method :
|
||||||
|
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||||
|
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
|
||||||
|
// If you don't need them, just use the simplified class method :
|
||||||
|
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
|
||||||
|
//
|
||||||
|
// Example :
|
||||||
|
// buttonCssColor = [CPColor colorWithCSSDictionary:@{
|
||||||
|
// @"background-color": A3ColorBackgroundWhite,
|
||||||
|
// @"border-color": A3ColorActiveBorder,
|
||||||
|
// @"border-style": @"solid",
|
||||||
|
// @"border-width": @"1px",
|
||||||
|
// @"border-radius": @"3px",
|
||||||
|
// @"box-sizing": @"border-box"
|
||||||
|
// }
|
||||||
|
// beforeDictionary:@{
|
||||||
|
// @"background-color": @"rgb(225,225,225)",
|
||||||
|
// @"bottom": @"3px",
|
||||||
|
// @"content": @"''",
|
||||||
|
// @"position": @"absolute",
|
||||||
|
// @"right": @"21px",
|
||||||
|
// @"top": @"3px",
|
||||||
|
// @"width": @"1px"
|
||||||
|
// }
|
||||||
|
// afterDictionary:@{
|
||||||
|
// @"content": @"''",
|
||||||
|
// @"bottom": @"3px",
|
||||||
|
// @"right": @"6px",
|
||||||
|
// @"top": @"1px",
|
||||||
|
// @"position": @"absolute",
|
||||||
|
// @"height": @"14px",
|
||||||
|
// @"width": @"9px",
|
||||||
|
// @"margin": @"2px 0px 2px 0px",
|
||||||
|
// @"background-image": @"url(%%packed.png)",
|
||||||
|
// @"background-position": @"0px -64px",
|
||||||
|
// @"background-repeat": @"no-repeat",
|
||||||
|
// @"background-size": @"100px 400px"
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
|
||||||
|
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
|
||||||
|
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
|
||||||
|
//
|
||||||
|
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
|
||||||
|
// aCssColor = [CPColor colorWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
|
||||||
|
//
|
||||||
|
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
|
||||||
|
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
|
||||||
|
//
|
||||||
|
// Remark : +(void)restorePreviousCSSState and -(DOMElement)applyCSSColorForView are meant to be used by low level UI widgets (like CPView) to implement
|
||||||
|
// CSS theme support.
|
||||||
|
|
||||||
|
@implementation CPColor (CSSTheming)
|
||||||
|
{
|
||||||
|
CPDictionary _cssDictionary @accessors(property=cssDictionary);
|
||||||
|
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
|
||||||
|
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
|
||||||
|
{
|
||||||
|
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||||
|
{
|
||||||
|
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_cssDictionary = aDictionary;
|
||||||
|
_cssBeforeDictionary = beforeDictionary;
|
||||||
|
_cssAfterDictionary = afterDictionary;
|
||||||
|
_components = [0.0, 0.0, 0.0, 1.0];
|
||||||
|
|
||||||
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeState = CPThemeStateNormal;
|
||||||
|
[self _loadThemeAttributes];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isCSSBased
|
||||||
|
{
|
||||||
|
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSDictionary
|
||||||
|
{
|
||||||
|
return ([_cssDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSBeforeDictionary
|
||||||
|
{
|
||||||
|
return ([_cssBeforeDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSAfterDictionary
|
||||||
|
{
|
||||||
|
return ([_cssAfterDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)restorePreviousCSSState:(CPArrayRef)aPreviousStateRef forDOMElement:(DOMElement)aDOMElement
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var aPreviousState = @deref(aPreviousStateRef);
|
||||||
|
|
||||||
|
for (var i = 0, count = aPreviousState.length; i < count; i++)
|
||||||
|
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
|
||||||
|
|
||||||
|
@deref(aPreviousStateRef) = @[];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DOMElement)applyCSSColorForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var aPreviousState = @deref(aPreviousStateRef);
|
||||||
|
|
||||||
|
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
|
||||||
|
aDOMElement.style[aKey] = anObject;
|
||||||
|
}];
|
||||||
|
|
||||||
|
if ([self hasCSSBeforeDictionary] || [self hasCSSAfterDictionary])
|
||||||
|
{
|
||||||
|
// We need to create a unique class name
|
||||||
|
|
||||||
|
var styleClassName = @".CP" + [aView UID],
|
||||||
|
styleContent = @"";
|
||||||
|
|
||||||
|
if ([self hasCSSBeforeDictionary])
|
||||||
|
{
|
||||||
|
styleContent += styleClassName + @"::before { ";
|
||||||
|
|
||||||
|
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
styleContent += aKey + ": " + anObject + "; ";
|
||||||
|
}];
|
||||||
|
|
||||||
|
styleContent += "} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([self hasCSSAfterDictionary])
|
||||||
|
{
|
||||||
|
styleContent += styleClassName + @"::after { ";
|
||||||
|
|
||||||
|
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
styleContent += aKey + ": " + anObject + "; ";
|
||||||
|
}];
|
||||||
|
|
||||||
|
styleContent += "} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
var styleDescription = document.createTextNode(styleContent);
|
||||||
|
|
||||||
|
if (!aStyleNode)
|
||||||
|
{
|
||||||
|
aStyleNode = document.createElement("style");
|
||||||
|
|
||||||
|
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
|
||||||
|
|
||||||
|
aStyleNode.appendChild(styleDescription);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
[aView setDOMClassName:@"CP"+[aView UID]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no before/after so remove aStyleNode if existing
|
||||||
|
|
||||||
|
if (aStyleNode)
|
||||||
|
{
|
||||||
|
aView._DOMElement.removeChild(aStyleNode);
|
||||||
|
aStyleNode = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return actualised values
|
||||||
|
|
||||||
|
@deref(aPreviousStateRef) = aPreviousState;
|
||||||
|
|
||||||
|
return aStyleNode;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
/// @cond IGNORE
|
/// @cond IGNORE
|
||||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
CPColorPatternImageKey = @"CPColorPatternImageKey",
|
||||||
|
CPColorCssDictionaryKey = @"CPColorCssDictionaryKey",
|
||||||
|
CPColorCssBeforeDictionaryKey = @"CPColorCssBeforeDictionaryKey",
|
||||||
|
CPColorCssAfterDictionaryKey = @"CPColorCssAfterDictionaryKey";
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|
||||||
@implementation CPColor (CPCoding)
|
@implementation CPColor (CPCoding)
|
||||||
@@ -829,9 +1110,17 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
|||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
if ([aCoder containsValueForKey:CPColorPatternImageKey])
|
if ([aCoder containsValueForKey:CPColorPatternImageKey])
|
||||||
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
|
self = [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
|
||||||
|
else if ([aCoder containsValueForKey:CPColorCssDictionaryKey])
|
||||||
|
self = [self _initWithCSSDictionary:[aCoder decodeObjectForKey:CPColorCssDictionaryKey]
|
||||||
|
beforeDictionary:[aCoder decodeObjectForKey:CPColorCssBeforeDictionaryKey]
|
||||||
|
afterDictionary:[aCoder decodeObjectForKey:CPColorCssAfterDictionaryKey]];
|
||||||
|
else
|
||||||
|
self = [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
|
||||||
|
|
||||||
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
|
[self _decodeThemeObjectsWithCoder:aCoder];
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -842,8 +1131,16 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
|||||||
{
|
{
|
||||||
if (_patternImage)
|
if (_patternImage)
|
||||||
[aCoder encodeObject:_patternImage forKey:CPColorPatternImageKey];
|
[aCoder encodeObject:_patternImage forKey:CPColorPatternImageKey];
|
||||||
|
else if (_cssDictionary)
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_cssDictionary forKey:CPColorCssDictionaryKey];
|
||||||
|
[aCoder encodeObject:_cssBeforeDictionary forKey:CPColorCssBeforeDictionaryKey];
|
||||||
|
[aCoder encodeObject:_cssAfterDictionary forKey:CPColorCssAfterDictionaryKey];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
[aCoder encodeObject:_components forKey:CPColorComponentsKey];
|
[aCoder encodeObject:_components forKey:CPColorComponentsKey];
|
||||||
|
|
||||||
|
[self _encodeThemeObjectsWithCoder:aCoder];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -1180,7 +1477,8 @@ var patternColorsFromPattern = function(pattern, attributes, imageFactory)
|
|||||||
bottomHeight,
|
bottomHeight,
|
||||||
centerWidthHeight,
|
centerWidthHeight,
|
||||||
centerIsNil,
|
centerIsNil,
|
||||||
numParts;
|
numParts,
|
||||||
|
isVertical;
|
||||||
|
|
||||||
// positions are mandatory
|
// positions are mandatory
|
||||||
if (pattern.indexOf("{position}") < 0)
|
if (pattern.indexOf("{position}") < 0)
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
@class CPSlider
|
@class CPSlider
|
||||||
|
@class _CPColorPanelToolbar
|
||||||
|
@class _CPColorPanelSwatches
|
||||||
|
@class _CPColorPanelPreview
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
@@ -68,7 +71,6 @@ var SharedColorPanel = nil,
|
|||||||
*/
|
*/
|
||||||
@implementation CPColorPanel : CPPanel
|
@implementation CPColorPanel : CPPanel
|
||||||
{
|
{
|
||||||
_CPColorPanelToolbar _toolbar;
|
|
||||||
_CPColorPanelSwatches _swatchView;
|
_CPColorPanelSwatches _swatchView;
|
||||||
_CPColorPanelPreview _previewView;
|
_CPColorPanelPreview _previewView;
|
||||||
|
|
||||||
@@ -481,13 +483,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
var cookieValue = eval(cookieValue),
|
var cookieValue = JSON.parse(cookieValue);
|
||||||
result = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < cookieValue.length; i++)
|
return [cookieValue arrayByApplyingBlock:function(value)
|
||||||
result.push([CPColor colorWithHexString:cookieValue[i]]);
|
{
|
||||||
|
return [CPColor colorWithHexString:value];
|
||||||
return result;
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPArray)saveColorList
|
- (CPArray)saveColorList
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
@class CPSlider
|
@class CPSlider
|
||||||
|
@class CPColorPanel
|
||||||
|
@class __CPColorWheel
|
||||||
|
|
||||||
@global CPColorPickerViewWidth
|
@global CPColorPickerViewWidth
|
||||||
@global CPColorPickerViewHeight
|
@global CPColorPickerViewHeight
|
||||||
@@ -123,7 +125,8 @@
|
|||||||
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
|
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
|
||||||
|
|
||||||
[_brightnessSlider setValue:15.0 forThemeAttribute:@"track-width"];
|
[_brightnessSlider setValue:15.0 forThemeAttribute:@"track-width"];
|
||||||
[_brightnessSlider setValue:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"]]] forThemeAttribute:@"track-color"];
|
var brightnessImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"] size:CGSizeMake(272, 20)];
|
||||||
|
[_brightnessSlider setValue:[CPColor colorWithPatternImage:brightnessImage] forThemeAttribute:@"track-color"];
|
||||||
|
|
||||||
[_brightnessSlider setMinValue:0.0];
|
[_brightnessSlider setMinValue:0.0];
|
||||||
[_brightnessSlider setMaxValue:100.0];
|
[_brightnessSlider setMaxValue:100.0];
|
||||||
@@ -244,7 +247,7 @@
|
|||||||
_blackWheelImage = new Image();
|
_blackWheelImage = new Image();
|
||||||
_blackWheelImage.src = path;
|
_blackWheelImage.src = path;
|
||||||
_blackWheelImage.style.opacity = "0";
|
_blackWheelImage.style.opacity = "0";
|
||||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
_blackWheelImage.style.filter = "alpha(opacity=0)";
|
||||||
_blackWheelImage.style.position = "absolute";
|
_blackWheelImage.style.position = "absolute";
|
||||||
|
|
||||||
_DOMElement.appendChild(_wheelImage);
|
_DOMElement.appendChild(_wheelImage);
|
||||||
|
|||||||
+41
-5
@@ -86,14 +86,12 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
_active = NO;
|
_active = NO;
|
||||||
_color = [CPColor whiteColor];
|
_color = [CPColor whiteColor];
|
||||||
[self setBordered:YES];
|
[self setBordered:YES];
|
||||||
|
|
||||||
[self _registerForNotifications];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_registerForNotifications
|
- (void)_registerNotifications
|
||||||
{
|
{
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
@@ -110,6 +108,22 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
object:[CPColorPanel sharedColorPanel]];
|
object:[CPColorPanel sharedColorPanel]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_removeNotifications
|
||||||
|
{
|
||||||
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:self
|
||||||
|
name:_CPColorWellDidBecomeExclusiveNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:self
|
||||||
|
name:CPWindowWillCloseNotification
|
||||||
|
object:[CPColorPanel sharedColorPanel]];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the color well is bordered.
|
Sets whether the color well is bordered.
|
||||||
*/
|
*/
|
||||||
@@ -241,6 +255,8 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
|
|
||||||
var colorPanel = [CPColorPanel sharedColorPanel];
|
var colorPanel = [CPColorPanel sharedColorPanel];
|
||||||
|
|
||||||
|
[colorPanel setPlatformWindow:[[self window] platformWindow]];
|
||||||
|
|
||||||
[colorPanel setColor:_color];
|
[colorPanel setColor:_color];
|
||||||
[colorPanel orderFront:self];
|
[colorPanel orderFront:self];
|
||||||
}
|
}
|
||||||
@@ -312,6 +328,28 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
[contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
|
[contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Observers method
|
||||||
|
|
||||||
|
- (void)_addObservers
|
||||||
|
{
|
||||||
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
[self _registerNotifications];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
|
{
|
||||||
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
[self _removeNotifications];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPColorWellValueBinder : CPBinder
|
@implementation CPColorWellValueBinder : CPBinder
|
||||||
@@ -363,8 +401,6 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
|||||||
_active = NO;
|
_active = NO;
|
||||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||||
[self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
|
[self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
|
||||||
|
|
||||||
[self _registerForNotifications];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
+182
-81
@@ -25,6 +25,27 @@
|
|||||||
@import "_CPPopUpList.j"
|
@import "_CPPopUpList.j"
|
||||||
|
|
||||||
|
|
||||||
|
// TODO : should conform to protocol CPTextFieldDelegate
|
||||||
|
@protocol CPComboBoxDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification;
|
||||||
|
- (void)comboBoxSelectionDidChange:(CPNotification)aNotification;
|
||||||
|
- (void)comboBoxWillPopUp:(CPNotification)aNotification;
|
||||||
|
- (void)comboBoxWillDismiss:(CPNotification)aNotification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol CPComboBoxDataSource <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (CPString)comboBox:(CPComboBox)aComboBox completedString:(CPString)uncompletedString;
|
||||||
|
- (id)comboBox:(CPComboBox)aComboBox objectValueForItemAtIndex:(int)index;
|
||||||
|
- (int)comboBox:(CPComboBox)aComboBox indexOfItemWithStringValue:(CPString)stringValue;
|
||||||
|
- (int)numberOfItemsInComboBox:(CPComboBox)aComboBox;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
CPComboBoxSelectionDidChangeNotification = @"CPComboBoxSelectionDidChangeNotification";
|
CPComboBoxSelectionDidChangeNotification = @"CPComboBoxSelectionDidChangeNotification";
|
||||||
CPComboBoxSelectionIsChangingNotification = @"CPComboBoxSelectionIsChangingNotification";
|
CPComboBoxSelectionIsChangingNotification = @"CPComboBoxSelectionIsChangingNotification";
|
||||||
CPComboBoxWillDismissNotification = @"CPComboBoxWillDismissNotification";
|
CPComboBoxWillDismissNotification = @"CPComboBoxWillDismissNotification";
|
||||||
@@ -32,6 +53,11 @@ CPComboBoxWillPopUpNotification = @"CPComboBoxWillPopUpNotification";
|
|||||||
|
|
||||||
CPComboBoxStateButtonBordered = CPThemeState("button-bordered");
|
CPComboBoxStateButtonBordered = CPThemeState("button-bordered");
|
||||||
|
|
||||||
|
var CPComboBoxDelegate_comboBoxSelectionIsChanging_ = 1 << 0,
|
||||||
|
CPComboBoxDelegate_comboBoxSelectionDidChange_ = 1 << 1,
|
||||||
|
CPComboBoxDelegate_comboBoxWillPopUp_ = 1 << 2,
|
||||||
|
CPComboBoxDelegate_comboBoxWillDismiss_ = 1 << 3;
|
||||||
|
|
||||||
var CPComboBoxTextSubview = @"text",
|
var CPComboBoxTextSubview = @"text",
|
||||||
CPComboBoxButtonSubview = @"button",
|
CPComboBoxButtonSubview = @"button",
|
||||||
CPComboBoxDefaultNumberOfVisibleItems = 5,
|
CPComboBoxDefaultNumberOfVisibleItems = 5,
|
||||||
@@ -40,17 +66,20 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
@implementation CPComboBox : CPTextField
|
@implementation CPComboBox : CPTextField
|
||||||
{
|
{
|
||||||
CPArray _items;
|
BOOL _canComplete;
|
||||||
_CPPopUpList _listDelegate;
|
BOOL _completes;
|
||||||
CPComboBoxDataSource _dataSource;
|
BOOL _forceSelection;
|
||||||
BOOL _usesDataSource;
|
BOOL _hasVerticalScroller;
|
||||||
BOOL _completes;
|
BOOL _popUpButtonCausedResign;
|
||||||
BOOL _canComplete;
|
BOOL _usesDataSource;
|
||||||
int _numberOfVisibleItems;
|
CGSize _intercellSpacing;
|
||||||
BOOL _forceSelection;
|
CPArray _items;
|
||||||
BOOL _hasVerticalScroller;
|
id <CPComboBoxDataSource> _dataSource;
|
||||||
CPString _selectedStringValue;
|
CPInteger _implementedDelegateComboBoxMethods;
|
||||||
BOOL _popUpButtonCausedResign;
|
CPString _selectedStringValue;
|
||||||
|
float _itemHeight;
|
||||||
|
int _numberOfVisibleItems;
|
||||||
|
_CPPopUpList _listDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
+ (CPString)defaultThemeClass
|
||||||
@@ -119,7 +148,9 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_hasVerticalScroller = flag;
|
_hasVerticalScroller = flag;
|
||||||
[[_listDelegate scrollView] setHasVerticalScroller:flag];
|
|
||||||
|
if (_listDelegate)
|
||||||
|
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)intercellSpacing
|
- (CGSize)intercellSpacing
|
||||||
@@ -129,7 +160,13 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
- (void)setIntercellSpacing:(CGSize)aSize
|
- (void)setIntercellSpacing:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[[_listDelegate tableView] setIntercellSpacing:aSize];
|
if (_intercellSpacing && CGSizeEqualToSize(aSize, _intercellSpacing))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_intercellSpacing = aSize;
|
||||||
|
|
||||||
|
if (_listDelegate)
|
||||||
|
[[_listDelegate tableView] setIntercellSpacing:_intercellSpacing];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isButtonBordered
|
- (BOOL)isButtonBordered
|
||||||
@@ -152,10 +189,18 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
- (void)setItemHeight:(float)itemHeight
|
- (void)setItemHeight:(float)itemHeight
|
||||||
{
|
{
|
||||||
[[_listDelegate tableView] setRowHeight:itemHeight];
|
if (itemHeight === _itemHeight)
|
||||||
|
return;
|
||||||
|
|
||||||
// FIXME: This shouldn't be necessary, but CPTableView does not tile after setRowHeight
|
_itemHeight = itemHeight;
|
||||||
[[_listDelegate tableView] reloadData];
|
|
||||||
|
if (_listDelegate)
|
||||||
|
{
|
||||||
|
[[_listDelegate tableView] setRowHeight:_itemHeight];
|
||||||
|
|
||||||
|
// FIXME: This shouldn't be necessary, but CPTableView does not tile after setRowHeight
|
||||||
|
[[_listDelegate tableView] reloadData];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)numberOfVisibleItems
|
- (int)numberOfVisibleItems
|
||||||
@@ -171,7 +216,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
#pragma mark Setting a Delegate
|
#pragma mark Setting a Delegate
|
||||||
|
|
||||||
- (id /*< CPComboBoxDelegate >*/)delegate
|
- (id <CPComboBoxDelegate>)delegate
|
||||||
{
|
{
|
||||||
return [super delegate];
|
return [super delegate];
|
||||||
}
|
}
|
||||||
@@ -182,48 +227,28 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
protocol, in actual fact it doesn't. Also note that the same
|
protocol, in actual fact it doesn't. Also note that the same
|
||||||
delegate may conform to the NSTextFieldDelegate protocol.
|
delegate may conform to the NSTextFieldDelegate protocol.
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id /*< CPComboBoxDelegate >*/)aDelegate
|
- (void)setDelegate:(id <CPComboBoxDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
var delegate = [self delegate];
|
var delegate = [self delegate];
|
||||||
|
|
||||||
if (aDelegate === delegate)
|
if (aDelegate === delegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
_implementedDelegateComboBoxMethods = 0;
|
||||||
|
|
||||||
if (delegate)
|
|
||||||
{
|
|
||||||
[defaultCenter removeObserver:delegate name:CPComboBoxSelectionIsChangingNotification object:self];
|
|
||||||
[defaultCenter removeObserver:delegate name:CPComboBoxSelectionDidChangeNotification object:self];
|
|
||||||
[defaultCenter removeObserver:delegate name:CPComboBoxWillDismissNotification object:self];
|
|
||||||
[defaultCenter removeObserver:delegate name:CPComboBoxWillPopUpNotification object:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aDelegate)
|
if (aDelegate)
|
||||||
{
|
{
|
||||||
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionIsChanging:)])
|
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionIsChanging:)])
|
||||||
[defaultCenter addObserver:delegate
|
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxSelectionIsChanging_;
|
||||||
selector:@selector(comboBoxSelectionIsChanging:)
|
|
||||||
name:CPComboBoxSelectionIsChangingNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionDidChange:)])
|
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionDidChange:)])
|
||||||
[defaultCenter addObserver:delegate
|
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxSelectionDidChange_;
|
||||||
selector:@selector(comboBoxSelectionDidChange:)
|
|
||||||
name:CPComboBoxSelectionDidChangeNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
if ([aDelegate respondsToSelector:@selector(comboBoxWillPopUp:)])
|
if ([aDelegate respondsToSelector:@selector(comboBoxWillPopUp:)])
|
||||||
[defaultCenter addObserver:delegate
|
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxWillPopUp_;
|
||||||
selector:@selector(comboBoxWillPopUp:)
|
|
||||||
name:CPComboBoxWillPopUpNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
if ([aDelegate respondsToSelector:@selector(comboBoxWillDismiss:)])
|
if ([aDelegate respondsToSelector:@selector(comboBoxWillDismiss:)])
|
||||||
[defaultCenter addObserver:delegate
|
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxWillDismiss_;
|
||||||
selector:@selector(comboBoxWillDissmis:)
|
|
||||||
name:CPComboBoxWillDismissNotification
|
|
||||||
object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[super setDelegate:aDelegate];
|
[super setDelegate:aDelegate];
|
||||||
@@ -231,7 +256,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
#pragma mark Setting a Data Source
|
#pragma mark Setting a Data Source
|
||||||
|
|
||||||
- (id /*< CPComboBoxDataSource >*/)dataSource
|
- (id <CPComboBoxDataSource>)dataSource
|
||||||
{
|
{
|
||||||
if (!_usesDataSource)
|
if (!_usesDataSource)
|
||||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||||
@@ -239,10 +264,12 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
return _dataSource;
|
return _dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDataSource:(id /*< CPComboBoxDataSource >*/)aSource
|
- (void)setDataSource:(id <CPComboBoxDataSource>)aSource
|
||||||
{
|
{
|
||||||
if (!_usesDataSource)
|
if (!_usesDataSource)
|
||||||
|
{
|
||||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||||
|
}
|
||||||
else if (_dataSource !== aSource)
|
else if (_dataSource !== aSource)
|
||||||
{
|
{
|
||||||
if (![aSource respondsToSelector:@selector(numberOfItemsInComboBox:)] ||
|
if (![aSource respondsToSelector:@selector(numberOfItemsInComboBox:)] ||
|
||||||
@@ -251,7 +278,9 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
CPLog.warn("Illegal %s data source (%s). Must implement numberOfItemsInComboBox: and comboBox:objectValueForItemAtIndex:", [self className], [aSource description]);
|
CPLog.warn("Illegal %s data source (%s). Must implement numberOfItemsInComboBox: and comboBox:objectValueForItemAtIndex:", [self className], [aSource description]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_dataSource = aSource;
|
_dataSource = aSource;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,49 +398,57 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
if (_listDelegate === aDelegate)
|
if (_listDelegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
[self _removeObserversForListDelegate:_listDelegate];
|
||||||
|
|
||||||
if (_listDelegate)
|
|
||||||
{
|
|
||||||
[defaultCenter removeObserver:self name:_CPPopUpListWillPopUpNotification object:_listDelegate];
|
|
||||||
[defaultCenter removeObserver:self name:_CPPopUpListWillDismissNotification object:_listDelegate];
|
|
||||||
[defaultCenter removeObserver:self name:_CPPopUpListDidDismissNotification object:_listDelegate];
|
|
||||||
[defaultCenter removeObserver:self name:_CPPopUpListItemWasClickedNotification object:_listDelegate];
|
|
||||||
|
|
||||||
var oldTableView = [_listDelegate tableView];
|
|
||||||
|
|
||||||
if (oldTableView)
|
|
||||||
{
|
|
||||||
[defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:oldTableView];
|
|
||||||
[defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:oldTableView];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_listDelegate = aDelegate;
|
_listDelegate = aDelegate;
|
||||||
|
|
||||||
|
// We only add the observers if the CPComboBox is displayed
|
||||||
|
if ([self window])
|
||||||
|
[self _addObserversForListDelegate:_listDelegate]
|
||||||
|
|
||||||
|
// Apply our text style to the list
|
||||||
|
[_listDelegate setFont:[self font]];
|
||||||
|
[_listDelegate setAlignment:[self alignment]];
|
||||||
|
|
||||||
|
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||||
|
|
||||||
|
if (_intercellSpacing)
|
||||||
|
[[_listDelegate tableView] setIntercellSpacing:_intercellSpacing];
|
||||||
|
|
||||||
|
if (_itemHeight)
|
||||||
|
[[_listDelegate tableView] setRowHeight:_itemHeight];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_addObserversForListDelegate:(_CPPopUpList)aDelegate
|
||||||
|
{
|
||||||
|
if (!aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(comboBoxWillPopUp:)
|
selector:@selector(comboBoxWillPopUp:)
|
||||||
name:_CPPopUpListWillPopUpNotification
|
name:_CPPopUpListWillPopUpNotification
|
||||||
object:_listDelegate];
|
object:aDelegate];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(comboBoxWillDismiss:)
|
selector:@selector(comboBoxWillDismiss:)
|
||||||
name:_CPPopUpListWillDismissNotification
|
name:_CPPopUpListWillDismissNotification
|
||||||
object:_listDelegate];
|
object:aDelegate];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(listDidDismiss:)
|
selector:@selector(listDidDismiss:)
|
||||||
name:_CPPopUpListDidDismissNotification
|
name:_CPPopUpListDidDismissNotification
|
||||||
object:_listDelegate];
|
object:aDelegate];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(itemWasClicked:)
|
selector:@selector(itemWasClicked:)
|
||||||
name:_CPPopUpListItemWasClickedNotification
|
name:_CPPopUpListItemWasClickedNotification
|
||||||
object:_listDelegate];
|
object:aDelegate];
|
||||||
|
|
||||||
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
[[aDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||||
|
|
||||||
var tableView = [_listDelegate tableView];
|
var tableView = [aDelegate tableView];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(comboBoxSelectionIsChanging:)
|
selector:@selector(comboBoxSelectionIsChanging:)
|
||||||
@@ -422,10 +459,27 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
selector:@selector(comboBoxSelectionDidChange:)
|
selector:@selector(comboBoxSelectionDidChange:)
|
||||||
name:CPTableViewSelectionDidChangeNotification
|
name:CPTableViewSelectionDidChangeNotification
|
||||||
object:tableView];
|
object:tableView];
|
||||||
|
}
|
||||||
|
|
||||||
// Apply our text style to the list
|
- (void)_removeObserversForListDelegate:(_CPPopUpList)aDelegate
|
||||||
[_listDelegate setFont:[self font]];
|
{
|
||||||
[_listDelegate setAlignment:[self alignment]];
|
if (!aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
[defaultCenter removeObserver:self name:_CPPopUpListWillPopUpNotification object:aDelegate];
|
||||||
|
[defaultCenter removeObserver:self name:_CPPopUpListWillDismissNotification object:aDelegate];
|
||||||
|
[defaultCenter removeObserver:self name:_CPPopUpListDidDismissNotification object:aDelegate];
|
||||||
|
[defaultCenter removeObserver:self name:_CPPopUpListItemWasClickedNotification object:aDelegate];
|
||||||
|
|
||||||
|
var oldTableView = [aDelegate tableView];
|
||||||
|
|
||||||
|
if (oldTableView)
|
||||||
|
{
|
||||||
|
[defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:oldTableView];
|
||||||
|
[defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:oldTableView];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)indexOfItemWithObjectValue:(id)anObject
|
- (int)indexOfItemWithObjectValue:(id)anObject
|
||||||
@@ -470,8 +524,6 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
if (!_listDelegate)
|
if (!_listDelegate)
|
||||||
[self setListDelegate:[[_CPPopUpList alloc] initWithDataSource:self]];
|
[self setListDelegate:[[_CPPopUpList alloc] initWithDataSource:self]];
|
||||||
|
|
||||||
[self _selectMatchingItem];
|
|
||||||
|
|
||||||
// Note the offset here is 1 less than the focus ring width because the outer edge
|
// Note the offset here is 1 less than the focus ring width because the outer edge
|
||||||
// of the focus ring is very transparent and it looks better if the list is closer.
|
// of the focus ring is very transparent and it looks better if the list is closer.
|
||||||
if (CPComboBoxFocusRingWidth < 0)
|
if (CPComboBoxFocusRingWidth < 0)
|
||||||
@@ -482,6 +534,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
}
|
}
|
||||||
|
|
||||||
[_listDelegate popUpRelativeToRect:[self _borderFrame] view:self offset:CPComboBoxFocusRingWidth - 1];
|
[_listDelegate popUpRelativeToRect:[self _borderFrame] view:self offset:CPComboBoxFocusRingWidth - 1];
|
||||||
|
[self _selectMatchingItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
@@ -511,7 +564,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
|
|
||||||
var selectedStringValue = [_listDelegate selectedStringValue];
|
var selectedStringValue = [_listDelegate selectedStringValue];
|
||||||
|
|
||||||
if (selectedStringValue === nil)
|
if (selectedStringValue == nil)
|
||||||
return NO;
|
return NO;
|
||||||
else
|
else
|
||||||
_selectedStringValue = selectedStringValue;
|
_selectedStringValue = selectedStringValue;
|
||||||
@@ -790,7 +843,17 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
// In FireFox this needs to be done in setTimeout, otherwise there is no caret
|
// In FireFox this needs to be done in setTimeout, otherwise there is no caret
|
||||||
// We have to save the input element now, when we lose focus it will change.
|
// We have to save the input element now, when we lose focus it will change.
|
||||||
var element = [self _inputElement];
|
var element = [self _inputElement];
|
||||||
window.setTimeout(function() { element.focus(); }, 0);
|
|
||||||
|
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||||
|
{
|
||||||
|
// This will prevent to jump to the focused element
|
||||||
|
var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||||
|
|
||||||
|
element.focus();
|
||||||
|
|
||||||
|
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||||
|
|
||||||
|
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
@@ -817,13 +880,17 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
- (void)setFont:(CPFont)aFont
|
- (void)setFont:(CPFont)aFont
|
||||||
{
|
{
|
||||||
[super setFont:aFont];
|
[super setFont:aFont];
|
||||||
[_listDelegate setFont:aFont];
|
|
||||||
|
if (_listDelegate)
|
||||||
|
[_listDelegate setFont:aFont];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlignment:(CPTextAlignment)alignment
|
- (void)setAlignment:(CPTextAlignment)alignment
|
||||||
{
|
{
|
||||||
[super setAlignment:alignment];
|
[super setAlignment:alignment];
|
||||||
[_listDelegate setAlignment:alignment];
|
|
||||||
|
if (_listDelegate)
|
||||||
|
[_listDelegate setAlignment:alignment];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Pop Up Button Layout
|
#pragma mark Pop Up Button Layout
|
||||||
@@ -894,7 +961,9 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
index = [_dataSource comboBox:self indexOfItemWithStringValue:stringValue]
|
index = [_dataSource comboBox:self indexOfItemWithStringValue:stringValue]
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
index = [self indexOfItemWithObjectValue:stringValue];
|
index = [self indexOfItemWithObjectValue:stringValue];
|
||||||
|
}
|
||||||
|
|
||||||
[_listDelegate selectRow:index];
|
[_listDelegate selectRow:index];
|
||||||
|
|
||||||
@@ -946,6 +1015,28 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Observers method
|
||||||
|
|
||||||
|
- (void)_addObservers
|
||||||
|
{
|
||||||
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
[self _addObserversForListDelegate:_listDelegate];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
|
{
|
||||||
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
[self _removeObserversForListDelegate:_listDelegate];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPComboBox (CPComboBoxDelegate)
|
@implementation CPComboBox (CPComboBoxDelegate)
|
||||||
@@ -953,24 +1044,36 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification
|
- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
|
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxSelectionIsChanging_)
|
||||||
|
[_delegate comboBoxSelectionIsChanging:[[CPNotification alloc] initWithName:CPComboBoxSelectionIsChangingNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionIsChangingNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionIsChangingNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)comboBoxSelectionDidChange:(CPNotification)aNotification
|
- (void)comboBoxSelectionDidChange:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
|
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxSelectionDidChange_)
|
||||||
|
[_delegate comboBoxSelectionDidChange:[[CPNotification alloc] initWithName:CPComboBoxSelectionDidChangeNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionDidChangeNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionDidChangeNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)comboBoxWillPopUp:(CPNotification)aNotification
|
- (void)comboBoxWillPopUp:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
|
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxWillPopUp_)
|
||||||
|
[_delegate comboBoxWillPopUp:[[CPNotification alloc] initWithName:CPComboBoxWillPopUpNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillPopUpNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillPopUpNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)comboBoxWillDismiss:(CPNotification)aNotification
|
- (void)comboBoxWillDismiss:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
|
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxWillDismiss_)
|
||||||
|
[_delegate comboBoxWillDismiss:[[CPNotification alloc] initWithName:CPComboBoxWillDismissNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillDismissNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillDismissNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,11 +1142,9 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
// Directly nuke _items, [_items removeAll] will trigger an extra call to setContent
|
// Directly nuke _items, [_items removeAll] will trigger an extra call to setContent
|
||||||
_items = [];
|
_items = [];
|
||||||
|
|
||||||
var values = [];
|
var values = [anArray arrayByApplyingBlock:function(object)
|
||||||
|
|
||||||
[anArray enumerateObjectsUsingBlock:function(object)
|
|
||||||
{
|
{
|
||||||
values.push([object description]);
|
return [object description];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self addItemsWithObjectValues:values];
|
[self addItemsWithObjectValues:values];
|
||||||
|
|||||||
+89
-15
@@ -26,11 +26,13 @@
|
|||||||
|
|
||||||
// Browser Engines
|
// Browser Engines
|
||||||
CPUnknownBrowserEngine = 0;
|
CPUnknownBrowserEngine = 0;
|
||||||
CPGeckoBrowserEngine = 1;
|
CPGeckoBrowserEngine = 1 << 0;
|
||||||
CPInternetExplorerBrowserEngine = 2;
|
CPInternetExplorerBrowserEngine = 1 << 1;
|
||||||
CPKHTMLBrowserEngine = 3;
|
CPKHTMLBrowserEngine = 1 << 2;
|
||||||
CPOperaBrowserEngine = 4;
|
CPOperaBrowserEngine = 1 << 3;
|
||||||
CPWebKitBrowserEngine = 5;
|
CPWebKitBrowserEngine = 1 << 4; // Safari + Chrome
|
||||||
|
CPBlinkBrowserEngine = 1 << 5; // Recent Chrome
|
||||||
|
CPEdgeBrowserEngine = 1 << 6;
|
||||||
|
|
||||||
// Operating Systems
|
// Operating Systems
|
||||||
CPMacOperatingSystem = 0;
|
CPMacOperatingSystem = 0;
|
||||||
@@ -78,18 +80,30 @@ CPInputOnInputEventFeature = 30;
|
|||||||
|
|
||||||
CPFileAPIFeature = 31;
|
CPFileAPIFeature = 31;
|
||||||
|
|
||||||
|
CPAltEnterTextAreaFeature = 32;
|
||||||
|
|
||||||
|
CPCSSAnimationFeature = 33;
|
||||||
|
|
||||||
|
CPBackspaceTriggersPageBack = 34;
|
||||||
/*
|
/*
|
||||||
When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas (subviews) don't redraw correctly. E.g. if you have a bunch of text fields in a CPBox in a sheet which animates in, some of the text fields might not be visible because the CPBox has a canvas at the bottom and the box moved form offscreen to onscreen. This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
|
When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas (subviews) don't redraw correctly. E.g. if you have a bunch of text fields in a CPBox in a sheet which animates in, some of the text fields might not be visible because the CPBox has a canvas at the bottom and the box moved form offscreen to onscreen. This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
|
||||||
*/
|
*/
|
||||||
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
|
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
|
||||||
|
|
||||||
// The paste event is only sent if an input or textarea has focus.
|
// The paste event is only sent if an input or textarea has focus.
|
||||||
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
|
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
|
||||||
// Redirecting the focus of the browser on keydown to an input for Cmd-V or Ctrl-V makes the paste fail.
|
// Redirecting the focus of the browser on keydown to an input for Cmd-V or Ctrl-V makes the paste fail.
|
||||||
CPJavaScriptPasteCantRefocus = 1 << 2;
|
CPJavaScriptPasteCantRefocus = 1 << 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Safari calculates incorrect text size unless you set the canvas font even if it is already set
|
||||||
|
You can see the bug after disabling the workaround and opening any panel while typing.
|
||||||
|
You can use the font panel in the manual test for CPTextView.
|
||||||
|
Look out for a displaced cursor, i.e. after typing letters of small width, such as the 'i'.
|
||||||
|
https://bugs.webkit.org/show_bug.cgi?id=150224
|
||||||
|
*/
|
||||||
|
CPTextSizingAlwaysNeedsSetFontBug = 1 << 3;
|
||||||
|
|
||||||
|
|
||||||
var USER_AGENT = "",
|
var USER_AGENT = "",
|
||||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||||
@@ -100,6 +114,7 @@ var USER_AGENT = "",
|
|||||||
// default these features to true
|
// default these features to true
|
||||||
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = YES;
|
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = YES;
|
||||||
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
||||||
|
PLATFORM_FEATURES[CPAltEnterTextAreaFeature] = YES;
|
||||||
|
|
||||||
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||||
USER_AGENT = window.navigator.userAgent;
|
USER_AGENT = window.navigator.userAgent;
|
||||||
@@ -107,15 +122,15 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
|||||||
// Opera
|
// Opera
|
||||||
if (typeof window !== "undefined" && window.opera)
|
if (typeof window !== "undefined" && window.opera)
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
PLATFORM_ENGINE |= CPOperaBrowserEngine;
|
||||||
|
|
||||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internet Explorer
|
// Internet Explorer
|
||||||
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
|
else if (typeof window !== "undefined" && (window.attachEvent || (!(window.ActiveXObject) && "ActiveXObject" in window))) // Must follow Opera check.
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
PLATFORM_ENGINE |= CPInternetExplorerBrowserEngine;
|
||||||
|
|
||||||
// Features we can only be sure of with IE (no known independent tests)
|
// Features we can only be sure of with IE (no known independent tests)
|
||||||
PLATFORM_FEATURES[CPVMLFeature] = YES;
|
PLATFORM_FEATURES[CPVMLFeature] = YES;
|
||||||
@@ -133,10 +148,32 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
|
|||||||
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
|
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebKit
|
// Edge
|
||||||
|
else if (USER_AGENT.indexOf("Edge/") != -1)
|
||||||
|
{
|
||||||
|
PLATFORM_ENGINE |= CPEdgeBrowserEngine;
|
||||||
|
|
||||||
|
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||||
|
PLATFORM_FEATURES[CPHTMLContentEditableFeature] = YES;
|
||||||
|
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptClipboardEventsFeature] = YES;
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = NO;
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptShadowFeature] = YES;
|
||||||
|
|
||||||
|
var versionStart = USER_AGENT.indexOf("Edge/") + "Edge/".length,
|
||||||
|
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||||
|
versionString = USER_AGENT.substring(versionStart, versionEnd),
|
||||||
|
versionDivision = versionString.indexOf('.'),
|
||||||
|
majorVersion = parseInt(versionString.substring(0, versionDivision)),
|
||||||
|
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
||||||
|
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safari + Chrome (WebKit and Blink)
|
||||||
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPWebKitBrowserEngine;
|
PLATFORM_ENGINE |= CPWebKitBrowserEngine;
|
||||||
|
|
||||||
// Features we can only be sure of with WebKit (no known independent tests)
|
// Features we can only be sure of with WebKit (no known independent tests)
|
||||||
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||||
@@ -176,7 +213,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
|||||||
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
|
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=39689
|
// https://bugs.webkit.org/show_bug.cgi?id=39689
|
||||||
PLATFORM_BUGS |= CPJavaScriptPasteCantRefocus;
|
PLATFORM_BUGS |= CPJavaScriptPasteCantRefocus;
|
||||||
|
PLATFORM_BUGS |= CPTextSizingAlwaysNeedsSetFontBug;
|
||||||
}
|
}
|
||||||
|
else if ((window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window)
|
||||||
|
PLATFORM_ENGINE |= CPBlinkBrowserEngine;
|
||||||
|
|
||||||
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
|
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
|
||||||
if (majorVersion > 533)
|
if (majorVersion > 533)
|
||||||
@@ -186,15 +226,16 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
|||||||
// KHTML
|
// KHTML
|
||||||
else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
|
else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPKHTMLBrowserEngine;
|
PLATFORM_ENGINE |= CPKHTMLBrowserEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gecko
|
// Gecko
|
||||||
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
PLATFORM_ENGINE |= CPGeckoBrowserEngine;
|
||||||
|
|
||||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||||
|
PLATFORM_FEATURES[CPBackspaceTriggersPageBack] = YES;
|
||||||
|
|
||||||
var index = USER_AGENT.indexOf("Firefox"),
|
var index = USER_AGENT.indexOf("Firefox"),
|
||||||
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
||||||
@@ -205,9 +246,13 @@ else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
|||||||
if (version < 3.0)
|
if (version < 3.0)
|
||||||
PLATFORM_FEATURES[CPJavaScriptMouseWheelValues_8_15] = YES;
|
PLATFORM_FEATURES[CPJavaScriptMouseWheelValues_8_15] = YES;
|
||||||
|
|
||||||
|
if (version >= 66)
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||||
|
|
||||||
// Some day this might be fixed and should be version prefixed. No known fixed version yet.
|
// Some day this might be fixed and should be version prefixed. No known fixed version yet.
|
||||||
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
||||||
|
|
||||||
|
PLATFORM_FEATURES[CPAltEnterTextAreaFeature] = NO;
|
||||||
// This was supposed to be added in Firefox 22, but when testing with the latest beta as of 2013-06-14
|
// This was supposed to be added in Firefox 22, but when testing with the latest beta as of 2013-06-14
|
||||||
// it does not seem to work. It seems to exhibit the CPJavaScriptPasteRequiresEditableTarget problem,
|
// it does not seem to work. It seems to exhibit the CPJavaScriptPasteRequiresEditableTarget problem,
|
||||||
// and in addition doesn't seem to work with our native copy code either.
|
// and in addition doesn't seem to work with our native copy code either.
|
||||||
@@ -282,7 +327,7 @@ function CPPlatformHasBug(aBug)
|
|||||||
|
|
||||||
function CPBrowserIsEngine(anEngine)
|
function CPBrowserIsEngine(anEngine)
|
||||||
{
|
{
|
||||||
return PLATFORM_ENGINE === anEngine;
|
return PLATFORM_ENGINE & anEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
||||||
@@ -318,6 +363,14 @@ else
|
|||||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets a feature with the given value.
|
||||||
|
*/
|
||||||
|
function CPSetPlatformFeature(aFeature, aBool)
|
||||||
|
{
|
||||||
|
PLATFORM_FEATURES[aFeature] = aBool;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Return the properly prefixed JS property for the given name. E.g. in a webkit browser,
|
Return the properly prefixed JS property for the given name. E.g. in a webkit browser,
|
||||||
CPBrowserStyleProperty('transition') -> WebkitTransition
|
CPBrowserStyleProperty('transition') -> WebkitTransition
|
||||||
@@ -365,6 +418,18 @@ function CPBrowserStyleProperty(aProperty)
|
|||||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
|
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'animationend':
|
||||||
|
var candidates = {
|
||||||
|
'WebkitAnimation' : 'webkitAnimationEnd',
|
||||||
|
'MozAnimation' : 'animationend',
|
||||||
|
'OAnimation' : 'oAnimationEnd',
|
||||||
|
'msAnimation' : 'MSAnimationEnd',
|
||||||
|
'animation' : 'animationend'
|
||||||
|
};
|
||||||
|
|
||||||
|
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['animation']] || nil;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var prefixes = ["Webkit", "Moz", "O", "ms"],
|
var prefixes = ["Webkit", "Moz", "O", "ms"],
|
||||||
strippedProperty = aProperty.split('-').join(' '),
|
strippedProperty = aProperty.split('-').join(' '),
|
||||||
@@ -434,3 +499,12 @@ function CPBrowserCSSProperty(aProperty)
|
|||||||
|
|
||||||
return browserProperty.toLowerCase();
|
return browserProperty.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CPBrowserBackingStorePixelRatio(context)
|
||||||
|
{
|
||||||
|
return context.webkitBackingStorePixelRatio ||
|
||||||
|
context.mozBackingStorePixelRatio ||
|
||||||
|
context.msBackingStorePixelRatio ||
|
||||||
|
context.oBackingStorePixelRatio ||
|
||||||
|
context.backingStorePixelRatio || 1;
|
||||||
|
}
|
||||||
|
|||||||
+211
-27
@@ -23,23 +23,36 @@
|
|||||||
@import <Foundation/CPFormatter.j>
|
@import <Foundation/CPFormatter.j>
|
||||||
@import <Foundation/CPTimer.j>
|
@import <Foundation/CPTimer.j>
|
||||||
|
|
||||||
@import "CPFont.j"
|
|
||||||
@import "CPShadow.j"
|
@import "CPShadow.j"
|
||||||
@import "CPView.j"
|
@import "CPText.j"
|
||||||
@import "CPKeyValueBinding.j"
|
@import "CPKeyValueBinding.j"
|
||||||
|
@import "CPTrackingArea.j"
|
||||||
|
|
||||||
|
@class CPFont
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
CPLeftTextAlignment = 0;
|
@protocol CPControlTextEditingDelegate <CPObject>
|
||||||
CPRightTextAlignment = 1;
|
|
||||||
CPCenterTextAlignment = 2;
|
|
||||||
CPJustifiedTextAlignment = 3;
|
|
||||||
CPNaturalTextAlignment = 4;
|
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)controlTextDidBeginEditing:(CPNotification)aNotification;
|
||||||
|
- (void)controlTextDidChange:(CPNotification)aNotification;
|
||||||
|
- (void)controlTextDidEndEditing:(CPNotification)aNotification;
|
||||||
|
- (void)controlTextDidFocus:(CPNotification)aNotification;
|
||||||
|
- (void)controlTextDidBlur:(CPNotification)aNotification;
|
||||||
|
- (BOOL)control:(CPControl)control didFailToFormatString:(CPString)string errorDescription:(CPString)error;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@typedef CPControlSize
|
||||||
CPRegularControlSize = 0;
|
CPRegularControlSize = 0;
|
||||||
CPSmallControlSize = 1;
|
CPSmallControlSize = 1;
|
||||||
CPMiniControlSize = 2;
|
CPMiniControlSize = 2;
|
||||||
|
|
||||||
|
// To get the theme state corresponding to a control size, use CPControlSizeThemeStates[controlSize]
|
||||||
|
CPControlSizeThemeStates = @[CPThemeStateControlSizeRegular, CPThemeStateControlSizeSmall, CPThemeStateControlSizeMini];
|
||||||
|
|
||||||
|
@typedef CPLineBreakMode
|
||||||
CPLineBreakByWordWrapping = 0;
|
CPLineBreakByWordWrapping = 0;
|
||||||
CPLineBreakByCharWrapping = 1;
|
CPLineBreakByCharWrapping = 1;
|
||||||
CPLineBreakByClipping = 2;
|
CPLineBreakByClipping = 2;
|
||||||
@@ -47,11 +60,13 @@ CPLineBreakByTruncatingHead = 3;
|
|||||||
CPLineBreakByTruncatingTail = 4;
|
CPLineBreakByTruncatingTail = 4;
|
||||||
CPLineBreakByTruncatingMiddle = 5;
|
CPLineBreakByTruncatingMiddle = 5;
|
||||||
|
|
||||||
|
@typedef CPVerticalTextAlignment
|
||||||
CPTopVerticalTextAlignment = 1;
|
CPTopVerticalTextAlignment = 1;
|
||||||
CPCenterVerticalTextAlignment = 2;
|
CPCenterVerticalTextAlignment = 2;
|
||||||
CPBottomVerticalTextAlignment = 3;
|
CPBottomVerticalTextAlignment = 3;
|
||||||
|
|
||||||
// Deprecated for use with images, use the CPImageScale constants
|
// Deprecated for use with images, use the CPImageScale constants
|
||||||
|
@typedef CPImageScaling
|
||||||
CPScaleProportionally = 0;
|
CPScaleProportionally = 0;
|
||||||
CPScaleToFit = 1;
|
CPScaleToFit = 1;
|
||||||
CPScaleNone = 2;
|
CPScaleNone = 2;
|
||||||
@@ -61,6 +76,7 @@ CPImageScaleAxesIndependently = 1;
|
|||||||
CPImageScaleNone = 2;
|
CPImageScaleNone = 2;
|
||||||
CPImageScaleProportionallyUpOrDown = 3;
|
CPImageScaleProportionallyUpOrDown = 3;
|
||||||
|
|
||||||
|
@typedef CPCellImagePosition
|
||||||
CPNoImage = 0;
|
CPNoImage = 0;
|
||||||
CPImageOnly = 1;
|
CPImageOnly = 1;
|
||||||
CPImageLeft = 2;
|
CPImageLeft = 2;
|
||||||
@@ -106,6 +122,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
BOOL _trackingWasWithinFrame;
|
BOOL _trackingWasWithinFrame;
|
||||||
unsigned _trackingMouseDownFlags;
|
unsigned _trackingMouseDownFlags;
|
||||||
CGPoint _previousTrackingLocation;
|
CGPoint _previousTrackingLocation;
|
||||||
|
|
||||||
|
CPControlSize _controlSize;
|
||||||
|
|
||||||
|
CPWritingDirection _baseWritingDirection @accessors(property=baseWritingDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPDictionary)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
@@ -115,13 +135,13 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
@"vertical-alignment": CPTopVerticalTextAlignment,
|
@"vertical-alignment": CPTopVerticalTextAlignment,
|
||||||
@"line-break-mode": CPLineBreakByClipping,
|
@"line-break-mode": CPLineBreakByClipping,
|
||||||
@"text-color": [CPColor blackColor],
|
@"text-color": [CPColor blackColor],
|
||||||
@"font": [CPFont systemFontOfSize:CPFontCurrentSystemSize],
|
@"font": [CPNull null],
|
||||||
@"text-shadow-color": [CPNull null],
|
@"text-shadow-color": [CPNull null],
|
||||||
@"text-shadow-offset": CGSizeMakeZero(),
|
@"text-shadow-offset": CGSizeMakeZero(),
|
||||||
@"image-position": CPImageLeft,
|
@"image-position": CPImageLeft,
|
||||||
@"image-scaling": CPScaleToFit,
|
@"image-scaling": CPScaleToFit,
|
||||||
@"min-size": CGSizeMakeZero(),
|
@"min-size": CGSizeMakeZero(),
|
||||||
@"max-size": CGSizeMake(-1.0, -1.0),
|
@"max-size": CGSizeMake(-1.0, -1.0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +172,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
|
Reverse set the binding if the CPContinuouslyUpdatesValueBindingOption is set.
|
||||||
*/
|
*/
|
||||||
- (void)_continuouslyReverseSetBinding
|
- (void)_continuouslyReverseSetBinding
|
||||||
{
|
{
|
||||||
@@ -177,13 +197,97 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_sendActionOn = CPLeftMouseUpMask;
|
_sendActionOn = CPLeftMouseUpMask;
|
||||||
_trackingMouseDownFlags = 0;
|
_trackingMouseDownFlags = 0;
|
||||||
|
|
||||||
|
[self setControlSize:CPThemeStateControlSizeRegular];
|
||||||
|
[self updateTrackingAreas];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Control Size
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the control's control size
|
||||||
|
*/
|
||||||
|
- (CPControlSize)controlSize
|
||||||
|
{
|
||||||
|
return _controlSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the control's size.
|
||||||
|
@param aControlSize the control's size
|
||||||
|
*/
|
||||||
|
- (void)setControlSize:(CPControlSize)aControlSize
|
||||||
|
{
|
||||||
|
if (_controlSize === aControlSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self unsetThemeState:[self _controlSizeThemeState]];
|
||||||
|
_controlSize = aControlSize;
|
||||||
|
[self setThemeState:[self _controlSizeThemeState]];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Gets the current theme state according to the current controlSize.
|
||||||
|
@return a CPThemeState
|
||||||
|
*/
|
||||||
|
- (ThemeState)_controlSizeThemeState
|
||||||
|
{
|
||||||
|
switch (_controlSize)
|
||||||
|
{
|
||||||
|
case CPSmallControlSize:
|
||||||
|
return CPThemeStateControlSizeSmall;
|
||||||
|
|
||||||
|
case CPMiniControlSize:
|
||||||
|
return CPThemeStateControlSizeMini;
|
||||||
|
|
||||||
|
case CPRegularControlSize:
|
||||||
|
default:
|
||||||
|
return CPThemeStateControlSizeRegular;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Change frame size according to the theme control size theme constraints
|
||||||
|
Basically for height to min-size.
|
||||||
|
*/
|
||||||
|
- (void)_sizeToControlSize
|
||||||
|
{
|
||||||
|
var frameSize = [self frameSize],
|
||||||
|
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
|
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||||
|
|
||||||
|
if (minSize.width > 0)
|
||||||
|
{
|
||||||
|
frameSize.width = MAX(minSize.width, frameSize.width);
|
||||||
|
|
||||||
|
if (maxSize.width > 0)
|
||||||
|
frameSize.width = MIN(maxSize.width, frameSize.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minSize.height > 0)
|
||||||
|
{
|
||||||
|
frameSize.height = MAX(minSize.height, frameSize.height);
|
||||||
|
|
||||||
|
if (maxSize.height > 0)
|
||||||
|
frameSize.height = MIN(maxSize.height, frameSize.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setFrameSize:frameSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the receiver's target action.
|
Sets the receiver's target action.
|
||||||
|
|
||||||
@@ -522,15 +626,15 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
*/
|
*/
|
||||||
- (CPString)stringValue
|
- (CPString)stringValue
|
||||||
{
|
{
|
||||||
if (_formatter && _value !== undefined)
|
if (_formatter && _value != nil)
|
||||||
{
|
{
|
||||||
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
||||||
|
|
||||||
if (formattedValue !== nil && formattedValue !== undefined)
|
if (formattedValue != nil)
|
||||||
return formattedValue;
|
return formattedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (_value === undefined || _value === nil) ? @"" : String(_value);
|
return _value == nil ? @"" : String(_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -539,7 +643,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
- (void)setStringValue:(CPString)aString
|
- (void)setStringValue:(CPString)aString
|
||||||
{
|
{
|
||||||
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
||||||
if (aString === nil || aString === undefined)
|
if (aString == nil)
|
||||||
{
|
{
|
||||||
CPLog.warn("nil or undefined sent to CPControl -setStringValue");
|
CPLog.warn("nil or undefined sent to CPControl -setStringValue");
|
||||||
return;
|
return;
|
||||||
@@ -705,7 +809,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
CPBottomVerticalTextAlignment
|
CPBottomVerticalTextAlignment
|
||||||
</pre>
|
</pre>
|
||||||
*/
|
*/
|
||||||
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
|
- (void)setVerticalAlignment:(CPVerticalTextAlignment)alignment
|
||||||
{
|
{
|
||||||
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
|
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
|
||||||
}
|
}
|
||||||
@@ -750,7 +854,12 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
*/
|
*/
|
||||||
- (void)setTextColor:(CPColor)aColor
|
- (void)setTextColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
[self setValue:aColor forThemeAttribute:@"text-color"];
|
[self setValue:aColor forThemeAttribute:@"text-color" inState:[self themeState]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor inThemeStates:(CPArray)themeStates
|
||||||
|
{
|
||||||
|
[self setValue:aColor forThemeAttribute:@"text-color" inStates:themeStates];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -808,7 +917,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
*/
|
*/
|
||||||
- (CPFont)font
|
- (CPFont)font
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"font"];
|
return [self currentValueForThemeAttribute:@"font"] || [CPFont systemFontForControlSize:_controlSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -913,16 +1022,81 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
return [self hasThemeState:CPThemeStateHighlighted];
|
return [self hasThemeState:CPThemeStateHighlighted];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Base writing direction
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the initial writing direction of the receiver
|
||||||
|
@param writingDirection - It could be CPWritingDirectionNatural, CPWritingDirectionLeftToRight, CPWritingDirectionRightToLeft
|
||||||
|
*/
|
||||||
|
- (void)setBaseWritingDirection:(CPWritingDirection)writingDirection
|
||||||
|
{
|
||||||
|
if (writingDirection == _baseWritingDirection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"baseWritingDirection"];
|
||||||
|
_baseWritingDirection = writingDirection;
|
||||||
|
[self didChangeValueForKey:@"baseWritingDirection"];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
|
var style;
|
||||||
|
|
||||||
|
switch (_baseWritingDirection)
|
||||||
|
{
|
||||||
|
case CPWritingDirectionNatural:
|
||||||
|
style = "initial";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPWritingDirectionLeftToRight:
|
||||||
|
style = "ltr";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPWritingDirectionRightToLeft:
|
||||||
|
style = "rtl";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
style = "initial";
|
||||||
|
}
|
||||||
|
|
||||||
|
_DOMElement.style.direction = style;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPControlValueKey = @"CPControlValueKey",
|
@implementation CPControl (CPTrackingArea)
|
||||||
|
{
|
||||||
|
CPTrackingArea _controlTrackingArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateTrackingAreas
|
||||||
|
{
|
||||||
|
if (_controlTrackingArea)
|
||||||
|
[self removeTrackingArea:_controlTrackingArea];
|
||||||
|
|
||||||
|
_controlTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||||
|
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||||
|
owner:self
|
||||||
|
userInfo:nil];
|
||||||
|
[self addTrackingArea:_controlTrackingArea];
|
||||||
|
[super updateTrackingAreas];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPControlActionKey = @"CPControlActionKey",
|
||||||
|
CPControlControlSizeKey = @"CPControlControlSizeKey",
|
||||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||||
CPControlIsEnabledKey = @"CPControlIsEnabledKey",
|
|
||||||
CPControlTargetKey = @"CPControlTargetKey",
|
|
||||||
CPControlActionKey = @"CPControlActionKey",
|
|
||||||
CPControlSendActionOnKey = @"CPControlSendActionOnKey",
|
|
||||||
CPControlFormatterKey = @"CPControlFormatterKey",
|
CPControlFormatterKey = @"CPControlFormatterKey",
|
||||||
|
CPControlIsEnabledKey = @"CPControlIsEnabledKey",
|
||||||
|
CPControlSendActionOnKey = @"CPControlSendActionOnKey",
|
||||||
CPControlSendsActionOnEndEditingKey = @"CPControlSendsActionOnEndEditingKey",
|
CPControlSendsActionOnEndEditingKey = @"CPControlSendsActionOnEndEditingKey",
|
||||||
|
CPControlTargetKey = @"CPControlTargetKey",
|
||||||
|
CPControlValueKey = @"CPControlValueKey",
|
||||||
|
CPControlBaseWrittingDirectionKey = @"CPControlBaseWrittingDirectionKey";
|
||||||
|
|
||||||
__Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
__Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||||
|
|
||||||
@@ -949,6 +1123,11 @@ var CPControlValueKey = @"CPControlValueKey",
|
|||||||
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||||
|
|
||||||
[self setFormatter:[aCoder decodeObjectForKey:CPControlFormatterKey]];
|
[self setFormatter:[aCoder decodeObjectForKey:CPControlFormatterKey]];
|
||||||
|
|
||||||
|
[self setControlSize:[aCoder decodeIntForKey:CPControlControlSizeKey]];
|
||||||
|
|
||||||
|
[self setBaseWritingDirection:[aCoder decodeIntForKey:CPControlBaseWrittingDirectionKey]];
|
||||||
|
[self updateTrackingAreas];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -968,19 +1147,24 @@ var CPControlValueKey = @"CPControlValueKey",
|
|||||||
|
|
||||||
var objectValue = [self objectValue];
|
var objectValue = [self objectValue];
|
||||||
|
|
||||||
if (objectValue !== nil)
|
if (objectValue != nil)
|
||||||
[aCoder encodeObject:objectValue forKey:CPControlValueKey];
|
[aCoder encodeObject:objectValue forKey:CPControlValueKey];
|
||||||
|
|
||||||
if (_target !== nil)
|
if (_target != nil)
|
||||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||||
|
|
||||||
if (_action !== nil)
|
if (_action != nil)
|
||||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||||
|
|
||||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||||
|
|
||||||
if (_formatter !== nil)
|
if (_formatter != nil)
|
||||||
[aCoder encodeObject:_formatter forKey:CPControlFormatterKey];
|
[aCoder encodeObject:_formatter forKey:CPControlFormatterKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_controlSize forKey:CPControlControlSizeKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_baseWritingDirection forKey:CPControlBaseWrittingDirectionKey];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
CPString _expires;
|
CPString _expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes a cookie with a given name \c aName.
|
Initializes a cookie with a given name \c aName.
|
||||||
@param the name for the cookie
|
@param the name for the cookie
|
||||||
|
|||||||
Executable → Regular
+116
-44
@@ -22,6 +22,8 @@ Cursor support by browser:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import "CPImage.j"
|
||||||
|
@import "CPCompatibility.j"
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
@@ -30,6 +32,12 @@ var currentCursor = nil,
|
|||||||
cursors = {},
|
cursors = {},
|
||||||
ieCursorMap = {};
|
ieCursorMap = {};
|
||||||
|
|
||||||
|
@typedef CPCursorPlatform
|
||||||
|
CPCursorPlatformNone = 0;
|
||||||
|
CPCursorPlatformMac = 1;
|
||||||
|
CPCursorPlatformWindows = 2;
|
||||||
|
CPCursorPlatformBoth = 3;
|
||||||
|
|
||||||
@implementation CPCursor : CPObject
|
@implementation CPCursor : CPObject
|
||||||
{
|
{
|
||||||
CPString _cssString @accessors(readonly);
|
CPString _cssString @accessors(readonly);
|
||||||
@@ -122,6 +130,9 @@ var currentCursor = nil,
|
|||||||
|
|
||||||
- (void)set
|
- (void)set
|
||||||
{
|
{
|
||||||
|
if (currentCursor === self)
|
||||||
|
return;
|
||||||
|
|
||||||
currentCursor = self;
|
currentCursor = self;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
@@ -153,7 +164,7 @@ var currentCursor = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal method that is used to return the system cursors. Caches the system cursors for performance.
|
// Internal method that is used to return the system cursors. Caches the system cursors for performance.
|
||||||
+ (CPCursor)_systemCursorWithName:(CPString)cursorName cssString:(CPString)aString hasImage:(BOOL)doesHaveImage
|
+ (CPCursor)_nativeSystemCursorWithName:(CPString)cursorName cssString:(CPString)aString
|
||||||
{
|
{
|
||||||
var cursor = cursors[cursorName];
|
var cursor = cursors[cursorName];
|
||||||
|
|
||||||
@@ -161,155 +172,216 @@ var currentCursor = nil,
|
|||||||
{
|
{
|
||||||
var cssString;
|
var cssString;
|
||||||
|
|
||||||
if (doesHaveImage)
|
// IE <= 8 does not support some cursors, map them to supported cursors
|
||||||
{
|
var ieLessThan9 = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !CPFeatureIsCompatible(CPHTMLCanvasFeature);
|
||||||
var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath],
|
|
||||||
extension = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) ? @"cur" : @"png";
|
|
||||||
|
|
||||||
cssString = [CPString stringWithFormat:@"url(%@cursors/%@.%@), %@", themeResourcePath, cursorName, extension, aString];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (ieLessThan9)
|
||||||
|
cssString = ieCursorMap[aString] || aString;
|
||||||
else
|
else
|
||||||
{
|
cssString = aString;
|
||||||
// IE <= 8 does not support some cursors, map them to supported cursors
|
|
||||||
var ieLessThan9 = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !CPFeatureIsCompatible(CPHTMLCanvasFeature);
|
|
||||||
|
|
||||||
if (ieLessThan9)
|
cursors[cursorName] = cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||||
cssString = ieCursorMap[aString] || aString;
|
|
||||||
else
|
|
||||||
cssString = aString;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
|
||||||
cursors[cursorName] = cursor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)_imageCursorWithName:(CPString)cursorName cssString:(CPString)aString
|
||||||
|
{
|
||||||
|
var cursor = cursors[cursorName];
|
||||||
|
|
||||||
|
if (typeof cursor === "undefined")
|
||||||
|
{
|
||||||
|
var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath],
|
||||||
|
extension = CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) ? @"cur" : @"png",
|
||||||
|
cssString = [CPString stringWithFormat:@"url(%@cursors/%@.%@), %@", themeResourcePath, cursorName, extension, aString];
|
||||||
|
|
||||||
|
cursors[cursorName] = cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)_tryUsingNativeSystemCursorWithName:(CPString)cursorName cssString:(CPString)cssName onPlatform:(CPCursorPlatform)shouldUseNativeCursorOn fallingBackWithImageAndCSSPointer:(CPString)aString
|
||||||
|
{
|
||||||
|
var useNativeSystemCursor = (((shouldUseNativeCursorOn == CPCursorPlatformBoth) ||
|
||||||
|
((shouldUseNativeCursorOn == CPCursorPlatformMac) && CPBrowserIsOperatingSystem(CPMacOperatingSystem)) ||
|
||||||
|
((shouldUseNativeCursorOn == CPCursorPlatformWindows) && CPBrowserIsOperatingSystem(CPWindowsOperatingSystem)))
|
||||||
|
&& [CPCursor _nativeCursorExists:cssName]);
|
||||||
|
|
||||||
|
if (useNativeSystemCursor)
|
||||||
|
return [CPCursor _nativeSystemCursorWithName:cursorName cssString:cssName];
|
||||||
|
else
|
||||||
|
return [CPCursor _imageCursorWithName:cursorName cssString:aString];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)_nativeCursorExists:(CPString)cursorCSSName
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
|
// FIXME: Trick until FF/Win & Chrome/Win correctly implement context-menu cursor
|
||||||
|
// They will answer that they implement it but they actually don't
|
||||||
|
|
||||||
|
if ([cursorCSSName isEqualToString:@"context-menu"] && CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !CPBrowserIsEngine(CPEdgeBrowserEngine))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
// Normal usage : try to set the cursor and check if resulting cursor is the one we tried to set.
|
||||||
|
// If yes, then the browser implements the cursor. If no (and usually we get "default"), then it doesn't.
|
||||||
|
|
||||||
|
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects],
|
||||||
|
count = [platformWindows count];
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
var currentPlatformCursor = platformWindows[0]._DOMBodyElement.style.cursor;
|
||||||
|
platformWindows[0]._DOMBodyElement.style.cursor = cursorCSSName;
|
||||||
|
var doesExist = (platformWindows[0]._DOMBodyElement.style.cursor == cursorCSSName);
|
||||||
|
platformWindows[0]._DOMBodyElement.style.cursor = currentPlatformCursor;
|
||||||
|
|
||||||
|
return doesExist;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPCursor)arrowCursor
|
+ (CPCursor)arrowCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"default" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)crosshairCursor
|
+ (CPCursor)crosshairCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)IBeamCursor
|
+ (CPCursor)IBeamCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)pointingHandCursor
|
+ (CPCursor)pointingHandCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeNorthwestCursor
|
+ (CPCursor)resizeNorthwestCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nw-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nw-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeNorthwestSoutheastCursor
|
+ (CPCursor)resizeNorthwestSoutheastCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nwse-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nwse-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeNortheastCursor
|
+ (CPCursor)resizeNortheastCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ne-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ne-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeNortheastSouthwestCursor
|
+ (CPCursor)resizeNortheastSouthwestCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nesw-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nesw-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeSouthwestCursor
|
+ (CPCursor)resizeSouthwestCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"sw-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"sw-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeSoutheastCursor
|
+ (CPCursor)resizeSoutheastCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"se-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"se-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeDownCursor
|
+ (CPCursor)resizeDownCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeUpCursor
|
+ (CPCursor)resizeUpCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeLeftCursor
|
+ (CPCursor)resizeLeftCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeRightCursor
|
+ (CPCursor)resizeRightCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeLeftRightCursor
|
+ (CPCursor)resizeLeftRightCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeEastWestCursor
|
+ (CPCursor)resizeEastWestCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ew-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ew-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeUpDownCursor
|
+ (CPCursor)resizeUpDownCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)resizeNorthSouthCursor
|
+ (CPCursor)resizeNorthSouthCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ns-resize" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ns-resize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)operationNotAllowedCursor
|
+ (CPCursor)operationNotAllowedCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed" hasImage:NO];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)dragCopyCursor
|
+ (CPCursor)dragCopyCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy" hasImage:YES];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)dragLinkCursor
|
+ (CPCursor)dragLinkCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias" hasImage:YES];
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)contextualMenuCursor
|
+ (CPCursor)contextualMenuCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"context-menu" hasImage:YES];
|
return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
|
||||||
|
cssString:@"context-menu"
|
||||||
|
onPlatform:CPCursorPlatformBoth
|
||||||
|
fallingBackWithImageAndCSSPointer:@"default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)openHandCursor
|
+ (CPCursor)openHandCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"move" hasImage:YES];
|
return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
|
||||||
|
cssString:@"grab"
|
||||||
|
onPlatform:CPCursorPlatformMac
|
||||||
|
fallingBackWithImageAndCSSPointer:@"default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)closedHandCursor
|
+ (CPCursor)closedHandCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"-moz-grabbing" hasImage:YES];
|
return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
|
||||||
|
cssString:@"grabbing"
|
||||||
|
onPlatform:CPCursorPlatformMac
|
||||||
|
fallingBackWithImageAndCSSPointer:@"default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)disappearingItemCursor
|
+ (CPCursor)disappearingItemCursor
|
||||||
{
|
{
|
||||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"auto" hasImage:YES];
|
return [CPCursor _imageCursorWithName:CPStringFromSelector(_cmd) cssString:@"default"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)IBeamCursorForVerticalLayout
|
||||||
|
{
|
||||||
|
return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"vertical-text"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* CPDatePicker.j
|
/* CPDatePicker.j
|
||||||
* AppKit
|
* AppKit
|
||||||
*
|
*
|
||||||
* Created by Alexandre Wilhelm
|
* Created by Alexandre Wilhelm
|
||||||
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPDate.j>
|
@import <Foundation/CPDate.j>
|
||||||
@import <Foundation/CPDateFormatter.j>
|
|
||||||
@import <Foundation/CPLocale.j>
|
@import <Foundation/CPLocale.j>
|
||||||
@import <Foundation/CPTimeZone.j>
|
@import <Foundation/CPTimeZone.j>
|
||||||
|
|
||||||
@@ -60,25 +59,26 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
@implementation CPDatePicker : CPControl
|
@implementation CPDatePicker : CPControl
|
||||||
{
|
{
|
||||||
BOOL _isBordered @accessors(getter=isBordered, setter=setBordered:);
|
BOOL _isBordered @accessors(getter=isBordered, setter=setBordered:);
|
||||||
BOOL _isBezeled @accessors(getter=isBezeled, setter=setBezeled:);
|
BOOL _isBezeled @accessors(getter=isBezeled, setter=setBezeled:);
|
||||||
BOOL _drawsBackground @accessors(property=drawsBackground);
|
BOOL _drawsBackground @accessors(property=drawsBackground);
|
||||||
CPDate _dateValue @accessors(property=dateValue);
|
CPDate _dateValue @accessors(property=dateValue);
|
||||||
CPDate _minDate @accessors(property=minDate);
|
CPDate _minDate @accessors(property=minDate);
|
||||||
CPDate _maxDate @accessors(property=maxDate);
|
CPDate _maxDate @accessors(property=maxDate);
|
||||||
CPFont _textFont @accessors(property=textFont);
|
CPFont _textFont @accessors(property=textFont);
|
||||||
CPLocale _locale @accessors(property=locale);
|
CPLocale _locale @accessors(property=locale);
|
||||||
//CPCalendar _calendar @accessors(property=calendar);
|
//CPCalendar _calendar @accessors(property=calendar);
|
||||||
CPTimeZone _timeZone @accessors(property=timeZone);
|
CPTimeZone _timeZone @accessors(property=timeZone);
|
||||||
id _delegate @accessors(property=delegate);
|
id _delegate @accessors(property=delegate);
|
||||||
CPInteger _datePickerElements @accessors(property=datePickerElements);
|
CPInteger _datePickerElements @accessors(property=datePickerElements);
|
||||||
CPInteger _datePickerMode @accessors(property=datePickerMode);
|
CPInteger _datePickerMode @accessors(property=datePickerMode);
|
||||||
CPInteger _datePickerStyle @accessors(property=datePickerStyle);
|
CPInteger _datePickerStyle @accessors(property=datePickerStyle);
|
||||||
CPInteger _timeInterval @accessors(property=timeInterval);
|
CPInteger _timeInterval @accessors(property=timeInterval);
|
||||||
|
|
||||||
_CPDatePickerTextField _datePickerTextfield;
|
BOOL _invokedByUserEvent;
|
||||||
_CPDatePickerCalendar _datePickerCalendar;
|
|
||||||
unsigned _implementedCDatePickerDelegateMethods;
|
unsigned _implementedCDatePickerDelegateMethods;
|
||||||
|
BOOL _isTextual;
|
||||||
|
id _datePickerComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,6 +144,32 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
@"hour-hand-size": CGSizeMakeZero(),
|
@"hour-hand-size": CGSizeMakeZero(),
|
||||||
@"middle-hand-size": CGSizeMakeZero(),
|
@"middle-hand-size": CGSizeMakeZero(),
|
||||||
@"minute-hand-size": CGSizeMakeZero(),
|
@"minute-hand-size": CGSizeMakeZero(),
|
||||||
|
@"previous-button-size": CGSizeMakeZero(),
|
||||||
|
@"current-button-size": CGSizeMakeZero(),
|
||||||
|
@"next-button-size": CGSizeMakeZero(),
|
||||||
|
@"title-inset": [CPNull null],
|
||||||
|
@"day-label-inset": [CPNull null],
|
||||||
|
@"tile-content-inset": CGInsetMakeZero(),
|
||||||
|
@"tile-margin": [CPNull null],
|
||||||
|
@"tile-inset": CGInsetMakeZero(),
|
||||||
|
@"separator-color": [CPNull null],
|
||||||
|
@"separator-margin-width": 0,
|
||||||
|
@"separator-height": 0,
|
||||||
|
@"bezel-color-calendar-left": [CPNull null],
|
||||||
|
@"bezel-color-calendar-middle": [CPNull null],
|
||||||
|
@"bezel-color-calendar-right": [CPNull null],
|
||||||
|
@"tile-vertical-alignment": CPCenterVerticalTextAlignment,
|
||||||
|
@"tile-text-alignment": CPCenterTextAlignment,
|
||||||
|
@"hour-ampm-margin": 2,
|
||||||
|
@"time-separator-content-inset": CGInsetMakeZero(),
|
||||||
|
@"clock-second-hand-over": NO,
|
||||||
|
@"clock-draws-hours": NO,
|
||||||
|
@"clock-hours-font": [CPNull null],
|
||||||
|
@"clock-hours-text-color": [CPColor clearColor],
|
||||||
|
@"clock-hours-radius": 0,
|
||||||
|
@"calendar-clock-margin": 10,
|
||||||
|
@"clock-only-nib2cib-adjustment-frame": CPRectMakeZero(),
|
||||||
|
@"uses-focus-ring": NO
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,23 +232,58 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
if (!_locale)
|
if (!_locale)
|
||||||
_locale = [CPLocale currentLocale];
|
_locale = [CPLocale currentLocale];
|
||||||
|
|
||||||
if (!_timeZone)
|
_datePickerComponent = nil;
|
||||||
_timeZone = [CPTimeZone systemTimeZone];
|
|
||||||
|
|
||||||
_datePickerTextfield = [[_CPDatePickerTextField alloc] initWithFrame:[self bounds] withDatePicker:self];
|
[self _createComponents];
|
||||||
|
|
||||||
[_datePickerTextfield setDateValue:_dateValue];
|
|
||||||
[self addSubview:_datePickerTextfield];
|
|
||||||
|
|
||||||
_datePickerCalendar = [[_CPDatePickerCalendar alloc] initWithFrame:[self bounds] withDatePicker:self];
|
|
||||||
[_datePickerCalendar setDateValue:_dateValue];
|
|
||||||
[_datePickerCalendar setHidden:YES];
|
|
||||||
[self addSubview:_datePickerCalendar];
|
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_createComponents
|
||||||
|
{
|
||||||
|
_isTextual = (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle) || (_datePickerStyle == CPTextFieldDatePickerStyle);
|
||||||
|
|
||||||
|
if (_datePickerComponent)
|
||||||
|
{
|
||||||
|
[_datePickerComponent removeFromSuperview];
|
||||||
|
|
||||||
|
_datePickerComponent = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_datePickerComponent = [[(_isTextual ? _CPDatePickerTextField : _CPDatePickerCalendar) alloc] initWithFrame:[self bounds] withDatePicker:self];
|
||||||
|
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
[_datePickerComponent setControlSize:[self controlSize]];
|
||||||
|
[_datePickerComponent setDatePickerElements:_datePickerElements];
|
||||||
|
|
||||||
|
// FIXME: Don't know why but next line will cause theme compilation to fail...
|
||||||
|
// Workaround: added "if PLATFORM(DOM)"
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
[_datePickerComponent setEnabled:[self isEnabled]];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_isTextual)
|
||||||
|
// We need to transmit text color to the text field version (Cocoa doesn't permit adapting the calendar view text color)
|
||||||
|
[_datePickerComponent setTextColor:[self textColor]];
|
||||||
|
|
||||||
|
[self addSubview:_datePickerComponent];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Control Size
|
||||||
|
|
||||||
|
- (void)setControlSize:(CPControlSize)aControlSize
|
||||||
|
{
|
||||||
|
[super setControlSize:aControlSize];
|
||||||
|
|
||||||
|
[_datePickerComponent setControlSize:aControlSize];
|
||||||
|
|
||||||
|
if (_isTextual)
|
||||||
|
[self _sizeToControlSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Delegate methods
|
#pragma mark Delegate methods
|
||||||
@@ -248,20 +309,8 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
[super layoutSubviews];
|
[_datePickerComponent setNeedsLayout];
|
||||||
|
[_datePickerComponent setNeedsDisplay:YES];
|
||||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
|
||||||
{
|
|
||||||
[_datePickerTextfield setHidden:NO];
|
|
||||||
[_datePickerCalendar setHidden:YES];
|
|
||||||
[_datePickerTextfield setNeedsLayout];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[_datePickerCalendar setHidden:NO];
|
|
||||||
[_datePickerTextfield setHidden:YES];
|
|
||||||
[_datePickerCalendar setNeedsLayout];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
@@ -275,11 +324,14 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
return _dateValue
|
return _dateValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set the objectValue ofhe datePier. It has to be a CPDate
|
/*! Set the objectValue of the datePicker. It has to be a CPDate
|
||||||
@param aDateValue the dateValue
|
@param aDateValue the dateValue
|
||||||
*/
|
*/
|
||||||
- (void)setObjectValue:(CPDate)aValue
|
- (void)setObjectValue:(CPDate)aValue
|
||||||
{
|
{
|
||||||
|
if (![aValue isKindOfClass:[CPDate class]])
|
||||||
|
return;
|
||||||
|
|
||||||
[self setDateValue:aValue];
|
[self setDateValue:aValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +343,7 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
if (aDateValue == nil)
|
if (aDateValue == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_invokedByUserEvent = NO;
|
||||||
[self _setDateValue:aDateValue timeInterval:_timeInterval];
|
[self _setDateValue:aDateValue timeInterval:_timeInterval];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +353,14 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)_setDateValue:(CPDate)aDateValue timeInterval:(CPTimeInterval)aTimeInterval
|
- (void)_setDateValue:(CPDate)aDateValue timeInterval:(CPTimeInterval)aTimeInterval
|
||||||
{
|
{
|
||||||
|
// Make sure to have a valid date and avoid NaN values
|
||||||
|
if (!isFinite(aDateValue))
|
||||||
|
{
|
||||||
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:@"aDateValue is not valid"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_minDate)
|
if (_minDate)
|
||||||
aDateValue = new Date (MAX(aDateValue, _minDate));
|
aDateValue = new Date (MAX(aDateValue, _minDate));
|
||||||
|
|
||||||
@@ -309,13 +370,17 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
aTimeInterval = MAX(MIN(aTimeInterval, [_maxDate timeIntervalSinceDate:aDateValue]), [_minDate timeIntervalSinceDate:aDateValue]);
|
aTimeInterval = MAX(MIN(aTimeInterval, [_maxDate timeIntervalSinceDate:aDateValue]), [_minDate timeIntervalSinceDate:aDateValue]);
|
||||||
|
|
||||||
if ([aDateValue isEqualToDate:_dateValue] && aTimeInterval == _timeInterval)
|
if ([aDateValue isEqualToDate:_dateValue] && aTimeInterval == _timeInterval)
|
||||||
|
{
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
|
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
|
||||||
{
|
{
|
||||||
// constrain timeInterval also
|
// constrain timeInterval also
|
||||||
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;}
|
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;};
|
||||||
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;}
|
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;};
|
||||||
|
|
||||||
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
|
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
|
||||||
}
|
}
|
||||||
@@ -331,12 +396,10 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
_timeInterval = (_datePickerMode == CPSingleDateMode)? 0 : aTimeInterval;
|
_timeInterval = (_datePickerMode == CPSingleDateMode)? 0 : aTimeInterval;
|
||||||
[self didChangeValueForKey:@"timeInterval"];
|
[self didChangeValueForKey:@"timeInterval"];
|
||||||
|
|
||||||
[self sendAction:[self action] to:[self target]];
|
if (_invokedByUserEvent)
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
|
||||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
[_datePickerTextfield setDateValue:_dateValue];
|
|
||||||
else
|
|
||||||
[_datePickerCalendar setDateValue:_dateValue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set the minDate of the datePicker
|
/*! Set the minDate of the datePicker
|
||||||
@@ -344,6 +407,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setMinDate:(CPDate)aMinDate
|
- (void)setMinDate:(CPDate)aMinDate
|
||||||
{
|
{
|
||||||
|
if (_minDate === aMinDate)
|
||||||
|
return;
|
||||||
|
|
||||||
[self willChangeValueForKey:@"minDate"];
|
[self willChangeValueForKey:@"minDate"];
|
||||||
_minDate = aMinDate;
|
_minDate = aMinDate;
|
||||||
[self didChangeValueForKey:@"minDate"];
|
[self didChangeValueForKey:@"minDate"];
|
||||||
@@ -356,6 +422,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setMaxDate:(CPDate)aMaxDate
|
- (void)setMaxDate:(CPDate)aMaxDate
|
||||||
{
|
{
|
||||||
|
if (_maxDate === aMaxDate)
|
||||||
|
return;
|
||||||
|
|
||||||
[self willChangeValueForKey:@"maxDate"];
|
[self willChangeValueForKey:@"maxDate"];
|
||||||
_maxDate = aMaxDate;
|
_maxDate = aMaxDate;
|
||||||
[self didChangeValueForKey:@"maxDate"];
|
[self didChangeValueForKey:@"maxDate"];
|
||||||
@@ -368,8 +437,32 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setDatePickerStyle:(CPInteger)aDatePickerStyle
|
- (void)setDatePickerStyle:(CPInteger)aDatePickerStyle
|
||||||
{
|
{
|
||||||
|
if (_datePickerStyle === aDatePickerStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
_datePickerStyle = aDatePickerStyle;
|
_datePickerStyle = aDatePickerStyle;
|
||||||
|
|
||||||
|
// This is needed in order to specify different theme attributes values for textual / graphical date picker
|
||||||
|
if (_datePickerStyle === CPClockAndCalendarDatePickerStyle)
|
||||||
|
[self setThemeState:CPThemeStateAlternateState];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateAlternateState];
|
||||||
|
|
||||||
|
// This is needed in order to specify different theme attributes values for with / without stepper textual date picker
|
||||||
|
if (_datePickerStyle === CPTextFieldAndStepperDatePickerStyle)
|
||||||
|
[self setThemeState:CPThemeStateComposedControl];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateComposedControl];
|
||||||
|
|
||||||
|
[self setControlSize:[self controlSize]];
|
||||||
|
|
||||||
|
if (_datePickerComponent)
|
||||||
|
{
|
||||||
|
// We already have a component so we need to update it
|
||||||
|
[_datePickerComponent resignFirstResponder];
|
||||||
|
[self _createComponents];
|
||||||
|
}
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -379,8 +472,14 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||||
{
|
{
|
||||||
|
if (_datePickerElements === aDatePickerElements)
|
||||||
|
return;
|
||||||
|
|
||||||
_datePickerElements = aDatePickerElements;
|
_datePickerElements = aDatePickerElements;
|
||||||
|
|
||||||
|
// Notify the component of the new value
|
||||||
|
[_datePickerComponent setDatePickerElements:_datePickerElements];
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -390,6 +489,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setDatePickerMode:(CPInteger)aDatePickerMode
|
- (void)setDatePickerMode:(CPInteger)aDatePickerMode
|
||||||
{
|
{
|
||||||
|
if (_datePickerMode === aDatePickerMode)
|
||||||
|
return;
|
||||||
|
|
||||||
_datePickerMode = aDatePickerMode;
|
_datePickerMode = aDatePickerMode;
|
||||||
|
|
||||||
if (_datePickerMode == CPSingleDateMode)
|
if (_datePickerMode == CPSingleDateMode)
|
||||||
@@ -415,6 +517,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setLocale:(CPLocale)aLocale
|
- (void)setLocale:(CPLocale)aLocale
|
||||||
{
|
{
|
||||||
|
if (_locale === aLocale)
|
||||||
|
return;
|
||||||
|
|
||||||
_locale = aLocale;
|
_locale = aLocale;
|
||||||
|
|
||||||
if (_formatter)
|
if (_formatter)
|
||||||
@@ -425,7 +530,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This will update the textFields (usefull when changing with a date with pm and am)
|
// This will update the textFields (usefull when changing with a date with pm and am)
|
||||||
[_datePickerTextfield setDateValue:_dateValue];
|
if (_isTextual)
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -436,6 +543,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setBezeled:(BOOL)shouldBeBezeled
|
- (void)setBezeled:(BOOL)shouldBeBezeled
|
||||||
{
|
{
|
||||||
|
if (_isBezeled === shouldBeBezeled)
|
||||||
|
return;
|
||||||
|
|
||||||
_isBezeled = shouldBeBezeled;
|
_isBezeled = shouldBeBezeled;
|
||||||
|
|
||||||
if (shouldBeBezeled)
|
if (shouldBeBezeled)
|
||||||
@@ -450,6 +560,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setBordered:(BOOL)shouldBeBordered
|
- (void)setBordered:(BOOL)shouldBeBordered
|
||||||
{
|
{
|
||||||
|
if (_isBordered === shouldBeBordered)
|
||||||
|
return;
|
||||||
|
|
||||||
_isBordered = shouldBeBordered;
|
_isBordered = shouldBeBordered;
|
||||||
|
|
||||||
if (shouldBeBordered)
|
if (shouldBeBordered)
|
||||||
@@ -465,6 +578,22 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
- (void)setTextFont:(CPFont)aFont
|
- (void)setTextFont:(CPFont)aFont
|
||||||
{
|
{
|
||||||
[self setFont:aFont];
|
[self setFont:aFont];
|
||||||
|
|
||||||
|
if (_isTextual)
|
||||||
|
[_datePickerComponent setTextFont:aFont];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the color of the control.
|
||||||
|
@param aColor
|
||||||
|
*/
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[super setTextColor:aColor];
|
||||||
|
|
||||||
|
if (_isTextual)
|
||||||
|
[_datePickerComponent setTextColor:aColor];
|
||||||
|
// REM: in Cocoa, setTextColor has no effect on calendar view
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Sets the enabled status of the control. Controls that are not enabled can not be used by the user and obtain the CPThemeStateDisabled theme state.
|
/*! Sets the enabled status of the control. Controls that are not enabled can not be used by the user and obtain the CPThemeStateDisabled theme state.
|
||||||
@@ -474,8 +603,10 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
{
|
{
|
||||||
[super setEnabled:aBoolean];
|
[super setEnabled:aBoolean];
|
||||||
|
|
||||||
[_datePickerTextfield setEnabled:aBoolean];
|
[_datePickerComponent setEnabled:aBoolean];
|
||||||
[_datePickerCalendar setEnabled:aBoolean];
|
|
||||||
|
if (!aBoolean)
|
||||||
|
[self resignFirstResponder];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set the background color of the datePicker
|
/*! Set the background color of the datePicker
|
||||||
@@ -492,6 +623,9 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setDrawsBackground:(BOOL)aBoolean
|
- (void)setDrawsBackground:(BOOL)aBoolean
|
||||||
{
|
{
|
||||||
|
if (_drawsBackground === aBoolean)
|
||||||
|
return;
|
||||||
|
|
||||||
[self willChangeValueForKey:@"drawsBackground"];
|
[self willChangeValueForKey:@"drawsBackground"];
|
||||||
_drawsBackground = aBoolean;
|
_drawsBackground = aBoolean;
|
||||||
[self didChangeValueForKey:@"drawsBackground"];
|
[self didChangeValueForKey:@"drawsBackground"];
|
||||||
@@ -504,11 +638,16 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)setTimeZone:(CPTimeZone)aTimeZone
|
- (void)setTimeZone:(CPTimeZone)aTimeZone
|
||||||
{
|
{
|
||||||
|
if (_timeZone === aTimeZone)
|
||||||
|
return;
|
||||||
|
|
||||||
[self willChangeValueForKey:@"timeZone"];
|
[self willChangeValueForKey:@"timeZone"];
|
||||||
_timeZone = aTimeZone;
|
_timeZone = aTimeZone;
|
||||||
[self didChangeValueForKey:@"timeZone"];
|
[self didChangeValueForKey:@"timeZone"];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
|
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -519,12 +658,17 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)becomeFirstResponder
|
- (BOOL)becomeFirstResponder
|
||||||
{
|
{
|
||||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
if (_isTextual)
|
||||||
[_datePickerTextfield _selecteTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
{
|
||||||
else
|
if (![super becomeFirstResponder])
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
return YES;
|
[_datePickerComponent _selectTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Return YES
|
/*! Return YES
|
||||||
@@ -538,8 +682,8 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)resignFirstResponder
|
- (BOOL)resignFirstResponder
|
||||||
{
|
{
|
||||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
if (_isTextual)
|
||||||
[_datePickerTextfield resignFirstResponder];
|
[_datePickerComponent resignFirstResponder];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@@ -579,14 +723,6 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
return [[_locale objectForKey:CPLocaleCountryCode] isEqualToString:@"US"];
|
return [[_locale objectForKey:CPLocaleCountryCode] isEqualToString:@"US"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Check if we are in the english format or not. Depending on the locale
|
|
||||||
*/
|
|
||||||
- (BOOL)_isEnglishFormat
|
|
||||||
{
|
|
||||||
return [[_locale objectForKey:CPLocaleLanguageCode] isEqualToString:@"en"];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Key event
|
#pragma mark Key event
|
||||||
|
|
||||||
@@ -595,8 +731,8 @@ CPEraDatePickerElementFlag = 0x0100;
|
|||||||
*/
|
*/
|
||||||
- (void)keyDown:(CPEvent)anEvent
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
if (_isTextual)
|
||||||
[_datePickerTextfield keyDown:anEvent];
|
[_datePickerComponent keyDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -622,19 +758,22 @@ var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_textFont = [aCoder decodeObjectForKey:CPTextFontKey];
|
|
||||||
_minDate = [aCoder decodeObjectForKey:CPMinDateKey] || [CPDate distantPast];
|
|
||||||
_maxDate = [aCoder decodeObjectForKey:CPMaxDateKey] || [CPDate distantFuture];
|
|
||||||
_timeInterval = [aCoder decodeDoubleForKey:CPIntervalKey];
|
|
||||||
_datePickerMode = [aCoder decodeIntForKey:CPDatePickerModeKey];
|
|
||||||
_datePickerElements = [aCoder decodeIntForKey:CPDatePickerElementsKey];
|
|
||||||
_datePickerStyle = [aCoder decodeIntForKey:CPDatePickerStyleKey];
|
|
||||||
_locale = [aCoder decodeObjectForKey:CPLocaleKey];
|
|
||||||
_dateValue = [aCoder decodeObjectForKey:CPDateValueKey];
|
|
||||||
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
||||||
_drawsBackground = [aCoder decodeBoolForKey:CPDrawsBackgroundKey];
|
[self setBordered:[aCoder decodeBoolForKey:CPBorderedKey]];
|
||||||
_isBordered = [aCoder decodeBoolForKey:CPBorderedKey];
|
[self setDrawsBackground:[aCoder decodeBoolForKey:CPDrawsBackgroundKey]];
|
||||||
|
|
||||||
|
[self setDatePickerElements:[aCoder decodeIntForKey:CPDatePickerElementsKey]];
|
||||||
|
[self setDatePickerMode:[aCoder decodeIntForKey:CPDatePickerModeKey]];
|
||||||
|
[self setDatePickerStyle:[aCoder decodeIntForKey:CPDatePickerStyleKey]];
|
||||||
|
[self setMinDate:[aCoder decodeObjectForKey:CPMinDateKey] || [CPDate distantPast]];
|
||||||
|
[self setMaxDate:[aCoder decodeObjectForKey:CPMaxDateKey] || [CPDate distantFuture]];
|
||||||
|
[self setLocale:[aCoder decodeObjectForKey:CPLocaleKey]];
|
||||||
|
|
||||||
[self _init];
|
[self _init];
|
||||||
|
|
||||||
|
[self setTextFont:[aCoder decodeObjectForKey:CPTextFontKey]];
|
||||||
|
[self setTimeInterval:[aCoder decodeDoubleForKey:CPIntervalKey]];
|
||||||
|
[self setDateValue:[aCoder decodeObjectForKey:CPDateValueKey]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -642,23 +781,30 @@ var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
|||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
|
// Before encoding, we remove all subviews as we'll recreate them at loading
|
||||||
|
while ([[self subviews] count] > 0)
|
||||||
|
[[[self subviews] lastObject] removeFromSuperview];
|
||||||
|
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeDouble:_timeInterval forKey:CPIntervalKey];
|
[aCoder encodeDouble:_timeInterval forKey:CPIntervalKey];
|
||||||
[aCoder encodeInt:_datePickerMode forKey:CPDatePickerModeKey];
|
[aCoder encodeInt:_datePickerMode forKey:CPDatePickerModeKey];
|
||||||
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
|
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
|
||||||
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
|
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
|
||||||
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
|
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
|
||||||
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey]
|
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey];
|
||||||
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];;
|
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];
|
||||||
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
|
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
|
||||||
[aCoder encodeObject:_locale forKey:CPLocaleKey];
|
[aCoder encodeObject:_locale forKey:CPLocaleKey];
|
||||||
[aCoder encodeObject:_backgroundColor forKey:CPBackgroundColorKey];
|
[aCoder encodeObject:_backgroundColor forKey:CPBackgroundColorKey];
|
||||||
[aCoder encodeObject:_drawsBackground forKey:CPDrawsBackgroundKey];
|
[aCoder encodeObject:_drawsBackground forKey:CPDrawsBackgroundKey];
|
||||||
[aCoder encodeObject:_isBordered forKey:CPBorderedKey];
|
[aCoder encodeObject:_isBordered forKey:CPBorderedKey];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
// FIXME: add support for CPEditorRegistrationProtocol as implemented for CPTextField
|
||||||
@implementation _CPDatePickerValueBinder : CPBinder
|
@implementation _CPDatePickerValueBinder : CPBinder
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/* _CPDatePickerBox.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
|
||||||
|
@implementation _CPDatePickerBox : CPView
|
||||||
|
{
|
||||||
|
CPDatePicker _datePicker @accessors(property=datePicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
[super drawRect:aRect];
|
||||||
|
|
||||||
|
if ([_datePicker isCSSBased])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([_datePicker isBordered])
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
borderWidth = [_datePicker valueForThemeAttribute:@"border-width"] / 2;
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [_datePicker valueForThemeAttribute:@"border-color" inState:[_datePicker themeState]]);
|
||||||
|
CGContextSetLineWidth(context, [_datePicker valueForThemeAttribute:@"border-width"]);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, borderWidth, borderWidth);
|
||||||
|
CGContextAddLineToPoint(context, aRect.size.width - borderWidth, borderWidth);
|
||||||
|
CGContextAddLineToPoint(context, aRect.size.width - borderWidth, aRect.size.height - borderWidth);
|
||||||
|
CGContextAddLineToPoint(context, borderWidth, aRect.size.height - borderWidth);
|
||||||
|
CGContextAddLineToPoint(context, borderWidth,borderWidth);
|
||||||
|
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
if (aName === "bezel-view")
|
||||||
|
return [self bounds];
|
||||||
|
|
||||||
|
return [super rectForEphemeralSubviewNamed:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
if (aName === "bezel-view")
|
||||||
|
{
|
||||||
|
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[view setHitTests:NO];
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [super createEphemeralSubviewNamed:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if ([_datePicker isCSSBased])
|
||||||
|
{
|
||||||
|
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||||
|
positioned:CPWindowBelow
|
||||||
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
|
[bezelView setBackgroundColor:[_datePicker currentValueForThemeAttribute:@"bezel-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_datePicker drawsBackground])
|
||||||
|
[self setBackgroundColor:[_datePicker backgroundColor]];
|
||||||
|
else
|
||||||
|
[self setBackgroundColor:[CPColor clearColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,14 +20,18 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPKeyedArchiver.j>
|
||||||
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@import "CPImageView.j"
|
@import "CPImage.j"
|
||||||
@import "CALayer.j"
|
@import "CALayer.j"
|
||||||
|
|
||||||
|
|
||||||
@class _CPCibCustomResource
|
@class _CPCibCustomResource
|
||||||
@class CPDatePicker
|
@class CPDatePicker
|
||||||
|
@class HandImageLayer
|
||||||
|
@class HoursLayer
|
||||||
|
@class HandLayer
|
||||||
|
|
||||||
@global CPHourMinuteSecondDatePickerElementFlag
|
@global CPHourMinuteSecondDatePickerElementFlag
|
||||||
@global CPTextFieldAndStepperDatePickerStyle
|
@global CPTextFieldAndStepperDatePickerStyle
|
||||||
@@ -35,17 +39,35 @@
|
|||||||
|
|
||||||
var RADIANS = Math.PI / 180;
|
var RADIANS = Math.PI / 180;
|
||||||
|
|
||||||
|
@typedef _CPDatePickerClockHand
|
||||||
|
_CPDatePickerClockHours = 1;
|
||||||
|
_CPDatePickerClockMinutes = 2;
|
||||||
|
_CPDatePickerClockSeconds = 3;
|
||||||
|
|
||||||
@implementation _CPDatePickerClock : CPView
|
@implementation _CPDatePickerClock : CPControl
|
||||||
{
|
{
|
||||||
BOOL _isEnabled;
|
BOOL _isEnabled;
|
||||||
CALayer _rootLayer;
|
HoursLayer _rootLayer;
|
||||||
CALayer _hourHandLayer;
|
HandLayer _hourHandLayer;
|
||||||
CALayer _minuteHandLayer;
|
HandLayer _minuteHandLayer;
|
||||||
CALayer _secondHandLayer;
|
HandLayer _secondHandLayer;
|
||||||
CALayer _middleHandLayer;
|
CALayer _middleHandLayer;
|
||||||
CPDatePicker _datePicker;
|
CPDatePicker _datePicker;
|
||||||
CPTextField _PMAMTextField;
|
CPTextField _PMAMTextField;
|
||||||
|
|
||||||
|
CALayer _currentHandLayer;
|
||||||
|
_CPDatePickerClockHand _currentHand;
|
||||||
|
CPInteger _currentRepresentedValue;
|
||||||
|
float _currentValueShift;
|
||||||
|
CPInteger _numberOfUnits;
|
||||||
|
BOOL _trackingHand;
|
||||||
|
|
||||||
|
CPInteger _representedHours;
|
||||||
|
CPInteger _representedMinutes;
|
||||||
|
CPInteger _representedSeconds;
|
||||||
|
BOOL _representedHourIsPM;
|
||||||
|
|
||||||
|
CPInteger _datePickerElements @accessors(getter=datePickerElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -56,7 +78,9 @@ var RADIANS = Math.PI / 180;
|
|||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
{
|
{
|
||||||
_datePicker = aDatePicker;
|
_datePicker = aDatePicker;
|
||||||
|
_datePickerElements = [_datePicker datePickerElements];
|
||||||
|
_trackingHand = NO;
|
||||||
|
|
||||||
_PMAMTextField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
_PMAMTextField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
@@ -74,7 +98,7 @@ var RADIANS = Math.PI / 180;
|
|||||||
|
|
||||||
var middleHandSize = [_datePicker valueForThemeAttribute:@"middle-hand-size"],
|
var middleHandSize = [_datePicker valueForThemeAttribute:@"middle-hand-size"],
|
||||||
minuteHandSize = [_datePicker valueForThemeAttribute:@"minute-hand-size"],
|
minuteHandSize = [_datePicker valueForThemeAttribute:@"minute-hand-size"],
|
||||||
hourHandSize = [_datePicker valueForThemeAttribute:@"hour-hand-size"],
|
hourHandSize = [_datePicker valueForThemeAttribute:@"hour-hand-size"],
|
||||||
secondHandSize = [_datePicker valueForThemeAttribute:@"second-hand-size"];
|
secondHandSize = [_datePicker valueForThemeAttribute:@"second-hand-size"];
|
||||||
|
|
||||||
// We use layer to make the rotation possible
|
// We use layer to make the rotation possible
|
||||||
@@ -98,106 +122,132 @@ var RADIANS = Math.PI / 180;
|
|||||||
[_middleHandLayer setAnchorPoint:CGPointMakeZero()];
|
[_middleHandLayer setAnchorPoint:CGPointMakeZero()];
|
||||||
[_middleHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
[_middleHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
||||||
|
|
||||||
_rootLayer = [CALayer layer];
|
_rootLayer = [[HoursLayer alloc] init];
|
||||||
[self setWantsLayer:YES];
|
[self setWantsLayer:YES];
|
||||||
[self setLayer:_rootLayer];
|
[self setLayer:_rootLayer];
|
||||||
|
|
||||||
[_hourHandLayer setNeedsDisplay];
|
[self _initHands];
|
||||||
[_middleHandLayer setNeedsDisplay];
|
|
||||||
[_secondHandLayer setNeedsDisplay];
|
|
||||||
[_minuteHandLayer setNeedsDisplay];
|
|
||||||
|
|
||||||
[_rootLayer addSublayer:_hourHandLayer];
|
[_rootLayer addSublayer:_hourHandLayer];
|
||||||
[_rootLayer addSublayer:_minuteHandLayer];
|
[_rootLayer addSublayer:_minuteHandLayer];
|
||||||
[_rootLayer addSublayer:_secondHandLayer];
|
|
||||||
[_rootLayer addSublayer:_middleHandLayer];
|
|
||||||
|
|
||||||
|
if ([_datePicker valueForThemeAttribute:@"clock-second-hand-over"])
|
||||||
|
{
|
||||||
|
[_rootLayer addSublayer:_middleHandLayer];
|
||||||
|
[_rootLayer addSublayer:_secondHandLayer];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_rootLayer addSublayer:_secondHandLayer];
|
||||||
|
[_rootLayer addSublayer:_middleHandLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_rootLayer setDrawsHours:[_datePicker valueForThemeAttribute:@"clock-draws-hours"]];
|
||||||
[_rootLayer setNeedsDisplay];
|
[_rootLayer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_initHands
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Layout methods
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
{
|
||||||
if ([_datePicker datePickerStyle] == CPTextFieldAndStepperDatePickerStyle || [_datePicker datePickerStyle] == CPTextFieldDatePickerStyle)
|
var middleHandImage = [_datePicker currentValueForThemeAttribute:@"middle-hand-image"],
|
||||||
return;
|
hourHandImage = [_datePicker currentValueForThemeAttribute:@"hour-hand-image"],
|
||||||
|
minuteHandImage = [_datePicker currentValueForThemeAttribute:@"minute-hand-image"],
|
||||||
|
secondHandImage = [_datePicker currentValueForThemeAttribute:@"second-hand-image"];
|
||||||
|
|
||||||
[super layoutSubviews];
|
// If hand images are true CPImage, we have to duplicate them to avoid
|
||||||
|
// the multiple delegates bug when multiple clocks are displayed
|
||||||
|
|
||||||
var bounds = [self bounds],
|
if ([middleHandImage isKindOfClass:[CPImage class]])
|
||||||
dateValue = [[_datePicker dateValue] copy];
|
middleHandImage = [middleHandImage duplicate];
|
||||||
|
|
||||||
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
if ([hourHandImage isKindOfClass:[CPImage class]])
|
||||||
|
hourHandImage = [hourHandImage duplicate];
|
||||||
|
|
||||||
[self setBackgroundColor:[_datePicker currentValueForThemeAttribute:@"bezel-color-clock"]];
|
if ([minuteHandImage isKindOfClass:[CPImage class]])
|
||||||
[_middleHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"middle-hand-image"]];
|
minuteHandImage = [minuteHandImage duplicate];
|
||||||
[_hourHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"hour-hand-image"]];
|
|
||||||
[_minuteHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"minute-hand-image"]];
|
|
||||||
[_secondHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"second-hand-image"]];
|
|
||||||
|
|
||||||
if ([_datePicker _isEnglishFormat])
|
if ([secondHandImage isKindOfClass:[CPImage class]])
|
||||||
{
|
secondHandImage = [secondHandImage duplicate];
|
||||||
if (dateValue.getHours() > 11)
|
|
||||||
[_PMAMTextField setStringValue:@"PM"]
|
|
||||||
else
|
|
||||||
[_PMAMTextField setStringValue:@"AM"];
|
|
||||||
|
|
||||||
[_PMAMTextField sizeToFit];
|
[_middleHandLayer setImage:middleHandImage];
|
||||||
[_PMAMTextField setFrameOrigin:CGPointMake(bounds.size.width / 2 - [_PMAMTextField frameSize].width / 2, bounds.size.height / 2 + 15)];
|
[_hourHandLayer setImage:hourHandImage];
|
||||||
[_PMAMTextField setHidden:NO];
|
[_minuteHandLayer setImage:minuteHandImage];
|
||||||
}
|
[_secondHandLayer setImage:secondHandImage];
|
||||||
else
|
|
||||||
{
|
|
||||||
[_PMAMTextField setHidden:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_hourHandLayer setRotationRadians:[self _hourPositionRadianForDate:dateValue]];
|
[_hourHandLayer setNeedsDisplay];
|
||||||
[_minuteHandLayer setRotationRadians:[self _minutePositionRadianForDate:dateValue]];
|
[_middleHandLayer setNeedsDisplay];
|
||||||
[_secondHandLayer setRotationRadians:[self _secondPositionRadianForDate:dateValue]];
|
[_secondHandLayer setNeedsDisplay];
|
||||||
|
[_minuteHandLayer setNeedsDisplay];
|
||||||
|
|
||||||
[_PMAMTextField setEnabled:_isEnabled];
|
[_rootLayer setFont:[_datePicker currentValueForThemeAttribute:@"clock-hours-font"]];
|
||||||
[_hourHandLayer setEnabled:_isEnabled];
|
[_rootLayer setTextColor:[_datePicker currentValueForThemeAttribute:@"clock-hours-text-color"]];
|
||||||
[_middleHandLayer setEnabled:_isEnabled];
|
[_rootLayer setRadius:[_datePicker currentValueForThemeAttribute:@"clock-hours-radius"]];
|
||||||
[_secondHandLayer setEnabled:_isEnabled];
|
|
||||||
[_minuteHandLayer setEnabled:_isEnabled];
|
|
||||||
|
|
||||||
// Check if we have to display the hand second
|
|
||||||
if (([_datePicker datePickerElements] & CPHourMinuteSecondDatePickerElementFlag) == CPHourMinuteSecondDatePickerElementFlag)
|
|
||||||
[_secondHandLayer setHidden:NO];
|
|
||||||
else
|
|
||||||
[_secondHandLayer setHidden:YES];
|
|
||||||
|
|
||||||
[_rootLayer setNeedsDisplay];
|
[_rootLayer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||||
|
{
|
||||||
|
_datePickerElements = aDatePickerElements;
|
||||||
|
|
||||||
|
// Check if we have to display the hand second
|
||||||
|
// FIXME: Don't know why but next line will cause theme compilation to fail...
|
||||||
|
// Workaround: added "if PLATFORM(DOM)"
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
[_secondHandLayer setHidden:!((_datePickerElements & CPHourMinuteSecondDatePickerElementFlag) == CPHourMinuteSecondDatePickerElementFlag)];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
// While tracking a hand, we don't want the whole thing to be relayouted at each mouse movement
|
||||||
|
if (_trackingHand)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self setBackgroundColor:[_datePicker currentValueForThemeAttribute:@"bezel-color-clock"]];
|
||||||
|
|
||||||
|
var dateValue = [[_datePicker dateValue] copy];
|
||||||
|
|
||||||
|
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||||
|
|
||||||
|
_representedHours = dateValue.getHours();
|
||||||
|
_representedMinutes = dateValue.getMinutes();
|
||||||
|
_representedSeconds = dateValue.getSeconds();
|
||||||
|
_representedHourIsPM = (_representedHours > 11);
|
||||||
|
|
||||||
|
// Hours are expressed in 24 hours format, we need 12 hours format
|
||||||
|
_representedHours -= (_representedHourIsPM ? 12 : 0);
|
||||||
|
|
||||||
|
[self _updateHands];
|
||||||
|
|
||||||
|
// FIXME: Workaround. Seems that CALayer doesn't redraw without an event
|
||||||
|
[CALayer runLoopUpdateLayers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateHands
|
||||||
|
{
|
||||||
|
var bounds = [self bounds];
|
||||||
|
|
||||||
|
[_PMAMTextField setStringValue:_representedHourIsPM ? @"PM" : @"AM"];
|
||||||
|
[_PMAMTextField sizeToFit];
|
||||||
|
[_PMAMTextField setFrameOrigin:CGPointMake(bounds.size.width / 2 - [_PMAMTextField frameSize].width / 2, bounds.size.height / 2 + 15)];
|
||||||
|
|
||||||
|
[_hourHandLayer setRotationRadians:(360 * (_representedHours + _representedMinutes / 60) / 12) * RADIANS];
|
||||||
|
[_minuteHandLayer setRotationRadians:(360 * (_representedMinutes + _representedSeconds / 60) / 60) * RADIANS];
|
||||||
|
[_secondHandLayer setRotationRadians:(360 * _representedSeconds / 60) * RADIANS];
|
||||||
|
|
||||||
|
[_hourHandLayer setNeedsDisplay];
|
||||||
|
[_minuteHandLayer setNeedsDisplay];
|
||||||
|
[_secondHandLayer setNeedsDisplay];
|
||||||
|
// [_middleHandLayer setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Accessors
|
#pragma mark Accessors
|
||||||
|
|
||||||
- (float)_hourPositionRadianForDate:(CPDate)aDate
|
|
||||||
{
|
|
||||||
var hours = aDate.getHours() + aDate.getMinutes() / 60;
|
|
||||||
|
|
||||||
return (360 * hours / 12) * RADIANS;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (float)_secondPositionRadianForDate:(CPDate)aDate
|
|
||||||
{
|
|
||||||
return (360 * aDate.getSeconds() / 60) * RADIANS;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (float)_minutePositionRadianForDate:(CPDate)aDate
|
|
||||||
{
|
|
||||||
var minutes = aDate.getMinutes() + aDate.getSeconds() / 60;
|
|
||||||
|
|
||||||
return (360 * minutes / 60) * RADIANS;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setEnabled:(BOOL)shouldEnable
|
- (void)setEnabled:(BOOL)shouldEnable
|
||||||
{
|
{
|
||||||
shouldEnable = !!shouldEnable;
|
shouldEnable = !!shouldEnable;
|
||||||
@@ -206,36 +256,191 @@ var RADIANS = Math.PI / 180;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_isEnabled = shouldEnable;
|
_isEnabled = shouldEnable;
|
||||||
[self setNeedsLayout];
|
|
||||||
|
|
||||||
// FIXME: This is a workaround for an apparent bug in CALayer.
|
[self _initHands];
|
||||||
// Without pumping the event loop, the sublayers of _rootLayer
|
[self setNeedsLayout];
|
||||||
// (the hands) are not redrawn until an event occurs.
|
}
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
|
||||||
|
#pragma mark Mouse actions
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (!_isEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
|
if ([_secondHandLayer handIsHitAtPoint:currentLocation])
|
||||||
|
{
|
||||||
|
_currentHandLayer = _secondHandLayer;
|
||||||
|
_currentHand = _CPDatePickerClockSeconds;
|
||||||
|
_currentRepresentedValue = _representedSeconds;
|
||||||
|
_currentValueShift = 0;
|
||||||
|
_numberOfUnits = 60;
|
||||||
|
}
|
||||||
|
else if ([_minuteHandLayer handIsHitAtPoint:currentLocation])
|
||||||
|
{
|
||||||
|
_currentHandLayer = _minuteHandLayer;
|
||||||
|
_currentHand = _CPDatePickerClockMinutes;
|
||||||
|
_currentRepresentedValue = _representedMinutes;
|
||||||
|
_currentValueShift = _representedSeconds / 60;
|
||||||
|
_numberOfUnits = 60;
|
||||||
|
}
|
||||||
|
else if ([_hourHandLayer handIsHitAtPoint:currentLocation])
|
||||||
|
{
|
||||||
|
_currentHandLayer = _hourHandLayer;
|
||||||
|
_currentHand = _CPDatePickerClockHours;
|
||||||
|
_currentRepresentedValue = _representedHours;
|
||||||
|
_currentValueShift = _representedMinutes / 60;
|
||||||
|
_numberOfUnits = 12;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentHandLayer = nil;
|
||||||
|
_currentHand = CPNotFound;
|
||||||
|
_currentRepresentedValue = CPNotFound;
|
||||||
|
_currentValueShift = CPNotFound;
|
||||||
|
_numberOfUnits = CPNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentHandLayer)
|
||||||
|
[self trackMouse:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tracksMouseOutsideOfFrame
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
_trackingHand = YES;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var dx = aPoint.x -_bounds.size.width / 2,
|
||||||
|
dy = _bounds.size.height / 2 - aPoint.y,
|
||||||
|
angle = (PI_2 - ATAN2(dy,dx) + PI2) % PI2,
|
||||||
|
value = ROUND(angle * _numberOfUnits / PI2 - _currentValueShift) % _numberOfUnits;
|
||||||
|
|
||||||
|
if (value !== _currentRepresentedValue)
|
||||||
|
{
|
||||||
|
var movedForward = (_currentRepresentedValue > _numberOfUnits * 3/4) && (value < _numberOfUnits / 4),
|
||||||
|
movedBackward = (_currentRepresentedValue < _numberOfUnits / 4) && (value > _numberOfUnits * 3/4),
|
||||||
|
dateValue = [[_datePicker dateValue] copy];
|
||||||
|
|
||||||
|
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||||
|
|
||||||
|
switch (_currentHand)
|
||||||
|
{
|
||||||
|
case _CPDatePickerClockHours:
|
||||||
|
|
||||||
|
if (movedForward || movedBackward)
|
||||||
|
{
|
||||||
|
_representedHourIsPM = !_representedHourIsPM;
|
||||||
|
|
||||||
|
if (movedForward && !_representedHourIsPM)
|
||||||
|
// Day++
|
||||||
|
dateValue.setDate(dateValue.getDate() + 1);
|
||||||
|
|
||||||
|
else if (movedBackward && _representedHourIsPM)
|
||||||
|
// Day--
|
||||||
|
dateValue.setDate(dateValue.getDate() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dateValue.setHours(value + (_representedHourIsPM ? 12 : 0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _CPDatePickerClockMinutes:
|
||||||
|
|
||||||
|
if (movedForward)
|
||||||
|
// Hours++
|
||||||
|
dateValue.setHours(dateValue.getHours() + 1);
|
||||||
|
|
||||||
|
else if (movedBackward)
|
||||||
|
// Hours--
|
||||||
|
dateValue.setHours(dateValue.getHours() - 1);
|
||||||
|
|
||||||
|
dateValue.setMinutes(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _CPDatePickerClockSeconds:
|
||||||
|
|
||||||
|
if (movedForward)
|
||||||
|
// Minutes++
|
||||||
|
dateValue.setMinutes(dateValue.getMinutes() + 1);
|
||||||
|
|
||||||
|
else if (movedBackward)
|
||||||
|
// Minutes--
|
||||||
|
dateValue.setMinutes(dateValue.getMinutes() - 1);
|
||||||
|
|
||||||
|
dateValue.setSeconds(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = YES;
|
||||||
|
#endif
|
||||||
|
[_datePicker _setDateValue:dateValue timeInterval:[_datePicker timeInterval]];
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = NO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We have to adapt represented values
|
||||||
|
_representedHours = dateValue.getHours();
|
||||||
|
_representedMinutes = dateValue.getMinutes();
|
||||||
|
_representedSeconds = dateValue.getSeconds();
|
||||||
|
_representedHourIsPM = (_representedHours > 11);
|
||||||
|
|
||||||
|
// Hours are expressed in 24 hours format, we need 12 hours format
|
||||||
|
_representedHours -= (_representedHourIsPM ? 12 : 0);
|
||||||
|
|
||||||
|
switch (_currentHand) {
|
||||||
|
case _CPDatePickerClockHours:
|
||||||
|
_currentRepresentedValue = _representedHours;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _CPDatePickerClockMinutes:
|
||||||
|
_currentRepresentedValue = _representedMinutes;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _CPDatePickerClockSeconds:
|
||||||
|
_currentRepresentedValue = _representedSeconds;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _updateHands];
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||||
|
{
|
||||||
|
_trackingHand = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
@implementation HandLayer : CALayer
|
@implementation HandLayer : CALayer
|
||||||
{
|
{
|
||||||
BOOL _isEnabled @accessors(setter=setEnabled:, getter=isEnabled);
|
CPImage _image;
|
||||||
|
HandImageLayer _imageLayer;
|
||||||
CPImage _image;
|
float _rotationRadians;
|
||||||
CALayer _imageLayer;
|
|
||||||
float _rotationRadians;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Init methods
|
#pragma mark Init methods
|
||||||
|
|
||||||
- (id)initWithSize:(CGSize)aSize
|
- (id)initWithSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
{
|
{
|
||||||
_isEnabled = YES;
|
_imageLayer = [HandImageLayer layer];
|
||||||
_imageLayer = [CALayer layer];
|
|
||||||
_rotationRadians = 0;
|
_rotationRadians = 0;
|
||||||
|
|
||||||
[_imageLayer setDelegate:self];
|
[_imageLayer setDelegate:self];
|
||||||
@@ -248,7 +453,6 @@ var RADIANS = Math.PI / 180;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Setter Getter methods
|
#pragma mark Setter Getter methods
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -286,18 +490,6 @@ var RADIANS = Math.PI / 180;
|
|||||||
1.0, 1.0)];
|
1.0, 1.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setEnabled:(BOOL)shouldEnable
|
|
||||||
{
|
|
||||||
shouldEnable = !!shouldEnable;
|
|
||||||
|
|
||||||
if (_isEnabled === shouldEnable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_isEnabled = shouldEnable;
|
|
||||||
[self setNeedsDisplay];
|
|
||||||
[_imageLayer setNeedsDisplay];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)imageDidLoad:(CPImage)anImage
|
- (void)imageDidLoad:(CPImage)anImage
|
||||||
{
|
{
|
||||||
[_imageLayer setNeedsDisplay];
|
[_imageLayer setNeedsDisplay];
|
||||||
@@ -311,4 +503,109 @@ var RADIANS = Math.PI / 180;
|
|||||||
CGContextDrawImage(aContext, [aLayer bounds], _image);
|
CGContextDrawImage(aContext, [aLayer bounds], _image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)handIsHitAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
return (!_isHidden && [_imageLayer hitTest:aPoint] === _imageLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setNeedsDisplay
|
||||||
|
{
|
||||||
|
[super setNeedsDisplay];
|
||||||
|
[_imageLayer setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation HandImageLayer : CALayer
|
||||||
|
{
|
||||||
|
CGRect _handBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to adapt hitTest so it only takes the hand into account (that's the top half of the image layer)
|
||||||
|
// We are also sure there's no sublayers
|
||||||
|
- (CALayer)hitTest:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
if (_isHidden)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
var point = CGPointApplyAffineTransform(aPoint, _transformToLayer);
|
||||||
|
|
||||||
|
return CGRectContainsPoint(_handBounds, point) ? self : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBounds:(CGRect)aBounds
|
||||||
|
{
|
||||||
|
if (CGRectEqualToRect(_bounds, aBounds))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_handBounds = CGRectMakeCopy(aBounds);
|
||||||
|
|
||||||
|
_handBounds.size.height = _handBounds.size.height / 2;
|
||||||
|
|
||||||
|
[super setBounds:aBounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation HoursLayer : CALayer
|
||||||
|
{
|
||||||
|
BOOL _drawsHours;
|
||||||
|
|
||||||
|
CPFont _font @accessors(property=font);
|
||||||
|
CPColor _textColor @accessors(property=textColor);
|
||||||
|
float _radius @accessors(property=radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_drawsHours = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDrawsHours:(BOOL)shouldDrawHours
|
||||||
|
{
|
||||||
|
shouldDrawHours = !!shouldDrawHours;
|
||||||
|
|
||||||
|
if (_drawsHours === shouldDrawHours)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_drawsHours = shouldDrawHours;
|
||||||
|
[self setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawInContext:(CGContext)aContext
|
||||||
|
{
|
||||||
|
[super drawInContext:aContext];
|
||||||
|
|
||||||
|
if (_drawsHours)
|
||||||
|
{
|
||||||
|
var bounds = [self bounds],
|
||||||
|
centerX = bounds.size.width / 2,
|
||||||
|
centerY = bounds.size.height / 2;
|
||||||
|
|
||||||
|
CGContextSelectFont(aContext, _font);
|
||||||
|
CGContextSetFillColor(aContext, _textColor);
|
||||||
|
aContext.textBaseline = @"middle";
|
||||||
|
aContext.textAlign = @"center";
|
||||||
|
|
||||||
|
for (var i = 1, angle = 60.0, x, y; i < 13; i++, angle -= 30.0)
|
||||||
|
{
|
||||||
|
x = centerX + _radius * COS(angle * RADIANS);
|
||||||
|
y = centerY - _radius * SIN(angle * RADIANS);
|
||||||
|
|
||||||
|
aContext.fillText(i, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -0,0 +1,280 @@
|
|||||||
|
/* _CPDatePickerDayView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
|
||||||
|
@import "_CPDatePickerDayViewTextField.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
|
||||||
|
@implementation _CPDatePickerDayView : CPControl
|
||||||
|
{
|
||||||
|
CPDate _date @accessors(property=date);
|
||||||
|
|
||||||
|
BOOL _isDisabled;
|
||||||
|
BOOL _isHighlighted;
|
||||||
|
BOOL _isSelected;
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
CPTextField _textField;
|
||||||
|
|
||||||
|
CPInteger _dayInWeek @accessors(property=dayInWeek);
|
||||||
|
BOOL _firstSelected @accessors(property=firstSelected);
|
||||||
|
BOOL _lastSelected @accessors(property=lastSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
/*! Create a new instance of _CPDatePickerDayView
|
||||||
|
@param aFrame
|
||||||
|
@param aDatePicker
|
||||||
|
@return a new instance of _CPDatePickerDayView
|
||||||
|
*/
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame withDatePicker:(CPDatePicker)aDatePicker
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
[self setHitTests:NO];
|
||||||
|
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
|
||||||
|
// FIXME: Beginning with Aristo3, the text field is directly themed based on a new class _CPDatePickerDayViewTextField
|
||||||
|
if ([self isCSSBased])
|
||||||
|
{
|
||||||
|
_textField = [[_CPDatePickerDayViewTextField alloc] initWithFrame:aFrame];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_textField = [[CPTextField alloc] initWithFrame:aFrame];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-alignment"] forThemeAttribute:@"alignment"];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-vertical-alignment"] forThemeAttribute:@"vertical-alignment"];
|
||||||
|
|
||||||
|
var contentInset = [_datePicker valueForThemeAttribute:@"tile-content-inset"];
|
||||||
|
|
||||||
|
if (contentInset)
|
||||||
|
[_textField setValue:contentInset forThemeAttribute:@"content-inset"];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateNormal] forThemeAttribute:@"font" inState:CPThemeStateNormal];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-color" inState:CPThemeStateNormal];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateNormal];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateNormal];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateSelected] forThemeAttribute:@"font" inState:CPThemeStateSelected];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateSelected] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateSelected] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateSelected];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateSelected] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateSelected];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateDisabled] forThemeAttribute:@"font" inState:CPThemeStateDisabled];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateHighlighted] forThemeAttribute:@"font" inState:CPThemeStateHighlighted];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateHighlighted];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateHighlighted];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||||
|
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||||
|
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self addSubview:_textField];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Theme methods
|
||||||
|
|
||||||
|
/*! Set a theme
|
||||||
|
*/
|
||||||
|
- (BOOL)setThemeState:(ThemeState)aState
|
||||||
|
{
|
||||||
|
[_textField setThemeState:aState];
|
||||||
|
[super setThemeState:aState];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unset a theme
|
||||||
|
*/
|
||||||
|
- (BOOL)unsetThemeState:(ThemeState)aState
|
||||||
|
{
|
||||||
|
[_textField unsetThemeState:aState];
|
||||||
|
[super unsetThemeState:aState];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Getter methods
|
||||||
|
|
||||||
|
/*! Select the tile
|
||||||
|
*/
|
||||||
|
- (void)setSelected:(BOOL)shouldBeSelected
|
||||||
|
{
|
||||||
|
if (_isSelected === shouldBeSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isSelected = shouldBeSelected;
|
||||||
|
|
||||||
|
if (_isSelected)
|
||||||
|
[self setThemeState:CPThemeStateSelected];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateSelected];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Disabled the tile (used for previous and next month tile)
|
||||||
|
*/
|
||||||
|
- (void)setDisabled:(BOOL)shouldBeDisabled
|
||||||
|
{
|
||||||
|
if (_isDisabled === shouldBeDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isDisabled = shouldBeDisabled;
|
||||||
|
|
||||||
|
if (_isDisabled)
|
||||||
|
[self setThemeState:CPThemeStateDisabled];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateDisabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isDisabled
|
||||||
|
{
|
||||||
|
return _isDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Highlight the tile (used for current day)
|
||||||
|
*/
|
||||||
|
- (void)setHighlighted:(BOOL)shouldBeHighlighted
|
||||||
|
{
|
||||||
|
if (_isHighlighted === shouldBeHighlighted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isHighlighted = shouldBeHighlighted;
|
||||||
|
|
||||||
|
if (_isHighlighted)
|
||||||
|
[self setThemeState:CPThemeStateHighlighted];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the stringValue of the tile
|
||||||
|
@param aStringValue
|
||||||
|
*/
|
||||||
|
- (void)setStringValue:(CPString)aStringValue
|
||||||
|
{
|
||||||
|
[_textField setStringValue:aStringValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
/*! Layout the subviews
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if ([_datePicker isCSSBased])
|
||||||
|
{
|
||||||
|
var attributeName = @"bezel-color-calendar";
|
||||||
|
|
||||||
|
if (_isSelected)
|
||||||
|
{
|
||||||
|
if (_firstSelected && !_lastSelected)
|
||||||
|
attributeName = @"bezel-color-calendar-left";
|
||||||
|
else if (_lastSelected && !_firstSelected)
|
||||||
|
attributeName = @"bezel-color-calendar-right";
|
||||||
|
else if (!_firstSelected && !_lastSelected)
|
||||||
|
{
|
||||||
|
if (_dayInWeek == 0)
|
||||||
|
attributeName = @"bezel-color-calendar-left";
|
||||||
|
else if (_dayInWeek == 6)
|
||||||
|
attributeName = @"bezel-color-calendar-right";
|
||||||
|
else
|
||||||
|
attributeName = @"bezel-color-calendar-middle";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setBackgroundColor:[_datePicker valueForThemeAttribute:attributeName inState:[self themeState]]];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = [self bounds];
|
||||||
|
[_textField sizeToFit];
|
||||||
|
[_textField setFrameOrigin:CGPointMake(bounds.size.width / 2 - [_textField frameSize].width / 2 + [_datePicker valueForThemeAttribute:@"border-width"], bounds.size.height / 2 - [_textField frameSize].height / 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
[super setFrame:aFrame];
|
||||||
|
[_textField setFrame:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Drawrect
|
||||||
|
*/
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
[super drawRect:aRect];
|
||||||
|
|
||||||
|
if ([_datePicker isCSSBased])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var themeState = [self themeState],
|
||||||
|
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
if (themeState.hasThemeState(CPThemeStateSelected))
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:[_datePicker valueForThemeAttribute:@"bezel-color-calendar" inState:themeState]];
|
||||||
|
CGContextSetLineWidth(context, [_datePicker valueForThemeAttribute:@"border-width"]);
|
||||||
|
CGContextSetStrokeColor(context, [_datePicker valueForThemeAttribute:@"border-color" inState:themeState]);
|
||||||
|
CGContextAddRect(context, [self bounds]);
|
||||||
|
CGContextStrokeRect(context, [self bounds]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clear color, because the original color of a tile is handle by his superview
|
||||||
|
[self setBackgroundColor:[CPColor clearColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* _CPDatePickerDayViewTextField.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
|
||||||
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
@implementation _CPDatePickerDayViewTextField : CPTextField
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"datePickerDayViewTextField";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"min-size": CGSizeMakeZero(),
|
||||||
|
@"content-inset": CGInsetMakeZero(),
|
||||||
|
@"text-color": [CPColor blackColor],
|
||||||
|
@"text-shadow-color": [CPColor clearColor],
|
||||||
|
@"text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"font": [CPNull null],
|
||||||
|
@"vertical-alignment": CPCenterVerticalTextAlignment,
|
||||||
|
@"alignment": CPCenterTextAlignment,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@@ -0,0 +1,589 @@
|
|||||||
|
/* _CPDatePickerElementTextField.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
@class _CPDatePickerElementView
|
||||||
|
|
||||||
|
CPDatePickerElementTextFieldBecomeFirstResponder = @"CPDatePickerElementTextFieldBecomeFirstResponder";
|
||||||
|
CPDatePickerElementTextFieldAMPMChangedNotification = @"CPDatePickerElementTextFieldAMPMChangedNotification";
|
||||||
|
|
||||||
|
var CPZeroKeyCode = 48,
|
||||||
|
CPNineKeyCode = 57,
|
||||||
|
CPMajAKeyCode = 65,
|
||||||
|
CPMajPKeyCode = 80,
|
||||||
|
CPAKeyCode = 97,
|
||||||
|
CPPKeyCode = 112;
|
||||||
|
|
||||||
|
CPMonthDateType = 0;
|
||||||
|
CPDayDateType = 1;
|
||||||
|
CPYearDateType = 2;
|
||||||
|
CPHourDateType = 3;
|
||||||
|
CPSecondDateType = 4;
|
||||||
|
CPMinuteDateType = 5;
|
||||||
|
CPAMPMDateType = 6;
|
||||||
|
|
||||||
|
/*! An element textField
|
||||||
|
*/
|
||||||
|
@implementation _CPDatePickerElementTextField : CPTextField
|
||||||
|
{
|
||||||
|
_CPDatePickerElementTextField _nextTextField @accessors(property=nextTextField);
|
||||||
|
_CPDatePickerElementTextField _previousTextField @accessors(property=previousTextField);
|
||||||
|
_CPDatePickerElementView _datePickerElementView @accessors(property=datePickerElementView);
|
||||||
|
|
||||||
|
CPDatePicker _datePicker @accessors(setter=setDatePicker:);
|
||||||
|
|
||||||
|
int _dateType @accessors(getter=dateType);
|
||||||
|
int _maxNumber @accessors(getter=maxNumber);
|
||||||
|
int _minNumber @accessors(getter=minNumber);
|
||||||
|
|
||||||
|
BOOL _firstEvent;
|
||||||
|
CPTimer _timerEdition;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"datePickerElementTextField";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
|
||||||
|
@"bezel-color": [CPNull null],
|
||||||
|
@"min-size": CGSizeMakeZero()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_firstEvent = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return [_datePicker isEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the dateType of the textField
|
||||||
|
*/
|
||||||
|
- (void)setDateType:(int)aDateType
|
||||||
|
{
|
||||||
|
_dateType = aDateType;
|
||||||
|
|
||||||
|
switch (aDateType)
|
||||||
|
{
|
||||||
|
case CPMonthDateType:
|
||||||
|
_minNumber = 1;
|
||||||
|
_maxNumber = 12;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPDayDateType:
|
||||||
|
_minNumber = 1;
|
||||||
|
_maxNumber = 31;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPYearDateType:
|
||||||
|
_minNumber = 0;
|
||||||
|
_maxNumber = 9999;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPHourDateType:
|
||||||
|
_minNumber = 0;
|
||||||
|
_maxNumber = 23;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSecondDateType:
|
||||||
|
_minNumber = 0;
|
||||||
|
_maxNumber = 59;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMinuteDateType:
|
||||||
|
_minNumber = 0;
|
||||||
|
_maxNumber = 59;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the maxNumber of the textField
|
||||||
|
*/
|
||||||
|
- (int)maxNumber
|
||||||
|
{
|
||||||
|
if (_dateType == CPDayDateType)
|
||||||
|
return [[_datePicker dateValue] _daysInMonth];
|
||||||
|
|
||||||
|
return _maxNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the maxNumber of the textField depending of the maxDate
|
||||||
|
*/
|
||||||
|
- (int)_maxNumberWithMaxDate
|
||||||
|
{
|
||||||
|
var maxDate = [_datePicker maxDate],
|
||||||
|
date = [_datePicker dateValue];
|
||||||
|
|
||||||
|
if (maxDate)
|
||||||
|
{
|
||||||
|
switch (_dateType)
|
||||||
|
{
|
||||||
|
case CPMonthDateType:
|
||||||
|
if (maxDate.getFullYear() == date.getFullYear())
|
||||||
|
return maxDate.getMonth();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPDayDateType:
|
||||||
|
if (maxDate.getFullYear() == date.getFullYear() && maxDate.getMonth() == date.getMonth())
|
||||||
|
return maxDate.getDate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPYearDateType:
|
||||||
|
return maxDate.getFullYear();
|
||||||
|
|
||||||
|
case CPHourDateType:
|
||||||
|
if (maxDate.getFullYear() == date.getFullYear() && maxDate.getMonth() == date.getMonth() && maxDate.getDate() == date.getDate())
|
||||||
|
return maxDate.getHours();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSecondDateType:
|
||||||
|
if (maxDate.getFullYear() == date.getFullYear() && maxDate.getMonth() == date.getMonth() && maxDate.getDate() == date.getDate() && maxDate.getHours() == date.getHours() && maxDate.getMinutes() == date.getMinutes())
|
||||||
|
return maxDate.getSeconds();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMinuteDateType:
|
||||||
|
if (maxDate.getFullYear() == date.getFullYear() && maxDate.getMonth() == date.getMonth() && maxDate.getDate() == date.getDate() && maxDate.getHours() == date.getHours())
|
||||||
|
return maxDate.getMinutes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _maxNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the stringValue of the textField. This is going to check if there is 2 or 4 letters. If not it adds a space. Check also the maxDate
|
||||||
|
It's called when the user is editing with the keyboard
|
||||||
|
@param aStringValue a CPString
|
||||||
|
*/
|
||||||
|
- (void)setValueForKeyEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var keyCode = [anEvent keyCode];
|
||||||
|
|
||||||
|
if (keyCode != CPDeleteKeyCode && keyCode != CPDeleteForwardKeyCode && keyCode < CPZeroKeyCode || keyCode > CPNineKeyCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newValue = [self stringValue].replace(/\s/g, ''),
|
||||||
|
length = [newValue length],
|
||||||
|
eventKeyValue = parseInt([anEvent characters]).toString();
|
||||||
|
|
||||||
|
if (keyCode == CPDeleteKeyCode || keyCode == CPDeleteForwardKeyCode)
|
||||||
|
{
|
||||||
|
[_timerEdition invalidate];
|
||||||
|
_timerEdition = nil;
|
||||||
|
newValue = [newValue substringToIndex:(length - 1)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_timerEdition)
|
||||||
|
{
|
||||||
|
_timerEdition = [CPTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(_timerKeyEvent:) userInfo:nil repeats:NO];
|
||||||
|
|
||||||
|
if (_firstEvent || !length)
|
||||||
|
newValue = eventKeyValue;
|
||||||
|
else
|
||||||
|
newValue = parseInt(newValue).toString() + eventKeyValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newFireDate = [CPDate date];
|
||||||
|
|
||||||
|
newFireDate.setSeconds(newFireDate.getSeconds() + 2);
|
||||||
|
[_timerEdition setFireDate:newFireDate];
|
||||||
|
|
||||||
|
newValue = parseInt(newValue).toString() + eventKeyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseInt(newValue) > [self _maxNumberWithMaxDate] || ([_datePicker _isAmericanFormat] && _dateType == CPHourDateType && parseInt(newValue) > 12))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_firstEvent = NO;
|
||||||
|
|
||||||
|
[super setObjectValue:newValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
End of the timer
|
||||||
|
*/
|
||||||
|
- (void)_timerKeyEvent:(id)sender
|
||||||
|
{
|
||||||
|
var stringValue = [self stringValue];
|
||||||
|
|
||||||
|
_timerEdition = nil;
|
||||||
|
|
||||||
|
if ([stringValue length])
|
||||||
|
{
|
||||||
|
if ([_datePicker _isAmericanFormat] && [self dateType] == CPHourDateType)
|
||||||
|
{
|
||||||
|
var isAMHour = [[self superview] _isAMHour];
|
||||||
|
|
||||||
|
if (!isAMHour && stringValue != 12)
|
||||||
|
stringValue = parseInt(stringValue) + 12;
|
||||||
|
|
||||||
|
if (stringValue == 12 && !isAMHour)
|
||||||
|
stringValue = 12;
|
||||||
|
else if (stringValue == 12)
|
||||||
|
stringValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setObjectValue:stringValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
We force to end the timer
|
||||||
|
*/
|
||||||
|
- (void)_invalidTimer
|
||||||
|
{
|
||||||
|
if (_timerEdition)
|
||||||
|
{
|
||||||
|
[_timerEdition invalidate];
|
||||||
|
_timerEdition = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
We force to end the timer and to update the objectValue of the datePicker
|
||||||
|
*/
|
||||||
|
- (void)_endEditing
|
||||||
|
{
|
||||||
|
if (_timerEdition)
|
||||||
|
[_timerEdition invalidate];
|
||||||
|
|
||||||
|
_timerEdition = nil;
|
||||||
|
|
||||||
|
var objectValue = [self stringValue];
|
||||||
|
|
||||||
|
if (![objectValue length])
|
||||||
|
objectValue = [self objectValue];
|
||||||
|
|
||||||
|
if ([_datePicker _isAmericanFormat] && [self dateType] == CPHourDateType)
|
||||||
|
{
|
||||||
|
var isAMHour = [[self superview] _isAMHour];
|
||||||
|
|
||||||
|
if (!isAMHour && objectValue != 12)
|
||||||
|
objectValue = parseInt(objectValue) + 12;
|
||||||
|
|
||||||
|
if (objectValue == 12 && !isAMHour)
|
||||||
|
objectValue = 12;
|
||||||
|
else if (objectValue == 12)
|
||||||
|
objectValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setObjectValue:objectValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the stringValue of the TextField. Add some zeros of there isn't 2/4 letters in the value. It's called at the end of the editing process
|
||||||
|
@param aStringValue a CPString
|
||||||
|
*/
|
||||||
|
- (void)setStringValue:(CPString)aStringValue
|
||||||
|
{
|
||||||
|
if (_dateType == CPYearDateType)
|
||||||
|
{
|
||||||
|
while ([aStringValue length] < 4)
|
||||||
|
aStringValue = "0" + aStringValue;
|
||||||
|
}
|
||||||
|
else if (_dateType != CPAMPMDateType)
|
||||||
|
{
|
||||||
|
if (_dateType == CPHourDateType && [_datePicker _isAmericanFormat])
|
||||||
|
{
|
||||||
|
var value = parseInt(aStringValue);
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
value = 12;
|
||||||
|
else if (value > 12)
|
||||||
|
value = value - 12;
|
||||||
|
|
||||||
|
aStringValue = value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
while ([aStringValue length] < 2)
|
||||||
|
{
|
||||||
|
if (_dateType == CPSecondDateType || _dateType == CPMinuteDateType)
|
||||||
|
aStringValue = @"0" + aStringValue;
|
||||||
|
else
|
||||||
|
aStringValue = @" " + aStringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:aStringValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the objectValue. This will update the dateValue of the datePicker also. It's called with the binding of the stepper or arrows
|
||||||
|
This is not going to update the objectValue of the control !!! It updates the dateValue of the datePicker who's going to update the datePickerTextField if necessary
|
||||||
|
It's a bit tricky
|
||||||
|
@param aObjectValue
|
||||||
|
*/
|
||||||
|
- (void)setObjectValue:(id)anObjectValue
|
||||||
|
{
|
||||||
|
var dateValue = [[_datePicker dateValue] copy],
|
||||||
|
lengthString = [[self stringValue] length],
|
||||||
|
objectValue = parseInt(anObjectValue);
|
||||||
|
|
||||||
|
switch (_dateType)
|
||||||
|
{
|
||||||
|
case CPMonthDateType:
|
||||||
|
|
||||||
|
if (objectValue == 0 || !lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:(dateValue.getMonth() + 1).toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dateNextMonth = [dateValue copy];
|
||||||
|
|
||||||
|
dateNextMonth.setDate(1);
|
||||||
|
dateNextMonth.setMonth(parseInt(anObjectValue) - 1);
|
||||||
|
|
||||||
|
var numberDayNextMonth = [dateNextMonth _daysInMonth];
|
||||||
|
|
||||||
|
if (numberDayNextMonth < [dateValue _daysInMonth] && dateValue.getDate() > numberDayNextMonth)
|
||||||
|
[_datePickerElementView setDayDateValue:numberDayNextMonth.toString()];
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPDayDateType:
|
||||||
|
|
||||||
|
if (objectValue == 0 || !lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:dateValue.getDate().toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we enter a day that is too high for the current month
|
||||||
|
// we need to increase the month by one
|
||||||
|
// if we do not do this, the user input would be silently reset
|
||||||
|
// very poor user experience
|
||||||
|
|
||||||
|
if (parseInt(anObjectValue, 10) > [dateValue _daysInMonth])
|
||||||
|
{
|
||||||
|
[_datePickerElementView._textFieldMonth setIntValue:(dateValue.getMonth() + 2)];
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPYearDateType:
|
||||||
|
|
||||||
|
if (objectValue == 0 || !lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:dateValue.getFullYear().toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPHourDateType:
|
||||||
|
|
||||||
|
if (!lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:dateValue.getHours().toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSecondDateType:
|
||||||
|
|
||||||
|
if (!lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:dateValue.getSeconds().toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMinuteDateType:
|
||||||
|
|
||||||
|
if (!lengthString)
|
||||||
|
{
|
||||||
|
[self setStringValue:dateValue.getMinutes().toString()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super setObjectValue:objectValue];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newDateValue = [_datePickerElementView dateValue],
|
||||||
|
timeZone = [_datePicker timeZone];
|
||||||
|
|
||||||
|
if (timeZone)
|
||||||
|
{
|
||||||
|
var secondsFromGMT = [timeZone secondsFromGMTForDate:newDateValue],
|
||||||
|
secondsFromGMTTimeZone = [timeZone secondsFromGMT];
|
||||||
|
|
||||||
|
newDateValue.setSeconds(newDateValue.getSeconds() + secondsFromGMT - secondsFromGMTTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = YES;
|
||||||
|
#endif
|
||||||
|
[_datePicker _setDateValue:newDateValue timeInterval:[_datePicker timeInterval]];
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = NO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Mouse event
|
||||||
|
|
||||||
|
/*! Mouse down event. Launch a notification to notif the new first responder textField
|
||||||
|
*/
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super mouseDown:anEvent];
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPDatePickerElementTextFieldBecomeFirstResponder object:[[self superview] superview] userInfo:[CPDictionary dictionaryWithObject:self forKey:@"textField"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Theme functions
|
||||||
|
|
||||||
|
/*! Set the theme CPThemeStateSelected
|
||||||
|
*/
|
||||||
|
- (void)makeSelectable
|
||||||
|
{
|
||||||
|
[self setThemeState:CPThemeStateSelected];
|
||||||
|
[_datePicker setThemeState:CPThemeStateEditing];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unsert the theme CPThemeStateSelected
|
||||||
|
*/
|
||||||
|
- (void)makeDeselectable
|
||||||
|
{
|
||||||
|
_firstEvent = YES;
|
||||||
|
[self unsetThemeState:CPThemeStateSelected];
|
||||||
|
[_datePicker unsetThemeState:CPThemeStateEditing];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
/*!
|
||||||
|
We override this method to get all the time the good width
|
||||||
|
*/
|
||||||
|
- (CGSize)_minimumFrameSize
|
||||||
|
{
|
||||||
|
var frameSize = [self frameSize],
|
||||||
|
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
|
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
|
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||||
|
lineBreakMode = [self lineBreakMode],
|
||||||
|
text = (_dateType == CPYearDateType) ? @"0000" : (_dateType == CPMonthDateType) ? @"10" : @"00",
|
||||||
|
textSize = CGSizeMakeCopy(frameSize),
|
||||||
|
font = [self currentValueForThemeAttribute:@"font"];
|
||||||
|
|
||||||
|
textSize.width -= contentInset.left + contentInset.right;
|
||||||
|
textSize.height -= contentInset.top + contentInset.bottom;
|
||||||
|
|
||||||
|
if (_dateType == CPAMPMDateType)
|
||||||
|
text = [self stringValue];
|
||||||
|
|
||||||
|
if (frameSize.width !== 0 &&
|
||||||
|
![self isBezeled] &&
|
||||||
|
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
|
||||||
|
{
|
||||||
|
textSize = [text sizeWithFont:font inWidth:textSize.width];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textSize = [text sizeWithFont:font];
|
||||||
|
|
||||||
|
// Account for possible fractional pixels at right edge
|
||||||
|
textSize.width += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account for possible fractional pixels at bottom edge
|
||||||
|
textSize.height += 1;
|
||||||
|
|
||||||
|
frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
|
||||||
|
|
||||||
|
if ([self isBezeled])
|
||||||
|
{
|
||||||
|
frameSize.height = MAX(frameSize.height, minSize.height);
|
||||||
|
|
||||||
|
if (maxSize.width > 0.0)
|
||||||
|
frameSize.width = MIN(frameSize.width, maxSize.width);
|
||||||
|
|
||||||
|
if (maxSize.height > 0.0)
|
||||||
|
frameSize.height = MIN(frameSize.height, maxSize.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
frameSize.width = textSize.width + contentInset.left + contentInset.right;
|
||||||
|
|
||||||
|
frameSize.width = MAX(frameSize.width, minSize.width);
|
||||||
|
|
||||||
|
return frameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||||
|
{
|
||||||
|
return CGRectMakeCopy(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPDatePickerElementSeparator : CPTextField
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"datePickerElementSeparator";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
|
||||||
|
@"min-size": CGSizeMakeZero()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,306 @@
|
|||||||
|
/* _CPDatePickerHeaderView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
|
||||||
|
@import "CPControl.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "CPButton.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
|
||||||
|
var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"],
|
||||||
|
CPShortWeekDayNameArrayUS = [@"Su", @"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa"],
|
||||||
|
CPShortWeekDayNameArrayFr = [@"L", @"M", @"M", @"J", @"V", @"S", @"D"],
|
||||||
|
CPShortWeekDayNameArrayDe = [@"M", @"D", @"M", @"D", @"F", @"S", @"S"],
|
||||||
|
CPShortWeekDayNameArrayEs = [@"L", @"M", @"X", @"J", @"V", @"S", @"D"],
|
||||||
|
CPShortMonthNameArrayEn = [@"Jan", @"Feb", @"Mar", @"Apr", @"May", @"Jun", @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec"],
|
||||||
|
CPShortMonthNameArrayFr = [@"janv.", String.fromCharCode(102, 233, 118, 46), @"mars", @"apr.", @"mai", @"juin", @"juil.", String.fromCharCode(97, 111, 251, 116), @"sept.", @"oct.", @"nov.", String.fromCharCode(100, 233, 99, 46)],
|
||||||
|
CPShortMonthNameArrayDe = [@"Jan", @"Feb", String.fromCharCode(77, 228, 114), @"Apr", @"Mai", @"Jun", @"Jul", @"Aug", @"Sep", @"Okt", @"Nov", @"Dez"],
|
||||||
|
CPShortMonthNameArrayEs = [@"ene", @"feb", @"mar", @"abr", @"may", @"jun", @"jul", @"ago", @"sep", @"oct", @"nov", @"dic"];
|
||||||
|
|
||||||
|
@implementation _CPDatePickerHeaderView : CPControl
|
||||||
|
{
|
||||||
|
CPArray _dayLabels;
|
||||||
|
CPArray _monthNames;
|
||||||
|
CPButton _nextButton;
|
||||||
|
CPButton _previousButton;
|
||||||
|
CPButton _currentButton;
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
CPDate _date;
|
||||||
|
CPTextField _title;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
/*! Init a new instance of _CPDatePickerHeaderView
|
||||||
|
@param aFrame
|
||||||
|
@param aDatePicker
|
||||||
|
@return a new instance of _CPDatePickerHeaderView
|
||||||
|
*/
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame datePicker:(CPDatePicker)aDatePicker delegate:(id)aDelegate
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
|
||||||
|
// Title
|
||||||
|
_title = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-font" inState:CPThemeStateNormal] forThemeAttribute:@"font" inState:CPThemeStateNormal];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-color" inState:CPThemeStateNormal];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-shadow-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateNormal];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-shadow-offset" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateNormal];
|
||||||
|
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-font" inState:CPThemeStateDisabled] forThemeAttribute:@"font" inState:CPThemeStateDisabled];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled];
|
||||||
|
[_title setValue:[_datePicker valueForThemeAttribute:@"title-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled];
|
||||||
|
|
||||||
|
[self addSubview:_title];
|
||||||
|
|
||||||
|
_dayLabels = [CPArray array];
|
||||||
|
|
||||||
|
// Days
|
||||||
|
for (var i = 0, count = [[self _dayNames] count]; i < count; i++)
|
||||||
|
{
|
||||||
|
var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"tile-text-alignment"] forThemeAttribute:@"alignment"];
|
||||||
|
|
||||||
|
var contentInset = [_datePicker valueForThemeAttribute:@"tile-content-inset"];
|
||||||
|
|
||||||
|
if (contentInset)
|
||||||
|
[label setValue:contentInset forThemeAttribute:@"content-inset"];
|
||||||
|
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-font" inState:CPThemeStateNormal] forThemeAttribute:@"font" inState:CPThemeStateNormal];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-color" inState:CPThemeStateNormal];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-shadow-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateNormal];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-shadow-offset" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateNormal];
|
||||||
|
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-font" inState:CPThemeStateDisabled] forThemeAttribute:@"font" inState:CPThemeStateDisabled];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled];
|
||||||
|
[label setValue:[_datePicker valueForThemeAttribute:@"weekday-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled];
|
||||||
|
|
||||||
|
[_dayLabels addObject:label];
|
||||||
|
[self addSubview:label];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrows
|
||||||
|
var size = [_datePicker valueForThemeAttribute:@"previous-button-size"];
|
||||||
|
|
||||||
|
_previousButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
||||||
|
[_previousButton setButtonType:CPMomentaryChangeButton];
|
||||||
|
[_previousButton setBordered:NO];
|
||||||
|
[_previousButton setImage:[_datePicker valueForThemeAttribute:@"arrow-image-left"]];
|
||||||
|
[_previousButton setAlternateImage:[_datePicker valueForThemeAttribute:@"arrow-image-left-highlighted"]];
|
||||||
|
[self addSubview:_previousButton];
|
||||||
|
|
||||||
|
size = [_datePicker valueForThemeAttribute:@"next-button-size"];
|
||||||
|
|
||||||
|
_nextButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
||||||
|
[_nextButton setButtonType:CPMomentaryChangeButton];
|
||||||
|
[_nextButton setBordered:NO];
|
||||||
|
[_nextButton setImage:[_datePicker valueForThemeAttribute:@"arrow-image-right"]];
|
||||||
|
[_nextButton setAlternateImage:[_datePicker valueForThemeAttribute:@"arrow-image-right-highlighted"]];
|
||||||
|
[self addSubview:_nextButton];
|
||||||
|
|
||||||
|
size = [_datePicker valueForThemeAttribute:@"current-button-size"];
|
||||||
|
|
||||||
|
_currentButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
||||||
|
[_currentButton setButtonType:CPMomentaryChangeButton];
|
||||||
|
[_currentButton setBordered:NO];
|
||||||
|
[_currentButton setImage:[_datePicker valueForThemeAttribute:@"circle-image"]];
|
||||||
|
[_currentButton setAlternateImage:[_datePicker valueForThemeAttribute:@"circle-image-highlighted"]];
|
||||||
|
[self addSubview:_currentButton];
|
||||||
|
|
||||||
|
[_previousButton setTarget:aDelegate];
|
||||||
|
[_previousButton setAction:@selector(_clickArrowPrevious:)];
|
||||||
|
[_previousButton setContinuous:YES];
|
||||||
|
|
||||||
|
[_nextButton setTarget:aDelegate];
|
||||||
|
[_nextButton setAction:@selector(_clickArrowNext:)];
|
||||||
|
[_nextButton setContinuous:YES];
|
||||||
|
|
||||||
|
[_currentButton setTarget:aDelegate];
|
||||||
|
[_currentButton setAction:@selector(_currentMonth:)];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Getter Setter methods
|
||||||
|
|
||||||
|
/*! Return the day names depending on the CPLocale of the datePicker
|
||||||
|
@return an array
|
||||||
|
*/
|
||||||
|
- (CPArray)_dayNames
|
||||||
|
{
|
||||||
|
switch ([[_datePicker locale] objectForKey:CPLocaleLanguageCode])
|
||||||
|
{
|
||||||
|
case @"en":
|
||||||
|
|
||||||
|
// Check if it's in the american format. If yes the week will begin the sunday
|
||||||
|
if ([_datePicker _isAmericanFormat])
|
||||||
|
return CPShortWeekDayNameArrayUS;
|
||||||
|
else
|
||||||
|
return CPShortWeekDayNameArrayEn;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"es":
|
||||||
|
return CPShortWeekDayNameArrayEs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"de":
|
||||||
|
return CPShortWeekDayNameArrayDe;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"fr":
|
||||||
|
return CPShortWeekDayNameArrayFr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CPShortWeekDayNameArrayEn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the month names depending on the CPLocale of the datePicker
|
||||||
|
@return an array
|
||||||
|
*/
|
||||||
|
- (CPArray)_monthNames
|
||||||
|
{
|
||||||
|
switch ([[_datePicker locale] objectForKey:CPLocaleLanguageCode])
|
||||||
|
{
|
||||||
|
case @"en":
|
||||||
|
return CPShortMonthNameArrayEn;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"es":
|
||||||
|
return CPShortMonthNameArrayEs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"de":
|
||||||
|
return CPShortMonthNameArrayDe;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case @"fr":
|
||||||
|
return CPShortMonthNameArrayFr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CPShortMonthNameArrayEn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the monthDate of the header
|
||||||
|
@aMonthDate the new monthDate
|
||||||
|
*/
|
||||||
|
- (void)setMonthForDate:(CPDate)aMonthDate
|
||||||
|
{
|
||||||
|
_date = aMonthDate;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set enabled
|
||||||
|
@param aBoolean
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
[_previousButton setEnabled:aBoolean];
|
||||||
|
[_nextButton setEnabled:aBoolean];
|
||||||
|
[_currentButton setEnabled:aBoolean];
|
||||||
|
[_dayLabels makeObjectsPerformSelector:@selector(setEnabled:) withObject:aBoolean];
|
||||||
|
[_title setEnabled:aBoolean];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
/*! Layout the subviews
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
var bounds = [self bounds],
|
||||||
|
dayNames = [self _dayNames],
|
||||||
|
width = CGRectGetWidth(bounds),
|
||||||
|
buttonInset = [_datePicker valueForThemeAttribute:@"arrow-inset"],
|
||||||
|
numberOfLabels = [_dayLabels count],
|
||||||
|
labelWidth = width / numberOfLabels,
|
||||||
|
sizeButtonLeft = [[_datePicker valueForThemeAttribute:@"arrow-image-left"] size],
|
||||||
|
sizeButtonRight = [[_datePicker valueForThemeAttribute:@"arrow-image-right"] size],
|
||||||
|
sizeButtonCircle = [[_datePicker valueForThemeAttribute:@"circle-image"] size],
|
||||||
|
sizeTileWidth = [_datePicker valueForThemeAttribute:@"size-tile"].width,
|
||||||
|
titleInset = [_datePicker valueForThemeAttribute:@"title-inset"],
|
||||||
|
dayLabelInset = [_datePicker valueForThemeAttribute:@"day-label-inset"];
|
||||||
|
|
||||||
|
// Arrows
|
||||||
|
[_nextButton setFrame:CGRectMake(width - [_nextButton frameSize].width - buttonInset.right, buttonInset.top, sizeButtonRight.width, sizeButtonRight.height)];
|
||||||
|
[_currentButton setFrame:CGRectMake(CGRectGetMinX([_nextButton frame]) - sizeButtonCircle.width - buttonInset.left - buttonInset.right, buttonInset.top, sizeButtonCircle.width, sizeButtonCircle.height)];
|
||||||
|
[_previousButton setFrame:CGRectMake(CGRectGetMinX([_currentButton frame]) - sizeButtonLeft.width - buttonInset.left - buttonInset.right, buttonInset.top, sizeButtonLeft.width, sizeButtonLeft.height)];
|
||||||
|
|
||||||
|
var firstDayTileX;
|
||||||
|
|
||||||
|
// Weekday label
|
||||||
|
for (var i = 0; i < numberOfLabels; i++)
|
||||||
|
{
|
||||||
|
var dayLabel = _dayLabels[i];
|
||||||
|
|
||||||
|
[dayLabel setStringValue:dayNames[i]];
|
||||||
|
|
||||||
|
if (dayLabelInset) // Beginning with Aristo3
|
||||||
|
{
|
||||||
|
var thisWidth = ROUND((i+1) * sizeTileWidth) - ROUND(i * sizeTileWidth);
|
||||||
|
|
||||||
|
[dayLabel sizeToFit];
|
||||||
|
[dayLabel setFrame:CGRectMake(dayLabelInset.left + ROUND(i * sizeTileWidth), dayLabelInset.top, thisWidth, [dayLabel frameSize].height)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[dayLabel sizeToFit];
|
||||||
|
[dayLabel setFrameOrigin:CGPointMake(sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2, 23)];
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
firstDayTileX = sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Title
|
||||||
|
[_title setStringValue:[CPString stringWithFormat:@"%s %i", [self _monthNames][_date.getMonth()], _date.getFullYear()]];
|
||||||
|
[_title sizeToFit];
|
||||||
|
|
||||||
|
if (titleInset) // Beginning with Aristo3
|
||||||
|
[_title setFrameOrigin:CGPointMake(titleInset.left, titleInset.top)];
|
||||||
|
else
|
||||||
|
[_title setFrameOrigin:CGPointMake(firstDayTileX, 6)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,636 @@
|
|||||||
|
/* _CPDatePickerMonthView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexandre Wilhelm
|
||||||
|
* Copyright 2012 <alexandre.wilhelmfr@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
|
||||||
|
@import "CPControl.j"
|
||||||
|
@import "_CPDatePickerDayView.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
|
||||||
|
@global CPSingleDateMode
|
||||||
|
@global CPRangeDateMode
|
||||||
|
|
||||||
|
@implementation _CPDatePickerMonthView : CPControl
|
||||||
|
{
|
||||||
|
BOOL _isMonthJustChanged;
|
||||||
|
CPArray _dayTiles;
|
||||||
|
CPDate _clickDate;
|
||||||
|
CPDate _dragDate;
|
||||||
|
CPDate _date;
|
||||||
|
CPDate _previousMonth @accessors(property=previousMonth);
|
||||||
|
CPDate _nextMonth @accessors(property=nextMonth);
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
CPEvent _eventDragged;
|
||||||
|
CPTimer _timerMonth;
|
||||||
|
id _delegate;
|
||||||
|
int _indexDayTile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
/*! Init a _CPDatePickerMonthView
|
||||||
|
@param aFrame
|
||||||
|
@param aDatePicker
|
||||||
|
@return a new _CPDatePickerMonthView
|
||||||
|
*/
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame datePicker:(CPDatePicker)aDatePicker delegate:(id)aDelegate
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_delegate = aDelegate;
|
||||||
|
_isMonthJustChanged = NO;
|
||||||
|
_indexDayTile = -1;
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
_dayTiles = [CPArray array];
|
||||||
|
|
||||||
|
// Create tiles
|
||||||
|
for (var i = 0; i < 42; i++)
|
||||||
|
{
|
||||||
|
var dayView = [[_CPDatePickerDayView alloc] initWithFrame:CGRectMakeZero() withDatePicker:_datePicker];
|
||||||
|
[self addSubview:dayView];
|
||||||
|
[_dayTiles addObject:dayView];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Getter Setter methods
|
||||||
|
|
||||||
|
/*! Set the monthDate of the component
|
||||||
|
@param aDate
|
||||||
|
*/
|
||||||
|
- (void)setMonthForDate:(CPDate)aDate
|
||||||
|
{
|
||||||
|
if (_dragDate)
|
||||||
|
{
|
||||||
|
if (_dragDate.getMonth() != _date.getMonth())
|
||||||
|
_isMonthJustChanged = YES;
|
||||||
|
|
||||||
|
_date = [_dragDate copy];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_date = [aDate copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![aDate isEqualToDate:[CPDate distantFuture]])
|
||||||
|
{
|
||||||
|
// Reset the date to the first day of the month & midnight
|
||||||
|
_date.setDate(1);
|
||||||
|
[_date _resetToMidnight];
|
||||||
|
|
||||||
|
// There must be a better way to do this.
|
||||||
|
var firstDay = [_date copy];
|
||||||
|
firstDay.setDate(1);
|
||||||
|
|
||||||
|
// Set the previous and next month date. This is usefull for the tile of the next/previous month
|
||||||
|
_previousMonth = new Date(firstDay.getTime() - 86400000);
|
||||||
|
_previousMonth.setDate(1);
|
||||||
|
|
||||||
|
_nextMonth = new Date(firstDay.getTime() + (([_date _daysInMonth] + 1) * 86400000));
|
||||||
|
_nextMonth.setDate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self reloadData];
|
||||||
|
|
||||||
|
if (_isMonthJustChanged)
|
||||||
|
{
|
||||||
|
var dayTile = [_dayTiles objectAtIndex:_indexDayTile];
|
||||||
|
|
||||||
|
if ([dayTile date].getMonth() == _date.getMonth())
|
||||||
|
{
|
||||||
|
[self mouseDragged:_eventDragged];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([dayTile date].getMonth() - _date.getMonth() == 1 || [dayTile date].getFullYear() - _date.getFullYear() == 1)
|
||||||
|
_timerMonth = [CPTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(_timerNextMonthEvent:) userInfo:nil repeats:NO];
|
||||||
|
else
|
||||||
|
_timerMonth = [CPTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(_timerPreviousMonthEvent:) userInfo:nil repeats:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)monthDate
|
||||||
|
{
|
||||||
|
return _date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the size of a tile
|
||||||
|
*/
|
||||||
|
- (CGSize)tileSize
|
||||||
|
{
|
||||||
|
return [_datePicker valueForThemeAttribute:@"size-tile"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the first index day of the month
|
||||||
|
*/
|
||||||
|
- (int)startOfWeekForDate:(CPDate)aDate
|
||||||
|
{
|
||||||
|
var day = aDate.getDay();
|
||||||
|
|
||||||
|
// American people begins the week the sunday
|
||||||
|
if (![_datePicker _isAmericanFormat])
|
||||||
|
return (day + 6) % 7;
|
||||||
|
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set enabled
|
||||||
|
@param aBoolean
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
[super setEnabled:aBoolean];
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Return the index of tile depending of the giving event
|
||||||
|
@param anEvent
|
||||||
|
@return an index
|
||||||
|
*/
|
||||||
|
- (CPInteger)indexOfTileForEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var locationInView = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
tileSize = [self tileSize],
|
||||||
|
borderWidth = [_datePicker valueForThemeAttribute:@"border-width"],
|
||||||
|
margin = [_datePicker valueForThemeAttribute:@"tile-margin"] || CGSizeMakeZero(),
|
||||||
|
tileInset = [_datePicker valueForThemeAttribute:@"tile-inset"] || CGInsetMakeZero();
|
||||||
|
|
||||||
|
// Get the week row
|
||||||
|
var rowIndex = FLOOR((locationInView.y - tileInset.top - margin.height) / (tileSize.height + 2 * margin.height + borderWidth)),
|
||||||
|
columnIndex = FLOOR((locationInView.x - tileInset.left) / (tileSize.width + 2 * margin.width + borderWidth));
|
||||||
|
|
||||||
|
columnIndex = MIN(MAX(columnIndex, 0), 6);
|
||||||
|
rowIndex = MIN(MAX(rowIndex, 0), 5);
|
||||||
|
|
||||||
|
var tileIndex = (rowIndex * 7) + columnIndex;
|
||||||
|
|
||||||
|
return tileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Reload data
|
||||||
|
|
||||||
|
/*! Reload the data
|
||||||
|
*/
|
||||||
|
- (void)reloadData
|
||||||
|
{
|
||||||
|
if (!_date)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var currentMonth = _date,
|
||||||
|
startOfMonthDay = [self startOfWeekForDate:currentMonth],
|
||||||
|
daysInPreviousMonth = [_previousMonth _daysInMonth],
|
||||||
|
firstDayToShowInPreviousMonth = daysInPreviousMonth - startOfMonthDay,
|
||||||
|
currentDate = new Date(_previousMonth.getFullYear(), _previousMonth.getMonth(), firstDayToShowInPreviousMonth),
|
||||||
|
now = [CPDate date],
|
||||||
|
dateValue = [_datePicker dateValue];
|
||||||
|
|
||||||
|
// Update the tiles
|
||||||
|
for (var i = 0; i < [_dayTiles count]; i++)
|
||||||
|
{
|
||||||
|
var dayTile = _dayTiles[i];
|
||||||
|
|
||||||
|
// Increment to next day
|
||||||
|
currentDate.setTime(currentDate.getTime() + 90000000);
|
||||||
|
[currentDate _resetToMidnight];
|
||||||
|
|
||||||
|
var isPresentMonth = (now.getMonth() == currentDate.getMonth()
|
||||||
|
&& now.getFullYear() == currentDate.getFullYear());
|
||||||
|
|
||||||
|
[dayTile setDate:[currentDate copy]];
|
||||||
|
[dayTile setStringValue:currentDate.getDate()];
|
||||||
|
[dayTile setDisabled:/*![self isEnabled] ||*/ currentDate.getMonth() !== currentMonth.getMonth() || currentDate < [_datePicker minDate] || currentDate > [_datePicker maxDate]];
|
||||||
|
[dayTile setHighlighted:isPresentMonth && currentDate.getDate() == now.getDate()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the dates
|
||||||
|
[self _selectDate:[_datePicker dateValue] timeInterval:[_datePicker timeInterval]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Select methods
|
||||||
|
|
||||||
|
/*! Select one date or several date depending of the giving interval
|
||||||
|
@param aStartDate
|
||||||
|
@param anInterval;
|
||||||
|
*/
|
||||||
|
- (void)_selectDate:(CPDate)aStartDate timeInterval:(CPInteger)anInterval
|
||||||
|
{
|
||||||
|
var endDate = [[CPDate alloc] initWithTimeInterval:anInterval sinceDate:aStartDate],
|
||||||
|
tilesCount = [_dayTiles count];
|
||||||
|
|
||||||
|
aStartDate = [aStartDate copy];
|
||||||
|
|
||||||
|
[aStartDate _resetToMidnight];
|
||||||
|
[endDate _resetToMidnight];
|
||||||
|
|
||||||
|
var firstSelected = NO;
|
||||||
|
|
||||||
|
for (var i = 0; i < tilesCount; i++)
|
||||||
|
{
|
||||||
|
var tile = _dayTiles[i],
|
||||||
|
tileDate = [[tile date] copy],
|
||||||
|
selected = NO;
|
||||||
|
|
||||||
|
[tileDate _resetToMidnight];
|
||||||
|
|
||||||
|
if (aStartDate)
|
||||||
|
selected = tileDate >= aStartDate && tileDate <= endDate;
|
||||||
|
|
||||||
|
// Select a tile
|
||||||
|
[tile setSelected:selected];
|
||||||
|
|
||||||
|
// If we are disabled, we have to disable selected tiles so they will appear disabled
|
||||||
|
[tile setDisabled:[tile isDisabled] || (selected && ![self isEnabled])];
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
if (!firstSelected)
|
||||||
|
{
|
||||||
|
firstSelected = YES;
|
||||||
|
[tile setFirstSelected:YES];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[tile setFirstSelected:NO];
|
||||||
|
|
||||||
|
[tile setLastSelected:NO];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (firstSelected)
|
||||||
|
{
|
||||||
|
firstSelected = NO;
|
||||||
|
|
||||||
|
// As there was a first selected and we are now on an unselected tile,
|
||||||
|
// we are sure that i > 0
|
||||||
|
[_dayTiles[i-1] setLastSelected:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
/*! Tile the view
|
||||||
|
*/
|
||||||
|
- (void)tile
|
||||||
|
{
|
||||||
|
var tileSize = [self tileSize],
|
||||||
|
width = tileSize.width,
|
||||||
|
height = tileSize.height,
|
||||||
|
tilesCount = [_dayTiles count],
|
||||||
|
borderWidth = [_datePicker valueForThemeAttribute:@"border-width"],
|
||||||
|
margin = [_datePicker valueForThemeAttribute:@"tile-margin"],
|
||||||
|
tileInset = [_datePicker valueForThemeAttribute:@"tile-inset"],
|
||||||
|
thisWidth,
|
||||||
|
thisX,
|
||||||
|
dayInWeek,
|
||||||
|
weekInMonth,
|
||||||
|
tileFrame,
|
||||||
|
tileIndex;
|
||||||
|
|
||||||
|
// Set the frame of the tiles
|
||||||
|
for (tileIndex = 0; tileIndex < tilesCount; tileIndex++)
|
||||||
|
{
|
||||||
|
dayInWeek = tileIndex % 7;
|
||||||
|
weekInMonth = (tileIndex - dayInWeek) / 7;
|
||||||
|
tileFrame;
|
||||||
|
|
||||||
|
if (margin) // Beginning with Aristo3
|
||||||
|
{
|
||||||
|
thisX = ROUND(dayInWeek * (width + 2 * margin.width));
|
||||||
|
thisWidth = ROUND((dayInWeek+1) * (width + 2 * margin.width)) - thisX;
|
||||||
|
|
||||||
|
tileFrame = CGRectMake(tileInset.left + thisX, tileInset.top + margin.height + weekInMonth * (height + 2 * margin.height), thisWidth + borderWidth, height + borderWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tileFrame = CGRectMake(dayInWeek * width, weekInMonth * height, width + borderWidth, height + borderWidth);
|
||||||
|
|
||||||
|
[_dayTiles[tileIndex] setFrame:tileFrame];
|
||||||
|
[_dayTiles[tileIndex] setDayInWeek:dayInWeek];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Layout the subviews
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[super layoutSubviews];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
[_dayTiles makeObjectsPerformSelector:@selector(setNeedsLayout)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Draw the component. This draws the border of the tile.
|
||||||
|
The selected tile are drawed in the drawRect method of the tile. But the unselected tile here.
|
||||||
|
It avoids some problems with tiles over other tiles (otherwise the color of the tile border would be different).
|
||||||
|
Rememeber that the first pixel of a tile are over the last pixel of the last tile (because the border)
|
||||||
|
*/
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
[super drawRect:aRect];
|
||||||
|
|
||||||
|
if ([_datePicker isCSSBased])
|
||||||
|
{
|
||||||
|
// We just have to draw the separator (if any)
|
||||||
|
// No separator color means no separator
|
||||||
|
var separatorColor = [_datePicker valueForThemeAttribute:@"separator-color"],
|
||||||
|
separatorHeight = [_datePicker valueForThemeAttribute:@"separator-height"],
|
||||||
|
separatorMarginWidth = [_datePicker valueForThemeAttribute:@"separator-margin-width"];
|
||||||
|
|
||||||
|
if (separatorColor)
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, separatorColor);
|
||||||
|
CGContextSetLineWidth(context, separatorHeight);
|
||||||
|
CGContextMoveToPoint(context, separatorMarginWidth, 0.5);
|
||||||
|
CGContextAddLineToPoint(context, bounds.size.width - separatorMarginWidth, 0.5);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
width = [self tileSize].width,
|
||||||
|
height = [self tileSize].height,
|
||||||
|
isBorderPair = ([_datePicker valueForThemeAttribute:@"border-width"] % 2) == 0;
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [_datePicker valueForThemeAttribute:@"border-color" inState:[_datePicker themeState]]);
|
||||||
|
CGContextSetLineWidth(context, [_datePicker valueForThemeAttribute:@"border-width"]);
|
||||||
|
|
||||||
|
if ([_datePicker isBordered])
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
var y = i * height;
|
||||||
|
|
||||||
|
// Very usefull to avoid to have a line of two pixels instead one
|
||||||
|
if (!isBorderPair)
|
||||||
|
y += 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, 0, y);
|
||||||
|
CGContextAddLineToPoint(context, [self bounds].size.width, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
var x = i * width;
|
||||||
|
|
||||||
|
// Very usefull to avoid to have a line of two pixels instead one
|
||||||
|
if (!isBorderPair)
|
||||||
|
x += 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x, 0);
|
||||||
|
CGContextAddLineToPoint(context, x, [self bounds].size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var y = 0;
|
||||||
|
|
||||||
|
// Very usefull to avoid to have a line of two pixels instead one
|
||||||
|
if (!isBorderPair)
|
||||||
|
y += 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, 0, y);
|
||||||
|
CGContextAddLineToPoint(context, [self bounds].size.width, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Mouse event
|
||||||
|
|
||||||
|
/*! Mouse down event
|
||||||
|
*/
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dayTile = [_dayTiles objectAtIndex:[self indexOfTileForEvent:anEvent]],
|
||||||
|
dateTile = [[dayTile date] copy],
|
||||||
|
dateValue = [_datePicker dateValue];
|
||||||
|
|
||||||
|
_clickDate = [dateTile copy];
|
||||||
|
_dragDate = nil;
|
||||||
|
_indexDayTile = -1;
|
||||||
|
_eventDragged = nil;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = YES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check if we have to change or not the month of the component
|
||||||
|
if ([dayTile date].getMonth() == _date.getMonth())
|
||||||
|
{
|
||||||
|
if ([_datePicker datePickerMode] == CPRangeDateMode && [anEvent modifierFlags] & CPShiftKeyMask)
|
||||||
|
{
|
||||||
|
var dateValueAtMidnight = [[_datePicker dateValue] copy];
|
||||||
|
|
||||||
|
[dateValueAtMidnight _resetToMidnight];
|
||||||
|
|
||||||
|
if (dateTile < dateValueAtMidnight)
|
||||||
|
{
|
||||||
|
var interval;
|
||||||
|
|
||||||
|
if (dateTile == dateValueAtMidnight)
|
||||||
|
interval = [_datePicker timeInterval];
|
||||||
|
else
|
||||||
|
interval = ([dateValueAtMidnight timeIntervalSinceDate:dateTile] + [_datePicker timeInterval]);
|
||||||
|
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:interval];
|
||||||
|
}
|
||||||
|
else if ([[dayTile date] isEqualToDate:dateValueAtMidnight])
|
||||||
|
{
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:[dateValueAtMidnight copy]] timeInterval:([dateTile timeIntervalSinceDate:dateValueAtMidnight])];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be sure to display the good month
|
||||||
|
[_delegate setDateValue:dateTile];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var minDate = [[_datePicker minDate] copy],
|
||||||
|
maxDate = [[_datePicker maxDate] copy];
|
||||||
|
|
||||||
|
[minDate _resetToMidnight];
|
||||||
|
[maxDate _resetToLastSeconds];
|
||||||
|
|
||||||
|
if (dateTile >= minDate && dateTile <= maxDate)
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check the year and the month. The year is usefull when changing from Jan to Dec.
|
||||||
|
if (_date.getMonth() - [dayTile date].getMonth() == 1 || _date.getFullYear() - [dayTile date].getFullYear() == 1)
|
||||||
|
[_delegate _displayPreviousMonth];
|
||||||
|
else
|
||||||
|
[_delegate _displayNextMonth];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = NO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Mouse dragged event
|
||||||
|
*/
|
||||||
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEnabled] || !CGRectContainsPoint([self bounds],[self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dayTile = [_dayTiles objectAtIndex:[self indexOfTileForEvent:anEvent]],
|
||||||
|
dateTile = [[dayTile date] copy],
|
||||||
|
dateValue = [_datePicker dateValue];
|
||||||
|
|
||||||
|
_dragDate = [dateTile copy];
|
||||||
|
_indexDayTile = [self indexOfTileForEvent:anEvent];
|
||||||
|
_eventDragged = anEvent;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = YES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ([_datePicker datePickerMode] == CPSingleDateMode)
|
||||||
|
{
|
||||||
|
// Check if we have to change or not the month of the component
|
||||||
|
if ([dayTile date].getMonth() == _date.getMonth())
|
||||||
|
{
|
||||||
|
[_timerMonth invalidate];
|
||||||
|
_isMonthJustChanged = NO;
|
||||||
|
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||||
|
}
|
||||||
|
else if (!_isMonthJustChanged)
|
||||||
|
{
|
||||||
|
[_timerMonth invalidate];
|
||||||
|
_isMonthJustChanged = NO;
|
||||||
|
|
||||||
|
// Check the year and the month. The year is usefull when changing from Jan to Dec.
|
||||||
|
if (_date.getMonth() - [dayTile date].getMonth() == 1 || _date.getFullYear() - [dayTile date].getFullYear() == 1)
|
||||||
|
[_delegate _displayPreviousMonth];
|
||||||
|
else
|
||||||
|
[_delegate _displayNextMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dateTile.getMonth() == _date.getMonth() || !_isMonthJustChanged)
|
||||||
|
{
|
||||||
|
[_timerMonth invalidate];
|
||||||
|
_isMonthJustChanged = NO;
|
||||||
|
|
||||||
|
var dateValueAtMidnight = [[_datePicker dateValue] copy];
|
||||||
|
|
||||||
|
[dateValueAtMidnight _resetToMidnight];
|
||||||
|
|
||||||
|
if (dateTile < _clickDate)
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:[_clickDate timeIntervalSinceDate:dateTile]];
|
||||||
|
else if ([[dayTile date] isEqualToDate:_clickDate])
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||||
|
else
|
||||||
|
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:_clickDate] timeInterval:[dateTile timeIntervalSinceDate:dateValueAtMidnight]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_datePicker._invokedByUserEvent = NO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[_timerMonth invalidate];
|
||||||
|
_dragDate = nil;
|
||||||
|
_clickDate = nil;
|
||||||
|
_isMonthJustChanged = NO;
|
||||||
|
_indexDayTile = -1;
|
||||||
|
_eventDragged = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Timer
|
||||||
|
|
||||||
|
- (void)_timerNextMonthEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_isMonthJustChanged)
|
||||||
|
{
|
||||||
|
_dragDate.setMonth(_date.getMonth() + 1);
|
||||||
|
[_delegate _displayNextMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_timerPreviousMonthEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_isMonthJustChanged)
|
||||||
|
{
|
||||||
|
_dragDate.setMonth(_date.getMonth() - 1);
|
||||||
|
[_delegate _displayPreviousMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Date methods
|
||||||
|
|
||||||
|
- (CPDate)_hoursMinutesSecondsFromDatePickerForDate:(CPDate)aDate
|
||||||
|
{
|
||||||
|
var dateValue = [_datePicker dateValue];
|
||||||
|
|
||||||
|
aDate.setHours(dateValue.getHours());
|
||||||
|
aDate.setMinutes(dateValue.getMinutes());
|
||||||
|
aDate.setSeconds(dateValue.getSeconds());
|
||||||
|
|
||||||
|
return aDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -69,7 +69,7 @@
|
|||||||
aNewObject._controller = self;
|
aNewObject._controller = self;
|
||||||
aNewObject._key = aKey;
|
aNewObject._key = aKey;
|
||||||
|
|
||||||
if (aValue !== nil)
|
if (aValue != nil)
|
||||||
[aNewObject setValue:aValue];
|
[aNewObject setValue:aValue];
|
||||||
|
|
||||||
return aNewObject;
|
return aNewObject;
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
var iter = [[CPSet setWithArray:allKeys] objectEnumerator],
|
var iter = [[CPSet setWithArray:allKeys] objectEnumerator],
|
||||||
obj;
|
obj;
|
||||||
|
|
||||||
while ((obj = [iter nextObject]) !== nil)
|
while ((obj = [iter nextObject]) != nil)
|
||||||
if (![_excludedKeys containsObject:obj])
|
if (![_excludedKeys containsObject:obj])
|
||||||
[array addObject:[self _newObjectWithKey:obj value:nil]];
|
[array addObject:[self _newObjectWithKey:obj value:nil]];
|
||||||
|
|
||||||
|
|||||||
+22
-13
@@ -515,7 +515,9 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
alert("There was an error retrieving the document.");
|
alert("There was an error retrieving the document.");
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
var theDelegate = session.delegate;
|
||||||
|
|
||||||
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -540,7 +542,9 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
_writeRequest = nil;
|
_writeRequest = nil;
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
var theDelegate = session.delegate;
|
||||||
|
|
||||||
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||||
[self _sendDocumentSavedNotification:NO];
|
[self _sendDocumentSavedNotification:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,14 +557,15 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
|
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
|
||||||
{
|
{
|
||||||
var session = aConnection.session;
|
var session = aConnection.session,
|
||||||
|
theDelegate = session.delegate;
|
||||||
|
|
||||||
// READ
|
// READ
|
||||||
if (aConnection == _readConnection)
|
if (aConnection == _readConnection)
|
||||||
{
|
{
|
||||||
[self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
|
[self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, YES, session.contextInfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -569,7 +574,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
_writeRequest = nil;
|
_writeRequest = nil;
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||||
[self _sendDocumentSavedNotification:YES];
|
[self _sendDocumentSavedNotification:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,10 +585,11 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||||
{
|
{
|
||||||
var session = aConnection.session;
|
var session = aConnection.session,
|
||||||
|
theDelegate = session.delegate;
|
||||||
|
|
||||||
if (_readConnection == aConnection)
|
if (_readConnection == aConnection)
|
||||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -597,7 +603,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
alert("There was an error saving the document.");
|
alert("There was an error saving the document.");
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||||
[self _sendDocumentSavedNotification:NO];
|
[self _sendDocumentSavedNotification:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -858,21 +864,24 @@ var CPDocumentUntitledCount = 0;
|
|||||||
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
||||||
|
|
||||||
else if ([delegate respondsToSelector:selector])
|
else if ([delegate respondsToSelector:selector])
|
||||||
objj_msgSend(delegate, selector, self, YES, info);
|
delegate.isa.objj_msgSend3(delegate, selector, self, YES, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
- (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||||
{
|
{
|
||||||
|
var theDelegate = context.delegate;
|
||||||
|
|
||||||
if (aDocument === self && shouldClose)
|
if (aDocument === self && shouldClose)
|
||||||
[self close];
|
[self close];
|
||||||
|
|
||||||
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
|
if (theDelegate != null)
|
||||||
|
theDelegate.isa.objj_msgSend3(theDelegate, context.selector, aDocument, shouldClose, context.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
|
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
|
||||||
{
|
{
|
||||||
if (![self isDocumentEdited])
|
if (![self isDocumentEdited])
|
||||||
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
|
return [aDelegate respondsToSelector:aSelector] && aDelegate.isa.objj_msgSend3(aDelegate, aSelector, self, YES, context);
|
||||||
|
|
||||||
_canCloseAlert = [[CPAlert alloc] init];
|
_canCloseAlert = [[CPAlert alloc] init];
|
||||||
|
|
||||||
@@ -901,8 +910,8 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
if (returnCode === 0)
|
if (returnCode === 0)
|
||||||
[self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
|
[self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
|
||||||
else
|
else if (delegate != null)
|
||||||
objj_msgSend(delegate, selector, self, returnCode === 2, context);
|
delegate.isa.objj_msgSend3(delegate, selector, self, returnCode === 2, context);
|
||||||
|
|
||||||
_canCloseAlert = nil;
|
_canCloseAlert = nil;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ var CPSharedDocumentController = nil;
|
|||||||
@param aType the type of the new document
|
@param aType the type of the new document
|
||||||
@param shouldDisplay whether to display the document on screen
|
@param shouldDisplay whether to display the document on screen
|
||||||
*/
|
*/
|
||||||
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
|
- (CPDocument)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
|
||||||
{
|
{
|
||||||
var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
|
var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ var CPSharedDocumentController = nil;
|
|||||||
var iter = [_documents objectEnumerator],
|
var iter = [_documents objectEnumerator],
|
||||||
obj;
|
obj;
|
||||||
|
|
||||||
while ((obj = [iter nextObject]) !== nil)
|
while ((obj = [iter nextObject]) != nil)
|
||||||
{
|
{
|
||||||
if ([obj isDocumentEdited])
|
if ([obj isDocumentEdited])
|
||||||
return YES;
|
return YES;
|
||||||
@@ -402,8 +402,10 @@ var CPSharedDocumentController = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([context.delegate respondsToSelector:context.selector])
|
var theDelegate = context.delegate;
|
||||||
objj_msgSend(context.delegate, context.selector, self, [[self documents] count] === 0, context.context);
|
|
||||||
|
if ([theDelegate respondsToSelector:context.selector])
|
||||||
|
theDelegate.isa.objj_msgSend3(theDelegate, context.selector, self, [[self documents] count] === 0, context.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@typedef CPDragOperation
|
||||||
CPDragOperationNone = 0;
|
CPDragOperationNone = 0;
|
||||||
CPDragOperationCopy = 1 << 1;
|
CPDragOperationCopy = 1 << 1;
|
||||||
CPDragOperationLink = 1 << 1;
|
CPDragOperationLink = 1 << 1;
|
||||||
|
|||||||
+104
-3
@@ -28,11 +28,20 @@
|
|||||||
|
|
||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPText.j"
|
@import "CPTrackingArea.j"
|
||||||
|
|
||||||
@class CPTextField
|
@class CPTextField
|
||||||
|
@class CPWindow
|
||||||
|
@class CPGraphicsContext
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
@global CPNewlineCharacter
|
||||||
|
@global CPCarriageReturnCharacter
|
||||||
|
@global CPEnterCharacter
|
||||||
|
|
||||||
|
@typedef DOMEvent
|
||||||
|
@typedef CPEventType
|
||||||
|
|
||||||
|
|
||||||
var _CPEventPeriodicEventPeriod = 0,
|
var _CPEventPeriodicEventPeriod = 0,
|
||||||
_CPEventPeriodicEventTimer = nil,
|
_CPEventPeriodicEventTimer = nil,
|
||||||
@@ -57,7 +66,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
CPWindow _window;
|
CPWindow _window;
|
||||||
Number _windowNumber;
|
Number _windowNumber;
|
||||||
CPString _characters;
|
CPString _characters;
|
||||||
CPString _charactersIgnoringModifiers
|
CPString _charactersIgnoringModifiers;
|
||||||
BOOL _isARepeat;
|
BOOL _isARepeat;
|
||||||
unsigned _keyCode;
|
unsigned _keyCode;
|
||||||
DOMEvent _DOMEvent;
|
DOMEvent _DOMEvent;
|
||||||
@@ -68,11 +77,16 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
float _deltaX;
|
float _deltaX;
|
||||||
float _deltaY;
|
float _deltaY;
|
||||||
float _deltaZ;
|
float _deltaZ;
|
||||||
|
float _scrollingDeltaX;
|
||||||
|
float _scrollingDeltaY;
|
||||||
|
BOOL _hasPreciseScrollingDeltas;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
BOOL _suppressCappuccinoCut;
|
BOOL _suppressCappuccinoCut;
|
||||||
BOOL _suppressCappuccinoPaste;
|
BOOL _suppressCappuccinoPaste;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CPTrackingArea _trackingArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -132,6 +146,27 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
|
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a new mouse tracking event.
|
||||||
|
|
||||||
|
@param anEventType the event type
|
||||||
|
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
|
||||||
|
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||||
|
@param aTimestamp the time the event occurred
|
||||||
|
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||||
|
@param aGraphicsContext the graphics context where the event occurred
|
||||||
|
@param anEventNumber a number for this event
|
||||||
|
@param aTrackingArea the tracking area that triggered the event
|
||||||
|
@throws CPInternalInconsistencyException if an invalid event type is provided
|
||||||
|
@return the new mouse event
|
||||||
|
*/
|
||||||
|
+ (id)enterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||||
|
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||||
|
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||||
|
{
|
||||||
|
return [[self alloc] _initEnterExitEventWithType:anEventType location:aPoint modifierFlags:modifierFlags timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber trackingArea:aTrackingArea];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new custom event.
|
Creates a new custom event.
|
||||||
|
|
||||||
@@ -163,7 +198,9 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
|
|
||||||
// Make sure these are 0 rather than nil.
|
// Make sure these are 0 rather than nil.
|
||||||
_deltaX = 0;
|
_deltaX = 0;
|
||||||
|
_scrollingDeltaX = 0;
|
||||||
_deltaY = 0;
|
_deltaY = 0;
|
||||||
|
_scrollingDeltaY = 0;
|
||||||
_deltaZ = 0;
|
_deltaZ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +227,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @ignore */
|
||||||
|
- (id)_initEnterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||||
|
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||||
|
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||||
|
{
|
||||||
|
if ((anEventType != CPMouseEntered) && (anEventType != CPMouseExited) && (anEventType != CPCursorUpdate))
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:"Invalid event type"];
|
||||||
|
|
||||||
|
if (self = [self _initWithType:anEventType])
|
||||||
|
{
|
||||||
|
_location = CGPointCreateCopy(aPoint);
|
||||||
|
_modifierFlags = modifierFlags;
|
||||||
|
_timestamp = aTimestamp;
|
||||||
|
_context = aGraphicsContext;
|
||||||
|
_eventNumber = anEventNumber;
|
||||||
|
_trackingArea = aTrackingArea;
|
||||||
|
_window = [CPApp windowWithWindowNumber:aWindowNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
||||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||||
@@ -225,6 +284,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
_subtype = aSubtype;
|
_subtype = aSubtype;
|
||||||
_data1 = aData1;
|
_data1 = aData1;
|
||||||
_data2 = aData2;
|
_data2 = aData2;
|
||||||
|
_windowNumber = aWindowNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -278,6 +338,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the subtype of the event.
|
||||||
|
*/
|
||||||
|
- (CPEventType)subtype
|
||||||
|
{
|
||||||
|
return _subtype;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the event's associated window.
|
Returns the event's associated window.
|
||||||
*/
|
*/
|
||||||
@@ -417,6 +485,31 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return _deltaZ;
|
return _deltaZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasPreciseScrollingDeltas
|
||||||
|
{
|
||||||
|
return !!_hasPreciseScrollingDeltas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the change in points on the x-axis for a mouse movement, unless hasPreciseScrollingDeltas is NO,
|
||||||
|
in which case the change is measured in number of "lines" or "rows" and needs to be multiplied as appropriate
|
||||||
|
to get change in pixels.
|
||||||
|
*/
|
||||||
|
- (float)scrollingDeltaX
|
||||||
|
{
|
||||||
|
return _scrollingDeltaX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the change in points on the y-axis for a mouse movement, unless hasPreciseScrollingDeltas is NO,
|
||||||
|
in which case the change is measured in number of "lines" or "columns" and needs to be multiplied as appropriate
|
||||||
|
to get change in pixels.
|
||||||
|
*/
|
||||||
|
- (float)scrollingDeltaY
|
||||||
|
{
|
||||||
|
return _scrollingDeltaY;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
|
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
|
||||||
{
|
{
|
||||||
if (!aKeyEquivalent)
|
if (!aKeyEquivalent)
|
||||||
@@ -515,7 +608,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
+ (void)stopPeriodicEvents
|
+ (void)stopPeriodicEvents
|
||||||
{
|
{
|
||||||
if (_CPEventPeriodicEventTimer === nil)
|
if (_CPEventPeriodicEventTimer == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
window.clearTimeout(_CPEventPeriodicEventTimer);
|
window.clearTimeout(_CPEventPeriodicEventTimer);
|
||||||
@@ -546,6 +639,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPTrackingArea)trackingArea
|
||||||
|
{
|
||||||
|
if ((_type !== CPMouseEntered) && (_type !== CPMouseExited) && (_type !== CPCursorUpdate))
|
||||||
|
[CPException raise:CPInternalInconsistencyException format:@"You can't call trackingArea for events of type %#x", _type];
|
||||||
|
|
||||||
|
return _trackingArea;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
function _CPEventFirePeriodEvent()
|
function _CPEventFirePeriodEvent()
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* CPFlashMovie.j
|
|
||||||
* AppKit
|
|
||||||
*
|
|
||||||
* Created by Francisco Tolmasky.
|
|
||||||
* Copyright 2008, 280 North, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@ingroup appkit
|
|
||||||
@class CPFlashMovie
|
|
||||||
|
|
||||||
CPFlashMovie is used to represent a Flash movie in the Cappuccino framework.
|
|
||||||
*/
|
|
||||||
@implementation CPFlashMovie : CPObject
|
|
||||||
{
|
|
||||||
CPString _filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a new Flash movie with the swf at \c aFileName.
|
|
||||||
@param aFilename the swf to load
|
|
||||||
@return the initialized CPFlashMovie
|
|
||||||
*/
|
|
||||||
+ (id)flashMovieWithFile:(CPString)aFilename
|
|
||||||
{
|
|
||||||
return [[self alloc] initWithFile:aFilename];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Initializes the Flash movie.
|
|
||||||
@param aFilename the swf to load
|
|
||||||
@return the initialized CPFlashMovie
|
|
||||||
*/
|
|
||||||
- (id)initWithFile:(CPString)aFilename
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
_filename = aFilename;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPString)filename
|
|
||||||
{
|
|
||||||
return _filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey";
|
|
||||||
|
|
||||||
@implementation CPFlashMovie (CPCoding)
|
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
_filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
[aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
/*
|
|
||||||
* CPFlashView.j
|
|
||||||
* AppKit
|
|
||||||
*
|
|
||||||
* Created by Francisco Tolmasky.
|
|
||||||
* Copyright 2008, 280 North, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import "CPFlashMovie.j"
|
|
||||||
@import "CPView.j"
|
|
||||||
|
|
||||||
|
|
||||||
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@ingroup appkit
|
|
||||||
*/
|
|
||||||
@implementation CPFlashView : CPView
|
|
||||||
{
|
|
||||||
CPFlashMovie _flashMovie;
|
|
||||||
|
|
||||||
CPDictionary _params;
|
|
||||||
CPDictionary _paramElements;
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
DOMElement _DOMParamElement;
|
|
||||||
DOMElement _DOMObjectElement;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:aFrame];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
_DOMObjectElement = document.createElement(@"object");
|
|
||||||
_DOMObjectElement.id = [self elementID];
|
|
||||||
_DOMObjectElement.width = @"100%";
|
|
||||||
_DOMObjectElement.height = @"100%";
|
|
||||||
_DOMObjectElement.style.top = @"0px";
|
|
||||||
_DOMObjectElement.style.left = @"0px";
|
|
||||||
_DOMObjectElement.type = @"application/x-shockwave-flash";
|
|
||||||
_DOMParamElement = document.createElement(@"param");
|
|
||||||
_DOMParamElement.name = @"movie";
|
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
|
||||||
|
|
||||||
_DOMElement.appendChild(_DOMObjectElement);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[self _rebuildIEObjects];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFlashMovie:(CPFlashMovie)aFlashMovie
|
|
||||||
{
|
|
||||||
if (_flashMovie == aFlashMovie)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_flashMovie = aFlashMovie;
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
_DOMParamElement.value = [aFlashMovie filename];
|
|
||||||
_DOMObjectElement.data = [aFlashMovie filename];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[self _rebuildIEObjects];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPFlashMovie)flashMovie
|
|
||||||
{
|
|
||||||
return _flashMovie;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFlashVars:(CPDictionary)aDictionary
|
|
||||||
{
|
|
||||||
var varString = @"",
|
|
||||||
enumerator = [aDictionary keyEnumerator],
|
|
||||||
key;
|
|
||||||
|
|
||||||
if (key = [enumerator nextObject])
|
|
||||||
varString = [varString stringByAppendingFormat:@"%@=%@", key, [aDictionary objectForKey:key]];
|
|
||||||
|
|
||||||
while (key = [enumerator nextObject])
|
|
||||||
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
|
|
||||||
|
|
||||||
if (!_params)
|
|
||||||
_params = @{};
|
|
||||||
|
|
||||||
[_params setObject:varString forKey:@"flashvars"];
|
|
||||||
[self setParameters:_params];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPDictionary)flashVars
|
|
||||||
{
|
|
||||||
return [_params objectForKey:@"flashvars"];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setParameters:(CPDictionary)aDictionary
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
var elements = [_paramElements allValues],
|
|
||||||
count = [elements count];
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!_params)
|
|
||||||
_params = aDictionary;
|
|
||||||
else
|
|
||||||
[_params addEntriesFromDictionary:aDictionary];
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
_paramElements = @{};
|
|
||||||
|
|
||||||
var enumerator = [_params keyEnumerator],
|
|
||||||
key;
|
|
||||||
|
|
||||||
while (_DOMObjectElement && (key = [enumerator nextObject]) !== nil)
|
|
||||||
{
|
|
||||||
var param = document.createElement(@"param");
|
|
||||||
param.name = key;
|
|
||||||
param.value = [_params objectForKey:key];
|
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(param);
|
|
||||||
|
|
||||||
[_paramElements setObject:param forKey:key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[self _rebuildIEObjects];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPDictionary)parameters
|
|
||||||
{
|
|
||||||
return _params;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
- (void)_rebuildIEObjects
|
|
||||||
{
|
|
||||||
_DOMElement.innerHTML = @"";
|
|
||||||
if (![_flashMovie filename])
|
|
||||||
return;
|
|
||||||
|
|
||||||
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
|
|
||||||
paramEnumerator = [_params keyEnumerator],
|
|
||||||
key;
|
|
||||||
|
|
||||||
while ((key = [paramEnumerator nextObject]) !== nil)
|
|
||||||
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
|
|
||||||
|
|
||||||
_DOMObjectElement = document.createElement(@"object");
|
|
||||||
_DOMElement.appendChild(_DOMObjectElement);
|
|
||||||
|
|
||||||
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object id=%@ classid=%@ width=%@ height=%@>%@</object>", [self elementID], IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- (CPString)elementID
|
|
||||||
{
|
|
||||||
return @"CPFV_" + [self UID];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseMoved:(CPEvent)sommit
|
|
||||||
{
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseDragged:(CPEvent)anEvent
|
|
||||||
{
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
|
||||||
{
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
|
||||||
{
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
+156
-14
@@ -24,6 +24,9 @@
|
|||||||
@import <Foundation/CPBundle.j>
|
@import <Foundation/CPBundle.j>
|
||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPFontDescriptor.j"
|
||||||
|
@import "_CPObject+Theme.j"
|
||||||
|
@import "CPControl.j"
|
||||||
|
|
||||||
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
|
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
|
||||||
CPFontDefaultSystemFontSize = 12;
|
CPFontDefaultSystemFontSize = 12;
|
||||||
@@ -37,12 +40,15 @@ CPFontCurrentSystemSize = -1;
|
|||||||
// For internal use only by this class and subclasses
|
// For internal use only by this class and subclasses
|
||||||
_CPFontSystemFacePlaceholder = "_CPFontSystemFacePlaceholder";
|
_CPFontSystemFacePlaceholder = "_CPFontSystemFacePlaceholder";
|
||||||
|
|
||||||
var _CPFontCache = {},
|
var _CPFontCache = {},
|
||||||
_CPSystemFontCache = {},
|
_CPSystemFontCache = {},
|
||||||
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
||||||
_CPFontSystemFontSize = 12,
|
_CPFontSystemFontSize = CPFontDefaultSystemFontSize,
|
||||||
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
_CPFontSystemFontSizeSmall = CPFontDefaultSystemFontSize - 1,
|
||||||
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
|
_CPFontSystemFontSizeMini = CPFontDefaultSystemFontSize - 2,
|
||||||
|
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
||||||
|
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g"),
|
||||||
|
_CPFontSystemFontFaceSpecified = NO;
|
||||||
|
|
||||||
|
|
||||||
#define _CPRealFontSize(aSize) (aSize <= 0 ? _CPFontSystemFontSize : aSize)
|
#define _CPRealFontSize(aSize) (aSize <= 0 ? _CPFontSystemFontSize : aSize)
|
||||||
@@ -108,7 +114,7 @@ following:
|
|||||||
<string>Asap</string>
|
<string>Asap</string>
|
||||||
@endcode
|
@endcode
|
||||||
*/
|
*/
|
||||||
@implementation CPFont : CPObject
|
@implementation CPFont : CPObject <CPTheme>
|
||||||
{
|
{
|
||||||
CPString _name;
|
CPString _name;
|
||||||
float _size;
|
float _size;
|
||||||
@@ -122,6 +128,22 @@ following:
|
|||||||
CPString _cssString;
|
CPString _cssString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"font";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"system-font-face": [CPNull null],
|
||||||
|
@"system-font-style": [CPNull null],
|
||||||
|
@"system-font-size-regular": [CPNull null],
|
||||||
|
@"system-font-size-small": [CPNull null],
|
||||||
|
@"system-font-size-mini": [CPNull null]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self !== [CPFont class])
|
if (self !== [CPFont class])
|
||||||
@@ -133,7 +155,10 @@ following:
|
|||||||
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
||||||
|
|
||||||
if (systemFontFace)
|
if (systemFontFace)
|
||||||
|
{
|
||||||
_CPFontSystemFontFace = _CPFontNormalizedNames(systemFontFace);
|
_CPFontSystemFontFace = _CPFontNormalizedNames(systemFontFace);
|
||||||
|
_CPFontSystemFontFaceSpecified = YES;
|
||||||
|
}
|
||||||
|
|
||||||
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
||||||
|
|
||||||
@@ -141,7 +166,62 @@ following:
|
|||||||
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
||||||
|
|
||||||
if (systemFontSize)
|
if (systemFontSize)
|
||||||
|
{
|
||||||
_CPFontSystemFontSize = systemFontSize;
|
_CPFontSystemFontSize = systemFontSize;
|
||||||
|
_CPFontSystemFontFaceSpecified = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initializeSystemFontFromTheme:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
// If something was specified via +initialize (from an Info.plist file), don't do anything
|
||||||
|
if (_CPFontSystemFontFaceSpecified)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Reset all system font caches
|
||||||
|
_CPSystemFontCache = {};
|
||||||
|
|
||||||
|
// Now, try to get information from the theme
|
||||||
|
var systemFontFace = [aTheme valueForAttributeWithName:@"system-font-face" forClass:[CPFont class]];
|
||||||
|
|
||||||
|
if (systemFontFace)
|
||||||
|
{
|
||||||
|
[self _invalidateSystemFontCache];
|
||||||
|
_CPFontSystemFontFace = _CPFontNormalizedNames(systemFontFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
var systemFontSize = [aTheme valueForAttributeWithName:@"system-font-size-regular" forClass:[CPFont class]];
|
||||||
|
|
||||||
|
if (systemFontSize)
|
||||||
|
{
|
||||||
|
[self _invalidateSystemFontCache];
|
||||||
|
_CPFontSystemFontSize = systemFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
systemFontSize = [aTheme valueForAttributeWithName:@"system-font-size-small" forClass:[CPFont class]];
|
||||||
|
|
||||||
|
if (systemFontSize)
|
||||||
|
{
|
||||||
|
[self _invalidateSystemFontCache];
|
||||||
|
_CPFontSystemFontSizeSmall = systemFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
systemFontSize = [aTheme valueForAttributeWithName:@"system-font-size-mini" forClass:[CPFont class]];
|
||||||
|
|
||||||
|
if (systemFontSize)
|
||||||
|
{
|
||||||
|
[self _invalidateSystemFontCache];
|
||||||
|
_CPFontSystemFontSizeMini = systemFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there something to add to the global syle definition ?
|
||||||
|
var systemFontStyle = [aTheme valueForAttributeWithName:@"system-font-style" forClass:[CPFont class]];
|
||||||
|
|
||||||
|
if (systemFontStyle)
|
||||||
|
{
|
||||||
|
// Yes, so install it in the DOM Style element
|
||||||
|
document.getElementsByTagName("STYLE")[0].innerHTML += "\n" + [aTheme setCSSResourcesPathInString:systemFontStyle];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -162,7 +242,7 @@ following:
|
|||||||
if (normalizedFaces === _CPFontSystemFontFace)
|
if (normalizedFaces === _CPFontSystemFontFace)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self _invalidateSystemFontCache]
|
[self _invalidateSystemFontCache];
|
||||||
_CPFontSystemFontFace = aFace;
|
_CPFontSystemFontFace = aFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,20 +254,19 @@ following:
|
|||||||
return _CPFontSystemFontSize;
|
return _CPFontSystemFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)systemFontSizeForControlSize:(CPControlSize)aSize
|
+ (CPFont)systemFontForControlSize:(CPControlSize)aSize
|
||||||
{
|
{
|
||||||
// TODO These sizes should be themable or made less arbitrary in some other way.
|
|
||||||
switch (aSize)
|
switch (aSize)
|
||||||
{
|
{
|
||||||
case CPSmallControlSize:
|
case CPSmallControlSize:
|
||||||
return _CPFontSystemFontSize - 1;
|
return [self systemFontOfSize:_CPFontSystemFontSizeSmall];
|
||||||
|
|
||||||
case CPMiniControlSize:
|
case CPMiniControlSize:
|
||||||
return _CPFontSystemFontSize - 2;
|
return [self systemFontOfSize:_CPFontSystemFontSizeMini];
|
||||||
|
|
||||||
case CPRegularControlSize:
|
case CPRegularControlSize:
|
||||||
default:
|
default:
|
||||||
return _CPFontSystemFontSize;
|
return [self systemFontOfSize:_CPFontSystemFontSize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +393,10 @@ following:
|
|||||||
_isItalic = isItalic;
|
_isItalic = isItalic;
|
||||||
_isSystem = isSystem;
|
_isSystem = isSystem;
|
||||||
|
|
||||||
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeState = CPThemeStateNormal;
|
||||||
|
[self _loadThemeAttributes];
|
||||||
|
|
||||||
if (isSystem)
|
if (isSystem)
|
||||||
{
|
{
|
||||||
_name = aName;
|
_name = aName;
|
||||||
@@ -431,8 +514,61 @@ following:
|
|||||||
_lineHeight = [metrics objectForKey:@"lineHeight"];
|
_lineHeight = [metrics objectForKey:@"lineHeight"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPControlSize)controlSizeCorrespondingToFontSize
|
||||||
|
{
|
||||||
|
switch (_size)
|
||||||
|
{
|
||||||
|
case _CPFontSystemFontSizeSmall:
|
||||||
|
return CPSmallControlSize;
|
||||||
|
|
||||||
|
case _CPFontSystemFontSizeMini:
|
||||||
|
return CPMiniControlSize;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// If we can't find a corresponding size, return regular control size
|
||||||
|
return CPRegularControlSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPFont(DescriptorAdditions)
|
||||||
|
|
||||||
|
- (id)_initWithFontDescriptor:(CPFontDescriptor)fontDescriptor
|
||||||
|
{
|
||||||
|
var aName = [fontDescriptor objectForKey: CPFontNameAttribute] ,
|
||||||
|
aSize = [fontDescriptor pointSize],
|
||||||
|
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
|
||||||
|
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
|
||||||
|
|
||||||
|
return [self _initWithName:aName size:aSize bold:isBold italic:isItalic system:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPFont)fontWithDescriptor:(CPFontDescriptor)fontDescriptor size:(float)aSize
|
||||||
|
{
|
||||||
|
var aName = [fontDescriptor objectForKey: CPFontNameAttribute],
|
||||||
|
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
|
||||||
|
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
|
||||||
|
|
||||||
|
return [self _fontWithName:aName size:aSize || [fontDescriptor pointSize] bold:isBold italic:isItalic];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPFontDescriptor)fontDescriptor
|
||||||
|
{
|
||||||
|
var traits = 0;
|
||||||
|
|
||||||
|
if ([self isBold])
|
||||||
|
traits |= CPFontBoldTrait;
|
||||||
|
|
||||||
|
if ([self isItalic])
|
||||||
|
traits |= CPFontItalicTrait;
|
||||||
|
|
||||||
|
return [[CPFontDescriptor fontDescriptorWithName:_name size:_size] fontDescriptorWithSymbolicTraits:traits];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
var CPFontNameKey = @"CPFontNameKey",
|
var CPFontNameKey = @"CPFontNameKey",
|
||||||
CPFontSizeKey = @"CPFontSizeKey",
|
CPFontSizeKey = @"CPFontSizeKey",
|
||||||
CPFontIsBoldKey = @"CPFontIsBoldKey",
|
CPFontIsBoldKey = @"CPFontIsBoldKey",
|
||||||
@@ -454,7 +590,11 @@ var CPFontNameKey = @"CPFontNameKey",
|
|||||||
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey],
|
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey],
|
||||||
isSystem = [aCoder decodeBoolForKey:CPFontIsSystemKey];
|
isSystem = [aCoder decodeBoolForKey:CPFontIsSystemKey];
|
||||||
|
|
||||||
return [self _initWithName:fontName size:size bold:isBold italic:isItalic system:isSystem];
|
self = [self _initWithName:fontName size:size bold:isBold italic:isItalic system:isSystem];
|
||||||
|
|
||||||
|
[self _decodeThemeObjectsWithCoder:aCoder];
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -468,6 +608,8 @@ var CPFontNameKey = @"CPFontNameKey",
|
|||||||
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
|
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
|
||||||
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
|
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
|
||||||
[aCoder encodeBool:_isSystem forKey:CPFontIsSystemKey];
|
[aCoder encodeBool:_isSystem forKey:CPFontIsSystemKey];
|
||||||
|
|
||||||
|
[self _encodeThemeObjectsWithCoder:aCoder];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+213
-31
@@ -22,9 +22,14 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CPControl.j"
|
||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
|
@import "CPFontDescriptor.j"
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
@class CPFontPanel
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
CPItalicFontMask = 1 << 0;
|
CPItalicFontMask = 1 << 0;
|
||||||
CPBoldFontMask = 1 << 1;
|
CPBoldFontMask = 1 << 1;
|
||||||
@@ -41,7 +46,20 @@ CPUnitalicFontMask = 1 << 24;
|
|||||||
|
|
||||||
|
|
||||||
var CPSharedFontManager = nil,
|
var CPSharedFontManager = nil,
|
||||||
CPFontManagerFactory = Nil;
|
CPFontManagerFactory = nil,
|
||||||
|
CPFontPanelFactory = nil;
|
||||||
|
|
||||||
|
/*
|
||||||
|
modifyFont: sender's tag
|
||||||
|
*/
|
||||||
|
CPNoFontChangeAction = 0;
|
||||||
|
CPViaPanelFontAction = 1;
|
||||||
|
CPAddTraitFontAction = 2;
|
||||||
|
CPSizeUpFontAction = 3;
|
||||||
|
CPSizeDownFontAction = 4;
|
||||||
|
CPHeavierFontAction = 5;
|
||||||
|
CPLighterFontAction = 6;
|
||||||
|
CPRemoveTraitFontAction = 7;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -59,6 +77,8 @@ var CPSharedFontManager = nil,
|
|||||||
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
|
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
|
||||||
|
|
||||||
CPDictionary _activeChange;
|
CPDictionary _activeChange;
|
||||||
|
|
||||||
|
unsigned _fontAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting the Shared Font Manager
|
// Getting the Shared Font Manager
|
||||||
@@ -83,6 +103,15 @@ var CPSharedFontManager = nil,
|
|||||||
{
|
{
|
||||||
CPFontManagerFactory = aClass;
|
CPFontManagerFactory = aClass;
|
||||||
}
|
}
|
||||||
|
/*!
|
||||||
|
Sets the class that will be used to create the application's
|
||||||
|
Font panel.
|
||||||
|
*/
|
||||||
|
+ (void)setFontPanelFactory:(Class)aClass
|
||||||
|
{
|
||||||
|
CPFontPanelFactory = aClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
@@ -163,35 +192,6 @@ var CPSharedFontManager = nil,
|
|||||||
return ([aFont isBold] ? CPBoldFontMask : 0) | ([aFont isItalic] ? CPItalicFontMask : 0);
|
return ([aFont isBold] ? CPBoldFontMask : 0) | ([aFont isItalic] ? CPItalicFontMask : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPFont)convertFont:(CPFont)aFont
|
|
||||||
{
|
|
||||||
if (!_activeChange)
|
|
||||||
return aFont;
|
|
||||||
|
|
||||||
var addTraits = [_activeChange valueForKey:@"addTraits"];
|
|
||||||
|
|
||||||
if (addTraits)
|
|
||||||
aFont = [self convertFont:aFont toHaveTrait:addTraits];
|
|
||||||
|
|
||||||
return aFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)addTraits
|
|
||||||
{
|
|
||||||
if (!aFont)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
var shouldBeBold = ([aFont isBold] || (addTraits & CPBoldFontMask)) && !(addTraits & CPUnboldFontMask),
|
|
||||||
shouldBeItalic = ([aFont isItalic] || (addTraits & CPItalicFontMask)) && !(addTraits & CPUnitalicFontMask),
|
|
||||||
shouldBeSize = [aFont size];
|
|
||||||
|
|
||||||
// XXX On the current platform there will always be a bold/italic version of each font, but still leave
|
|
||||||
// || aFont in here for future platforms.
|
|
||||||
aFont = [CPFont _fontWithName:[aFont familyName] size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
|
|
||||||
|
|
||||||
return aFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPFont)convertFont:(CPFont)aFont toFace:(CPString)aTypeface
|
- (CPFont)convertFont:(CPFont)aFont toFace:(CPString)aTypeface
|
||||||
{
|
{
|
||||||
if (!aFont)
|
if (!aFont)
|
||||||
@@ -209,7 +209,8 @@ var CPSharedFontManager = nil,
|
|||||||
- (@action)addFontTrait:(id)sender
|
- (@action)addFontTrait:(id)sender
|
||||||
{
|
{
|
||||||
var tag = [sender tag];
|
var tag = [sender tag];
|
||||||
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
|
_activeChange = tag == nil ? @{} : @{ @"addTraits": tag };
|
||||||
|
_fontAction = CPAddTraitFontAction;
|
||||||
|
|
||||||
[self sendAction];
|
[self sendAction];
|
||||||
}
|
}
|
||||||
@@ -219,6 +220,187 @@ var CPSharedFontManager = nil,
|
|||||||
return [CPApp sendAction:_action to:_target from:self];
|
return [CPApp sendAction:_action to:_target from:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This method open the font panel, create it if necessary.
|
||||||
|
@param sender The object that sent the message.
|
||||||
|
*/
|
||||||
|
- (CPFontPanel)fontPanel:(BOOL)createIt
|
||||||
|
{
|
||||||
|
var panel = nil,
|
||||||
|
panelExists = [CPFontPanelFactory sharedFontPanelExists];
|
||||||
|
|
||||||
|
if ((panelExists) || (!panelExists && createIt))
|
||||||
|
panel = [CPFontPanelFactory sharedFontPanel];
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convert a font to have the specified Font traits. The font is unchanged expect for the specified Font traits.
|
||||||
|
Using CPUnboldFontMask or CPUnitalicFontMask will respectively remove Bold and Italic traits.
|
||||||
|
@param aFont The font to convert.
|
||||||
|
@param fontTrait The new font traits mask.
|
||||||
|
@result The converted font or \c aFont if the conversion failed.
|
||||||
|
*/
|
||||||
|
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)fontTrait
|
||||||
|
{
|
||||||
|
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
|
||||||
|
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
|
||||||
|
|
||||||
|
if (fontTrait & CPBoldFontMask)
|
||||||
|
symbolicTrait |= CPFontBoldTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPItalicFontMask)
|
||||||
|
symbolicTrait |= CPFontItalicTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPUnboldFontMask) /* FIXME: this only change CPFontSymbolicTrait what about CPFontWeightTrait */
|
||||||
|
symbolicTrait &= ~CPFontBoldTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPUnitalicFontMask)
|
||||||
|
symbolicTrait &= ~CPFontItalicTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPExpandedFontMask)
|
||||||
|
symbolicTrait |= CPFontExpandedTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPSmallCapsFontMask)
|
||||||
|
symbolicTrait |= CPFontSmallCapsTrait;
|
||||||
|
|
||||||
|
if (![attributes containsKey:CPFontTraitsAttribute])
|
||||||
|
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||||
|
forKey:CPFontSymbolicTrait]
|
||||||
|
forKey:CPFontTraitsAttribute];
|
||||||
|
else
|
||||||
|
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||||
|
forKey:CPFontSymbolicTrait];
|
||||||
|
|
||||||
|
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convert a font to not have the specified Font traits. The font is unchanged expect for the specified Font traits.
|
||||||
|
@param aFont The font to convert.
|
||||||
|
@param fontTrait The font traits mask to remove.
|
||||||
|
@result The converted font or \c aFont if the conversion failed.
|
||||||
|
*/
|
||||||
|
- (CPFont)convertFont:(CPFont)aFont toNotHaveTrait:(CPFontTraitMask)fontTrait
|
||||||
|
{
|
||||||
|
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
|
||||||
|
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
|
||||||
|
|
||||||
|
if ((fontTrait & CPBoldFontMask) || (fontTrait & CPUnboldFontMask)) /* FIXME: see convertFont:toHaveTrait: about CPFontWeightTrait */
|
||||||
|
symbolicTrait &= ~CPFontBoldTrait;
|
||||||
|
|
||||||
|
if ((fontTrait & CPItalicFontMask) || (fontTrait & CPUnitalicFontMask))
|
||||||
|
symbolicTrait &= ~CPFontItalicTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPExpandedFontMask)
|
||||||
|
symbolicTrait &= ~CPFontExpandedTrait;
|
||||||
|
|
||||||
|
if (fontTrait & CPSmallCapsFontMask)
|
||||||
|
symbolicTrait &= ~CPFontSmallCapsTrait;
|
||||||
|
|
||||||
|
if (![attributes containsKey:CPFontTraitsAttribute])
|
||||||
|
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||||
|
forKey:CPFontSymbolicTrait]
|
||||||
|
forKey:CPFontTraitsAttribute];
|
||||||
|
else
|
||||||
|
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||||
|
forKey:CPFontSymbolicTrait];
|
||||||
|
|
||||||
|
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convert a font to have specified size. The font is unchanged expect for the specified size.
|
||||||
|
@param aFont The font to convert.
|
||||||
|
@param aSize The new font size.
|
||||||
|
@result The converted font or \c aFont if the conversion failed.
|
||||||
|
*/
|
||||||
|
- (CPFont)convertFont:(CPFont)aFont toSize:(float)aSize
|
||||||
|
{
|
||||||
|
var descriptor = [aFont fontDescriptor];
|
||||||
|
|
||||||
|
return [[aFont class] fontWithDescriptor: descriptor size:aSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)orderFrontFontPanel:(id)sender
|
||||||
|
{
|
||||||
|
[[self fontPanel:YES] orderFront:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)modifyFont:(id)sender
|
||||||
|
{
|
||||||
|
_fontAction = [sender tag];
|
||||||
|
[self sendAction];
|
||||||
|
|
||||||
|
if (_selectedFont)
|
||||||
|
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This method causes the receiver to send its action message.
|
||||||
|
@param sender The object that sent the message. (a Font panel)
|
||||||
|
*/
|
||||||
|
- (void)modifyFontViaPanel:(id)sender
|
||||||
|
{
|
||||||
|
_fontAction = CPViaPanelFontAction;
|
||||||
|
if (_selectedFont)
|
||||||
|
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
|
||||||
|
|
||||||
|
[self sendAction];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convert a font according to current font changes, provided by the object that initiated the font change.
|
||||||
|
@param aFont The font to convert.
|
||||||
|
@result The converted font or \c aFont if the conversion failed.
|
||||||
|
*/
|
||||||
|
- (CPFont)convertFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
var newFont = nil;
|
||||||
|
|
||||||
|
switch (_fontAction)
|
||||||
|
{
|
||||||
|
case CPNoFontChangeAction:
|
||||||
|
newFont = aFont;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPViaPanelFontAction:
|
||||||
|
newFont = [[self fontPanel:NO] panelConvertFont:aFont];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPAddTraitFontAction:
|
||||||
|
newFont = aFont;
|
||||||
|
|
||||||
|
if (!_activeChange)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var addTraits = [_activeChange valueForKey:@"addTraits"];
|
||||||
|
|
||||||
|
if (addTraits)
|
||||||
|
newFont = [self convertFont:aFont toHaveTrait:addTraits];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSizeUpFontAction:
|
||||||
|
newFont = [self convertFont:aFont toSize:[aFont size] + 1.0]; /* any limit ? */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSizeDownFontAction:
|
||||||
|
if ([aFont size] > 1)
|
||||||
|
newFont = [self convertFont:aFont toSize:[aFont size] - 1.0];
|
||||||
|
/* else CPBeep() :-p */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CPLog.trace(@"-[" + [self className] + " " + _cmd + "] unsupported font action: " + _fontAction + " aFont unchanged");
|
||||||
|
newFont = aFont;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newFont;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var _CPFontDetectSpan,
|
var _CPFontDetectSpan,
|
||||||
|
|||||||
+6
-5
@@ -70,11 +70,12 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
|||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
{
|
{
|
||||||
var cgColors = [],
|
var colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB,
|
||||||
count = [someColors count],
|
cgColors = [someColors arrayByApplyingBlock:function(color)
|
||||||
colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB;
|
{
|
||||||
for (var i = 0; i < count; i++)
|
return CGColorCreate(colorSpace, [color components])
|
||||||
cgColors.push(CGColorCreate(colorSpace, [someColors[i] components]));
|
}];
|
||||||
|
|
||||||
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
|
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -43,10 +43,10 @@ function CPDrawTiledRects(
|
|||||||
if (sides.length != grays.length)
|
if (sides.length != grays.length)
|
||||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
|
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
|
||||||
|
|
||||||
var colors = [];
|
var colors = [grays arrayByApplyingBlock:function(gray)
|
||||||
|
{
|
||||||
for (var i = 0; i < grays.length; ++i)
|
return [CPColor colorWithCalibratedWhite:gray alpha:1.0];
|
||||||
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
|
}];
|
||||||
|
|
||||||
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
|
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ var CPGraphicsContextCurrent = nil,
|
|||||||
@param aGraphicsPort the graphics port to initialize with
|
@param aGraphicsPort the graphics port to initialize with
|
||||||
@return the initialized context
|
@return the initialized context
|
||||||
*/
|
*/
|
||||||
- (id)initWithGraphicsPort:(CPContext)aGraphicsPort
|
- (id)initWithGraphicsPort:(CGContext)aGraphicsPort
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
|
|||||||
+459
-17
@@ -26,10 +26,28 @@
|
|||||||
@import <Foundation/CPRunLoop.j>
|
@import <Foundation/CPRunLoop.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
@import <Foundation/CPData.j>
|
@import <Foundation/CPData.j>
|
||||||
|
@import <Foundation/CPKeyedArchiver.j>
|
||||||
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
|
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
|
|
||||||
|
@class CPColor
|
||||||
|
@global document
|
||||||
|
|
||||||
|
@protocol CPImageDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)imageDidLoad:(CPImage)anImage;
|
||||||
|
- (void)imageDidError:(CPImage)anImage;
|
||||||
|
- (void)imageDidAbort:(CPImage)anImage;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPImageDelegate_imageDidLoad_ = 1 << 1,
|
||||||
|
CPImageDelegate_imageDidError_ = 1 << 2,
|
||||||
|
CPImageDelegate_imageDidAbort_ = 1 << 3;
|
||||||
|
|
||||||
CPImageLoadStatusInitialized = 0;
|
CPImageLoadStatusInitialized = 0;
|
||||||
CPImageLoadStatusLoading = 1;
|
CPImageLoadStatusLoading = 1;
|
||||||
CPImageLoadStatusCompleted = 2;
|
CPImageLoadStatusCompleted = 2;
|
||||||
@@ -71,9 +89,7 @@ function CPImageInBundle()
|
|||||||
|
|
||||||
if (typeof(arguments[1]) === "number")
|
if (typeof(arguments[1]) === "number")
|
||||||
{
|
{
|
||||||
if (arguments[1] !== nil && arguments[1] !== undefined)
|
size = CGSizeMake(arguments[1], arguments[2]);
|
||||||
size = CGSizeMake(arguments[1], arguments[2]);
|
|
||||||
|
|
||||||
bundle = arguments[3];
|
bundle = arguments[3];
|
||||||
}
|
}
|
||||||
else if (typeof(arguments[1]) === "object")
|
else if (typeof(arguments[1]) === "object")
|
||||||
@@ -119,14 +135,15 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
*/
|
*/
|
||||||
@implementation CPImage : CPObject
|
@implementation CPImage : CPObject
|
||||||
{
|
{
|
||||||
CGSize _size;
|
CGSize _size;
|
||||||
CPString _filename;
|
CPString _filename;
|
||||||
CPString _name;
|
CPString _name;
|
||||||
|
|
||||||
id _delegate;
|
id <CPImageDelegate> _delegate;
|
||||||
unsigned _loadStatus;
|
unsigned _loadStatus;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
Image _image;
|
Image _image;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -146,7 +163,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||||
{
|
{
|
||||||
// Quietly return nil like in Cocoa, rather than crashing later.
|
// Quietly return nil like in Cocoa, rather than crashing later.
|
||||||
if (aFilename === undefined || aFilename === nil)
|
if (aFilename == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -231,7 +248,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
var canvas = document.createElement("canvas"),
|
var canvas = document.createElement("canvas"),
|
||||||
ctx = canvas.getContext("2d");
|
ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
canvas.width = _image.width,
|
canvas.width = _image.width;
|
||||||
canvas.height = _image.height;
|
canvas.height = _image.height;
|
||||||
|
|
||||||
ctx.drawImage(_image, 0, 0);
|
ctx.drawImage(_image, 0, 0);
|
||||||
@@ -260,7 +277,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
*/
|
*/
|
||||||
- (CGSize)size
|
- (CGSize)size
|
||||||
{
|
{
|
||||||
return _size;
|
return CGSizeMakeCopy(_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)imageNamed:(CPString)aName
|
+ (id)imageNamed:(CPString)aName
|
||||||
@@ -319,9 +336,22 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
Sets the receiver's delegate.
|
Sets the receiver's delegate.
|
||||||
@param the delegate
|
@param the delegate
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPImageDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
|
||||||
|
_implementedDelegateMethods |= CPImageDelegate_imageDidLoad_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(imageDidError:)])
|
||||||
|
_implementedDelegateMethods |= CPImageDelegate_imageDidError_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
|
||||||
|
_implementedDelegateMethods |= CPImageDelegate_imageDidAbort_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -418,6 +448,11 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isMaterialIconImage
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (CPString)description
|
- (CPString)description
|
||||||
{
|
{
|
||||||
var filename = [self filename],
|
var filename = [self filename],
|
||||||
@@ -457,7 +492,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
postNotificationName:CPImageDidLoadNotification
|
postNotificationName:CPImageDidLoadNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
|
if (_implementedDelegateMethods & CPImageDelegate_imageDidLoad_)
|
||||||
[_delegate imageDidLoad:self];
|
[_delegate imageDidLoad:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +501,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
{
|
{
|
||||||
_loadStatus = CPImageLoadStatusReadError;
|
_loadStatus = CPImageLoadStatusReadError;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(imageDidError:)])
|
if (_implementedDelegateMethods & CPImageDelegate_imageDidError_)
|
||||||
[_delegate imageDidError:self];
|
[_delegate imageDidError:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,12 +510,235 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
{
|
{
|
||||||
_loadStatus = CPImageLoadStatusCancelled;
|
_loadStatus = CPImageLoadStatusCancelled;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
|
if (_implementedDelegateMethods & CPImageDelegate_imageDidAbort_)
|
||||||
[_delegate imageDidAbort:self];
|
[_delegate imageDidAbort:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CSS Theming
|
||||||
|
|
||||||
|
// The code below adds support for CSS theming with 100% compatibility with current theming system.
|
||||||
|
// The idea is to extend CPImage (and CPColor) with CSS components and adapt low level UI components to
|
||||||
|
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
|
||||||
|
//
|
||||||
|
// To create a CPImage that uses CSS, simply use the new class method :
|
||||||
|
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||||
|
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
|
||||||
|
// If you don't need them, just use the simplified class method :
|
||||||
|
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
|
||||||
|
//
|
||||||
|
// Examples :
|
||||||
|
// regularImageNormal = [CPImage imageWithCSSDictionary:@{
|
||||||
|
// @"border-color": A3ColorActiveBorder,
|
||||||
|
// @"border-style": @"solid",
|
||||||
|
// @"border-width": @"1px",
|
||||||
|
// @"border-radius": @"50%",
|
||||||
|
// @"box-sizing": @"border-box",
|
||||||
|
// @"background-color": A3ColorBackgroundWhite,
|
||||||
|
// @"transition-duration": @"0.35s",
|
||||||
|
// @"transition-property": @"all",
|
||||||
|
// @"transition-timing-function": @"ease"
|
||||||
|
// }
|
||||||
|
// size:CGSizeMake(16,16)];
|
||||||
|
//
|
||||||
|
// imageSearch = [CPImage imageWithCSSDictionary:@{
|
||||||
|
// @"background-image": @"url(%%packed.png)",
|
||||||
|
// @"background-position": @"-16px -32px",
|
||||||
|
// @"background-repeat": @"no-repeat",
|
||||||
|
// @"background-size": @"100px 400px"
|
||||||
|
// }
|
||||||
|
// size:CGSizeMake(16,16)];
|
||||||
|
//
|
||||||
|
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
|
||||||
|
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
|
||||||
|
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
|
||||||
|
//
|
||||||
|
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
|
||||||
|
// aCssImage = [CPImage imageWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
|
||||||
|
//
|
||||||
|
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
|
||||||
|
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
|
||||||
|
//
|
||||||
|
// Remark : -(DOMElement)applyCSSImageForView is meant to be used by low level UI widgets (like CPImageView and _CPImageAndTextView) to implement CSS theme support.
|
||||||
|
//
|
||||||
|
// In some circumstances, you may have to clear a CSS image. You can do this easily by replacing your current image with the special dummy empty CSS image :
|
||||||
|
// [CPImage dummyCSSImageOfSize:CGSizeMake(someWidth, someHeight)]
|
||||||
|
|
||||||
|
@implementation CPImage (CSSTheming)
|
||||||
|
{
|
||||||
|
CPDictionary _cssDictionary @accessors(property=cssDictionary);
|
||||||
|
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
|
||||||
|
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
|
||||||
|
CGSize _displaySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
|
||||||
|
{
|
||||||
|
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil size:aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||||
|
{
|
||||||
|
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary size:aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)dummyCSSImageOfSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
// This is used to clear a previous CSS image
|
||||||
|
return [[CPImage alloc] initWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:nil size:aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)imageWithMaterialIconNamed:(CPString)iconName size:(CGSize)size
|
||||||
|
{
|
||||||
|
return [_CPMaterialIconImage imageWithIconNamed:iconName size:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)imageWithMaterialIconNamed:(CPString)iconName size:(CGSize)size color:(CPColor)color
|
||||||
|
{
|
||||||
|
return [_CPMaterialIconImage imageWithIconNamed:iconName size:size color:color];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_size = CGSizeMakeCopy(aSize);
|
||||||
|
_filename = @"CSS image";
|
||||||
|
_loadStatus = CPImageLoadStatusCompleted;
|
||||||
|
_cssDictionary = aDictionary;
|
||||||
|
_cssBeforeDictionary = beforeDictionary;
|
||||||
|
_cssAfterDictionary = afterDictionary;
|
||||||
|
_displaySize = CGSizeMakeCopy(aSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isCSSBased
|
||||||
|
{
|
||||||
|
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSDictionary
|
||||||
|
{
|
||||||
|
return ([_cssDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSBeforeDictionary
|
||||||
|
{
|
||||||
|
return ([_cssBeforeDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCSSAfterDictionary
|
||||||
|
{
|
||||||
|
return ([_cssAfterDictionary count] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DOMElement)applyCSSImageForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
// First, restore previous CSS styling before applying the new one
|
||||||
|
|
||||||
|
var aPreviousState = @deref(aPreviousStateRef);
|
||||||
|
|
||||||
|
for (var i = 0, count = aPreviousState.length; i < count; i++)
|
||||||
|
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
|
||||||
|
|
||||||
|
aPreviousState = @[];
|
||||||
|
|
||||||
|
// Then apply new CSS styling
|
||||||
|
|
||||||
|
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
|
||||||
|
aDOMElement.style[aKey] = anObject;
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (_cssBeforeDictionary || _cssAfterDictionary)
|
||||||
|
{
|
||||||
|
// We need to create a unique class name
|
||||||
|
|
||||||
|
var styleClassName = @".CP" + [aView UID],
|
||||||
|
styleContent = @"";
|
||||||
|
|
||||||
|
if (_cssBeforeDictionary)
|
||||||
|
{
|
||||||
|
styleContent += styleClassName + @"::before { ";
|
||||||
|
|
||||||
|
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
styleContent += aKey + ": " + anObject + "; ";
|
||||||
|
}];
|
||||||
|
|
||||||
|
styleContent += "} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cssAfterDictionary)
|
||||||
|
{
|
||||||
|
styleContent += styleClassName + @"::after { ";
|
||||||
|
|
||||||
|
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||||
|
{
|
||||||
|
styleContent += aKey + ": " + anObject + "; ";
|
||||||
|
}];
|
||||||
|
|
||||||
|
styleContent += "} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
var styleDescription = document.createTextNode(styleContent);
|
||||||
|
|
||||||
|
if (!aStyleNode)
|
||||||
|
{
|
||||||
|
aStyleNode = document.createElement("style");
|
||||||
|
|
||||||
|
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
|
||||||
|
|
||||||
|
aStyleNode.appendChild(styleDescription);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
aDOMElement.className = @"CP"+[aView UID];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no before/after so remove aStyleNode if existing
|
||||||
|
|
||||||
|
if (aStyleNode)
|
||||||
|
{
|
||||||
|
aView._DOMElement.removeChild(aStyleNode);
|
||||||
|
aStyleNode = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return actualised values
|
||||||
|
|
||||||
|
@deref(aPreviousStateRef) = aPreviousState;
|
||||||
|
|
||||||
|
return aStyleNode;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_shouldBeResized
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPImageCSSDictionaryKey = @"CPImageCSSDictionaryKey",
|
||||||
|
CPImageCSSBeforeDictionaryKey = @"CPImageCSSBeforeDictionaryKey",
|
||||||
|
CPImageCSSAfterDictionaryKey = @"CPImageCSSAfterDictionaryKey";
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
@implementation CPImage (CPCoding)
|
@implementation CPImage (CPCoding)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -490,7 +748,10 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
if ([aCoder containsValueForKey:CPImageCSSDictionaryKey])
|
||||||
|
return [self initWithCSSDictionary:[aCoder decodeObjectForKey:CPImageCSSDictionaryKey] beforeDictionary:[aCoder decodeObjectForKey:CPImageCSSBeforeDictionaryKey] afterDictionary:[aCoder decodeObjectForKey:CPImageCSSAfterDictionaryKey] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
||||||
|
else
|
||||||
|
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -501,10 +762,180 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
{
|
{
|
||||||
[aCoder encodeObject:_filename forKey:@"CPFilename"];
|
[aCoder encodeObject:_filename forKey:@"CPFilename"];
|
||||||
[aCoder encodeSize:_size forKey:@"CPSize"];
|
[aCoder encodeSize:_size forKey:@"CPSize"];
|
||||||
|
|
||||||
|
// CSS Styling
|
||||||
|
if ([self isCSSBased])
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_cssDictionary forKey:CPImageCSSDictionaryKey];
|
||||||
|
[aCoder encodeObject:_cssBeforeDictionary forKey:CPImageCSSBeforeDictionaryKey];
|
||||||
|
[aCoder encodeObject:_cssAfterDictionary forKey:CPImageCSSAfterDictionaryKey];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPMaterialIconImage : CPImage
|
||||||
|
{
|
||||||
|
CPMutableDictionary _cachedColorVersions;
|
||||||
|
CPColor _cachedInvertedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPMaterialIconImage)imageWithIconNamed:(CPString)iconName size:(CGSize)size
|
||||||
|
{
|
||||||
|
return [[_CPMaterialIconImage alloc] initWithIconName:iconName size:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPMaterialIconImage)imageWithIconNamed:(CPString)iconName size:(CGSize)size color:(CPColor)color
|
||||||
|
{
|
||||||
|
return [[_CPMaterialIconImage alloc] initWithIconName:iconName size:size color:color];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPMaterialIconImage)imageWithIconNamed:(CPString)iconName size:(CGSize)size color:(CPColor)color additionalCSSDictionary:(CPDictionary)additionalCSSDictionary
|
||||||
|
{
|
||||||
|
return [[_CPMaterialIconImage alloc] initWithIconName:iconName size:size color:color additionalCSSDictionary:additionalCSSDictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDictionary)_baseMaterialIconCSSDictionaryForIconName:(CPString)iconName size:(CGSize)size
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"width": size.width + @"px",
|
||||||
|
@"height": size.height + @"px",
|
||||||
|
@"top": @"0px",
|
||||||
|
@"left": @"0px",
|
||||||
|
@"content": @"'" + iconName + @"'",
|
||||||
|
|
||||||
|
@"position": @"absolute",
|
||||||
|
@"z-index": @"300",
|
||||||
|
|
||||||
|
@"font-family": @"'Material Icons'",
|
||||||
|
@"font-weight": @"normal",
|
||||||
|
@"font-style": @"normal",
|
||||||
|
@"font-size": MIN(size.width, size.height) + @"px",
|
||||||
|
@"display": @"inline-block",
|
||||||
|
@"line-height": @"1",
|
||||||
|
@"text-transform": @"none",
|
||||||
|
@"letter-spacing": @"normal",
|
||||||
|
@"word-wrap": @"normal",
|
||||||
|
@"white-space": @"nowrap",
|
||||||
|
@"direction": @"ltr",
|
||||||
|
@"-webkit-font-smoothing": @"antialiased",
|
||||||
|
@"text-rendering": @"optimizeLegibility",
|
||||||
|
@"-moz-osx-font-smoothing": @"grayscale",
|
||||||
|
@"font-feature-settings": @"'liga'"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPMaterialIconImage)initWithIconName:(CPString)iconName size:(CGSize)size
|
||||||
|
{
|
||||||
|
return [super initWithCSSDictionary:@{}
|
||||||
|
beforeDictionary:@{}
|
||||||
|
afterDictionary:[self _baseMaterialIconCSSDictionaryForIconName:iconName size:size]
|
||||||
|
size:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPMaterialIconImage)initWithIconName:(CPString)iconName size:(CGSize)size color:(CPColor)color
|
||||||
|
{
|
||||||
|
var materialIconCSSDictionary = [self _baseMaterialIconCSSDictionaryForIconName:iconName size:size];
|
||||||
|
|
||||||
|
[materialIconCSSDictionary setObject:[color cssString] forKey:@"color"];
|
||||||
|
|
||||||
|
return [super initWithCSSDictionary:@{}
|
||||||
|
beforeDictionary:@{}
|
||||||
|
afterDictionary:materialIconCSSDictionary
|
||||||
|
size:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addRotationEffectWithAngle:(float)angle
|
||||||
|
{
|
||||||
|
[self addCSSDictionary:@{
|
||||||
|
@"transform": @"rotate("+angle+"deg)",
|
||||||
|
@"transition": @"transform 0.35s ease"
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addCSSDictionary:(CPDictionary)additionalCSSDictionary
|
||||||
|
{
|
||||||
|
[_cssAfterDictionary addEntriesFromDictionary:additionalCSSDictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
[self _setDisplaySize:aSize];
|
||||||
|
[super setSize:aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setDisplaySize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
if (CGSizeEqualToSize(_displaySize, aSize))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_displaySize = CGSizeMakeCopy(aSize);
|
||||||
|
|
||||||
|
[_cssAfterDictionary setObject:(aSize.width + @"px") forKey:@"width"];
|
||||||
|
[_cssAfterDictionary setObject:(aSize.height + @"px") forKey:@"height"];
|
||||||
|
[_cssAfterDictionary setObject:(MIN(aSize.width, aSize.height) + @"px") forKey:@"font-size"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_shouldBeResized
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isMaterialIconImage
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPMaterialIconImage)invertedImage
|
||||||
|
{
|
||||||
|
if (!_cachedInvertedColor)
|
||||||
|
{
|
||||||
|
var sourceCSSColor = [_cssAfterDictionary objectForKey:@"color"] || @"rgba(0,0,0,1)",
|
||||||
|
sourceColor = [CPColor colorWithCSSString:sourceCSSColor];
|
||||||
|
|
||||||
|
_cachedInvertedColor = [CPColor colorWithRed:(1-[sourceColor redComponent])
|
||||||
|
green:(1-[sourceColor greenComponent])
|
||||||
|
blue:(1-[sourceColor blueComponent])
|
||||||
|
alpha:[sourceColor alphaComponent]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self imageVersionWithColor:_cachedInvertedColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPMaterialIconImage)imageVersionWithColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
// We can't just set the color in the cssAfterDictionary as this would not be noticed as a new image,
|
||||||
|
// so -setImage won't do anything, so no visual refresh won't occur.
|
||||||
|
// The trick here is to keep in cache a clone of this image for each needed color.
|
||||||
|
var colorCSSString = [aColor cssString];
|
||||||
|
|
||||||
|
if (!_cachedColorVersions)
|
||||||
|
_cachedColorVersions = @{};
|
||||||
|
|
||||||
|
var cachedColorVersion = [_cachedColorVersions objectForKey:colorCSSString];
|
||||||
|
|
||||||
|
if (!cachedColorVersion)
|
||||||
|
{
|
||||||
|
cachedColorVersion = [self duplicate];
|
||||||
|
[cachedColorVersion _setCSSColor:colorCSSString];
|
||||||
|
|
||||||
|
[_cachedColorVersions setObject:cachedColorVersion forKey:colorCSSString];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedColorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setCSSColor:(CPString)aCSSColor
|
||||||
|
{
|
||||||
|
[_cssAfterDictionary setObject:aCSSColor forKey:@"color"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
@implementation CPThreePartImage : CPObject
|
@implementation CPThreePartImage : CPObject
|
||||||
{
|
{
|
||||||
CPArray _imageSlices;
|
CPArray _imageSlices;
|
||||||
@@ -645,3 +1076,14 @@ var CPNinePartImageImageSlicesKey = @"CPNinePartImageImageSlicesKey";
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPImage (Duplication)
|
||||||
|
|
||||||
|
- (CPImage)duplicate
|
||||||
|
{
|
||||||
|
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+49
-6
@@ -29,6 +29,9 @@
|
|||||||
@global CPImagesPboardType
|
@global CPImagesPboardType
|
||||||
@global appkit_tag_dom_elements
|
@global appkit_tag_dom_elements
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
|
@typedef CPImageAlignment
|
||||||
CPImageAlignCenter = 0;
|
CPImageAlignCenter = 0;
|
||||||
CPImageAlignTop = 1;
|
CPImageAlignTop = 1;
|
||||||
CPImageAlignTopLeft = 2;
|
CPImageAlignTopLeft = 2;
|
||||||
@@ -97,10 +100,32 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
- (void)_createDOMImageElement
|
- (void)_createDOMImageElement
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
if (_DOMImageElement)
|
var image = [self objectValue],
|
||||||
return;
|
isCSSBasedImage = [image isCSSBased],
|
||||||
|
isIMGImageElement = _DOMImageElement && (_DOMImageElement.nodeName == "IMG");
|
||||||
|
|
||||||
_DOMImageElement = document.createElement("img");
|
// First, check if we need to destroy a current DOM image element. This is the case if :
|
||||||
|
// - we have one but not the right one (that is a DIV but needing an IMG, and vice versa)
|
||||||
|
|
||||||
|
if (_DOMImageElement)
|
||||||
|
{
|
||||||
|
if ((isIMGImageElement && isCSSBasedImage) || (!isIMGImageElement && !isCSSBasedImage))
|
||||||
|
{
|
||||||
|
// OK, destroy it
|
||||||
|
|
||||||
|
_DOMElement.removeChild(_DOMImageElement);
|
||||||
|
|
||||||
|
_DOMImageElement = nil;
|
||||||
|
|
||||||
|
// CSS styling cleaning
|
||||||
|
_cssStylePreviousState = @[];
|
||||||
|
_cssStyleNode = nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_DOMImageElement = document.createElement(isCSSBasedImage ? "div" : "img");
|
||||||
_DOMImageElement.style.position = "absolute";
|
_DOMImageElement.style.position = "absolute";
|
||||||
_DOMImageElement.style.left = "0px";
|
_DOMImageElement.style.left = "0px";
|
||||||
_DOMImageElement.style.top = "0px";
|
_DOMImageElement.style.top = "0px";
|
||||||
@@ -149,10 +174,15 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
var newImage = [self objectValue];
|
var newImage = [self objectValue];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
if (!_DOMImageElement)
|
[self _createDOMImageElement];
|
||||||
[self _createDOMImageElement];
|
|
||||||
|
|
||||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
if ([newImage isCSSBased])
|
||||||
|
_cssStyleNode = [newImage applyCSSImageForView:self
|
||||||
|
onDOMElement:_DOMImageElement
|
||||||
|
styleNode:_cssStyleNode
|
||||||
|
previousState:@ref(_cssStylePreviousState)];
|
||||||
|
else
|
||||||
|
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var size = [newImage size];
|
var size = [newImage size];
|
||||||
@@ -178,6 +208,7 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
|
|
||||||
- (void)imageDidLoad:(CPNotification)aNotification
|
- (void)imageDidLoad:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPImageDidLoadNotification object:[self objectValue]];
|
||||||
[self hideOrDisplayContents];
|
[self hideOrDisplayContents];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
@@ -415,6 +446,18 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
if ([image isCSSBased] && [image _shouldBeResized])
|
||||||
|
{
|
||||||
|
[image _setDisplaySize:CGSizeMake(ROUND(width), ROUND(height))];
|
||||||
|
|
||||||
|
_cssStyleNode = [image applyCSSImageForView:self
|
||||||
|
onDOMElement:_DOMImageElement
|
||||||
|
styleNode:_cssStyleNode
|
||||||
|
previousState:@ref(_cssStylePreviousState)];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
_imageRect = CGRectMake(x, y, width, height);
|
_imageRect = CGRectMake(x, y, width, height);
|
||||||
|
|
||||||
if (_hasShadow)
|
if (_hasShadow)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
var exposedBindingsMap = @{},
|
var exposedBindingsMap = @{},
|
||||||
bindingsMap = @{};
|
bindingsMap = @{};
|
||||||
|
|
||||||
|
@typedef CPBindingOperationKind
|
||||||
var CPBindingOperationAnd = 0,
|
var CPBindingOperationAnd = 0,
|
||||||
CPBindingOperationOr = 1;
|
CPBindingOperationOr = 1;
|
||||||
|
|
||||||
@@ -70,6 +71,20 @@ var CPBindingOperationAnd = 0,
|
|||||||
return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
|
return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)_reverseSetValueFromExclusiveBinderForObject:(id)anObject
|
||||||
|
{
|
||||||
|
var bindersByBindingName = [bindingsMap objectForKey:[anObject UID]];
|
||||||
|
|
||||||
|
[bindersByBindingName enumerateKeysAndObjectsUsingBlock:function(binding, binder, stop)
|
||||||
|
{
|
||||||
|
if ([binder isKindOfClass:[self class]])
|
||||||
|
{
|
||||||
|
[binder reverseSetValueFor:binding];
|
||||||
|
stop(YES);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
|
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
|
||||||
{
|
{
|
||||||
var theBinding = [self getBinding:aBinding forObject:anObject];
|
var theBinding = [self getBinding:aBinding forObject:anObject];
|
||||||
@@ -116,7 +131,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
count = allKeys.length;
|
count = allKeys.length;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
[anObject unbind:[bindings objectForKey:allKeys[count]]];
|
[anObject unbind:allKeys[count]];
|
||||||
|
|
||||||
[bindingsMap removeObjectForKey:[anObject UID]];
|
[bindingsMap removeObjectForKey:[anObject UID]];
|
||||||
}
|
}
|
||||||
@@ -142,7 +157,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
|
|
||||||
[self _updatePlaceholdersWithOptions:options forBinding:aName];
|
[self _updatePlaceholdersWithOptions:options forBinding:aName];
|
||||||
|
|
||||||
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
|
[aDestination addObserver:self forKeyPath:aKeyPath options:0 context:aBinding];
|
||||||
|
|
||||||
var bindings = [bindingsMap objectForKey:[_source UID]];
|
var bindings = [bindingsMap objectForKey:[_source UID]];
|
||||||
|
|
||||||
@@ -159,6 +174,24 @@ var CPBindingOperationAnd = 0,
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingAllowed:(CPString)aBinding forObject:(id)anObject
|
||||||
|
{
|
||||||
|
if ([[anObject class] isBindingExclusive:aBinding])
|
||||||
|
{
|
||||||
|
var bindingsForObject = [bindingsMap objectForKey:[anObject UID]],
|
||||||
|
allBindings = [bindingsForObject allKeys],
|
||||||
|
count = [allBindings count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
if ([[anObject class] isBindingExclusive:allBindings[count]])
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)raiseIfNotApplicable:(id)aValue forKeyPath:(CPString)keyPath options:(CPDictionary)options
|
- (void)raiseIfNotApplicable:(id)aValue forKeyPath:(CPString)keyPath options:(CPDictionary)options
|
||||||
{
|
{
|
||||||
if (aValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
if (aValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||||
@@ -260,7 +293,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
// If the value is nil AND the source doesn't respond to setPlaceholderString: then
|
// If the value is nil AND the source doesn't respond to setPlaceholderString: then
|
||||||
// we set the value to the placeholder. Otherwise, we do not want to short cut the process
|
// we set the value to the placeholder. Otherwise, we do not want to short cut the process
|
||||||
// of setting the placeholder that is based on the fact that the value is nil.
|
// of setting the placeholder that is based on the fact that the value is nil.
|
||||||
if ((aValue === undefined || aValue === nil || aValue === [CPNull null])
|
if ((aValue == nil || aValue === [CPNull null])
|
||||||
&& ![_source respondsToSelector:@selector(setPlaceholderString:)])
|
&& ![_source respondsToSelector:@selector(setPlaceholderString:)])
|
||||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||||
|
|
||||||
@@ -387,6 +420,11 @@ var CPBindingOperationAnd = 0,
|
|||||||
return [CPBinder class];
|
return [CPBinder class];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (CPArray)exposedBindings
|
- (CPArray)exposedBindings
|
||||||
{
|
{
|
||||||
var exposedBindings = [],
|
var exposedBindings = [],
|
||||||
@@ -415,6 +453,11 @@ var CPBindingOperationAnd = 0,
|
|||||||
if (!anObject || !aKeyPath)
|
if (!anObject || !aKeyPath)
|
||||||
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
||||||
|
|
||||||
|
if (![CPBinder isBindingAllowed:aBinding forObject:self])
|
||||||
|
{
|
||||||
|
CPLog.warn([self description] + " : cannot bind " + aBinding + " because another binding with the same functionality is already in use.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
//if (![[self exposedBindings] containsObject:aBinding])
|
//if (![[self exposedBindings] containsObject:aBinding])
|
||||||
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
|
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
|
||||||
|
|
||||||
@@ -610,7 +653,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
value = [object valueForKeyPath:keyPath];
|
value = [object valueForKeyPath:keyPath];
|
||||||
|
|
||||||
if (value === nil || value === undefined)
|
if (value == nil)
|
||||||
{
|
{
|
||||||
[_source setEnabled:NO];
|
[_source setEnabled:NO];
|
||||||
return;
|
return;
|
||||||
@@ -753,7 +796,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
else
|
else
|
||||||
value = [theBinding transformValue:value withOptions:options];
|
value = [theBinding transformValue:value withOptions:options];
|
||||||
|
|
||||||
if (value === nil || value === undefined)
|
if (value == nil)
|
||||||
value = @"";
|
value = @"";
|
||||||
|
|
||||||
result.value = result.value.replace("%{" + _patternPlaceholder + count + "}@", [value description]);
|
result.value = result.value.replace("%{" + _patternPlaceholder + count + "}@", [value description]);
|
||||||
@@ -814,7 +857,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
- (id)initWithName:(CPString)aName
|
- (id)initWithName:(CPString)aName
|
||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
_name = aName
|
_name = aName;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -875,6 +918,7 @@ CPTextColorBinding = @"textColor";
|
|||||||
CPTitleBinding = @"title";
|
CPTitleBinding = @"title";
|
||||||
CPToolTipBinding = @"toolTip";
|
CPToolTipBinding = @"toolTip";
|
||||||
CPValueBinding = @"value";
|
CPValueBinding = @"value";
|
||||||
|
CPAttributedStringBinding = @"attributedString";
|
||||||
CPValueURLBinding = @"valueURL";
|
CPValueURLBinding = @"valueURL";
|
||||||
CPValuePathBinding = @"valuePath";
|
CPValuePathBinding = @"valuePath";
|
||||||
CPDataBinding = @"data";
|
CPDataBinding = @"data";
|
||||||
|
|||||||
+19
-11
@@ -22,14 +22,11 @@
|
|||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@import "CPWindow_Constants.j"
|
@import "CPWindow_Constants.j"
|
||||||
|
@import "CPSlider.j"
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
CPTickMarkBelow = 0;
|
@typedef CPLevelIndicatorStyle
|
||||||
CPTickMarkAbove = 1;
|
|
||||||
CPTickMarkLeft = CPTickMarkAbove;
|
|
||||||
CPTickMarkRight = CPTickMarkBelow;
|
|
||||||
|
|
||||||
CPRelevancyLevelIndicatorStyle = 0;
|
CPRelevancyLevelIndicatorStyle = 0;
|
||||||
CPContinuousCapacityLevelIndicatorStyle = 1;
|
CPContinuousCapacityLevelIndicatorStyle = 1;
|
||||||
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
||||||
@@ -105,10 +102,21 @@ CPRatingLevelIndicatorStyle = 3;
|
|||||||
var filledColor = [self valueForThemeAttribute:@"color-normal"],
|
var filledColor = [self valueForThemeAttribute:@"color-normal"],
|
||||||
value = [self doubleValue];
|
value = [self doubleValue];
|
||||||
|
|
||||||
if (value <= _criticalValue)
|
if (_warningValue < _criticalValue)
|
||||||
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
{
|
||||||
else if (value <= _warningValue)
|
if (value >= _criticalValue)
|
||||||
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||||
|
else if (value >= _warningValue)
|
||||||
|
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value <= _criticalValue)
|
||||||
|
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||||
|
else if (value <= _warningValue)
|
||||||
|
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for (var i = 0; i < segmentCount; i++)
|
for (var i = 0; i < segmentCount; i++)
|
||||||
{
|
{
|
||||||
@@ -279,7 +287,7 @@ CPRatingLevelIndicatorStyle = 3;
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWarningValue:(double)warningValue;
|
- (void)setWarningValue:(double)warningValue
|
||||||
{
|
{
|
||||||
if (_warningValue === warningValue)
|
if (_warningValue === warningValue)
|
||||||
return;
|
return;
|
||||||
@@ -288,7 +296,7 @@ CPRatingLevelIndicatorStyle = 3;
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCriticalValue:(double)criticalValue;
|
- (void)setCriticalValue:(double)criticalValue
|
||||||
{
|
{
|
||||||
if (_criticalValue === criticalValue)
|
if (_criticalValue === criticalValue)
|
||||||
return;
|
return;
|
||||||
|
|||||||
+101
-23
@@ -30,6 +30,17 @@
|
|||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
|
@protocol CPMenuDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)menuWillOpen:(CPMenu)aMenu;
|
||||||
|
- (void)menuDidClose:(CPMenu)aMenu;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPMenuDelegate_menuWillOpen_ = 1 << 1,
|
||||||
|
CPMenuDelegate_menuDidClose_ = 1 << 2;
|
||||||
|
|
||||||
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
||||||
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
||||||
CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
|
CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
|
||||||
@@ -50,26 +61,27 @@ var _CPMenuBarVisible = NO,
|
|||||||
*/
|
*/
|
||||||
@implementation CPMenu : CPObject
|
@implementation CPMenu : CPObject
|
||||||
{
|
{
|
||||||
CPMenu _supermenu;
|
CPMenu _supermenu;
|
||||||
|
|
||||||
CPString _title;
|
CPString _title;
|
||||||
CPString _name;
|
CPString _name;
|
||||||
|
|
||||||
CPFont _font;
|
CPFont _font;
|
||||||
|
|
||||||
float _minimumWidth;
|
float _minimumWidth;
|
||||||
|
|
||||||
CPMutableArray _items;
|
CPMutableArray _items;
|
||||||
|
|
||||||
BOOL _autoenablesItems;
|
BOOL _autoenablesItems;
|
||||||
BOOL _showsStateColumn;
|
BOOL _showsStateColumn;
|
||||||
|
|
||||||
id _delegate;
|
id <CPMenuDelegate> _delegate;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
int _highlightedIndex;
|
int _highlightedIndex;
|
||||||
_CPMenuWindow _menuWindow;
|
_CPMenuWindow _menuWindow;
|
||||||
|
|
||||||
CPEvent _lastCloseEvent;
|
CPEvent _lastCloseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing the Menu Bar
|
// Managing the Menu Bar
|
||||||
@@ -152,7 +164,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
+ (void)_setOrRemoveMenuBarAttribute:(id)aValue forKey:(id)aKey
|
+ (void)_setOrRemoveMenuBarAttribute:(id)aValue forKey:(id)aKey
|
||||||
{
|
{
|
||||||
if (aValue === nil)
|
if (aValue == nil)
|
||||||
[_CPMenuBarAttributes removeObjectForKey:aKey];
|
[_CPMenuBarAttributes removeObjectForKey:aKey];
|
||||||
else
|
else
|
||||||
[_CPMenuBarAttributes setObject:aValue forKey:aKey];
|
[_CPMenuBarAttributes setObject:aValue forKey:aKey];
|
||||||
@@ -639,6 +651,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
if (binder)
|
if (binder)
|
||||||
{
|
{
|
||||||
[binder setValueFor:CPEnabledBinding];
|
[binder setValueFor:CPEnabledBinding];
|
||||||
|
[[_menuWindow _menuView] tile];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -941,9 +954,19 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
// Managing the Delegate
|
// Managing the Delegate
|
||||||
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPMenuDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||||
|
_implementedDelegateMethods |= CPMenuDelegate_menuWillOpen_;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(menuDidClose:)])
|
||||||
|
_implementedDelegateMethods |= CPMenuDelegate_menuDidClose_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)delegate
|
- (id)delegate
|
||||||
@@ -953,10 +976,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
- (void)_menuWillOpen
|
- (void)_menuWillOpen
|
||||||
{
|
{
|
||||||
var delegate = [self delegate];
|
[self _sendDelegateMenuWillOpen];
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
|
||||||
[delegate menuWillOpen:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_menuDidClose
|
- (void)_menuDidClose
|
||||||
@@ -965,10 +985,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
// when a click on the button itself caused the menu to close.
|
// when a click on the button itself caused the menu to close.
|
||||||
_lastCloseEvent = [CPApp currentEvent];
|
_lastCloseEvent = [CPApp currentEvent];
|
||||||
|
|
||||||
var delegate = [self delegate];
|
[self _sendDelegateMenuDidClose];
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
|
||||||
[delegate menuDidClose:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling Tracking
|
// Handling Tracking
|
||||||
@@ -1114,7 +1131,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_menuWithName:(CPString)aName
|
- (CPMenu)_menuWithName:(CPString)aName
|
||||||
{
|
{
|
||||||
if (aName === _name)
|
if (aName === _name)
|
||||||
return self;
|
return self;
|
||||||
@@ -1132,6 +1149,36 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPMenu (CPMenuDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate menuWillOpen
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateMenuWillOpen
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPMenuDelegate_menuWillOpen_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate menuWillOpen:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate menuDidClose
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateMenuDidClose
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPMenuDelegate_menuDidClose_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate menuDidClose:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation CPMenu (CPKeyValueCoding)
|
@implementation CPMenu (CPKeyValueCoding)
|
||||||
|
|
||||||
- (CPUInteger)countOfItems
|
- (CPUInteger)countOfItems
|
||||||
@@ -1246,6 +1293,37 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPMenu (CSSTheming)
|
||||||
|
|
||||||
|
+ (void)setNamedValue:(CPString)aName forKey:(CPString)aKey inAttributes:(CPDictionary)aDictionary forTheme:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
var value = [aTheme valueForAttributeWithName:aName forClass:_CPMenuView];
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
[aDictionary setObject:value forKey:aKey];
|
||||||
|
else
|
||||||
|
[aDictionary removeObjectForKey:aKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)updateMenuBarAttributesWithTheme:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
var newAttributes = @{};
|
||||||
|
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-text-color" forKey:@"CPMenuBarTextColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-title-color" forKey:@"CPMenuBarTitleColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-text-shadow-color" forKey:@"CPMenuBarTextShadowColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-title-shadow-color" forKey:@"CPMenuBarTitleShadowColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-highlight-color" forKey:@"CPMenuBarHighlightColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-highlight-text-color" forKey:@"CPMenuBarHighlightTextColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
[CPMenu setNamedValue:@"menu-bar-highlight-text-shadow-color" forKey:@"CPMenuBarHighlightTextShadowColor" inAttributes:newAttributes forTheme:aTheme];
|
||||||
|
|
||||||
|
[CPMenu setMenuBarAttributes:newAttributes];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@import "_CPMenuBarWindow.j"
|
@import "_CPMenuBarWindow.j"
|
||||||
@import "_CPMenuWindow.j"
|
@import "_CPMenuWindow.j"
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,17 @@
|
|||||||
@import "_CPMenuManager.j"
|
@import "_CPMenuManager.j"
|
||||||
|
|
||||||
@class _CPMenuView
|
@class _CPMenuView
|
||||||
|
@class CPMenu
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
@global CPMenuDidAddItemNotification
|
@global CPMenuDidAddItemNotification
|
||||||
@global CPMenuDidChangeItemNotification
|
@global CPMenuDidChangeItemNotification
|
||||||
@global CPMenuDidRemoveItemNotification
|
@global CPMenuDidRemoveItemNotification
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
@implementation _CPMenuBarWindow : CPPanel
|
@implementation _CPMenuBarWindow : CPPanel
|
||||||
{
|
{
|
||||||
CPMenu _menu;
|
|
||||||
CPView _highlightView;
|
CPView _highlightView;
|
||||||
CPArray _menuItemViews;
|
CPArray _menuItemViews;
|
||||||
|
|
||||||
@@ -129,10 +132,12 @@
|
|||||||
|
|
||||||
- (void)setColor:(CPColor)aColor
|
- (void)setColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
|
var targetView = [[CPTheme defaultTheme] valueForAttributeWithName:@"css-based" forClass:CPView] ? [[self contentView] superview] : [self contentView];
|
||||||
|
|
||||||
if (!aColor)
|
if (!aColor)
|
||||||
[[self contentView] setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-background-color" forClass:_CPMenuView]];
|
[targetView setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-background-color" forClass:_CPMenuView]];
|
||||||
else
|
else
|
||||||
[[self contentView] setBackgroundColor:aColor];
|
[targetView setBackgroundColor:aColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTextColor:(CPColor)aColor
|
- (void)setTextColor:(CPColor)aColor
|
||||||
@@ -277,6 +282,16 @@
|
|||||||
[menuItemView setTextColor:_textColor];
|
[menuItemView setTextColor:_textColor];
|
||||||
[menuItemView setHidden:[item isHidden]];
|
[menuItemView setHidden:[item isHidden]];
|
||||||
|
|
||||||
|
// If first menu item has tag -1 and if there is a special theme value menu-bar-window-first-item-font,
|
||||||
|
// set the corresponding font. This is used to set bold on the first item of the menubar (à la Cocoa)
|
||||||
|
if ((index == 0) && ([item tag] == -1))
|
||||||
|
{
|
||||||
|
var firstItemFont = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-first-item-font" forClass:_CPMenuView];
|
||||||
|
|
||||||
|
if (firstItemFont)
|
||||||
|
[item setFont:firstItemFont];
|
||||||
|
}
|
||||||
|
|
||||||
[menuItemView synchronizeWithMenuItem];
|
[menuItemView synchronizeWithMenuItem];
|
||||||
|
|
||||||
[contentView addSubview:menuItemView];
|
[contentView addSubview:menuItemView];
|
||||||
@@ -350,7 +365,7 @@
|
|||||||
|
|
||||||
- (CPFont)font
|
- (CPFont)font
|
||||||
{
|
{
|
||||||
[CPFont systemFontOfSize:[CPFont systemFontSize]];
|
return [CPFont systemFontOfSize:[CPFont systemFontSize]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tile
|
- (void)tile
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
@class CPWindow
|
@class CPWindow
|
||||||
@class _CPMenuWindow
|
@class _CPMenuWindow
|
||||||
|
@class _CPMenuView
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
@@ -223,7 +225,7 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
_lastGlobalLocation = globalLocation;
|
_lastGlobalLocation = globalLocation;
|
||||||
|
|
||||||
// If the item isn't enabled its as if we clicked on nothing.
|
// If the item isn't enabled its as if we clicked on nothing.
|
||||||
if (![activeItem isEnabled] || [activeItem _isMenuBarButton])
|
if ([activeItem _isMenuBarButton])
|
||||||
{
|
{
|
||||||
activeItemIndex = CPNotFound;
|
activeItemIndex = CPNotFound;
|
||||||
activeItem = nil;
|
activeItem = nil;
|
||||||
@@ -352,7 +354,23 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
if ([activeMenuContainer isMenuBar])
|
if ([activeMenuContainer isMenuBar])
|
||||||
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||||
else
|
else
|
||||||
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
{
|
||||||
|
// New theme attributes to have more precise submenus positioning
|
||||||
|
|
||||||
|
var defaultTheme = [CPTheme defaultTheme],
|
||||||
|
themeDeltaX = [defaultTheme valueForAttributeWithName:@"menu-window-submenu-delta-x" forClass:_CPMenuView],
|
||||||
|
themeDeltaY = [defaultTheme valueForAttributeWithName:@"menu-window-submenu-delta-y" forClass:_CPMenuView],
|
||||||
|
themeFirstDeltaY = [defaultTheme valueForAttributeWithName:@"menu-window-submenu-first-level-delta-y" forClass:_CPMenuView],
|
||||||
|
activeMenuIndex = [_menuContainerStack indexOfObject:activeMenuContainer],
|
||||||
|
|
||||||
|
deltaX = themeDeltaX ? themeDeltaX : 0,
|
||||||
|
deltaY = themeDeltaY ? themeDeltaY : 0;
|
||||||
|
|
||||||
|
if (themeFirstDeltaY && (activeMenuIndex == 1) && [_menuContainerStack[0] isMenuBar])
|
||||||
|
deltaY += themeFirstDeltaY;
|
||||||
|
|
||||||
|
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect)+deltaX, CGRectGetMinY(activeItemRect)+deltaY);
|
||||||
|
}
|
||||||
|
|
||||||
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
||||||
|
|
||||||
@@ -553,7 +571,7 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
var iter = [selectorNames objectEnumerator],
|
var iter = [selectorNames objectEnumerator],
|
||||||
obj;
|
obj;
|
||||||
|
|
||||||
while ((obj = [iter nextObject]) !== nil)
|
while ((obj = [iter nextObject]) != nil)
|
||||||
{
|
{
|
||||||
var aSelector = CPSelectorFromString(obj);
|
var aSelector = CPSelectorFromString(obj);
|
||||||
|
|
||||||
@@ -580,6 +598,8 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu];
|
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu];
|
||||||
_lastGlobalLocation = nil;
|
_lastGlobalLocation = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu
|
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu
|
||||||
@@ -587,7 +607,7 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
var iter = [[menu itemArray] objectEnumerator],
|
var iter = [[menu itemArray] objectEnumerator],
|
||||||
obj;
|
obj;
|
||||||
|
|
||||||
while ((obj = [iter nextObject]) !== nil)
|
while ((obj = [iter nextObject]) != nil)
|
||||||
{
|
{
|
||||||
if ([obj isHidden] || ![obj isEnabled])
|
if ([obj isHidden] || ![obj isEnabled])
|
||||||
continue;
|
continue;
|
||||||
@@ -725,39 +745,32 @@ var STICKY_TIME_INTERVAL = 0.4,
|
|||||||
|
|
||||||
- (void)moveDown:(CPMenu)menu
|
- (void)moveDown:(CPMenu)menu
|
||||||
{
|
{
|
||||||
var index = menu._highlightedIndex + 1;
|
var index = menu._highlightedIndex + 1,
|
||||||
|
item;
|
||||||
|
|
||||||
|
// Search for the next enabled item
|
||||||
|
while ((index < [menu numberOfItems]) && (item = [menu itemAtIndex:index]) && ([item isSeparatorItem] || [item isHidden] || ![item isEnabled]))
|
||||||
|
index++;
|
||||||
|
|
||||||
if (index < [menu numberOfItems])
|
if (index < [menu numberOfItems])
|
||||||
{
|
|
||||||
[menu _highlightItemAtIndex:index];
|
[menu _highlightItemAtIndex:index];
|
||||||
|
|
||||||
var item = [menu highlightedItem];
|
|
||||||
|
|
||||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
|
||||||
[self moveDown:menu];
|
|
||||||
}
|
|
||||||
else if (menu == [CPApp mainMenu])
|
else if (menu == [CPApp mainMenu])
|
||||||
[menu _highlightItemAtIndex:0];
|
[menu _highlightItemAtIndex:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)moveUp:(CPMenu)menu
|
- (void)moveUp:(CPMenu)menu
|
||||||
{
|
{
|
||||||
var index = menu._highlightedIndex - 1;
|
var index = menu._highlightedIndex - 1,
|
||||||
|
item;
|
||||||
|
|
||||||
if (index < 0)
|
// Search for the previous enabled item
|
||||||
{
|
while ((index >= 0) && (item = [menu itemAtIndex:index]) && ([item isSeparatorItem] || [item isHidden] || ![item isEnabled]))
|
||||||
if (index != CPNotFound || menu == [CPApp mainMenu])
|
index--;
|
||||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
|
||||||
|
|
||||||
return;
|
if (index >= 0)
|
||||||
}
|
[menu _highlightItemAtIndex:index];
|
||||||
|
else if (menu == [CPApp mainMenu])
|
||||||
[menu _highlightItemAtIndex:index];
|
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||||
|
|
||||||
var item = [menu highlightedItem];
|
|
||||||
|
|
||||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
|
||||||
[self moveUp:menu];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertNewline:(CPMenu)menu
|
- (void)insertNewline:(CPMenu)menu
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
@import "_CPMenuManager.j"
|
@import "_CPMenuManager.j"
|
||||||
|
|
||||||
|
@class _CPMenuView
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
var _CPMenuWindowPool = [],
|
var _CPMenuWindowPool = [],
|
||||||
_CPMenuWindowPoolCapacity = 5,
|
_CPMenuWindowPoolCapacity = 5,
|
||||||
|
|
||||||
@@ -410,13 +413,28 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
|||||||
{
|
{
|
||||||
// Don't return indexes of items that aren't visible.
|
// Don't return indexes of items that aren't visible.
|
||||||
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
|
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
|
||||||
return NO;
|
return CPNotFound;
|
||||||
|
|
||||||
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
|
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPMenuWindow (CSSTheming)
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[[self contentView] _setThemeIncludingDescendants:aTheme];
|
||||||
|
[_menuView _setThemeIncludingDescendants:aTheme];
|
||||||
|
[_menuView tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
@@ -447,6 +465,7 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
|||||||
@"menu-bar-window-background-color": [CPNull null],
|
@"menu-bar-window-background-color": [CPNull null],
|
||||||
@"menu-bar-window-background-selected-color": [CPNull null],
|
@"menu-bar-window-background-selected-color": [CPNull null],
|
||||||
@"menu-bar-window-font": [CPNull null],
|
@"menu-bar-window-font": [CPNull null],
|
||||||
|
@"menu-bar-window-first-item-font": [CPNull null],
|
||||||
@"menu-bar-window-height": 30.0,
|
@"menu-bar-window-height": 30.0,
|
||||||
@"menu-bar-window-margin": 10.0,
|
@"menu-bar-window-margin": 10.0,
|
||||||
@"menu-bar-window-left-margin": 10.0,
|
@"menu-bar-window-left-margin": 10.0,
|
||||||
@@ -464,6 +483,9 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
|||||||
@"menu-general-icon-new": [CPNull null],
|
@"menu-general-icon-new": [CPNull null],
|
||||||
@"menu-general-icon-save": [CPNull null],
|
@"menu-general-icon-save": [CPNull null],
|
||||||
@"menu-general-icon-open": [CPNull null],
|
@"menu-general-icon-open": [CPNull null],
|
||||||
|
@"menu-window-submenu-delta-x": 0.0,
|
||||||
|
@"menu-window-submenu-delta-y": 0.0,
|
||||||
|
@"menu-window-submenu-first-level-delta-y": 0.0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,6 +572,7 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
|||||||
|
|
||||||
[view setFrameOrigin:CGPointMake(0.0, y)];
|
[view setFrameOrigin:CGPointMake(0.0, y)];
|
||||||
|
|
||||||
|
[view _setThemeIncludingDescendants:[CPTheme defaultTheme]];
|
||||||
[self addSubview:view];
|
[self addSubview:view];
|
||||||
|
|
||||||
var size = [view minSize],
|
var size = [view minSize],
|
||||||
@@ -580,3 +603,18 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPMenuView (CSSTheming)
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[self setTheme:aTheme];
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(_setThemeIncludingDescendants:) withObject:aTheme];
|
||||||
|
|
||||||
|
for (var i = 0, items = [[self menu] itemArray], count = [items count]; i < count; i++)
|
||||||
|
[[items[i] _menuItemView] _setThemeIncludingDescendants:aTheme];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ CPOffState
|
|||||||
if (_submenu)
|
if (_submenu)
|
||||||
{
|
{
|
||||||
[_submenu setSupermenu:_menu];
|
[_submenu setSupermenu:_menu];
|
||||||
[_submenu setTitle:[self title]]
|
[_submenu setTitle:[self title]];
|
||||||
|
|
||||||
[self setTarget:_menu];
|
[self setTarget:_menu];
|
||||||
[self setAction:@selector(submenuAction:)];
|
[self setAction:@selector(submenuAction:)];
|
||||||
@@ -843,7 +843,7 @@ CPControlKeyMask
|
|||||||
[item setTarget:_target];
|
[item setTarget:_target];
|
||||||
[item setAction:_action];
|
[item setAction:_action];
|
||||||
[item setEnabled:_isEnabled];
|
[item setEnabled:_isEnabled];
|
||||||
[item setHidden:_isHidden]
|
[item setHidden:_isHidden];
|
||||||
[item setTag:_tag];
|
[item setTag:_tag];
|
||||||
[item setState:_state];
|
[item setState:_state];
|
||||||
[item setImage:_image];
|
[item setImage:_image];
|
||||||
@@ -897,6 +897,20 @@ CPControlKeyMask
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPMenuItem (CSSTheming)
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[_view _setThemeIncludingDescendants:aTheme];
|
||||||
|
[_menuItemView _setThemeIncludingDescendants:aTheme];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||||
|
|
||||||
CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||||
@@ -911,6 +925,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
|||||||
|
|
||||||
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
||||||
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
||||||
|
CPMenuItemOnStateImageKey = @"CPMenuItemOnStateImageKey",
|
||||||
|
CPMenuItemOffStateImageKey = @"CPMenuItemOffStateImageKey",
|
||||||
|
CPMenuItemMixedStateImageKey = @"CPMenuItemMixedStateImageKey",
|
||||||
|
|
||||||
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
||||||
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
||||||
@@ -955,9 +972,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
|||||||
|
|
||||||
_image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
|
_image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
|
||||||
_alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
|
_alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
|
||||||
// CPImage _onStateImage;
|
_onStateImage = [aCoder decodeObjectForKey:CPMenuItemOnStateImageKey];
|
||||||
// CPImage _offStateImage;
|
_offStateImage = [aCoder decodeObjectForKey:CPMenuItemOffStateImageKey];
|
||||||
// CPImage _mixedStateImage;
|
_mixedStateImage = [aCoder decodeObjectForKey:CPMenuItemMixedStateImageKey];
|
||||||
|
|
||||||
// This order matters because setSubmenu: needs _menu to be around.
|
// This order matters because setSubmenu: needs _menu to be around.
|
||||||
_menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
|
_menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
|
||||||
@@ -1003,6 +1020,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
|||||||
|
|
||||||
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
|
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
|
||||||
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
|
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
|
||||||
|
ENCODE_IFNOT(CPMenuItemOnStateImageKey, _onStateImage, nil);
|
||||||
|
ENCODE_IFNOT(CPMenuItemOffStateImageKey, _offStateImage, nil);
|
||||||
|
ENCODE_IFNOT(CPMenuItemMixedStateImageKey, _mixedStateImage, nil);
|
||||||
|
|
||||||
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
||||||
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
@class _CPMenuBarWindow
|
@class _CPMenuBarWindow
|
||||||
@class _CPMenuView
|
@class _CPMenuView
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
@implementation _CPMenuItemMenuBarView : CPView
|
@implementation _CPMenuItemMenuBarView : CPView
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
|
|
||||||
+ (id)view
|
+ (id)view
|
||||||
{
|
{
|
||||||
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
var themedHeight = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-item-separator-view-height" forClass:_CPMenuItemStandardView];
|
||||||
|
|
||||||
|
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, (themedHeight ? themedHeight : 10.0))];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -47,12 +49,25 @@
|
|||||||
- (void)drawRect:(CGRect)aRect
|
- (void)drawRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
bounds = [self bounds];
|
bounds = [self bounds],
|
||||||
|
height = CGRectGetMaxY(bounds),
|
||||||
|
themedHeight = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-item-separator-height" forClass:_CPMenuItemStandardView],
|
||||||
|
lineHeight = themedHeight ? themedHeight : 1.0;
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
|
|
||||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
CGContextSetLineWidth(context, lineHeight);
|
||||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
|
||||||
|
if (!!((height - lineHeight) % 2))
|
||||||
|
{
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)));
|
||||||
|
}
|
||||||
|
|
||||||
CGContextSetStrokeColor(context, [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-item-separator-color" forClass:_CPMenuItemStandardView]);
|
CGContextSetStrokeColor(context, [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-item-separator-color" forClass:_CPMenuItemStandardView]);
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "_CPImageAndTextView.j"
|
@import "_CPImageAndTextView.j"
|
||||||
|
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
|
|
||||||
@implementation _CPMenuItemStandardView : CPView
|
@implementation _CPMenuItemStandardView : CPView
|
||||||
{
|
{
|
||||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||||
@@ -38,6 +41,8 @@
|
|||||||
_CPImageAndTextView _imageAndTextView;
|
_CPImageAndTextView _imageAndTextView;
|
||||||
_CPImageAndTextView _keyEquivalentView;
|
_CPImageAndTextView _keyEquivalentView;
|
||||||
CPView _submenuIndicatorView;
|
CPView _submenuIndicatorView;
|
||||||
|
|
||||||
|
BOOL _hasSubmenuIndicatorImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
+ (CPString)defaultThemeClass
|
||||||
@@ -52,6 +57,7 @@
|
|||||||
@"menu-item-selection-color": [CPNull null],
|
@"menu-item-selection-color": [CPNull null],
|
||||||
@"menu-item-text-shadow-color": [CPNull null],
|
@"menu-item-text-shadow-color": [CPNull null],
|
||||||
@"menu-item-text-color": [CPNull null],
|
@"menu-item-text-color": [CPNull null],
|
||||||
|
@"menu-item-disabled-text-color": [CPColor lightGrayColor],
|
||||||
@"menu-item-default-off-state-image": [CPNull null],
|
@"menu-item-default-off-state-image": [CPNull null],
|
||||||
@"menu-item-default-off-state-highlighted-image": [CPNull null],
|
@"menu-item-default-off-state-highlighted-image": [CPNull null],
|
||||||
@"menu-item-default-on-state-image": [CPNull null],
|
@"menu-item-default-on-state-image": [CPNull null],
|
||||||
@@ -59,12 +65,17 @@
|
|||||||
@"menu-item-default-mixed-state-image": [CPNull null],
|
@"menu-item-default-mixed-state-image": [CPNull null],
|
||||||
@"menu-item-default-mixed-state-highlighted-image": [CPNull null],
|
@"menu-item-default-mixed-state-highlighted-image": [CPNull null],
|
||||||
@"menu-item-separator-color": [CPNull null],
|
@"menu-item-separator-color": [CPNull null],
|
||||||
|
@"menu-item-separator-height": 1.0,
|
||||||
|
@"menu-item-separator-view-height": 10.0,
|
||||||
@"left-margin": 3.0,
|
@"left-margin": 3.0,
|
||||||
@"right-margin": 17.0,
|
@"right-margin": 17.0,
|
||||||
@"state-column-width": 14.0,
|
@"state-column-width": 14.0,
|
||||||
@"indentation-width": 17.0,
|
@"indentation-width": 17.0,
|
||||||
@"vertical-margin": 4.0,
|
@"vertical-margin": 4.0,
|
||||||
|
@"vertical-offset": 0.0,
|
||||||
@"right-columns-margin": 30.0,
|
@"right-columns-margin": 30.0,
|
||||||
|
@"submenu-indicator-image": [CPNull null],
|
||||||
|
@"submenu-indicator-highlighted-image": [CPNull null]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +98,7 @@
|
|||||||
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
[_stateView setImageScaling:CPImageScaleNone];
|
[_stateView setImageScaling:CPImageScaleNone];
|
||||||
|
[_stateView setImageAlignment:CPImageAlignCenter];
|
||||||
|
|
||||||
[self addSubview:_stateView];
|
[self addSubview:_stateView];
|
||||||
|
|
||||||
@@ -105,9 +117,24 @@
|
|||||||
|
|
||||||
[self addSubview:_keyEquivalentView];
|
[self addSubview:_keyEquivalentView];
|
||||||
|
|
||||||
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
|
// Do we have a submenu indicator image specified in the theme ?
|
||||||
|
_hasSubmenuIndicatorImage = !![self valueForThemeAttribute:@"submenu-indicator-image"];
|
||||||
|
|
||||||
|
if (_hasSubmenuIndicatorImage)
|
||||||
|
{
|
||||||
|
// Yes, then use an imageView
|
||||||
|
_submenuIndicatorView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setImageAlignment:CPImageAlignCenter];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No, then use self drawing _CPMenuItemSubmenuIndicatorView
|
||||||
|
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
|
||||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
|
||||||
[self addSubview:_submenuIndicatorView];
|
[self addSubview:_submenuIndicatorView];
|
||||||
@@ -121,7 +148,7 @@
|
|||||||
- (CPColor)textColor
|
- (CPColor)textColor
|
||||||
{
|
{
|
||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return [CPColor lightGrayColor];
|
return [self valueForThemeAttribute:@"menu-item-disabled-text-color"];
|
||||||
|
|
||||||
if (_highlighted)
|
if (_highlighted)
|
||||||
return [CPColor whiteColor];
|
return [CPColor whiteColor];
|
||||||
@@ -145,11 +172,24 @@
|
|||||||
_font = aFont;
|
_font = aFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPFont)font
|
||||||
|
{
|
||||||
|
// Menu item font is forced local font or _menuItem font or system font
|
||||||
|
return _font || [_menuItem font] || [CPFont systemFontOfSize:CPFontCurrentSystemSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: update is called 2 times at each display. Find why and fix.
|
||||||
- (void)update
|
- (void)update
|
||||||
{
|
{
|
||||||
var x = [self valueForThemeAttribute:@"left-margin"] + [_menuItem indentationLevel] * [self valueForThemeAttribute:@"indentation-width"],
|
var x = [self valueForThemeAttribute:@"left-margin"] + [_menuItem indentationLevel] * [self valueForThemeAttribute:@"indentation-width"],
|
||||||
height = 0.0,
|
height = 0.0,
|
||||||
hasStateColumn = [[_menuItem menu] showsStateColumn];
|
hasStateColumn = [[_menuItem menu] showsStateColumn],
|
||||||
|
myFont = [self font],
|
||||||
|
|
||||||
|
// When possible, use specific vertical margin/offset value based on font size (which could have been set by control size)
|
||||||
|
correspondingControlSize = [myFont controlSizeCorrespondingToFontSize],
|
||||||
|
verticalMargin = [self valueForThemeAttribute:@"vertical-margin" inState:CPControlSizeThemeStates[correspondingControlSize]],
|
||||||
|
verticalOffset = [self valueForThemeAttribute:@"vertical-offset" inState:CPControlSizeThemeStates[correspondingControlSize]];
|
||||||
|
|
||||||
if (hasStateColumn)
|
if (hasStateColumn)
|
||||||
{
|
{
|
||||||
@@ -159,27 +199,32 @@
|
|||||||
switch ([_menuItem state])
|
switch ([_menuItem state])
|
||||||
{
|
{
|
||||||
case CPOnState:
|
case CPOnState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-image"]];
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPOffState:
|
case CPOffState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-image"]];
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPMixedState:
|
case CPMixedState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-image"]];
|
[_stateView setImage:[_menuItem mixedStateImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stateViewFrameOrigin = [_stateView frameOrigin];
|
||||||
|
|
||||||
|
stateViewFrameOrigin.x = x;
|
||||||
|
[_stateView setFrameOrigin:stateViewFrameOrigin];
|
||||||
|
|
||||||
x += [self valueForThemeAttribute:@"state-column-width"];
|
x += [self valueForThemeAttribute:@"state-column-width"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[_stateView setHidden:YES];
|
[_stateView setHidden:YES];
|
||||||
|
|
||||||
[_imageAndTextView setFont:[_menuItem font] || _font];
|
[_imageAndTextView setFont:myFont];
|
||||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
[_imageAndTextView setImage:[_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_imageAndTextView setText:[_menuItem title]];
|
[_imageAndTextView setText:[_menuItem title]];
|
||||||
@@ -192,7 +237,7 @@
|
|||||||
|
|
||||||
imageAndTextViewFrame.origin.x = x;
|
imageAndTextViewFrame.origin.x = x;
|
||||||
x += CGRectGetWidth(imageAndTextViewFrame);
|
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame)); // FIXME: here, height = 0 -> MAX useless
|
||||||
|
|
||||||
var hasKeyEquivalent = !![_menuItem keyEquivalent],
|
var hasKeyEquivalent = !![_menuItem keyEquivalent],
|
||||||
hasSubmenu = [_menuItem hasSubmenu];
|
hasSubmenu = [_menuItem hasSubmenu];
|
||||||
@@ -202,14 +247,14 @@
|
|||||||
|
|
||||||
if (hasKeyEquivalent)
|
if (hasKeyEquivalent)
|
||||||
{
|
{
|
||||||
[_keyEquivalentView setFont:[_menuItem font] || _font];
|
[_keyEquivalentView setFont:myFont];
|
||||||
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
[_keyEquivalentView setImage:[_menuItem image]];
|
[_keyEquivalentView setImage:[_menuItem image]];
|
||||||
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
|
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
|
||||||
[_keyEquivalentView setTextColor:[self textColor]];
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||||
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
|
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||||
[_keyEquivalentView setFrameOrigin:CGPointMake(x, [self valueForThemeAttribute:@"vertical-margin"])];
|
[_keyEquivalentView setFrameOrigin:CGPointMake(x, verticalMargin)];
|
||||||
[_keyEquivalentView sizeToFit];
|
[_keyEquivalentView sizeToFit];
|
||||||
|
|
||||||
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
||||||
@@ -226,6 +271,14 @@
|
|||||||
|
|
||||||
if (hasSubmenu)
|
if (hasSubmenu)
|
||||||
{
|
{
|
||||||
|
if (_hasSubmenuIndicatorImage)
|
||||||
|
{
|
||||||
|
var submenuIndicatorImage = [self valueForThemeAttribute:@"submenu-indicator-image" inState:CPControlSizeThemeStates[correspondingControlSize]];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setImage:submenuIndicatorImage];
|
||||||
|
[_submenuIndicatorView setFrameSize:[submenuIndicatorImage size]];
|
||||||
|
}
|
||||||
|
|
||||||
[_submenuIndicatorView setHidden:NO];
|
[_submenuIndicatorView setHidden:NO];
|
||||||
|
|
||||||
var submenuViewFrame = [_submenuIndicatorView frame];
|
var submenuViewFrame = [_submenuIndicatorView frame];
|
||||||
@@ -238,9 +291,9 @@
|
|||||||
else
|
else
|
||||||
[_submenuIndicatorView setHidden:YES];
|
[_submenuIndicatorView setHidden:YES];
|
||||||
|
|
||||||
height += 2.0 * [self valueForThemeAttribute:@"vertical-margin"];
|
height += 2.0 * verticalMargin;
|
||||||
|
|
||||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0) + verticalOffset;
|
||||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||||
|
|
||||||
if (hasStateColumn)
|
if (hasStateColumn)
|
||||||
@@ -248,7 +301,7 @@
|
|||||||
|
|
||||||
if (hasKeyEquivalent)
|
if (hasKeyEquivalent)
|
||||||
{
|
{
|
||||||
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
|
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0) + verticalOffset;
|
||||||
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
|
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +326,8 @@
|
|||||||
|
|
||||||
_highlighted = shouldHighlight;
|
_highlighted = shouldHighlight;
|
||||||
|
|
||||||
|
var correspondingControlSize = [[self font] controlSizeCorrespondingToFontSize];
|
||||||
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
[_keyEquivalentView setTextColor:[self textColor]];
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
@@ -282,13 +337,21 @@
|
|||||||
{
|
{
|
||||||
[self setBackgroundColor:[self valueForThemeAttribute:@"menu-item-selection-color"]];
|
[self setBackgroundColor:[self valueForThemeAttribute:@"menu-item-selection-color"]];
|
||||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
[_submenuIndicatorView setColor:[self textColor]];
|
|
||||||
|
if (_hasSubmenuIndicatorImage)
|
||||||
|
[_submenuIndicatorView setImage:[self valueForThemeAttribute:@"submenu-indicator-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
else
|
||||||
|
[_submenuIndicatorView setColor:[self textColor]];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[self setBackgroundColor:nil];
|
[self setBackgroundColor:nil];
|
||||||
[_imageAndTextView setImage:[_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
|
||||||
|
if (_hasSubmenuIndicatorImage)
|
||||||
|
[_submenuIndicatorView setImage:[self valueForThemeAttribute:@"submenu-indicator-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
else
|
||||||
|
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([[_menuItem menu] showsStateColumn])
|
if ([[_menuItem menu] showsStateColumn])
|
||||||
@@ -298,15 +361,15 @@
|
|||||||
switch ([_menuItem state])
|
switch ([_menuItem state])
|
||||||
{
|
{
|
||||||
case CPOnState:
|
case CPOnState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-highlighted-image"]];
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPOffState:
|
case CPOffState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-highlighted-image"]];
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPMixedState:
|
case CPMixedState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-highlighted-image"]];
|
[_stateView setImage:[_menuItem mixedImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -318,15 +381,15 @@
|
|||||||
switch ([_menuItem state])
|
switch ([_menuItem state])
|
||||||
{
|
{
|
||||||
case CPOnState:
|
case CPOnState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-image"]];
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPOffState:
|
case CPOffState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-image"]];
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPMixedState:
|
case CPMixedState:
|
||||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-image"]];
|
[_stateView setImage:[_menuItem mixedImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -343,6 +406,22 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPMenuItemStandardView (CSSTheming)
|
||||||
|
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[self setTheme:aTheme];
|
||||||
|
[[self subviews] makeObjectsPerformSelector:@selector(_setThemeIncludingDescendants:) withObject:aTheme];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
||||||
{
|
{
|
||||||
CPColor _color;
|
CPColor _color;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
@import "_CPMenuItemStandardView.j"
|
@import "_CPMenuItemStandardView.j"
|
||||||
@import "_CPMenuItemMenuBarView.j"
|
@import "_CPMenuItemMenuBarView.j"
|
||||||
|
|
||||||
|
@class CPMenuItem
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -251,6 +252,31 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPMenuItemView (CSSTheming)
|
||||||
|
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[self setTheme:aTheme];
|
||||||
|
[_view _setThemeIncludingDescendants:aTheme];
|
||||||
|
|
||||||
|
// Items must also perform this (without this, only the selected item does)
|
||||||
|
|
||||||
|
[_imageAndTextView _setThemeIncludingDescendants:aTheme];
|
||||||
|
[_submenuView _setThemeIncludingDescendants:aTheme];
|
||||||
|
[[_menuItem view] _setThemeIncludingDescendants:aTheme];
|
||||||
|
|
||||||
|
if ([_view respondsToSelector:@selector(update)])
|
||||||
|
[_view update];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
@implementation _CPMenuItemArrowView : CPView
|
@implementation _CPMenuItemArrowView : CPView
|
||||||
{
|
{
|
||||||
CPColor _color;
|
CPColor _color;
|
||||||
|
|||||||
+147
-18
@@ -27,6 +27,9 @@
|
|||||||
@import "CPController.j"
|
@import "CPController.j"
|
||||||
@import "CPKeyValueBinding.j"
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
|
@class _CPManagedProxy
|
||||||
|
@class CPPredicate;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@class
|
@class
|
||||||
|
|
||||||
@@ -47,6 +50,9 @@
|
|||||||
|
|
||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
BOOL _automaticallyPreparesContent;
|
BOOL _automaticallyPreparesContent;
|
||||||
|
BOOL _usesLazyFetching @accessors(getter=usesLazyFetching, setter=setUsesLazyFetching:);
|
||||||
|
BOOL _isUsingManagedProxy;
|
||||||
|
_CPManagedProxy _managedProxy;
|
||||||
|
|
||||||
CPCountedSet _observedKeys;
|
CPCountedSet _observedKeys;
|
||||||
}
|
}
|
||||||
@@ -179,6 +185,52 @@
|
|||||||
return _automaticallyPreparesContent;
|
return _automaticallyPreparesContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the entity name the controller handles.
|
||||||
|
|
||||||
|
@param CPString newEntityName - The new entity name.
|
||||||
|
*/
|
||||||
|
- (void)setEntityName:(CPString)newEntityName
|
||||||
|
{
|
||||||
|
if (!_managedProxy)
|
||||||
|
{
|
||||||
|
_managedProxy = [[_CPManagedProxy alloc] init];
|
||||||
|
_isUsingManagedProxy = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_managedProxy setEntityName:newEntityName];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the entity name.
|
||||||
|
|
||||||
|
@return CPString - The name of the entity.
|
||||||
|
*/
|
||||||
|
- (CPString)entityName
|
||||||
|
{
|
||||||
|
return [_managedProxy entityName];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the predicate used to fetch content.
|
||||||
|
|
||||||
|
@param CPPredicate newPredicate - The fetch predicate.
|
||||||
|
*/
|
||||||
|
- (void)setFetchPredicate:(CPPredicate)newPredicate
|
||||||
|
{
|
||||||
|
[_managedProxy setFetchPredicate:newPredicate];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the fetch predicate.
|
||||||
|
|
||||||
|
@return CPPredicate - The predicate used to fetch content.
|
||||||
|
*/
|
||||||
|
- (CPPredicate)fetchPredicate
|
||||||
|
{
|
||||||
|
return [_managedProxy fetchPredicate];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Overridden by a subclass that require control over the creation of new objects.
|
Overridden by a subclass that require control over the creation of new objects.
|
||||||
*/
|
*/
|
||||||
@@ -189,6 +241,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the object class when creating new objects.
|
Sets the object class when creating new objects.
|
||||||
|
|
||||||
@param Class - the class of new objects that will be created.
|
@param Class - the class of new objects that will be created.
|
||||||
*/
|
*/
|
||||||
- (void)setObjectClass:(Class)aClass
|
- (void)setObjectClass:(Class)aClass
|
||||||
@@ -331,13 +384,35 @@
|
|||||||
*/
|
*/
|
||||||
- (void)_selectionDidChange
|
- (void)_selectionDidChange
|
||||||
{
|
{
|
||||||
if (_selection === undefined || _selection === nil)
|
if (_selection == nil)
|
||||||
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||||
|
|
||||||
[_selection controllerDidChange];
|
[_selection controllerDidChange];
|
||||||
[self didChangeValueForKey:@"selection"];
|
[self didChangeValueForKey:@"selection"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
These two private methods map CPTextField notifications to the CPEditorRegistration protocol
|
||||||
|
This should be generalized in the future:
|
||||||
|
|
||||||
|
The CPEditorRegistrationProtocol can be implemented in all controls that support editing, not just CPTextField.
|
||||||
|
In CPArrayController there are other cases than selection change when we need to review all editor pending changes. They should be covered, including the selection change, by the wider concept described by the methods commitEditing: (forces to end editing) and discardEditing: (pending changes are lost).
|
||||||
|
*/
|
||||||
|
- (void)_objectDidBeginEditing:(CPNotification)notification
|
||||||
|
{
|
||||||
|
[self objectDidBeginEditing:[notification object]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void) _objectDidEndEditing:(CPNotification)notification
|
||||||
|
{
|
||||||
|
[self objectDidEndEditing:[notification object]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@return id - Returns the keys which are being observed.
|
@return id - Returns the keys which are being observed.
|
||||||
*/
|
*/
|
||||||
@@ -363,7 +438,10 @@
|
|||||||
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
|
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
|
||||||
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
|
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
|
||||||
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
|
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
|
||||||
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
|
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey",
|
||||||
|
CPObjectControllerUsesLazyFetchingKey = @"CPObjectControllerUsesLazyFetchingKey",
|
||||||
|
CPObjectControllerIsUsingManagedProxyKey = @"CPObjectControllerIsUsingManagedProxyKey",
|
||||||
|
CPObjectControllerManagedProxyKey = @"CPObjectControllerManagedProxyKey";
|
||||||
|
|
||||||
@implementation CPObjectController (CPCoding)
|
@implementation CPObjectController (CPCoding)
|
||||||
|
|
||||||
@@ -374,12 +452,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
|
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
|
||||||
objectClass = CPClassFromString(objectClassName);
|
objectClass = CPClassFromString(objectClassName),
|
||||||
|
content = [aCoder decodeObjectForKey:CPObjectControllerContentKey];
|
||||||
|
|
||||||
[self setObjectClass:objectClass || [CPMutableDictionary class]];
|
[self setObjectClass:objectClass || [CPMutableDictionary class]];
|
||||||
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
|
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
|
||||||
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
|
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
|
||||||
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
|
[self setUsesLazyFetching:[aCoder decodeBoolForKey:CPObjectControllerUsesLazyFetchingKey]];
|
||||||
|
_isUsingManagedProxy = [aCoder decodeBoolForKey:CPObjectControllerIsUsingManagedProxyKey];
|
||||||
|
_managedProxy = [aCoder decodeObjectForKey:CPObjectControllerManagedProxyKey];
|
||||||
|
|
||||||
|
if (content != nil)
|
||||||
|
[self setContent:content];
|
||||||
|
|
||||||
_observedKeys = [[CPCountedSet alloc] init];
|
_observedKeys = [[CPCountedSet alloc] init];
|
||||||
}
|
}
|
||||||
@@ -398,6 +482,11 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
|
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
|
||||||
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
|
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
|
||||||
|
[aCoder encodeBool:[self usesLazyFetching] forKey:CPObjectControllerUsesLazyFetchingKey];
|
||||||
|
[aCoder encodeBool:_isUsingManagedProxy forKey:CPObjectControllerIsUsingManagedProxyKey];
|
||||||
|
|
||||||
|
if (_managedProxy)
|
||||||
|
[aCoder encodeObject:_managedProxy forKey:CPObjectControllerManagedProxyKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
@@ -459,13 +548,13 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (BOOL)isEqual:(id)anObject
|
- (BOOL)isEqual:(id)anObject
|
||||||
{
|
{
|
||||||
if ([anObject class] === [self class])
|
if (self === anObject)
|
||||||
{
|
return YES;
|
||||||
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
if (!anObject || [anObject class] !== [self class] || anObject._observer !== _observer || anObject._keyPath !== _keyPath || anObject._object !== _object)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
|
||||||
@@ -703,7 +792,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value === nil || value.isa && [value isEqual:[CPNull null]])
|
if (value == nil || value.isa && [value isEqual:[CPNull null]])
|
||||||
value = CPNullMarker;
|
value = CPNullMarker;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -749,7 +838,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
|
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
|
||||||
{
|
{
|
||||||
[self setValue:theKeyPath forKeyPath:theKeyPath];
|
[self setValue:theValue forKeyPath:theKeyPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned)count
|
- (unsigned)count
|
||||||
@@ -808,15 +897,55 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
|
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
|
||||||
{
|
{
|
||||||
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
|
[_observationProxies enumerateObjectsUsingBlock:function(aProxy, idx, stop)
|
||||||
index = [_observationProxies indexOfObject:proxy];
|
{
|
||||||
|
if (aProxy._object === self && aProxy._keyPath == aKeyPath && aProxy._observer === anObject)
|
||||||
|
{
|
||||||
|
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
|
||||||
|
|
||||||
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
|
[observedObjects removeObserver:aProxy forKeyPath:aKeyPath];
|
||||||
[observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
|
[_observationProxies removeObjectAtIndex:idx];
|
||||||
|
|
||||||
[_observationProxies removeObjectAtIndex:index];
|
_observedObjectsByKeyPath[aKeyPath] = nil;
|
||||||
|
|
||||||
_observedObjectsByKeyPath[aKeyPath] = nil;
|
stop(YES);
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPManagedProxy : CPObject
|
||||||
|
{
|
||||||
|
CPString _entityName @accessors(getter=entityName, setter=setEntityName:);
|
||||||
|
CPPredicate _fetchPredicate @accessors(getter=fetchPredicate, setter=setFetchPredicate:);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPManagedProxyEntityNameKey = @"CPManagedProxyEntityNameKey",
|
||||||
|
CPManagedProxyFetchPredicateKey = @"CPManagedProxyFetchPredicateKey";
|
||||||
|
|
||||||
|
@implementation _CPManagedProxy (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
[self setEntityName:[aCoder decodeObjectForKey:CPManagedProxyEntityNameKey]];
|
||||||
|
[self setFetchPredicate:[aCoder decodeObjectForKey:CPManagedProxyFetchPredicateKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:[self entityName] forKey:CPManagedProxyEntityNameKey];
|
||||||
|
[aCoder encodeObject:[self fetchPredicate] forKey:CPManagedProxyFetchPredicateKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+476
-344
File diff suppressed because it is too large
Load Diff
+23
-2
@@ -22,10 +22,13 @@
|
|||||||
|
|
||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
CPOKButton = 1;
|
CPOKButton = 1;
|
||||||
CPCancelButton = 0;
|
CPCancelButton = 0;
|
||||||
|
|
||||||
|
CPDocModalWindowMask = 1 << 6;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPPanel
|
@class CPPanel
|
||||||
@@ -51,8 +54,6 @@ CPCancelButton = 0;
|
|||||||
@global
|
@global
|
||||||
@class CPWindow
|
@class CPWindow
|
||||||
*/
|
*/
|
||||||
CPDocModalWindowMask = 1 << 6;
|
|
||||||
|
|
||||||
@implementation CPPanel : CPWindow
|
@implementation CPPanel : CPWindow
|
||||||
{
|
{
|
||||||
BOOL _becomesKeyOnlyIfNeeded;
|
BOOL _becomesKeyOnlyIfNeeded;
|
||||||
@@ -119,4 +120,24 @@ CPDocModalWindowMask = 1 << 6;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Overrides
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void)cancelOperation:(id)sender
|
||||||
|
{
|
||||||
|
if ([[CPApp currentEvent] _couldBeKeyEquivalent] && [self performKeyEquivalent:[CPApp currentEvent]])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[self firstResponder] tryToPerform:@selector(cancel:) with:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cancel:(id)sender
|
||||||
|
{
|
||||||
|
[self performClose:sender];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+7
-69
@@ -26,6 +26,9 @@
|
|||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPPropertyListSerialization.j>
|
@import <Foundation/CPPropertyListSerialization.j>
|
||||||
|
|
||||||
|
@class CPWebScriptObject
|
||||||
|
|
||||||
|
@typedef DataTransfer
|
||||||
|
|
||||||
CPGeneralPboard = @"CPGeneralPboard";
|
CPGeneralPboard = @"CPGeneralPboard";
|
||||||
CPFontPboard = @"CPFontPboard";
|
CPFontPboard = @"CPFontPboard";
|
||||||
@@ -41,6 +44,9 @@ CPStringPboardType = @"CPStringPboardType";
|
|||||||
CPURLPboardType = @"CPURLPboardType";
|
CPURLPboardType = @"CPURLPboardType";
|
||||||
CPImagesPboardType = @"CPImagesPboardType";
|
CPImagesPboardType = @"CPImagesPboardType";
|
||||||
CPVideosPboardType = @"CPVideosPboardType";
|
CPVideosPboardType = @"CPVideosPboardType";
|
||||||
|
CPRTFPboardType = @"CPRTFPboardType";
|
||||||
|
_CPSmartPboardType = @"_CPSmartPboardType";
|
||||||
|
_CPASPboardType = @"_CPASPboardType";
|
||||||
|
|
||||||
UTF8PboardType = @"public.utf8-plain-text";
|
UTF8PboardType = @"public.utf8-plain-text";
|
||||||
|
|
||||||
@@ -48,8 +54,7 @@ UTF8PboardType = @"public.utf8-plain-text";
|
|||||||
CPImagePboardType = @"CPImagePboardType";
|
CPImagePboardType = @"CPImagePboardType";
|
||||||
|
|
||||||
|
|
||||||
var CPPasteboards = nil,
|
var CPPasteboards = nil;
|
||||||
supportsNativePasteboard = NO;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -65,8 +70,6 @@ var CPPasteboards = nil,
|
|||||||
|
|
||||||
unsigned _changeCount;
|
unsigned _changeCount;
|
||||||
CPString _stateUID;
|
CPString _stateUID;
|
||||||
|
|
||||||
WebScriptObject _nativePasteboard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,9 +83,6 @@ var CPPasteboards = nil,
|
|||||||
[self setVersion:1.0];
|
[self setVersion:1.0];
|
||||||
|
|
||||||
CPPasteboards = @{};
|
CPPasteboards = @{};
|
||||||
|
|
||||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
|
||||||
supportsNativePasteboard = YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -125,12 +125,6 @@ var CPPasteboards = nil,
|
|||||||
_provided = @{};
|
_provided = @{};
|
||||||
|
|
||||||
_changeCount = 0;
|
_changeCount = 0;
|
||||||
|
|
||||||
if (supportsNativePasteboard)
|
|
||||||
{
|
|
||||||
_nativePasteboard = window.cpPasteboardWithName(aName);
|
|
||||||
[self _synchronizePasteboard];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -160,15 +154,6 @@ var CPPasteboards = nil,
|
|||||||
[_owners setObject:anOwner forKey:type];
|
[_owners setObject:anOwner forKey:type];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nativePasteboard)
|
|
||||||
{
|
|
||||||
var nativeTypes = [types copy];
|
|
||||||
if ([types containsObject:CPStringPboardType])
|
|
||||||
nativeTypes.push(UTF8PboardType);
|
|
||||||
|
|
||||||
_nativePasteboard.addTypes_(nativeTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ++_changeCount;
|
return ++_changeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,12 +164,6 @@ var CPPasteboards = nil,
|
|||||||
@return the pasteboard's change count
|
@return the pasteboard's change count
|
||||||
*/
|
*/
|
||||||
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
||||||
{
|
|
||||||
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @ignore */
|
|
||||||
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
|
|
||||||
{
|
{
|
||||||
[_types setArray:types];
|
[_types setArray:types];
|
||||||
|
|
||||||
@@ -198,16 +177,6 @@ var CPPasteboards = nil,
|
|||||||
[_owners setObject:anOwner forKey:_types[count]];
|
[_owners setObject:anOwner forKey:_types[count]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nativePasteboard && shouldUpdate)
|
|
||||||
{
|
|
||||||
var nativeTypes = [types copy];
|
|
||||||
if ([types containsObject:CPStringPboardType])
|
|
||||||
nativeTypes.push(UTF8PboardType);
|
|
||||||
|
|
||||||
_nativePasteboard.declareTypes_(nativeTypes);
|
|
||||||
_changeCount = _nativePasteboard.changeCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ++_changeCount;
|
return ++_changeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +239,6 @@ var CPPasteboards = nil,
|
|||||||
*/
|
*/
|
||||||
- (CPArray)types
|
- (CPArray)types
|
||||||
{
|
{
|
||||||
[self _synchronizePasteboard];
|
|
||||||
return _types;
|
return _types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,36 +277,6 @@ var CPPasteboards = nil,
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_synchronizePasteboard
|
|
||||||
{
|
|
||||||
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
|
|
||||||
{
|
|
||||||
var nativeTypes = [_nativePasteboard.types() copy];
|
|
||||||
if ([nativeTypes containsObject:UTF8PboardType])
|
|
||||||
nativeTypes.push(CPStringPboardType);
|
|
||||||
|
|
||||||
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
|
|
||||||
|
|
||||||
_changeCount = _nativePasteboard.changeCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @ignore
|
|
||||||
method provided for integration with native pasteboard
|
|
||||||
*/
|
|
||||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
|
||||||
{
|
|
||||||
if (aType === CPStringPboardType)
|
|
||||||
{
|
|
||||||
var string = _nativePasteboard.stringForType_(UTF8PboardType);
|
|
||||||
|
|
||||||
[self setString:string forType:CPStringPboardType];
|
|
||||||
[self setString:string forType:UTF8PboardType];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the property list for the specified data type
|
Returns the property list for the specified data type
|
||||||
@param aType the requested data type
|
@param aType the requested data type
|
||||||
|
|||||||
+62
-47
@@ -26,8 +26,6 @@
|
|||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
|
|
||||||
var VISIBLE_MARGIN = 7.0;
|
|
||||||
|
|
||||||
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -47,6 +45,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
return "popup-button";
|
return "popup-button";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"menu-offset": CGSizeMake(0, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
|
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
|
||||||
{
|
{
|
||||||
return [CPSet setWithObject:@"objectValue"];
|
return [CPSet setWithObject:@"objectValue"];
|
||||||
@@ -363,15 +368,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
*/
|
*/
|
||||||
- (CPArray)itemTitles
|
- (CPArray)itemTitles
|
||||||
{
|
{
|
||||||
var titles = [],
|
return [[self itemArray] arrayByApplyingBlock:function(item)
|
||||||
items = [self itemArray],
|
{
|
||||||
index = 0,
|
return [item title];
|
||||||
count = [items count];
|
}];
|
||||||
|
|
||||||
for (; index < count; ++index)
|
|
||||||
titles.push([items[index] title]);
|
|
||||||
|
|
||||||
return titles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -498,9 +498,17 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
[self addItemWithTitle:aTitle];
|
|
||||||
|
|
||||||
index = [self numberOfItems] - 1;
|
// this ist to match cocoa where setting an empty string does not add it but simply clears the title
|
||||||
|
// and sets objectValue to -1
|
||||||
|
if (aTitle === '')
|
||||||
|
[self selectItemAtIndex:-1];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self addItemWithTitle:aTitle];
|
||||||
|
|
||||||
|
index = [self numberOfItems] - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self selectItemAtIndex:index];
|
[self selectItemAtIndex:index];
|
||||||
@@ -684,14 +692,16 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
if ([self pullsDown])
|
if ([self pullsDown])
|
||||||
{
|
{
|
||||||
var positionedItem = nil,
|
var positionedItem = nil,
|
||||||
location = CGPointMake(0.0, CGRectGetMaxY(bounds) - 1);
|
menuOffset = [self currentValueForThemeAttribute:@"menu-offset"],
|
||||||
|
location = CGPointMake(menuOffset.width, CGRectGetMaxY(bounds) + menuOffset.height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var contentRect = [self contentRectForBounds:bounds],
|
var contentRect = [self contentRectForBounds:bounds],
|
||||||
positionedItem = [self selectedItem],
|
positionedItem = [self selectedItem],
|
||||||
standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
|
standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
|
||||||
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
menuOffset = [self currentValueForThemeAttribute:@"menu-offset"],
|
||||||
|
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin + menuOffset.width, menuOffset.height);
|
||||||
|
|
||||||
minimumWidth += standardLeftMargin;
|
minimumWidth += standardLeftMargin;
|
||||||
|
|
||||||
@@ -773,13 +783,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
[[self selectedItem] setState:CPOffState];
|
[[self selectedItem] setState:CPOffState];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_reverseSetBinding
|
|
||||||
{
|
|
||||||
[_CPPopUpButtonSelectionBinder reverseSetValueForObject:self];
|
|
||||||
|
|
||||||
[super _reverseSetBinding];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPPopUpButton (BindingSupport)
|
@implementation CPPopUpButton (BindingSupport)
|
||||||
@@ -802,6 +805,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
return [super _binderClassForBinding:aBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return (aBinding == CPSelectedIndexBinding ||
|
||||||
|
aBinding == CPSelectedTagBinding ||
|
||||||
|
aBinding == CPSelectedValueBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_reverseSetBinding
|
||||||
|
{
|
||||||
|
[_CPPopUpButtonSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||||
|
|
||||||
|
[super _reverseSetBinding];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPPopUpButtonContentBinder : CPBinder
|
@implementation _CPPopUpButtonContentBinder : CPBinder
|
||||||
@@ -847,7 +864,17 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
{
|
{
|
||||||
var count = [aValue count],
|
var count = [aValue count],
|
||||||
options = [_info objectForKey:CPOptionsKey],
|
options = [_info objectForKey:CPOptionsKey],
|
||||||
offset = [self _getInsertNullOffset];
|
offset = [self _getInsertNullOffset],
|
||||||
|
selectedBindingInfo = [_source infoForBinding:CPSelectedObjectBinding],
|
||||||
|
selectedObject = nil;
|
||||||
|
|
||||||
|
if (selectedBindingInfo)
|
||||||
|
{
|
||||||
|
var destination = [selectedBindingInfo objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [selectedBindingInfo objectForKey:CPObservedKeyPathKey];
|
||||||
|
|
||||||
|
selectedObject = [destination valueForKeyPath:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
if (count + offset != [_source numberOfItems])
|
if (count + offset != [_source numberOfItems])
|
||||||
{
|
{
|
||||||
@@ -858,9 +885,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil];
|
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil],
|
||||||
[self _setValue:[aValue objectAtIndex:i] forItem:item withOptions:options];
|
itemValue = [aValue objectAtIndex:i];
|
||||||
|
|
||||||
|
[self _setValue:itemValue forItem:item withOptions:options];
|
||||||
[_source addItem:item];
|
[_source addItem:item];
|
||||||
|
|
||||||
|
// Select this item if it is the one selected by the selected object binding
|
||||||
|
// This is needed if the selected object binding is set before the items
|
||||||
|
// from the content binding
|
||||||
|
if (itemValue === selectedObject)
|
||||||
|
{
|
||||||
|
[_source setSelectedIndex:[_source numberOfItems] - 1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -931,30 +968,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var binderForObject = {};
|
|
||||||
|
|
||||||
@implementation _CPPopUpButtonSelectionBinder : CPBinder
|
@implementation _CPPopUpButtonSelectionBinder : CPBinder
|
||||||
{
|
{
|
||||||
CPString _selectionBinding @accessors;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
|
||||||
{
|
|
||||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
binderForObject[[aSource UID]] = self;
|
|
||||||
_selectionBinding = aName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)reverseSetValueForObject:(id)aSource
|
|
||||||
{
|
|
||||||
var binder = binderForObject[[aSource UID]];
|
|
||||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
|||||||
+70
-32
@@ -28,8 +28,19 @@
|
|||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPViewController.j"
|
||||||
@import "_CPPopoverWindow.j"
|
@import "_CPPopoverWindow.j"
|
||||||
|
|
||||||
|
@protocol CPPopoverDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)popoverShouldClose:(CPPopover)aPopover;
|
||||||
|
- (void)popoverWillClose:(CPPopover)aPopover;
|
||||||
|
- (void)popoverDidClose:(CPPopover)aPopover;
|
||||||
|
- (void)popoverWillShow:(CPPopover)aPopover;
|
||||||
|
- (void)popoverDidShow:(CPPopover)aPopover;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
CPPopoverBehaviorApplicationDefined = 0;
|
CPPopoverBehaviorApplicationDefined = 0;
|
||||||
CPPopoverBehaviorTransient = 1;
|
CPPopoverBehaviorTransient = 1;
|
||||||
@@ -60,15 +71,16 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
@implementation CPPopover : CPResponder
|
@implementation CPPopover : CPResponder
|
||||||
{
|
{
|
||||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||||
@outlet id _delegate @accessors(getter=delegate);
|
@outlet id <CPPopoverDelegate> _delegate @accessors(getter=delegate);
|
||||||
|
|
||||||
BOOL _animates @accessors(getter=animates);
|
BOOL _animates @accessors(getter=animates);
|
||||||
int _appearance @accessors(property=appearance);
|
int _appearance @accessors(property=appearance);
|
||||||
int _behavior @accessors(getter=behavior);
|
int _behavior @accessors(getter=behavior);
|
||||||
|
|
||||||
_CPPopoverWindow _popoverWindow;
|
_CPPopoverWindow _popoverWindow;
|
||||||
int _implementedDelegateMethods;
|
CPView _positioningView;
|
||||||
|
int _implementedDelegateMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -127,9 +139,6 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (CGSize)contentSize
|
- (CGSize)contentSize
|
||||||
{
|
{
|
||||||
if (![_popoverWindow isVisible])
|
|
||||||
return CGRectMakeZero();
|
|
||||||
|
|
||||||
return [[_contentViewController view] frameSize];
|
return [[_contentViewController view] frameSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +149,10 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (void)setContentSize:(CGSize)aSize
|
- (void)setContentSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[[_contentViewController view] setFrameSize:aSize];
|
if (!_popoverWindow)
|
||||||
|
[[_contentViewController view] setFrameSize:aSize];
|
||||||
|
else
|
||||||
|
[_popoverWindow updateFrameWithSize:aSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -181,10 +193,10 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_behavior = aBehavior;
|
_behavior = aBehavior;
|
||||||
[_popoverWindow setStyleMask:[self styleMaskForBehavior]];
|
[_popoverWindow setStyleMask:[self _styleMaskForBehavior]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPPopoverDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate === aDelegate)
|
if (_delegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
@@ -226,17 +238,14 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
if (!_contentViewController)
|
if (!_contentViewController)
|
||||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||||
|
|
||||||
// If the popover is currently closing, do nothing. That is what Cocoa does.
|
// If the popover is currently closing or opening, do nothing. That is what Cocoa does.
|
||||||
if ([_popoverWindow isClosing])
|
if ([_popoverWindow isClosing] || [_popoverWindow isOpening])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
_positioningView = positioningView;
|
||||||
[_delegate popoverWillShow:self];
|
|
||||||
|
|
||||||
if (!_popoverWindow)
|
if (!_popoverWindow)
|
||||||
{
|
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self _styleMaskForBehavior]];
|
||||||
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self styleMaskForBehavior]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
||||||
[_popoverWindow setAppearance:_appearance];
|
[_popoverWindow setAppearance:_appearance];
|
||||||
@@ -245,15 +254,22 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
[_popoverWindow setMovableByWindowBackground:NO];
|
[_popoverWindow setMovableByWindowBackground:NO];
|
||||||
[_popoverWindow setFrame:[_popoverWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
[_popoverWindow setFrame:[_popoverWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||||
[_popoverWindow setContentView:[_contentViewController view]];
|
[_popoverWindow setContentView:[_contentViewController view]];
|
||||||
|
|
||||||
|
if (![self isShown])
|
||||||
|
[self _popoverWillShow];
|
||||||
|
|
||||||
[_popoverWindow positionRelativeToRect:positioningRect ofView:positioningView preferredEdge:preferredEdge];
|
[_popoverWindow positionRelativeToRect:positioningRect ofView:positioningView preferredEdge:preferredEdge];
|
||||||
|
|
||||||
if (!_animates && _implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
if (![self isShown])
|
||||||
[_delegate popoverDidShow:self];
|
[self _popoverWindowDidShow];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned)styleMaskForBehavior
|
- (unsigned)_styleMaskForBehavior
|
||||||
{
|
{
|
||||||
return (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : 0;
|
if (_behavior == CPPopoverBehaviorApplicationDefined)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return CPClosableOnBlurWindowMask
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -272,9 +288,9 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
if ([_popoverWindow isClosing] || ![self isShown])
|
if ([_popoverWindow isClosing] || ![self isShown])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
[self _popoverWillClose];
|
||||||
[_delegate popoverWillClose:self];
|
|
||||||
|
|
||||||
|
_positioningView = nil;
|
||||||
[_popoverWindow close];
|
[_popoverWindow close];
|
||||||
|
|
||||||
// popoverDidClose will be sent from popoverWindowDidClose, since
|
// popoverDidClose will be sent from popoverWindowDidClose, since
|
||||||
@@ -295,9 +311,8 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
if ([_popoverWindow isClosing])
|
if ([_popoverWindow isClosing])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
if (![self _popoverShouldClose])
|
||||||
if (![_delegate popoverShouldClose:self])
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
[self _close];
|
[self _close];
|
||||||
}
|
}
|
||||||
@@ -307,7 +322,7 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
#pragma mark Delegates
|
#pragma mark Delegates
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (BOOL)popoverWindowShouldClose:(_CPPopoverWindow)aPopoverWindow
|
- (BOOL)_popoverWindowShouldClose
|
||||||
{
|
{
|
||||||
[self performClose:self];
|
[self performClose:self];
|
||||||
|
|
||||||
@@ -318,19 +333,42 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)popoverWindowDidClose:(_CPPopoverWindow)aPopoverWindow
|
- (void)_popoverWindowDidClose
|
||||||
{
|
{
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||||
[_delegate popoverDidClose:self];
|
[_delegate popoverDidClose:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)popoverWindowDidShow:(_CPPopoverWindow)aPopoverWindow
|
- (void)_popoverWindowDidShow
|
||||||
{
|
{
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||||
[_delegate popoverDidShow:self];
|
[_delegate popoverDidShow:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (BOOL)_popoverShouldClose
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||||
|
return [_delegate popoverShouldClose:self];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)_popoverWillClose
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||||
|
[_delegate popoverWillClose:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)_popoverWillShow
|
||||||
|
{
|
||||||
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||||
|
[_delegate popoverWillShow:self];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPPopover (Deprecated)
|
@implementation CPPopover (Deprecated)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
@import "CPWindow_Constants.j"
|
@import "CPWindow_Constants.j"
|
||||||
|
|
||||||
|
|
||||||
|
@typedef CPProgressIndicatorStyle
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPProgressIndicatorStyle
|
@group CPProgressIndicatorStyle
|
||||||
@@ -85,6 +86,9 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
|||||||
@"spinning-mini-gif": [CPNull null],
|
@"spinning-mini-gif": [CPNull null],
|
||||||
@"spinning-small-gif": [CPNull null],
|
@"spinning-small-gif": [CPNull null],
|
||||||
@"spinning-regular-gif": [CPNull null],
|
@"spinning-regular-gif": [CPNull null],
|
||||||
|
@"circular-border-color": [CPNull null],
|
||||||
|
@"circular-border-size": 1,
|
||||||
|
@"circular-color": [CPNull null]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +371,7 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
|||||||
- (void)drawBar
|
- (void)drawBar
|
||||||
{
|
{
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
@@ -412,6 +417,9 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
|||||||
{
|
{
|
||||||
if (_style == CPProgressIndicatorSpinningStyle)
|
if (_style == CPProgressIndicatorSpinningStyle)
|
||||||
{
|
{
|
||||||
|
if (!_indeterminate)
|
||||||
|
return;
|
||||||
|
|
||||||
// This will cause the bar view to go away due to having a nil rect when _style == CPProgressIndicatorSpinningStyle.
|
// This will cause the bar view to go away due to having a nil rect when _style == CPProgressIndicatorSpinningStyle.
|
||||||
[self layoutEphemeralSubviewNamed:"bar-view"
|
[self layoutEphemeralSubviewNamed:"bar-view"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
@@ -437,6 +445,54 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
|||||||
[self setBackgroundColor:nil];
|
[self setBackgroundColor:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
if (_style == CPProgressIndicatorSpinningStyle && !_indeterminate)
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
rect = CGRectMakeCopy(aRect),
|
||||||
|
borderSize = [self currentValueForThemeAttribute:@"circular-border-size"];
|
||||||
|
|
||||||
|
rect.origin.x += borderSize;
|
||||||
|
rect.origin.y += borderSize;
|
||||||
|
rect.size.width = rect.size.width - borderSize * 2;
|
||||||
|
rect.size.height = rect.size.height - borderSize * 2;
|
||||||
|
|
||||||
|
if ([self doubleValue] > [self minValue] && [self doubleValue] < [self maxValue])
|
||||||
|
{
|
||||||
|
var midX = CGRectGetMidX(rect),
|
||||||
|
midY = CGRectGetMidY(rect),
|
||||||
|
endAngle = Math.PI * 2 * (([self doubleValue] - [self minValue]) / ([self maxValue] - [self minValue])) - Math.PI / 2,
|
||||||
|
radius = MIN(rect.size.width / 2, rect.size.height / 2);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetLineWidth(context, borderSize);
|
||||||
|
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
|
||||||
|
CGContextMoveToPoint(context, midX, midY);
|
||||||
|
CGContextAddArc(context, midX, midY, radius, 3 * Math.PI / 2, endAngle, YES);
|
||||||
|
CGContextAddLineToPoint(context, midX, midY);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextFillPath(context);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
else if ([self doubleValue] == [self maxValue])
|
||||||
|
{
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
|
||||||
|
CGContextAddEllipseInRect(context, rect);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextFillPath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context , [self currentValueForThemeAttribute:@"circular-border-color"]);
|
||||||
|
CGContextSetLineWidth(context, borderSize);
|
||||||
|
CGContextAddEllipseInRect(context, rect);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+122
-39
@@ -25,8 +25,11 @@
|
|||||||
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
|
|
||||||
|
@class CPRadioGroup
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
|
CPRadioImageOffset = 4.0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -64,10 +67,19 @@
|
|||||||
[[button1 radioGroup] selectedRadio] returns the currently selected
|
[[button1 radioGroup] selectedRadio] returns the currently selected
|
||||||
option.
|
option.
|
||||||
|
|
||||||
|
UPDATE 09/2020 : Implementation of modern Cocoa behavior :
|
||||||
|
|
||||||
|
As in Cocoa, radio buttons grouping is now automatic.
|
||||||
|
|
||||||
|
To be associated in a common group (and so being mutually exclusive),
|
||||||
|
radio buttons must combine 2 criteria :
|
||||||
|
|
||||||
|
- same superview (enclosing view)
|
||||||
|
- same action
|
||||||
|
|
||||||
|
TODO: This first implementation uses "as is" CPRadioGroup. This could
|
||||||
|
be simplified (no more need for radio group action, for example)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CPRadioImageOffset = 4.0;
|
|
||||||
|
|
||||||
@implementation CPRadio : CPButton
|
@implementation CPRadio : CPButton
|
||||||
{
|
{
|
||||||
CPRadioGroup _radioGroup;
|
CPRadioGroup _radioGroup;
|
||||||
@@ -160,6 +172,71 @@ CPRadioImageOffset = 4.0;
|
|||||||
[CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
|
[CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidMoveToSuperview
|
||||||
|
{
|
||||||
|
[self _setRadioGroup];
|
||||||
|
[super viewDidMoveToSuperview];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAction:(SEL)anAction
|
||||||
|
{
|
||||||
|
if (anAction === _action)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super setAction:anAction];
|
||||||
|
[self _setRadioGroup];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Private methods
|
||||||
|
|
||||||
|
- (void)_setRadioGroup
|
||||||
|
{
|
||||||
|
// Implementation of modern Cocoa behavior : automatic radio group
|
||||||
|
|
||||||
|
// If no action is set or no superview, no grouping can be done.
|
||||||
|
if (![self action] || ![self superview])
|
||||||
|
{
|
||||||
|
// If this radio is in a group (size > 1), remove it.
|
||||||
|
if ([[self radioGroup] size] > 1)
|
||||||
|
{
|
||||||
|
[self setRadioGroup:[CPRadioGroup new]];
|
||||||
|
|
||||||
|
if ([self state] === CPOnState)
|
||||||
|
[_radioGroup _setSelectedRadio:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search in superview subviews for other radio buttons having the same action.
|
||||||
|
// Take the one with the radio group having the greatest number of members.
|
||||||
|
|
||||||
|
var radioGroup;
|
||||||
|
|
||||||
|
for (var i = 0, superviewSubviews = [[self superview] subviews], count = [superviewSubviews count], aSubview, myAction = [self action], radioGroupSize = -1; (i < count); i++)
|
||||||
|
{
|
||||||
|
aSubview = superviewSubviews[i];
|
||||||
|
|
||||||
|
if ([aSubview isKindOfClass:CPRadio] && (aSubview !== self) && ([aSubview action] === myAction) && ([[aSubview radioGroup] size] > radioGroupSize))
|
||||||
|
{
|
||||||
|
radioGroup = [aSubview radioGroup];
|
||||||
|
radioGroupSize = [radioGroup size];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radioGroup)
|
||||||
|
[self setRadioGroup:radioGroup];
|
||||||
|
else
|
||||||
|
// No other radio buttons to group with found.
|
||||||
|
// It may be because this radio button was in a radio group and its action was changed.
|
||||||
|
// If this is the case, we must reisolate it in a new radio group.
|
||||||
|
if ([_radioGroup size] > 1)
|
||||||
|
[self setRadioGroup:[CPRadioGroup new]];
|
||||||
|
|
||||||
|
if ([self state] === CPOnState)
|
||||||
|
[_radioGroup _setSelectedRadio:self];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||||
@@ -183,21 +260,37 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
[aCoder encodeObject:_radioGroup forKey:CPRadioRadioGroupKey];
|
[aCoder encodeObject:_radioGroup forKey:CPRadioRadioGroupKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)image
|
#pragma mark -
|
||||||
|
#pragma mark Override methods from CPButton
|
||||||
|
|
||||||
|
- (CPThemeState)_contentVisualState
|
||||||
{
|
{
|
||||||
return [self currentValueForThemeAttribute:@"image"];
|
// Note : Behavior differs from CPButton as title doesn't follow the highlightsBy content flag
|
||||||
|
|
||||||
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
|
currentState = [self state];
|
||||||
|
|
||||||
|
if ((currentState !== CPOffState) && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)alternateImage
|
- (CPThemeState)_imageVisualState
|
||||||
{
|
{
|
||||||
return [self currentValueForThemeAttribute:@"image"];
|
// Note : Behavior differs from CPButton as we don't force "not selected" theme state
|
||||||
}
|
// when button is highglighted and selected
|
||||||
|
|
||||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
var visualState = [self themeState] || CPThemeStateNormal, // Needed during theme compilation
|
||||||
{
|
currentState = [self state];
|
||||||
var startedTracking = [super startTrackingAt:aPoint];
|
|
||||||
[self highlight:YES];
|
if (_isHighlighted && (_highlightsBy & CPContentsCellMask))
|
||||||
return startedTracking;
|
visualState = visualState.and(CPThemeStateHighlighted);
|
||||||
|
|
||||||
|
if ((currentState !== CPOffState) && (_showsStateBy & CPContentsCellMask))
|
||||||
|
visualState = visualState.and((currentState === CPOnState) ? CPThemeStateSelected : CPButtonStateMixed);
|
||||||
|
|
||||||
|
return visualState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -267,9 +360,9 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
- (BOOL)selectRadioWithTag:(int)tag
|
- (BOOL)selectRadioWithTag:(int)tag
|
||||||
{
|
{
|
||||||
var index = [_radios indexOfObjectPassingTest:function(radio)
|
var index = [_radios indexOfObjectPassingTest:function(radio)
|
||||||
{
|
{
|
||||||
return [radio tag] === tag;
|
return [radio tag] === tag;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (index !== CPNotFound)
|
if (index !== CPNotFound)
|
||||||
{
|
{
|
||||||
@@ -304,6 +397,11 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
return _radios;
|
return _radios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (int)size
|
||||||
|
{
|
||||||
|
return [_radios count];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setEnabled:(BOOL)enabled
|
- (void)setEnabled:(BOOL)enabled
|
||||||
{
|
{
|
||||||
[_radios makeObjectsPerformSelector:@selector(setEnabled:) withObject:enabled];
|
[_radios makeObjectsPerformSelector:@selector(setEnabled:) withObject:enabled];
|
||||||
@@ -356,7 +454,7 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
[_selectedRadio setState:CPOffState];
|
[_selectedRadio setState:CPOffState];
|
||||||
|
|
||||||
_selectedRadio = aRadio;
|
_selectedRadio = aRadio;
|
||||||
[_CPRadioGroupSelectionBinder reverseSetValueForObject:self];
|
[_CPRadioGroupSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -407,32 +505,17 @@ var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
|
|||||||
return [super _binderClassForBinding:aBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return (aBinding == CPSelectedIndexBinding ||
|
||||||
|
aBinding == CPSelectedTagBinding ||
|
||||||
|
aBinding == CPSelectedValueBinding);
|
||||||
|
}
|
||||||
|
|
||||||
var binderForObject = {};
|
@end
|
||||||
|
|
||||||
@implementation _CPRadioGroupSelectionBinder : CPBinder
|
@implementation _CPRadioGroupSelectionBinder : CPBinder
|
||||||
{
|
{
|
||||||
CPString _selectionBinding @accessors;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
|
||||||
{
|
|
||||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
binderForObject[[aSource UID]] = self;
|
|
||||||
_selectionBinding = aName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)reverseSetValueForObject:(id)aSource
|
|
||||||
{
|
|
||||||
var binder = binderForObject[[aSource UID]];
|
|
||||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
|||||||
+15
-1
@@ -24,8 +24,10 @@
|
|||||||
@import <Foundation/CPObjJRuntime.j>
|
@import <Foundation/CPObjJRuntime.j>
|
||||||
|
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
|
@import "CPCursor.j"
|
||||||
|
|
||||||
@class CPKeyBinding
|
@class CPKeyBinding
|
||||||
|
@class CPMenu
|
||||||
|
|
||||||
CPDeleteKeyCode = 8;
|
CPDeleteKeyCode = 8;
|
||||||
CPTabKeyCode = 9;
|
CPTabKeyCode = 9;
|
||||||
@@ -199,6 +201,18 @@ CPDeleteForwardKeyCode = 46;
|
|||||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Notifies the receiver that the mouse entered the receiver's area and that it can adapt the cursor.
|
||||||
|
@param anEvent contains information about the exit
|
||||||
|
*/
|
||||||
|
- (void)cursorUpdate:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_nextResponder)
|
||||||
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
|
else
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Notifies the receiver that the mouse scroll wheel has moved.
|
Notifies the receiver that the mouse scroll wheel has moved.
|
||||||
@param anEvent information about the scroll
|
@param anEvent information about the scroll
|
||||||
@@ -383,7 +397,7 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
|||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
// This will come out nil on the other side with decodeObjectForKey:
|
// This will come out nil on the other side with decodeObjectForKey:
|
||||||
if (_nextResponder !== nil)
|
if (_nextResponder != nil)
|
||||||
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
|
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
|
||||||
|
|||||||
@@ -27,8 +27,7 @@
|
|||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
// NOTE: CPDatePicker is not implemented yet
|
@import "CPDatePicker.j"
|
||||||
@class CPDatePicker
|
|
||||||
|
|
||||||
|
|
||||||
CPUndefinedAttributeType = 0;
|
CPUndefinedAttributeType = 0;
|
||||||
@@ -472,9 +471,11 @@ CPTransformableAttributeType = 1800;
|
|||||||
|
|
||||||
var value;
|
var value;
|
||||||
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
|
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
|
||||||
value = [aView intValue];
|
value = [aView floatValue];
|
||||||
else if (attributeType == CPBooleanAttributeType)
|
else if (attributeType == CPBooleanAttributeType)
|
||||||
value = [aView state];
|
value = [aView state];
|
||||||
|
else if (attributeType == CPDateAttributeType)
|
||||||
|
value = [aView dateValue];
|
||||||
else
|
else
|
||||||
value = [aView stringValue];
|
value = [aView stringValue];
|
||||||
|
|
||||||
@@ -488,7 +489,36 @@ CPTransformableAttributeType = 1800;
|
|||||||
|
|
||||||
- (id)copy
|
- (id)copy
|
||||||
{
|
{
|
||||||
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
|
var views = [CPArray array],
|
||||||
|
copy = [[[self class] alloc] init];
|
||||||
|
|
||||||
|
[copy _setTemplateType:_templateType];
|
||||||
|
[copy _setOptions:_predicateOptions];
|
||||||
|
[copy _setModifier:_predicateModifier];
|
||||||
|
[copy _setLeftAttributeType:_leftAttributeType];
|
||||||
|
[copy _setRightAttributeType:_rightAttributeType];
|
||||||
|
[copy setLeftIsWildcard:_leftIsWildcard];
|
||||||
|
[copy setRightIsWildcard:_rightIsWildcard];
|
||||||
|
|
||||||
|
[_views enumerateObjectsUsingBlock:function(aView, idx, stop)
|
||||||
|
{
|
||||||
|
var vcopy;
|
||||||
|
|
||||||
|
if ([aView implementsSelector:@selector(copy)])
|
||||||
|
{
|
||||||
|
vcopy = [aView copy];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vcopy = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:aView]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[views addObject:vcopy];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[copy setTemplateViews:views];
|
||||||
|
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
|
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
|
||||||
@@ -680,7 +710,10 @@ CPTransformableAttributeType = 1800;
|
|||||||
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
|
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
|
||||||
}
|
}
|
||||||
else if (attributeType == CPDateAttributeType)
|
else if (attributeType == CPDateAttributeType)
|
||||||
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
|
{
|
||||||
|
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 180, 26)];
|
||||||
|
[view setDatePickerElements:CPYearMonthDayDatePickerElementFlag];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
@@ -797,5 +830,31 @@ var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
|
|||||||
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
|
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Copy support for built-in types
|
||||||
|
@implementation CPDatePicker (CPCopying)
|
||||||
|
|
||||||
|
- (id)copy
|
||||||
|
{
|
||||||
|
var ret = [[[self class] alloc] initWithFrame:[self frame]];
|
||||||
|
|
||||||
|
[ret setTextFont:[self textFont]];
|
||||||
|
[ret setMinDate:[self minDate]];
|
||||||
|
[ret setMaxDate:[self maxDate]];
|
||||||
|
[ret setTimeInterval:[self timeInterval]];
|
||||||
|
[ret setDatePickerMode:[self datePickerMode]];
|
||||||
|
[ret setDatePickerElements:[self datePickerElements]];
|
||||||
|
[ret setDatePickerStyle:[self datePickerStyle]];
|
||||||
|
[ret setLocale:[self locale]];
|
||||||
|
[ret setDateValue:[self dateValue]];
|
||||||
|
[ret setBackgroundColor:[self backgroundColor]];
|
||||||
|
[ret setDrawsBackground:[self drawsBackground]];
|
||||||
|
[ret setBordered:[self isBordered]];
|
||||||
|
[ret _init];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
/*! @endcond */
|
/*! @endcond */
|
||||||
|
|||||||
@@ -41,6 +41,21 @@
|
|||||||
@global CPCaseInsensitivePredicateOption
|
@global CPCaseInsensitivePredicateOption
|
||||||
@global CPOrPredicateType
|
@global CPOrPredicateType
|
||||||
|
|
||||||
|
@protocol CPRuleEditorDelegate <CPObject>
|
||||||
|
|
||||||
|
@required
|
||||||
|
- (id)ruleEditor:(CPRuleEditor)editor child:(CPInteger)index forCriterion:(id)criterion withRowType:(CPRuleEditorRowType)rowType;
|
||||||
|
- (id)ruleEditor:(CPRuleEditor)editor displayValueForCriterion:(id)criterion inRow:(CPInteger)row;
|
||||||
|
- (CPInteger)ruleEditor:(CPRuleEditor)editor numberOfChildrenForCriterion:(id)criterion withRowType:(CPRuleEditorRowType)rowType;
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (CPDictionary)ruleEditor:(CPRuleEditor)editor predicatePartsForCriterion:(id)criterion withDisplayValue:(id)value inRow:(CPInteger)row;
|
||||||
|
- (void)ruleEditorRowsDidChange:(CPNotification)notification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_ = 1 << 1;
|
||||||
|
|
||||||
var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||||
itemsContext = "items",
|
itemsContext = "items",
|
||||||
valuesContext = "values",
|
valuesContext = "values",
|
||||||
@@ -69,50 +84,51 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
|
|
||||||
@implementation CPRuleEditor : CPControl
|
@implementation CPRuleEditor : CPControl
|
||||||
{
|
{
|
||||||
BOOL _suppressKeyDownHandling;
|
BOOL _suppressKeyDownHandling;
|
||||||
BOOL _allowsEmptyCompoundRows;
|
BOOL _allowsEmptyCompoundRows;
|
||||||
BOOL _disallowEmpty;
|
BOOL _disallowEmpty;
|
||||||
BOOL _delegateWantsValidation;
|
BOOL _delegateWantsValidation;
|
||||||
BOOL _editable;
|
BOOL _editable;
|
||||||
BOOL _sendAction;
|
BOOL _sendAction;
|
||||||
|
|
||||||
Class _rowClass;
|
Class _rowClass;
|
||||||
|
|
||||||
CPIndexSet _draggingRows;
|
CPIndexSet _draggingRows;
|
||||||
CPInteger _subviewIndexOfDropLine;
|
CPInteger _subviewIndexOfDropLine;
|
||||||
CPView _dropLineView;
|
CPView _dropLineView;
|
||||||
|
|
||||||
CPMutableArray _rowCache;
|
CPMutableArray _rowCache;
|
||||||
CPMutableArray _slices;
|
CPMutableArray _slices;
|
||||||
|
|
||||||
CPPredicate _predicate;
|
CPPredicate _predicate;
|
||||||
|
|
||||||
CPString _itemsKeyPath;
|
CPString _itemsKeyPath;
|
||||||
CPString _subrowsArrayKeyPath;
|
CPString _subrowsArrayKeyPath;
|
||||||
CPString _typeKeyPath;
|
CPString _typeKeyPath;
|
||||||
CPString _valuesKeyPath;
|
CPString _valuesKeyPath;
|
||||||
CPString _boundArrayKeyPath @accessors(property=boundArrayKeyPath);
|
CPString _boundArrayKeyPath @accessors(property=boundArrayKeyPath);
|
||||||
|
|
||||||
CPView _slicesHolder;
|
CPView _slicesHolder;
|
||||||
CPViewAnimation _currentAnimation;
|
CPViewAnimation _currentAnimation;
|
||||||
|
|
||||||
CPInteger _lastRow;
|
CPInteger _lastRow;
|
||||||
CPInteger _nestingMode;
|
CPInteger _nestingMode;
|
||||||
|
|
||||||
float _alignmentGridWidth;
|
float _alignmentGridWidth;
|
||||||
float _sliceHeight;
|
float _sliceHeight;
|
||||||
|
|
||||||
id _ruleDataSource;
|
id _ruleDataSource;
|
||||||
id _ruleDelegate;
|
id <CPRuleEditorDelegate> _ruleDelegate;
|
||||||
id _boundArrayOwner;
|
id _boundArrayOwner;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
|
|
||||||
CPString _stringsFilename;
|
CPString _stringsFilename;
|
||||||
|
|
||||||
BOOL _isKeyDown;
|
BOOL _isKeyDown;
|
||||||
BOOL _nestingModeDidChange;
|
BOOL _nestingModeDidChange;
|
||||||
|
|
||||||
_CPRuleEditorLocalizer _standardLocalizer @accessors(property=standardLocalizer);
|
_CPRuleEditorLocalizer _standardLocalizer @accessors(property=standardLocalizer);
|
||||||
CPDictionary _itemsAndValuesToAddForRowType;
|
CPDictionary _itemsAndValuesToAddForRowType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @cond */
|
/*! @cond */
|
||||||
@@ -130,20 +146,22 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
@"slice-top-border-color": [CPNull null],
|
@"slice-top-border-color": [CPNull null],
|
||||||
@"slice-bottom-border-color": [CPNull null],
|
@"slice-bottom-border-color": [CPNull null],
|
||||||
@"slice-last-bottom-border-color": [CPNull null],
|
@"slice-last-bottom-border-color": [CPNull null],
|
||||||
@"font": [CPNull null],
|
@"font": [CPFont systemFontOfSize:12],
|
||||||
|
@"font-color": [CPNull null],
|
||||||
@"add-image": [CPNull null],
|
@"add-image": [CPNull null],
|
||||||
@"remove-image": [CPNull null],
|
@"remove-image": [CPNull null],
|
||||||
|
@"vertical-alignment": [CPNull null]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame
|
- (id)initWithFrame:(CGRect)frame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:frame];
|
self = [super initWithFrame:frame];
|
||||||
if (self !== nil)
|
if (self)
|
||||||
{
|
{
|
||||||
_slices = [[CPMutableArray alloc] init];
|
_slices = [[CPMutableArray alloc] init];
|
||||||
|
|
||||||
_sliceHeight = 26.;
|
_sliceHeight = 26.0;
|
||||||
_nestingMode = CPRuleEditorNestingModeSimple; // 10.5 default is CPRuleEditorNestingModeCompound
|
_nestingMode = CPRuleEditorNestingModeSimple; // 10.5 default is CPRuleEditorNestingModeCompound
|
||||||
_editable = YES;
|
_editable = YES;
|
||||||
_allowsEmptyCompoundRows = NO;
|
_allowsEmptyCompoundRows = NO;
|
||||||
@@ -213,19 +231,24 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
@discussion CPRuleEditor requires a delegate that implements the required delegate methods to function.
|
@discussion CPRuleEditor requires a delegate that implements the required delegate methods to function.
|
||||||
@see delegate
|
@see delegate
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPRuleEditorDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (_ruleDelegate === aDelegate)
|
if (_ruleDelegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var nc = [CPNotificationCenter defaultCenter];
|
var nc = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
if (_ruleDelegate)
|
if (_ruleDelegate)
|
||||||
[nc removeObserver:_ruleDelegate name:nil object:self];
|
[nc removeObserver:_ruleDelegate name:nil object:self];
|
||||||
|
|
||||||
_ruleDelegate = aDelegate;
|
_ruleDelegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
if ([_ruleDelegate respondsToSelector:@selector(ruleEditorRowsDidChange:)])
|
if ([_ruleDelegate respondsToSelector:@selector(ruleEditorRowsDidChange:)])
|
||||||
[nc addObserver:_ruleDelegate selector:@selector(ruleEditorRowsDidChange:) name:CPRuleEditorRowsDidChangeNotification object:nil];
|
[nc addObserver:_ruleDelegate selector:@selector(ruleEditorRowsDidChange:) name:CPRuleEditorRowsDidChangeNotification object:nil];
|
||||||
|
|
||||||
|
if ([_ruleDelegate respondsToSelector:@selector(ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:)])
|
||||||
|
_implementedDelegateMethods |= CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_;
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
@brief Returns a Boolean value that indicates whether the receiver is editable.
|
@brief Returns a Boolean value that indicates whether the receiver is editable.
|
||||||
@@ -396,7 +419,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
*/
|
*/
|
||||||
- (void)setFormattingStringsFilename:(CPString)stringsFilename
|
- (void)setFormattingStringsFilename:(CPString)stringsFilename
|
||||||
{
|
{
|
||||||
if (_standardLocalizer === nil)
|
if (_standardLocalizer == nil)
|
||||||
_standardLocalizer = [_CPRuleEditorLocalizer new];
|
_standardLocalizer = [_CPRuleEditorLocalizer new];
|
||||||
|
|
||||||
if (_stringsFilename !== stringsFilename)
|
if (_stringsFilename !== stringsFilename)
|
||||||
@@ -404,14 +427,14 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
// Convert an empty string to nil
|
// Convert an empty string to nil
|
||||||
_stringsFilename = stringsFilename || nil;
|
_stringsFilename = stringsFilename || nil;
|
||||||
|
|
||||||
if (stringsFilename !== nil)
|
if (stringsFilename != nil)
|
||||||
{
|
{
|
||||||
if (![stringsFilename hasSuffix:@".strings"])
|
if (![stringsFilename hasSuffix:@".strings"])
|
||||||
stringsFilename = stringsFilename + @".strings";
|
stringsFilename = stringsFilename + @".strings";
|
||||||
|
|
||||||
var path = [[CPBundle mainBundle] pathForResource:stringsFilename];
|
var path = [[CPBundle mainBundle] pathForResource:stringsFilename];
|
||||||
|
|
||||||
if (path !== nil)
|
if (path != nil)
|
||||||
[_standardLocalizer loadContentOfURL:[CPURL URLWithString:path]];
|
[_standardLocalizer loadContentOfURL:[CPURL URLWithString:path]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,7 +465,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
*/
|
*/
|
||||||
- (void)setCriteria:(CPArray)criteria andDisplayValues:(CPArray)values forRowAtIndex:(int)rowIndex
|
- (void)setCriteria:(CPArray)criteria andDisplayValues:(CPArray)values forRowAtIndex:(int)rowIndex
|
||||||
{
|
{
|
||||||
if (criteria === nil || values === nil)
|
if (criteria == nil || values == nil)
|
||||||
[CPException raise:CPInvalidArgumentException reason:_cmd + @". criteria and values parameters must not be nil."];
|
[CPException raise:CPInvalidArgumentException reason:_cmd + @". criteria and values parameters must not be nil."];
|
||||||
|
|
||||||
if (rowIndex < 0 || rowIndex >= [self numberOfRows])
|
if (rowIndex < 0 || rowIndex >= [self numberOfRows])
|
||||||
@@ -810,7 +833,7 @@ TODO: implement
|
|||||||
var item = [items objectAtIndex:i],
|
var item = [items objectAtIndex:i],
|
||||||
//var displayValue = [self _queryValueForItem:item inRow:aRow]; Ask the delegate or get cached value ?.
|
//var displayValue = [self _queryValueForItem:item inRow:aRow]; Ask the delegate or get cached value ?.
|
||||||
displayValue = [[self displayValuesForRow:aRow] objectAtIndex:i],
|
displayValue = [[self displayValuesForRow:aRow] objectAtIndex:i],
|
||||||
predpart = [_ruleDelegate ruleEditor:self predicatePartsForCriterion:item withDisplayValue:displayValue inRow:aRow];
|
predpart = [self _sendDelegateRuleEditorPredicatePartsForCriterion:item withDisplayValue:displayValue inRow:aRow];
|
||||||
|
|
||||||
if (predpart)
|
if (predpart)
|
||||||
[predicateParts addEntriesFromDictionary:predpart];
|
[predicateParts addEntriesFromDictionary:predpart];
|
||||||
@@ -829,7 +852,7 @@ TODO: implement
|
|||||||
while (current_index !== CPNotFound)
|
while (current_index !== CPNotFound)
|
||||||
{
|
{
|
||||||
var subpredicate = [self predicateForRow:current_index];
|
var subpredicate = [self predicateForRow:current_index];
|
||||||
if (subpredicate !== nil)
|
if (subpredicate != nil)
|
||||||
[subpredicates addObject:subpredicate];
|
[subpredicates addObject:subpredicate];
|
||||||
|
|
||||||
current_index = [subrowsIndexes indexGreaterThanIndex:current_index];
|
current_index = [subrowsIndexes indexGreaterThanIndex:current_index];
|
||||||
@@ -865,33 +888,33 @@ TODO: implement
|
|||||||
modifier = [predicateParts objectForKey:CPRuleEditorPredicateComparisonModifier],
|
modifier = [predicateParts objectForKey:CPRuleEditorPredicateComparisonModifier],
|
||||||
selector = CPSelectorFromString([predicateParts objectForKey:CPRuleEditorPredicateCustomSelector]);
|
selector = CPSelectorFromString([predicateParts objectForKey:CPRuleEditorPredicateCustomSelector]);
|
||||||
|
|
||||||
if (lhs === nil)
|
if (lhs == nil)
|
||||||
{
|
{
|
||||||
CPLogConsole(@"missing left expression in predicate parts dictionary");
|
CPLogConsole(@"missing left expression in predicate parts dictionary");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs === nil)
|
if (rhs == nil)
|
||||||
{
|
{
|
||||||
CPLogConsole(@"missing right expression in predicate parts dictionary");
|
CPLogConsole(@"missing right expression in predicate parts dictionary");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selector === nil && operator === nil)
|
if (selector == nil && operator == nil)
|
||||||
{
|
{
|
||||||
CPLogConsole(@"missing operator and selector in predicate parts dictionary");
|
CPLogConsole(@"missing operator and selector in predicate parts dictionary");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifier === nil)
|
if (modifier == nil)
|
||||||
CPLogConsole(@"missing modifier in predicate parts dictionary. Setting default: CPDirectPredicateModifier");
|
CPLogConsole(@"missing modifier in predicate parts dictionary. Setting default: CPDirectPredicateModifier");
|
||||||
|
|
||||||
if (options === nil)
|
if (options == nil)
|
||||||
CPLogConsole(@"missing options in predicate parts dictionary. Setting default: CPCaseInsensitivePredicateOption");
|
CPLogConsole(@"missing options in predicate parts dictionary. Setting default: CPCaseInsensitivePredicateOption");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (selector !== nil)
|
if (selector != nil)
|
||||||
predicate = [CPComparisonPredicate predicateWithLeftExpression:lhs
|
predicate = [CPComparisonPredicate predicateWithLeftExpression:lhs
|
||||||
rightExpression:rhs
|
rightExpression:rhs
|
||||||
customSelector:selector
|
customSelector:selector
|
||||||
@@ -1144,7 +1167,7 @@ TODO: implement
|
|||||||
|
|
||||||
- (BOOL)_wantsRowAnimations
|
- (BOOL)_wantsRowAnimations
|
||||||
{
|
{
|
||||||
return (_currentAnimation !== nil);
|
return (_currentAnimation != nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateButtonVisibilities
|
- (void)_updateButtonVisibilities
|
||||||
@@ -1716,8 +1739,7 @@ TODO: implement
|
|||||||
{
|
{
|
||||||
if (_delegateWantsValidation)
|
if (_delegateWantsValidation)
|
||||||
{
|
{
|
||||||
var selector = @selector(ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:);
|
if (![self _delegateRespondsToRuleEditorPredicatePartsForCriterionWithDisplayValueInRow])
|
||||||
if (![_ruleDelegate respondsToSelector:selector])
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_delegateWantsValidation = NO;
|
_delegateWantsValidation = NO;
|
||||||
@@ -1731,7 +1753,7 @@ TODO: implement
|
|||||||
{
|
{
|
||||||
var subpredicate = [self predicateForRow:current_index];
|
var subpredicate = [self predicateForRow:current_index];
|
||||||
|
|
||||||
if (subpredicate !== nil)
|
if (subpredicate != nil)
|
||||||
[subpredicates addObject:subpredicate];
|
[subpredicates addObject:subpredicate];
|
||||||
|
|
||||||
current_index = [subindexes indexGreaterThanIndex:current_index];
|
current_index = [subindexes indexGreaterThanIndex:current_index];
|
||||||
@@ -1773,7 +1795,7 @@ TODO: implement
|
|||||||
startRect = [aslice frame],
|
startRect = [aslice frame],
|
||||||
startIndex = [aslice rowIndex] - 1;
|
startIndex = [aslice rowIndex] - 1;
|
||||||
|
|
||||||
if ([aslice superview] === nil)
|
if ([aslice superview] == nil)
|
||||||
{
|
{
|
||||||
startRect = CGRectMake(0, startIndex * _sliceHeight, CGRectGetWidth(startRect), _sliceHeight);
|
startRect = CGRectMake(0, startIndex * _sliceHeight, CGRectGetWidth(startRect), _sliceHeight);
|
||||||
[aslice _reconfigureSubviews];
|
[aslice _reconfigureSubviews];
|
||||||
@@ -1865,14 +1887,34 @@ TODO: implement
|
|||||||
return [self valueForThemeAttribute:@"font"];
|
return [self valueForThemeAttribute:@"font"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)_addImage
|
- (CPColor)_fontColor
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"add-image"];
|
return [self valueForThemeAttribute:@"font-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)_removeImage
|
- (CPImage)_imageAdd
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"remove-image"];
|
return [self valueForThemeAttribute:@"add-image" inState:CPThemeStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)_imageAddHighlighted
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"add-image" inState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)_imageRemove
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"remove-image" inState:CPThemeStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)_imageRemoveHighlighted
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"remove-image" inState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPVerticalTextAlignment)_verticalAlignment
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"vertical-alignment"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)_toolTipForAddCompoundRowButton
|
- (CPString)_toolTipForAddCompoundRowButton
|
||||||
@@ -2079,7 +2121,7 @@ TODO: implement
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var point = [self convertPoint:[event locationInWindow] fromView:nil],
|
var point = [self convertPoint:[event locationInWindow] fromView:nil],
|
||||||
view = [_slices objectAtIndex:FLOOR(point.y / _sliceHeight)];
|
view = [_slices objectAtIndex:FLOOR(MAX(0, point.y) / _sliceHeight)];
|
||||||
|
|
||||||
if ([self _dragShouldBeginFromMouseDown:view])
|
if ([self _dragShouldBeginFromMouseDown:view])
|
||||||
[self _performDragForSlice:view withEvent:event];
|
[self _performDragForSlice:view withEvent:event];
|
||||||
@@ -2087,7 +2129,7 @@ TODO: implement
|
|||||||
|
|
||||||
- (BOOL)_dragShouldBeginFromMouseDown:(CPView)view
|
- (BOOL)_dragShouldBeginFromMouseDown:(CPView)view
|
||||||
{
|
{
|
||||||
return (([self nestingMode] === CPRuleEditorNestingModeList || [view rowIndex] !== 0) && _editable && [view isKindOfClass:[_CPRuleEditorViewSliceRow class]] && _draggingRows === nil);
|
return (([self nestingMode] === CPRuleEditorNestingModeList || [view rowIndex] !== 0) && _editable && [view isKindOfClass:[_CPRuleEditorViewSliceRow class]] && _draggingRows == nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_performDragForSlice:(id)slice withEvent:(CPEvent)event
|
- (BOOL)_performDragForSlice:(id)slice withEvent:(CPEvent)event
|
||||||
@@ -2165,7 +2207,7 @@ TODO: implement
|
|||||||
indexOfDropLine = FLOOR(y / _sliceHeight),
|
indexOfDropLine = FLOOR(y / _sliceHeight),
|
||||||
numberOfRows = [self numberOfRows];
|
numberOfRows = [self numberOfRows];
|
||||||
|
|
||||||
if (indexOfDropLine < 0 || indexOfDropLine > numberOfRows || (indexOfDropLine >= [_draggingRows firstIndex] && indexOfDropLine <= [_draggingRows lastIndex] + 1))
|
if (indexOfDropLine <= 0 || indexOfDropLine > numberOfRows || (indexOfDropLine >= [_draggingRows firstIndex] && indexOfDropLine <= [_draggingRows lastIndex] + 1))
|
||||||
{
|
{
|
||||||
if (_subviewIndexOfDropLine !== CPNotFound && indexOfDropLine !== _subviewIndexOfDropLine)
|
if (_subviewIndexOfDropLine !== CPNotFound && indexOfDropLine !== _subviewIndexOfDropLine)
|
||||||
[self _clearDropLine];
|
[self _clearDropLine];
|
||||||
@@ -2279,7 +2321,7 @@ TODO: implement
|
|||||||
|
|
||||||
- (void)_postRowCountChangedNotificationOfType:(CPString)notificationName indexes:indexes
|
- (void)_postRowCountChangedNotificationOfType:(CPString)notificationName indexes:indexes
|
||||||
{
|
{
|
||||||
var userInfo = indexes === nil ? @{} : @{ "indexes": indexes };
|
var userInfo = indexes == nil ? @{} : @{ "indexes": indexes };
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo];
|
[[CPNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2344,7 +2386,7 @@ TODO: implement
|
|||||||
var criteria = [self criteriaForRow:aRow];
|
var criteria = [self criteriaForRow:aRow];
|
||||||
indexofCriterion = [criteria indexOfObject:criterion];
|
indexofCriterion = [criteria indexOfObject:criterion];
|
||||||
|
|
||||||
if (parentItem !== nil
|
if (parentItem != nil
|
||||||
&& indexofCriterion !== CPNotFound
|
&& indexofCriterion !== CPNotFound
|
||||||
&& indexofCriterion < [criteria count] - 1)
|
&& indexofCriterion < [criteria count] - 1)
|
||||||
{
|
{
|
||||||
@@ -2377,6 +2419,33 @@ TODO: implement
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPRuleEditor (CPRuleEditorDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Check if the delegate responds to ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:
|
||||||
|
*/
|
||||||
|
- (BOOL)_delegateRespondsToRuleEditorPredicatePartsForCriterionWithDisplayValueInRow
|
||||||
|
{
|
||||||
|
return _implementedDelegateMethods & CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:
|
||||||
|
*/
|
||||||
|
- (CPDictionary)_sendDelegateRuleEditorPredicatePartsForCriterion:(id)criterion withDisplayValue:(id)value inRow:(CPInteger)row
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_))
|
||||||
|
return @{};
|
||||||
|
|
||||||
|
return [_ruleDelegate ruleEditor:self predicatePartsForCriterion:criterion withDisplayValue:value inRow:row];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
||||||
CPRuleEditorSliceHeightKey = @"CPRuleEditorSliceHeight",
|
CPRuleEditorSliceHeightKey = @"CPRuleEditorSliceHeight",
|
||||||
CPRuleEditorStringsFilenameKey = @"CPRuleEditorStringsFilename",
|
CPRuleEditorStringsFilenameKey = @"CPRuleEditorStringsFilename",
|
||||||
@@ -2400,7 +2469,7 @@ var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
|||||||
- (id)initWithCoder:(CPCoder)coder
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
self = [super initWithCoder:coder];
|
self = [super initWithCoder:coder];
|
||||||
if (self !== nil)
|
if (self)
|
||||||
{
|
{
|
||||||
[self setFormattingStringsFilename:[coder decodeObjectForKey:CPRuleEditorStringsFilenameKey]];
|
[self setFormattingStringsFilename:[coder decodeObjectForKey:CPRuleEditorStringsFilenameKey]];
|
||||||
_alignmentGridWidth = [coder decodeFloatForKey:CPRuleEditorAlignmentGridWidthKey];
|
_alignmentGridWidth = [coder decodeFloatForKey:CPRuleEditorAlignmentGridWidthKey];
|
||||||
@@ -2484,7 +2553,7 @@ var CriteriaKey = @"criteria",
|
|||||||
- (id)initWithCoder:(CPCoder)coder
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self !== nil)
|
if (self)
|
||||||
{
|
{
|
||||||
subrows = [coder decodeObjectForKey:SubrowsKey];
|
subrows = [coder decodeObjectForKey:SubrowsKey];
|
||||||
criteria = [coder decodeObjectForKey:CriteriaKey];
|
criteria = [coder decodeObjectForKey:CriteriaKey];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
||||||
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
||||||
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
||||||
@@ -36,5 +37,6 @@ CPRuleEditorNestingModeList = 1; // Allows a single list, with no nes
|
|||||||
CPRuleEditorNestingModeCompound = 2; // Unlimited nesting and compound rows; this is the default
|
CPRuleEditorNestingModeCompound = 2; // Unlimited nesting and compound rows; this is the default
|
||||||
CPRuleEditorNestingModeSimple = 3; // One compound row at the top with subrows beneath it, and no further nesting allowed
|
CPRuleEditorNestingModeSimple = 3; // One compound row at the top with subrows beneath it, and no further nesting allowed
|
||||||
|
|
||||||
|
@typedef CPRuleEditorRowType
|
||||||
CPRuleEditorRowTypeSimple = 0;
|
CPRuleEditorRowTypeSimple = 0;
|
||||||
CPRuleEditorRowTypeCompound = 1;
|
CPRuleEditorRowTypeCompound = 1;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
{
|
{
|
||||||
var title = [self title];
|
var title = [self title];
|
||||||
|
|
||||||
if (title !== nil)
|
if (title != nil)
|
||||||
return title;
|
return title;
|
||||||
|
|
||||||
return [self templateView];
|
return [self templateView];
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
@class CPPredicateEditorRowTemplate
|
||||||
|
|
||||||
@implementation _CPPredicateEditorTree : CPObject
|
@implementation _CPPredicateEditorTree : CPObject
|
||||||
{
|
{
|
||||||
CPPredicateEditorRowTemplate template @accessors;
|
CPPredicateEditorRowTemplate template @accessors;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
|||||||
|
|
||||||
- (void)reloadIfNeeded
|
- (void)reloadIfNeeded
|
||||||
{
|
{
|
||||||
if (connection !== nil) // Connection waiting
|
if (connection != nil) // Connection waiting
|
||||||
{
|
{
|
||||||
connection = nil;
|
connection = nil;
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
|||||||
|
|
||||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
|
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
|
||||||
{
|
{
|
||||||
if (connection !== nil && rawString !== nil)
|
if (connection != nil && rawString != nil)
|
||||||
[self loadContent:rawString];
|
[self loadContent:rawString];
|
||||||
|
|
||||||
connection = nil;
|
connection = nil;
|
||||||
@@ -83,11 +83,11 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
|||||||
{
|
{
|
||||||
[self reloadIfNeeded];
|
[self reloadIfNeeded];
|
||||||
|
|
||||||
if (_dictionary !== nil && aString !== nil)
|
if (_dictionary != nil && aString != nil)
|
||||||
{
|
{
|
||||||
var localized = [_dictionary objectForKey:aString];
|
var localized = [_dictionary objectForKey:aString];
|
||||||
|
|
||||||
if (localized !== nil)
|
if (localized != nil)
|
||||||
return localized;
|
return localized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by cacaodev@gmail.com.
|
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import "CPBezierPath.j"
|
|
||||||
@import "CPPopUpButton.j"
|
|
||||||
|
|
||||||
@class _CPRuleEditorViewSlice
|
|
||||||
|
|
||||||
var GRADIENT_START_COLOR = "#fcfcfc",
|
|
||||||
GRADIENT_END_COLOR = "#dfdfdf",
|
|
||||||
BORDER_COLOR = "#BDBDBD";
|
|
||||||
|
|
||||||
var GRADIENT_NORMAL,
|
|
||||||
GRADIENT_HIGHLIGHTED,
|
|
||||||
GRADIENT_PROPERTY;
|
|
||||||
|
|
||||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
|
||||||
{
|
|
||||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_START_COLOR + "), to(" + GRADIENT_END_COLOR + "))",
|
|
||||||
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_END_COLOR + "), to(" + GRADIENT_START_COLOR + "))";
|
|
||||||
GRADIENT_PROPERTY = "background";
|
|
||||||
}
|
|
||||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
|
||||||
{
|
|
||||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, " + GRADIENT_START_COLOR + ", " + GRADIENT_END_COLOR + ")",
|
|
||||||
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, " + GRADIENT_END_COLOR + ", " + GRADIENT_START_COLOR + ")";
|
|
||||||
GRADIENT_PROPERTY = "background";
|
|
||||||
}
|
|
||||||
else if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
GRADIENT_NORMAL = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_START_COLOR + "', endColorstr='" + GRADIENT_END_COLOR + "')";
|
|
||||||
GRADIENT_HIGHLIGHTED = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_END_COLOR + "', endColorstr='" + GRADIENT_START_COLOR + "')";
|
|
||||||
GRADIENT_PROPERTY = "filter";
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
GRADIENT_NORMAL = GRADIENT_START_COLOR;
|
|
||||||
GRADIENT_HIGHLIGHTED = GRADIENT_END_COLOR;
|
|
||||||
GRADIENT_PROPERTY = "background";
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
|
|
||||||
{
|
|
||||||
CPInteger radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_sharedInit
|
|
||||||
{
|
|
||||||
[self setBordered:NO];
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
var style = _DOMElement.style;
|
|
||||||
style.border = "1px solid " + BORDER_COLOR;
|
|
||||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
if (self = [super initWithFrame:aFrame])
|
|
||||||
[self _sharedInit];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
self = [super initWithCoder:aCoder];
|
|
||||||
[self _sharedInit];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)hitTest:(CGPoint)point
|
|
||||||
{
|
|
||||||
if (!CGRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)sliceIsEditable
|
|
||||||
{
|
|
||||||
var superview = [self superview];
|
|
||||||
return ![superview isKindOfClass:[_CPRuleEditorViewSlice]] || [superview isEditable];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)trackMouse:(CPEvent)theEvent
|
|
||||||
{
|
|
||||||
if (![self sliceIsEditable])
|
|
||||||
return;
|
|
||||||
|
|
||||||
[super trackMouse:theEvent];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
|
||||||
{
|
|
||||||
var contentRect = [super contentRectForBounds:bounds];
|
|
||||||
contentRect.origin.x += radius;
|
|
||||||
contentRect.size.width -= 2 * radius;
|
|
||||||
|
|
||||||
return contentRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
|
||||||
var style = _DOMElement.style,
|
|
||||||
radiusCSS = radius + "px";
|
|
||||||
|
|
||||||
style.borderRadius = radiusCSS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[super layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
|
||||||
{
|
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
|
||||||
bounds = [self bounds],
|
|
||||||
arrow_width = FLOOR(CGRectGetHeight(bounds) / 3.5);
|
|
||||||
|
|
||||||
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
|
|
||||||
|
|
||||||
var arrowsPath = [CPBezierPath bezierPath];
|
|
||||||
[arrowsPath moveToPoint:CGPointMake(0, 1)];
|
|
||||||
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
|
|
||||||
[arrowsPath lineToPoint:CGPointMake(arrow_width / 2, arrow_width + 1)];
|
|
||||||
[arrowsPath closePath];
|
|
||||||
|
|
||||||
CGContextSetFillColor(context, [CPColor colorWithWhite:101 / 255 alpha:1]);
|
|
||||||
[arrowsPath fill];
|
|
||||||
|
|
||||||
CGContextScaleCTM(context, 1 , -1);
|
|
||||||
[arrowsPath fill];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _CPRuleEditorButton : CPButton
|
|
||||||
{
|
|
||||||
CPInteger radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_sharedInit
|
|
||||||
{
|
|
||||||
[self setBordered:NO];
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
var style = _DOMElement.style;
|
|
||||||
style.border = "1px solid " + BORDER_COLOR;
|
|
||||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
if (self = [super initWithFrame:aFrame])
|
|
||||||
[self _sharedInit];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
self = [super initWithCoder:aCoder];
|
|
||||||
[self _sharedInit];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
|
||||||
|
|
||||||
var style = _DOMElement.style,
|
|
||||||
radiusCSS = radius + "px";
|
|
||||||
|
|
||||||
style.borderRadius = radiusCSS;
|
|
||||||
style[GRADIENT_PROPERTY] = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[super layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPRuleEditor
|
||||||
|
|
||||||
@implementation _CPRuleEditorViewSlice : CPView
|
@implementation _CPRuleEditorViewSlice : CPView
|
||||||
{
|
{
|
||||||
CPRuleEditor _ruleEditor;
|
CPRuleEditor _ruleEditor;
|
||||||
@@ -27,7 +29,6 @@
|
|||||||
CGRect _animationTargetRect @accessors(property=_animationTargetRect);
|
CGRect _animationTargetRect @accessors(property=_animationTargetRect);
|
||||||
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
|
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
|
||||||
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
|
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
|
||||||
CPColor _backgroundColor @accessors(property=backgroundColor);
|
|
||||||
BOOL _editable @accessors(getter=isEditable, setter=setEditable:);
|
BOOL _editable @accessors(getter=isEditable, setter=setEditable:);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +62,9 @@
|
|||||||
- (void)drawRect:(CGRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
bounds = [self bounds],
|
bounds = [self bounds],
|
||||||
maxX = CGRectGetWidth(bounds),
|
maxX = CGRectGetWidth(bounds),
|
||||||
maxY = CGRectGetHeight(bounds);
|
maxY = CGRectGetHeight(bounds);
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
if ([self _isSelected])
|
if ([self _isSelected])
|
||||||
|
|||||||
@@ -19,24 +19,27 @@
|
|||||||
|
|
||||||
@import "CPRuleEditor_Constants.j"
|
@import "CPRuleEditor_Constants.j"
|
||||||
@import "_CPRuleEditorViewSlice.j"
|
@import "_CPRuleEditorViewSlice.j"
|
||||||
@import "_CPRuleEditorPopUpButton.j"
|
|
||||||
|
@import "CPButton.j"
|
||||||
|
@import "CPDatePicker.j"
|
||||||
|
@import "CPPopUpButton.j"
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
@global CPMiniControlSize
|
||||||
var CONTROL_HEIGHT = 16.,
|
@global CPSmallControlSize
|
||||||
BUTTON_HEIGHT = 16.;
|
|
||||||
|
|
||||||
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
|
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
|
||||||
{
|
{
|
||||||
CPMutableArray _ruleOptionViews;
|
CPButton _addButton;
|
||||||
CPMutableArray _ruleOptionFrames;
|
CPButton _subtractButton;
|
||||||
CPMutableArray _correspondingRuleItems;
|
CPMutableArray _correspondingRuleItems;
|
||||||
CPMutableArray _ruleOptionInitialViewFrames;
|
CPMutableArray _ruleOptionFrames;
|
||||||
CPButton _addButton;
|
CPMutableArray _ruleOptionInitialViewFrames;
|
||||||
CPButton _subtractButton;
|
CPMutableArray _ruleOptionViews;
|
||||||
|
|
||||||
CPRuleEditorRowType _rowType @accessors;
|
|
||||||
CPRuleEditorRowType _plusButtonRowType;
|
CPRuleEditorRowType _rowType @accessors;
|
||||||
|
CPRuleEditorRowType _plusButtonRowType;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
||||||
@@ -49,34 +52,33 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
- (void)_initShared
|
- (void)_initShared
|
||||||
{
|
{
|
||||||
_correspondingRuleItems = [[CPMutableArray alloc] init];
|
_correspondingRuleItems = [[CPMutableArray alloc] init];
|
||||||
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
||||||
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
||||||
_ruleOptionViews = [[CPMutableArray alloc] init];
|
_ruleOptionViews = [[CPMutableArray alloc] init];
|
||||||
_editable = [_ruleEditor isEditable];
|
_editable = [_ruleEditor isEditable];
|
||||||
|
|
||||||
|
_addButton = [self _createAddRowButton];
|
||||||
|
_subtractButton = [self _createDeleteRowButton];
|
||||||
|
|
||||||
_addButton = [self _createAddRowButton];
|
|
||||||
_subtractButton = [self _createDeleteRowButton];
|
|
||||||
[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
|
||||||
[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
|
||||||
[_addButton setHidden:!_editable];
|
|
||||||
[_subtractButton setHidden:!_editable];
|
|
||||||
[self addSubview:_addButton];
|
[self addSubview:_addButton];
|
||||||
[self addSubview:_subtractButton];
|
[self addSubview:_subtractButton];
|
||||||
|
|
||||||
[self setAutoresizingMask:CPViewWidthSizable];
|
[self setAutoresizingMask:CPViewWidthSizable];
|
||||||
|
|
||||||
var center = [CPNotificationCenter defaultCenter];
|
|
||||||
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPButton)_createRowButton
|
- (CPButton)_createRowButton
|
||||||
{
|
{
|
||||||
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
|
var button = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
|
||||||
[button setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
|
|
||||||
[button setTextColor:[CPColor colorWithWhite:150 / 255 alpha:1]];
|
[button setFont:[_ruleEditor font]];
|
||||||
|
[button setTextColor:[_ruleEditor _fontColor]];
|
||||||
|
|
||||||
[button setAlignment:CPCenterTextAlignment];
|
[button setAlignment:CPCenterTextAlignment];
|
||||||
[button setAutoresizingMask:CPViewMinXMargin];
|
[button setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
[button setButtonType:CPMomentaryChangeButton];
|
||||||
|
[button setBordered:NO];
|
||||||
|
[button setHidden:!_editable];
|
||||||
[button setImagePosition:CPImageOnly];
|
[button setImagePosition:CPImageOnly];
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
@@ -86,7 +88,10 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
{
|
{
|
||||||
var button = [self _createRowButton];
|
var button = [self _createRowButton];
|
||||||
|
|
||||||
[button setImage:[_ruleEditor _addImage]];
|
[button setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||||
|
[button setValue:[_ruleEditor _imageAdd] forThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||||
|
[button setValue:[_ruleEditor _imageAddHighlighted] forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||||
|
|
||||||
[button setAction:@selector(_addOption:)];
|
[button setAction:@selector(_addOption:)];
|
||||||
[button setTarget:self];
|
[button setTarget:self];
|
||||||
|
|
||||||
@@ -97,7 +102,10 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
{
|
{
|
||||||
var button = [self _createRowButton];
|
var button = [self _createRowButton];
|
||||||
|
|
||||||
[button setImage:[_ruleEditor _removeImage]];
|
[button setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||||
|
[button setValue:[_ruleEditor _imageRemove] forThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||||
|
[button setValue:[_ruleEditor _imageRemoveHighlighted] forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||||
|
|
||||||
[button setAction:@selector(_deleteOption:)];
|
[button setAction:@selector(_deleteOption:)];
|
||||||
[button setTarget:self];
|
[button setTarget:self];
|
||||||
|
|
||||||
@@ -107,20 +115,17 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
|
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
|
||||||
{
|
{
|
||||||
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
|
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
|
||||||
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
return [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||||
return mItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
|
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
|
||||||
{
|
{
|
||||||
var title = [[itemsArray objectAtIndex:index] title],
|
var title = [[itemsArray objectAtIndex:index] title],
|
||||||
font = [_ruleEditor font],
|
font = [_ruleEditor font],
|
||||||
width = [title sizeWithFont:font].width + 20,
|
width = [title sizeWithFont:font].width + 35, // 35 for right arrows + margins
|
||||||
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT),
|
rect = CGRectMake(0, 0, width, [_ruleEditor rowHeight]),
|
||||||
|
popup = [[CPPopUpButton alloc] initWithFrame:rect];
|
||||||
|
|
||||||
popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
|
|
||||||
|
|
||||||
[popup setTextColor:[CPColor colorWithWhite:101 / 255 alpha:1]];
|
|
||||||
[popup setValue:font forThemeAttribute:@"font"];
|
[popup setValue:font forThemeAttribute:@"font"];
|
||||||
|
|
||||||
var count = [itemsArray count];
|
var count = [itemsArray count];
|
||||||
@@ -137,17 +142,17 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
return [CPMenuItem separatorItem];
|
return [CPMenuItem separatorItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
- (CPTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
||||||
{
|
{
|
||||||
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CGRectMakeZero()],
|
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()],
|
||||||
ruleEditorFont = [_ruleEditor font],
|
ruleEditorFont = [_ruleEditor font],
|
||||||
font = [CPFont fontWithName:[ruleEditorFont familyName] size:[ruleEditorFont size] + 2],
|
font = [CPFont fontWithName:[ruleEditorFont familyName] size:[ruleEditorFont size] + 2],
|
||||||
localizedText = [[_ruleEditor standardLocalizer] localizedStringForString:text],
|
localizedText = [[_ruleEditor standardLocalizer] localizedStringForString:text],
|
||||||
size = [localizedText sizeWithFont:font];
|
size = [localizedText sizeWithFont:font];
|
||||||
|
|
||||||
[textField setFrameSize:CGSizeMake(size.width + 4, CONTROL_HEIGHT + 2)];
|
|
||||||
|
|
||||||
|
[textField setFrameSize:CGSizeMake(size.width + 4, [_ruleEditor rowHeight])];
|
||||||
[textField setValue:font forThemeAttribute:@"font"];
|
[textField setValue:font forThemeAttribute:@"font"];
|
||||||
|
[textField setValue:[_ruleEditor _verticalAlignment] forThemeAttribute:@"vertical-alignment"];
|
||||||
[textField setStringValue:localizedText];
|
[textField setStringValue:localizedText];
|
||||||
|
|
||||||
return textField;
|
return textField;
|
||||||
@@ -159,6 +164,7 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
var type = _plusButtonRowType;
|
var type = _plusButtonRowType;
|
||||||
|
|
||||||
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
|
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
|
||||||
type = CPRuleEditorRowTypeCompound;
|
type = CPRuleEditorRowTypeCompound;
|
||||||
|
|
||||||
@@ -170,12 +176,12 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
[_ruleEditor _deleteSlice:self];
|
[_ruleEditor _deleteSlice:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
|
- (void)_ruleOptionPopupChangedAction:(CPMenuItem)sender
|
||||||
{
|
{
|
||||||
var layoutdict = [sender representedObject],
|
var layoutdict = [sender representedObject],
|
||||||
newItem = [layoutdict objectForKey:@"item"],
|
newItem = [layoutdict objectForKey:@"item"],
|
||||||
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
|
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
|
||||||
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
|
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
|
||||||
|
|
||||||
if (![newItem isEqual:oldItem])
|
if (![newItem isEqual:oldItem])
|
||||||
{
|
{
|
||||||
@@ -203,8 +209,7 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
- (void)_reconfigureSubviews
|
- (void)_reconfigureSubviews
|
||||||
{
|
{
|
||||||
var ruleItems,
|
var criteria,
|
||||||
criteria,
|
|
||||||
repObject,
|
repObject,
|
||||||
menuItem,
|
menuItem,
|
||||||
ruleView,
|
ruleView,
|
||||||
@@ -307,8 +312,16 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
if (ruleView != nil)
|
if (ruleView != nil)
|
||||||
{
|
{
|
||||||
|
[ruleView setControlSize:CPSmallControlSize];
|
||||||
|
|
||||||
|
var minSize = [ruleView currentValueForThemeAttribute:@"min-size"],
|
||||||
|
frame = [ruleView frame];
|
||||||
|
|
||||||
|
// Force controls to their minimum size
|
||||||
|
frame.size.height = minSize.height;
|
||||||
|
[ruleView setFrame:frame];
|
||||||
|
|
||||||
[_ruleOptionViews addObject:ruleView];
|
[_ruleOptionViews addObject:ruleView];
|
||||||
var frame = [ruleView frame];
|
|
||||||
[_ruleOptionInitialViewFrames addObject:frame];
|
[_ruleOptionInitialViewFrames addObject:frame];
|
||||||
[_ruleOptionFrames addObject:frame];
|
[_ruleOptionFrames addObject:frame];
|
||||||
|
|
||||||
@@ -331,8 +344,6 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
|
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
|
||||||
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
|
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
|
||||||
}
|
}
|
||||||
|
|
||||||
//[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateEnabledStateForSubviews
|
- (void)_updateEnabledStateForSubviews
|
||||||
@@ -350,14 +361,16 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
var optionViewOriginX,
|
var optionViewOriginX,
|
||||||
leftHorizontalPadding,
|
leftHorizontalPadding,
|
||||||
leftButtonMinX,
|
leftButtonMinX,
|
||||||
rowHeight = [_ruleEditor rowHeight],
|
rowHeight = [_ruleEditor rowHeight],
|
||||||
count = [_ruleOptionViews count],
|
count = [_ruleOptionViews count],
|
||||||
sliceFrame = [self frame],
|
sliceFrame = [self frame],
|
||||||
|
image = [_ruleEditor _imageAdd],
|
||||||
|
imageSize = image ? [image size] : CGSizeMake(0,0),
|
||||||
|
|
||||||
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT) / 2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
|
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - imageSize.width - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - imageSize.height) / 2 - 1, imageSize.width, imageSize.height);
|
||||||
|
|
||||||
[_addButton setFrame:buttonFrame];
|
[_addButton setFrame:buttonFrame];
|
||||||
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
|
buttonFrame.origin.x -= imageSize.width + [self _rowButtonsInterviewHorizontalPadding];
|
||||||
[_subtractButton setFrame:buttonFrame];
|
[_subtractButton setFrame:buttonFrame];
|
||||||
|
|
||||||
if (widthChanged)
|
if (widthChanged)
|
||||||
@@ -372,7 +385,8 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
var ruleOptionView = _ruleOptionViews[i],
|
var ruleOptionView = _ruleOptionViews[i],
|
||||||
optionFrame = _ruleOptionFrames[i];
|
optionFrame = _ruleOptionFrames[i];
|
||||||
|
|
||||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame)) / 2 - 2;
|
// Use a pixel correction to align controls
|
||||||
|
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame)) / 2;
|
||||||
|
|
||||||
if (widthChanged)
|
if (widthChanged)
|
||||||
{
|
{
|
||||||
@@ -481,6 +495,26 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
[self layoutSubviews];
|
[self layoutSubviews];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_addObservers
|
||||||
|
{
|
||||||
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
|
{
|
||||||
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[super drawRect:rect];
|
[super drawRect:rect];
|
||||||
@@ -488,8 +522,9 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
- (BOOL)_isRulePopup:(CPView)view
|
- (BOOL)_isRulePopup:(CPView)view
|
||||||
{
|
{
|
||||||
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
|
if ([view isKindOfClass:[CPPopUpButton class]])
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,28 +541,3 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPRuleEditorTextField : CPTextField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:frame];
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
[self setDrawsBackground:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)hitTest:(CGPoint)point
|
|
||||||
{
|
|
||||||
if (!CGRectContainsPoint([self frame], point))
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return [self superview];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|||||||
@@ -35,6 +35,11 @@
|
|||||||
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
|
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPURL)proposedFileURLWithDocumentName:(CPString)aDocumentName
|
||||||
|
{
|
||||||
|
return [CPURL URLWithString:aDocumentName];
|
||||||
|
}
|
||||||
|
|
||||||
+ (id)savePanel
|
+ (id)savePanel
|
||||||
{
|
{
|
||||||
return [[CPSavePanel alloc] init];
|
return [[CPSavePanel alloc] init];
|
||||||
|
|||||||
+189
-62
@@ -30,9 +30,20 @@
|
|||||||
@import "CPScroller.j"
|
@import "CPScroller.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPTableView
|
||||||
|
|
||||||
#define SHOULD_SHOW_CORNER_VIEW() (_scrollerStyle === CPScrollerStyleLegacy && _verticalScroller && ![_verticalScroller isHidden])
|
#define SHOULD_SHOW_CORNER_VIEW() (_scrollerStyle === CPScrollerStyleLegacy && _verticalScroller && ![_verticalScroller isHidden])
|
||||||
|
|
||||||
|
|
||||||
|
@protocol CPScrollViewDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)scrollViewWillScroll:(CPScrollView)aScrollView;
|
||||||
|
- (void)scrollViewDidScroll:(CPScrollView)aScrollView;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
var _isBrowserUsingOverlayScrollers = function()
|
var _isBrowserUsingOverlayScrollers = function()
|
||||||
{
|
{
|
||||||
@@ -77,15 +88,6 @@ var _isBrowserUsingOverlayScrollers = function()
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
@ingroup appkit
|
|
||||||
@class CPScrollView
|
|
||||||
|
|
||||||
Used to display views that are too large for the viewing area. the CPScrollView
|
|
||||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
|
||||||
contents of the view.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var TIMER_INTERVAL = 0.2,
|
var TIMER_INTERVAL = 0.2,
|
||||||
CPScrollViewDelegate_scrollViewWillScroll_ = 1 << 0,
|
CPScrollViewDelegate_scrollViewWillScroll_ = 1 << 0,
|
||||||
CPScrollViewDelegate_scrollViewDidScroll_ = 1 << 1,
|
CPScrollViewDelegate_scrollViewDidScroll_ = 1 << 1,
|
||||||
@@ -95,38 +97,45 @@ var TIMER_INTERVAL = 0.2,
|
|||||||
var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||||
CPScrollerStyleGlobalChangeNotification = @"CPScrollerStyleGlobalChangeNotification";
|
CPScrollerStyleGlobalChangeNotification = @"CPScrollerStyleGlobalChangeNotification";
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPScrollView
|
||||||
|
|
||||||
|
Used to display views that are too large for the viewing area. the CPScrollView
|
||||||
|
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||||
|
contents of the view.
|
||||||
|
*/
|
||||||
@implementation CPScrollView : CPView
|
@implementation CPScrollView : CPView
|
||||||
{
|
{
|
||||||
CPClipView _contentView;
|
CPClipView _contentView;
|
||||||
CPClipView _headerClipView;
|
CPClipView _headerClipView;
|
||||||
CPView _cornerView;
|
CPView _cornerView;
|
||||||
CPView _bottomCornerView;
|
CPView _bottomCornerView;
|
||||||
|
|
||||||
id _delegate;
|
id <CPScrollViewDelegate> _delegate;
|
||||||
CPTimer _scrollTimer;
|
CPTimer _scrollTimer;
|
||||||
|
|
||||||
BOOL _hasVerticalScroller;
|
BOOL _hasVerticalScroller;
|
||||||
BOOL _hasHorizontalScroller;
|
BOOL _hasHorizontalScroller;
|
||||||
BOOL _autohidesScrollers;
|
BOOL _autohidesScrollers;
|
||||||
|
|
||||||
CPScroller _verticalScroller;
|
CPScroller _verticalScroller;
|
||||||
CPScroller _horizontalScroller;
|
CPScroller _horizontalScroller;
|
||||||
|
|
||||||
CPInteger _recursionCount;
|
CPInteger _recursionCount;
|
||||||
CPInteger _implementedDelegateMethods;
|
CPInteger _implementedDelegateMethods;
|
||||||
|
|
||||||
float _verticalLineScroll;
|
float _verticalLineScroll;
|
||||||
float _verticalPageScroll;
|
float _verticalPageScroll;
|
||||||
float _horizontalLineScroll;
|
float _horizontalLineScroll;
|
||||||
float _horizontalPageScroll;
|
float _horizontalPageScroll;
|
||||||
|
|
||||||
CPBorderType _borderType;
|
CPBorderType _borderType;
|
||||||
|
|
||||||
CPTimer _timerScrollersHide;
|
CPTimer _timerScrollersHide;
|
||||||
|
|
||||||
int _scrollerStyle;
|
int _scrollerStyle;
|
||||||
int _scrollerKnobStyle;
|
int _scrollerKnobStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -140,7 +149,7 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
|
|
||||||
var globalValue = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPScrollersGlobalStyle"];
|
var globalValue = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPScrollersGlobalStyle"];
|
||||||
|
|
||||||
if (globalValue === nil || globalValue === -1)
|
if (globalValue == nil || globalValue === -1)
|
||||||
CPScrollerStyleGlobal = _isBrowserUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
CPScrollerStyleGlobal = _isBrowserUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
||||||
else
|
else
|
||||||
CPScrollerStyleGlobal = globalValue;
|
CPScrollerStyleGlobal = globalValue;
|
||||||
@@ -159,33 +168,65 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Deprecated
|
||||||
|
*/
|
||||||
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||||
{
|
{
|
||||||
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
|
return [self contentSizeForFrameSize:frameSize
|
||||||
scrollerWidth = [CPScroller scrollerWidth];
|
horizontalScrollerClass:hFlag ? [CPScroller class] : nil
|
||||||
|
verticalScrollerClass:vFlag ? [CPScroller class] : nil
|
||||||
|
borderType:borderType
|
||||||
|
controlSize:CPRegularControlSize
|
||||||
|
scrollerStyle:CPScrollerStyleGlobal];
|
||||||
|
}
|
||||||
|
|
||||||
if (hFlag)
|
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize
|
||||||
bounds.size.height -= scrollerWidth;
|
horizontalScrollerClass:(Class)horizontalScrollerClass
|
||||||
|
verticalScrollerClass:(Class)verticalScrollerClass
|
||||||
|
borderType:(CPBorderType)borderType
|
||||||
|
controlSize:(CPControlSize)controlSize
|
||||||
|
scrollerStyle:(CPScrollerStyle)scrollerStyle
|
||||||
|
{
|
||||||
|
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType];
|
||||||
|
|
||||||
if (vFlag)
|
if (horizontalScrollerClass)
|
||||||
bounds.size.width -= scrollerWidth;
|
bounds.size.height -= [horizontalScrollerClass scrollerWidthInStyle:scrollerStyle];
|
||||||
|
|
||||||
|
if (verticalScrollerClass)
|
||||||
|
bounds.size.width -= [verticalScrollerClass scrollerWidthForControlSize:scrollerStyle];
|
||||||
|
|
||||||
return bounds.size;
|
return bounds.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Deprecated
|
||||||
|
*/
|
||||||
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||||
|
{
|
||||||
|
return [self frameSizeForContentSize:contentSize
|
||||||
|
horizontalScrollerClass:hFlag ? [CPScroller class] : nil
|
||||||
|
verticalScrollerClass:vFlag ? [CPScroller class] : nil
|
||||||
|
borderType:borderType
|
||||||
|
controlSize:CPRegularControlSize
|
||||||
|
scrollerStyle:CPScrollerStyleGlobal];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize
|
||||||
|
horizontalScrollerClass:(Class)horizontalScrollerClass
|
||||||
|
verticalScrollerClass:(Class)verticalScrollerClass
|
||||||
|
borderType:(CPBorderType)borderType
|
||||||
|
controlSize:(CPControlSize)controlSize
|
||||||
|
scrollerStyle:(CPScrollerStyle)scrollerStyle
|
||||||
{
|
{
|
||||||
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
||||||
widthInset = contentSize.width - bounds.size.width,
|
widthInset = contentSize.width - bounds.size.width,
|
||||||
heightInset = contentSize.height - bounds.size.height,
|
heightInset = contentSize.height - bounds.size.height,
|
||||||
frameSize = CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
|
frameSize = CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset);
|
||||||
scrollerWidth = [CPScroller scrollerWidth];
|
|
||||||
|
|
||||||
if (hFlag)
|
if (hFlag)
|
||||||
frameSize.height += scrollerWidth;
|
frameSize.height += [horizontalScrollerClass scrollerWidthInStyle:scrollerStyle];
|
||||||
|
|
||||||
if (vFlag)
|
if (vFlag)
|
||||||
frameSize.width += scrollerWidth;
|
frameSize.width += [verticalScrollerClass scrollerWidthForControlSize:scrollerStyle];
|
||||||
|
|
||||||
return frameSize;
|
return frameSize;
|
||||||
}
|
}
|
||||||
@@ -213,7 +254,7 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
/*!
|
/*!
|
||||||
Get the system wide scroller style.
|
Get the system wide scroller style.
|
||||||
*/
|
*/
|
||||||
+ (int)globalScrollerStyle
|
+ (CPScrollerStyle)globalScrollerStyle
|
||||||
{
|
{
|
||||||
return CPScrollerStyleGlobal;
|
return CPScrollerStyleGlobal;
|
||||||
}
|
}
|
||||||
@@ -223,7 +264,7 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
|
|
||||||
@param aStyle the scroller style to set all scroller views to use (CPScrollerStyleLegacy or CPScrollerStyleOverlay)
|
@param aStyle the scroller style to set all scroller views to use (CPScrollerStyleLegacy or CPScrollerStyleOverlay)
|
||||||
*/
|
*/
|
||||||
+ (void)setGlobalScrollerStyle:(int)aStyle
|
+ (void)setGlobalScrollerStyle:(CPScrollerStyle)aStyle
|
||||||
{
|
{
|
||||||
CPScrollerStyleGlobal = aStyle;
|
CPScrollerStyleGlobal = aStyle;
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPScrollerStyleGlobalChangeNotification object:nil];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPScrollerStyleGlobalChangeNotification object:nil];
|
||||||
@@ -264,11 +305,6 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
_delegate = nil;
|
_delegate = nil;
|
||||||
_scrollTimer = nil;
|
_scrollTimer = nil;
|
||||||
_implementedDelegateMethods = 0;
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(_didReceiveDefaultStyleChange:)
|
|
||||||
name:CPScrollerStyleGlobalChangeNotification
|
|
||||||
object:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -301,7 +337,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPScrollViewDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (aDelegate === _delegate)
|
if (aDelegate === _delegate)
|
||||||
return;
|
return;
|
||||||
@@ -309,7 +345,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
_implementedDelegateMethods = 0;
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
if (_delegate === nil)
|
if (_delegate == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
|
if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
|
||||||
@@ -319,7 +355,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
|
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)scrollerStyle
|
- (CPScrollerStyle)scrollerStyle
|
||||||
{
|
{
|
||||||
return _scrollerStyle;
|
return _scrollerStyle;
|
||||||
}
|
}
|
||||||
@@ -330,7 +366,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
- CPScrollerStyleLegacy: Standard scrollers like Windows or Mac OS X prior to 10.7
|
- CPScrollerStyleLegacy: Standard scrollers like Windows or Mac OS X prior to 10.7
|
||||||
- CPScrollerStyleOverlay: scrollers like those in Mac OS X 10.7+
|
- CPScrollerStyleOverlay: scrollers like those in Mac OS X 10.7+
|
||||||
*/
|
*/
|
||||||
- (void)setScrollerStyle:(int)aStyle
|
- (void)setScrollerStyle:(CPScrollerStyle)aStyle
|
||||||
{
|
{
|
||||||
if (_scrollerStyle === aStyle)
|
if (_scrollerStyle === aStyle)
|
||||||
return;
|
return;
|
||||||
@@ -527,8 +563,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
{
|
{
|
||||||
var bounds = [self _insetBounds];
|
var bounds = [self _insetBounds];
|
||||||
|
|
||||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1), [CPScroller scrollerWidthInStyle:_scrollerStyle])]];
|
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(CGRectGetWidth(bounds), [_horizontalScroller scrollerWidth] + 1), [_horizontalScroller scrollerWidth])]];
|
||||||
[[self horizontalScroller] setFrameSize:CGSizeMake(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle])];
|
[[self horizontalScroller] setFrameSize:CGSizeMake(CGRectGetWidth(bounds), [_horizontalScroller scrollerWidth])];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
@@ -592,8 +628,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
{
|
{
|
||||||
var bounds = [self _insetBounds];
|
var bounds = [self _insetBounds];
|
||||||
|
|
||||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, [CPScroller scrollerWidthInStyle:_scrollerStyle], MAX(CGRectGetHeight(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1))]];
|
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, [_verticalScroller scrollerWidth], MAX(CGRectGetHeight(bounds), [_verticalScroller scrollerWidth] + 1))]];
|
||||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidthInStyle:_scrollerStyle], CGRectGetHeight(bounds))];
|
[[self verticalScroller] setFrameSize:CGSizeMake([_verticalScroller scrollerWidth], CGRectGetHeight(bounds))];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
@@ -909,8 +945,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
|
|
||||||
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
|
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
|
||||||
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
|
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
|
||||||
bottomCornerFrame.size.width = [CPScroller scrollerWidthInStyle:_scrollerStyle];
|
bottomCornerFrame.size.width = [_verticalScroller scrollerWidth];
|
||||||
bottomCornerFrame.size.height = [CPScroller scrollerWidthInStyle:_scrollerStyle];
|
bottomCornerFrame.size.height = [_horizontalScroller scrollerWidth];
|
||||||
|
|
||||||
return bottomCornerFrame;
|
return bottomCornerFrame;
|
||||||
}
|
}
|
||||||
@@ -1122,8 +1158,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
contentFrame.size.height -= headerClipViewHeight;
|
contentFrame.size.height -= headerClipViewHeight;
|
||||||
|
|
||||||
var difference = CGSizeMake(CGRectGetWidth(documentFrame) - CGRectGetWidth(contentFrame), CGRectGetHeight(documentFrame) - CGRectGetHeight(contentFrame)),
|
var difference = CGSizeMake(CGRectGetWidth(documentFrame) - CGRectGetWidth(contentFrame), CGRectGetHeight(documentFrame) - CGRectGetHeight(contentFrame)),
|
||||||
verticalScrollerWidth = [CPScroller scrollerWidthInStyle:[_verticalScroller style]],
|
verticalScrollerWidth = [_verticalScroller scrollerWidth],
|
||||||
horizontalScrollerHeight = [CPScroller scrollerWidthInStyle:[_horizontalScroller style]],
|
horizontalScrollerHeight = [_horizontalScroller scrollerWidth],
|
||||||
hasVerticalScroll = difference.height > 0.0,
|
hasVerticalScroll = difference.height > 0.0,
|
||||||
hasHorizontalScroll = difference.width > 0.0,
|
hasHorizontalScroll = difference.width > 0.0,
|
||||||
shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
|
shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
|
||||||
@@ -1251,7 +1287,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_timerScrollersHide)
|
if (_timerScrollersHide)
|
||||||
[_timerScrollersHide invalidate]
|
[_timerScrollersHide invalidate];
|
||||||
|
|
||||||
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
||||||
}
|
}
|
||||||
@@ -1262,10 +1298,45 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGRect)documentVisibleRect
|
||||||
|
{
|
||||||
|
return [_contentView documentVisibleRect];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Overrides
|
#pragma mark Overrides
|
||||||
|
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
|
{
|
||||||
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self
|
||||||
|
name:CPScrollerStyleGlobalChangeNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_addObservers
|
||||||
|
{
|
||||||
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Make sure to have the last global style for the scroller
|
||||||
|
[self _didReceiveDefaultStyleChange:nil];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(_didReceiveDefaultStyleChange:)
|
||||||
|
name:CPScrollerStyleGlobalChangeNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
- (void)drawRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
[super drawRect:aRect];
|
[super drawRect:aRect];
|
||||||
@@ -1399,7 +1470,16 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
if (![_horizontalScroller isHidden] || ![_verticalScroller isHidden])
|
if (![_horizontalScroller isHidden] || ![_verticalScroller isHidden])
|
||||||
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
||||||
|
|
||||||
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
|
var deltaX = [anEvent scrollingDeltaX],
|
||||||
|
deltaY = [anEvent scrollingDeltaY];
|
||||||
|
|
||||||
|
if (![anEvent hasPreciseScrollingDeltas])
|
||||||
|
{
|
||||||
|
deltaX *= (_horizontalLineScroll || 1.0);
|
||||||
|
deltaY *= (_verticalLineScroll || 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _respondToScrollWheelEventWithDeltaX:deltaX deltaY:deltaY];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollPageUp:(id)sender
|
- (void)scrollPageUp:(id)sender
|
||||||
@@ -1464,6 +1544,51 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPScrollView (FirstResponder)
|
||||||
|
|
||||||
|
// Those 4 next methods are needed to (un)set CPThemeStateFirstResponder based on content view
|
||||||
|
|
||||||
|
- (void)viewWillMoveToWindow:(CPWindow)aWindow
|
||||||
|
{
|
||||||
|
[super viewWillMoveToWindow:aWindow];
|
||||||
|
|
||||||
|
[self _stopObservingFirstResponderForWindow:[self window]];
|
||||||
|
|
||||||
|
if (aWindow)
|
||||||
|
[self _startObservingFirstResponderForWindow:aWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_startObservingFirstResponderForWindow:(CPWindow)aWindow
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_firstResponderDidChange:) name:_CPWindowDidChangeFirstResponderNotification object:aWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_stopObservingFirstResponderForWindow:(CPWindow)aWindow
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:_CPWindowDidChangeFirstResponderNotification object:aWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_firstResponderDidChange:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
var responder = [[self window] firstResponder],
|
||||||
|
// FIXME: We add focus ring only on table views right now. When focus ring management will be added, this must be adapted.
|
||||||
|
shouldAddFocusRing = [responder isKindOfClass:[CPTableView class]],
|
||||||
|
found;
|
||||||
|
|
||||||
|
while (!(found = (responder === self)) && responder)
|
||||||
|
responder = [responder superview];
|
||||||
|
|
||||||
|
if (found && shouldAddFocusRing)
|
||||||
|
[self setThemeState:CPThemeStateFirstResponder];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||||
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
|
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
|
||||||
@@ -1536,6 +1661,8 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
|||||||
*/
|
*/
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
|
[super awakeFromCib];
|
||||||
|
|
||||||
[self _updateScrollerStyle];
|
[self _updateScrollerStyle];
|
||||||
[self _updateCornerAndHeaderView];
|
[self _updateCornerAndHeaderView];
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-52
@@ -33,6 +33,7 @@
|
|||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
// CPScroller Constants
|
// CPScroller Constants
|
||||||
|
@typedef CPScrollerPart
|
||||||
CPScrollerNoPart = 0;
|
CPScrollerNoPart = 0;
|
||||||
CPScrollerDecrementPage = 1;
|
CPScrollerDecrementPage = 1;
|
||||||
CPScrollerKnob = 2;
|
CPScrollerKnob = 2;
|
||||||
@@ -44,15 +45,11 @@ CPScrollerKnobSlot = 6;
|
|||||||
CPScrollerIncrementArrow = 0;
|
CPScrollerIncrementArrow = 0;
|
||||||
CPScrollerDecrementArrow = 1;
|
CPScrollerDecrementArrow = 1;
|
||||||
|
|
||||||
|
@typedef CPUsableScrollerParts
|
||||||
CPNoScrollerParts = 0;
|
CPNoScrollerParts = 0;
|
||||||
CPOnlyScrollerArrows = 1;
|
CPOnlyScrollerArrows = 1;
|
||||||
CPAllScrollerParts = 2;
|
CPAllScrollerParts = 2;
|
||||||
|
|
||||||
/*!
|
|
||||||
@ingroup appkit
|
|
||||||
@class CPScroller
|
|
||||||
*/
|
|
||||||
|
|
||||||
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
||||||
NAMES_FOR_PARTS = {},
|
NAMES_FOR_PARTS = {},
|
||||||
PARTS_FOR_NAMES = {};
|
PARTS_FOR_NAMES = {};
|
||||||
@@ -65,6 +62,7 @@ NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
|
|||||||
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||||
|
|
||||||
|
|
||||||
|
@typedef CPScrollerStyle
|
||||||
CPScrollerStyleLegacy = 0;
|
CPScrollerStyleLegacy = 0;
|
||||||
CPScrollerStyleOverlay = 1;
|
CPScrollerStyleOverlay = 1;
|
||||||
|
|
||||||
@@ -76,9 +74,13 @@ CPThemeStateScrollViewLegacy = CPThemeState("scroller-style-legacy");
|
|||||||
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
|
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
|
||||||
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPScroller
|
||||||
|
*/
|
||||||
|
|
||||||
@implementation CPScroller : CPControl
|
@implementation CPScroller : CPControl
|
||||||
{
|
{
|
||||||
CPControlSize _controlSize;
|
|
||||||
CPUsableScrollerParts _usableParts;
|
CPUsableScrollerParts _usableParts;
|
||||||
CPArray _partRects;
|
CPArray _partRects;
|
||||||
|
|
||||||
@@ -133,7 +135,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
/*!
|
/*!
|
||||||
Returns the CPScroller's width for a CPRegularControlSize.
|
Returns the CPScroller's width for a CPRegularControlSize.
|
||||||
*/
|
*/
|
||||||
+ (float)scrollerWidthInStyle:(int)aStyle
|
+ (float)scrollerWidthInStyle:(CPScrollerStyle)aStyle
|
||||||
{
|
{
|
||||||
if (!_CACHED_THEME_SCROLLER)
|
if (!_CACHED_THEME_SCROLLER)
|
||||||
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||||
@@ -172,7 +174,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
{
|
{
|
||||||
_controlSize = CPRegularControlSize;
|
|
||||||
_partRects = [];
|
_partRects = [];
|
||||||
|
|
||||||
[self setFloatValue:0.0];
|
[self setFloatValue:0.0];
|
||||||
@@ -208,7 +209,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
/*!
|
/*!
|
||||||
Returns the scroller's style
|
Returns the scroller's style
|
||||||
*/
|
*/
|
||||||
- (void)style
|
- (int)style
|
||||||
{
|
{
|
||||||
return _style;
|
return _style;
|
||||||
}
|
}
|
||||||
@@ -217,7 +218,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
Set the scroller's control size
|
Set the scroller's control size
|
||||||
@param aStyle the scroller style: CPScrollerStyleLegacy or CPScrollerStyleOverlay
|
@param aStyle the scroller style: CPScrollerStyleLegacy or CPScrollerStyleOverlay
|
||||||
*/
|
*/
|
||||||
- (void)setStyle:(id)aStyle
|
- (void)setStyle:(CPScrollerStyle)aStyle
|
||||||
{
|
{
|
||||||
if (_style != nil && _style === aStyle)
|
if (_style != nil && _style === aStyle)
|
||||||
return;
|
return;
|
||||||
@@ -226,6 +227,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
if (_style === CPScrollerStyleLegacy)
|
if (_style === CPScrollerStyleLegacy)
|
||||||
{
|
{
|
||||||
|
_allowFadingOut = NO;
|
||||||
[self fadeIn];
|
[self fadeIn];
|
||||||
[self setThemeState:CPThemeStateScrollViewLegacy];
|
[self setThemeState:CPThemeStateScrollViewLegacy];
|
||||||
}
|
}
|
||||||
@@ -243,29 +245,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the scroller's control size
|
|
||||||
*/
|
|
||||||
- (CPControlSize)controlSize
|
|
||||||
{
|
|
||||||
return _controlSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the scroller's size.
|
|
||||||
@param aControlSize the scroller's size
|
|
||||||
*/
|
|
||||||
- (void)setControlSize:(CPControlSize)aControlSize
|
|
||||||
{
|
|
||||||
if (_controlSize == aControlSize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_controlSize = aControlSize;
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Return's the knob's proportion
|
Return's the knob's proportion
|
||||||
*/
|
*/
|
||||||
@@ -281,7 +260,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
- (void)setKnobProportion:(float)aProportion
|
- (void)setKnobProportion:(float)aProportion
|
||||||
{
|
{
|
||||||
if (!_IS_NUMERIC(aProportion))
|
if (!_IS_NUMERIC(aProportion))
|
||||||
[CPException raise:CPInvalidArgumentException reason:"aProportion must be numeric"];
|
[CPException raise:CPInvalidArgumentException reason:"aProportion must be numeric, was: "+aProportion];
|
||||||
|
|
||||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||||
|
|
||||||
@@ -339,7 +318,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
// The ordering of these tests is important. We check the knob and
|
// The ordering of these tests is important. We check the knob and
|
||||||
// page rects first since they may overlap with the arrows.
|
// page rects first since they may overlap with the arrows.
|
||||||
|
|
||||||
if (![self hasThemeState:CPThemeStateSelected])
|
if (![self hasThemeState:CPThemeStateSelected] && ![self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||||
return CPScrollerNoPart;
|
return CPScrollerNoPart;
|
||||||
|
|
||||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||||
@@ -403,9 +382,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
|
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
|
||||||
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
|
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
|
||||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||||
|
knobVerticalInset = knobInset.top + knobInset.bottom,
|
||||||
knobWidth = width - knobInset.left - knobInset.right,
|
knobWidth = width - knobInset.left - knobInset.right,
|
||||||
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
knobHeight = MAX(minimumKnobLength, ((slotSize - knobVerticalInset) * _knobProportion)),
|
||||||
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
|
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight - knobVerticalInset) * [self floatValue] + knobInset.top;
|
||||||
|
|
||||||
_partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
|
_partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
|
||||||
_partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
|
_partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
|
||||||
@@ -432,9 +412,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
||||||
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||||
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
knobHorizontalInset = knobInset.left + knobInset.right,
|
||||||
|
knobWidth = MAX(minimumKnobLength, ((slotSize - knobHorizontalInset) * _knobProportion)),
|
||||||
knobHeight = height - knobInset.top - knobInset.bottom,
|
knobHeight = height - knobInset.top - knobInset.bottom,
|
||||||
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
|
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth - knobHorizontalInset) * [self floatValue] + knobInset.left;
|
||||||
|
|
||||||
_partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
|
_partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
|
||||||
_partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
|
_partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
|
||||||
@@ -483,9 +464,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
*/
|
*/
|
||||||
- (void)fadeOut
|
- (void)fadeOut
|
||||||
{
|
{
|
||||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
|
||||||
return;
|
|
||||||
|
|
||||||
[_animationScroller startAnimation];
|
[_animationScroller startAnimation];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,7 +711,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
var themeState = _themeState;
|
var themeState = _themeState;
|
||||||
|
|
||||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||||
themeState &= ~CPThemeStateHighlighted;
|
themeState = themeState.without(CPThemeStateHighlighted);
|
||||||
|
|
||||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||||
}
|
}
|
||||||
@@ -782,15 +760,25 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
if ([self isHidden] || ![self isEnabled] || !_isMouseOver)
|
if ([self isHidden] || ![self isEnabled] || !_isMouseOver)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_allowFadingOut = YES;
|
_allowFadingOut = (_style !== CPScrollerStyleLegacy);
|
||||||
_isMouseOver = NO;
|
_isMouseOver = NO;
|
||||||
|
|
||||||
if (_timerFadeOut)
|
if (_timerFadeOut)
|
||||||
[_timerFadeOut invalidate];
|
[_timerFadeOut invalidate];
|
||||||
|
|
||||||
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||||
|
[self unsetThemeState:CPThemeStateSelected];
|
||||||
|
else
|
||||||
|
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (float)scrollerWidth
|
||||||
|
{
|
||||||
|
if (_style == CPScrollerStyleLegacy)
|
||||||
|
return [self valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||||
|
|
||||||
|
return [self currentValueForThemeAttribute:@"scroller-width"];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Delegates
|
#pragma mark Delegates
|
||||||
@@ -802,8 +790,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
var CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||||
CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
|
||||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||||
|
|
||||||
@@ -813,10 +800,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
|||||||
{
|
{
|
||||||
if (self = [super initWithCoder:aCoder])
|
if (self = [super initWithCoder:aCoder])
|
||||||
{
|
{
|
||||||
_controlSize = CPRegularControlSize;
|
|
||||||
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
|
|
||||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
|
||||||
|
|
||||||
_knobProportion = 1.0;
|
_knobProportion = 1.0;
|
||||||
|
|
||||||
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
|
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
|
||||||
@@ -851,7 +834,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
|
||||||
[aCoder encodeInt:_isVertical forKey:CPScrollerIsVerticalKey];
|
[aCoder encodeInt:_isVertical forKey:CPScrollerIsVerticalKey];
|
||||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||||
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
|
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
|
||||||
|
|||||||
+392
-68
@@ -24,8 +24,12 @@
|
|||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
@import "CPAnimationContext.j"
|
||||||
|
@import "CPViewAnimator.j"
|
||||||
|
@import "CPArrayController.j"
|
||||||
|
|
||||||
@class CPUserDefaults
|
@class CPUserDefaults
|
||||||
|
@class CALayer
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
@@ -36,8 +40,6 @@ CPSearchFieldNoRecentsMenuItemTag = 1003;
|
|||||||
|
|
||||||
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
||||||
|
|
||||||
var RECENT_SEARCH_PREFIX = @" ";
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPSearchField
|
@class CPSearchField
|
||||||
@@ -60,6 +62,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
BOOL _sendsSearchStringImmediately;
|
BOOL _sendsSearchStringImmediately;
|
||||||
BOOL _canResignFirstResponder;
|
BOOL _canResignFirstResponder;
|
||||||
CPTimer _partialStringTimer;
|
CPTimer _partialStringTimer;
|
||||||
|
|
||||||
|
CPView _contentView;
|
||||||
|
BOOL _isBecomingFirstResponder;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
+ (CPString)defaultThemeClass
|
||||||
@@ -73,10 +78,24 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
@"image-search": [CPNull null],
|
@"image-search": [CPNull null],
|
||||||
@"image-find": [CPNull null],
|
@"image-find": [CPNull null],
|
||||||
@"image-cancel": [CPNull null],
|
@"image-cancel": [CPNull null],
|
||||||
@"image-cancel-pressed": [CPNull null]
|
@"image-cancel-pressed": [CPNull null],
|
||||||
|
@"image-search-inset" : CGInsetMake(0, 0, 0, 5),
|
||||||
|
@"image-cancel-inset" : CGInsetMake(0, 5, 0, 0),
|
||||||
|
@"search-button-rect-function": [CPNull null],
|
||||||
|
@"layout-function": [CPNull null],
|
||||||
|
@"search-right-margin": 2,
|
||||||
|
@"search-menu-offset": CGPointMake(10, -4)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPPredicateBinding)
|
||||||
|
return [_CPSearchFieldPredicateBinder class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame
|
- (id)initWithFrame:(CGRect)frame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:frame])
|
if (self = [super initWithFrame:frame])
|
||||||
@@ -87,10 +106,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
_recentsAutosaveName = nil;
|
_recentsAutosaveName = nil;
|
||||||
|
|
||||||
[self _init];
|
[self _init];
|
||||||
#if PLATFORM(DOM)
|
|
||||||
_cancelButton._DOMElement.style.cursor = "default";
|
|
||||||
_searchButton._DOMElement.style.cursor = "default";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -117,18 +132,31 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
[self resetSearchButton];
|
[self resetSearchButton];
|
||||||
|
|
||||||
_canResignFirstResponder = YES;
|
_canResignFirstResponder = YES;
|
||||||
|
_isBecomingFirstResponder = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillMoveToSuperview:(CPView)aView
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override observers
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
{
|
{
|
||||||
[super viewWillMoveToSuperview:aView];
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
|
||||||
// First we remove any observer that may have been in place to avoid memory leakage.
|
|
||||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
|
||||||
|
}
|
||||||
|
|
||||||
// Register the observe here if we need to.
|
- (void)_addObservers
|
||||||
if (aView)
|
{
|
||||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Buttons
|
// Managing Buttons
|
||||||
@@ -165,7 +193,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
- (void)resetSearchButton
|
- (void)resetSearchButton
|
||||||
{
|
{
|
||||||
var button = [self searchButton],
|
var button = [self searchButton],
|
||||||
searchButtonImage = (_searchMenuTemplate === nil) ? [self valueForThemeAttribute:@"image-search"] : [self valueForThemeAttribute:@"image-find"];
|
searchButtonImage = (_searchMenuTemplate == nil) ? [self currentValueForThemeAttribute:@"image-search"] : [self currentValueForThemeAttribute:@"image-find"];
|
||||||
|
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||||
@@ -212,8 +240,8 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
var button = [self cancelButton];
|
var button = [self cancelButton];
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||||
[button setImage:[self valueForThemeAttribute:@"image-cancel"]];
|
[button setImage:[self currentValueForThemeAttribute:@"image-cancel"]];
|
||||||
[button setAlternateImage:[self valueForThemeAttribute:@"image-cancel-pressed"]];
|
[button setAlternateImage:[self currentValueForThemeAttribute:@"image-cancel-pressed"]];
|
||||||
[button setAutoresizingMask:CPViewMinXMargin];
|
[button setAutoresizingMask:CPViewMinXMargin];
|
||||||
[button setTarget:self];
|
[button setTarget:self];
|
||||||
[button setAction:@selector(cancelOperation:)];
|
[button setAction:@selector(cancelOperation:)];
|
||||||
@@ -234,8 +262,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
|
|
||||||
if (_searchButton)
|
if (_searchButton)
|
||||||
{
|
{
|
||||||
var searchBounds = [self searchButtonRectForBounds:bounds];
|
var searchBounds = [self searchButtonRectForBounds:bounds],
|
||||||
leftOffset = CGRectGetMaxX(searchBounds) + 2;
|
rightMargin = [self _potentialCurrentValueForThemeAttribute:@"search-right-margin"];
|
||||||
|
leftOffset = CGRectGetMaxX(searchBounds) + rightMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cancelButton)
|
if (_cancelButton)
|
||||||
@@ -254,9 +283,18 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
*/
|
*/
|
||||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
var size = [[self valueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero();
|
var themedRectFunction = [self _potentialCurrentValueForThemeAttribute:@"search-button-rect-function"];
|
||||||
|
|
||||||
return CGRectMake(5, (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
if (themedRectFunction)
|
||||||
|
// There's a theme defined positioning function, just use it
|
||||||
|
return objj_eval("("+themedRectFunction+")")(self, rect);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var size = [[self _potentialCurrentValueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero(),
|
||||||
|
inset = [self _potentialCurrentValueForThemeAttribute:@"image-search-inset"];
|
||||||
|
|
||||||
|
return CGRectMake(inset.left - inset.right, inset.top - inset.bottom + (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -266,9 +304,10 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
*/
|
*/
|
||||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
var size = [[self valueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero();
|
var size = [[self _potentialCurrentValueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero(),
|
||||||
|
inset = [self _potentialCurrentValueForThemeAttribute:@"image-cancel-inset"];
|
||||||
|
|
||||||
return CGRectMake(CGRectGetWidth(rect) - size.width - 5, (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
return CGRectMake(CGRectGetWidth(rect) - size.width + inset.left - inset.right, inset.top - inset.bottom + (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Menu Templates
|
// Managing Menu Templates
|
||||||
@@ -372,10 +411,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
*/
|
*/
|
||||||
- (void)setRecentSearches:(CPArray)searches
|
- (void)setRecentSearches:(CPArray)searches
|
||||||
{
|
{
|
||||||
var max = MIN([self maximumRecents], [searches count]),
|
var max = MIN([self maximumRecents], [searches count]);
|
||||||
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
|
||||||
|
|
||||||
_recentSearches = searches;
|
_recentSearches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
||||||
[self _autosaveRecentSearchList];
|
[self _autosaveRecentSearchList];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,6 +498,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
|
|
||||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||||
{
|
{
|
||||||
|
[self selectAll:nil];
|
||||||
[super sendAction:anAction to:anObject];
|
[super sendAction:anAction to:anObject];
|
||||||
|
|
||||||
[_partialStringTimer invalidate];
|
[_partialStringTimer invalidate];
|
||||||
@@ -470,7 +509,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
|
|
||||||
- (void)_addStringToRecentSearches:(CPString)string
|
- (void)_addStringToRecentSearches:(CPString)string
|
||||||
{
|
{
|
||||||
if (string === nil || string === @"" || [_recentSearches containsObject:string])
|
if (string == nil || string === @"" || [_recentSearches containsObject:string])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var searches = [CPMutableArray arrayWithArray:_recentSearches];
|
var searches = [CPMutableArray arrayWithArray:_recentSearches];
|
||||||
@@ -517,19 +556,16 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Provides the common case items for a recent searches menu. If there are not recent searches,
|
Provides the common case items for a recent searches menu.
|
||||||
displays a single disabled item:
|
|
||||||
|
|
||||||
No Recent Searches
|
|
||||||
|
|
||||||
If there are 1 more recent searches, it displays:
|
If there are 1 more recent searches, it displays:
|
||||||
|
|
||||||
Recent Searches
|
Clear
|
||||||
recent search 1
|
|
||||||
recent search 2
|
|
||||||
etc.
|
|
||||||
---------------------
|
---------------------
|
||||||
Clear Recent Searches
|
Recent Searches
|
||||||
|
recent search 1
|
||||||
|
recent search 2
|
||||||
|
etc.
|
||||||
|
|
||||||
If you wish to add items before or after the template, you can. If you put items
|
If you wish to add items before or after the template, you can. If you put items
|
||||||
before, a separator will automatically be placed before the default template item.
|
before, a separator will automatically be placed before the default template item.
|
||||||
@@ -554,6 +590,15 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
var template = [[CPMenu alloc] init],
|
var template = [[CPMenu alloc] init],
|
||||||
item;
|
item;
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"Clear"
|
||||||
|
action:@selector(_searchFieldClearRecents:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||||
|
[item setTarget:self];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
[self _addSeparatorToMenu:template];
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
||||||
action:nil
|
action:nil
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
@@ -568,32 +613,20 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[template addItem:item];
|
[template addItem:item];
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
|
|
||||||
action:@selector(_searchFieldClearRecents:)
|
|
||||||
keyEquivalent:@""];
|
|
||||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
|
||||||
[item setTarget:self];
|
|
||||||
[template addItem:item];
|
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
|
|
||||||
action:nil
|
|
||||||
keyEquivalent:@""];
|
|
||||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
|
||||||
[item setEnabled:NO];
|
|
||||||
[template addItem:item];
|
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateSearchMenu
|
- (void)_updateSearchMenu
|
||||||
{
|
{
|
||||||
if (_searchMenuTemplate === nil)
|
if (_searchMenuTemplate == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var menu = [[CPMenu alloc] init],
|
var menu = [[CPMenu alloc] init],
|
||||||
countOfRecents = [_recentSearches count],
|
countOfRecents = [_recentSearches count],
|
||||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||||
|
|
||||||
|
[menu setAutoenablesItems:NO];
|
||||||
|
|
||||||
for (var i = 0; i < numberOfItems; i++)
|
for (var i = 0; i < numberOfItems; i++)
|
||||||
{
|
{
|
||||||
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
||||||
@@ -603,9 +636,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
case CPSearchFieldRecentsTitleMenuItemTag:
|
case CPSearchFieldRecentsTitleMenuItemTag:
|
||||||
if (countOfRecents === 0)
|
if (countOfRecents === 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ([menu numberOfItems] > 0)
|
|
||||||
[self _addSeparatorToMenu:menu];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPSearchFieldRecentsMenuItemTag:
|
case CPSearchFieldRecentsMenuItemTag:
|
||||||
@@ -614,8 +644,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
|
|
||||||
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
||||||
{
|
{
|
||||||
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
|
var recentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:recentIndex]
|
||||||
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
|
|
||||||
action:itemAction
|
action:itemAction
|
||||||
keyEquivalent:[item keyEquivalent]];
|
keyEquivalent:[item keyEquivalent]];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
@@ -629,9 +658,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
if (countOfRecents === 0)
|
if (countOfRecents === 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ([menu numberOfItems] > 0)
|
|
||||||
[self _addSeparatorToMenu:menu];
|
|
||||||
|
|
||||||
[item setAction:@selector(_searchFieldClearRecents:)];
|
[item setAction:@selector(_searchFieldClearRecents:)];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
break;
|
break;
|
||||||
@@ -639,9 +665,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
case CPSearchFieldNoRecentsMenuItemTag:
|
case CPSearchFieldNoRecentsMenuItemTag:
|
||||||
if (countOfRecents !== 0)
|
if (countOfRecents !== 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ([menu numberOfItems] > 0)
|
|
||||||
[self _addSeparatorToMenu:menu];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,6 +681,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
{
|
{
|
||||||
var separator = [CPMenuItem separatorItem];
|
var separator = [CPMenuItem separatorItem];
|
||||||
[separator setEnabled:NO];
|
[separator setEnabled:NO];
|
||||||
|
[separator setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||||
[aMenu addItem:separator];
|
[aMenu addItem:separator];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +703,8 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
||||||
location = CGPointMake(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
|
offset = [self currentValueForThemeAttribute:@"search-menu-offset"],
|
||||||
|
location = CGPointMake(aFrame.origin.x + offset.x, aFrame.origin.y + aFrame.size.height + offset.y);
|
||||||
|
|
||||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||||
|
|
||||||
@@ -695,15 +720,19 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
|
|
||||||
- (void)cancelOperation:(id)sender
|
- (void)cancelOperation:(id)sender
|
||||||
{
|
{
|
||||||
[self setObjectValue:@""];
|
// If something was entered, the search field must deactivate itself (else, do nothing)
|
||||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
if ([[self stringValue] length] > 0)
|
||||||
|
{
|
||||||
|
[self setObjectValue:@""];
|
||||||
|
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
[self _updateCancelButtonVisibility];
|
[[self window] makeFirstResponder:[self window]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_searchFieldSearch:(id)sender
|
- (void)_searchFieldSearch:(id)sender
|
||||||
{
|
{
|
||||||
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
|
var searchString = [sender title];
|
||||||
|
|
||||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||||
[self _addStringToRecentSearches:searchString];
|
[self _addStringToRecentSearches:searchString];
|
||||||
@@ -748,17 +777,266 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
- (void)_loadRecentSearchList
|
- (void)_loadRecentSearchList
|
||||||
{
|
{
|
||||||
var name = [self recentsAutosaveName];
|
var name = [self recentsAutosaveName];
|
||||||
if (name === nil)
|
if (name == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
|
var list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
|
||||||
|
|
||||||
if (list !== nil)
|
if (list != nil)
|
||||||
_recentSearches = list;
|
_recentSearches = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPSearchField (ThemingAdditions)
|
||||||
|
|
||||||
|
// Overwrite CPTextField method to permit themed layout functions
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if (!_contentView)
|
||||||
|
{
|
||||||
|
// Search for the CPImageAndTextView subview of mine
|
||||||
|
|
||||||
|
for (var i = 0, subviews = [self subviews], nb = [subviews count]; (!_contentView && (i < nb)); i++)
|
||||||
|
if ([subviews[i] isKindOfClass:_CPImageAndTextView])
|
||||||
|
_contentView = subviews[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
var bezelColor = [self currentValueForThemeAttribute:@"bezel-color"];
|
||||||
|
|
||||||
|
if ([bezelColor isCSSBased])
|
||||||
|
{
|
||||||
|
// CSS Styling
|
||||||
|
// We don't need bezelView as we apply CSS styling directly on the search view itself
|
||||||
|
|
||||||
|
[self _setBackgroundColor:bezelColor];
|
||||||
|
|
||||||
|
if (!_contentView)
|
||||||
|
_contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||||
|
positioned:CPWindowAbove
|
||||||
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||||
|
positioned:CPWindowBelow
|
||||||
|
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||||
|
|
||||||
|
[bezelView setBackgroundColor:bezelColor];
|
||||||
|
|
||||||
|
if (!_contentView)
|
||||||
|
_contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||||
|
positioned:CPWindowAbove
|
||||||
|
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_contentView)
|
||||||
|
{
|
||||||
|
[_contentView setHidden:(_stringValue && _stringValue.length > 0) && [self hasThemeState:CPThemeStateEditing]];
|
||||||
|
|
||||||
|
[_contentView setText:[self hasThemeState:CPTextFieldStatePlaceholder] ? [self placeholderString] : _stringValue];
|
||||||
|
[_contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||||
|
[_contentView setFont:[self font]]; //[self currentValueForThemeAttribute:@"font"]];
|
||||||
|
[_contentView setAlignment:[self currentValueForThemeAttribute:@"alignment"]];
|
||||||
|
[_contentView setVerticalAlignment:[self currentValueForThemeAttribute:@"vertical-alignment"]];
|
||||||
|
[_contentView setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
|
||||||
|
[_contentView setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||||
|
[_contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isEditing)
|
||||||
|
[self _setCSSStyleForInputElement];
|
||||||
|
|
||||||
|
[self updateSearchButton];
|
||||||
|
[self updateTrackingAreas];
|
||||||
|
}
|
||||||
|
|
||||||
|
// As CPTextField redefines setBackgroundColor, we have to bypass it
|
||||||
|
- (void)_setBackgroundColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
var grannyMethod = class_getInstanceMethod([[self superclass] superclass], @selector(setBackgroundColor:)),
|
||||||
|
grannyImplementation = method_getImplementation(grannyMethod);
|
||||||
|
|
||||||
|
grannyImplementation(self, @selector(setBackgroundColor:), aColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_layoutSubviews
|
||||||
|
{
|
||||||
|
var themedLayoutFunction = [self currentValueForThemeAttribute:@"layout-function"];
|
||||||
|
|
||||||
|
if (themedLayoutFunction)
|
||||||
|
// There's a theme defined layout function, just use it
|
||||||
|
objj_eval("("+themedLayoutFunction+")")(self);
|
||||||
|
else
|
||||||
|
// Call directly the completion handler
|
||||||
|
[self themedLayoutFunctionCompletionHandler];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateSearchButton
|
||||||
|
{
|
||||||
|
[_searchButton setImage:(_searchMenuTemplate ? [self currentValueForThemeAttribute:@"image-find"] : [self currentValueForThemeAttribute:@"image-search"])];
|
||||||
|
[self updateTrackingAreas];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)themedLayoutFunctionCompletionHandler
|
||||||
|
{
|
||||||
|
if (_isBecomingFirstResponder)
|
||||||
|
{
|
||||||
|
_isBecomingFirstResponder = NO;
|
||||||
|
|
||||||
|
// Call the real _becomeFirstKeyResponder to finish setting the input element
|
||||||
|
[super _becomeFirstKeyResponder];
|
||||||
|
|
||||||
|
// For some (unknown yet) reason, input field doesn't focus and text field visual state is not updated
|
||||||
|
var element = [self _inputElement];
|
||||||
|
element.focus();
|
||||||
|
[self layoutSubviews];
|
||||||
|
[CALayer runLoopUpdateLayers]; // Thank you @daboe01 for suggesting adding this
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self layoutSubviews];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We override CPTextField method in order to delay the display of the input element until the end of the animation
|
||||||
|
- (BOOL)_becomeFirstKeyResponder
|
||||||
|
{
|
||||||
|
// As we have to return a result, we check if response could be NO
|
||||||
|
|
||||||
|
if (![self _isWithinUsablePlatformRect] || ![self isEditable])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
// We are now sure that response will be YES
|
||||||
|
_isBecomingFirstResponder = YES;
|
||||||
|
|
||||||
|
// We have to do this now in order to avoid running conditions messing things among multiple textfields
|
||||||
|
_stringValue = [self stringValue];
|
||||||
|
var element = [self _inputElement];
|
||||||
|
element.value = _stringValue;
|
||||||
|
|
||||||
|
[self _layoutSubviews];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)textDidEndEditing:(CPNotification)note
|
||||||
|
{
|
||||||
|
if ([note object] != self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _layoutSubviews];
|
||||||
|
[super textDidEndEditing:note];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_windowDidResignKey:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
// When the window resigns key, if the search field is empty, it must cancel first responder
|
||||||
|
if ([[self stringValue] length] == 0)
|
||||||
|
[[self window] makeFirstResponder:[self window]];
|
||||||
|
|
||||||
|
[super _windowDidResignKey:aNotification];
|
||||||
|
[self _layoutSubviews];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlaceholderString:(CPString)aStringValue
|
||||||
|
{
|
||||||
|
[super setPlaceholderString:aStringValue];
|
||||||
|
[self _layoutContent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_layoutContent
|
||||||
|
{
|
||||||
|
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
|
||||||
|
[_contentView setFrame:[self contentRectForBounds:[self bounds]]];
|
||||||
|
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
|
||||||
|
[self updateTrackingAreas];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
[super setFrameSize:aSize];
|
||||||
|
[self _layoutContent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_potentialCurrentValueForThemeAttribute:(CPString)aName
|
||||||
|
{
|
||||||
|
if (_isBecomingFirstResponder)
|
||||||
|
return [self valueForThemeAttribute:aName inState:[self themeState].and(CPThemeStateEditing)];
|
||||||
|
else
|
||||||
|
return [self currentValueForThemeAttribute:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unbind:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[super unbind:aBinding];
|
||||||
|
|
||||||
|
// our CPPredicateBinding binder adds a binding to the value.
|
||||||
|
// this private binding has to be also removed
|
||||||
|
if (aBinding === CPPredicateBinding)
|
||||||
|
[[[self class] _binderClassForBinding:aBinding] unbind:CPValueBinding forObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPSearchField (CPTrackingArea)
|
||||||
|
{
|
||||||
|
CPTrackingArea _searchButtonTrackingArea;
|
||||||
|
CPTrackingArea _cancelButtonTrackingArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateTrackingAreas
|
||||||
|
{
|
||||||
|
if (_searchButtonTrackingArea)
|
||||||
|
{
|
||||||
|
[self removeTrackingArea:_searchButtonTrackingArea];
|
||||||
|
_searchButtonTrackingArea = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cancelButtonTrackingArea)
|
||||||
|
{
|
||||||
|
[self removeTrackingArea:_cancelButtonTrackingArea];
|
||||||
|
_cancelButtonTrackingArea = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_searchButton)
|
||||||
|
{
|
||||||
|
_searchButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_searchButton frame]
|
||||||
|
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
|
||||||
|
owner:self
|
||||||
|
userInfo:@{ @"isButton": YES }];
|
||||||
|
|
||||||
|
[self addTrackingArea:_searchButtonTrackingArea];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cancelButton && ![_cancelButton isHidden])
|
||||||
|
{
|
||||||
|
_cancelButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_cancelButton frame]
|
||||||
|
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
|
||||||
|
owner:self
|
||||||
|
userInfo:@{ @"isButton": YES }];
|
||||||
|
|
||||||
|
[self addTrackingArea:_cancelButtonTrackingArea];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super updateTrackingAreas];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cursorUpdate:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if ([[[anEvent trackingArea] userInfo] objectForKey:@"isButton"])
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
else
|
||||||
|
[super cursorUpdate:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||||
@@ -811,3 +1089,49 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation _CPSearchFieldPredicateBinder : CPBinder
|
||||||
|
{
|
||||||
|
CPArrayController _controller;
|
||||||
|
CPString _predicateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPPredicateBinding)
|
||||||
|
{
|
||||||
|
var options = [_info objectForKey:CPOptionsKey];
|
||||||
|
|
||||||
|
_controller = [_info objectForKey:CPObservedObjectKey];
|
||||||
|
_predicateFormat = [options objectForKey:"CPPredicateFormat"];
|
||||||
|
[_source bind:CPValueBinding toObject:self withKeyPath:"searchFieldValue" options:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSearchFieldValue:(CPString)aValue
|
||||||
|
{
|
||||||
|
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [_info objectForKey:CPObservedKeyPathKey];
|
||||||
|
|
||||||
|
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||||
|
|
||||||
|
if (aValue)
|
||||||
|
{
|
||||||
|
var values = @[],
|
||||||
|
formatString = _predicateFormat.replace(/\$value/g, function(x) {[values addObject:aValue]; return "%@";});
|
||||||
|
|
||||||
|
[_controller setFilterPredicate:[CPPredicate predicateWithFormat:formatString argumentArray:values]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_controller setFilterPredicate:nil];
|
||||||
|
|
||||||
|
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)searchFieldValue
|
||||||
|
{
|
||||||
|
return [_source stringValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|||||||
+361
-251
@@ -25,9 +25,11 @@
|
|||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@import "CPWindow_Constants.j"
|
@import "CPWindow_Constants.j"
|
||||||
@import "_CPImageAndTextView.j"
|
@import "_CPImageAndTextView.j"
|
||||||
|
@import "CPMenu.j"
|
||||||
|
|
||||||
@global CPApp
|
@global CPApp
|
||||||
|
|
||||||
|
@typedef CPSegmentSwitchTracking
|
||||||
CPSegmentSwitchTrackingSelectOne = 0;
|
CPSegmentSwitchTrackingSelectOne = 0;
|
||||||
CPSegmentSwitchTrackingSelectAny = 1;
|
CPSegmentSwitchTrackingSelectAny = 1;
|
||||||
CPSegmentSwitchTrackingMomentary = 2;
|
CPSegmentSwitchTrackingMomentary = 2;
|
||||||
@@ -40,7 +42,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
@implementation CPSegmentedControl : CPControl
|
@implementation CPSegmentedControl : CPControl
|
||||||
{
|
{
|
||||||
CPArray _segments;
|
CPArray _segments @accessors(getter=segments);
|
||||||
CPArray _themeStates;
|
CPArray _themeStates;
|
||||||
|
|
||||||
int _selectedSegment;
|
int _selectedSegment;
|
||||||
@@ -70,23 +72,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
@"center-segment-bezel-color": [CPNull null],
|
@"center-segment-bezel-color": [CPNull null],
|
||||||
@"divider-bezel-color": [CPNull null],
|
@"divider-bezel-color": [CPNull null],
|
||||||
@"divider-thickness": 1.0,
|
@"divider-thickness": 1.0,
|
||||||
@"default-height": 24.0,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
|
||||||
{
|
|
||||||
if ([self _isSelectionBinding:aBinding])
|
|
||||||
return [_CPSegmentedControlBinder class];
|
|
||||||
|
|
||||||
return [super _binderClassForBinding:aBinding];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)_isSelectionBinding:(CPString)aBinding
|
|
||||||
{
|
|
||||||
return (aBinding === CPSelectedIndexBinding || aBinding === CPSelectedLabelBinding || aBinding === CPSelectedTagBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aRect
|
- (id)initWithFrame:(CGRect)aRect
|
||||||
{
|
{
|
||||||
_segments = [];
|
_segments = [];
|
||||||
@@ -99,22 +87,21 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
_selectedSegment = -1;
|
_selectedSegment = -1;
|
||||||
|
|
||||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||||
|
_trackingHighlighted = NO;
|
||||||
|
_trackingSegment = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
/*!
|
||||||
|
Sets the control's size.
|
||||||
|
@param aControlSize the control's size
|
||||||
|
*/
|
||||||
|
- (void)setControlSize:(CPControlSize)aControlSize
|
||||||
{
|
{
|
||||||
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
|
[super setControlSize:aControlSize];
|
||||||
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
|
[self _sizeToControlSize];
|
||||||
else
|
|
||||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_reverseSetBinding
|
|
||||||
{
|
|
||||||
[_CPSegmentedControlBinder reverseSetValueForObject:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -122,7 +109,54 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (int)selectedTag
|
- (int)selectedTag
|
||||||
{
|
{
|
||||||
return [_segments[_selectedSegment] tag];
|
return [[_segments objectAtIndex:_selectedSegment] tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)setSegments:(CPArray)segments
|
||||||
|
{
|
||||||
|
[self removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self segmentCount])]];
|
||||||
|
|
||||||
|
[self insertSegments:segments atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [segments count])]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)insertSegments:(CPArray)segments atIndexes:(CPIndexSet)indices
|
||||||
|
{
|
||||||
|
if ([segments count] == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newStates = @[],
|
||||||
|
count = [indices count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[newStates addObject:CPThemeStateNormal];
|
||||||
|
|
||||||
|
[_segments insertObjects:segments atIndexes:indices];
|
||||||
|
[_themeStates insertObjects:newStates atIndexes:indices];
|
||||||
|
|
||||||
|
if (_selectedSegment >= [indices firstIndex])
|
||||||
|
_selectedSegment += [indices count];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)removeSegmentsAtIndexes:(CPIndexSet)indices
|
||||||
|
{
|
||||||
|
if ([indices count] == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[indices enumerateIndexesUsingBlock:function(idx, stop)
|
||||||
|
{
|
||||||
|
[[_segments objectAtIndex:idx] setSelected:NO];
|
||||||
|
}];
|
||||||
|
|
||||||
|
if ([indices containsIndex:_selectedSegment])
|
||||||
|
_selectedSegment = -1;
|
||||||
|
else if ([indices lastIndex] < _selectedSegment)
|
||||||
|
_selectedSegment -= [indices count];
|
||||||
|
|
||||||
|
[_segments removeObjectsAtIndexes:indices];
|
||||||
|
[_themeStates removeObjectsAtIndexes:indices];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specifying the number of segments
|
// Specifying the number of segments
|
||||||
@@ -132,41 +166,32 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setSegmentCount:(unsigned)aCount
|
- (void)setSegmentCount:(unsigned)aCount
|
||||||
{
|
{
|
||||||
if (_segments.length == aCount)
|
var prevCount = [_segments count];
|
||||||
|
|
||||||
|
if (aCount == prevCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var height = CGRectGetHeight([self bounds]),
|
if (aCount > prevCount)
|
||||||
dividersBefore = MAX(0, _segments.length - 1),
|
|
||||||
dividersAfter = MAX(0, aCount - 1);
|
|
||||||
|
|
||||||
if (_segments.length < aCount)
|
|
||||||
{
|
{
|
||||||
for (var index = _segments.length; index < aCount; ++index)
|
var count = aCount - prevCount,
|
||||||
{
|
segments = @[];
|
||||||
_segments[index] = [[_CPSegmentItem alloc] init];
|
|
||||||
_themeStates[index] = CPThemeStateNormal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (aCount < _segments.length)
|
|
||||||
{
|
|
||||||
_segments.length = aCount;
|
|
||||||
_themeStates.length = aCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_selectedSegment >= _segments.length)
|
while (count--)
|
||||||
|
[segments addObject:[[_CPSegmentItem alloc] init]];
|
||||||
|
|
||||||
|
[self insertSegments:segments atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(prevCount, aCount - prevCount)]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(aCount, prevCount - aCount)]];
|
||||||
|
|
||||||
|
[self _updateSelectionIfNeeded];
|
||||||
|
[self tileWithChangedSegment:MAX(MIN(prevCount, aCount) - 1, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateSelectionIfNeeded
|
||||||
|
{
|
||||||
|
if (_selectedSegment >= [self segmentCount])
|
||||||
_selectedSegment = -1;
|
_selectedSegment = -1;
|
||||||
|
|
||||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
|
|
||||||
frame = [self frame],
|
|
||||||
widthOfAllSegments = 0,
|
|
||||||
dividerExtraSpace = ([_segments count] - 1) * thickness;
|
|
||||||
|
|
||||||
for (var i = 0; i < [_segments count]; i++)
|
|
||||||
widthOfAllSegments += [_segments[i] width];
|
|
||||||
|
|
||||||
[self setFrameSize:CGSizeMake(widthOfAllSegments + dividerExtraSpace, frame.size.height)];
|
|
||||||
|
|
||||||
[self tileWithChangedSegment:0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -174,7 +199,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (unsigned)segmentCount
|
- (unsigned)segmentCount
|
||||||
{
|
{
|
||||||
return _segments.length;
|
return [_segments count];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specifying Selected Segment
|
// Specifying Selected Segment
|
||||||
@@ -186,7 +211,20 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
- (void)setSelectedSegment:(unsigned)aSegment
|
- (void)setSelectedSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
// setSelected:forSegment throws the exception for us (if necessary)
|
// setSelected:forSegment throws the exception for us (if necessary)
|
||||||
[self setSelected:YES forSegment:aSegment];
|
if (_selectedSegment == aSegment)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (aSegment == -1)
|
||||||
|
{
|
||||||
|
var count = [self segmentCount];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[self setSelected:NO forSegment:count];
|
||||||
|
|
||||||
|
_selectedSegment = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self setSelected:YES forSegment:aSegment];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -204,8 +242,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < [_segments count]; ++index)
|
||||||
if (_segments[index].tag == aTag)
|
if ([[_segments objectAtIndex:index] tag] == aTag)
|
||||||
{
|
{
|
||||||
[self setSelectedSegment:index];
|
[self setSelectedSegment:index];
|
||||||
|
|
||||||
@@ -219,8 +257,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < [_segments count]; ++index)
|
||||||
if (_segments[index].label == aLabel)
|
if ([[_segments objectAtIndex:index] label] == aLabel)
|
||||||
{
|
{
|
||||||
[self setSelectedSegment:index];
|
[self setSelectedSegment:index];
|
||||||
|
|
||||||
@@ -231,7 +269,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Specifying Tracking Mode
|
// Specifying Tracking Mode
|
||||||
|
/*! @ignore */
|
||||||
- (BOOL)isTracking
|
- (BOOL)isTracking
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -249,7 +287,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
var index = 0,
|
var index = 0,
|
||||||
selected = NO;
|
selected = NO;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < [self segmentCount]; ++index)
|
||||||
if ([_segments[index] selected])
|
if ([_segments[index] selected])
|
||||||
if (selected)
|
if (selected)
|
||||||
[self setSelected:NO forSegment:index];
|
[self setSelected:NO forSegment:index];
|
||||||
@@ -261,7 +299,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < [self segmentCount]; ++index)
|
||||||
if ([_segments[index] selected])
|
if ([_segments[index] selected])
|
||||||
[self setSelected:NO forSegment:index];
|
[self setSelected:NO forSegment:index];
|
||||||
}
|
}
|
||||||
@@ -284,8 +322,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
[_segments[aSegment] setWidth:aWidth];
|
[[_segments objectAtIndex:aSegment] setWidth:aWidth];
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +333,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (float)widthForSegment:(unsigned)aSegment
|
- (float)widthForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] width];
|
return [[_segments objectAtIndex:aSegment] width];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -307,7 +344,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
[_segments[aSegment] setImage:anImage];
|
[[_segments objectAtIndex:aSegment] setImage:anImage];
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
@@ -319,7 +356,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] image];
|
return [[_segments objectAtIndex:aSegment] image];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -330,7 +367,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
[_segments[aSegment] setLabel:aLabel];
|
[[_segments objectAtIndex:aSegment] setLabel:aLabel];
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
@@ -342,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPString)labelForSegment:(unsigned)aSegment
|
- (CPString)labelForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] label];
|
return [[_segments objectAtIndex:aSegment] label];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -353,7 +390,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
[_segments[aSegment] setMenu:aMenu];
|
[[_segments objectAtIndex:aSegment] setMenu:aMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -363,7 +400,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] menu];
|
return [[_segments objectAtIndex:aSegment] menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -375,7 +412,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
var segment = _segments[aSegment];
|
var segment = [_segments objectAtIndex:aSegment];
|
||||||
|
|
||||||
// If we're already in this state, bail.
|
// If we're already in this state, bail.
|
||||||
if ([segment selected] == isSelected)
|
if ([segment selected] == isSelected)
|
||||||
@@ -392,7 +429,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
_selectedSegment = aSegment;
|
_selectedSegment = aSegment;
|
||||||
|
|
||||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1 && oldSelectedSegment < _segments.length)
|
||||||
{
|
{
|
||||||
[_segments[oldSelectedSegment] setSelected:NO];
|
[_segments[oldSelectedSegment] setSelected:NO];
|
||||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||||
@@ -415,7 +452,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] selected];
|
return [[_segments objectAtIndex:aSegment] selected];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -426,15 +463,17 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setEnabled:(BOOL)shouldBeEnabled forSegment:(unsigned)aSegment
|
- (void)setEnabled:(BOOL)shouldBeEnabled forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
if ([_segments[aSegment] enabled] === shouldBeEnabled)
|
var segment = [_segments objectAtIndex:aSegment];
|
||||||
|
|
||||||
|
if ([segment enabled] === shouldBeEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_segments[aSegment] setEnabled:shouldBeEnabled];
|
[segment setEnabled:shouldBeEnabled];
|
||||||
|
|
||||||
if (shouldBeEnabled)
|
if (shouldBeEnabled)
|
||||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
_themeStates[aSegment] = _themeStates[aSegment].without(CPThemeStateDisabled);
|
||||||
else
|
else
|
||||||
_themeStates[aSegment] |= CPThemeStateDisabled;
|
_themeStates[aSegment] = _themeStates[aSegment].and(CPThemeStateDisabled);
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -447,7 +486,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] enabled];
|
return [[_segments objectAtIndex:aSegment] enabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -457,7 +496,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
[_segments[aSegment] setTag:aTag];
|
[[_segments objectAtIndex:aSegment] setTag:aTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -466,7 +505,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (int)tagForSegment:(unsigned)aSegment
|
- (int)tagForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [_segments[aSegment] tag];
|
return [[_segments objectAtIndex:aSegment] tag];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drawings
|
// Drawings
|
||||||
@@ -477,10 +516,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||||
{
|
{
|
||||||
if (shouldHighlight)
|
if (aSegment < _themeStates.length)
|
||||||
_themeStates[aSegment] |= CPThemeStateHighlighted;
|
{
|
||||||
else
|
if (shouldHighlight)
|
||||||
_themeStates[aSegment] &= ~CPThemeStateHighlighted;
|
_themeStates[aSegment] = _themeStates[aSegment].and(CPThemeStateHighlighted);
|
||||||
|
else
|
||||||
|
_themeStates[aSegment] = _themeStates[aSegment].without(CPThemeStateHighlighted);
|
||||||
|
}
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -488,14 +530,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
- (float)_leftOffsetForSegment:(unsigned)segment
|
- (float)_leftOffsetForSegment:(unsigned)segment
|
||||||
{
|
{
|
||||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
|
||||||
|
|
||||||
if (segment == 0)
|
if (segment == 0)
|
||||||
return bezelInset.left;
|
return [self currentValueForThemeAttribute:@"bezel-inset"].left;
|
||||||
|
|
||||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||||
|
|
||||||
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
|
return [self _leftOffsetForSegment:segment - 1] + CGRectGetWidth([self frameForSegment:segment - 1]) + thickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned)_indexOfLastSegment
|
- (unsigned)_indexOfLastSegment
|
||||||
@@ -510,7 +550,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
var height = [self currentValueForThemeAttribute:@"min-size"].height,
|
||||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||||
bounds = [self bounds];
|
bounds = [self bounds];
|
||||||
@@ -521,15 +561,16 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
else if (aName === "right-segment-bezel")
|
else if (aName === "right-segment-bezel")
|
||||||
{
|
{
|
||||||
return CGRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
// we have to FLOOR the coordinates to prevent a 1px glitch in Safari
|
||||||
bezelInset.top,
|
return CGRectMake(FLOOR(CGRectGetWidth([self bounds]) - contentInset.right),
|
||||||
contentInset.right,
|
FLOOR(bezelInset.top),
|
||||||
height);
|
FLOOR(contentInset.right),
|
||||||
|
FLOOR(height));
|
||||||
}
|
}
|
||||||
else if (aName.indexOf("segment-bezel") === 0)
|
else if (aName.indexOf("segment-bezel") === 0)
|
||||||
{
|
{
|
||||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||||
frame = CGRectCreateCopy([_segments[segment] frame]);
|
frame = CGRectCreateCopy([self frameForSegment:segment]);
|
||||||
|
|
||||||
if (segment === 0)
|
if (segment === 0)
|
||||||
{
|
{
|
||||||
@@ -537,7 +578,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
frame.size.width -= contentInset.left;
|
frame.size.width -= contentInset.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment === _segments.length - 1)
|
if (segment === [self segmentCount] - 1)
|
||||||
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
|
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
@@ -545,7 +586,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
else if (aName.indexOf("divider-bezel") === 0)
|
else if (aName.indexOf("divider-bezel") === 0)
|
||||||
{
|
{
|
||||||
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
||||||
width = [self widthForSegment:segment],
|
width = CGRectGetWidth([self frameForSegment:segment]),
|
||||||
left = [self _leftOffsetForSegment:segment],
|
left = [self _leftOffsetForSegment:segment],
|
||||||
thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||||
|
|
||||||
@@ -564,19 +605,32 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
if ([aName hasPrefix:@"segment-content"])
|
if ([aName hasPrefix:@"segment-content"])
|
||||||
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
{
|
||||||
|
var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[view _setUsesSingleLineMode:YES];
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
if (_segments.length <= 0)
|
if ([self segmentCount] <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var themeState = _themeStates[0];
|
var themeState = _themeStates[0],
|
||||||
|
isDisabled = [self hasThemeState:CPThemeStateDisabled],
|
||||||
|
isControlSizeSmall = [self hasThemeState:CPThemeStateControlSizeSmall],
|
||||||
|
isControlSizeMini = [self hasThemeState:CPThemeStateControlSizeMini];
|
||||||
|
|
||||||
themeState |= _themeState & CPThemeStateDisabled;
|
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||||
|
|
||||||
|
if (isControlSizeSmall)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||||
|
else if (isControlSizeMini)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||||
|
|
||||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||||
inState:themeState],
|
inState:themeState],
|
||||||
@@ -589,7 +643,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
var themeState = _themeStates[_themeStates.length - 1];
|
var themeState = _themeStates[_themeStates.length - 1];
|
||||||
|
|
||||||
themeState |= _themeState & CPThemeStateDisabled;
|
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||||
|
|
||||||
|
if (isControlSizeSmall)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||||
|
else if (isControlSizeMini)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||||
|
|
||||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||||
inState:themeState],
|
inState:themeState],
|
||||||
@@ -604,7 +663,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
var themeState = _themeStates[i];
|
var themeState = _themeStates[i];
|
||||||
|
|
||||||
themeState |= _themeState & CPThemeStateDisabled;
|
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||||
|
|
||||||
|
if (isControlSizeSmall)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||||
|
else if (isControlSizeMini)
|
||||||
|
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||||
|
|
||||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||||
inState:themeState],
|
inState:themeState],
|
||||||
@@ -615,7 +679,6 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
[bezelView setBackgroundColor:bezelColor];
|
[bezelView setBackgroundColor:bezelColor];
|
||||||
|
|
||||||
|
|
||||||
// layout image/title views
|
// layout image/title views
|
||||||
var segment = _segments[i],
|
var segment = _segments[i],
|
||||||
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
|
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
|
||||||
@@ -642,11 +705,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
if (i == count - 1)
|
if (i == count - 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var borderState = _themeStates[i] | _themeStates[i + 1];
|
|
||||||
|
|
||||||
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
|
var borderState = _themeStates[i].and(_themeStates[i + 1]);
|
||||||
|
|
||||||
borderState |= _themeState & CPThemeStateDisabled;
|
borderState = isDisabled ? borderState.and(CPThemeStateDisabled) : borderState;
|
||||||
|
|
||||||
|
if (isControlSizeSmall)
|
||||||
|
borderState = borderState.and(CPThemeStateControlSizeSmall);
|
||||||
|
else if (isControlSizeMini)
|
||||||
|
borderState = borderState.and(CPThemeStateControlSizeMini);
|
||||||
|
|
||||||
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
||||||
inState:borderState],
|
inState:borderState],
|
||||||
@@ -669,61 +736,33 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tileWithChangedSegment:(unsigned)aSegment
|
/*! @ignore */
|
||||||
|
- (void)tile
|
||||||
{
|
{
|
||||||
if (aSegment >= _segments.length)
|
[self tileWithChangedSegment:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (void)tileWithChangedSegment:(CPInteger)aSegment
|
||||||
|
{
|
||||||
|
var segmentCount = [self segmentCount];
|
||||||
|
|
||||||
|
// Corner case: when segmentCount == 0 and aSegment == 0, we do not return here because we still need to set the new frameSize bellow.
|
||||||
|
if (aSegment < 0 || (segmentCount > 0 && aSegment >= segmentCount))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var segment = _segments[aSegment],
|
var width = 0;
|
||||||
segmentWidth = [segment width],
|
|
||||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
|
||||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
|
||||||
font = [self font];
|
|
||||||
|
|
||||||
if (!segmentWidth)
|
if (segmentCount > 0)
|
||||||
{
|
{
|
||||||
if ([segment image] && [segment label])
|
// Invalidate frames for segments on the right. They will be lazily computed by -frameForSegment:.
|
||||||
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
|
for (var i = aSegment; i < segmentCount; i++)
|
||||||
else if (segment.image)
|
[_segments[i] setFrame:CGRectMakeZero()];
|
||||||
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
|
|
||||||
else if (segment.label)
|
width = CGRectGetMaxX([self frameForSegment:(segmentCount - 1)]);
|
||||||
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
|
|
||||||
else
|
|
||||||
segmentWidth = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var delta = segmentWidth - CGRectGetWidth([segment frame]);
|
[self setFrameSize:CGSizeMake(width, CGRectGetHeight([self frame]))];
|
||||||
|
|
||||||
if (!delta)
|
|
||||||
{
|
|
||||||
[self setNeedsLayout];
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update control size
|
|
||||||
var frame = [self frame];
|
|
||||||
|
|
||||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
|
||||||
|
|
||||||
// Update segment width
|
|
||||||
[segment setWidth:segmentWidth];
|
|
||||||
[segment setFrame:[self frameForSegment:aSegment]];
|
|
||||||
|
|
||||||
// Update following segments widths
|
|
||||||
var index = aSegment + 1;
|
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
|
||||||
{
|
|
||||||
[_segments[index] frame].origin.x += delta;
|
|
||||||
|
|
||||||
[self drawSegmentBezel:index highlight:NO];
|
|
||||||
[self drawSegment:index highlight:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self drawSegmentBezel:aSegment highlight:NO];
|
|
||||||
[self drawSegment:aSegment highlight:NO];
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -735,29 +774,58 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CGRect)frameForSegment:(unsigned)aSegment
|
- (CGRect)frameForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return [self bezelFrameForSegment:aSegment];
|
var segment = [_segments objectAtIndex:aSegment],
|
||||||
|
frame = [segment frame];
|
||||||
|
|
||||||
|
if (CGRectEqualToRect(frame, CGRectMakeZero()))
|
||||||
|
{
|
||||||
|
frame = [self bezelFrameForSegment:aSegment];
|
||||||
|
[segment setFrame:frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)bezelFrameForSegment:(unsigned)aSegment
|
- (CGRect)bezelFrameForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
var left = [self _leftOffsetForSegment:aSegment],
|
||||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
top = [self currentValueForThemeAttribute:@"bezel-inset"].top,
|
||||||
width = [self widthForSegment:aSegment],
|
width = [self widthForSegment:aSegment],
|
||||||
left = [self _leftOffsetForSegment:aSegment];
|
height = [self currentValueForThemeAttribute:@"min-size"].height;
|
||||||
|
|
||||||
return CGRectMake(left, bezelInset.top, width, height);
|
if (width == 0)
|
||||||
|
{
|
||||||
|
var themeState = _themeState.hasThemeState(CPThemeStateDisabled) ? _themeStates[aSegment].and(CPThemeStateDisabled) : _themeStates[aSegment],
|
||||||
|
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||||
|
contentInsetWidth = contentInset.left + contentInset.right,
|
||||||
|
|
||||||
|
segment = _segments[aSegment],
|
||||||
|
label = [segment label],
|
||||||
|
image = [segment image];
|
||||||
|
|
||||||
|
// add 1 pixel to account for possible fractional pixels at right edge
|
||||||
|
width = (label ? [label sizeWithFont:[self font]].width + 1 : 4.0) + (image ? [image size].width : 0) + contentInsetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CGRectMake(left, top, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)contentFrameForSegment:(unsigned)aSegment
|
- (CGRect)contentFrameForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
var height = [self currentValueForThemeAttribute:@"min-size"].height,
|
||||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
width = [self widthForSegment:aSegment],
|
width = CGRectGetWidth([self frameForSegment:aSegment]),
|
||||||
left = [self _leftOffsetForSegment:aSegment];
|
left = [self _leftOffsetForSegment:aSegment];
|
||||||
|
|
||||||
return CGRectMake(left + contentInset.left, contentInset.top, width - contentInset.left - contentInset.right, height - contentInset.top - contentInset.bottom);
|
return CGRectMake(left + contentInset.left, contentInset.top, width - contentInset.left - contentInset.right, height - contentInset.top - contentInset.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGSize)_minimumFrameSize
|
||||||
|
{
|
||||||
|
// The current width is always the minimum width.
|
||||||
|
return CGSizeMake(CGRectGetWidth([self frame]), [self currentValueForThemeAttribute:@"min-size"].height);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the segment that is hit by the specified point.
|
Returns the segment that is hit by the specified point.
|
||||||
@param aPoint the point to test for a segment hit
|
@param aPoint the point to test for a segment hit
|
||||||
@@ -766,19 +834,19 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
- (unsigned)testSegment:(CGPoint)aPoint
|
- (unsigned)testSegment:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
var location = [self convertPoint:aPoint fromView:nil],
|
var location = [self convertPoint:aPoint fromView:nil],
|
||||||
count = _segments.length;
|
count = [self segmentCount];
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
if (CGRectContainsPoint([_segments[count] frame], aPoint))
|
if (CGRectContainsPoint([self frameForSegment:count], aPoint))
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
if (_segments.length)
|
if ([self segmentCount])
|
||||||
{
|
{
|
||||||
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
|
var adjustedLastFrame = CGRectCreateCopy([self frameForSegment:(_segments.length - 1)]);
|
||||||
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||||
|
|
||||||
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||||
return _segments.length - 1;
|
return [self segmentCount] - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@@ -806,64 +874,68 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
var type = [anEvent type],
|
var type = [anEvent type],
|
||||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
if (type == CPLeftMouseUp)
|
switch (type)
|
||||||
{
|
{
|
||||||
if (_trackingSegment == -1)
|
case CPLeftMouseUp:
|
||||||
|
|
||||||
|
if (_trackingSegment === CPNotFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_trackingSegment === [self testSegment:location])
|
||||||
|
{
|
||||||
|
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||||
|
{
|
||||||
|
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
|
||||||
|
|
||||||
|
// With ANY, _selectedSegment means last pressed.
|
||||||
|
_selectedSegment = _trackingSegment;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self setSelected:YES forSegment:_trackingSegment];
|
||||||
|
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
|
||||||
|
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
||||||
|
{
|
||||||
|
[self setSelected:NO forSegment:_trackingSegment];
|
||||||
|
|
||||||
|
_selectedSegment = CPNotFound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||||
|
|
||||||
|
_trackingSegment = CPNotFound;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_trackingSegment === [self testSegment:location])
|
case CPLeftMouseDown:
|
||||||
{
|
|
||||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
var trackingSegment = [self testSegment:location];
|
||||||
|
if (trackingSegment > CPNotFound && [self isEnabledForSegment:trackingSegment])
|
||||||
{
|
{
|
||||||
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
|
_trackingHighlighted = YES;
|
||||||
|
_trackingSegment = trackingSegment;
|
||||||
// With ANY, _selectedSegment means last pressed.
|
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||||
_selectedSegment = _trackingSegment;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
[self setSelected:YES forSegment:_trackingSegment];
|
|
||||||
|
|
||||||
[self sendAction:[self action] to:[self target]];
|
break;
|
||||||
|
|
||||||
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
case CPLeftMouseDragged:
|
||||||
|
|
||||||
|
if (_trackingSegment === CPNotFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||||
|
|
||||||
|
if (highlighted != _trackingHighlighted)
|
||||||
{
|
{
|
||||||
[self setSelected:NO forSegment:_trackingSegment];
|
_trackingHighlighted = highlighted;
|
||||||
|
|
||||||
_selectedSegment = -1;
|
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
break;
|
||||||
|
|
||||||
_trackingSegment = -1;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == CPLeftMouseDown)
|
|
||||||
{
|
|
||||||
var trackingSegment = [self testSegment:location];
|
|
||||||
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
|
|
||||||
{
|
|
||||||
_trackingHighlighted = YES;
|
|
||||||
_trackingSegment = trackingSegment;
|
|
||||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (type == CPLeftMouseDragged)
|
|
||||||
{
|
|
||||||
if (_trackingSegment == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var highlighted = [self testSegment:location] === _trackingSegment;
|
|
||||||
|
|
||||||
if (highlighted != _trackingHighlighted)
|
|
||||||
{
|
|
||||||
_trackingHighlighted = highlighted;
|
|
||||||
|
|
||||||
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
@@ -873,7 +945,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
{
|
{
|
||||||
[super setFont:aFont];
|
[super setFont:aFont];
|
||||||
|
|
||||||
[self tileWithChangedSegment:0];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -905,28 +977,49 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
|
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
|
||||||
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
|
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
|
||||||
else
|
else
|
||||||
_selectedSegment = -1;
|
_selectedSegment = CPNotFound;
|
||||||
|
|
||||||
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
|
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
|
||||||
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
|
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
|
||||||
else
|
else
|
||||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||||
|
|
||||||
// HACK
|
// Here we update the themeStates array for each segments to know if there are selected or not
|
||||||
|
for (var i = 0; i < [self segmentCount]; i++)
|
||||||
for (var i = 0; i < _segments.length; i++)
|
|
||||||
{
|
|
||||||
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
|
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
|
||||||
[self tileWithChangedSegment:i];
|
|
||||||
|
[self tile];
|
||||||
|
|
||||||
|
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
|
||||||
|
dividerExtraSpace = ([_segments count] - 1) * thickness,
|
||||||
|
difference = MAX(originalWidth - [self frame].size.width - dividerExtraSpace, 0.0),
|
||||||
|
remainingWidth = FLOOR(difference / [self segmentCount]),
|
||||||
|
widthOfAllSegments = 0;
|
||||||
|
|
||||||
|
// We do this in a second loop because it relies on all the themeStates being set first
|
||||||
|
for (var i = 0; i < [self segmentCount]; i++)
|
||||||
|
{
|
||||||
|
var frame = [_segments[i] frame];
|
||||||
|
frame.size.width += remainingWidth;
|
||||||
|
|
||||||
|
widthOfAllSegments += CGRectGetWidth(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
|
// Here we handle the leftovers pixel, and we will add one pixel to each segment cell till we have the same size as the originalSize.
|
||||||
remainingWidth = FLOOR(difference / _segments.length);
|
// This is needed to have a perfect/same alignment between our application and xCode.
|
||||||
|
var leftOversPixel = originalWidth - (widthOfAllSegments + dividerExtraSpace);
|
||||||
|
|
||||||
for (var i = 0; i < _segments.length; i++)
|
// Make sure we don't make an out of range
|
||||||
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
|
if (leftOversPixel < [self segmentCount] - 1)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < leftOversPixel; i++)
|
||||||
|
{
|
||||||
|
[_segments[i] frame].size.width += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[self tileWithChangedSegment:0];
|
[self setFrameSize:CGSizeMake(originalWidth, CGRectGetHeight([self frame]))];
|
||||||
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -944,31 +1037,48 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPSegmentedControlBindersMap = {},
|
@implementation CPSegmentedControl (BindingSupport)
|
||||||
CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if ([self _isSelectionBinding:aBinding])
|
||||||
|
return [_CPSegmentedControlBinder class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)_isSelectionBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return (aBinding === CPSelectedIndexBinding || aBinding === CPSelectedLabelBinding || aBinding === CPSelectedTagBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [self _isSelectionBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||||
|
{
|
||||||
|
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
|
||||||
|
{
|
||||||
|
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_reverseSetBinding
|
||||||
|
{
|
||||||
|
[_CPSegmentedControlBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
|
||||||
|
|
||||||
@implementation _CPSegmentedControlBinder : CPBinder
|
@implementation _CPSegmentedControlBinder : CPBinder
|
||||||
{
|
{
|
||||||
CPString _selectionBinding @accessors(readonly, getter=selectionBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)reverseSetValueForObject:(id)aSource
|
|
||||||
{
|
|
||||||
var binder = CPSegmentedControlBindersMap[[aSource UID]];
|
|
||||||
[binder reverseSetValueFor:[binder selectionBinding]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
|
||||||
{
|
|
||||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
CPSegmentedControlBindersMap[[aSource UID]] = self;
|
|
||||||
_selectionBinding = aName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||||
|
|||||||
+5
-2
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CGGeometry.j"
|
||||||
|
@import "CPColor.j"
|
||||||
|
@import "CPGraphicsContext.j"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@deprecated
|
@deprecated
|
||||||
@@ -31,9 +34,9 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPShadow : CPObject
|
@implementation CPShadow : CPObject
|
||||||
{
|
{
|
||||||
CGSize _offset @accessors(property=shadowOffset);
|
CGSize _offset @accessors(property=shadowOffset);
|
||||||
float _blurRadius @accessors(property=shadowBlurRadius);
|
float _blurRadius @accessors(property=shadowBlurRadius);
|
||||||
CPColor _color @accessors(property=shadowColor);
|
CPColor _color @accessors(property=shadowColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@typedef CPShadowWeight
|
||||||
CPLightShadow = 0;
|
CPLightShadow = 0;
|
||||||
CPHeavyShadow = 1;
|
CPHeavyShadow = 1;
|
||||||
|
|
||||||
|
|||||||
+808
-150
File diff suppressed because it is too large
Load Diff
+51
-2
@@ -23,6 +23,19 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPRunLoop.j>
|
@import <Foundation/CPRunLoop.j>
|
||||||
|
|
||||||
|
@typedef HTMLAudioElement
|
||||||
|
|
||||||
|
@protocol CPSoundDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (void)sound:(CPSound)aSound didFinishPlaying:(BOOL)finishedLoading;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
|
var CPSoundDelegate_sound_didFinishPlaying_ = 1 << 1;
|
||||||
|
|
||||||
CPSoundLoadStateEmpty = 0;
|
CPSoundLoadStateEmpty = 0;
|
||||||
CPSoundLoadStateLoading = 1;
|
CPSoundLoadStateLoading = 1;
|
||||||
CPSoundLoadStateCanBePlayed = 2;
|
CPSoundLoadStateCanBePlayed = 2;
|
||||||
@@ -50,6 +63,7 @@ CPSoundPlayBackStatePause = 2;
|
|||||||
HTMLAudioElement _audioTag;
|
HTMLAudioElement _audioTag;
|
||||||
int _loadStatus;
|
int _loadStatus;
|
||||||
int _playBackStatus;
|
int _playBackStatus;
|
||||||
|
unsigned _implementedDelegateMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
@@ -133,6 +147,25 @@ CPSoundPlayBackStatePause = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Delegate methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the sound's delegate.
|
||||||
|
@param aDelegate the new delegate
|
||||||
|
*/
|
||||||
|
- (void)setDelegate:(id)aDelegate
|
||||||
|
{
|
||||||
|
if (_delegate === aDelegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_delegate = aDelegate;
|
||||||
|
_implementedDelegateMethods = 0;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
|
||||||
|
_implementedDelegateMethods |= CPSoundDelegate_sound_didFinishPlaying_;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Events listener
|
#pragma mark Events listener
|
||||||
|
|
||||||
@@ -207,8 +240,7 @@ CPSoundPlayBackStatePause = 2;
|
|||||||
_audioTag.currentTime = 0.0;
|
_audioTag.currentTime = 0.0;
|
||||||
_playBackStatus = CPSoundPlayBackStateStop;
|
_playBackStatus = CPSoundPlayBackStateStop;
|
||||||
|
|
||||||
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
|
[self _sendDelegateSoundDidFinishPlaying:YES];
|
||||||
[_delegate sound:self didFinishPlaying:YES];
|
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@@ -316,3 +348,20 @@ CPSoundPlayBackStatePause = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPSound (CPSoundDelegate)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call delegate sound:didFinishPlaying:
|
||||||
|
*/
|
||||||
|
- (void)_sendDelegateSoundDidFinishPlaying:(BOOL)finishedPlaying
|
||||||
|
{
|
||||||
|
if (!(_implementedDelegateMethods & CPSoundDelegate_sound_didFinishPlaying_))
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_delegate sound:self didFinishPlaying:finishedPlaying];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+1233
-618
File diff suppressed because it is too large
Load Diff
+29
-21
@@ -25,7 +25,6 @@
|
|||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
CPStepper is an implementation of Cocoa NSStepper.
|
CPStepper is an implementation of Cocoa NSStepper.
|
||||||
|
|
||||||
@@ -53,9 +52,9 @@
|
|||||||
@param maxValue the maximal acceptable value of the stepper
|
@param maxValue the maximal acceptable value of the stepper
|
||||||
@return Initialized CPStepper
|
@return Initialized CPStepper
|
||||||
*/
|
*/
|
||||||
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
+ (id)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||||
{
|
{
|
||||||
var stepper = [[CPStepper alloc] initWithFrame:CGRectMakeZero()];
|
var stepper = [[self alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[stepper setDoubleValue:aValue];
|
[stepper setDoubleValue:aValue];
|
||||||
[stepper setMinValue:aMinValue];
|
[stepper setMinValue:aMinValue];
|
||||||
@@ -75,14 +74,14 @@
|
|||||||
|
|
||||||
@return Initialized CPStepper
|
@return Initialized CPStepper
|
||||||
*/
|
*/
|
||||||
+ (CPStepper)stepper
|
+ (id)stepper
|
||||||
{
|
{
|
||||||
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (aBinding == CPValueBinding || aBinding == CPMinValueBinding || aBinding == CPMaxValueBinding)
|
if (aBinding === CPValueBinding || aBinding === CPMinValueBinding || aBinding === CPMaxValueBinding)
|
||||||
return [_CPStepperValueBinder class];
|
return [_CPStepperValueBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:aBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
@@ -90,7 +89,7 @@
|
|||||||
|
|
||||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (aBinding == CPValueBinding)
|
if (aBinding === CPValueBinding)
|
||||||
return @"doubleValue";
|
return @"doubleValue";
|
||||||
|
|
||||||
return [super _replacementKeyPathForBinding:aBinding];
|
return [super _replacementKeyPathForBinding:aBinding];
|
||||||
@@ -138,9 +137,16 @@
|
|||||||
[self setContinuous:_autorepeat];
|
[self setContinuous:_autorepeat];
|
||||||
[self addSubview:_buttonDown];
|
[self addSubview:_buttonDown];
|
||||||
|
|
||||||
|
[self _sizeToFit];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setControlSize:(CPControlSize)aControlSize
|
||||||
|
{
|
||||||
|
[super setControlSize:aControlSize];
|
||||||
|
[self _sizeToFit];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Superclass overrides
|
#pragma mark Superclass overrides
|
||||||
|
|
||||||
@@ -159,8 +165,8 @@
|
|||||||
|
|
||||||
- (void)setFrame:(CGRect)aFrame
|
- (void)setFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
var upSize = [self valueForThemeAttribute:@"up-button-size"],
|
var upSize = [self currentValueForThemeAttribute:@"up-button-size"],
|
||||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
downSize = [self currentValueForThemeAttribute:@"down-button-size"],
|
||||||
minSize = CGSizeMake(upSize.width, upSize.height + downSize.height),
|
minSize = CGSizeMake(upSize.width, upSize.height + downSize.height),
|
||||||
frame = CGRectMakeCopy(aFrame);
|
frame = CGRectMakeCopy(aFrame);
|
||||||
|
|
||||||
@@ -172,21 +178,22 @@
|
|||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var aFrame = [self frame],
|
var controlSizeThemeState = [self _controlSizeThemeState],
|
||||||
upSize = [self valueForThemeAttribute:@"up-button-size"],
|
aFrame = [self frame],
|
||||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
upSize = [self valueForThemeAttribute:@"up-button-size" inState:controlSizeThemeState],
|
||||||
upFrame = CGRectMake(aFrame.size.width - upSize.width, 0, upSize.width, upSize.height),
|
downSize = [self valueForThemeAttribute:@"down-button-size" inState:controlSizeThemeState],
|
||||||
downFrame = CGRectMake(aFrame.size.width - downSize.width, upSize.height, downSize.width, downSize.height);
|
upFrame = CGRectMake(0, 0, upSize.width, upSize.height),
|
||||||
|
downFrame = CGRectMake(0, upSize.height, downSize.width, downSize.height);
|
||||||
|
|
||||||
[_buttonUp setFrame:upFrame];
|
[_buttonUp setFrame:upFrame];
|
||||||
[_buttonDown setFrame:downFrame];
|
[_buttonDown setFrame:downFrame];
|
||||||
|
|
||||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPButtonStateBezelStyleRoundRect]];
|
||||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
|
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled, CPButtonStateBezelStyleRoundRect]];
|
||||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted, CPButtonStateBezelStyleRoundRect]];
|
||||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPButtonStateBezelStyleRoundRect]];
|
||||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
|
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled, CPButtonStateBezelStyleRoundRect]];
|
||||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted, CPButtonStateBezelStyleRoundRect]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_sizeToFit
|
- (void)_sizeToFit
|
||||||
@@ -232,7 +239,7 @@
|
|||||||
if (![self isEnabled])
|
if (![self isEnabled])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (aSender == _buttonUp)
|
if (aSender === _buttonUp)
|
||||||
[self setDoubleValue:([self doubleValue] + _increment)];
|
[self setDoubleValue:([self doubleValue] + _increment)];
|
||||||
else
|
else
|
||||||
[self setDoubleValue:([self doubleValue] - _increment)];
|
[self setDoubleValue:([self doubleValue] - _increment)];
|
||||||
@@ -285,7 +292,7 @@
|
|||||||
|
|
||||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
var placeholder = (aBinding == CPMaxValueBinding) ? [_source maxValue] : [_source minValue];
|
var placeholder = (aBinding === CPMaxValueBinding) ? [_source maxValue] : [_source minValue];
|
||||||
|
|
||||||
[super _updatePlaceholdersWithOptions:options];
|
[super _updatePlaceholdersWithOptions:options];
|
||||||
|
|
||||||
@@ -316,6 +323,7 @@ var CPStepperMinValue = @"CPStepperMinValue",
|
|||||||
_autorepeat = [aCoder decodeBoolForKey:CPStepperAutorepeat];
|
_autorepeat = [aCoder decodeBoolForKey:CPStepperAutorepeat];
|
||||||
|
|
||||||
[self _init];
|
[self _init];
|
||||||
|
[self setEnabled:[self isEnabled]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
|
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPPlatformString.j"
|
@import "CPPlatformString.j"
|
||||||
|
@import "CPFont.j"
|
||||||
|
@import "CPCompatibility.j"
|
||||||
|
|
||||||
|
|
||||||
var CPStringSizeWithFontInWidthCache = {};
|
var CPStringSizeWithFontInWidthCache = [],
|
||||||
|
CPStringSizeWithFontHeightCache = [],
|
||||||
|
CPStringSizeMeasuringContext;
|
||||||
|
|
||||||
CPStringSizeCachingEnabled = YES;
|
CPCanvasStringSizingIsFunctional = NO;
|
||||||
|
|
||||||
@implementation CPString (CPStringDrawing)
|
@implementation CPString (CPStringDrawing)
|
||||||
|
|
||||||
@@ -53,20 +57,66 @@ CPStringSizeCachingEnabled = YES;
|
|||||||
return [self sizeWithFont:aFont inWidth:NULL];
|
return [self sizeWithFont:aFont inWidth:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if ([self class] != [CPString class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||||
|
{
|
||||||
|
if (!CPStringSizeMeasuringContext)
|
||||||
|
CPStringSizeMeasuringContext = CGBitmapGraphicsContextCreate();
|
||||||
|
|
||||||
|
// This is to make sure that Canvas based string sizing is functional before we use it.
|
||||||
|
// Currently, Chrome has issues with certain strings, FF had issues in the past.
|
||||||
|
// Unfortunately, this test does fit in CPCompatibility.j where things are not sufficiently initialized.
|
||||||
|
|
||||||
|
var testingFont = [CPFont systemFontOfSize:12];
|
||||||
|
var testingText = 'A A A A A A A A';
|
||||||
|
CPStringSizeMeasuringContext.font = [testingFont cssString];
|
||||||
|
CPCanvasStringSizingIsFunctional = ROUND(CPStringSizeMeasuringContext.measureText(testingText).width) == ROUND([CPPlatformString sizeOfString:testingText withFont:testingFont forWidth:NULL].width);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||||
{
|
{
|
||||||
if (!CPStringSizeCachingEnabled)
|
var size;
|
||||||
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
|
||||||
|
|
||||||
var cacheKey = self + [aFont cssString] + aWidth,
|
#if PLATFORM(DOM)
|
||||||
size = CPStringSizeWithFontInWidthCache[cacheKey];
|
var sizeCacheForFont = CPStringSizeWithFontInWidthCache[self];
|
||||||
|
|
||||||
if (size === undefined)
|
if (sizeCacheForFont === undefined)
|
||||||
{
|
sizeCacheForFont = CPStringSizeWithFontInWidthCache[self] = [];
|
||||||
|
|
||||||
|
var cssString = [aFont cssString],
|
||||||
|
cacheKey = cssString + '_' + (aWidth ? aWidth : '0');
|
||||||
|
|
||||||
|
size = sizeCacheForFont[cacheKey];
|
||||||
|
|
||||||
|
if (size !== undefined && sizeCacheForFont.hasOwnProperty(cacheKey))
|
||||||
|
return CGSizeMakeCopy(size);
|
||||||
|
|
||||||
|
if (!CPCanvasStringSizingIsFunctional || aWidth)
|
||||||
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||||
CPStringSizeWithFontInWidthCache[cacheKey] = size;
|
else
|
||||||
|
{
|
||||||
|
if (CPPlatformHasBug(CPTextSizingAlwaysNeedsSetFontBug) || CPStringSizeMeasuringContext.font !== cssString)
|
||||||
|
CPStringSizeMeasuringContext.font = cssString;
|
||||||
|
|
||||||
|
var fontHeight = CPStringSizeWithFontHeightCache[cssString];
|
||||||
|
|
||||||
|
if (fontHeight === undefined)
|
||||||
|
fontHeight = CPStringSizeWithFontHeightCache[cssString] = [aFont defaultLineHeightForFont];
|
||||||
|
|
||||||
|
size = CGSizeMake(CPStringSizeMeasuringContext.measureText(self).width, fontHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizeCacheForFont[cacheKey] = size;
|
||||||
|
#else
|
||||||
|
size = CGSizeMake(0, 0);
|
||||||
|
#endif
|
||||||
return CGSizeMakeCopy(size);
|
return CGSizeMakeCopy(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+607
-107
@@ -25,6 +25,7 @@
|
|||||||
@import "CPTabViewItem.j"
|
@import "CPTabViewItem.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@typedef CPTabViewType
|
||||||
CPTopTabsBezelBorder = 0;
|
CPTopTabsBezelBorder = 0;
|
||||||
//CPLeftTabsBezelBorder = 1;
|
//CPLeftTabsBezelBorder = 1;
|
||||||
CPBottomTabsBezelBorder = 2;
|
CPBottomTabsBezelBorder = 2;
|
||||||
@@ -33,10 +34,25 @@ CPNoTabsBezelBorder = 4; //Displays no tabs and has a bezeled border.
|
|||||||
CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
|
CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
|
||||||
CPNoTabsNoBorder = 6; //Displays no tabs and no border.
|
CPNoTabsNoBorder = 6; //Displays no tabs and no border.
|
||||||
|
|
||||||
var CPTabViewDidSelectTabViewItemSelector = 1,
|
@class _CPTabViewBox
|
||||||
CPTabViewShouldSelectTabViewItemSelector = 2,
|
@class _CPSegmentedControl
|
||||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
|
||||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
|
||||||
|
CPTabViewShouldSelectTabViewItemSelector = 1 << 2,
|
||||||
|
CPTabViewWillSelectTabViewItemSelector = 1 << 3,
|
||||||
|
CPTabViewDidChangeNumberOfTabViewItemsSelector = 1 << 4;
|
||||||
|
|
||||||
|
|
||||||
|
@protocol CPTabViewDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)tabView:(CPTabView)tabView shouldSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||||
|
- (void)tabView:(CPTabView)tabView didSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||||
|
- (void)tabView:(CPTabView)tabView willSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||||
|
- (void)tabViewDidChangeNumberOfTabViewItems:(CPTabView)tabView;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -48,27 +64,41 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
@implementation CPTabView : CPView
|
@implementation CPTabView : CPView
|
||||||
{
|
{
|
||||||
CPArray _items;
|
CPArray _items;
|
||||||
|
|
||||||
CPSegmentedControl _tabs;
|
_CPSegmentedControl _tabs;
|
||||||
CPBox _box;
|
_CPTabViewBox _box;
|
||||||
|
CPView _placeholderView @accessors;
|
||||||
|
|
||||||
CPNumber _selectedIndex;
|
CPTabViewItem _selectedTabViewItem;
|
||||||
|
|
||||||
CPTabViewType _type;
|
CPTabViewType _type;
|
||||||
CPFont _font;
|
CPFont _font;
|
||||||
|
|
||||||
id _delegate;
|
id <CPTabViewDelegate> _delegate;
|
||||||
unsigned _delegateSelectors;
|
unsigned _delegateSelectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"tab-view";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"nib2cib-adjustment-frame": [CPNull null],
|
||||||
|
@"should-center-on-border": NO,
|
||||||
|
@"box-content-inset": CGInsetMakeZero()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
{
|
{
|
||||||
_items = [CPArray array];
|
|
||||||
|
|
||||||
[self _init];
|
[self _init];
|
||||||
|
_selectedTabViewItem = nil;
|
||||||
[self setTabViewType:CPTopTabsBezelBorder];
|
[self setTabViewType:CPTopTabsBezelBorder];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,19 +107,30 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
|
|
||||||
- (void)_init
|
- (void)_init
|
||||||
{
|
{
|
||||||
_selectedIndex = CPNotFound;
|
_tabs = [[_CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[_tabs setTabView:self];
|
||||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
|
|
||||||
[_tabs setHitTests:NO];
|
[_tabs setHitTests:NO];
|
||||||
|
[_tabs setSegments:[CPArray array]];
|
||||||
|
[_tabs setAction:@selector(_reflectSelectedTab:)];
|
||||||
|
[_tabs setTarget:self];
|
||||||
|
|
||||||
var height = [_tabs valueForThemeAttribute:@"default-height"];
|
var height = [_tabs valueForThemeAttribute:@"min-size"].height;
|
||||||
[_tabs setFrameSize:CGSizeMake(0, height)];
|
[_tabs setFrameSize:CGSizeMake(0, height)];
|
||||||
|
|
||||||
_box = [[CPBox alloc] initWithFrame:[self bounds]];
|
_box = [[_CPTabViewBox alloc] initWithFrame:[self bounds]];
|
||||||
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
[_box setTabView:self];
|
||||||
|
[_box setContentInset:[self currentValueForThemeAttribute:@"box-content-inset"]];
|
||||||
|
[_box setContentViewMargins:CGSizeMakeZero()];
|
||||||
|
|
||||||
[self addSubview:_box];
|
[self addSubview:_box];
|
||||||
[self addSubview:_tabs];
|
[self addSubview:_tabs];
|
||||||
|
|
||||||
|
_placeholderView = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)items
|
||||||
|
{
|
||||||
|
return [_tabs segments];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding and Removing Tabs
|
// Adding and Removing Tabs
|
||||||
@@ -99,7 +140,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
[self insertTabViewItem:aTabViewItem atIndex:[_items count]];
|
[self insertTabViewItem:aTabViewItem atIndex:[self numberOfTabViewItems]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -109,15 +150,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
|
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
[_items insertObject:aTabViewItem atIndex:anIndex];
|
[self _insertTabViewItems:[aTabViewItem] atIndexes:[CPIndexSet indexSetWithIndex:anIndex] canUpdateSelectedTab:YES];
|
||||||
|
}
|
||||||
|
|
||||||
[self _updateItems];
|
- (void)_insertTabViewItems:(CPArray)tabViewItems atIndexes:(CPIndexSet)indexes canUpdateSelectedTab:(BOOL)canUpdateSelectedTab
|
||||||
[self _repositionTabs];
|
{
|
||||||
|
var prevItemsCount = [self numberOfTabViewItems];
|
||||||
|
|
||||||
[aTabViewItem _setTabView:self];
|
[_tabs insertSegments:tabViewItems atIndexes:indexes];
|
||||||
|
[tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
[self tileWithChangedItem:[tabViewItems firstObject]];
|
||||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
[self _reverseSetContent];
|
||||||
|
|
||||||
|
[self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
|
||||||
|
|
||||||
|
// Do not allow empty selection if selection bindings are not enabled.
|
||||||
|
if (prevItemsCount == 0 && [self numberOfTabViewItems] > 0 && ![self _isSelectionBinded] && canUpdateSelectedTab)
|
||||||
|
[self _selectTabViewItemAtIndex:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -126,23 +176,39 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
var count = [_items count];
|
var idx = [[self items] indexOfObjectIdenticalTo:aTabViewItem];
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ([_items objectAtIndex:i] === aTabViewItem)
|
|
||||||
{
|
|
||||||
[_items removeObjectAtIndex:i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateItems];
|
if (idx == CPNotFound)
|
||||||
[self _repositionTabs];
|
return;
|
||||||
|
|
||||||
|
[_tabs removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndex:idx]];
|
||||||
[aTabViewItem _setTabView:nil];
|
[aTabViewItem _setTabView:nil];
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
[self tileWithChangedItem:nil];
|
||||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
[self _didRemoveTabViewItem:aTabViewItem atIndex:idx];
|
||||||
|
[self _reverseSetContent];
|
||||||
|
|
||||||
|
[self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_didRemoveTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPInteger)idx
|
||||||
|
{
|
||||||
|
// If the selection is managed by bindings, let the binder do that.
|
||||||
|
if ([self _isSelectionBinded])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_selectedTabViewItem == aTabViewItem)
|
||||||
|
{
|
||||||
|
var didSelect = NO;
|
||||||
|
|
||||||
|
if (idx > 0)
|
||||||
|
didSelect = [self selectTabViewItemAtIndex:idx - 1];
|
||||||
|
else if ([self numberOfTabViewItems] > 0)
|
||||||
|
didSelect = [self selectTabViewItemAtIndex:0];
|
||||||
|
|
||||||
|
if (didSelect == NO)
|
||||||
|
_selectedTabViewItem == nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessing Tabs
|
// Accessing Tabs
|
||||||
@@ -153,7 +219,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
return [_items indexOfObjectIdenticalTo:aTabViewItem];
|
return [[self items] indexOfObjectIdenticalTo:aTabViewItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -163,11 +229,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||||
{
|
{
|
||||||
for (var index = [_items count]; index >= 0; index--)
|
return [[self items] indexOfObjectPassingTest:function(item, idx, stop)
|
||||||
if ([[_items[index] identifier] isEqual:anIdentifier])
|
{
|
||||||
return index;
|
return [[item identifier] isEqual:anIdentifier];
|
||||||
|
}];
|
||||||
return CPNotFound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -176,7 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (unsigned)numberOfTabViewItems
|
- (unsigned)numberOfTabViewItems
|
||||||
{
|
{
|
||||||
return [_items count];
|
return [[self items] count];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -185,7 +250,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPTabViewItem)tabViewItemAtIndex:(CPUInteger)anIndex
|
- (CPTabViewItem)tabViewItemAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [_items objectAtIndex:anIndex];
|
return [[self items] objectAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -194,7 +259,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPArray)tabViewItems
|
- (CPArray)tabViewItems
|
||||||
{
|
{
|
||||||
return [_items copy]; // Copy?
|
return [[self items] copy]; // Copy?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selecting a Tab
|
// Selecting a Tab
|
||||||
@@ -204,7 +269,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectFirstTabViewItem:(id)aSender
|
- (void)selectFirstTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if ([_items count] === 0)
|
if ([self numberOfTabViewItems] === 0)
|
||||||
return; // throw?
|
return; // throw?
|
||||||
|
|
||||||
[self selectTabViewItemAtIndex:0];
|
[self selectTabViewItemAtIndex:0];
|
||||||
@@ -216,10 +281,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectLastTabViewItem:(id)aSender
|
- (void)selectLastTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if ([_items count] === 0)
|
if ([self numberOfTabViewItems] === 0)
|
||||||
return; // throw?
|
return; // throw?
|
||||||
|
|
||||||
[self selectTabViewItemAtIndex:[_items count] - 1];
|
[self selectTabViewItemAtIndex:[self numberOfTabViewItems] - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -228,12 +293,12 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectNextTabViewItem:(id)aSender
|
- (void)selectNextTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if (_selectedIndex === CPNotFound)
|
if (_selectedTabViewItem == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var nextIndex = _selectedIndex + 1;
|
var nextIndex = [self indexOfTabViewItem:_selectedTabViewItem] + 1;
|
||||||
|
|
||||||
if (nextIndex === [_items count])
|
if (nextIndex === [self numberOfTabViewItems])
|
||||||
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
|
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -246,10 +311,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectPreviousTabViewItem:(id)aSender
|
- (void)selectPreviousTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if (_selectedIndex === CPNotFound)
|
if (_selectedTabViewItem == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var previousIndex = _selectedIndex - 1;
|
var previousIndex = [self indexOfTabViewItem:_selectedTabViewItem] - 1;
|
||||||
|
|
||||||
if (previousIndex < 0)
|
if (previousIndex < 0)
|
||||||
return; // does nothing. See above.
|
return; // does nothing. See above.
|
||||||
@@ -272,36 +337,70 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
|
- (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
if (anIndex === _selectedIndex)
|
if (![self _selectTabViewItemAtIndex:anIndex])
|
||||||
return;
|
|
||||||
|
|
||||||
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
|
||||||
|
|
||||||
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
[self _reverseSetSelectedIndex];
|
||||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
|
||||||
|
|
||||||
[_tabs selectSegmentWithTag:anIndex];
|
|
||||||
[self _setSelectedIndex:anIndex];
|
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
|
||||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like selectTabViewItemAtIndex: but without bindings interaction
|
||||||
|
- (BOOL)_selectTabViewItemAtIndex:(CPUInteger)anIndex
|
||||||
|
{
|
||||||
|
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||||
|
|
||||||
|
if (aTabViewItem == _selectedTabViewItem)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (![self _sendDelegateShouldSelectTabViewItem:aTabViewItem])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[self _sendDelegateWillSelectTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
[_tabs setSelectedSegment:anIndex];
|
||||||
|
_selectedTabViewItem = aTabViewItem;
|
||||||
|
[self _loadTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
[self _sendDelegateDidSelectTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_loadTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
|
{
|
||||||
|
var controller = [aTabViewItem viewController];
|
||||||
|
|
||||||
|
if (controller != nil && ![controller isViewLoaded])
|
||||||
|
{
|
||||||
|
[controller loadViewWithCompletionHandler:function(view, error)
|
||||||
|
{
|
||||||
|
if (error != nil)
|
||||||
|
{
|
||||||
|
CPLog.warn("Could not load the view for item " + aTabViewItem + ". " + error);
|
||||||
|
}
|
||||||
|
else if (view != nil)
|
||||||
|
{
|
||||||
|
[aTabViewItem setView:view];
|
||||||
|
|
||||||
|
if ([self selectedTabViewItem] == aTabViewItem)
|
||||||
|
[self _displayItemView:view];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self _displayItemView:[aTabViewItem view]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the current item being displayed.
|
Returns the current item being displayed.
|
||||||
@return the tab view item currenly being displayed by the receiver
|
@return the tab view item currenly being displayed by the receiver
|
||||||
*/
|
*/
|
||||||
- (CPTabViewItem)selectedTabViewItem
|
- (CPTabViewItem)selectedTabViewItem
|
||||||
{
|
{
|
||||||
if (_selectedIndex != CPNotFound)
|
return _selectedTabViewItem;
|
||||||
return [_items objectAtIndex:_selectedIndex];
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifying the font
|
// Modifying the font
|
||||||
@@ -362,6 +461,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)tileWithChangedItem:(CPTabViewItem)aTabViewItem
|
||||||
|
{
|
||||||
|
var segment = aTabViewItem ? [self indexOfTabViewItem:aTabViewItem] : 0;
|
||||||
|
[_tabs tileWithChangedSegment:segment];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
// Even if CPTabView's autoresizesSubviews is NO, _tabs and _box has to be laid out.
|
// Even if CPTabView's autoresizesSubviews is NO, _tabs and _box has to be laid out.
|
||||||
@@ -374,10 +481,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
{
|
{
|
||||||
var aFrame = [self frame],
|
var aFrame = [self frame],
|
||||||
segmentedHeight = CGRectGetHeight([_tabs frame]),
|
segmentedHeight = CGRectGetHeight([_tabs frame]),
|
||||||
origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
|
borderWidth = [self currentValueForThemeAttribute:@"should-center-on-border"] ? [_box borderWidth] : 0,
|
||||||
|
origin = _type === CPTopTabsBezelBorder ? (segmentedHeight - borderWidth) / 2 : 0;
|
||||||
|
|
||||||
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
|
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame), CGRectGetHeight(aFrame) - (segmentedHeight - borderWidth) / 2)];
|
||||||
CGRectGetHeight(aFrame) - segmentedHeight / 2)];
|
|
||||||
|
|
||||||
[self _repositionTabs];
|
[self _repositionTabs];
|
||||||
}
|
}
|
||||||
@@ -405,7 +512,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
Sets the delegate for this tab view.
|
Sets the delegate for this tab view.
|
||||||
@param aDelegate the tab view's delegate
|
@param aDelegate the tab view's delegate
|
||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPTabViewDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate == aDelegate)
|
if (_delegate == aDelegate)
|
||||||
return;
|
return;
|
||||||
@@ -439,10 +546,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
[_tabs trackSegment:anEvent];
|
||||||
|
|
||||||
if (segmentIndex != CPNotFound && [self selectTabViewItemAtIndex:segmentIndex])
|
|
||||||
[_tabs trackSegment:anEvent];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_repositionTabs
|
- (void)_repositionTabs
|
||||||
@@ -456,30 +560,248 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setSelectedIndex:(CPNumber)index
|
- (void)_displayItemView:(CPView)aView
|
||||||
{
|
{
|
||||||
_selectedIndex = index;
|
[_box setContentView:aView];
|
||||||
[self _setContentViewFromItem:[_items objectAtIndex:_selectedIndex]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setContentViewFromItem:(CPTabViewItem)anItem
|
- (void)_reflectSelectedTab:(id)aSender
|
||||||
{
|
{
|
||||||
[_box setContentView:[anItem view]];
|
[self selectTabViewItemAtIndex:[_tabs selectedSegment]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateItems
|
// DELEGATE METHODS
|
||||||
{
|
|
||||||
var count = [_items count];
|
|
||||||
[_tabs setSegmentCount:count];
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
- (BOOL)_sendDelegateShouldSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
|
{
|
||||||
|
if (_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector)
|
||||||
|
return [_delegate tabView:self shouldSelectTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_sendDelegateWillSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
|
{
|
||||||
|
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||||
|
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_sendDelegateDidSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
|
{
|
||||||
|
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||||
|
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_sendDelegateTabViewDidChangeNumberOfTabViewItems
|
||||||
|
{
|
||||||
|
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||||
|
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPTabView (BindingSupport)
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding == CPContentBinding)
|
||||||
|
return [_CPTabViewContentBinder class];
|
||||||
|
else if (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding)
|
||||||
|
return [_CPTabViewSelectionBinder class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_reverseSetContent
|
||||||
|
{
|
||||||
|
var theBinder = [self binderForBinding:CPContentBinding];
|
||||||
|
[theBinder reverseSetValueFor:@"items"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_reverseSetSelectedIndex
|
||||||
|
{
|
||||||
|
var theBinder = [self binderForBinding:CPSelectionIndexesBinding];
|
||||||
|
|
||||||
|
if (theBinder != nil)
|
||||||
|
[theBinder reverseSetValueFor:@"selectionIndexes"];
|
||||||
|
else
|
||||||
{
|
{
|
||||||
[_tabs setLabel:[[_items objectAtIndex:i] label] forSegment:i];
|
theBinder = [self binderForBinding:CPSelectedIndexBinding];
|
||||||
[_tabs setTag:i forSegment:i];
|
[theBinder reverseSetValueFor:@"selectedIndex"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPBinder)binderForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var cls = [[self class] _binderClassForBinding:aBinding];
|
||||||
|
return [cls getBinding:aBinding forObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_isSelectionBinded
|
||||||
|
{
|
||||||
|
return [self binderForBinding:CPSelectionIndexesBinding] || [self binderForBinding:CPSelectedIndexBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setItems:(CPArray)tabViewItems
|
||||||
|
{
|
||||||
|
if ([tabViewItems isEqualToArray:[_tabs segments]])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[self items] makeObjectsPerformSelector:@selector(_setTabView:) withObject:nil];
|
||||||
|
[_tabs setSegments:tabViewItems];
|
||||||
|
[tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||||
|
|
||||||
|
[self tileWithChangedItem:nil];
|
||||||
|
|
||||||
|
// Update the selection because setSegments: did remove all previous segments AND the selection.
|
||||||
|
[_tabs setSelectedSegment:[self indexOfTabViewItem:_selectedTabViewItem]];
|
||||||
|
|
||||||
|
// should we send delegate methods in bindings mode ?
|
||||||
|
//[self _delegateTabViewDidChangeNumberOfTabViewItems:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_deselectAll
|
||||||
|
{
|
||||||
|
[_tabs setSelectedSegment:-1];
|
||||||
|
_selectedTabViewItem = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_displayPlaceholder:(CPString)aPlaceholder
|
||||||
|
{
|
||||||
|
if (_placeholderView == nil)
|
||||||
|
{
|
||||||
|
_placeholderView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[textField setTag:1000];
|
||||||
|
[textField setTextColor:[CPColor whiteColor]];
|
||||||
|
[textField setFont:[CPFont boldFontWithName:@"Geneva" size:18 italic:YES]];
|
||||||
|
[_placeholderView addSubview:textField];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_selectedIndex === CPNotFound)
|
var textField = [_placeholderView viewWithTag:1000];
|
||||||
[self selectFirstTabViewItem:self];
|
[textField setStringValue:aPlaceholder];
|
||||||
|
[textField sizeToFit];
|
||||||
|
|
||||||
|
var boxBounds = [_box bounds],
|
||||||
|
textFieldBounds = [textField bounds],
|
||||||
|
origin = CGPointMake(CGRectGetWidth(boxBounds)/2 - CGRectGetWidth(textFieldBounds)/2, CGRectGetHeight(boxBounds)/2 - CGRectGetHeight(textFieldBounds));
|
||||||
|
|
||||||
|
[textField setFrameOrigin:origin];
|
||||||
|
|
||||||
|
[self _displayItemView:_placeholderView];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Enabled controls accept first mouse by default.
|
||||||
|
*/
|
||||||
|
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPTabViewContentBinderNull = @"NO CONTENT";
|
||||||
|
|
||||||
|
@implementation _CPTabViewContentBinder : CPBinder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||||
|
{
|
||||||
|
[super _updatePlaceholdersWithOptions:options];
|
||||||
|
[self _setPlaceholder:_CPTabViewContentBinderNull forMarker:CPNullMarker isDefault:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source setItems:@[]];
|
||||||
|
[_source _setPlaceholderView:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source setItems:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [_source items];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPTabViewSelectionBinderMultipleValues = @"Multiple Selection",
|
||||||
|
_CPTabViewSelectionBinderNoSelection = @"No Selection";
|
||||||
|
|
||||||
|
@implementation _CPTabViewSelectionBinder : CPBinder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||||
|
{
|
||||||
|
[super _updatePlaceholdersWithOptions:options];
|
||||||
|
|
||||||
|
[self _setPlaceholder:_CPTabViewSelectionBinderMultipleValues forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||||
|
[self _setPlaceholder:_CPTabViewSelectionBinderNoSelection forMarker:CPNoSelectionMarker isDefault:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aMarker == CPNoSelectionMarker || aMarker == CPNullMarker)
|
||||||
|
[_source _deselectAll];
|
||||||
|
|
||||||
|
[_source _displayPlaceholder:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding == CPSelectionIndexesBinding)
|
||||||
|
{
|
||||||
|
if (aValue == nil || [aValue count] == 0)
|
||||||
|
{
|
||||||
|
[_source _deselectAll];
|
||||||
|
[_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
|
||||||
|
}
|
||||||
|
else if ([aValue count] > 1)
|
||||||
|
[_source _displayPlaceholder:_CPTabViewSelectionBinderMultipleValues];
|
||||||
|
else if ([aValue firstIndex] < [_source numberOfTabViewItems])
|
||||||
|
[_source _selectTabViewItemAtIndex:[aValue firstIndex]];
|
||||||
|
}
|
||||||
|
else if (aBinding == CPSelectedIndexBinding)
|
||||||
|
{
|
||||||
|
if (aValue == CPNotFound)
|
||||||
|
{
|
||||||
|
[_source _deselectAll];
|
||||||
|
[_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
|
||||||
|
}
|
||||||
|
else if (aValue < [_source numberOfTabViewItems])
|
||||||
|
[_source _selectTabViewItemAtIndex:aValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding == CPSelectionIndexesBinding)
|
||||||
|
{
|
||||||
|
var result = [CPIndexSet indexSet],
|
||||||
|
idx = [_source indexOfTabViewItem:[_source selectedTabViewItem]];
|
||||||
|
|
||||||
|
if (idx !== CPNotFound)
|
||||||
|
[result addIndex:idx];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (aBinding == CPSelectedIndexBinding)
|
||||||
|
return [_source indexOfTabViewItem:[_source selectedTabViewItem]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -501,12 +823,13 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
|
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
|
||||||
[_tabs setFont:_font];
|
[_tabs setFont:_font];
|
||||||
|
|
||||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey] || [CPArray array];
|
||||||
[_items makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
[self _insertTabViewItems:items atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [items count])] canUpdateSelectedTab:NO];
|
||||||
|
|
||||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||||
|
|
||||||
self.selectOnAwake = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
_selectedTabViewItem = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||||
|
|
||||||
_type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
_type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,14 +838,23 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
|
[super awakeFromCib];
|
||||||
|
|
||||||
// This cannot be run in initWithCoder because it might call selectTabViewItem:, which is
|
// This cannot be run in initWithCoder because it might call selectTabViewItem:, which is
|
||||||
// not safe to call before the views of the tab views items are fully decoded.
|
// not safe to call before the views of the tab views items are fully decoded.
|
||||||
[self _updateItems];
|
|
||||||
|
|
||||||
if (self.selectOnAwake)
|
if (_selectedTabViewItem)
|
||||||
{
|
{
|
||||||
[self selectTabViewItem:self.selectOnAwake];
|
var idx = [self indexOfTabViewItem:_selectedTabViewItem];
|
||||||
delete self.selectOnAwake;
|
|
||||||
|
if (idx !== CPNotFound)
|
||||||
|
{
|
||||||
|
// Temporarily set the selected item to not selected.
|
||||||
|
// It allows the initial selection to be made correctly.
|
||||||
|
_selectedTabViewItem = nil;
|
||||||
|
|
||||||
|
[self selectTabViewItemAtIndex:idx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var type = _type;
|
var type = _type;
|
||||||
@@ -544,9 +876,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
|
|
||||||
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
|
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
|
||||||
|
|
||||||
var selected = [self selectedTabViewItem];
|
[aCoder encodeConditionalObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
|
||||||
if (selected)
|
|
||||||
[aCoder encodeObject:selected forKey:CPTabViewSelectedItemKey];
|
|
||||||
|
|
||||||
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
||||||
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
||||||
@@ -555,3 +885,173 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPTabView (CSSTheming)
|
||||||
|
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
[self setTheme:aTheme];
|
||||||
|
[[self subviews] makeObjectsPerformSelector:@selector(_setThemeIncludingDescendants:) withObject:aTheme];
|
||||||
|
|
||||||
|
// Items must also perform this (without this, only the selected item does)
|
||||||
|
|
||||||
|
for (var i = 0, allItems = [self items], count = allItems.length; i < count; i++)
|
||||||
|
if (allItems[i] != _selectedTabViewItem)
|
||||||
|
[[allItems[i] view] _setThemeIncludingDescendants:aTheme];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation _CPTabViewBox : CPBox
|
||||||
|
{
|
||||||
|
CPTabView _tabView @accessors(property=tabView);
|
||||||
|
CGInset _contentInset @accessors(property=contentInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
[self setBoxType:CPBoxPrimary];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)hitTest:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
// Here we check if we have clicked on the segmentedControl of the tabView or not
|
||||||
|
// If YES, the CPBox should not handle the click
|
||||||
|
var segmentIndex = [_tabView._tabs testSegment:[_tabView._tabs convertPoint:aPoint fromView:[self superview]]];
|
||||||
|
|
||||||
|
if (segmentIndex != CPNotFound)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [super hitTest:aPoint];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some CPBox overrides because CPTabView use of CPBox differs from legacy CPBox regarding layout.
|
||||||
|
|
||||||
|
- (void)setContentView:(CPView)aView
|
||||||
|
{
|
||||||
|
if (aView === _contentView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_contentInset)
|
||||||
|
[aView setFrame:CGRectInsetByInset([self bounds], _contentInset)];
|
||||||
|
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
|
// A nil contentView is allowed (tested in Cocoa 2013-02-22).
|
||||||
|
if (!aView)
|
||||||
|
[_contentView removeFromSuperview];
|
||||||
|
else if (_contentView)
|
||||||
|
[_boxView replaceSubview:_contentView with:aView];
|
||||||
|
else
|
||||||
|
[_boxView addSubview:aView];
|
||||||
|
|
||||||
|
_contentView = aView;
|
||||||
|
|
||||||
|
[self refreshDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sizeToFit
|
||||||
|
{
|
||||||
|
var offset = [self _titleHeightOffset],
|
||||||
|
size = [self frameSize];
|
||||||
|
|
||||||
|
[_boxView setFrame:CGRectMake(0, offset[1], size.width, size.height - offset[0])];
|
||||||
|
|
||||||
|
if (!_contentView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var boxSize = [_boxView frameSize];
|
||||||
|
|
||||||
|
if (_contentInset)
|
||||||
|
[_contentView setFrame:CGRectMake(_contentInset.left, _contentInset.top, boxSize.width - _contentInset.left - _contentInset.right, boxSize.height - _contentInset.top - _contentInset.bottom)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
# pragma mark -
|
||||||
|
|
||||||
|
// This subclass of CPSegmentedControl implements specific behaviour needed by CPTabView, which
|
||||||
|
// differs in some ways from normal CPSegmentedControl habits :
|
||||||
|
//
|
||||||
|
// - all items are enabled
|
||||||
|
// - when you select a tab (mouse down, holding) and drag upon another tab, the second one reacts
|
||||||
|
// (showing a pushed state) and can then be selected by releasing the mouse over it.
|
||||||
|
// - a delegate has the opportunity to accept or not the selection of an item
|
||||||
|
|
||||||
|
@implementation _CPSegmentedControl : CPSegmentedControl
|
||||||
|
{
|
||||||
|
CPTabView _tabView @accessors(property=tabView);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)trackSegment:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var type = [anEvent type],
|
||||||
|
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
currentSegment = [self testSegment:location];
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CPLeftMouseUp:
|
||||||
|
|
||||||
|
if (_trackingSegment === CPNotFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((_trackingSegment !== _selectedSegment) &&
|
||||||
|
[_tabView _sendDelegateShouldSelectTabViewItem:[_tabView tabViewItemAtIndex:_trackingSegment]])
|
||||||
|
{
|
||||||
|
[self setSelected:YES forSegment:_trackingSegment];
|
||||||
|
_selectedSegment = _trackingSegment;
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||||
|
|
||||||
|
_trackingSegment = CPNotFound;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CPLeftMouseDown:
|
||||||
|
|
||||||
|
if (currentSegment > CPNotFound)
|
||||||
|
{
|
||||||
|
_trackingSegment = currentSegment;
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPLeftMouseDragged:
|
||||||
|
|
||||||
|
if (_trackingSegment !== currentSegment)
|
||||||
|
{
|
||||||
|
if (_trackingSegment > CPNotFound)
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||||
|
|
||||||
|
_trackingSegment = currentSegment;
|
||||||
|
|
||||||
|
if (_trackingSegment > CPNotFound)
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|||||||
+103
-10
@@ -23,7 +23,8 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@class CPTabView
|
||||||
|
@class CPViewController
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The tab is currently selected.
|
The tab is currently selected.
|
||||||
@@ -53,14 +54,34 @@ CPPressedTab = 2;
|
|||||||
*/
|
*/
|
||||||
@implementation CPTabViewItem : CPObject
|
@implementation CPTabViewItem : CPObject
|
||||||
{
|
{
|
||||||
id _identifier;
|
id _identifier;
|
||||||
CPString _label;
|
CPString _label;
|
||||||
|
CPInteger _tag @accessors(property=tag);
|
||||||
|
|
||||||
CPView _view;
|
CPView _view;
|
||||||
CPView _auxiliaryView;
|
CPView _auxiliaryView;
|
||||||
|
|
||||||
CPTabView _tabView;
|
CPTabView _tabView;
|
||||||
unsigned _tabState; // Looks like it is not yet implemented
|
unsigned _tabState; // Looks like it is not yet implemented
|
||||||
|
|
||||||
|
CPImage _image @accessors(property=image);
|
||||||
|
CPViewController _viewController @accessors(getter=viewController);
|
||||||
|
|
||||||
|
BOOL _enabled @accessors(property=enabled);
|
||||||
|
BOOL _selected @accessors(property=selected);
|
||||||
|
CGRect _tabRect @accessors(property=frame);
|
||||||
|
float _width @accessors(property=width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
+ (CPTabViewItem)tabViewItemWithViewController:(CPViewController)aViewController
|
||||||
|
{
|
||||||
|
var item = [[CPTabViewItem alloc] init];
|
||||||
|
[item setViewController:aViewController];
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -68,6 +89,19 @@ CPPressedTab = 2;
|
|||||||
return [self initWithIdentifier:@""];
|
return [self initWithIdentifier:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_tag = 0;
|
||||||
|
_viewController = nil;
|
||||||
|
_image = nil;
|
||||||
|
_tabState = 0;
|
||||||
|
_tabView = nil;
|
||||||
|
_enabled = YES;
|
||||||
|
_selected = NO;
|
||||||
|
_tabRect = CGRectMakeZero();
|
||||||
|
_width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the tab view item with the specified identifier.
|
Initializes the tab view item with the specified identifier.
|
||||||
@return the initialized CPTabViewItem
|
@return the initialized CPTabViewItem
|
||||||
@@ -76,8 +110,12 @@ CPPressedTab = 2;
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
[self _init];
|
||||||
_identifier = anIdentifier;
|
|
||||||
|
_identifier = anIdentifier;
|
||||||
|
_label = nil;
|
||||||
|
_view = nil;
|
||||||
|
//_auxiliaryView = nil;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -89,7 +127,11 @@ CPPressedTab = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setLabel:(CPString)aLabel
|
- (void)setLabel:(CPString)aLabel
|
||||||
{
|
{
|
||||||
|
if ([aLabel isEqualToString:_label])
|
||||||
|
return;
|
||||||
|
|
||||||
_label = aLabel;
|
_label = aLabel;
|
||||||
|
[_tabView tileWithChangedItem:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -100,6 +142,28 @@ CPPressedTab = 2;
|
|||||||
return _label;
|
return _label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Working With Images
|
||||||
|
/*!
|
||||||
|
Sets the CPTabViewItem's image.
|
||||||
|
@param anImage the image for the item
|
||||||
|
*/
|
||||||
|
- (void)setImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
if ([anImage isEqual:_image])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_image = anImage;
|
||||||
|
[_tabView tileWithChangedItem:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the CPTabViewItem's image
|
||||||
|
*/
|
||||||
|
- (CPImage)image
|
||||||
|
{
|
||||||
|
return _image;
|
||||||
|
}
|
||||||
|
|
||||||
// Checking the Tab Display State
|
// Checking the Tab Display State
|
||||||
/*!
|
/*!
|
||||||
Returns the tab's current state.
|
Returns the tab's current state.
|
||||||
@@ -139,7 +203,7 @@ CPPressedTab = 2;
|
|||||||
_view = aView;
|
_view = aView;
|
||||||
|
|
||||||
if ([_tabView selectedTabViewItem] == self)
|
if ([_tabView selectedTabViewItem] == self)
|
||||||
[_tabView _setContentViewFromItem:self];
|
[_tabView _displayItemView:_view];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -147,6 +211,9 @@ CPPressedTab = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPView)view
|
- (CPView)view
|
||||||
{
|
{
|
||||||
|
if (!_view && _viewController)
|
||||||
|
return [_viewController view]; // The view controller loads here.
|
||||||
|
|
||||||
return _view;
|
return _view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,10 +252,32 @@ CPPressedTab = 2;
|
|||||||
_tabView = aView;
|
_tabView = aView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the specified view controller for the tab view item.
|
||||||
|
@param aViewController an instance of CPViewController.
|
||||||
|
*/
|
||||||
|
- (void)setViewController:(CPViewController)aViewController
|
||||||
|
{
|
||||||
|
_viewController = aViewController;
|
||||||
|
|
||||||
|
var identifier = [aViewController cibName],
|
||||||
|
title = [_viewController title];
|
||||||
|
|
||||||
|
if (identifier)
|
||||||
|
_identifier = identifier;
|
||||||
|
|
||||||
|
if (title)
|
||||||
|
[self setLabel:title];
|
||||||
|
|
||||||
|
if ([_tabView selectedTabViewItem] == self)
|
||||||
|
[_tabView _loadTabViewItem:self];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||||
CPTabViewItemLabelKey = "CPTabViewItemLabelKey",
|
CPTabViewItemLabelKey = "CPTabViewItemLabelKey",
|
||||||
|
CPTabViewItemImageKey = "CPTabViewItemImageKey",
|
||||||
CPTabViewItemViewKey = "CPTabViewItemViewKey",
|
CPTabViewItemViewKey = "CPTabViewItemViewKey",
|
||||||
CPTabViewItemAuxViewKey = "CPTabViewItemAuxViewKey";
|
CPTabViewItemAuxViewKey = "CPTabViewItemAuxViewKey";
|
||||||
|
|
||||||
@@ -201,8 +290,11 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
[self _init];
|
||||||
|
|
||||||
_identifier = [aCoder decodeObjectForKey:CPTabViewItemIdentifierKey];
|
_identifier = [aCoder decodeObjectForKey:CPTabViewItemIdentifierKey];
|
||||||
_label = [aCoder decodeObjectForKey:CPTabViewItemLabelKey];
|
_label = [aCoder decodeObjectForKey:CPTabViewItemLabelKey];
|
||||||
|
_image = [aCoder decodeObjectForKey:CPTabViewItemImageKey];
|
||||||
|
|
||||||
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
|
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
|
||||||
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
|
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
|
||||||
@@ -215,6 +307,7 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
|||||||
{
|
{
|
||||||
[aCoder encodeObject:_identifier forKey:CPTabViewItemIdentifierKey];
|
[aCoder encodeObject:_identifier forKey:CPTabViewItemIdentifierKey];
|
||||||
[aCoder encodeObject:_label forKey:CPTabViewItemLabelKey];
|
[aCoder encodeObject:_label forKey:CPTabViewItemLabelKey];
|
||||||
|
[aCoder encodeObject:_image forKey:CPTabViewItemImageKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_view forKey:CPTabViewItemViewKey];
|
[aCoder encodeObject:_view forKey:CPTabViewItemViewKey];
|
||||||
[aCoder encodeObject:_auxiliaryView forKey:CPTabViewItemAuxViewKey];
|
[aCoder encodeObject:_auxiliaryView forKey:CPTabViewItemAuxViewKey];
|
||||||
|
|||||||
+80
-29
@@ -28,9 +28,8 @@
|
|||||||
|
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
@global CPTableViewColumnDidResizeNotification
|
|
||||||
|
|
||||||
@class _CPTableColumnHeaderView
|
@class _CPTableColumnHeaderView
|
||||||
|
@class CPTableView
|
||||||
|
|
||||||
CPTableColumnNoResizing = 0;
|
CPTableColumnNoResizing = 0;
|
||||||
CPTableColumnAutoresizingMask = 1 << 0;
|
CPTableColumnAutoresizingMask = 1 << 0;
|
||||||
@@ -181,11 +180,11 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
|
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
|
||||||
|
|
||||||
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
|
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
|
||||||
[tableView _layoutDataViewsInRows:rows columns:columns];
|
[tableView _layoutViewsForRowIndexes:rows columnIndexes:columns];
|
||||||
[tableView tile];
|
[tableView tile];
|
||||||
|
|
||||||
if (!_disableResizingPosting)
|
if (!_disableResizingPosting)
|
||||||
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
[[self tableView] _didResizeTableColumn:self oldWidth:oldWidth];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +287,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
if (width < [self minWidth])
|
if (width < [self minWidth])
|
||||||
[self setMinWidth:width];
|
[self setMinWidth:width];
|
||||||
else if (width > [self maxWidth])
|
else if (width > [self maxWidth])
|
||||||
[self setMaxWidth:width]
|
[self setMaxWidth:width];
|
||||||
|
|
||||||
if (_width !== width)
|
if (_width !== width)
|
||||||
[self setWidth:width];
|
[self setWidth:width];
|
||||||
@@ -394,8 +393,8 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
*/
|
*/
|
||||||
- (void)setDataView:(CPView)aView
|
- (void)setDataView:(CPView)aView
|
||||||
{
|
{
|
||||||
if (_dataView)
|
if (_dataView === aView)
|
||||||
_dataViewData = nil;
|
return;
|
||||||
|
|
||||||
[aView setThemeState:CPThemeStateTableDataView];
|
[aView setThemeState:CPThemeStateTableDataView];
|
||||||
|
|
||||||
@@ -500,7 +499,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
*/
|
*/
|
||||||
- (void)setHidden:(BOOL)shouldBeHidden
|
- (void)setHidden:(BOOL)shouldBeHidden
|
||||||
{
|
{
|
||||||
shouldBeHidden = !!shouldBeHidden
|
shouldBeHidden = !!shouldBeHidden;
|
||||||
|
|
||||||
if (_isHidden === shouldBeHidden)
|
if (_isHidden === shouldBeHidden)
|
||||||
return;
|
return;
|
||||||
@@ -541,14 +540,9 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
/*!
|
/*!
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
|
- (CPString)description
|
||||||
{
|
{
|
||||||
[[self tableView] _didResizeTableColumn:self];
|
return [CPString stringWithFormat:"<%@ 0x%@ identifier=%@>", [self className], [CPString stringWithHash:[self UID]], [self identifier]];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
|
||||||
object:[self tableView]
|
|
||||||
userInfo:@{ @"CPTableColumn": self, @"CPOldWidth": oldWidth }];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -560,11 +554,22 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
- (void)setValueFor:(CPString)aBinding
|
- (void)setValueFor:(CPString)aBinding
|
||||||
{
|
{
|
||||||
var tableView = [_source tableView],
|
var tableView = [_source tableView],
|
||||||
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
|
newNumberOfRows = [tableView _numberOfRows];
|
||||||
rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [tableView numberOfRows])],
|
|
||||||
columnIndexes = [CPIndexSet indexSetWithIndex:column];
|
|
||||||
|
|
||||||
[tableView reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
|
if ([tableView numberOfRows] == newNumberOfRows)
|
||||||
|
{
|
||||||
|
var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, newNumberOfRows)],
|
||||||
|
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
|
||||||
|
columnIndexes = [CPIndexSet indexSetWithIndex:column];
|
||||||
|
|
||||||
|
// Reloads objectValues only, not the views.
|
||||||
|
// FIXME: reload data for all rows or just rows intersecting exposed rows ?
|
||||||
|
[tableView _reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[tableView reloadData];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPSortDescriptor)_defaultSortDescriptorPrototype
|
- (CPSortDescriptor)_defaultSortDescriptorPrototype
|
||||||
@@ -588,7 +593,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
{
|
{
|
||||||
var options = [_info objectForKey:CPOptionsKey],
|
var options = [_info objectForKey:CPOptionsKey],
|
||||||
optionValue = [options objectForKey:CPCreatesSortDescriptorBindingOption];
|
optionValue = [options objectForKey:CPCreatesSortDescriptorBindingOption];
|
||||||
return optionValue === nil ? YES : [optionValue boolValue];
|
return optionValue == nil ? YES : [optionValue boolValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -604,7 +609,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Binds the receiver to an object.
|
Binds the receiver to an object. Note that unlike Cocoa, this works only *after* the receiver has been added to a \c CPTableView.
|
||||||
|
|
||||||
@param CPString aBinding - The binding you wish to make. Typically CPValueBinding.
|
@param CPString aBinding - The binding you wish to make. Typically CPValueBinding.
|
||||||
@param id anObject - The object to bind the receiver to.
|
@param id anObject - The object to bind the receiver to.
|
||||||
@@ -634,6 +639,53 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
This method will return the object at a row in the first found CPArray in the key path
|
||||||
|
that is divided in a first and second part.
|
||||||
|
The first part is never a combined key path. The second part can be a combined key path.
|
||||||
|
If this optimization is not done we will create an array with the valueForKeyPath value on each row and then pick
|
||||||
|
the wanted value for the row and throw away all the other rows. It is much more effective to first
|
||||||
|
pick the row and then do the valueForKeyPath on the rest of the key path.
|
||||||
|
When the second part is depleated it will stop the search for a CPArray and return the
|
||||||
|
current object for the first part. The second part will then be nil.
|
||||||
|
The secondPartRef will always be updated with the rest of the key path that can be applied
|
||||||
|
to the returned object.
|
||||||
|
It will stop the search if the object is nil
|
||||||
|
*/
|
||||||
|
- (CPValueCoding)_firstObjectInArrayUsingKeyPathFirstPart:(CPString)firstPart secondPart:(CPStringRef)secondPartRef sourceObject:(CPValueCoding)source forRow:(unsigned)aRow
|
||||||
|
{
|
||||||
|
var firstValue = [source valueForKeyPath:firstPart];
|
||||||
|
|
||||||
|
if (firstValue == nil)
|
||||||
|
return firstValue;
|
||||||
|
|
||||||
|
if ([firstValue isKindOfClass:CPArray])
|
||||||
|
return [firstValue objectAtIndex:aRow];
|
||||||
|
|
||||||
|
var secondPart = @deref(secondPartRef);
|
||||||
|
|
||||||
|
if (secondPart == nil)
|
||||||
|
return firstValue;
|
||||||
|
|
||||||
|
var dotIndex = secondPart.indexOf(".");
|
||||||
|
|
||||||
|
if (dotIndex === CPNotFound)
|
||||||
|
{
|
||||||
|
firstPart = secondPart;
|
||||||
|
@deref(secondPartRef) = nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstPart = secondPart.substring(0, dotIndex);
|
||||||
|
@deref(secondPartRef) = secondPart.substring(dotIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self _firstObjectInArrayUsingKeyPathFirstPart:firstPart secondPart:secondPartRef sourceObject:firstValue forRow:aRow];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
@@ -650,7 +702,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
bindingInfo = binding._info,
|
bindingInfo = binding._info,
|
||||||
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
||||||
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
||||||
dotIndex = keyPath.lastIndexOf("."),
|
dotIndex = keyPath.indexOf("."),
|
||||||
value;
|
value;
|
||||||
|
|
||||||
if (dotIndex === CPNotFound)
|
if (dotIndex === CPNotFound)
|
||||||
@@ -665,17 +717,16 @@ CPTableColumnUserResizingMask = 1 << 1;
|
|||||||
|
|
||||||
The optimization is to get the array and access the value directly. This
|
The optimization is to get the array and access the value directly. This
|
||||||
turns the operation into a single access regardless of how long the model
|
turns the operation into a single access regardless of how long the model
|
||||||
array is.
|
array is or how long the key path is.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var firstPart = keyPath.substring(0, dotIndex),
|
var firstPart = keyPath.substring(0, dotIndex),
|
||||||
secondPart = keyPath.substring(dotIndex + 1),
|
secondPart = keyPath.substring(dotIndex + 1);
|
||||||
firstValue = [destination valueForKeyPath:firstPart];
|
|
||||||
|
|
||||||
if ([firstValue isKindOfClass:CPArray])
|
value = [self _firstObjectInArrayUsingKeyPathFirstPart:firstPart secondPart:@ref(secondPart) sourceObject:destination forRow:aRow];
|
||||||
value = [[firstValue objectAtIndex:aRow] valueForKeyPath:secondPart];
|
|
||||||
else
|
if (secondPart != nil)
|
||||||
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
|
value = [value valueForKeyPath:secondPart];
|
||||||
}
|
}
|
||||||
|
|
||||||
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
|
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
|
||||||
|
|||||||
+414
-365
File diff suppressed because it is too large
Load Diff
+1108
-840
File diff suppressed because it is too large
Load Diff
+337
-1
@@ -5,6 +5,13 @@
|
|||||||
* Created by Alexander Ljungberg.
|
* Created by Alexander Ljungberg.
|
||||||
* Copyright 2010, WireLoad, LLC.
|
* Copyright 2010, WireLoad, LLC.
|
||||||
*
|
*
|
||||||
|
* additions from
|
||||||
|
*
|
||||||
|
* Daniel Boehringer on 8/02/2014.
|
||||||
|
* Copyright Daniel Boehringer on 8/02/2014.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -20,6 +27,30 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/Foundation.j>
|
||||||
|
|
||||||
|
@import "CPPasteboard.j"
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@global CPStringPboardType
|
||||||
|
@global _CPSmartPboardType
|
||||||
|
|
||||||
|
@class CPAttributedString
|
||||||
|
@class _CPRTFParser
|
||||||
|
|
||||||
|
@protocol CPTextDelegate <CPObject>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (BOOL)textShouldBeginEditing:(CPText)aTextObject;
|
||||||
|
- (BOOL)textShouldEndEditing:(CPText)aTextObject;
|
||||||
|
- (void)textDidBeginEditing:(CPNotification)aNotification;
|
||||||
|
- (void)textDidChange:(CPNotification)aNotification;
|
||||||
|
- (void)textDidEndEditing:(CPNotification)aNotification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
CPParagraphSeparatorCharacter = 0x2029;
|
||||||
|
CPLineSeparatorCharacter = 0x2028;
|
||||||
CPEnterCharacter = "\u0003";
|
CPEnterCharacter = "\u0003";
|
||||||
CPBackspaceCharacter = "\u0008";
|
CPBackspaceCharacter = "\u0008";
|
||||||
CPTabCharacter = "\u0009";
|
CPTabCharacter = "\u0009";
|
||||||
@@ -29,6 +60,7 @@ CPCarriageReturnCharacter = "\u000d";
|
|||||||
CPBackTabCharacter = "\u0019";
|
CPBackTabCharacter = "\u0019";
|
||||||
CPDeleteCharacter = "\u007f";
|
CPDeleteCharacter = "\u007f";
|
||||||
|
|
||||||
|
@typedef CPTextMovement
|
||||||
CPIllegalTextMovement = 0;
|
CPIllegalTextMovement = 0;
|
||||||
CPOtherTextMovement = 0;
|
CPOtherTextMovement = 0;
|
||||||
CPReturnTextMovement = 16;
|
CPReturnTextMovement = 16;
|
||||||
@@ -38,4 +70,308 @@ CPLeftTextMovement = 19;
|
|||||||
CPRightTextMovement = 20;
|
CPRightTextMovement = 20;
|
||||||
CPUpTextMovement = 21;
|
CPUpTextMovement = 21;
|
||||||
CPDownTextMovement = 22;
|
CPDownTextMovement = 22;
|
||||||
CPCancelTextMovement = 23;
|
CPCancelTextMovement = 23;
|
||||||
|
|
||||||
|
@typedef CPWritingDirection
|
||||||
|
CPWritingDirectionNatural = -1;
|
||||||
|
CPWritingDirectionLeftToRight = 0;
|
||||||
|
CPWritingDirectionRightToLeft = 1;
|
||||||
|
|
||||||
|
@typedef CPTextAlignment
|
||||||
|
CPLeftTextAlignment = 0;
|
||||||
|
CPRightTextAlignment = 1;
|
||||||
|
CPCenterTextAlignment = 2;
|
||||||
|
CPJustifiedTextAlignment = 3;
|
||||||
|
CPNaturalTextAlignment = 4;
|
||||||
|
|
||||||
|
@typedef CPUnderlineStyle
|
||||||
|
CPUnderlineStyleNone = 0;
|
||||||
|
CPUnderlineStyleSingle = 1;
|
||||||
|
CPUnderlineStyleThick = 2;
|
||||||
|
CPUnderlineStyleDouble = 3;
|
||||||
|
CPUnderlineStylePatternSolid = 4;
|
||||||
|
CPUnderlineStylePatternDot = 5;
|
||||||
|
CPUnderlineStylePatternDash = 6;
|
||||||
|
CPUnderlineStylePatternDashDot = 7;
|
||||||
|
CPUnderlineStylePatternDashDotDot = 8;
|
||||||
|
CPUnderlineStyleByWord = 9;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CPText notifications
|
||||||
|
*/
|
||||||
|
CPTextDidBeginEditingNotification = @"CPTextDidBeginEditingNotification";
|
||||||
|
CPTextDidChangeNotification = @"CPTextDidChangeNotification";
|
||||||
|
CPTextDidEndEditingNotification = @"CPTextDidEndEditingNotification";
|
||||||
|
|
||||||
|
/*
|
||||||
|
CPTextView Notifications
|
||||||
|
*/
|
||||||
|
CPTextViewDidChangeSelectionNotification = @"CPTextViewDidChangeSelectionNotification";
|
||||||
|
CPTextViewDidChangeTypingAttributesNotification = @"CPTextViewDidChangeTypingAttributesNotification";
|
||||||
|
|
||||||
|
/*
|
||||||
|
FIXME: move these to CPAttributed string
|
||||||
|
Make use of attributed keys in AppKit
|
||||||
|
*/
|
||||||
|
CPFontAttributeName = @"CPFontAttributeName";
|
||||||
|
CPForegroundColorAttributeName = @"CPForegroundColorAttributeName";
|
||||||
|
CPBackgroundColorAttributeName = @"CPBackgroundColorAttributeName";
|
||||||
|
CPShadowAttributeName = @"CPShadowAttributeName";
|
||||||
|
CPUnderlineStyleAttributeName = @"CPUnderlineStyleAttributeName";
|
||||||
|
CPSuperscriptAttributeName = @"CPSuperscriptAttributeName";
|
||||||
|
CPBaselineOffsetAttributeName = @"CPBaselineOffsetAttributeName";
|
||||||
|
CPAttachmentAttributeName = @"CPAttachmentAttributeName";
|
||||||
|
CPLigatureAttributeName = @"CPLigatureAttributeName";
|
||||||
|
CPKernAttributeName = @"CPKernAttributeName";
|
||||||
|
|
||||||
|
@implementation CPText : CPView
|
||||||
|
{
|
||||||
|
BOOL _isEditable @accessors(getter=isEditable, setter=setEditable:);
|
||||||
|
BOOL _isSelectable @accessors(getter=isSelectable, setter=setSelectable:);
|
||||||
|
BOOL _isRichText @accessors(getter=isRichText, setter=setRichText:);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectable:(BOOL)flag
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"selectable"];
|
||||||
|
_isSelectable = flag;
|
||||||
|
[self didChangeValueForKey:@"selectable"];
|
||||||
|
|
||||||
|
if (!flag)
|
||||||
|
[self setEditable:flag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setEditable:(BOOL)flag
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"editable"];
|
||||||
|
_isEditable = flag;
|
||||||
|
[self didChangeValueForKey:@"editable"];
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
[self setSelectable:flag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)changeFont:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copy:(id)sender
|
||||||
|
{
|
||||||
|
var selectedRange = [self selectedRange];
|
||||||
|
|
||||||
|
if (selectedRange.length < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var pasteboard = [CPPasteboard generalPasteboard];
|
||||||
|
|
||||||
|
// put plain representation on the pasteboad unconditionally
|
||||||
|
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||||
|
[pasteboard setString:[[self stringValue] substringWithRange:selectedRange] forType:CPStringPboardType];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_plainStringForPasting
|
||||||
|
{
|
||||||
|
return [[CPPasteboard generalPasteboard] stringForType:CPStringPboardType];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_stringForPasting
|
||||||
|
{
|
||||||
|
var pasteboard = [CPPasteboard generalPasteboard],
|
||||||
|
dataForPasting = [pasteboard stringForType:CPRTFPboardType],
|
||||||
|
stringForPasting = [pasteboard stringForType:CPStringPboardType],
|
||||||
|
attributedStringData = [pasteboard stringForType:_CPASPboardType];
|
||||||
|
|
||||||
|
if ([self isRichText] && attributedStringData)
|
||||||
|
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPData dataWithRawString:attributedStringData]];
|
||||||
|
|
||||||
|
if (dataForPasting || [stringForPasting hasPrefix:"{\\rtf1\\ansi"])
|
||||||
|
stringForPasting = [[_CPRTFParser new] parseRTF:dataForPasting ? dataForPasting : stringForPasting];
|
||||||
|
|
||||||
|
if (![self isRichText] && [stringForPasting isKindOfClass:[CPAttributedString class]])
|
||||||
|
stringForPasting = stringForPasting._string;
|
||||||
|
|
||||||
|
return stringForPasting;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_shouldUseSmartPasting
|
||||||
|
{
|
||||||
|
return parseInt([[CPPasteboard generalPasteboard] stringForType:_CPSmartPboardType], 10) > 0 || NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)paste:(id)sender
|
||||||
|
{
|
||||||
|
var stringForPasting = [self _stringForPasting];
|
||||||
|
|
||||||
|
if (stringForPasting)
|
||||||
|
[self insertText:stringForPasting];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFont:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)delete:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPFont)font:(CPFont)aFont
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isHorizontallyResizable
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isRulerVisible
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isVerticallyResizable
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)maxSize
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return CGSizeMake(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)minSize
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
return CGSizeMake(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pasteFont:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollRangeToVisible:(CPRange)aRange
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectedAll:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPRange)selectedRange
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return CPMakeRange(CPNotFound, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont range:(CPRange)aRange
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHorizontallyResizable:(BOOL)flag
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMaxSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMinSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setString:(CPString)aString
|
||||||
|
{
|
||||||
|
[self replaceCharactersInRange:CPMakeRange(0, [[self string] length]) withString:aString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setUsesFontPanel:(BOOL)flag
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVerticallyResizable:(BOOL)flag
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)string
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)underline:(id)sender
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)usesFontPanel
|
||||||
|
{
|
||||||
|
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPTextViewIsEditableKey = @"CPTextViewIsEditableKey",
|
||||||
|
CPTextViewIsSelectableKey = @"CPTextViewIsSelectableKey",
|
||||||
|
CPTextViewIsRichTextKey = @"CPTextViewIsRichTextKey";
|
||||||
|
|
||||||
|
@implementation CPText (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
[self setSelectable:[aCoder decodeBoolForKey:CPTextViewIsSelectableKey]];
|
||||||
|
[self setEditable:[aCoder decodeBoolForKey:CPTextViewIsEditableKey]];
|
||||||
|
[self setRichText:[aCoder decodeBoolForKey:CPTextViewIsRichTextKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
[aCoder encodeBool:_isEditable forKey:CPTextViewIsEditableKey];
|
||||||
|
[aCoder encodeBool:_isSelectable forKey:CPTextViewIsSelectableKey];
|
||||||
|
[aCoder encodeBool:_isRichText forKey:CPTextViewIsRichTextKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user