mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-30 14:17:40 +00:00
Compare commits
4476
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 | ||
|
|
7662f89193 | ||
|
|
dbb59f57ea | ||
|
|
c1f538ece5 | ||
|
|
b4cabc97d1 | ||
|
|
cf2e66d7fe | ||
|
|
e511638962 | ||
|
|
8419001810 | ||
|
|
e058d2e143 | ||
|
|
40da5a849d | ||
|
|
616f0c61ef | ||
|
|
d0ef8a2885 | ||
|
|
985db21ed9 | ||
|
|
d0460ad202 | ||
|
|
8ca7227185 | ||
|
|
6c8a21c1cc | ||
|
|
4a82dbc34d | ||
|
|
1cec1b0637 | ||
|
|
abd9506d40 | ||
|
|
8f7a32141b | ||
|
|
ff067374bc | ||
|
|
6cbfa30652 | ||
|
|
f5a1a6725d | ||
|
|
2508fa7a97 | ||
|
|
0b351ac2d7 | ||
|
|
24b44c2acf | ||
|
|
8f70cebefc | ||
|
|
6e7fc5c887 | ||
|
|
7f53d15e75 | ||
|
|
ad170ed854 | ||
|
|
d3ab2a0f3d | ||
|
|
af26523e36 | ||
|
|
ebc1025fd9 | ||
|
|
a96242324a | ||
|
|
d1406e1b8f | ||
|
|
c22f489ee9 | ||
|
|
0ac74fe16e | ||
|
|
df2be926a5 | ||
|
|
71ed0d6cfc | ||
|
|
2d96875574 | ||
|
|
949c618ff1 | ||
|
|
8909576a0b | ||
|
|
0afc903138 | ||
|
|
8971972a28 | ||
|
|
2df13b7ffc | ||
|
|
bb6b5c1232 | ||
|
|
ab1c689e4e | ||
|
|
7bdedca350 | ||
|
|
e1eac245a7 | ||
|
|
cf19aef382 | ||
|
|
d6e40332c4 | ||
|
|
4b8a6ee674 | ||
|
|
406a049380 | ||
|
|
b2dc9c225c | ||
|
|
86e94178e3 | ||
|
|
f75955bb04 | ||
|
|
f0a9696634 | ||
|
|
016c267e69 | ||
|
|
f6028455b7 | ||
|
|
ed99833894 | ||
|
|
ef5f26fd81 | ||
|
|
2f18218ce5 | ||
|
|
0b5a98d3fe | ||
|
|
918543d617 | ||
|
|
6f8d6a5b25 | ||
|
|
95082c3263 | ||
|
|
8503081a6f | ||
|
|
6efefbedcd | ||
|
|
eef91c0240 | ||
|
|
5cefce1cf0 | ||
|
|
f0e2daf6c7 | ||
|
|
9f0d8c54e4 | ||
|
|
b20d711922 | ||
|
|
23fb618596 | ||
|
|
2dff348cca | ||
|
|
ba0604320e | ||
|
|
c979a69e6b | ||
|
|
40e06a634e | ||
|
|
30441b109f | ||
|
|
f17fd6a448 | ||
|
|
0e4ad998d8 | ||
|
|
9eebb0a64b | ||
|
|
9f7d0578e5 | ||
|
|
0afe21dd29 | ||
|
|
cfc682c165 | ||
|
|
c326168e83 | ||
|
|
b8b96a17d7 | ||
|
|
48d98f7ebd | ||
|
|
7044c1cda4 | ||
|
|
594ea6e5cb | ||
|
|
957a572bcd | ||
|
|
08eff6ec22 | ||
|
|
3fb12f6382 | ||
|
|
5958220bdd | ||
|
|
648dc6e86c | ||
|
|
9d43a559fe | ||
|
|
168738fb93 | ||
|
|
376b3a496e | ||
|
|
58d5d7d731 | ||
|
|
f637931ba7 | ||
|
|
ec4b348369 | ||
|
|
879ede5d70 | ||
|
|
1e7dd0dc59 | ||
|
|
f1077719fb | ||
|
|
c9dae8ced4 | ||
|
|
4e4fc389d2 | ||
|
|
fa86c54fff | ||
|
|
2065c7fbc8 | ||
|
|
100efc6450 | ||
|
|
987d2a2d73 | ||
|
|
63dac5553e | ||
|
|
0b75876283 | ||
|
|
beec0c5293 | ||
|
|
672ed6ed0c | ||
|
|
d6f1c2bc57 | ||
|
|
3b8aedf5aa | ||
|
|
d40449c469 | ||
|
|
8bdbb5d333 | ||
|
|
638d8de472 | ||
|
|
03acecdec9 | ||
|
|
f74312dc42 | ||
|
|
2e216d7e9a | ||
|
|
0e7b592786 | ||
|
|
29d7833fcb | ||
|
|
4eba639c73 | ||
|
|
361f421816 | ||
|
|
bb58a206a8 | ||
|
|
4775b594f5 | ||
|
|
a90180a92f | ||
|
|
377618dcd4 | ||
|
|
1cfc8139b9 | ||
|
|
4b4ac5d8b7 | ||
|
|
7c2c2a3114 | ||
|
|
c0dce226bf | ||
|
|
2fcf1f4ac4 | ||
|
|
8d47b3f048 | ||
|
|
06e392ee22 | ||
|
|
d38125db13 | ||
|
|
3beb753c63 | ||
|
|
d751fea510 | ||
|
|
42ad40d10d | ||
|
|
86e5c15e3c | ||
|
|
6bec4064b5 | ||
|
|
fc931902d7 | ||
|
|
d336c30ab6 | ||
|
|
9fb966d0ca | ||
|
|
3c2a2f39fc | ||
|
|
2183c6d383 | ||
|
|
e61b6783b3 | ||
|
|
7f089972bd | ||
|
|
5a7c2e5617 | ||
|
|
ceb22a47c5 | ||
|
|
3c9435ed21 | ||
|
|
9e7346f1e8 | ||
|
|
4221acf3fd | ||
|
|
b49a872806 | ||
|
|
655bc0348b | ||
|
|
2b23374ec7 | ||
|
|
1df1c1e9ab | ||
|
|
084bc84160 | ||
|
|
d8281a6e22 | ||
|
|
bdd29936d7 | ||
|
|
f3f1f72ae2 | ||
|
|
2da6c88fad | ||
|
|
b03e354dbf | ||
|
|
5b62773a39 | ||
|
|
5c211b350e | ||
|
|
2c6ab1714f | ||
|
|
17fe9b0f60 | ||
|
|
639670e47d | ||
|
|
27165db513 | ||
|
|
650bc77b2c | ||
|
|
a5e62ed132 | ||
|
|
56963d65f3 | ||
|
|
771370e64b | ||
|
|
0bd670b2a3 | ||
|
|
e0af5d0573 | ||
|
|
23d2a71649 | ||
|
|
3419f6fbb4 | ||
|
|
2ca020f3a9 | ||
|
|
778843593b | ||
|
|
64f962e29a | ||
|
|
90fe91d63e | ||
|
|
d404d027c2 | ||
|
|
b0babdb7bb | ||
|
|
0f53ceda30 | ||
|
|
315e3fccf3 | ||
|
|
2973743a0d | ||
|
|
083310c44f | ||
|
|
54d13c8fc9 | ||
|
|
fbc869ad29 | ||
|
|
f52f11899a | ||
|
|
fc403d679c | ||
|
|
e8b2f2e39f | ||
|
|
b258b1a164 | ||
|
|
0badf30763 | ||
|
|
c68b174be5 | ||
|
|
d61d4ebbe7 | ||
|
|
e7ecd92cbc | ||
|
|
93c27625b9 | ||
|
|
8d7c47a5e4 | ||
|
|
6ef776e488 | ||
|
|
d9e3542c34 | ||
|
|
093ac8cf54 | ||
|
|
757c79d15c | ||
|
|
8dd252eee1 | ||
|
|
f318759a4a | ||
|
|
85985add3c | ||
|
|
9d435e0f8a | ||
|
|
2b0754c6a0 | ||
|
|
0ead233cba | ||
|
|
5d07eb7316 | ||
|
|
198857e0ad | ||
|
|
a4aed913d7 | ||
|
|
613a20a639 | ||
|
|
e59389b0dd | ||
|
|
22905745f1 | ||
|
|
d3a44cbc63 | ||
|
|
a9a0b1c7d9 | ||
|
|
72169e54d8 | ||
|
|
bf94dd3a6e | ||
|
|
fe79628034 | ||
|
|
563300a16f | ||
|
|
29c336f7b8 | ||
|
|
b0b0452647 | ||
|
|
abd382d9c2 | ||
|
|
36c2672064 | ||
|
|
5bab2e1469 | ||
|
|
df7a6930c2 | ||
|
|
45c75235a5 | ||
|
|
0d283231a2 | ||
|
|
4652db7246 | ||
|
|
22dcacd8ce | ||
|
|
e2339ee1c6 | ||
|
|
6ab650346b | ||
|
|
2cbc4d93bd | ||
|
|
8bf2118b6e | ||
|
|
566521f854 | ||
|
|
c7c3bdd543 | ||
|
|
50d3bfd456 | ||
|
|
6a516873b7 | ||
|
|
827b9c4c57 | ||
|
|
3b48aafe66 | ||
|
|
8d7e2f9ec6 | ||
|
|
295443f2e3 | ||
|
|
595736b8c6 | ||
|
|
8f17f904f2 | ||
|
|
668eb1f8c4 | ||
|
|
3159021d27 | ||
|
|
fc4413d56b | ||
|
|
8b7eb1815d | ||
|
|
cb187c3e8f | ||
|
|
25f54c83ed | ||
|
|
a79ac2e9e4 | ||
|
|
b5df5f730b | ||
|
|
a2257dab8f | ||
|
|
ee4112b7f1 | ||
|
|
1d896c6ac9 | ||
|
|
42bc87d9ca | ||
|
|
85e71017d9 | ||
|
|
d8c8694c0d | ||
|
|
305fbb8ce2 | ||
|
|
0c613f1dde | ||
|
|
14ab582a53 | ||
|
|
6c2062c1f0 | ||
|
|
7385f04d7f | ||
|
|
9d76ab70fe | ||
|
|
ce22cebf07 | ||
|
|
22d66438fb | ||
|
|
de4e28b5cc | ||
|
|
5e0793c2ac | ||
|
|
54dd027c15 | ||
|
|
ad33411ec6 | ||
|
|
6bac934d0c | ||
|
|
8c5015a0bc | ||
|
|
302138c257 | ||
|
|
501310c058 | ||
|
|
cb2ba64a73 | ||
|
|
de1d6aad9c | ||
|
|
391ff7279d | ||
|
|
1d1016f08e | ||
|
|
d040e60f60 | ||
|
|
3808427f24 | ||
|
|
b3e6eb74b2 | ||
|
|
392aafb360 | ||
|
|
6556ccef80 | ||
|
|
f96e934cf8 | ||
|
|
44a872659a | ||
|
|
256c5b83da | ||
|
|
5e6c89ca8b | ||
|
|
bf4a5b2c9a | ||
|
|
6701117945 | ||
|
|
f2d9ef7720 | ||
|
|
3fb0dd725a | ||
|
|
a324cb3306 | ||
|
|
2a9f3deb0e | ||
|
|
89e81e97d1 | ||
|
|
b4fb4ba941 | ||
|
|
eb859d42a4 | ||
|
|
9d86391bdb | ||
|
|
9b709b85a9 | ||
|
|
9bde63923c | ||
|
|
d7c676893d | ||
|
|
8bc8ae4e3b | ||
|
|
35b4e8f653 | ||
|
|
7837277cbe | ||
|
|
8145df9613 | ||
|
|
9ffa184056 | ||
|
|
d7b5382c32 | ||
|
|
e047212f5f | ||
|
|
574672f15f | ||
|
|
9b3676fa4f | ||
|
|
57d5dac72a | ||
|
|
626e1e770e | ||
|
|
75b3bf22e6 | ||
|
|
48be680fde | ||
|
|
e95856dadd | ||
|
|
86d7ec4180 | ||
|
|
a63bb155c2 | ||
|
|
01291591b7 | ||
|
|
e7ad1a1f7a | ||
|
|
2e0b204b8d | ||
|
|
77f8136e79 | ||
|
|
e45c05b08e | ||
|
|
14eff74652 | ||
|
|
14fec1a608 | ||
|
|
7034635b8e | ||
|
|
19aee142de | ||
|
|
218eed7e97 | ||
|
|
ec3fb2bd33 | ||
|
|
b4a2ba4fc6 | ||
|
|
1e828b2e8d | ||
|
|
4c94691b6f | ||
|
|
2b273b1e12 | ||
|
|
f8faf5199d | ||
|
|
eb312d5f66 | ||
|
|
7fc7632971 | ||
|
|
e22d6e0217 | ||
|
|
a11de15e33 | ||
|
|
eb04174e68 | ||
|
|
97f93a031f | ||
|
|
1f280b3985 | ||
|
|
e0d33a8e3f | ||
|
|
345a54e8c9 | ||
|
|
21301cae21 | ||
|
|
f8513eae26 | ||
|
|
ee9b04944a | ||
|
|
e9ca7c7395 | ||
|
|
2abe573bfe | ||
|
|
0aad32ba86 | ||
|
|
a24aacdb3e | ||
|
|
d2b1968dec | ||
|
|
9ee7535039 | ||
|
|
d723c7306a | ||
|
|
9dd642395f | ||
|
|
2b5cf1a56d | ||
|
|
1f4b49c461 | ||
|
|
e20f2b75f0 | ||
|
|
550401dffe | ||
|
|
4d8f7c67d4 | ||
|
|
f9dad2c1b3 | ||
|
|
eacc527c5f | ||
|
|
30e9389a92 | ||
|
|
e5fc452063 | ||
|
|
7477294648 | ||
|
|
16b2334274 | ||
|
|
7b59ec93df | ||
|
|
23ef587f68 | ||
|
|
72455f43d4 | ||
|
|
e8828fe0bc | ||
|
|
3430684c22 | ||
|
|
3357162660 | ||
|
|
2e93e4abf7 | ||
|
|
3e268a88b3 | ||
|
|
6de967345c | ||
|
|
a38d6c11b4 | ||
|
|
807387463f | ||
|
|
52a53fb8d1 | ||
|
|
6bd9a08460 | ||
|
|
81a61c1412 | ||
|
|
811c7444df | ||
|
|
a5a9bbf1a7 | ||
|
|
12cf674595 | ||
|
|
7ccf7c731c | ||
|
|
d3a4ce4608 | ||
|
|
920204fc63 | ||
|
|
2d8d68dc5e | ||
|
|
736dffa334 | ||
|
|
bd2a7b2b7b | ||
|
|
fc8ca14743 | ||
|
|
15cf818b1e | ||
|
|
cf9b630401 | ||
|
|
3cc6b8dfbe | ||
|
|
bf6ce64209 | ||
|
|
afdad97aad | ||
|
|
7e27de8a1e | ||
|
|
949af39041 | ||
|
|
2104c838bd | ||
|
|
ee1c7a5f01 | ||
|
|
6d77faa7dd | ||
|
|
f4dc139675 | ||
|
|
73d62029ba | ||
|
|
b38f845643 | ||
|
|
cdef68034d | ||
|
|
467036bf34 | ||
|
|
934dedecd2 | ||
|
|
bd96d1b5e2 | ||
|
|
01920e674d | ||
|
|
0ec218a599 | ||
|
|
db21168a93 | ||
|
|
606205b58d | ||
|
|
1aa0956b4d | ||
|
|
14ee789df4 | ||
|
|
d400617c1b | ||
|
|
056a00e54e | ||
|
|
0b7e92aa53 | ||
|
|
9cb2c758c7 | ||
|
|
b6fd6a15f0 | ||
|
|
e35bfaf96c | ||
|
|
ffdee8c3d7 | ||
|
|
8a94c33a64 | ||
|
|
9d69ec739f | ||
|
|
c6553016d3 | ||
|
|
6048814635 | ||
|
|
fe26e6cfe0 | ||
|
|
3e35e3d8a8 | ||
|
|
70b5105daa | ||
|
|
d00846aae7 | ||
|
|
7ec660c509 | ||
|
|
8e4f1fdd10 | ||
|
|
0c2abf3629 | ||
|
|
95d4bef3ea | ||
|
|
4e1a1415f6 | ||
|
|
40579b5d56 | ||
|
|
60f79bdf63 | ||
|
|
96a772d4dc | ||
|
|
2974bdc1d7 | ||
|
|
c7f4517490 | ||
|
|
8f6efdaae0 | ||
|
|
e760ee39e5 | ||
|
|
0bc95c069d | ||
|
|
f883b6a182 | ||
|
|
88a247c107 | ||
|
|
de5fbd921e | ||
|
|
a8aeb8addb | ||
|
|
13211b489d | ||
|
|
9f5e977bcd | ||
|
|
28357bd57f | ||
|
|
f39e224c48 | ||
|
|
9b9b041263 | ||
|
|
98a59c4700 | ||
|
|
3497e36f23 | ||
|
|
3612565e3a | ||
|
|
c24a7712cd | ||
|
|
83677dae83 | ||
|
|
6e2dcd5dcb | ||
|
|
5eea9c301c | ||
|
|
efa2918ce9 | ||
|
|
e53337bcdc | ||
|
|
e5d883f97e | ||
|
|
548a55792c | ||
|
|
43f0f2a0fd | ||
|
|
0bbaec0829 | ||
|
|
7b1c696810 | ||
|
|
8d69c3764d | ||
|
|
87acd9d7ee | ||
|
|
06391c9de6 | ||
|
|
b42b41216b | ||
|
|
689ab09555 | ||
|
|
30ee1ad8cd | ||
|
|
cc9ff15142 | ||
|
|
4c756c7cbf | ||
|
|
100f1b0b41 | ||
|
|
d9117bd9a0 | ||
|
|
6ef5b46dd6 | ||
|
|
b3c60e56a6 | ||
|
|
8d345701da | ||
|
|
016ed4f6ee | ||
|
|
3da7e45244 | ||
|
|
b1229bce1d | ||
|
|
fea6b37379 | ||
|
|
d64ea284fb | ||
|
|
cc2503ac0f | ||
|
|
486bff44df | ||
|
|
04d6b34bfe | ||
|
|
0193632673 | ||
|
|
a3730812bc | ||
|
|
90e11039a1 | ||
|
|
80d928eff2 | ||
|
|
838041ef59 | ||
|
|
732f94a284 | ||
|
|
70081e1118 | ||
|
|
35c15c90e4 | ||
|
|
812cd463db | ||
|
|
090d097a53 | ||
|
|
36b337e784 | ||
|
|
0a1d215560 | ||
|
|
7d0d1056c0 | ||
|
|
21146ff49f | ||
|
|
b76eedfc0e | ||
|
|
c547117223 | ||
|
|
fc2132485d | ||
|
|
71cc825038 | ||
|
|
59d1da77c2 | ||
|
|
44b6136ce2 | ||
|
|
ba3c6023a8 | ||
|
|
be7f6ae7d1 | ||
|
|
984c7a67f5 | ||
|
|
a4bf6c1f7a | ||
|
|
690ae1a7b6 | ||
|
|
eae9a10a7d | ||
|
|
7c6765b969 | ||
|
|
a6c143a1c7 | ||
|
|
714da0ab3b | ||
|
|
377ec37257 | ||
|
|
c6a59d7c59 | ||
|
|
84559fae9c | ||
|
|
aa0602dcbb | ||
|
|
6d0caacdeb | ||
|
|
84df301f3e | ||
|
|
792a72af74 | ||
|
|
8fee6578c2 | ||
|
|
6d843e6aab | ||
|
|
27bb85bb00 | ||
|
|
2751f4fea9 | ||
|
|
c21cfeb28e | ||
|
|
8707247008 | ||
|
|
3d0bde6763 | ||
|
|
11f509933e | ||
|
|
7078dd92dd | ||
|
|
f5e0addbcc | ||
|
|
fd88ac509f | ||
|
|
d267ddcafa | ||
|
|
9084e9ed18 | ||
|
|
bf29a4faa9 | ||
|
|
615380a70c | ||
|
|
d268013bf0 | ||
|
|
835367e1bf | ||
|
|
054421c978 | ||
|
|
20a2b2d330 | ||
|
|
1649ea64cc | ||
|
|
d50439161a | ||
|
|
7d6cdf1b7b | ||
|
|
abcb60ed4c | ||
|
|
443b6ff4f9 | ||
|
|
de89eadcf2 | ||
|
|
4956218b10 | ||
|
|
bcfaf3a37e | ||
|
|
b1c45e579a | ||
|
|
e627f60b16 | ||
|
|
7154252dff | ||
|
|
a368fe5825 | ||
|
|
895a128ff7 | ||
|
|
792a4dda7f | ||
|
|
4d828a01aa | ||
|
|
195ee3ee2c | ||
|
|
d9e7912162 | ||
|
|
2a580c675a | ||
|
|
9f66de8422 | ||
|
|
b26542136e | ||
|
|
c135905e64 | ||
|
|
b7b7d33597 | ||
|
|
097d8e9b97 | ||
|
|
8c811ba9ca | ||
|
|
b6cf557483 | ||
|
|
3562aed899 | ||
|
|
07222e92c2 | ||
|
|
011c3c9c5b | ||
|
|
28b77fa02b | ||
|
|
a9ec90713e | ||
|
|
8663b7b3fa | ||
|
|
3ef5cfe846 | ||
|
|
05fa505bb6 | ||
|
|
5c3adfda29 | ||
|
|
0013375eea | ||
|
|
5868a4cefb | ||
|
|
3178f0b57d | ||
|
|
31c06771f3 | ||
|
|
6f57b8a2de | ||
|
|
bd6d2e71e7 | ||
|
|
89457845f9 | ||
|
|
53e98521f3 | ||
|
|
1842d7127a | ||
|
|
ecc1e774b9 | ||
|
|
fa18095538 | ||
|
|
da9333e884 | ||
|
|
af11431b09 | ||
|
|
16134aa0de | ||
|
|
ffbd9815d5 | ||
|
|
ab692bb15d | ||
|
|
085654e751 | ||
|
|
5b3386af2f | ||
|
|
d6545627aa | ||
|
|
cb63013197 | ||
|
|
5d2e4bf7cc | ||
|
|
a4fb2deece | ||
|
|
92ac8569b3 | ||
|
|
0c982b0999 | ||
|
|
bef0ca18c6 | ||
|
|
afc2c17b5a | ||
|
|
efdf0a6b84 | ||
|
|
b36f8d794c | ||
|
|
5c022f86ea | ||
|
|
fd20a8045e | ||
|
|
9482d14160 | ||
|
|
61783021cc | ||
|
|
64b5299c0d | ||
|
|
8d2077fc5d | ||
|
|
720b61f4f6 | ||
|
|
9fa8867495 | ||
|
|
b198fee11a | ||
|
|
2f71b8d5c9 | ||
|
|
33858cfc3b | ||
|
|
7225e7e038 | ||
|
|
d25ff21030 | ||
|
|
8055808235 | ||
|
|
9827f19c63 | ||
|
|
edb1a68952 | ||
|
|
6dc9aa815a | ||
|
|
bf36c40f88 | ||
|
|
099da1b071 | ||
|
|
cd620b0c5a | ||
|
|
21de08506c | ||
|
|
009ae1e14c | ||
|
|
c8b812bbb5 | ||
|
|
be2234113b | ||
|
|
4dd4d17ef9 | ||
|
|
cac0555c43 | ||
|
|
35dd35d821 | ||
|
|
03b663463d | ||
|
|
9a28beb6b5 | ||
|
|
dc96b3862b | ||
|
|
facd97c09d | ||
|
|
3696986a5c | ||
|
|
1e98c66b3c | ||
|
|
7df34cc709 | ||
|
|
3301754af2 | ||
|
|
25d5441444 | ||
|
|
07d35d606c | ||
|
|
2dd7ba6e28 | ||
|
|
92fb9eade5 | ||
|
|
2f4b0f8563 | ||
|
|
afd5925499 | ||
|
|
10b588a19c | ||
|
|
843e5016e5 | ||
|
|
8d54c0123b | ||
|
|
677124da49 | ||
|
|
50ca0d4b34 | ||
|
|
54bc851159 | ||
|
|
481f7c61b8 | ||
|
|
69bda9427a | ||
|
|
bbfaac5468 | ||
|
|
d15550cacb | ||
|
|
784eed9b1a | ||
|
|
7b11411b61 | ||
|
|
921b30a892 | ||
|
|
baa75a8b64 | ||
|
|
fd49bd2f2d | ||
|
|
445045565b | ||
|
|
6c80d1f883 | ||
|
|
3af2314a70 | ||
|
|
17f9304adc | ||
|
|
f208ff52fd | ||
|
|
2dca00c4a0 | ||
|
|
1443fff315 | ||
|
|
96605826ba | ||
|
|
22cdbd7ec7 | ||
|
|
362f3b890e | ||
|
|
da69a6e339 | ||
|
|
a549c191da | ||
|
|
26213491a3 | ||
|
|
5f086b11b8 | ||
|
|
0d168a4518 | ||
|
|
59b766eb93 | ||
|
|
0e4f5e9203 | ||
|
|
bbc7d2f29e | ||
|
|
a98def4326 | ||
|
|
b274c63395 | ||
|
|
6327d8c92e | ||
|
|
969f56911a | ||
|
|
09ea8c3241 | ||
|
|
ff15f11927 | ||
|
|
abadc6298d | ||
|
|
cd96f78228 | ||
|
|
5f2d1b8255 | ||
|
|
483bd16a2d | ||
|
|
b53616ead3 | ||
|
|
2bf2442096 | ||
|
|
ef4ba78ab7 | ||
|
|
85cb1b7a76 | ||
|
|
fe260a85f5 | ||
|
|
f201ab0721 | ||
|
|
767a7a7177 | ||
|
|
39b49d47f9 | ||
|
|
c550cd7afb | ||
|
|
f4096b94a7 | ||
|
|
9b4c126534 | ||
|
|
34faf362d1 | ||
|
|
1a24e954f9 | ||
|
|
eb6cdfe97c | ||
|
|
a01de54b65 | ||
|
|
5c7e26c176 | ||
|
|
4da1c67d18 | ||
|
|
f3d0cdbddc | ||
|
|
5fd241f7d7 | ||
|
|
159941696d | ||
|
|
7fab8d9782 | ||
|
|
152fd66bbe | ||
|
|
ae4c77a6d4 | ||
|
|
5fac631f6f | ||
|
|
72c277d9ee | ||
|
|
0fdf648e1b | ||
|
|
ba1fc13eed | ||
|
|
197decc842 | ||
|
|
9e5aa39781 | ||
|
|
c381672aee | ||
|
|
62670a4fa4 | ||
|
|
4469046b3b | ||
|
|
7d51a34d11 | ||
|
|
5cbe94ba66 | ||
|
|
f690d672a2 | ||
|
|
cdb9777e96 | ||
|
|
2bc5efe641 | ||
|
|
5481ce25b2 | ||
|
|
bd269501ac | ||
|
|
455ff57eec | ||
|
|
51e682335b | ||
|
|
2ca20dea23 | ||
|
|
7bef84e4e9 | ||
|
|
11c6b667fb | ||
|
|
262bd5b7c1 | ||
|
|
e2580bda05 | ||
|
|
3364733bd6 | ||
|
|
7461407140 | ||
|
|
0b1805d96f | ||
|
|
cfe099bb30 | ||
|
|
b98b301089 | ||
|
|
4b0b19aec7 | ||
|
|
af142a5ccc | ||
|
|
e3384d98b7 | ||
|
|
f4b08a9ce2 | ||
|
|
21595cdebc | ||
|
|
ac3a45aec5 | ||
|
|
4605130a53 | ||
|
|
89c943f755 | ||
|
|
9730e066b8 | ||
|
|
77d2ebbda0 | ||
|
|
8668911593 | ||
|
|
34843a70b9 | ||
|
|
e686fbc0a8 | ||
|
|
95ab1b355a | ||
|
|
5312524871 | ||
|
|
64fb0934a4 | ||
|
|
6ee3a395fb | ||
|
|
62ced1749f | ||
|
|
9ea3b70143 | ||
|
|
b7ff643a34 | ||
|
|
07f9b94548 | ||
|
|
c5b3c17ccc | ||
|
|
02460f0e9d | ||
|
|
ee20038dce | ||
|
|
226bf5299e | ||
|
|
ae2ed8bf94 | ||
|
|
395d140c76 | ||
|
|
d9354c867b | ||
|
|
a6fafcd03b | ||
|
|
0b88f1be14 | ||
|
|
69bbe627a9 | ||
|
|
26a9c9e725 | ||
|
|
9ce5c1c4d7 | ||
|
|
a0b9efe1fd | ||
|
|
1aa57ca11b | ||
|
|
e10ce7a445 | ||
|
|
cf9ce6ac60 | ||
|
|
10d120ccfd | ||
|
|
2cb3450cf8 | ||
|
|
53ce9b6588 | ||
|
|
05012985bb | ||
|
|
93c9a70aa0 | ||
|
|
7d03483210 | ||
|
|
c17053f71a | ||
|
|
fc9001353f | ||
|
|
6a8cba521b | ||
|
|
471641c228 | ||
|
|
887421c9fa | ||
|
|
cbe8659cc7 | ||
|
|
b28429f940 | ||
|
|
956a4c341c | ||
|
|
5b05dc92a1 | ||
|
|
8bcbeb0aa9 | ||
|
|
472848da91 | ||
|
|
5200f945fe | ||
|
|
a736bb4e93 | ||
|
|
00f60ccaa4 | ||
|
|
6d1c4a9570 | ||
|
|
c6a0e209ad | ||
|
|
be4a168601 | ||
|
|
2c10671fe4 | ||
|
|
b791289dfe | ||
|
|
c4370240f8 | ||
|
|
fd0bdcba67 | ||
|
|
f805b6bfa6 | ||
|
|
4188b274f7 | ||
|
|
bf1e720ebc | ||
|
|
599351b56d | ||
|
|
e8e87b3b83 | ||
|
|
84f42bdd05 | ||
|
|
340f1e3258 | ||
|
|
75b72d601a | ||
|
|
d2143844e3 | ||
|
|
ce7e5122e0 | ||
|
|
0268f9865c | ||
|
|
529e703ddd | ||
|
|
c401e3b55e | ||
|
|
946b336e92 | ||
|
|
e40138c2ee | ||
|
|
3dad330a59 | ||
|
|
fb3fe24567 | ||
|
|
a011596231 | ||
|
|
ac5a4b88d2 | ||
|
|
12e743f9dc | ||
|
|
5355c4935c | ||
|
|
f54f2e7b13 | ||
|
|
835096c089 | ||
|
|
16bb194019 | ||
|
|
a9952a28a4 | ||
|
|
67624208de | ||
|
|
ce0aadfcf7 | ||
|
|
7c677de10a | ||
|
|
f590d38746 | ||
|
|
3591ba0f89 | ||
|
|
80170cfa03 | ||
|
|
1cb8844470 | ||
|
|
9be703e271 | ||
|
|
a19ec35a47 | ||
|
|
47ade360d5 | ||
|
|
0e669417cd | ||
|
|
5c3d3bbc2e | ||
|
|
09b5eef617 | ||
|
|
92c2ed970c | ||
|
|
7ab84ca607 | ||
|
|
7d37427c96 | ||
|
|
17695ff77c | ||
|
|
bc2b26132a | ||
|
|
7c033f75ea | ||
|
|
816e3b71a9 | ||
|
|
b0e307bdd0 | ||
|
|
ee2d52c40a | ||
|
|
9007cab02c | ||
|
|
d473a82715 | ||
|
|
fb01ceb2a9 | ||
|
|
109f59ab6c | ||
|
|
699ef14b4e | ||
|
|
169f8eaad1 | ||
|
|
854780a22a | ||
|
|
b1883d7204 | ||
|
|
74be583fbb | ||
|
|
4bc54c45a3 | ||
|
|
56ec9dbb10 | ||
|
|
5d08ddadfa | ||
|
|
cd54687f41 | ||
|
|
899cd22999 | ||
|
|
3aadc958eb | ||
|
|
79dde7bb9b | ||
|
|
7d8e9dfc60 | ||
|
|
e623776f5d | ||
|
|
230988b90d | ||
|
|
a6f4e20078 | ||
|
|
02b7198e9b | ||
|
|
64cb4ddb14 | ||
|
|
238b6c8e57 | ||
|
|
ba372029f9 | ||
|
|
a774e52988 | ||
|
|
8c68854d1d | ||
|
|
64a38a2aef | ||
|
|
b6feecae70 | ||
|
|
cccfe7268b | ||
|
|
c03697c0a6 | ||
|
|
32bf87c0c3 | ||
|
|
8c63e32450 | ||
|
|
84d8e1ceb7 | ||
|
|
23d3cef52e | ||
|
|
6a5b6a70b5 | ||
|
|
b6f0a29f8f | ||
|
|
dc366809c8 | ||
|
|
ceeaab70fc | ||
|
|
3cfa81bdea | ||
|
|
9e99676b66 | ||
|
|
a63f185ba9 | ||
|
|
4a0dd80c5a | ||
|
|
62c62062e0 | ||
|
|
b9a97931c8 | ||
|
|
4ec3b5e387 | ||
|
|
8eb59d97b2 | ||
|
|
35b54117e0 | ||
|
|
aa7a915139 | ||
|
|
6d54bfe01f | ||
|
|
14dff27b97 | ||
|
|
ff35b4a4b6 | ||
|
|
9f15a85c86 | ||
|
|
e03622be9c | ||
|
|
3239337c1c | ||
|
|
9a58efaa07 | ||
|
|
3319f578ba | ||
|
|
3e942dbdbd | ||
|
|
5427e9a402 | ||
|
|
4a09feed59 | ||
|
|
7ff8bda52a | ||
|
|
1c6d2f7fa4 | ||
|
|
041f21d117 | ||
|
|
f4ba2d68cd | ||
|
|
20263e44ba | ||
|
|
347270a8b8 | ||
|
|
29dd685377 | ||
|
|
fa008c988c | ||
|
|
9a472731d8 | ||
|
|
9c4317783b | ||
|
|
fc4d347fa1 | ||
|
|
9c408bcf5a | ||
|
|
30aa6549ec | ||
|
|
ba4e3bab5c | ||
|
|
3fd39ea0c8 | ||
|
|
b6008b4870 | ||
|
|
dc7e95bbff | ||
|
|
f1e4ac4112 | ||
|
|
cf867cf3b6 | ||
|
|
6673823a74 | ||
|
|
46022b0588 | ||
|
|
db771960f3 | ||
|
|
2c4f3d7928 | ||
|
|
9ae851958a | ||
|
|
953bb0e936 | ||
|
|
821938ac9a | ||
|
|
1fee41d5d0 | ||
|
|
d3a0c57aca | ||
|
|
1fb33bf7cb | ||
|
|
ca339f32d5 | ||
|
|
54cc6a1e0c | ||
|
|
709eaf1a43 | ||
|
|
abaa1e81f2 | ||
|
|
c3d565c7e5 | ||
|
|
737a8323f2 | ||
|
|
9919a30a72 | ||
|
|
055d43eb23 | ||
|
|
2425c8c5d3 | ||
|
|
3e1a9434db | ||
|
|
4408e480dd | ||
|
|
80d5bf4458 | ||
|
|
71f6e9ac52 | ||
|
|
4791973b02 | ||
|
|
d82c0a5e0e | ||
|
|
26890ebe44 | ||
|
|
ed73fa12b1 | ||
|
|
1022029bd9 | ||
|
|
108042c190 | ||
|
|
1f19e028d5 | ||
|
|
21b5eade71 | ||
|
|
2ddb858647 | ||
|
|
13ede53195 | ||
|
|
06bd951d71 | ||
|
|
b59440584d | ||
|
|
3ba0f58738 | ||
|
|
61b19a1df5 | ||
|
|
76ff2a4492 | ||
|
|
5a558a9d50 | ||
|
|
fa83ba816b | ||
|
|
1b948b584f | ||
|
|
6472ac7701 | ||
|
|
498f494961 | ||
|
|
dc97b638cf | ||
|
|
c0d01ec752 | ||
|
|
8b17b52575 | ||
|
|
b91b85a0b2 | ||
|
|
b6a7615d8f | ||
|
|
1e6c7fa6d0 | ||
|
|
c67b212538 | ||
|
|
73d685adf5 | ||
|
|
e4283e2dc2 | ||
|
|
a622f5ca9b | ||
|
|
12b2bd2c52 | ||
|
|
aeb42ea4f8 | ||
|
|
9d99b5f550 | ||
|
|
63ae5848f6 | ||
|
|
6a74832c8b | ||
|
|
117dda3bb5 | ||
|
|
43817779c5 | ||
|
|
9af2648b22 | ||
|
|
caed991cb1 | ||
|
|
654cf22f3c | ||
|
|
ff7fdaa251 | ||
|
|
5361b787c5 | ||
|
|
5830269fea | ||
|
|
391abe4991 | ||
|
|
82605f4170 | ||
|
|
2221d40f47 | ||
|
|
ab49c63840 | ||
|
|
b6a520e350 | ||
|
|
a5e1ed44f4 | ||
|
|
a78d69c89e | ||
|
|
9a7996d40d | ||
|
|
fb577f8b70 | ||
|
|
933a1be8e1 | ||
|
|
5f99ebefb1 | ||
|
|
16c463f612 | ||
|
|
3406cdfb02 | ||
|
|
69915701de | ||
|
|
6f4ef18815 | ||
|
|
ef1c5949f1 | ||
|
|
9a646f856b | ||
|
|
21efb90b4c | ||
|
|
1248b1fb29 | ||
|
|
8ed85ede2c | ||
|
|
6181b75d9f | ||
|
|
7b1ffb942f | ||
|
|
61990e764c | ||
|
|
9c0c87d4c2 | ||
|
|
535b8e5fc4 | ||
|
|
baa69ff3bc | ||
|
|
4991913f45 | ||
|
|
b28ff18918 | ||
|
|
c38495de88 | ||
|
|
563fb657a4 | ||
|
|
b516f14f57 | ||
|
|
d0ef3c950b | ||
|
|
67b006f385 | ||
|
|
e12285ecfa | ||
|
|
3a92c013eb | ||
|
|
e376f97b46 | ||
|
|
08ad614611 | ||
|
|
d1ebf8d697 | ||
|
|
4680f0fcc6 | ||
|
|
0892ca1a2d | ||
|
|
27f498f40a | ||
|
|
c8029ee081 | ||
|
|
b5e6f888d7 | ||
|
|
66dfcd3700 | ||
|
|
114cd51971 | ||
|
|
e4e07b90d9 | ||
|
|
eb6bade2cf | ||
|
|
d5cf9e34db | ||
|
|
c5c381a034 | ||
|
|
ee5e6d3239 | ||
|
|
6b0565e9ab | ||
|
|
0fa56cb273 | ||
|
|
04026c054b | ||
|
|
3d9b69a860 | ||
|
|
d049d067ab | ||
|
|
4e3fb88dba | ||
|
|
c42184951f | ||
|
|
03e4c49091 | ||
|
|
0229e1938e | ||
|
|
0f6461602e | ||
|
|
951e439eaf | ||
|
|
5a226464de | ||
|
|
49c52a00be | ||
|
|
a339368023 | ||
|
|
ef1c2b4f03 | ||
|
|
d8e4769972 | ||
|
|
1dde5a12c4 | ||
|
|
f9095ceb74 | ||
|
|
18d77ca9f7 | ||
|
|
b2fa60ae08 | ||
|
|
cbaf562c44 | ||
|
|
250f255253 | ||
|
|
9a4e7fc467 | ||
|
|
351ee1a54e | ||
|
|
aa40a039f9 | ||
|
|
55ec70cbd6 | ||
|
|
48d711023e | ||
|
|
99c1e890b3 | ||
|
|
6b17cd4d9e | ||
|
|
8cbfc79034 | ||
|
|
b3bf190e10 | ||
|
|
d83d63b3e6 | ||
|
|
64d1465dfe | ||
|
|
952fd59c42 | ||
|
|
bfb85ccfd2 | ||
|
|
42eb4e2da1 | ||
|
|
acc240b669 | ||
|
|
b07f95c362 | ||
|
|
181c4ad3c6 | ||
|
|
50a586f489 | ||
|
|
0821794bcc | ||
|
|
347e9cc811 | ||
|
|
1a26fbf6f4 | ||
|
|
fc0689fc3c | ||
|
|
5b28d5f457 | ||
|
|
da47161e1a | ||
|
|
450081ee3e | ||
|
|
e30d54723d | ||
|
|
c874efaa24 | ||
|
|
28473a86dc | ||
|
|
57b2d73632 | ||
|
|
e17253d592 | ||
|
|
eefec02de4 | ||
|
|
c73a96ef7e | ||
|
|
6e424478f1 | ||
|
|
e4ff2fe476 | ||
|
|
120d726b8e | ||
|
|
b7d1ccf9b6 | ||
|
|
fdbef474f0 | ||
|
|
b34e24d593 | ||
|
|
c29a54e21a | ||
|
|
25633f03c5 | ||
|
|
7e635fb4ea | ||
|
|
0b865da3be | ||
|
|
30ae887126 | ||
|
|
75d73d3a5e | ||
|
|
0f57683e22 | ||
|
|
6a7e0ff921 | ||
|
|
237143851d | ||
|
|
76e9725e26 | ||
|
|
1080ace4cd | ||
|
|
95790d55d5 | ||
|
|
2d34d458f4 | ||
|
|
331a0a87b1 | ||
|
|
628a4db746 | ||
|
|
b44a3c191d | ||
|
|
8f4fdeaa8f | ||
|
|
cd0f0e3f01 | ||
|
|
abb4077c95 | ||
|
|
cc45fb58a8 | ||
|
|
b23cadea59 | ||
|
|
f27159f63f | ||
|
|
53c4dce509 | ||
|
|
1aaab57edc | ||
|
|
1e004fefcc | ||
|
|
fb2d2c8e05 | ||
|
|
836d8d030c | ||
|
|
38b772c523 | ||
|
|
d8f1446e76 | ||
|
|
f30b3afabd | ||
|
|
1656c60dee | ||
|
|
0f0b315f3b | ||
|
|
f0bb8ce8a7 | ||
|
|
899f40d5f5 | ||
|
|
448d3958a2 | ||
|
|
f36b23bdb2 | ||
|
|
f613f68570 | ||
|
|
58d069ed7d | ||
|
|
3eca24ed58 | ||
|
|
8aacdc0502 | ||
|
|
1f5920f685 | ||
|
|
93fb849296 | ||
|
|
98cfe2922a | ||
|
|
e09627775a | ||
|
|
90df913def | ||
|
|
c1dc40c79b | ||
|
|
c5fbeffa9c | ||
|
|
1f98dbdf65 | ||
|
|
2fdf51d12c | ||
|
|
fab6466180 | ||
|
|
fa708272bc | ||
|
|
a9b68f7c39 | ||
|
|
6281c6469b | ||
|
|
65fd33b9cf | ||
|
|
401a5f7ff7 | ||
|
|
1f0ab2ab49 | ||
|
|
fcad7a7fe4 | ||
|
|
98daaf858f | ||
|
|
348d689243 | ||
|
|
4acd11d649 | ||
|
|
af47857a47 | ||
|
|
1280b6e13e | ||
|
|
a7587d631c | ||
|
|
866e1f00f7 | ||
|
|
4f377bcebe | ||
|
|
64a0fb278b | ||
|
|
f8c9466d04 | ||
|
|
ef62191e6b | ||
|
|
e25cee0855 | ||
|
|
94439f0d10 | ||
|
|
2385f48fe4 | ||
|
|
ed98acc906 | ||
|
|
201c7637f6 | ||
|
|
765b10611b | ||
|
|
28a135880d | ||
|
|
2952812a4b | ||
|
|
6c57c4b1e1 | ||
|
|
706337d8fa | ||
|
|
d13d9228e8 | ||
|
|
c4492fb1a1 | ||
|
|
6e6d4ebc76 | ||
|
|
3b3aa6b2fe | ||
|
|
11bad2e474 | ||
|
|
556f17969c | ||
|
|
a2f40be00e | ||
|
|
cc0503c8a4 | ||
|
|
5ec9cf7faf | ||
|
|
cc05df412e | ||
|
|
806c7935c5 | ||
|
|
e7f0400580 | ||
|
|
ad109532be | ||
|
|
9dbfa99284 | ||
|
|
3c684404ed | ||
|
|
d818615472 | ||
|
|
06694061d2 | ||
|
|
75c305ae0f | ||
|
|
cb786a0166 | ||
|
|
e292bf01d7 | ||
|
|
17f07ee888 | ||
|
|
51c09a1b02 | ||
|
|
fe7befa845 | ||
|
|
eca5ef6f84 | ||
|
|
c023a38544 | ||
|
|
7c831fa19d | ||
|
|
24c0f2aedc | ||
|
|
6170a274d7 | ||
|
|
155796b0e0 | ||
|
|
3b7262681c | ||
|
|
988ab9722c | ||
|
|
8eae427591 | ||
|
|
b4fe13dfb1 | ||
|
|
f435a15b43 | ||
|
|
08d5be5ce3 | ||
|
|
c3d8f4f80b | ||
|
|
bbb8bdb687 | ||
|
|
4138a6d6dc | ||
|
|
6b172cd3a6 | ||
|
|
86e0282011 | ||
|
|
f1250ae5eb | ||
|
|
586c9d3139 | ||
|
|
00fea3e02f | ||
|
|
6a72855de8 | ||
|
|
6b0edaecc6 | ||
|
|
a4bfd2c9f7 | ||
|
|
7a419c262e | ||
|
|
40ac3210c4 | ||
|
|
3bb9e234d8 | ||
|
|
75a4ef99c9 | ||
|
|
1e4b6b6c49 | ||
|
|
c9eeab09a1 | ||
|
|
1a61fc832e | ||
|
|
1d232fd263 | ||
|
|
197f3665bc | ||
|
|
ce62e32dfa | ||
|
|
2cc3521989 | ||
|
|
6fbab322cf | ||
|
|
458fa9d02e | ||
|
|
9f85d2bdb3 | ||
|
|
ff20822b47 | ||
|
|
eff0621966 | ||
|
|
6aeb6199f7 | ||
|
|
072fac837c | ||
|
|
f1fa185383 | ||
|
|
c471bc0f82 | ||
|
|
37e29949ef | ||
|
|
e840e4a547 | ||
|
|
82bb9a6008 | ||
|
|
15ed959da7 | ||
|
|
a0f4c46cb5 | ||
|
|
71d5655ab2 | ||
|
|
29d56b63f7 | ||
|
|
35f495ef5b | ||
|
|
1006890b6e | ||
|
|
083d7304fd | ||
|
|
2d8f651674 | ||
|
|
e8ee370499 | ||
|
|
5c3d71258d | ||
|
|
519031a10e | ||
|
|
0799ce190d | ||
|
|
a7c4802446 | ||
|
|
094c6fd273 | ||
|
|
72a601371e | ||
|
|
2a80ad8344 | ||
|
|
7e502fffe6 | ||
|
|
e5de031423 | ||
|
|
d064ecd842 | ||
|
|
c0d33a1a19 | ||
|
|
e78f211e8a | ||
|
|
77d66fa0c9 | ||
|
|
a652fdf8d2 | ||
|
|
85481225a3 | ||
|
|
6210bd2e6d | ||
|
|
7dd7dca99a | ||
|
|
48991e6c3b | ||
|
|
825d045143 | ||
|
|
86593cc0f4 | ||
|
|
d987bcf0d0 | ||
|
|
c52a72ec90 | ||
|
|
b82f7061a0 | ||
|
|
55d651ad27 | ||
|
|
5239749580 | ||
|
|
fe5b6d40ac | ||
|
|
5fa42279bd | ||
|
|
b7a2ab57cc | ||
|
|
78949f3620 | ||
|
|
924bf07950 | ||
|
|
181f7acbb8 | ||
|
|
d331de6683 | ||
|
|
41dbc66d24 | ||
|
|
6230319f63 | ||
|
|
b7e768820f | ||
|
|
5dc2595159 | ||
|
|
919aa2622d | ||
|
|
025c66db7e | ||
|
|
b3361100da | ||
|
|
e0ffde1614 | ||
|
|
4bfe607f64 | ||
|
|
c0cbe8e0ab | ||
|
|
1e6d41e113 | ||
|
|
54f0a49281 | ||
|
|
618f5360ae | ||
|
|
6f8b5afd56 | ||
|
|
6432528d37 | ||
|
|
b62e2c0b78 | ||
|
|
f30e846f09 | ||
|
|
0a9b4bdc11 | ||
|
|
0102e99d3c | ||
|
|
19548c196e | ||
|
|
46ee987742 | ||
|
|
34428d82c7 | ||
|
|
bab27b8be1 | ||
|
|
6d06970c0f | ||
|
|
c16a965eb7 | ||
|
|
5cb7b82415 | ||
|
|
4d9a4267f4 | ||
|
|
fdbc7cc585 | ||
|
|
ed6c35a59f | ||
|
|
eca14a8868 | ||
|
|
fc719cb1c2 | ||
|
|
3dc6a30c4c | ||
|
|
3e93e180f1 | ||
|
|
3446f8f6ae | ||
|
|
541dd9eac7 | ||
|
|
62d866b60f | ||
|
|
f8f0444503 | ||
|
|
7eaf84d066 | ||
|
|
317e9881b8 | ||
|
|
c4e06bd2f7 | ||
|
|
fb1532be1c | ||
|
|
f076b05e7e | ||
|
|
5e1ac06375 | ||
|
|
959a8e7594 | ||
|
|
4fde060510 | ||
|
|
6da4c54f9e | ||
|
|
ad0e3441a1 | ||
|
|
56e9e436cf | ||
|
|
6fde1e459d | ||
|
|
fa314611bc | ||
|
|
c34ebfa2e8 | ||
|
|
c6f0589ed5 | ||
|
|
8ffa8b6657 | ||
|
|
0a92b98110 | ||
|
|
b6c31757a7 | ||
|
|
676efe247f | ||
|
|
f6defc091c | ||
|
|
8bb779ea9e | ||
|
|
18d0cf51ef | ||
|
|
8b7b363440 | ||
|
|
6ba77c146b | ||
|
|
54ab7ea9ee | ||
|
|
b9c0e96933 | ||
|
|
41650d58a2 | ||
|
|
3519f4f9c7 | ||
|
|
991e40e089 | ||
|
|
9e845ec580 | ||
|
|
c95fb32d0a | ||
|
|
bfe64ea153 | ||
|
|
146d641f97 | ||
|
|
6a94ea066d | ||
|
|
477ec44b75 | ||
|
|
284b00fa78 | ||
|
|
0f94ba3d39 | ||
|
|
2e157dd969 | ||
|
|
f945845a77 | ||
|
|
457cf98089 | ||
|
|
ab65b53201 | ||
|
|
3da4daeed5 | ||
|
|
f9c5f89595 | ||
|
|
d71947cb63 | ||
|
|
cdf29b6c56 | ||
|
|
73ddadc0f0 | ||
|
|
bd8431504d | ||
|
|
efcee75f30 | ||
|
|
b283e05f9c | ||
|
|
d15757755a | ||
|
|
b3259e4b49 | ||
|
|
cebf8d3579 | ||
|
|
9451a6a1ec | ||
|
|
5d3321839d | ||
|
|
594458235b | ||
|
|
a3273dedc1 | ||
|
|
42824713e3 | ||
|
|
4ad40ee00d | ||
|
|
ddf33a13cd | ||
|
|
4ce8ea9ce9 | ||
|
|
5b84fd6e40 | ||
|
|
d7af63877e | ||
|
|
844ed59dd8 | ||
|
|
35e29a0615 | ||
|
|
7c71cd1f80 | ||
|
|
74ad0faffa | ||
|
|
e13948957c | ||
|
|
0d6a962344 | ||
|
|
c192f3b47b | ||
|
|
53fa384608 | ||
|
|
1448791fcd | ||
|
|
a66a4210c3 | ||
|
|
b1ffd8d556 | ||
|
|
4548696c73 | ||
|
|
0d460dd6b1 | ||
|
|
4333e3da67 | ||
|
|
352ccb21ff | ||
|
|
2ac57642a4 | ||
|
|
af1ddf2fc6 | ||
|
|
e23c519fac | ||
|
|
664a31fc87 | ||
|
|
cbcc988625 | ||
|
|
ce33737a38 | ||
|
|
f4e243255a | ||
|
|
8df8479716 | ||
|
|
f28ac43446 | ||
|
|
263df059a4 | ||
|
|
64d1e9ca46 | ||
|
|
286ec29f91 | ||
|
|
66ca5c0d34 | ||
|
|
919335b4f5 | ||
|
|
c5a4b2605c | ||
|
|
2da0142387 | ||
|
|
7ba759b08a | ||
|
|
fdd5aa0a5a | ||
|
|
6ee80f6182 | ||
|
|
d4bf45a8b8 | ||
|
|
d30425b2bd | ||
|
|
cff8fbbd79 | ||
|
|
8b52c99604 | ||
|
|
5dee254fca | ||
|
|
2ab0f494b4 | ||
|
|
b4a58b47b3 | ||
|
|
b19450684b | ||
|
|
6451e3b3e3 | ||
|
|
14e2a169e4 | ||
|
|
f809919561 | ||
|
|
68d4b9d2cd | ||
|
|
5e1c6ae30d | ||
|
|
e1ba234a76 | ||
|
|
b9b84fe692 | ||
|
|
a3f5c461c3 | ||
|
|
91479543fa | ||
|
|
4dfa724972 | ||
|
|
f8e72504e5 | ||
|
|
51d6ba98d7 | ||
|
|
2309e18eb7 | ||
|
|
6ddb891c29 | ||
|
|
5100f6cb72 | ||
|
|
73e56d820b | ||
|
|
803cbae1dc | ||
|
|
9b9f877942 | ||
|
|
0e6df9d299 | ||
|
|
1cbe1cfaeb | ||
|
|
97a766517b | ||
|
|
42868ecbee | ||
|
|
4fd4b145d7 | ||
|
|
d5f7dc851e | ||
|
|
06fae21c76 | ||
|
|
89da16afec | ||
|
|
1dfc77a4ba | ||
|
|
4fb8fa1311 | ||
|
|
7eba982278 | ||
|
|
df78df5908 | ||
|
|
0dd98b56bc | ||
|
|
0a573f9da1 | ||
|
|
6d43387c55 | ||
|
|
ed4094016b | ||
|
|
56100f150d | ||
|
|
4e06ed80d1 | ||
|
|
a0c294f689 | ||
|
|
02bd640aab | ||
|
|
06b1060a45 | ||
|
|
0f0dcb9eae | ||
|
|
5ec6d571eb | ||
|
|
347de2cb8b | ||
|
|
f6a923ad56 | ||
|
|
43455ee661 | ||
|
|
911df72aeb | ||
|
|
b82225e279 | ||
|
|
bb3cc58ad0 | ||
|
|
804a345fec | ||
|
|
7f05164a7f | ||
|
|
52a6806022 | ||
|
|
1a9d47c554 | ||
|
|
2c3b3be3ee | ||
|
|
cdaed50939 | ||
|
|
5a155020e6 | ||
|
|
957b34d169 | ||
|
|
79d2ac0566 | ||
|
|
547f9ff61f | ||
|
|
9f0da2ec41 | ||
|
|
c755dc3ed9 | ||
|
|
d20fb2039a | ||
|
|
1c3411f808 | ||
|
|
7357be3c35 | ||
|
|
5dd1bed913 | ||
|
|
18eda8aade | ||
|
|
8100cdb17f | ||
|
|
7fa01fa4f3 | ||
|
|
d49e78c43e | ||
|
|
cf46768ac7 | ||
|
|
cfe718f4ef | ||
|
|
bf32b90702 | ||
|
|
9cb14d6db3 | ||
|
|
140cf0debe | ||
|
|
7e9b12b475 | ||
|
|
63a3a8a731 | ||
|
|
c95421f307 | ||
|
|
edc62449f6 | ||
|
|
a7f1192402 | ||
|
|
6bbda8a8e7 | ||
|
|
2431dbc16f | ||
|
|
d87f86b2a4 | ||
|
|
55a0652c2b | ||
|
|
aa1559b159 | ||
|
|
88dd2f1495 | ||
|
|
eb2cd75370 | ||
|
|
4757648349 | ||
|
|
a1f166942c | ||
|
|
7dbe0c2899 | ||
|
|
9bc4873721 | ||
|
|
15005f5754 | ||
|
|
c959ca9821 | ||
|
|
26687226f4 | ||
|
|
408b5b517b | ||
|
|
f403699fb2 | ||
|
|
193b289e8e | ||
|
|
533fd0574a | ||
|
|
48ffdf419f | ||
|
|
93e931e2b6 | ||
|
|
6561e4f84e | ||
|
|
24d6e581a6 | ||
|
|
d5748474d0 | ||
|
|
2277fb04b9 | ||
|
|
78b2d30905 | ||
|
|
ed81d75815 | ||
|
|
ac3a399df3 | ||
|
|
619f90c677 | ||
|
|
0f3d5f4b10 | ||
|
|
26be5bf264 | ||
|
|
227c696750 | ||
|
|
b1cec9480e | ||
|
|
982da962e5 | ||
|
|
803c8ce6b5 | ||
|
|
ca99114b16 | ||
|
|
897adf27f0 | ||
|
|
fd59efe41f | ||
|
|
b52217e8a0 | ||
|
|
0280a10832 | ||
|
|
c297e926f9 | ||
|
|
59fa5c27b6 | ||
|
|
6b7b63dff4 | ||
|
|
dd5bd17e2b | ||
|
|
2ab1493d27 | ||
|
|
9a1e75712d | ||
|
|
4c1ebfbdd4 | ||
|
|
34d6d0695f | ||
|
|
524bd52a56 | ||
|
|
efc5b8faaa | ||
|
|
112c6bd594 | ||
|
|
8b5c0fb715 | ||
|
|
82337b8baa | ||
|
|
744f3d70ed | ||
|
|
cd22b29ff1 | ||
|
|
1d8c46216f | ||
|
|
b5d70b90d9 | ||
|
|
9b03abaeef | ||
|
|
8a3d832b4c | ||
|
|
d2848fc519 | ||
|
|
48092bd7ba | ||
|
|
5c15ceedc4 | ||
|
|
f568a2407b | ||
|
|
7bf5f6f5a9 | ||
|
|
5b1cf49170 | ||
|
|
182f4c369a | ||
|
|
1d1f2d73ca | ||
|
|
23401d37d8 | ||
|
|
ada73a16ce | ||
|
|
7ecf6ece7c | ||
|
|
1c3d658ca1 | ||
|
|
9cbb8fd5bc | ||
|
|
f4904b8915 | ||
|
|
176440eeae | ||
|
|
1a0434fd85 | ||
|
|
c6ccf1d487 | ||
|
|
0faf38a1e1 | ||
|
|
4c4a707624 | ||
|
|
e2d4ae4acc | ||
|
|
95b7f78a5a | ||
|
|
e694f8f173 | ||
|
|
be35ea2704 | ||
|
|
91f2252255 | ||
|
|
0582033fb7 | ||
|
|
d01a0e1b2d | ||
|
|
2d8681dbd4 | ||
|
|
2bd5696d99 | ||
|
|
0b1d67116d | ||
|
|
de04c72767 | ||
|
|
da99b7b455 | ||
|
|
f29f39d427 | ||
|
|
1ee85181e8 | ||
|
|
c7ef136a7b | ||
|
|
5017189440 | ||
|
|
6281f188f8 | ||
|
|
a444a7de19 | ||
|
|
4369f4b5bb | ||
|
|
3689a7f17f | ||
|
|
6b051d77ab | ||
|
|
10ae5bfbc0 | ||
|
|
4daef7fc07 | ||
|
|
25a4a00b16 | ||
|
|
36bbab1d84 | ||
|
|
59b6ddc29e | ||
|
|
f04032aa97 | ||
|
|
96cba7281a | ||
|
|
63e8c732cc | ||
|
|
dfb2340e83 | ||
|
|
5e3d9df81a | ||
|
|
a0d52d415b | ||
|
|
9ef9bf9f42 | ||
|
|
ca381029f1 | ||
|
|
f42e0d42fd | ||
|
|
99798ffea7 | ||
|
|
e4d3334313 | ||
|
|
5384a9e86f | ||
|
|
a76fbb0073 | ||
|
|
299a035b7f | ||
|
|
a41ff7f2d0 | ||
|
|
b11294d9cf | ||
|
|
fda6694e0f | ||
|
|
399734fad4 | ||
|
|
0b5f0e5e61 | ||
|
|
f87dbec170 | ||
|
|
67f7649f6c | ||
|
|
c2cad3cca3 | ||
|
|
5a99011feb | ||
|
|
392702cc18 | ||
|
|
ed2e637219 | ||
|
|
3649b0ed9c | ||
|
|
13fbfb6cac | ||
|
|
27cda34f8b | ||
|
|
57c8d223ad | ||
|
|
8641738777 | ||
|
|
bafd62d42d | ||
|
|
1a88651e4e | ||
|
|
229e43f20c |
@@ -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
|
||||||
+16
@@ -5,8 +5,24 @@ Demos
|
|||||||
./Aristo
|
./Aristo
|
||||||
WebSite
|
WebSite
|
||||||
.push-package
|
.push-package
|
||||||
|
*.xcodeproj*
|
||||||
*.xcodeproj/*.pbxuser
|
*.xcodeproj/*.pbxuser
|
||||||
*.xcodeproj/*.perspectivev3
|
*.xcodeproj/*.perspectivev3
|
||||||
xcuserdata/
|
xcuserdata/
|
||||||
!*.xcodeproj/project.pbxproj
|
!*.xcodeproj/project.pbxproj
|
||||||
*.xCodeSupport/
|
*.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/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
|
||||||
|
|
||||||
+2
-4
@@ -1,8 +1,6 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 0.8
|
- 0.8
|
||||||
before_install:
|
install: ./bootstrap.sh --noprompt --directory ./narwhal
|
||||||
- jdk_switcher use openjdk6
|
|
||||||
install: ./bootstrap.sh --quiet --noprompt --directory ./narwhal
|
|
||||||
script: jake test
|
script: jake test
|
||||||
env: PATH=/home/travis/builds/cappuccino/cappuccino/narwhal/bin:$PATH CAPP_BUILD=/home/travis/builds/cappuccino/cappuccino/Build NARWHAL_ENGINE=rhino
|
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
||||||
|
|||||||
+8
-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"
|
||||||
@@ -55,11 +58,10 @@
|
|||||||
@import "CPController.j"
|
@import "CPController.j"
|
||||||
@import "CPCookie.j"
|
@import "CPCookie.j"
|
||||||
@import "CPCursor.j"
|
@import "CPCursor.j"
|
||||||
|
@import "CPDatePicker.j"
|
||||||
@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"
|
||||||
@@ -97,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"
|
||||||
|
|||||||
+15
-15
@@ -106,7 +106,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
_itemViews = [];
|
_itemViews = [];
|
||||||
_expandedItemIndexes = [CPIndexSet indexSet];
|
_expandedItemIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
[self setItemHeaderPrototype:[[CPButton alloc] initWithFrame:_CGRectMake(0.0, 0.0, 100.0, 24.0)]];
|
[self setItemHeaderPrototype:[[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -227,7 +227,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
{
|
{
|
||||||
var indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, _items.length)];
|
var indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, _items.length)];
|
||||||
|
|
||||||
[indexSet removeIndexes:_expandedIndexes];
|
[indexSet removeIndexes:_expandedItemIndexes];
|
||||||
|
|
||||||
return indexSet;
|
return indexSet;
|
||||||
}
|
}
|
||||||
@@ -258,18 +258,18 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
|
|
||||||
- (void)setFrameSize:(CGSize)aSize
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
var width = _CGRectGetWidth([self frame]);
|
var width = CGRectGetWidth([self frame]);
|
||||||
|
|
||||||
[super setFrameSize:aSize];
|
[super setFrameSize:aSize];
|
||||||
|
|
||||||
if (width !== _CGRectGetWidth([self frame]))
|
if (width !== CGRectGetWidth([self frame]))
|
||||||
[self _invalidateItemsStartingAtIndex:0];
|
[self _invalidateItemsStartingAtIndex:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
if (_items.length <= 0)
|
if (_items.length <= 0)
|
||||||
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
|
return [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), 0.0)];
|
||||||
|
|
||||||
if (_dirtyItemIndex === CPNotFound)
|
if (_dirtyItemIndex === CPNotFound)
|
||||||
return;
|
return;
|
||||||
@@ -278,7 +278,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
|
|
||||||
var index = _dirtyItemIndex,
|
var index = _dirtyItemIndex,
|
||||||
count = _itemViews.length,
|
count = _itemViews.length,
|
||||||
width = _CGRectGetWidth([self bounds]),
|
width = CGRectGetWidth([self bounds]),
|
||||||
y = index > 0 ? CGRectGetMaxY([_itemViews[index - 1] frame]) : 0.0;
|
y = index > 0 ? CGRectGetMaxY([_itemViews[index - 1] frame]) : 0.0;
|
||||||
|
|
||||||
// Do this now (instead of after looping), so that if we are made dirty again in the middle we don't blow this value away.
|
// Do this now (instead of after looping), so that if we are made dirty again in the middle we don't blow this value away.
|
||||||
@@ -293,7 +293,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
y = CGRectGetMaxY([itemView frame]);
|
y = CGRectGetMaxY([itemView frame]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), y)];
|
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), y)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -310,7 +310,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
|
|
||||||
- (id)initWithAccordionView:(CPAccordionView)anAccordionView
|
- (id)initWithAccordionView:(CPAccordionView)anAccordionView
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:_CGRectMakeZero()];
|
self = [super initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
@@ -376,21 +376,21 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
|||||||
|
|
||||||
- (void)setFrameY:(float)aY width:(float)aWidth
|
- (void)setFrameY:(float)aY width:(float)aWidth
|
||||||
{
|
{
|
||||||
var headerHeight = _CGRectGetHeight([_headerView frame]);
|
var headerHeight = CGRectGetHeight([_headerView frame]);
|
||||||
|
|
||||||
// Size to fit or something?
|
// Size to fit or something?
|
||||||
[_headerView setFrameSize:_CGSizeMake(aWidth, headerHeight)];
|
[_headerView setFrameSize:CGSizeMake(aWidth, headerHeight)];
|
||||||
[_contentView setFrameOrigin:_CGPointMake(0.0, headerHeight)];
|
[_contentView setFrameOrigin:CGPointMake(0.0, headerHeight)];
|
||||||
|
|
||||||
if ([self isCollapsed])
|
if ([self isCollapsed])
|
||||||
[self setFrame:_CGRectMake(0.0, aY, aWidth, headerHeight)];
|
[self setFrame:CGRectMake(0.0, aY, aWidth, headerHeight)];
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var contentHeight = _CGRectGetHeight([_contentView frame]);
|
var contentHeight = CGRectGetHeight([_contentView frame]);
|
||||||
|
|
||||||
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
|
[_contentView setFrameSize:CGSizeMake(aWidth, contentHeight)];
|
||||||
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
[self setFrame:CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+222
-109
@@ -28,15 +28,23 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import "CPApplication.j"
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
@import "CPColor.j"
|
@import "CPColor.j"
|
||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
|
@import "CPText.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
@class CPCheckBox
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
var CPAlertDelegate_alertShowHelp_ = 1 << 0,
|
||||||
|
CPAlertDelegate_alertDidEnd_returnCode_ = 1 << 1;
|
||||||
|
|
||||||
|
@typedef CPAlertStyle
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPAlertStyle
|
@group CPAlertStyle
|
||||||
@@ -53,6 +61,64 @@ CPInformationalAlertStyle = 1;
|
|||||||
*/
|
*/
|
||||||
CPCriticalAlertStyle = 2;
|
CPCriticalAlertStyle = 2;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@@ -77,31 +143,33 @@ CPCriticalAlertStyle = 2;
|
|||||||
*/
|
*/
|
||||||
@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;
|
SEL _didEndSelector @accessors(property=didEndSelector);
|
||||||
|
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
|
||||||
@@ -164,7 +232,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
_alertStyle = CPWarningAlertStyle;
|
_alertStyle = CPWarningAlertStyle;
|
||||||
_showHelp = NO;
|
_showHelp = NO;
|
||||||
_needsLayout = YES;
|
_needsLayout = YES;
|
||||||
_defaultWindowStyle = CPTitledWindowMask;
|
_defaultWindowStyle = _CPModalWindowMask;
|
||||||
_themeView = [_CPAlertThemeView new];
|
_themeView = [_CPAlertThemeView new];
|
||||||
|
|
||||||
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
||||||
@@ -180,6 +248,30 @@ CPCriticalAlertStyle = 2;
|
|||||||
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
|
||||||
@@ -212,22 +304,21 @@ CPCriticalAlertStyle = 2;
|
|||||||
[_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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! @deprecated
|
/*! @deprecated */
|
||||||
*/
|
- (void)setWindowStyle:(int)style
|
||||||
- (void)setWindowStyle:(int)aStyle
|
|
||||||
{
|
{
|
||||||
CPLog.warn("DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
|
CPLog.warn("DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
|
||||||
[self setTheme:(aStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
|
||||||
|
[self setTheme:(style === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @deprecated
|
/*! @deprecated */
|
||||||
*/
|
|
||||||
- (int)windowStyle
|
- (int)windowStyle
|
||||||
{
|
{
|
||||||
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
|
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
|
||||||
@@ -236,18 +327,19 @@ CPCriticalAlertStyle = 2;
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
set the text of the alert's message
|
Set the text of the alert's message.
|
||||||
|
|
||||||
@param aText CPString containing the text
|
@param aText CPString containing the text
|
||||||
*/
|
*/
|
||||||
- (void)setMessageText:(CPString)aText
|
- (void)setMessageText:(CPString)text
|
||||||
{
|
{
|
||||||
[_messageLabel setStringValue:aText];
|
[_messageLabel setStringValue:text];
|
||||||
_needsLayout = YES;
|
_needsLayout = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
return the content of the message text
|
Return the content of the message text.
|
||||||
|
|
||||||
@return CPString containing the message text
|
@return CPString containing the message text
|
||||||
*/
|
*/
|
||||||
- (CPString)messageText
|
- (CPString)messageText
|
||||||
@@ -256,13 +348,13 @@ CPCriticalAlertStyle = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
set the text of the alert's informative text
|
Set the text of the alert's informative text.
|
||||||
|
|
||||||
@param aText CPString containing the informative text
|
@param aText CPString containing the informative text
|
||||||
*/
|
*/
|
||||||
- (void)setInformativeText:(CPString)aText
|
- (void)setInformativeText:(CPString)text
|
||||||
{
|
{
|
||||||
[_informativeLabel setStringValue:aText];
|
[_informativeLabel setStringValue:text];
|
||||||
_needsLayout = YES;
|
_needsLayout = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +371,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
/*!
|
/*!
|
||||||
Sets the title of the alert window.
|
Sets the title of the alert window.
|
||||||
This API is not present in Cocoa.
|
This API is not present in Cocoa.
|
||||||
|
|
||||||
@param aTitle CPString containing the window title
|
@param aTitle CPString containing the window title
|
||||||
*/
|
*/
|
||||||
- (void)setTitle:(CPString)aTitle
|
- (void)setTitle:(CPString)aTitle
|
||||||
@@ -288,7 +381,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
set the accessory view
|
Set the accessory view.
|
||||||
|
|
||||||
@param aView the accessory view
|
@param aView the accessory view
|
||||||
*/
|
*/
|
||||||
@@ -299,7 +392,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
set if alert shows the suppression button
|
Set if the alert shows the suppression button.
|
||||||
|
|
||||||
@param shouldShowSuppressionButton YES or NO
|
@param shouldShowSuppressionButton YES or NO
|
||||||
*/
|
*/
|
||||||
@@ -450,6 +543,9 @@ CPCriticalAlertStyle = 2;
|
|||||||
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
||||||
panelSize = [[_window contentView] frame].size,
|
panelSize = [[_window contentView] frame].size,
|
||||||
buttonsOriginY,
|
buttonsOriginY,
|
||||||
|
buttonMarginY,
|
||||||
|
buttonMarginX,
|
||||||
|
theme = [self theme],
|
||||||
offsetX;
|
offsetX;
|
||||||
|
|
||||||
[aRepresentativeButton setTheme:[self theme]];
|
[aRepresentativeButton setTheme:[self theme]];
|
||||||
@@ -462,6 +558,19 @@ CPCriticalAlertStyle = 2;
|
|||||||
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
|
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
|
||||||
offsetX = panelSize.width - inset.right;
|
offsetX = panelSize.width - inset.right;
|
||||||
|
|
||||||
|
switch ([_window styleMask])
|
||||||
|
{
|
||||||
|
case _CPModalWindowMask:
|
||||||
|
buttonMarginY = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-y"];
|
||||||
|
buttonMarginX = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-x"];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buttonMarginY = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-y"];
|
||||||
|
buttonMarginX = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-x"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = [_buttons count] - 1; i >= 0 ; i--)
|
for (var i = [_buttons count] - 1; i >= 0 ; i--)
|
||||||
{
|
{
|
||||||
var button = _buttons[i];
|
var button = _buttons[i];
|
||||||
@@ -473,7 +582,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
height = CGRectGetHeight(buttonFrame);
|
height = CGRectGetHeight(buttonFrame);
|
||||||
|
|
||||||
offsetX -= width;
|
offsetX -= width;
|
||||||
[button setFrame:CGRectMake(offsetX, buttonsOriginY, width, height)];
|
[button setFrame:CGRectMake(offsetX + buttonMarginX, buttonsOriginY + buttonMarginY, width, height)];
|
||||||
offsetX -= 10;
|
offsetX -= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,6 +655,12 @@ CPCriticalAlertStyle = 2;
|
|||||||
[_window setFrameSize:finalSize];
|
[_window setFrameSize:finalSize];
|
||||||
[_window center];
|
[_window center];
|
||||||
|
|
||||||
|
if ([_window styleMask] & _CPModalWindowMask || [_window styleMask] & CPHUDBackgroundWindowMask)
|
||||||
|
{
|
||||||
|
[_window setMovable:YES];
|
||||||
|
[_window setMovableByWindowBackground:YES];
|
||||||
|
}
|
||||||
|
|
||||||
_needsLayout = NO;
|
_needsLayout = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,6 +683,17 @@ CPCriticalAlertStyle = 2;
|
|||||||
[CPApp runModalForWindow:_window];
|
[CPApp runModalForWindow:_window];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The same as \c runModal, but executes the code in \c block when the
|
||||||
|
alert is dismissed.
|
||||||
|
*/
|
||||||
|
- (void)runModalWithDidEndBlock:(Function /*(CPAlert alert, int returnCode)*/)block
|
||||||
|
{
|
||||||
|
_didEndBlock = block;
|
||||||
|
|
||||||
|
[self runModal];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Runs the receiver modally as an alert sheet attached to a specified window.
|
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||||
|
|
||||||
@@ -602,6 +728,20 @@ CPCriticalAlertStyle = 2;
|
|||||||
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||||
|
Executes the code in \c block when the alert is dismissed.
|
||||||
|
|
||||||
|
@param window The parent window for the sheet.
|
||||||
|
@param block Code block to execute on dismissal
|
||||||
|
*/
|
||||||
|
- (void)beginSheetModalForWindow:(CPWindow)aWindow didEndBlock:(Function /*(CPAlert alert, int returnCode)*/)block
|
||||||
|
{
|
||||||
|
_didEndBlock = block;
|
||||||
|
|
||||||
|
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Private
|
#pragma mark Private
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -612,8 +752,9 @@ CPCriticalAlertStyle = 2;
|
|||||||
var frame = CGRectMakeZero();
|
var frame = CGRectMakeZero();
|
||||||
frame.size = [_themeView currentValueForThemeAttribute:@"size"];
|
frame.size = [_themeView currentValueForThemeAttribute:@"size"];
|
||||||
|
|
||||||
_window = [[CPWindow alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
|
_window = [[CPPanel alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
|
||||||
[_window setLevel:CPStatusWindowLevel];
|
[_window setLevel:CPStatusWindowLevel];
|
||||||
|
[_window setPlatformWindow:[[CPApp keyWindow] platformWindow]];
|
||||||
|
|
||||||
if (_title)
|
if (_title)
|
||||||
[_window setTitle:_title];
|
[_window setTitle:_title];
|
||||||
@@ -640,8 +781,7 @@ CPCriticalAlertStyle = 2;
|
|||||||
*/
|
*/
|
||||||
- (@action)_showHelp:(id)aSender
|
- (@action)_showHelp:(id)aSender
|
||||||
{
|
{
|
||||||
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
|
[self _sendDelegateAlertShowHelp];
|
||||||
[_delegate alertShowHelp:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -668,84 +808,57 @@ CPCriticalAlertStyle = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
|
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
|
||||||
{
|
{
|
||||||
if (_didEndSelector)
|
if (_didEndBlock)
|
||||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
{
|
||||||
|
if (typeof(_didEndBlock) === "function")
|
||||||
|
_didEndBlock(self, returnCode);
|
||||||
|
else
|
||||||
|
CPLog.warn("%s: didEnd block is not a function", [self description]);
|
||||||
|
|
||||||
_modalDelegate = nil;
|
// didEnd blocks are transient
|
||||||
_didEndSelector = nil;
|
_didEndBlock = nil;
|
||||||
|
}
|
||||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
else if (_modalDelegate)
|
||||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
{
|
||||||
|
if (_didEndSelector)
|
||||||
|
_modalDelegate.isa.objj_msgSend3(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||||
|
}
|
||||||
|
else if (_delegate)
|
||||||
|
{
|
||||||
|
if (_didEndSelector)
|
||||||
|
_delegate.isa.objj_msgSend2(_delegate, _didEndSelector, self, returnCode);
|
||||||
|
else
|
||||||
|
[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];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
/*!
|
||||||
|
@ignore
|
||||||
|
Call the delegate alertShowHelp:
|
||||||
|
*/
|
||||||
|
- (BOOL)_sendDelegateAlertShowHelp
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[
|
if (!(_implementedDelegateMethods & CPAlertDelegate_alertShowHelp_))
|
||||||
CGSizeMake(400.0, 110.0),
|
return YES;
|
||||||
CGInsetMake(15, 15, 15, 50), 6, 10,
|
|
||||||
CPJustifiedTextAlignment,
|
return [_delegate alertShowHelp:self];
|
||||||
[CPColor blackColor],
|
|
||||||
[CPFont boldSystemFontOfSize:13.0],
|
|
||||||
[CPNull null], CGSizeMakeZero(),
|
|
||||||
CPJustifiedTextAlignment,
|
|
||||||
[CPColor blackColor],
|
|
||||||
[CPFont systemFontOfSize:12.0],
|
|
||||||
[CPNull null], CGSizeMakeZero(),
|
|
||||||
CGPointMake(15, 12),
|
|
||||||
[CPNull null],
|
|
||||||
[CPNull null],
|
|
||||||
[CPNull null],
|
|
||||||
[CPNull null],
|
|
||||||
[CPNull null],
|
|
||||||
[CPNull null],
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
3.0,
|
|
||||||
[CPColor blackColor],
|
|
||||||
[CPFont systemFontOfSize:12.0],
|
|
||||||
[CPNull null],
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
forKeys:[
|
|
||||||
@"size",
|
|
||||||
@"content-inset",
|
|
||||||
@"informative-offset",
|
|
||||||
@"button-offset",
|
|
||||||
@"message-text-alignment",
|
|
||||||
@"message-text-color",
|
|
||||||
@"message-text-font",
|
|
||||||
@"message-text-shadow-color",
|
|
||||||
@"message-text-shadow-offset",
|
|
||||||
@"informative-text-alignment",
|
|
||||||
@"informative-text-color",
|
|
||||||
@"informative-text-font",
|
|
||||||
@"informative-text-shadow-color",
|
|
||||||
@"informative-text-shadow-offset",
|
|
||||||
@"image-offset",
|
|
||||||
@"information-image",
|
|
||||||
@"warning-image",
|
|
||||||
@"error-image",
|
|
||||||
@"help-image",
|
|
||||||
@"help-image-left-offset",
|
|
||||||
@"help-image-pressed",
|
|
||||||
@"suppression-button-y-offset",
|
|
||||||
@"suppression-button-x-offset",
|
|
||||||
@"default-elements-margin",
|
|
||||||
@"suppression-button-text-color",
|
|
||||||
@"suppression-button-text-font",
|
|
||||||
@"suppression-button-text-shadow-color",
|
|
||||||
@"suppression-button-text-shadow-offset"
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+131
-45
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -123,23 +125,29 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
||||||
{
|
{
|
||||||
var timingFunctionName;
|
var timingFunctionName;
|
||||||
|
|
||||||
switch (anAnimationCurve)
|
switch (anAnimationCurve)
|
||||||
{
|
{
|
||||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
case CPAnimationEaseInOut:
|
||||||
break;
|
timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||||
|
break;
|
||||||
|
|
||||||
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
|
case CPAnimationEaseIn:
|
||||||
break;
|
timingFunctionName = kCAMediaTimingFunctionEaseIn;
|
||||||
|
break;
|
||||||
|
|
||||||
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
case CPAnimationEaseOut:
|
||||||
break;
|
timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
||||||
|
break;
|
||||||
|
|
||||||
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
|
case CPAnimationLinear:
|
||||||
break;
|
timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||||
|
break;
|
||||||
|
|
||||||
default: [CPException raise:CPInvalidArgumentException
|
default:
|
||||||
reason:"Invalid value provided for animation curve"];
|
[CPException raise:CPInvalidArgumentException
|
||||||
break;
|
reason:@"Invalid value provided for animation curve"];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_animationCurve = anAnimationCurve;
|
_animationCurve = anAnimationCurve;
|
||||||
@@ -208,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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -221,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)
|
||||||
@@ -230,7 +254,9 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
ACTUAL_FRAME_RATE = 0;
|
ACTUAL_FRAME_RATE = 0;
|
||||||
_lastTime = new Date();
|
_lastTime = new Date();
|
||||||
|
|
||||||
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
var timerInterval = _frameRate <= 0.0 ? 0.0001 : 1.0 / _frameRate;
|
||||||
|
|
||||||
|
_timer = [CPTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -252,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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -305,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;
|
||||||
@@ -322,10 +346,72 @@ 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
|
||||||
var CubicBezierAtTime = function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration)
|
var CubicBezierAtTime = function(t, p1x, p1y, p2x, p2y, duration)
|
||||||
{
|
{
|
||||||
var ax = 0,
|
var ax = 0,
|
||||||
bx = 0,
|
bx = 0,
|
||||||
|
|||||||
@@ -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
|
||||||
+209
-148
@@ -20,41 +20,48 @@
|
|||||||
* 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/CPRange.h"
|
|
||||||
|
|
||||||
@import <Foundation/CPBundle.j>
|
@import <Foundation/CPBundle.j>
|
||||||
|
|
||||||
|
@import "CPApplication_Constants.j"
|
||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
|
@import "CPColorPanel.j"
|
||||||
|
@import "CPCursor.j"
|
||||||
|
@import "CPDocumentController.j"
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPDocumentController.j"
|
|
||||||
@import "CPThemeBlend.j"
|
@import "CPThemeBlend.j"
|
||||||
@import "CPCibLoading.j"
|
@import "CPCibLoading.j"
|
||||||
|
@import "CPPanel.j"
|
||||||
@import "CPPlatform.j"
|
@import "CPPlatform.j"
|
||||||
|
@import "CPWindowController.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;
|
||||||
|
|
||||||
CPApp = nil;
|
|
||||||
|
|
||||||
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
@protocol CPApplicationDelegate <CPObject>
|
||||||
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
|
||||||
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
|
||||||
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
|
||||||
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
|
||||||
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
|
||||||
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
|
||||||
|
|
||||||
CPTerminateNow = YES;
|
@optional
|
||||||
CPTerminateCancel = NO;
|
- (CPApplicationTerminateReply)applicationShouldTerminate:(CPApplication)sender;
|
||||||
CPTerminateLater = -1; // not currently supported
|
- (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;
|
||||||
|
|
||||||
CPRunStoppedResponse = -1000;
|
@end
|
||||||
CPRunAbortedResponse = -1001;
|
|
||||||
CPRunContinuesResponse = -1002;
|
var CPApplicationDelegate_applicationShouldTerminate_ = 1 << 0,
|
||||||
|
CPApplicationDelegate_applicationShouldTerminateMessage_ = 1 << 1;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -83,35 +90,38 @@ CPRunContinuesResponse = -1002;
|
|||||||
*/
|
*/
|
||||||
@implementation CPApplication : CPResponder
|
@implementation CPApplication : CPResponder
|
||||||
{
|
{
|
||||||
CPArray _eventListeners;
|
CPArray _eventListeners;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -122,7 +132,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
+ (CPApplication)sharedApplication
|
+ (CPApplication)sharedApplication
|
||||||
{
|
{
|
||||||
if (!CPApp)
|
if (!CPApp)
|
||||||
CPApp = [[CPApplication alloc] init];
|
CPApp = [[self alloc] init];
|
||||||
|
|
||||||
return CPApp;
|
return CPApp;
|
||||||
}
|
}
|
||||||
@@ -141,6 +151,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_eventListeners = [];
|
_eventListeners = [];
|
||||||
|
_eventListenerInsertionIndex = 0;
|
||||||
|
|
||||||
_windows = [[CPNull null]];
|
_windows = [[CPNull null]];
|
||||||
}
|
}
|
||||||
@@ -156,11 +167,13 @@ CPRunContinuesResponse = -1002;
|
|||||||
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 =
|
||||||
[
|
[
|
||||||
@@ -170,7 +183,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
|
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
|
||||||
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
|
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
|
||||||
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
|
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
|
||||||
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
|
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:),
|
||||||
|
CPApplicationDidChangeScreenParametersNotification, @selector(applicationDidChangeScreenParameters:)
|
||||||
],
|
],
|
||||||
count = [delegateNotifications count];
|
count = [delegateNotifications count];
|
||||||
|
|
||||||
@@ -200,6 +214,12 @@ CPRunContinuesResponse = -1002;
|
|||||||
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_
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -368,22 +388,32 @@ CPRunContinuesResponse = -1002;
|
|||||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||||
|
|
||||||
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
|
var windowWidth = 275,
|
||||||
aboutPanelController = [CPWindowController alloc],
|
windowHeight = 223,
|
||||||
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
|
imgWidth = 100,
|
||||||
aboutPanel = [aboutPanelController window],
|
imgHeight = 100,
|
||||||
contentView = [aboutPanel contentView],
|
interField = 8,
|
||||||
imageView = [contentView viewWithTag:1],
|
aboutPanel = [[CPWindow alloc] initWithContentRect:CGRectMake(0, 0, windowWidth, windowHeight) styleMask:CPClosableWindowMask],
|
||||||
applicationLabel = [contentView viewWithTag:2],
|
imageView = [[CPImageView alloc] initWithFrame:CGRectMake((windowWidth / 2) - (imgWidth / 2), interField, imgWidth, imgHeight)],
|
||||||
versionLabel = [contentView viewWithTag:3],
|
applicationLabel = [[CPTextField alloc] initWithFrame:CGRectMake(17, imgHeight + 16, windowWidth - 34, 24)],
|
||||||
copyrightLabel = [contentView viewWithTag:4],
|
versionLabel = [[CPTextField alloc] initWithFrame:CGRectMake(17, imgHeight + 48, windowWidth - 34, 16)],
|
||||||
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
copyrightLabel = [[CPTextField alloc] initWithFrame:CGRectMake(17, imgHeight + 72, windowWidth - 34, 32)],
|
||||||
|
contentView = [aboutPanel contentView];
|
||||||
|
|
||||||
// FIXME move this into the CIB eventually
|
|
||||||
[applicationLabel setFont:[CPFont boldSystemFontOfSize:[CPFont systemFontSize] + 2]];
|
[applicationLabel setFont:[CPFont boldSystemFontOfSize:[CPFont systemFontSize] + 2]];
|
||||||
[applicationLabel setAlignment:CPCenterTextAlignment];
|
[applicationLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
[versionLabel setFont:[CPFont systemFontOfSize:[CPFont systemFontSize] - 1]];
|
||||||
[versionLabel setAlignment:CPCenterTextAlignment];
|
[versionLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
[copyrightLabel setFont:[CPFont systemFontOfSize:[CPFont systemFontSize] - 1]];
|
||||||
[copyrightLabel setAlignment:CPCenterTextAlignment];
|
[copyrightLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
[copyrightLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||||
|
|
||||||
|
[contentView addSubview:imageView];
|
||||||
|
[contentView addSubview:applicationLabel];
|
||||||
|
[contentView addSubview:versionLabel];
|
||||||
|
[contentView addSubview:copyrightLabel];
|
||||||
|
|
||||||
|
var standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
||||||
|
|
||||||
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
||||||
size:CGSizeMake(256, 256)]];
|
size:CGSizeMake(256, 256)]];
|
||||||
@@ -397,7 +427,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
else
|
else
|
||||||
[versionLabel setStringValue:@""];
|
[versionLabel setStringValue:@""];
|
||||||
|
|
||||||
[copyrightLabel setStringValue:copyright || ""];
|
[copyrightLabel setStringValue:copyright || @""];
|
||||||
[aboutPanel center];
|
[aboutPanel center];
|
||||||
|
|
||||||
_aboutPanel = aboutPanel;
|
_aboutPanel = aboutPanel;
|
||||||
@@ -407,16 +437,11 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
- (void)_documentController:(CPDocumentController)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
||||||
{
|
{
|
||||||
// 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
|
||||||
@@ -430,16 +455,22 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
- (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];
|
||||||
@@ -448,7 +479,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
[self _didResignActive];
|
[self _didResignActive];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)isActive
|
- (BOOL)isActive
|
||||||
{
|
{
|
||||||
return _isActive;
|
return _isActive;
|
||||||
}
|
}
|
||||||
@@ -465,6 +496,15 @@ CPRunContinuesResponse = -1002;
|
|||||||
- (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
|
||||||
@@ -506,6 +546,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||||
{
|
{
|
||||||
_eventListeners.splice(count, 1);
|
_eventListeners.splice(count, 1);
|
||||||
|
if (count <= _eventListenerInsertionIndex)
|
||||||
|
_eventListenerInsertionIndex--;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -553,7 +595,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
// [theWindow._bridge _obscureWindowsBelowModalWindow];
|
// [theWindow._bridge _obscureWindowsBelowModalWindow];
|
||||||
|
|
||||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -571,8 +613,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
||||||
[[self mainMenu] performKeyEquivalent:anEvent];
|
[[self mainMenu] performKeyEquivalent:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -586,42 +628,6 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
var theWindow = [anEvent window];
|
var theWindow = [anEvent window];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
var willPropagate = [[theWindow platformWindow] _willPropagateCurrentDOMEvent];
|
|
||||||
|
|
||||||
// temporarily pretend we won't propagate the event. we'll restore the saved value later
|
|
||||||
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
|
|
||||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:NO];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check if this is a candidate for key equivalent...
|
|
||||||
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
var characters = [anEvent characters],
|
|
||||||
modifierFlags = [anEvent modifierFlags];
|
|
||||||
|
|
||||||
// Unconditionally propagate on these keys to solve browser copy paste bugs
|
|
||||||
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
|
|
||||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:YES];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
// if we make it this far, then restore the original willPropagate value
|
|
||||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_eventListeners.length)
|
|
||||||
{
|
|
||||||
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
|
|
||||||
_eventListeners.pop()._callback(anEvent);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([anEvent type] == CPMouseMoved)
|
if ([anEvent type] == CPMouseMoved)
|
||||||
{
|
{
|
||||||
if (theWindow !== _lastMouseMoveWindow)
|
if (theWindow !== _lastMouseMoveWindow)
|
||||||
@@ -630,6 +636,39 @@ CPRunContinuesResponse = -1002;
|
|||||||
_lastMouseMoveWindow = theWindow;
|
_lastMouseMoveWindow = theWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event listeners are processed from back to front so that newer event listeners normally take
|
||||||
|
precedence. If during the execution of a callback a new event listener is added, it should
|
||||||
|
be inserted after the current callback but before any higher priority callbacks. This makes
|
||||||
|
repeating event listeners (those that reinsert themselves) stable relative to each other.
|
||||||
|
*/
|
||||||
|
for (var i = _eventListeners.length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var listener = _eventListeners[i];
|
||||||
|
|
||||||
|
if (listener._mask & (1 << [anEvent type]))
|
||||||
|
{
|
||||||
|
_eventListeners.splice(i, 1);
|
||||||
|
// In case the callback wants to add more listeners.
|
||||||
|
_eventListenerInsertionIndex = i;
|
||||||
|
listener._callback(anEvent);
|
||||||
|
|
||||||
|
if (listener._dequeue)
|
||||||
|
{
|
||||||
|
// Don't process the event normally and don't send it to any other listener.
|
||||||
|
_eventListenerInsertionIndex = _eventListeners.length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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];
|
||||||
}
|
}
|
||||||
@@ -680,7 +719,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
- (CPArray)windows
|
- (CPArray)windows
|
||||||
{
|
{
|
||||||
// Return all windows, but not the CPNull placeholder in _windows[0].
|
// Return all windows, but not the CPNull placeholder in _windows[0].
|
||||||
return [_windows subarrayWithRange:_CPMakeRange(1, [_windows count] - 1)];
|
return [_windows subarrayWithRange:CPMakeRange(1, [_windows count] - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -908,31 +947,44 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Fires a callback function when an event matching a given mask occurs.
|
Fires a callback function when an event matching a given mask occurs.
|
||||||
@param aCallback - A js function to be fired.
|
|
||||||
@prarm aMask - An event mask for the next event.
|
If multiple callbacks are set which match the same event, later callbacks
|
||||||
@param anExpiration - The date for which this callback expires (not implemented).
|
take priority over earlier callbacks, unless a new callback is set while
|
||||||
|
an existing callback is being processed in which case it's given the same
|
||||||
|
priority as the currently processing callback.
|
||||||
|
|
||||||
|
@param aCallback A js function to be fired.
|
||||||
|
@prarm aMask An event mask for the next event.
|
||||||
|
@param anExpiration The date for which this callback expires (not implemented).
|
||||||
@param inMode (not implemented).
|
@param inMode (not implemented).
|
||||||
@param shouldDequeue (not implemented).
|
@param shouldDequeue YES to remove the event from the queue after calling the callback,
|
||||||
|
NO to deliver it normally.
|
||||||
*/
|
*/
|
||||||
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||||
{
|
{
|
||||||
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
|
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, aCallback, shouldDequeue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Assigns a target and action for the next event matching a given event mask.
|
Assigns a target and action for the next event matching a given event mask.
|
||||||
The callback method called will be passed the CPEvent when it fires.
|
The callback method called will be passed the CPEvent when it fires.
|
||||||
|
|
||||||
@param aTarget - The target object for the callback.
|
If multiple callbacks are set which match the same event, later callbacks
|
||||||
@param aSelector - The selector which should be called on the target object.
|
take priority over earlier callbacks, unless a new callback is set while
|
||||||
@param aMask - The mask for a given event which should trigger the callback.
|
an existing callback is being processed in which case it's given the same
|
||||||
@param anExpiration - The date for which the callback expires (not implemented).
|
priority as the currently processing callback.
|
||||||
|
|
||||||
|
@param aTarget The target object for the callback.
|
||||||
|
@param aSelector The selector which should be called on the target object.
|
||||||
|
@param aMask The mask for a given event which should trigger the callback.
|
||||||
|
@param anExpiration The date for which the callback expires (not implemented).
|
||||||
@param aMode (not implemented).
|
@param aMode (not implemented).
|
||||||
@param shouldDequeue (not implemented).
|
@param shouldDequeue YES to remove the event from the queue after calling the callback,
|
||||||
|
NO to deliver it normally.
|
||||||
*/
|
*/
|
||||||
- (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.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
|
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { if (aTarget != null) aTarget.isa.objj_msgSend1(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -950,10 +1002,10 @@ CPRunContinuesResponse = -1002;
|
|||||||
@param aSheet the window to display as a sheet
|
@param aSheet the window to display as a sheet
|
||||||
@param aWindow the window that will hold the sheet as a child
|
@param aWindow the window that will hold the sheet as a child
|
||||||
@param aModalDelegate
|
@param aModalDelegate
|
||||||
@param aDidEndSelector
|
@param didEndSelector
|
||||||
@param aContextInfo
|
@param contextInfo
|
||||||
*/
|
*/
|
||||||
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
|
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(id)contextInfo
|
||||||
{
|
{
|
||||||
if ([aWindow isSheet])
|
if ([aWindow isSheet])
|
||||||
{
|
{
|
||||||
@@ -961,17 +1013,10 @@ CPRunContinuesResponse = -1002;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[aSheet._windowView _enableSheet:YES];
|
if (![aWindow attachedSheet])
|
||||||
|
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
||||||
|
|
||||||
// -dw- if a sheet is already visible, we skip this since it serves no purpose and causes
|
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:didEndSelector contextInfo:contextInfo];
|
||||||
// orderOut: to be called on the sheet, which is not what we want.
|
|
||||||
if (![aWindow isVisible])
|
|
||||||
{
|
|
||||||
[aWindow orderFront:self];
|
|
||||||
[aSheet setPlatformWindow:[aWindow platformWindow]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -996,7 +1041,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
var aWindow = [_windows objectAtIndex:count],
|
var aWindow = [_windows objectAtIndex:count],
|
||||||
context = aWindow._sheetContext;
|
context = aWindow._sheetContext;
|
||||||
|
|
||||||
if (context != nil && context["sheet"] === sheet)
|
if (context && context["sheet"] === sheet)
|
||||||
{
|
{
|
||||||
context["returnCode"] = returnCode;
|
context["returnCode"] = returnCode;
|
||||||
[aWindow _endSheet];
|
[aWindow _endSheet];
|
||||||
@@ -1157,7 +1202,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
[[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;
|
||||||
@@ -1175,6 +1220,22 @@ CPRunContinuesResponse = -1002;
|
|||||||
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)
|
||||||
@@ -1199,7 +1260,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
+ (CPString)defaultThemeName
|
+ (CPString)defaultThemeName
|
||||||
{
|
{
|
||||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -1209,28 +1270,29 @@ var _CPModalSessionMake = function(aWindow, aStopCode)
|
|||||||
return { _window:aWindow, _state:CPRunContinuesResponse , _previous:nil };
|
return { _window:aWindow, _state:CPRunContinuesResponse , _previous:nil };
|
||||||
};
|
};
|
||||||
|
|
||||||
var _CPEventListenerMake = function(anEventMask, aCallback)
|
var _CPEventListenerMake = function(anEventMask, aCallback, shouldDequeue)
|
||||||
{
|
{
|
||||||
return { _mask:anEventMask, _callback:aCallback };
|
return { _mask:anEventMask, _callback:aCallback, _dequeue:shouldDequeue };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make this a global for use in CPPlatformWindow+DOM.j.
|
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||||
_CPRunModalLoop = function(anEvent)
|
_CPRunModalLoop = function(anEvent)
|
||||||
{
|
{
|
||||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:YES];
|
||||||
|
|
||||||
var theWindow = [anEvent window],
|
var theWindow = [anEvent window],
|
||||||
modalSession = CPApp._currentSession;
|
modalSession = CPApp._currentSession;
|
||||||
|
|
||||||
// The special case for popovers here is not clear. In Cocoa the popover window does not respond YES to worksWhenModal,
|
/*
|
||||||
// yet it works when there is a modal window. Maybe it starts its own modal session, but interaction with the original
|
The special case for popovers here is not clear. In Cocoa the popover window does not respond YES to worksWhenModal, yet it works when there is a modal window. Maybe it starts its own modal session, but interaction with the original modal window seems to continue working as well. Regardless of correctness, this solution beats popovers not working at all from sheets.
|
||||||
// modal window seems to continue working as well. Regardless of correctness, this solution beats popovers not working
|
*/
|
||||||
// at all from sheets.
|
|
||||||
if (theWindow == modalSession._window ||
|
if (theWindow == modalSession._window ||
|
||||||
[theWindow worksWhenModal] ||
|
[theWindow worksWhenModal] ||
|
||||||
[theWindow attachedSheet] == modalSession._window || // -dw- allow modal parent of sheet to be repositioned
|
[theWindow attachedSheet] == modalSession._window || // -dw- allow modal parent of sheet to be repositioned
|
||||||
([theWindow isKindOfClass:_CPAttachedWindow] && [[theWindow targetView] window] === modalSession._window))
|
([theWindow isKindOfClass:_CPPopoverWindow] && [[theWindow targetView] window] === modalSession._window))
|
||||||
|
{
|
||||||
[theWindow sendEvent:anEvent];
|
[theWindow sendEvent:anEvent];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1296,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1313,7 +1375,7 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
var defaultThemeName = [CPApplication defaultThemeName],
|
var defaultThemeName = [CPApplication defaultThemeName],
|
||||||
themeURL = nil;
|
themeURL = nil;
|
||||||
|
|
||||||
if (defaultThemeName === @"Aristo")
|
if (defaultThemeName === @"Aristo" || defaultThemeName === @"Aristo2")
|
||||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||||
else
|
else
|
||||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||||
@@ -1340,8 +1402,8 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
if (mainCibFile)
|
if (mainCibFile)
|
||||||
{
|
{
|
||||||
[mainBundle loadCibFile:mainCibFile
|
[mainBundle loadCibFile:mainCibFile
|
||||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
externalNameTable:@{ CPCibOwner: CPApp }
|
||||||
loadDelegate:self];
|
loadDelegate:self];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@@ -1358,26 +1420,25 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
// FIXME: We should implement autoenabling.
|
// FIXME: We should implement autoenabling.
|
||||||
[mainMenu setAutoenablesItems:NO];
|
[mainMenu setAutoenablesItems:NO];
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
var newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
||||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
|
||||||
|
|
||||||
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
[newMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-new" forClass:_CPMenuView]];
|
||||||
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[newMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-new" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||||
|
|
||||||
[mainMenu addItem:newMenuItem];
|
[mainMenu addItem:newMenuItem];
|
||||||
|
|
||||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
|
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
|
||||||
|
|
||||||
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
[openMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-open" forClass:_CPMenuView]];
|
||||||
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[openMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-open" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||||
|
|
||||||
[mainMenu addItem:openMenuItem];
|
[mainMenu addItem:openMenuItem];
|
||||||
|
|
||||||
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
||||||
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
||||||
|
|
||||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
[saveMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-save" forClass:_CPMenuView]];
|
||||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[saveMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-save" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||||
|
|
||||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
||||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
||||||
@@ -1419,7 +1480,7 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
|
|
||||||
+ (void)cibDidFailToLoad:(CPCib)aCib
|
+ (void)cibDidFailToLoad:(CPCib)aCib
|
||||||
{
|
{
|
||||||
throw new Error("Could not load main cib file (Did you forget to nib2cib it?).");
|
throw new Error("Could not load main cib file. Did you forget to nib2cib it?");
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)reset
|
+ (void)reset
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* CPApplication_Constants.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Aparajita Fishman.
|
||||||
|
* Copyright 2013 The 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
CPApp = nil;
|
||||||
|
|
||||||
|
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
||||||
|
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
||||||
|
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
||||||
|
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
||||||
|
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
||||||
|
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
||||||
|
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||||
|
CPApplicationDidChangeScreenParametersNotification = @"CPApplicationDidChangeScreenParametersNotification";
|
||||||
|
|
||||||
|
@typedef CPApplicationTerminateReply
|
||||||
|
CPTerminateNow = YES;
|
||||||
|
CPTerminateCancel = NO;
|
||||||
|
CPTerminateLater = -1; // not currently supported
|
||||||
|
|
||||||
|
CPRunStoppedResponse = -1000;
|
||||||
|
CPRunAbortedResponse = -1001;
|
||||||
|
CPRunContinuesResponse = -1002;
|
||||||
+68
-45
@@ -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"
|
||||||
|
|
||||||
@@ -65,51 +65,51 @@
|
|||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingContentArray
|
+ (CPSet)keyPathsForValuesAffectingContentArray
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"content"];
|
return [CPSet setWithObjects:@"content"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
||||||
{
|
{
|
||||||
// Also depends on "filterPredicate" but we'll handle that manually.
|
// Also depends on "filterPredicate" but we'll handle that manually.
|
||||||
return [CPSet setWithObjects:"content", "sortDescriptors"];
|
return [CPSet setWithObjects:@"content", @"sortDescriptors"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingSelection
|
+ (CPSet)keyPathsForValuesAffectingSelection
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
|
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
|
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
|
||||||
{
|
{
|
||||||
// When the arranged objects change, selection preservation may cause the indexes
|
// When the arranged objects change, selection preservation may cause the indexes
|
||||||
// to change.
|
// to change.
|
||||||
return [CPSet setWithObjects:"arrangedObjects"];
|
return [CPSet setWithObjects:@"arrangedObjects"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
|
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
|
||||||
{
|
{
|
||||||
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
|
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
|
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
|
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
|
||||||
{
|
{
|
||||||
return [CPSet setWithObjects:"selectionIndexes"];
|
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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.
|
||||||
@@ -744,6 +743,7 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var willClearPredicate = NO;
|
var willClearPredicate = NO;
|
||||||
|
|
||||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||||
{
|
{
|
||||||
[self willChangeValueForKey:@"filterPredicate"];
|
[self willChangeValueForKey:@"filterPredicate"];
|
||||||
@@ -773,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];
|
||||||
@@ -786,16 +786,24 @@
|
|||||||
[_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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This will also send notificaitons for arrangedObjects.
|
// TODO: Remove these lines when granular notifications are implemented
|
||||||
|
var proxy = [_CPKVOProxy proxyForObject:self];
|
||||||
|
[proxy setAdding:YES];
|
||||||
|
|
||||||
|
// This will also send notifications for arrangedObjects.
|
||||||
[self didChangeValueForKey:@"content"];
|
[self didChangeValueForKey:@"content"];
|
||||||
|
|
||||||
if (willClearPredicate)
|
if (willClearPredicate)
|
||||||
[self didChangeValueForKey:@"filterPredicate"];
|
[self didChangeValueForKey:@"filterPredicate"];
|
||||||
|
|
||||||
|
// TODO: Remove this line when granular notifications are implemented
|
||||||
|
[proxy setAdding:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -811,6 +819,7 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var willClearPredicate = NO;
|
var willClearPredicate = NO;
|
||||||
|
|
||||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||||
{
|
{
|
||||||
[self willChangeValueForKey:@"filterPredicate"];
|
[self willChangeValueForKey:@"filterPredicate"];
|
||||||
@@ -848,9 +857,15 @@
|
|||||||
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
|
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
|
||||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
||||||
|
|
||||||
|
var proxy = [_CPKVOProxy proxyForObject:self];
|
||||||
|
[proxy setAdding:YES];
|
||||||
|
|
||||||
[self didChangeValueForKey:@"content"];
|
[self didChangeValueForKey:@"content"];
|
||||||
|
|
||||||
if (willClearPredicate)
|
if (willClearPredicate)
|
||||||
[self didChangeValueForKey:@"filterPredicate"];
|
[self didChangeValueForKey:@"filterPredicate"];
|
||||||
|
|
||||||
|
[proxy setAdding:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -871,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.
|
||||||
@@ -897,7 +912,9 @@
|
|||||||
if (![self canAdd])
|
if (![self canAdd])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self insert:sender];
|
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
||||||
|
|
||||||
|
[self addObject:newObject];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -909,9 +926,13 @@
|
|||||||
if (![self canInsert])
|
if (![self canInsert])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject],
|
||||||
|
lastSelectedIndex = [_selectionIndexes lastIndex];
|
||||||
|
|
||||||
[self addObject:newObject];
|
if (lastSelectedIndex !== CPNotFound)
|
||||||
|
[self insertObject:newObject atArrangedObjectIndex:lastSelectedIndex];
|
||||||
|
else
|
||||||
|
[self addObject:newObject];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -964,7 +985,7 @@
|
|||||||
// be the 'wrong' one - as in not the one the user selected - but the wrong
|
// be the 'wrong' one - as in not the one the user selected - but the wrong
|
||||||
// one is still just another pointer to the same object, so the user will not
|
// one is still just another pointer to the same object, so the user will not
|
||||||
// be able to see any difference.
|
// be able to see any difference.
|
||||||
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
|
var contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
|
||||||
[_contentObject removeObjectAtIndex:contentIndex];
|
[_contentObject removeObjectAtIndex:contentIndex];
|
||||||
}
|
}
|
||||||
[arrangedObjects removeObjectAtIndex:anIndex];
|
[arrangedObjects removeObjectAtIndex:anIndex];
|
||||||
@@ -1073,12 +1094,12 @@
|
|||||||
|
|
||||||
@implementation CPArrayController (CPBinder)
|
@implementation CPArrayController (CPBinder)
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding == @"contentArray")
|
if (aBinding == @"contentArray")
|
||||||
return [_CPArrayControllerContentBinder class];
|
return [_CPArrayControllerContentBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -1093,7 +1114,8 @@
|
|||||||
isCompound = [self handlesContentAsCompoundValue],
|
isCompound = [self handlesContentAsCompoundValue],
|
||||||
dotIndex = keyPath.lastIndexOf("."),
|
dotIndex = keyPath.lastIndexOf("."),
|
||||||
firstPart = dotIndex !== CPNotFound ? keyPath.substring(0, dotIndex) : nil,
|
firstPart = dotIndex !== CPNotFound ? keyPath.substring(0, dotIndex) : nil,
|
||||||
isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy];
|
isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy],
|
||||||
|
newValue;
|
||||||
|
|
||||||
if (!isCompound && !isSelectionProxy)
|
if (!isCompound && !isSelectionProxy)
|
||||||
{
|
{
|
||||||
@@ -1113,6 +1135,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isPlaceholder = CPIsControllerMarker(newValue);
|
var isPlaceholder = CPIsControllerMarker(newValue);
|
||||||
|
|
||||||
if (isPlaceholder)
|
if (isPlaceholder)
|
||||||
{
|
{
|
||||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||||
|
|||||||
+59
-5
@@ -48,6 +48,8 @@ var DefaultLineWidth = 1.0;
|
|||||||
{
|
{
|
||||||
CGPath _path;
|
CGPath _path;
|
||||||
float _lineWidth;
|
float _lineWidth;
|
||||||
|
CPArray _lineDashes;
|
||||||
|
float _lineDashesPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -61,11 +63,11 @@ var DefaultLineWidth = 1.0;
|
|||||||
/*!
|
/*!
|
||||||
Create a new CPBezierPath object initialized with an oval path drawn within a rectangular path.
|
Create a new CPBezierPath object initialized with an oval path drawn within a rectangular path.
|
||||||
*/
|
*/
|
||||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var path = [self bezierPath];
|
var path = [self bezierPath];
|
||||||
|
|
||||||
[path appendBezierPathWithOvalInRect:rect];
|
[path appendBezierPathWithOvalInRect:aRect];
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -73,11 +75,20 @@ var DefaultLineWidth = 1.0;
|
|||||||
/*!
|
/*!
|
||||||
Create a new CPBezierPath object initialized with a rectangular path.
|
Create a new CPBezierPath object initialized with a rectangular path.
|
||||||
*/
|
*/
|
||||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
+ (CPBezierPath)bezierPathWithRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var path = [self bezierPath];
|
var path = [self bezierPath];
|
||||||
|
|
||||||
[path appendBezierPathWithRect:rect];
|
[path appendBezierPathWithRect:aRect];
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPBezierPath)bezierPathWithRoundedRect:(CGRect)aRect xRadius:(float)xRadius yRadius:(float)yRadius
|
||||||
|
{
|
||||||
|
var path = [self bezierPath];
|
||||||
|
|
||||||
|
[path appendBezierPathWithRoundedRect:aRect xRadius:xRadius yRadius:yRadius];
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -136,6 +147,8 @@ var DefaultLineWidth = 1.0;
|
|||||||
{
|
{
|
||||||
_path = CGPathCreateMutable();
|
_path = CGPathCreateMutable();
|
||||||
_lineWidth = [[self class] defaultLineWidth];
|
_lineWidth = [[self class] defaultLineWidth];
|
||||||
|
_lineDashesPhase = 0;
|
||||||
|
_lineDashes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -168,7 +181,7 @@ var DefaultLineWidth = 1.0;
|
|||||||
- (CGRect)bounds
|
- (CGRect)bounds
|
||||||
{
|
{
|
||||||
// TODO: this should return this. The controlPointBounds is not a tight fit.
|
// TODO: this should return this. The controlPointBounds is not a tight fit.
|
||||||
// return CGPathGetPathBoundingBox(_path);
|
// return CGPathGetBoundingBox(_path);
|
||||||
|
|
||||||
return [self controlPointBounds];
|
return [self controlPointBounds];
|
||||||
}
|
}
|
||||||
@@ -196,6 +209,7 @@ var DefaultLineWidth = 1.0;
|
|||||||
CGContextBeginPath(ctx);
|
CGContextBeginPath(ctx);
|
||||||
CGContextAddPath(ctx, _path);
|
CGContextAddPath(ctx, _path);
|
||||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||||
|
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||||
CGContextStrokePath(ctx);
|
CGContextStrokePath(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,10 +223,50 @@ var DefaultLineWidth = 1.0;
|
|||||||
CGContextBeginPath(ctx);
|
CGContextBeginPath(ctx);
|
||||||
CGContextAddPath(ctx, _path);
|
CGContextAddPath(ctx, _path);
|
||||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||||
|
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||||
CGContextClosePath(ctx);
|
CGContextClosePath(ctx);
|
||||||
CGContextFillPath(ctx);
|
CGContextFillPath(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Cocoa compatibility.
|
||||||
|
*/
|
||||||
|
- (void)getLineDash:(CPArrayRef)patternRef count:(CPInteger)count phase:(CGFloatRef)phaseRef
|
||||||
|
{
|
||||||
|
return [self getLineDash:patternRef phase:phaseRef];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Retrieve the line dash pattern and phase and write them into the provided references.
|
||||||
|
*/
|
||||||
|
- (void)getLineDash:(CPArrayRef)patternRef phase:(CGFloatRef)phaseRef
|
||||||
|
{
|
||||||
|
if (patternRef)
|
||||||
|
@deref(patternRef) = [_lineDashes copy];
|
||||||
|
if (phaseRef)
|
||||||
|
@deref(phaseRef) = _lineDashesPhase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Cocoa compatibility.
|
||||||
|
*/
|
||||||
|
- (void)setLineDash:(CPArray)aPattern count:(CPInteger)count phase:(CGFloat)aPhase
|
||||||
|
{
|
||||||
|
[self setLineDash:aPattern phase:aPhase];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set stroke line dash pattern.
|
||||||
|
|
||||||
|
@param aPattern an array of stroke-skip lengths such as [2, 2, 4, 4]
|
||||||
|
@param aPhase amount of shift for the starting position of the first stroke
|
||||||
|
*/
|
||||||
|
- (void)setLineDash:(CPArray)aPattern phase:(CGFloat)aPhase
|
||||||
|
{
|
||||||
|
_lineDashes = aPattern;
|
||||||
|
_lineDashesPhase = aPhase;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Get the line width.
|
Get the line width.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+515
-139
@@ -20,22 +20,27 @@
|
|||||||
* 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 "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;
|
||||||
@@ -54,20 +59,51 @@ CPBelowBottom = 6;
|
|||||||
@implementation CPBox : CPView
|
@implementation CPBox : CPView
|
||||||
{
|
{
|
||||||
CPBoxType _boxType;
|
CPBoxType _boxType;
|
||||||
CPBorderType _borderType;
|
CPBorderType _borderType; // deprecated
|
||||||
|
|
||||||
CPColor _borderColor;
|
|
||||||
CPColor _fillColor;
|
|
||||||
|
|
||||||
float _cornerRadius;
|
|
||||||
float _borderWidth;
|
|
||||||
|
|
||||||
CPSize _contentMargin;
|
|
||||||
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
|
||||||
|
{
|
||||||
|
if ([aBinding hasPrefix:CPDisplayPatternTitleBinding])
|
||||||
|
return [CPTitleWithPatternBinding class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"box";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"background-color": [CPNull null],
|
||||||
|
@"border-color": [CPNull null],
|
||||||
|
@"border-width": 1.0,
|
||||||
|
@"corner-radius": 3.0,
|
||||||
|
@"inner-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"inner-shadow-size": 6.0,
|
||||||
|
@"inner-shadow-color": [CPNull null],
|
||||||
|
@"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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)boxEnclosingView:(CPView)aView
|
+ (id)boxEnclosingView:(CPView)aView
|
||||||
@@ -85,27 +121,32 @@ CPBelowBottom = 6;
|
|||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)frameRect
|
- (id)initWithFrame:(CGRect)frameRect
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:frameRect];
|
self = [super initWithFrame:frameRect];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_borderType = CPBezelBorder;
|
_borderType = CPGrooveBorder; // Was CPBezelBorder but Cocoa default is CPGrooveBorder
|
||||||
_fillColor = [CPColor clearColor];
|
_boxType = CPBoxPrimary;
|
||||||
_borderColor = [CPColor blackColor];
|
|
||||||
|
|
||||||
_borderWidth = 1.0;
|
|
||||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
|
||||||
|
|
||||||
_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;
|
||||||
@@ -118,7 +159,7 @@ CPBelowBottom = 6;
|
|||||||
|
|
||||||
@return the border rectangle of the box
|
@return the border rectangle of the box
|
||||||
*/
|
*/
|
||||||
- (CPRect)borderRect
|
- (CGRect)borderRect
|
||||||
{
|
{
|
||||||
return [self bounds];
|
return [self bounds];
|
||||||
}
|
}
|
||||||
@@ -137,6 +178,8 @@ CPBelowBottom = 6;
|
|||||||
*/
|
*/
|
||||||
- (CPBorderType)borderType
|
- (CPBorderType)borderType
|
||||||
{
|
{
|
||||||
|
CPLog.warn("CPBox borderType is deprecated.");
|
||||||
|
|
||||||
return _borderType;
|
return _borderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +202,8 @@ CPBelowBottom = 6;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_borderType = aBorderType;
|
_borderType = aBorderType;
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -199,67 +243,146 @@ 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 _borderColor;
|
return [self valueForThemeAttribute:@"border-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBorderColor:(CPColor)color
|
- (void)setBorderColor:(CPColor)color
|
||||||
{
|
{
|
||||||
if ([color isEqual:_borderColor])
|
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]])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_borderColor = color;
|
[self setValue:color forThemeAttribute:@"border-color"];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark borderWidth
|
||||||
- (float)borderWidth
|
- (float)borderWidth
|
||||||
{
|
{
|
||||||
return _borderWidth;
|
return [self valueForThemeAttribute:@"border-width"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBorderWidth:(float)width
|
- (void)setBorderWidth:(float)width
|
||||||
{
|
{
|
||||||
if (width === _borderWidth)
|
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])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_borderWidth = width;
|
[self setValue:width forThemeAttribute:@"border-width"];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark cornerRadius
|
||||||
- (float)cornerRadius
|
- (float)cornerRadius
|
||||||
{
|
{
|
||||||
return _cornerRadius;
|
return [self valueForThemeAttribute:@"corner-radius"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCornerRadius:(float)radius
|
- (void)setCornerRadius:(float)radius
|
||||||
{
|
{
|
||||||
if (radius === _cornerRadius)
|
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])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_cornerRadius = radius;
|
[self setValue:radius forThemeAttribute:@"corner-radius"];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See discussion above.
|
||||||
|
#pragma mark fillColor
|
||||||
- (CPColor)fillColor
|
- (CPColor)fillColor
|
||||||
{
|
{
|
||||||
return _fillColor;
|
return [self valueForThemeAttribute:@"background-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFillColor:(CPColor)color
|
- (void)setFillColor:(CPColor)color
|
||||||
{
|
{
|
||||||
if ([color isEqual:_fillColor])
|
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]])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_fillColor = color;
|
[self setValue:color forThemeAttribute:@"background-color"];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)contentView
|
- (CPView)contentView
|
||||||
@@ -272,34 +395,47 @@ CPBelowBottom = 6;
|
|||||||
if (aView === _contentView)
|
if (aView === _contentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
|
||||||
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
[self replaceSubview:_contentView with:aView];
|
|
||||||
|
// 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;
|
_contentView = aView;
|
||||||
|
|
||||||
|
[self sizeToFit];
|
||||||
|
[self refreshDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPSize)contentViewMargins
|
- (CGSize)contentViewMargins
|
||||||
{
|
{
|
||||||
return _contentMargin;
|
return [self valueForThemeAttribute:@"content-margin"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setContentViewMargins:(CPSize)size
|
- (void)setContentViewMargins:(CGSize)size
|
||||||
{
|
{
|
||||||
if (size.width < 0 || size.height < 0)
|
if (size.width < 0 || size.height < 0)
|
||||||
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
||||||
|
|
||||||
_contentMargin = CGSizeMakeCopy(size);
|
[self setValue:CGSizeMakeCopy(size) forThemeAttribute:@"content-margin"];
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrameFromContentFrame:(CPRect)aRect
|
- (void)setFrameFromContentFrame:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var offset = [self _titleHeightOffset];
|
var offset = [self _titleHeightOffset],
|
||||||
|
borderWidth = [self borderWidth],
|
||||||
|
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,
|
||||||
[self setNeedsDisplay:YES];
|
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
|
||||||
@@ -324,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.
|
||||||
|
|
||||||
@@ -342,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:CPPointMake(5.0, 0.0)];
|
[_titleView setFrameOrigin:CGPointMake(titleLeftOffset, titleTopOffset)]; // FIXME: was 0.0
|
||||||
[_titleView setAutoresizingMask:CPViewNotSizable];
|
[_titleView setAutoresizingMask:CPViewNotSizable];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -368,69 +546,85 @@ CPBelowBottom = 6;
|
|||||||
case CPAtBottom:
|
case CPAtBottom:
|
||||||
case CPBelowBottom:
|
case CPBelowBottom:
|
||||||
var h = [_titleView frameSize].height;
|
var h = [_titleView frameSize].height;
|
||||||
[_titleView setFrameOrigin:CPPointMake(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];
|
||||||
|
|
||||||
if (!contentFrame)
|
[_boxView setFrame:CGRectMake(0, offset[1], size.width, size.height - offset[0])];
|
||||||
|
|
||||||
|
if (!_contentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_contentView setAutoresizingMask:CPViewNotSizable];
|
var boxSize = [_boxView frameSize],
|
||||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
contentMargin = [self valueForThemeAttribute:@"content-margin"],
|
||||||
contentFrame.size.height + _contentMargin.height * 2 + offset[0])];
|
contentAdjustment = [self valueForThemeAttribute:@"content-adjustment"],
|
||||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
borderWidth = [self valueForThemeAttribute:@"border-width"],
|
||||||
|
minYCorrection = [self valueForThemeAttribute:(_titlePosition === CPNoTitle ? @"min-y-correction-no-title" : @"min-y-correction-title")];
|
||||||
|
|
||||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height + offset[1])];
|
[_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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CPRect)rect
|
- (void)setValue:(id)aValue forKey:(CPString)aKey
|
||||||
{
|
{
|
||||||
if (_borderType === CPNoBorder)
|
if (aKey === CPDisplayPatternTitleBinding)
|
||||||
|
[self setTitle:aValue || @""];
|
||||||
|
else
|
||||||
|
[super setValue:aValue forKey:aKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)rect
|
||||||
|
{
|
||||||
|
if ([self isCSSBased] && (_boxType !== CPBoxCustom))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var bounds = CGRectMakeCopy([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 _drawVerticalSeperatorInRect:bounds];
|
else if (CGRectGetHeight(bounds) === 5.0)
|
||||||
else if (CGRectGetHeight(bounds) === 5.0)
|
return [self _drawHorizontalSeparatorInRect:bounds];
|
||||||
return [self _drawHorizontalSeperatorInRect:bounds];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_transparent)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_titlePosition == CPAtTop)
|
if (_titlePosition == CPAtTop)
|
||||||
{
|
{
|
||||||
bounds.origin.y += [_titleView frameSize].height;
|
bounds.origin.y += [_titleView frameSize].height;
|
||||||
@@ -441,84 +635,209 @@ CPBelowBottom = 6;
|
|||||||
bounds.size.height -= [_titleView frameSize].height;
|
bounds.size.height -= [_titleView frameSize].height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Primary or secondary type boxes always draw the same way, unless they are CPNoBorder.
|
||||||
|
if ((_boxType === CPBoxPrimary || _boxType === CPBoxSecondary) && _borderType !== CPNoBorder)
|
||||||
|
{
|
||||||
|
[self _drawPrimaryBorderInRect:bounds];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (_borderType)
|
switch (_borderType)
|
||||||
{
|
{
|
||||||
case CPBezelBorder:
|
case CPBezelBorder:
|
||||||
[self _drawBezelBorderInRect:bounds];
|
case CPGrooveBorder:
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
case CPLineBorder:
|
case CPLineBorder:
|
||||||
[self _drawLineBorderInRect:bounds];
|
[self _drawLineBorderInRect:bounds];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CPNoBorder:
|
||||||
|
[self _drawNoBorderInRect:bounds];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
|
- (void)_drawHorizontalSeparatorInRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
CGContextSetStrokeColor(context, [self borderColor]);
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
CGContextSetLineWidth(context, 1.0);
|
CGContextSetLineWidth(context, 1.0);
|
||||||
|
|
||||||
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect) + 0.5);
|
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMidY(aRect));
|
||||||
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect) + 0.5);
|
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMidY(aRect));
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
|
- (void)_drawVerticalSeparatorInRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
CGContextSetStrokeColor(context, [self borderColor]);
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
CGContextSetLineWidth(context, 1.0);
|
CGContextSetLineWidth(context, 1.0);
|
||||||
|
|
||||||
CGContextMoveToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetMinY(aRect));
|
CGContextMoveToPoint(context, CGRectGetMidX(aRect), CGRectGetMinY(aRect));
|
||||||
CGContextAddLineToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetHeight(aRect));
|
CGContextAddLineToPoint(context, CGRectGetMidX(aRect), CGRectGetHeight(aRect));
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_drawLineBorderInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
cornerRadius = [self cornerRadius],
|
||||||
|
borderWidth = [self borderWidth];
|
||||||
|
|
||||||
|
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||||
|
|
||||||
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
|
||||||
|
CGContextSetLineWidth(context, borderWidth);
|
||||||
|
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_drawBezelBorderInRect:(CGRect)aRect
|
- (void)_drawBezelBorderInRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
|
cornerRadius = [self cornerRadius],
|
||||||
sideGray = 190.0 / 255.0,
|
borderWidth = [self borderWidth],
|
||||||
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
|
shadowOffset = [self valueForThemeAttribute:@"inner-shadow-offset"],
|
||||||
borderWidth = _borderWidth;
|
shadowSize = [self valueForThemeAttribute:@"inner-shadow-size"],
|
||||||
|
shadowColor = [self valueForThemeAttribute:@"inner-shadow-color"];
|
||||||
|
|
||||||
while (borderWidth--)
|
var baseRect = aRect;
|
||||||
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
|
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||||
|
|
||||||
|
CGContextSaveGState(context);
|
||||||
|
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
CGContextSetLineWidth(context, borderWidth);
|
||||||
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
|
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
|
||||||
|
CGContextRestoreGState(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawPrimaryBorderInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
// Draw the "primary" style CPBox.
|
||||||
|
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
cornerRadius = [self cornerRadius],
|
||||||
|
borderWidth = [self borderWidth],
|
||||||
|
shadowOffset = [self valueForThemeAttribute:@"inner-shadow-offset"],
|
||||||
|
shadowSize = [self valueForThemeAttribute:@"inner-shadow-size"],
|
||||||
|
shadowColor = [self valueForThemeAttribute:@"inner-shadow-color"],
|
||||||
|
baseRect = aRect;
|
||||||
|
|
||||||
|
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||||
|
|
||||||
|
CGContextSaveGState(context);
|
||||||
|
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
CGContextSetLineWidth(context, borderWidth);
|
||||||
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
|
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
// Note we can't use the 0.5 inset rectangle when setting up clipping. The clipping has to be
|
||||||
|
// on integer coordinates for this to look right in Chrome.
|
||||||
|
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(baseRect, cornerRadius, cornerRadius, YES, YES, YES, YES));
|
||||||
|
CGContextClip(context);
|
||||||
|
CGContextSetShadowWithColor(context, shadowOffset, shadowSize, shadowColor);
|
||||||
|
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||||
|
|
||||||
|
CGContextRestoreGState(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawNoBorderInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
CGContextSetFillColor(context, [self fillColor]);
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
CGContextFillRect(context, aRect);
|
CGContextFillRect(context, aRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_drawLineBorderInRect:(CGRect)aRect
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPBox (CSSTheming)
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
if (![self isCSSBased] || (_boxType === CPBoxCustom))
|
||||||
|
return;
|
||||||
|
|
||||||
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
|
var bounds = [self bounds];
|
||||||
|
|
||||||
CGContextSetFillColor(context, [self fillColor]);
|
if (_boxType === CPBoxSeparator)
|
||||||
CGContextSetStrokeColor(context, [self borderColor]);
|
{
|
||||||
|
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)];
|
||||||
|
}
|
||||||
|
|
||||||
CGContextSetLineWidth(context, _borderWidth);
|
[_boxView setBackgroundColor:[self valueForThemeAttribute:@"border-color"]];
|
||||||
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
|
||||||
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
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
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
var CPBoxTypeKey = @"CPBoxTypeKey",
|
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||||
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||||
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
|
CPBoxTitleKey = @"CPBoxTitleKey",
|
||||||
CPBoxFillColorKey = @"CPBoxFillColorKey",
|
CPBoxTitlePositionKey = @"CPBoxTitlePositionKey",
|
||||||
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
|
CPBoxTitleViewKey = @"CPBoxTitleViewKey",
|
||||||
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
|
CPBoxContentViewKey = @"CPBoxContentViewKey",
|
||||||
CPBoxContentMarginKey = @"CPBoxContentMarginKey",
|
CPBoxBoxViewKey = @"CPBoxBoxViewKey";
|
||||||
CPBoxTitle = @"CPBoxTitle",
|
|
||||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
|
||||||
CPBoxTitleView = @"CPBoxTitleView";
|
|
||||||
|
|
||||||
@implementation CPBox (CPCoding)
|
@implementation CPBox (CPCoding)
|
||||||
|
|
||||||
@@ -531,24 +850,56 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
|||||||
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
||||||
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||||
|
|
||||||
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
|
_title = [aCoder decodeObjectForKey:CPBoxTitleKey];
|
||||||
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
|
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePositionKey];
|
||||||
|
|
||||||
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
|
// Important : see comment on encodeWithCoder below
|
||||||
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
|
|
||||||
|
|
||||||
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
|
_boxView = [aCoder decodeObjectForKey:CPBoxBoxViewKey];
|
||||||
|
|
||||||
_title = [aCoder decodeObjectForKey:CPBoxTitle];
|
if (!_boxView)
|
||||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
{
|
||||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
// We're coming from nib2cib.
|
||||||
|
|
||||||
_contentView = [self subviews][0];
|
_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;
|
||||||
@@ -556,22 +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:CPBoxTitleKey];
|
||||||
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
|
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePositionKey];
|
||||||
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
|
[aCoder encodeConditionalObject:_contentView forKey:CPBoxContentViewKey];
|
||||||
|
[aCoder encodeConditionalObject:_titleView forKey:CPBoxTitleViewKey];
|
||||||
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
|
[aCoder encodeConditionalObject:_boxView forKey:CPBoxBoxViewKey];
|
||||||
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
|
|
||||||
|
|
||||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
|
||||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
|
||||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
|
||||||
|
|
||||||
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+313
-136
@@ -20,63 +20,109 @@
|
|||||||
* 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"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
|
@import "CPScrollView.j"
|
||||||
@import "CPTableView.j"
|
@import "CPTableView.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@import "CPScrollView.j"
|
|
||||||
|
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPImage)branchImage
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
return "browser";
|
||||||
pathForResource:"browser-leaf.png"]
|
|
||||||
size:CGSizeMake(9,9)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPImage)highlightedBranchImage
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
return @{
|
||||||
pathForResource:"browser-leaf-highlighted.png"]
|
@"image-control-resize": [CPNull null],
|
||||||
size:CGSizeMake(9,9)];
|
@"image-control-leaf": [CPNull null],
|
||||||
|
@"image-control-leaf-pressed": [CPNull null]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -136,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];
|
||||||
}
|
}
|
||||||
@@ -161,16 +268,13 @@
|
|||||||
|
|
||||||
- (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];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLastColumn:(int)columnIndex
|
- (void)setLastColumn:(CPInteger)columnIndex
|
||||||
{
|
{
|
||||||
if (columnIndex >= _tableViews.length)
|
if (columnIndex >= _tableViews.length)
|
||||||
return;
|
return;
|
||||||
@@ -178,14 +282,18 @@
|
|||||||
var oldValue = _tableViews.length - 1,
|
var oldValue = _tableViews.length - 1,
|
||||||
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
||||||
|
|
||||||
|
if (columnIndex > 0)
|
||||||
|
[_tableViews[columnIndex - 1] setNeedsDisplay:YES];
|
||||||
|
|
||||||
|
[_tableViews[columnIndex] setNeedsDisplay:YES];
|
||||||
|
|
||||||
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||||
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
|
|
||||||
_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];
|
||||||
}
|
}
|
||||||
@@ -276,8 +384,8 @@
|
|||||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
||||||
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[view setBranchImage:[[self class] branchImage]];
|
[view setBranchImage:[self valueForThemeAttribute:@"image-control-leaf"]];
|
||||||
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
|
[view setHighlightedBranchImage:[self valueForThemeAttribute:@"image-control-leaf-pressed"]];
|
||||||
|
|
||||||
[column setDataView:view];
|
[column setDataView:view];
|
||||||
[column setResizingMask:CPTableColumnNoResizing];
|
[column setResizingMask:CPTableColumnNoResizing];
|
||||||
@@ -285,7 +393,7 @@
|
|||||||
[aTableView addTableColumn:column];
|
[aTableView addTableColumn:column];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadColumn:(int)column
|
- (void)reloadColumn:(CPInteger)column
|
||||||
{
|
{
|
||||||
[[self tableViewInColumn:column] reloadData];
|
[[self tableViewInColumn:column] reloadData];
|
||||||
}
|
}
|
||||||
@@ -353,19 +461,19 @@
|
|||||||
|
|
||||||
// ITEMS
|
// ITEMS
|
||||||
|
|
||||||
- (id)itemAtRow:(int)row inColumn:(int)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:(int)column
|
- (id)parentForItemsInColumn:(CPInteger)column
|
||||||
{
|
{
|
||||||
return [_tableDelegates[column] _item];
|
return [_tableDelegates[column] _item] || nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPSet)selectedItems
|
- (CPSet)selectedItems
|
||||||
@@ -425,11 +533,26 @@
|
|||||||
|
|
||||||
- (void)keyDown:(CPEvent)anEvent
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var column = [self selectedColumn];
|
var key = [anEvent charactersIgnoringModifiers],
|
||||||
if (column === -1)
|
column = [self selectedColumn];
|
||||||
|
|
||||||
|
if (column === CPNotFound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_tableViews[column] keyDown:anEvent];
|
if (key === CPLeftArrowFunctionKey || key === CPRightArrowFunctionKey)
|
||||||
|
{
|
||||||
|
if (key === CPLeftArrowFunctionKey)
|
||||||
|
{
|
||||||
|
var previousColumn = column - 1,
|
||||||
|
selectedRow = [self selectedRowInColumn:previousColumn];
|
||||||
|
|
||||||
|
[self selectRow:selectedRow inColumn:previousColumn];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self selectRow:0 inColumn:column + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_tableViews[column] keyDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIZING
|
// SIZING
|
||||||
@@ -472,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,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];
|
||||||
@@ -608,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
|
||||||
@@ -631,30 +748,6 @@
|
|||||||
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)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:(int)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:(int)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)
|
||||||
@@ -704,8 +797,6 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
var _CPBrowserResizeControlBackgroundImage = nil;
|
|
||||||
|
|
||||||
@implementation _CPBrowserResizeControl : CPView
|
@implementation _CPBrowserResizeControl : CPView
|
||||||
{
|
{
|
||||||
CGPoint _mouseDownX;
|
CGPoint _mouseDownX;
|
||||||
@@ -714,22 +805,14 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
unsigned _width;
|
unsigned _width;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPImage)backgroundImage
|
|
||||||
{
|
|
||||||
if (!_CPBrowserResizeControlBackgroundImage)
|
|
||||||
{
|
|
||||||
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
|
|
||||||
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
|
|
||||||
size:CGSizeMake(15, 14)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _CPBrowserResizeControlBackgroundImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
{
|
||||||
|
var browser = [[CPBrowser alloc] init];
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:[browser valueForThemeAttribute:@"image-control-resize"]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -760,7 +843,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
CPBrowser _browser @accessors;
|
CPBrowser _browser @accessors;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
{
|
{
|
||||||
@@ -814,18 +897,26 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
return _browser;
|
return _browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (BOOL)_isFocused
|
||||||
|
{
|
||||||
|
return ([super _isFocused] || [_browser tableViewInColumn:[_browser selectedColumn]] === self);
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||||
{
|
{
|
||||||
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
|
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||||
{
|
{
|
||||||
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
||||||
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
|
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragViewOffset
|
||||||
{
|
{
|
||||||
var count = theTableColumns.length;
|
var count = theTableColumns.length;
|
||||||
while (count--)
|
while (count--)
|
||||||
@@ -838,35 +929,9 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
|
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)moveUp:(id)sender
|
|
||||||
{
|
|
||||||
[super moveUp:sender];
|
|
||||||
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)moveDown:(id)sender
|
|
||||||
{
|
|
||||||
[super moveDown:sender];
|
|
||||||
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)moveLeft:(id)sender
|
|
||||||
{
|
|
||||||
var previousColumn = [_browser selectedColumn] - 1,
|
|
||||||
selectedRow = [_browser selectedRowInColumn:previousColumn];
|
|
||||||
|
|
||||||
[_browser selectRow:selectedRow inColumn:previousColumn];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)moveRight:(id)sender
|
|
||||||
{
|
|
||||||
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
|
||||||
|
|
||||||
@implementation _CPBrowserTableDelegate : CPObject
|
@implementation _CPBrowserTableDelegate : CPObject
|
||||||
{
|
{
|
||||||
CPBrowser _browser @accessors;
|
CPBrowser _browser @accessors;
|
||||||
@@ -907,22 +972,22 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)childAtIndex:(unsigned)index
|
- (id)childAtIndex:(CPUInteger)index
|
||||||
{
|
{
|
||||||
return [_delegate browser:_browser child:index ofItem:_item];
|
return [_delegate browser:_browser child:index ofItem:_item];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)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;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)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;
|
||||||
@@ -930,7 +995,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
|
|
||||||
- (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;
|
||||||
@@ -985,7 +1050,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
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];
|
||||||
@@ -1000,7 +1065,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
if (self = [super initWithCoder:aCoder])
|
if (self = [super initWithCoder:aCoder])
|
||||||
{
|
{
|
||||||
@@ -1013,3 +1078,115 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@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
|
||||||
|
|||||||
+330
-213
@@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@import "CPStringDrawing.j"
|
@import "CPStringDrawing.j"
|
||||||
|
@import "CPText.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;
|
||||||
@@ -44,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;
|
||||||
@@ -59,11 +61,11 @@ CPMomentaryPushInButton = 7;
|
|||||||
CPMomentaryPushButton = 0;
|
CPMomentaryPushButton = 0;
|
||||||
CPMomentaryLight = 7;
|
CPMomentaryLight = 7;
|
||||||
|
|
||||||
CPNoButtonMask = 0;
|
CPNoButtonMask = 0;
|
||||||
CPContentsButtonMask = 1;
|
CPContentsButtonMask = 1;
|
||||||
CPPushInButtonMask = 2;
|
CPPushInButtonMask = 2;
|
||||||
CPGrayButtonMask = 4;
|
CPGrayButtonMask = 4;
|
||||||
CPBackgroundButtonMask = 8;
|
CPBackgroundButtonMask = 8;
|
||||||
|
|
||||||
CPNoCellMask = CPNoButtonMask;
|
CPNoCellMask = CPNoButtonMask;
|
||||||
CPContentsCellMask = CPContentsButtonMask;
|
CPContentsCellMask = CPContentsButtonMask;
|
||||||
@@ -71,16 +73,38 @@ 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 = [CPDictionary dictionaryWithObjects:[CPButtonStateBezelStyleRounded, nil]
|
var CPButtonBezelStyleStateMap = @{
|
||||||
forKeys:[CPRoundedBezelStyle, CPRoundRectBezelStyle]];
|
CPRoundedBezelStyle: CPButtonStateBezelStyleRounded,
|
||||||
|
CPShadowlessSquareBezelStyle: CPButtonStateBezelStyleShadowlessSquare,
|
||||||
|
CPSmallSquareBezelStyle: CPButtonStateBezelStyleSmallSquare,
|
||||||
|
CPTexturedRoundedBezelStyle: CPButtonStateBezelStyleTexturedRounded,
|
||||||
|
CPRoundRectBezelStyle: CPButtonStateBezelStyleRoundRect,
|
||||||
|
CPRecessedBezelStyle: CPButtonStateBezelStyleRecessed,
|
||||||
|
CPInlineBezelStyle: CPButtonStateBezelStyleInline,
|
||||||
|
CPRegularSquareBezelStyle: CPButtonStateBezelStyleRegularSquare,
|
||||||
|
CPTexturedSquareBezelStyle: CPButtonStateBezelStyleTextured,
|
||||||
|
CPDisclosureBezelStyle: CPButtonStateBezelStyleDisclosure,
|
||||||
|
CPRoundedDisclosureBezelStyle: CPButtonStateBezelStyleRoundedDisclosure
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @cond IGNORE
|
||||||
CPButtonDefaultHeight = 24.0;
|
CPButtonDefaultHeight = 25.0;
|
||||||
CPButtonImageOffset = 3.0;
|
CPButtonImageOffset = 3.0;
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -103,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;
|
||||||
@@ -113,7 +137,15 @@ CPButtonImageOffset = 3.0;
|
|||||||
float _periodicDelay;
|
float _periodicDelay;
|
||||||
float _periodicInterval;
|
float _periodicInterval;
|
||||||
|
|
||||||
BOOL _isTracking;
|
BOOL _isHighlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
|
||||||
|
return [CPActionBinding class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)buttonWithTitle:(CPString)aTitle
|
+ (id)buttonWithTitle:(CPString)aTitle
|
||||||
@@ -137,10 +169,23 @@ CPButtonImageOffset = 3.0;
|
|||||||
return @"button";
|
return @"button";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
return @{
|
||||||
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
|
@"image": [CPNull null],
|
||||||
|
@"image-offset": 0.0,
|
||||||
|
@"image-vertical-offset": 0.0,
|
||||||
|
@"bezel-inset": CGInsetMakeZero(),
|
||||||
|
@"content-inset": CGInsetMakeZero(),
|
||||||
|
@"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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -154,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];
|
||||||
|
|
||||||
@@ -171,8 +210,6 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
- (void)_init
|
- (void)_init
|
||||||
{
|
{
|
||||||
_controlSize = CPRegularControlSize;
|
|
||||||
|
|
||||||
_keyEquivalent = @"";
|
_keyEquivalent = @"";
|
||||||
_keyEquivalentModifierMask = 0;
|
_keyEquivalentModifierMask = 0;
|
||||||
|
|
||||||
@@ -183,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.
|
||||||
@@ -221,7 +272,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
else if (![anObjectValue isKindOfClass:[CPNumber class]])
|
else if (![anObjectValue isKindOfClass:[CPNumber class]])
|
||||||
anObjectValue = CPOnState;
|
anObjectValue = CPOnState;
|
||||||
else if (anObjectValue >= CPOnState)
|
else if (anObjectValue >= CPOnState)
|
||||||
anObjectValue = CPOnState
|
anObjectValue = CPOnState;
|
||||||
else if (anObjectValue < CPOffState)
|
else if (anObjectValue < CPOffState)
|
||||||
if ([self allowsMixedState])
|
if ([self allowsMixedState])
|
||||||
anObjectValue = CPMixedState;
|
anObjectValue = CPMixedState;
|
||||||
@@ -229,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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -275,7 +302,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the button's next state to \c aState.
|
Sets the button's state to the next available state.
|
||||||
@param aState Possible states are any of the CPButton globals:
|
@param aState Possible states are any of the CPButton globals:
|
||||||
\c CPOffState, \c CPOnState, \c CPMixedState
|
\c CPOffState, \c CPOnState, \c CPMixedState
|
||||||
*/
|
*/
|
||||||
@@ -349,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -363,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)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -371,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
|
||||||
@@ -394,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];
|
||||||
}
|
}
|
||||||
@@ -415,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
|
||||||
@@ -431,38 +470,47 @@ CPButtonImageOffset = 3.0;
|
|||||||
{
|
{
|
||||||
switch (aButtonType)
|
switch (aButtonType)
|
||||||
{
|
{
|
||||||
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
case CPMomentaryLightButton:
|
||||||
[self setShowsStateBy:CPNoCellMask];
|
[self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPNoCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPMomentaryPushInButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
case CPMomentaryPushInButton:
|
||||||
[self setShowsStateBy:CPNoCellMask];
|
[self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPNoCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPMomentaryChangeButton: [self setHighlightsBy:CPContentsCellMask];
|
case CPMomentaryChangeButton:
|
||||||
[self setShowsStateBy:CPNoCellMask];
|
[self setHighlightsBy:CPContentsCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPNoCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPPushOnPushOffButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
case CPPushOnPushOffButton:
|
||||||
[self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
|
[self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPOnOffButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
case CPOnOffButton:
|
||||||
[self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
[self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
case CPToggleButton:
|
||||||
[self setShowsStateBy:CPContentsCellMask];
|
[self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
||||||
break;
|
[self setShowsStateBy:CPContentsCellMask];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
|
case CPSwitchButton:
|
||||||
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
|
||||||
|
|
||||||
case CPRadioButton: [CPException raise:CPInvalidArgumentException
|
case CPRadioButton:
|
||||||
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
|
||||||
|
|
||||||
default: [CPException raise:CPInvalidArgumentException
|
default:
|
||||||
reason:"Unknown button type."];
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:"Unknown button type."];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setImageDimsWhenDisabled:YES];
|
[self setImageDimsWhenDisabled:YES];
|
||||||
@@ -495,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()
|
||||||
{
|
{
|
||||||
@@ -517,44 +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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,9 +602,9 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||||
@@ -588,7 +615,7 @@ CPButtonImageOffset = 3.0;
|
|||||||
|
|
||||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||||
|
|
||||||
return _CGRectInsetByInset(bounds, bezelInset);
|
return CGRectInsetByInset(bounds, bezelInset);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)_minimumFrameSize
|
- (CGSize)_minimumFrameSize
|
||||||
@@ -602,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"],
|
||||||
@@ -648,96 +675,174 @@ CPButtonImageOffset = 3.0;
|
|||||||
{
|
{
|
||||||
if (aName === "bezel-view")
|
if (aName === "bezel-view")
|
||||||
{
|
{
|
||||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[view setHitTests:NO];
|
[view setHitTests:NO];
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
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
|
||||||
@@ -767,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)
|
||||||
@@ -833,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
|
||||||
{
|
{
|
||||||
@@ -855,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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -879,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
|
||||||
@@ -902,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)
|
||||||
|
|
||||||
@@ -951,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];
|
||||||
}
|
}
|
||||||
@@ -985,9 +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
|
||||||
|
|
||||||
@import "CPCheckBox.j"
|
|
||||||
@import "CPRadio.j"
|
|
||||||
|
|||||||
+81
-16
@@ -1,6 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* CPButtonBar.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPWindow_Constants.j"
|
||||||
|
|
||||||
|
@class CPSplitView
|
||||||
|
|
||||||
|
@global CPPopUpButtonStatePullsDown
|
||||||
|
@global CPKeyValueChangeOldKey
|
||||||
|
@global CPKeyValueChangeNewKey
|
||||||
|
@global CPKeyValueObservingOptionNew
|
||||||
|
@global CPKeyValueObservingOptionOld
|
||||||
|
|
||||||
@implementation CPButtonBar : CPView
|
@implementation CPButtonBar : CPView
|
||||||
{
|
{
|
||||||
@@ -12,7 +41,7 @@
|
|||||||
+ (id)plusButton
|
+ (id)plusButton
|
||||||
{
|
{
|
||||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-plus" forClass:[CPButtonBar class]];
|
||||||
|
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImage:image];
|
[button setImage:image];
|
||||||
@@ -24,7 +53,7 @@
|
|||||||
+ (id)minusButton
|
+ (id)minusButton
|
||||||
{
|
{
|
||||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-minus" forClass:[CPButtonBar class]];
|
||||||
|
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImage:image];
|
[button setImage:image];
|
||||||
@@ -36,12 +65,12 @@
|
|||||||
+ (id)actionPopupButton
|
+ (id)actionPopupButton
|
||||||
{
|
{
|
||||||
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
|
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-action" forClass:[CPButtonBar class]];
|
||||||
|
|
||||||
[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];
|
||||||
|
|
||||||
@@ -53,10 +82,19 @@
|
|||||||
return @"button-bar";
|
return @"button-bar";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
return @{
|
||||||
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
|
@"resize-control-inset": CGInsetMake(0.0, 0.0, 0.0, 0.0),
|
||||||
|
@"resize-control-size": CGSizeMakeZero(),
|
||||||
|
@"resize-control-color": [CPNull null],
|
||||||
|
@"bezel-color": [CPNull null],
|
||||||
|
@"button-bezel-color": [CPNull null],
|
||||||
|
@"button-text-color": [CPNull null],
|
||||||
|
@"button-image-plus": [CPNull null],
|
||||||
|
@"button-image-minus": [CPNull null],
|
||||||
|
@"button-image-action": [CPNull null],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -74,6 +112,8 @@
|
|||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
|
[super awakeFromCib];
|
||||||
|
|
||||||
var view = [self superview],
|
var view = [self superview],
|
||||||
subview = self;
|
subview = self;
|
||||||
|
|
||||||
@@ -94,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];
|
||||||
}
|
}
|
||||||
@@ -183,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],
|
||||||
@@ -215,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];
|
||||||
}
|
}
|
||||||
@@ -239,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];
|
||||||
|
|||||||
+65
-11
@@ -44,12 +44,12 @@ CPCheckBoxImageOffset = 4.0;
|
|||||||
return @"check-box";
|
return @"check-box";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding === CPValueBinding)
|
if (aBinding === CPValueBinding)
|
||||||
return [_CPCheckBoxValueBinder class];
|
return [_CPCheckBoxValueBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -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
|
||||||
|
|||||||
+15
-36
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPScrollView
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -44,44 +45,13 @@
|
|||||||
if (_documentView == aView)
|
if (_documentView == aView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
|
||||||
|
|
||||||
if (_documentView)
|
if (_documentView)
|
||||||
{
|
|
||||||
[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];
|
||||||
|
|
||||||
[_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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -101,19 +71,19 @@
|
|||||||
- (CGPoint)constrainScrollPoint:(CGPoint)aPoint
|
- (CGPoint)constrainScrollPoint:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
if (!_documentView)
|
if (!_documentView)
|
||||||
return _CGPointMakeZero();
|
return CGPointMakeZero();
|
||||||
|
|
||||||
var documentFrame = [_documentView frame];
|
var documentFrame = [_documentView frame];
|
||||||
|
|
||||||
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
|
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(CGRectGetWidth(documentFrame) - CGRectGetWidth(_bounds), 0.0)));
|
||||||
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
|
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(CGRectGetHeight(documentFrame) - CGRectGetHeight(_bounds), 0.0)));
|
||||||
|
|
||||||
return aPoint;
|
return aPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBoundsOrigin:(CGPoint)aPoint
|
- (void)setBoundsOrigin:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
if (_CGPointEqualToPoint(_bounds.origin, aPoint))
|
if (CGPointEqualToPoint(_bounds.origin, aPoint))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[super setBoundsOrigin:aPoint];
|
[super setBoundsOrigin:aPoint];
|
||||||
@@ -223,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
|
||||||
|
|
||||||
|
|
||||||
@@ -233,7 +208,11 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
|||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
if (self = [super initWithCoder:aCoder])
|
if (self = [super initWithCoder:aCoder])
|
||||||
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
|
{
|
||||||
|
// 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.
|
||||||
|
_documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
+835
-287
File diff suppressed because it is too large
Load Diff
@@ -22,13 +22,38 @@
|
|||||||
|
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Represents an object inside a CPCollectionView.
|
Represents an object inside a CPCollectionView.
|
||||||
*/
|
*/
|
||||||
@implementation CPCollectionViewItem : CPViewController
|
@implementation CPCollectionViewItem : CPViewController
|
||||||
{
|
{
|
||||||
BOOL _isSelected;
|
BOOL _isSelected;
|
||||||
|
CPData _cachedArchive;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)copy
|
||||||
|
{
|
||||||
|
var cibName = [self cibName],
|
||||||
|
copy;
|
||||||
|
|
||||||
|
if (cibName)
|
||||||
|
{
|
||||||
|
copy = [[[self class] alloc] initWithCibName:cibName bundle:[self cibBundle]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_cachedArchive)
|
||||||
|
_cachedArchive = [CPKeyedArchiver archivedDataWithRootObject:self];
|
||||||
|
|
||||||
|
copy = [CPKeyedUnarchiver unarchiveObjectWithData:_cachedArchive];
|
||||||
|
|
||||||
|
// copy connections
|
||||||
|
}
|
||||||
|
|
||||||
|
[copy setRepresentedObject:[self representedObject]];
|
||||||
|
[copy setSelected:_isSelected];
|
||||||
|
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the Represented Object
|
// Setting the Represented Object
|
||||||
|
|||||||
+956
-90
File diff suppressed because it is too large
Load Diff
+40
-35
@@ -20,12 +20,35 @@
|
|||||||
* 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 "CPApplication.j"
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
@import "CPCookie.j"
|
@import "CPCookie.j"
|
||||||
@import "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
|
@import "CPPasteboard.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPSlider
|
||||||
|
@class _CPColorPanelToolbar
|
||||||
|
@class _CPColorPanelSwatches
|
||||||
|
@class _CPColorPanelPreview
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
/*
|
||||||
|
A color wheel
|
||||||
|
@global
|
||||||
|
@group CPColorPanelMode
|
||||||
|
*/
|
||||||
|
CPWheelColorPickerMode = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Slider based picker
|
||||||
|
@global
|
||||||
|
@group CPColorPanelMode
|
||||||
|
*/
|
||||||
|
CPSliderColorPickerMode = 2;
|
||||||
|
|
||||||
|
CPColorPickerViewWidth = 265;
|
||||||
|
CPColorPickerViewHeight = 370;
|
||||||
|
|
||||||
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
||||||
|
|
||||||
@@ -38,22 +61,6 @@ var PREVIEW_HEIGHT = 20.0,
|
|||||||
var SharedColorPanel = nil,
|
var SharedColorPanel = nil,
|
||||||
ColorPickerClasses = [];
|
ColorPickerClasses = [];
|
||||||
|
|
||||||
/*
|
|
||||||
A color wheel
|
|
||||||
@global
|
|
||||||
@group CPColorPanelMode
|
|
||||||
*/
|
|
||||||
CPWheelColorPickerMode = 1;
|
|
||||||
/*
|
|
||||||
Slider based picker
|
|
||||||
@global
|
|
||||||
@group CPColorPanelMode
|
|
||||||
*/
|
|
||||||
CPSliderColorPickerMode = 2;
|
|
||||||
|
|
||||||
CPColorPickerViewWidth = 265;
|
|
||||||
CPColorPickerViewHeight = 370;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPColorPanel
|
@class CPColorPanel
|
||||||
@@ -64,7 +71,6 @@ CPColorPickerViewHeight = 370;
|
|||||||
*/
|
*/
|
||||||
@implementation CPColorPanel : CPPanel
|
@implementation CPColorPanel : CPPanel
|
||||||
{
|
{
|
||||||
_CPColorPanelToolbar _toolbar;
|
|
||||||
_CPColorPanelSwatches _swatchView;
|
_CPColorPanelSwatches _swatchView;
|
||||||
_CPColorPanelPreview _previewView;
|
_CPColorPanelPreview _previewView;
|
||||||
|
|
||||||
@@ -123,7 +129,7 @@ CPColorPickerViewHeight = 370;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
//[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
||||||
|
|
||||||
[self setTitle:@"Color Panel"];
|
[self setTitle:@"Color Panel"];
|
||||||
[self setLevel:CPFloatingWindowLevel];
|
[self setLevel:CPFloatingWindowLevel];
|
||||||
@@ -248,8 +254,8 @@ CPColorPickerViewHeight = 370;
|
|||||||
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
|
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
|
||||||
bounds = [[self contentView] bounds];
|
bounds = [[self contentView] bounds];
|
||||||
|
|
||||||
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
[view setFrameSize:CGSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||||
[view setFrameOrigin:CPPointMake(5, height)];
|
[view setFrameOrigin:CGPointMake(5, height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_currentView removeFromSuperview];
|
[_currentView removeFromSuperview];
|
||||||
@@ -419,7 +425,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
CPCookie _swatchCookie;
|
CPCookie _swatchCookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
@@ -437,7 +443,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
for (var i = 0; i < 50; i++)
|
for (var i = 0; i < 50; i++)
|
||||||
{
|
{
|
||||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||||
var view = [[CPView alloc] initWithFrame:CPRectMake(13 * i + 1, 1, 12, 12)],
|
var view = [[CPView alloc] initWithFrame:CGRectMake(13 * i + 1, 1, 12, 12)],
|
||||||
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
|
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
|
||||||
|
|
||||||
[view setBackgroundColor:whiteColor];
|
[view setBackgroundColor:whiteColor];
|
||||||
@@ -477,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
|
||||||
@@ -572,7 +577,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
|
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
- (void)performDragOperation:(id /*<CPDraggingInfo>*/)aSender
|
||||||
{
|
{
|
||||||
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
|
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
|
||||||
pasteboard = [aSender draggingPasteboard],
|
pasteboard = [aSender draggingPasteboard],
|
||||||
@@ -592,7 +597,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
CPColorPanel _colorPanel;
|
CPColorPanel _colorPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
@@ -611,7 +616,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
return _colorPanel;
|
return _colorPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
- (void)performDragOperation:(id /*<CPDraggingInfo>*/)aSender
|
||||||
{
|
{
|
||||||
var pasteboard = [aSender draggingPasteboard];
|
var pasteboard = [aSender draggingPasteboard];
|
||||||
|
|
||||||
@@ -633,7 +638,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
|
|
||||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||||
|
|
||||||
var bounds = CPRectMake(0, 0, 15, 15);
|
var bounds = CGRectMake(0, 0, 15, 15);
|
||||||
|
|
||||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||||
var dragView = [[CPView alloc] initWithFrame:bounds],
|
var dragView = [[CPView alloc] initWithFrame:bounds],
|
||||||
@@ -645,8 +650,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
[dragView addSubview:dragFillView];
|
[dragView addSubview:dragFillView];
|
||||||
|
|
||||||
[self dragView:dragView
|
[self dragView:dragView
|
||||||
at:CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
at:CGPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||||
offset:CPPointMake(0.0, 0.0)
|
offset:CGPointMake(0.0, 0.0)
|
||||||
event:anEvent
|
event:anEvent
|
||||||
pasteboard:nil
|
pasteboard:nil
|
||||||
source:self
|
source:self
|
||||||
|
|||||||
+25
-16
@@ -24,6 +24,14 @@
|
|||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class CPSlider
|
||||||
|
@class CPColorPanel
|
||||||
|
@class __CPColorWheel
|
||||||
|
|
||||||
|
@global CPColorPickerViewWidth
|
||||||
|
@global CPColorPickerViewHeight
|
||||||
|
@global CPWheelColorPickerMode
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -109,15 +117,16 @@
|
|||||||
|
|
||||||
- (id)initView
|
- (id)initView
|
||||||
{
|
{
|
||||||
var aFrame = _CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
var aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||||
|
|
||||||
_pickerView = [[CPView alloc] initWithFrame:aFrame];
|
_pickerView = [[CPView alloc] initWithFrame:aFrame];
|
||||||
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
_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];
|
||||||
@@ -127,7 +136,7 @@
|
|||||||
[_brightnessSlider setAction:@selector(brightnessSliderDidChange:)];
|
[_brightnessSlider setAction:@selector(brightnessSliderDidChange:)];
|
||||||
[_brightnessSlider setAutoresizingMask:CPViewWidthSizable | CPViewMinYMargin];
|
[_brightnessSlider setAutoresizingMask:CPViewWidthSizable | CPViewMinYMargin];
|
||||||
|
|
||||||
_hueSaturationView = [[__CPColorWheel alloc] initWithFrame:_CGRectMake(0, 0, aFrame.size.width, aFrame.size.height - 38)];
|
_hueSaturationView = [[__CPColorWheel alloc] initWithFrame:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height - 38)];
|
||||||
[_hueSaturationView setDelegate:self];
|
[_hueSaturationView setDelegate:self];
|
||||||
[_hueSaturationView setAutoresizingMask:(CPViewWidthSizable | CPViewHeightSizable)];
|
[_hueSaturationView setAutoresizingMask:(CPViewWidthSizable | CPViewHeightSizable)];
|
||||||
|
|
||||||
@@ -152,12 +161,12 @@
|
|||||||
brightness = [_brightnessSlider floatValue];
|
brightness = [_brightnessSlider floatValue];
|
||||||
|
|
||||||
[_hueSaturationView setWheelBrightness:brightness / 100.0];
|
[_hueSaturationView setWheelBrightness:brightness / 100.0];
|
||||||
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hue saturation:saturation brightness:100]];
|
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hue / 360.0 saturation:saturation / 100.0 brightness:1]];
|
||||||
|
|
||||||
var colorPanel = [self colorPanel],
|
var colorPanel = [self colorPanel],
|
||||||
opacity = [colorPanel opacity];
|
opacity = [colorPanel opacity];
|
||||||
|
|
||||||
_cachedColor = [CPColor colorWithHue:hue saturation:saturation brightness:brightness alpha:opacity];
|
_cachedColor = [CPColor colorWithHue:hue / 360.0 saturation:saturation / 100.0 brightness:brightness / 100.0 alpha:opacity];
|
||||||
|
|
||||||
[[self colorPanel] setColor:_cachedColor];
|
[[self colorPanel] setColor:_cachedColor];
|
||||||
}
|
}
|
||||||
@@ -188,10 +197,10 @@
|
|||||||
var hsb = [newColor hsbComponents];
|
var hsb = [newColor hsbComponents];
|
||||||
|
|
||||||
[_hueSaturationView setPositionToColor:newColor];
|
[_hueSaturationView setPositionToColor:newColor];
|
||||||
[_brightnessSlider setFloatValue:hsb[2]];
|
[_brightnessSlider setFloatValue:hsb[2] * 100.0];
|
||||||
[_hueSaturationView setWheelBrightness:hsb[2] / 100.0];
|
[_hueSaturationView setWheelBrightness:hsb[2]];
|
||||||
|
|
||||||
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hsb[0] saturation:hsb[1] brightness:100]];
|
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hsb[0] saturation:hsb[1] brightness:1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)provideNewButtonImage
|
- (CPImage)provideNewButtonImage
|
||||||
@@ -222,7 +231,7 @@
|
|||||||
float _radius;
|
float _radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:aFrame])
|
if (self = [super initWithFrame:aFrame])
|
||||||
{
|
{
|
||||||
@@ -238,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);
|
||||||
@@ -269,13 +278,13 @@
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrameSize:(CPSize)aSize
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[super setFrameSize:aSize];
|
[super setFrameSize:aSize];
|
||||||
[self setWheelSize:aSize];
|
[self setWheelSize:aSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWheelSize:(CPSize)aSize
|
- (void)setWheelSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
var min = MIN(aSize.width, aSize.height);
|
var min = MIN(aSize.width, aSize.height);
|
||||||
|
|
||||||
@@ -353,15 +362,15 @@
|
|||||||
_angle = [self radiansToDegrees:angle];
|
_angle = [self radiansToDegrees:angle];
|
||||||
_distance = (distance / _radius) * 100.0;
|
_distance = (distance / _radius) * 100.0;
|
||||||
|
|
||||||
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
|
[_crosshair setFrameOrigin:CGPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPositionToColor:(CPColor)aColor
|
- (void)setPositionToColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
var hsb = [aColor hsbComponents],
|
var hsb = [aColor hsbComponents],
|
||||||
bounds = [self bounds],
|
bounds = [self bounds],
|
||||||
angle = [self degreesToRadians:hsb[0]],
|
angle = [self degreesToRadians:hsb[0] * 360.0],
|
||||||
distance = (hsb[1] / 100.0) * _radius;
|
distance = hsb[1] * _radius;
|
||||||
|
|
||||||
[self setAngle:angle distance:distance];
|
[self setAngle:angle distance:distance];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
* 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>
|
||||||
|
|
||||||
var sRGBColorSpace = nil;
|
var sRGBColorSpace = nil;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
+67
-37
@@ -45,12 +45,12 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
CPColor _color;
|
CPColor _color;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding == CPValueBinding)
|
if (aBinding == CPValueBinding)
|
||||||
return [CPColorWellValueBinder class];
|
return [CPColorWellValueBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)defaultThemeClass
|
+ (CPString)defaultThemeClass
|
||||||
@@ -58,10 +58,15 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
return @"colorwell";
|
return @"colorwell";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), [CPNull null], _CGInsetMake(3.0, 3.0, 3.0, 3.0), _CGInsetMakeZero(), [CPNull null]]
|
return @{
|
||||||
forKeys:[@"bezel-inset", @"bezel-color", @"content-inset", @"content-border-inset", @"content-border-color"]];
|
@"bezel-inset": CGInsetMakeZero(),
|
||||||
|
@"bezel-color": [CPNull null],
|
||||||
|
@"content-inset": CGInsetMake(3.0, 3.0, 3.0, 3.0),
|
||||||
|
@"content-border-inset": CGInsetMakeZero(),
|
||||||
|
@"content-border-color": [CPNull null],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_reverseSetBinding
|
- (void)_reverseSetBinding
|
||||||
@@ -81,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];
|
||||||
|
|
||||||
@@ -105,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.
|
||||||
*/
|
*/
|
||||||
@@ -236,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];
|
||||||
}
|
}
|
||||||
@@ -244,21 +265,21 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
{
|
{
|
||||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||||
|
|
||||||
return _CGRectInsetByInset(bounds, contentInset);
|
return CGRectInsetByInset(bounds, contentInset);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||||
|
|
||||||
return _CGRectInsetByInset(bounds, bezelInset);
|
return CGRectInsetByInset(bounds, bezelInset);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)contentBorderRectForBounds:(CGRect)bounds
|
- (CGRect)contentBorderRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
|
var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
|
||||||
|
|
||||||
return _CGRectInsetByInset(bounds, contentBorderInset);
|
return CGRectInsetByInset(bounds, contentBorderInset);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
@@ -278,7 +299,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[view setHitTests:NO];
|
[view setHitTests:NO];
|
||||||
|
|
||||||
@@ -307,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
|
||||||
@@ -315,7 +358,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
|
|
||||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||||
{
|
{
|
||||||
var placeholderColor = [CPColor blueColor];
|
var placeholderColor = [CPColor blackColor];
|
||||||
|
|
||||||
[self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
|
[self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||||
[self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
|
[self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
|
||||||
@@ -323,30 +366,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
[self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
|
[self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)theBinding
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
return [_source color];
|
||||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
}
|
||||||
options = [_info objectForKey:CPOptionsKey],
|
|
||||||
newValue = [destination valueForKeyPath:keyPath],
|
|
||||||
isPlaceholder = CPIsControllerMarker(newValue);
|
|
||||||
|
|
||||||
if (isPlaceholder)
|
- (void)setValue:(id)aValue forBinding:(CPString)theBinding
|
||||||
{
|
{
|
||||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
[_source setColor:aValue];
|
||||||
{
|
}
|
||||||
[CPException raise:CPGenericException
|
|
||||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
newValue = [self _placeholderForMarker:newValue];
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
}
|
{
|
||||||
else
|
[_source setColor:aValue];
|
||||||
{
|
|
||||||
newValue = [self transformValue:newValue withOptions:options];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_source setColor:newValue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -369,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;
|
||||||
|
|||||||
+201
-94
@@ -20,10 +20,32 @@
|
|||||||
* 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 "CPText.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@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";
|
||||||
@@ -31,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,
|
||||||
@@ -39,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
|
||||||
@@ -57,17 +87,20 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
return "combobox";
|
return "combobox";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjectsAndKeys:_CGSizeMake(21.0, 29.0), @"popup-button-size", _CGInsetMake(3.0, 3.0, 3.0, 3.0), @"border-inset"];
|
return @{
|
||||||
|
@"popup-button-size": CGSizeMake(21.0, 29.0),
|
||||||
|
@"border-inset": CGInsetMake(3.0, 3.0, 3.0, 3.0),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding === CPContentBinding || theBinding === CPContentValuesBinding)
|
if (aBinding === CPContentBinding || aBinding === CPContentValuesBinding)
|
||||||
return [_CPComboBoxContentBinder class];
|
return [_CPComboBoxContentBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -83,7 +116,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
- (void)_initComboBox
|
- (void)_initComboBox
|
||||||
{
|
{
|
||||||
_items = [CPArray array];
|
_items = [CPArray array];
|
||||||
_listClass = [_CPPopUpList class];
|
// _listClass = [_CPPopUpList class];
|
||||||
_usesDataSource = NO;
|
_usesDataSource = NO;
|
||||||
_completes = NO;
|
_completes = NO;
|
||||||
_canComplete = NO;
|
_canComplete = NO;
|
||||||
@@ -115,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
|
||||||
@@ -125,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
|
||||||
@@ -148,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
|
||||||
@@ -167,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];
|
||||||
}
|
}
|
||||||
@@ -178,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];
|
||||||
@@ -227,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];
|
||||||
@@ -235,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:)] ||
|
||||||
@@ -247,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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,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:)
|
||||||
@@ -418,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
|
||||||
@@ -466,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)
|
||||||
@@ -478,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 */
|
||||||
@@ -507,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;
|
||||||
@@ -786,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;
|
||||||
@@ -813,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
|
||||||
@@ -850,7 +921,7 @@ var CPComboBoxTextSubview = @"text",
|
|||||||
{
|
{
|
||||||
if (aName === "popup-button-view")
|
if (aName === "popup-button-view")
|
||||||
{
|
{
|
||||||
var view = [[_CPComboBoxPopUpButton alloc] initWithFrame:_CGRectMakeZero() comboBox:self];
|
var view = [[_CPComboBoxPopUpButton alloc] initWithFrame:CGRectMakeZero() comboBox:self];
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -890,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];
|
||||||
|
|
||||||
@@ -942,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)
|
||||||
@@ -949,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1035,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];
|
||||||
@@ -1110,7 +1215,7 @@ var CPComboBoxCompletionTest = function(object, index, context)
|
|||||||
*/
|
*/
|
||||||
@implementation _CPComboBoxContentBinder : CPBinder
|
@implementation _CPComboBoxContentBinder : CPBinder
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)theBinding
|
- (void)setValueFor:(CPString)aBinding
|
||||||
{
|
{
|
||||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||||
@@ -1152,13 +1257,15 @@ var CPComboBoxCompletionTest = function(object, index, context)
|
|||||||
else
|
else
|
||||||
newValue = [self transformValue:newValue withOptions:options];
|
newValue = [self transformValue:newValue withOptions:options];
|
||||||
|
|
||||||
switch (theBinding)
|
switch (aBinding)
|
||||||
{
|
{
|
||||||
case CPContentBinding: [_source setContent:newValue];
|
case CPContentBinding:
|
||||||
break;
|
[_source setContent:newValue];
|
||||||
|
break;
|
||||||
|
|
||||||
case CPContentValuesBinding: [_source setContentValues:newValue];
|
case CPContentValuesBinding:
|
||||||
break;
|
[_source setContentValues:newValue];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+210
-79
@@ -20,17 +20,19 @@
|
|||||||
* 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 "CPEvent.j"
|
@import "CPEvent_Constants.j"
|
||||||
@import "CPPlatform.j"
|
@import "CPPlatform.j"
|
||||||
|
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -38,58 +40,81 @@ CPWindowsOperatingSystem = 1;
|
|||||||
CPOtherOperatingSystem = 2;
|
CPOtherOperatingSystem = 2;
|
||||||
|
|
||||||
// Features
|
// Features
|
||||||
CPCSSRGBAFeature = 1 << 5;
|
CPCSSRGBAFeature = 5;
|
||||||
|
|
||||||
CPHTMLCanvasFeature = 1 << 6;
|
CPHTMLCanvasFeature = 6;
|
||||||
CPHTMLContentEditableFeature = 1 << 7;
|
CPHTMLContentEditableFeature = 7;
|
||||||
CPHTMLDragAndDropFeature = 1 << 8;
|
CPHTMLDragAndDropFeature = 8;
|
||||||
|
|
||||||
CPJavaScriptInnerTextFeature = 1 << 9;
|
CPJavaScriptInnerTextFeature = 9;
|
||||||
CPJavaScriptTextContentFeature = 1 << 10;
|
CPJavaScriptTextContentFeature = 10;
|
||||||
CPJavaScriptClipboardEventsFeature = 1 << 11;
|
// In onpaste, oncopy and oncut events, the event has an event.clipboardData from which the current pasteboard contents can be read with event.clipboardData.getData.
|
||||||
CPJavaScriptClipboardAccessFeature = 1 << 12;
|
CPJavaScriptClipboardEventsFeature = 11;
|
||||||
CPJavaScriptCanvasDrawFeature = 1 << 13;
|
// window.clipboardData exists and can be read and written to at any time using window.clipboardData.getData/setData.
|
||||||
CPJavaScriptCanvasTransformFeature = 1 << 14;
|
CPJavaScriptClipboardAccessFeature = 12;
|
||||||
|
CPJavaScriptCanvasDrawFeature = 13;
|
||||||
|
CPJavaScriptCanvasTransformFeature = 14;
|
||||||
|
|
||||||
CPVMLFeature = 1 << 15;
|
CPVMLFeature = 15;
|
||||||
|
|
||||||
CPJavaScriptRemedialKeySupport = 1 << 16;
|
CPJavaScriptRemedialKeySupport = 16;
|
||||||
CPJavaScriptShadowFeature = 1 << 20;
|
CPJavaScriptShadowFeature = 20;
|
||||||
|
|
||||||
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
CPJavaScriptNegativeMouseWheelValues = 22;
|
||||||
CPJavaScriptMouseWheelValues_8_15 = 1 << 23;
|
CPJavaScriptMouseWheelValues_8_15 = 23;
|
||||||
|
|
||||||
CPOpacityRequiresFilterFeature = 1 << 24;
|
CPOpacityRequiresFilterFeature = 24;
|
||||||
|
|
||||||
//Internet explorer does not allow dynamically changing the type of an input element
|
// Internet explorer does not allow dynamically changing the type of an input element
|
||||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
CPInputTypeCanBeChangedFeature = 25;
|
||||||
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
CPHTML5DragAndDropSourceYOffBy1 = 26;
|
||||||
|
|
||||||
CPSOPDisabledFromFileURLs = 1 << 27;
|
CPSOPDisabledFromFileURLs = 27;
|
||||||
|
|
||||||
// element.style.font can be set for an element not in the DOM.
|
// element.style.font can be set for an element not in the DOM.
|
||||||
CPInputSetFontOutsideOfDOM = 1 << 28;
|
CPInputSetFontOutsideOfDOM = 28;
|
||||||
|
|
||||||
// Input elements have 1 px of extra padding on the left regardless of padding setting.
|
// Input elements have 1 px of extra padding on the left regardless of padding setting.
|
||||||
CPInput1PxLeftPadding = 1 << 29;
|
CPInput1PxLeftPadding = 29;
|
||||||
CPInputOnInputEventFeature = 1 << 30;
|
CPInputOnInputEventFeature = 30;
|
||||||
|
|
||||||
// When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas
|
CPFileAPIFeature = 31;
|
||||||
// (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.
|
CPAltEnterTextAreaFeature = 32;
|
||||||
// This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
|
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
|
||||||
|
|
||||||
|
// The paste event is only sent if an input or textarea has focus.
|
||||||
|
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
|
||||||
|
// Redirecting the focus of the browser on keydown to an input for Cmd-V or Ctrl-V makes the paste fail.
|
||||||
|
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,
|
||||||
PLATFORM_FEATURES = 0,
|
PLATFORM_FEATURES = [],
|
||||||
PLATFORM_BUGS = 0,
|
PLATFORM_BUGS = 0,
|
||||||
PLATFORM_STYLE_JS_PROPERTIES = {};
|
PLATFORM_STYLE_JS_PROPERTIES = {};
|
||||||
|
|
||||||
// default these features to true
|
// default these features to true
|
||||||
|
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = YES;
|
||||||
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
||||||
PLATFORM_FEATURES |= CPInputSetFontOutsideOfDOM;
|
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;
|
||||||
@@ -97,44 +122,66 @@ 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;
|
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;
|
PLATFORM_FEATURES[CPVMLFeature] = YES;
|
||||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
PLATFORM_FEATURES[CPJavaScriptShadowFeature] = YES;
|
||||||
|
|
||||||
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
|
PLATFORM_FEATURES[CPOpacityRequiresFilterFeature] = YES;
|
||||||
|
|
||||||
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
|
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = NO;
|
||||||
|
|
||||||
// Tested in Internet Explore 8 and 9.
|
// Tested in Internet Explore 8 and 9.
|
||||||
PLATFORM_FEATURES &= ~CPInputSetFontOutsideOfDOM;
|
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = NO;
|
||||||
|
|
||||||
|
// IE allows free clipboard access.
|
||||||
|
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;
|
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||||
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
PLATFORM_FEATURES[CPHTMLContentEditableFeature] = YES;
|
||||||
|
|
||||||
if (USER_AGENT.indexOf("Chrome") === -1)
|
PLATFORM_FEATURES[CPJavaScriptClipboardEventsFeature] = YES;
|
||||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = NO;
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptShadowFeature] = YES;
|
||||||
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
|
|
||||||
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
|
|
||||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
|
||||||
|
|
||||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||||
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||||
@@ -144,22 +191,32 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
|||||||
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
||||||
|
|
||||||
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
|
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
|
||||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||||
|
|
||||||
// FIXME this is a terrible hack to get around this bug:
|
// FIXME this is a terrible hack to get around this bug:
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=21548
|
// https://bugs.webkit.org/show_bug.cgi?id=21548
|
||||||
if (![CPPlatform isBrowser])
|
if (![CPPlatform isBrowser])
|
||||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||||
|
|
||||||
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
|
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
|
||||||
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
|
PLATFORM_FEATURES[CPHTML5DragAndDropSourceYOffBy1] = YES;
|
||||||
|
|
||||||
// This is supposedly fixed in webkit r123603. Seems to work in Chrome 21 but not Safari 6.0.
|
// This is supposedly fixed in webkit r123603. Seems to work in Chrome 21 but not Safari 6.0.
|
||||||
if (majorVersion < 537)
|
if (majorVersion < 537)
|
||||||
PLATFORM_FEATURES |= CPInput1PxLeftPadding;
|
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
||||||
|
|
||||||
if (USER_AGENT.indexOf("Chrome") === CPNotFound)
|
if (USER_AGENT.indexOf("Chrome") === CPNotFound)
|
||||||
PLATFORM_FEATURES |= CPSOPDisabledFromFileURLs;
|
{
|
||||||
|
PLATFORM_FEATURES[CPSOPDisabledFromFileURLs] = YES;
|
||||||
|
PLATFORM_FEATURES[CPHTMLDragAndDropFeature] = YES;
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=75891
|
||||||
|
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=39689
|
||||||
|
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)
|
||||||
@@ -169,67 +226,98 @@ 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;
|
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));
|
||||||
|
|
||||||
if (version >= 3.0)
|
if (version >= 3.0)
|
||||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||||
|
|
||||||
if (version < 3.0)
|
if (version < 3.0)
|
||||||
PLATFORM_FEATURES |= CPJavaScriptMouseWheelValues_8_15;
|
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;
|
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
|
||||||
|
// 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.
|
||||||
|
/*if (version >= 22.0)
|
||||||
|
{
|
||||||
|
PLATFORM_FEATURES[CPJavaScriptClipboardEventsFeature] = YES;
|
||||||
|
// TODO File a bug at https://bugzilla.mozilla.org/. In other browsers, one can return "false" from the
|
||||||
|
// beforepaste event to indicate a paste should be enabled even that the DOMEvent.target is not editable.
|
||||||
|
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feature Specific Checks
|
// Feature-specific checks
|
||||||
if (typeof document != "undefined")
|
if (typeof document != "undefined")
|
||||||
{
|
{
|
||||||
var canvasElement = document.createElement("canvas");
|
var canvasElement = document.createElement("canvas");
|
||||||
// Detect Canvas Support
|
|
||||||
|
// Detect canvas support
|
||||||
if (canvasElement && canvasElement.getContext)
|
if (canvasElement && canvasElement.getContext)
|
||||||
{
|
{
|
||||||
PLATFORM_FEATURES |= CPHTMLCanvasFeature;
|
PLATFORM_FEATURES[CPHTMLCanvasFeature] = YES;
|
||||||
|
|
||||||
// Detect Canvas setTransform/transform support
|
// Any browser that supports canvas supports CSS opacity
|
||||||
|
PLATFORM_FEATURES[CPOpacityRequiresFilterFeature] = NO;
|
||||||
|
|
||||||
|
// Detect canvas setTransform/transform support
|
||||||
var context = document.createElement("canvas").getContext("2d");
|
var context = document.createElement("canvas").getContext("2d");
|
||||||
|
|
||||||
if (context && context.setTransform && context.transform)
|
if (context && context.setTransform && context.transform)
|
||||||
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
|
PLATFORM_FEATURES[CPJavaScriptCanvasTransformFeature] = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
var DOMElement = document.createElement("div");
|
var DOMElement = document.createElement("div");
|
||||||
|
|
||||||
// Detect whether we have innerText or textContent (or neither)
|
// Detect whether we have innerText or textContent (or neither)
|
||||||
if (DOMElement.innerText != undefined)
|
if (DOMElement.innerText != undefined)
|
||||||
PLATFORM_FEATURES |= CPJavaScriptInnerTextFeature;
|
PLATFORM_FEATURES[CPJavaScriptInnerTextFeature] = YES;
|
||||||
else if (DOMElement.textContent != undefined)
|
else if (DOMElement.textContent != undefined)
|
||||||
PLATFORM_FEATURES |= CPJavaScriptTextContentFeature;
|
PLATFORM_FEATURES[CPJavaScriptTextContentFeature] = YES;
|
||||||
|
|
||||||
var DOMInputElement = document.createElement("input");
|
var DOMInputElement = document.createElement("input");
|
||||||
|
|
||||||
if ("oninput" in DOMInputElement)
|
if ("oninput" in DOMInputElement)
|
||||||
PLATFORM_FEATURES |= CPInputOnInputEventFeature;
|
PLATFORM_FEATURES[CPInputOnInputEventFeature] = YES;
|
||||||
else if (typeof DOMInputElement.setAttribute === "function")
|
else if (typeof DOMInputElement.setAttribute === "function")
|
||||||
{
|
{
|
||||||
DOMInputElement.setAttribute("oninput", "return;");
|
DOMInputElement.setAttribute("oninput", "return;");
|
||||||
|
|
||||||
if (typeof DOMInputElement.oninput === "function")
|
if (typeof DOMInputElement.oninput === "function")
|
||||||
PLATFORM_FEATURES |= CPInputOnInputEventFeature;
|
PLATFORM_FEATURES[CPInputOnInputEventFeature] = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect FileAPI support
|
||||||
|
if (typeof DOMInputElement.setAttribute === "function")
|
||||||
|
{
|
||||||
|
DOMInputElement.setAttribute("type", "file");
|
||||||
|
PLATFORM_FEATURES[CPFileAPIFeature] = !!DOMInputElement["files"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PLATFORM_FEATURES[CPFileAPIFeature] = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CPFeatureIsCompatible(aFeature)
|
function CPFeatureIsCompatible(aFeature)
|
||||||
{
|
{
|
||||||
return PLATFORM_FEATURES & aFeature;
|
return !!PLATFORM_FEATURES[aFeature];
|
||||||
}
|
}
|
||||||
|
|
||||||
function CPPlatformHasBug(aBug)
|
function CPPlatformHasBug(aBug)
|
||||||
@@ -239,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)
|
||||||
@@ -275,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
|
||||||
@@ -308,6 +404,32 @@ function CPBrowserStyleProperty(aProperty)
|
|||||||
|
|
||||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil;
|
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'transformorigin':
|
||||||
|
|
||||||
|
var candidates = {
|
||||||
|
'WebkitTransform' : 'WebkitTransformOrigin',
|
||||||
|
'MozTransform' : 'MozTransformOrigin',
|
||||||
|
'OTransform' : 'OTransformOrigin',
|
||||||
|
'msTransform' : 'MSTransformOrigin',
|
||||||
|
'transform' : 'transformOrigin'
|
||||||
|
};
|
||||||
|
|
||||||
|
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
|
||||||
|
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(' '),
|
||||||
@@ -377,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;
|
||||||
|
}
|
||||||
|
|||||||
+292
-60
@@ -20,24 +20,39 @@
|
|||||||
* 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/Ref.h"
|
@import <Foundation/CPFormatter.j>
|
||||||
|
@import <Foundation/CPTimer.j>
|
||||||
|
|
||||||
@import "../Foundation/CPFormatter.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"
|
||||||
|
|
||||||
CPLeftTextAlignment = 0;
|
@class CPFont
|
||||||
CPRightTextAlignment = 1;
|
|
||||||
CPCenterTextAlignment = 2;
|
|
||||||
CPJustifiedTextAlignment = 3;
|
|
||||||
CPNaturalTextAlignment = 4;
|
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
@protocol CPControlTextEditingDelegate <CPObject>
|
||||||
|
|
||||||
|
@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;
|
||||||
@@ -45,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;
|
||||||
@@ -59,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;
|
||||||
@@ -104,32 +122,27 @@ 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
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[CPLeftTextAlignment,
|
return @{
|
||||||
CPTopVerticalTextAlignment,
|
@"alignment": CPLeftTextAlignment,
|
||||||
CPLineBreakByClipping,
|
@"vertical-alignment": CPTopVerticalTextAlignment,
|
||||||
[CPColor blackColor],
|
@"line-break-mode": CPLineBreakByClipping,
|
||||||
[CPFont systemFontOfSize:CPFontCurrentSystemSize],
|
@"text-color": [CPColor blackColor],
|
||||||
[CPNull null],
|
@"font": [CPNull null],
|
||||||
_CGSizeMakeZero(),
|
@"text-shadow-color": [CPNull null],
|
||||||
CPImageLeft,
|
@"text-shadow-offset": CGSizeMakeZero(),
|
||||||
CPScaleToFit,
|
@"image-position": CPImageLeft,
|
||||||
_CGSizeMakeZero(),
|
@"image-scaling": CPScaleToFit,
|
||||||
_CGSizeMake(-1.0, -1.0)]
|
@"min-size": CGSizeMakeZero(),
|
||||||
forKeys:[@"alignment",
|
@"max-size": CGSizeMake(-1.0, -1.0)
|
||||||
@"vertical-alignment",
|
};
|
||||||
@"line-break-mode",
|
|
||||||
@"text-color",
|
|
||||||
@"font",
|
|
||||||
@"text-shadow-color",
|
|
||||||
@"text-shadow-offset",
|
|
||||||
@"image-position",
|
|
||||||
@"image-scaling",
|
|
||||||
@"min-size",
|
|
||||||
@"max-size"]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
@@ -148,16 +161,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
[self exposeBinding:@"enabled"];
|
[self exposeBinding:@"enabled"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding === CPValueBinding)
|
if (aBinding === CPValueBinding)
|
||||||
return [_CPValueBinder class];
|
return [_CPValueBinder class];
|
||||||
|
else if ([aBinding hasPrefix:CPEnabledBinding])
|
||||||
|
return [CPMultipleValueAndBinding class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
|
Reverse set the binding if the CPContinuouslyUpdatesValueBindingOption is set.
|
||||||
*/
|
*/
|
||||||
- (void)_continuouslyReverseSetBinding
|
- (void)_continuouslyReverseSetBinding
|
||||||
{
|
{
|
||||||
@@ -182,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.
|
||||||
|
|
||||||
@@ -235,6 +334,9 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
{
|
{
|
||||||
[self _reverseSetBinding];
|
[self _reverseSetBinding];
|
||||||
|
|
||||||
|
var binding = [CPBinder getBinding:CPTargetBinding forObject:self];
|
||||||
|
[binding invokeAction];
|
||||||
|
|
||||||
return [CPApp sendAction:anAction to:anObject from:self];
|
return [CPApp sendAction:anAction to:anObject from:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,11 +426,11 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
_previousTrackingLocation = currentLocation;
|
_previousTrackingLocation = currentLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setState:(int)state
|
- (void)setState:(CPInteger)state
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)nextState
|
- (CPInteger)nextState
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -397,6 +499,14 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
[self highlight:YES];
|
[self highlight:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Enabled controls accept first mouse by default.
|
||||||
|
*/
|
||||||
|
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
return [self isEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (![self isEnabled])
|
if (![self isEnabled])
|
||||||
@@ -516,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -533,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;
|
||||||
@@ -545,10 +655,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
{
|
{
|
||||||
value = nil;
|
value = nil;
|
||||||
|
|
||||||
if ([_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil] === NO)
|
if ([_formatter getObjectValue:@ref(value) forString:aString errorDescription:nil] === NO)
|
||||||
{
|
{
|
||||||
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
|
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
|
||||||
if (!aString || [_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
if (!aString || [_formatter getObjectValue:@ref(value) forString:@"" errorDescription:nil] === NO)
|
||||||
value = undefined; // Means the value is invalid
|
value = undefined; // Means the value is invalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -601,7 +711,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
if ([note object] != self)
|
if ([note object] != self)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:@{"CPFieldEditor": [note object]}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)textDidChange:(CPNotification)note
|
- (void)textDidChange:(CPNotification)note
|
||||||
@@ -610,7 +720,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
if ([note object] != self)
|
if ([note object] != self)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:@{"CPFieldEditor": [note object]}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)textDidEndEditing:(CPNotification)note
|
- (void)textDidEndEditing:(CPNotification)note
|
||||||
@@ -621,7 +731,49 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
|
|
||||||
[self _reverseSetBinding];
|
[self _reverseSetBinding];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[note userInfo]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
Return the currentTextMovement needed by the delegate textDidEndEditing
|
||||||
|
This is going to check the currentEvent of the CPApp
|
||||||
|
*/
|
||||||
|
- (unsigned)_currentTextMovement
|
||||||
|
{
|
||||||
|
var currentEvent = [CPApp currentEvent],
|
||||||
|
keyCode = [currentEvent keyCode],
|
||||||
|
modifierFlags = [currentEvent modifierFlags];
|
||||||
|
|
||||||
|
switch (keyCode)
|
||||||
|
{
|
||||||
|
case CPEscapeKeyCode:
|
||||||
|
return CPCancelTextMovement;
|
||||||
|
|
||||||
|
case CPLeftArrowKeyCode:
|
||||||
|
return CPLeftTextMovement;
|
||||||
|
|
||||||
|
case CPRightArrowKeyCode:
|
||||||
|
return CPRightTextMovement;
|
||||||
|
|
||||||
|
case CPUpArrowKeyCode:
|
||||||
|
return CPUpTextMovement;
|
||||||
|
|
||||||
|
case CPDownArrowKeyCode:
|
||||||
|
return CPDownTextMovement;
|
||||||
|
|
||||||
|
case CPReturnKeyCode:
|
||||||
|
return CPReturnTextMovement;
|
||||||
|
|
||||||
|
case CPTabKeyCode:
|
||||||
|
if (modifierFlags & CPShiftKeyMask)
|
||||||
|
return CPBacktabTextMovement;
|
||||||
|
|
||||||
|
return CPTabTextMovement;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CPOtherTextMovement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -657,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"];
|
||||||
}
|
}
|
||||||
@@ -702,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -760,7 +917,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
*/
|
*/
|
||||||
- (CPFont)font
|
- (CPFont)font
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"font"];
|
return [self currentValueForThemeAttribute:@"font"] || [CPFont systemFontForControlSize:_controlSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -807,7 +964,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
/*!
|
/*!
|
||||||
Returns the image scaling of the control.
|
Returns the image scaling of the control.
|
||||||
*/
|
*/
|
||||||
- (CPImageScaling)imageScaling
|
- (CPUInteger)imageScaling
|
||||||
{
|
{
|
||||||
return [self valueForThemeAttribute:@"image-scaling"];
|
return [self valueForThemeAttribute:@"image-scaling"];
|
||||||
}
|
}
|
||||||
@@ -865,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";
|
||||||
|
|
||||||
@@ -901,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;
|
||||||
@@ -920,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
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
|
|||||||
count = _editors.length;
|
count = _editors.length;
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
if (![[_editors objectAtIndex:i] commitEditing])
|
if (![[_editors objectAtIndex:index] commitEditing])
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
|
|||||||
@@ -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
+122
-41
@@ -22,12 +22,22 @@ Cursor support by browser:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import "CPImage.j"
|
||||||
|
@import "CPCompatibility.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
var currentCursor = nil,
|
var currentCursor = nil,
|
||||||
cursorStack = [],
|
cursorStack = [],
|
||||||
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);
|
||||||
@@ -77,7 +87,7 @@ var currentCursor = nil,
|
|||||||
*/
|
*/
|
||||||
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CGPoint)aHotSpot
|
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CGPoint)aHotSpot
|
||||||
{
|
{
|
||||||
return [self initWithImage:image hotSpot:hotSpot];
|
return [self initWithImage:image hotSpot:aHotSpot];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)hide
|
+ (void)hide
|
||||||
@@ -114,11 +124,15 @@ var currentCursor = nil,
|
|||||||
|
|
||||||
- (void)push
|
- (void)push
|
||||||
{
|
{
|
||||||
currentCursor = cursorStack.push(self);
|
cursorStack.push(self);
|
||||||
|
currentCursor = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)set
|
- (void)set
|
||||||
{
|
{
|
||||||
|
if (currentCursor === self)
|
||||||
|
return;
|
||||||
|
|
||||||
currentCursor = self;
|
currentCursor = self;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
@@ -150,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];
|
||||||
|
|
||||||
@@ -158,149 +172,216 @@ var currentCursor = nil,
|
|||||||
{
|
{
|
||||||
var cssString;
|
var cssString;
|
||||||
|
|
||||||
if (doesHaveImage)
|
// IE <= 8 does not support some cursors, map them to supported cursors
|
||||||
cssString = [CPString stringWithFormat:@"url(%@/CPCursor/%@.cur), %@", [[CPBundle bundleForClass:self] resourcePath], cursorName, aString];
|
var ieLessThan9 = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !CPFeatureIsCompatible(CPHTMLCanvasFeature);
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -0,0 +1,837 @@
|
|||||||
|
/* CPDatePicker.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 "CPControl.j"
|
||||||
|
@import "CPFont.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "_CPDatePickerTextField.j"
|
||||||
|
@import "_CPDatePickerCalendar.j"
|
||||||
|
|
||||||
|
@import <Foundation/CPArray.j>
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPDate.j>
|
||||||
|
@import <Foundation/CPLocale.j>
|
||||||
|
@import <Foundation/CPTimeZone.j>
|
||||||
|
|
||||||
|
@class CPStepper
|
||||||
|
@class CPApp
|
||||||
|
|
||||||
|
@global CPLocaleLanguageCode
|
||||||
|
@global CPDateFormatterShortStyle
|
||||||
|
|
||||||
|
var CPDatePicker_validateProposedDateValue_timeInterval = 1 << 1;
|
||||||
|
|
||||||
|
CPSingleDateMode = 0;
|
||||||
|
CPRangeDateMode = 1;
|
||||||
|
|
||||||
|
CPTextFieldAndStepperDatePickerStyle = 0;
|
||||||
|
CPClockAndCalendarDatePickerStyle = 1;
|
||||||
|
CPTextFieldDatePickerStyle = 2;
|
||||||
|
|
||||||
|
CPHourMinuteDatePickerElementFlag = 0x000c;
|
||||||
|
CPHourMinuteSecondDatePickerElementFlag = 0x000e;
|
||||||
|
CPTimeZoneDatePickerElementFlag = 0x0010;
|
||||||
|
CPYearMonthDatePickerElementFlag = 0x00c0;
|
||||||
|
CPYearMonthDayDatePickerElementFlag = 0x00e0;
|
||||||
|
CPEraDatePickerElementFlag = 0x0100;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
This control displays a datepicker in a Cappuccino application
|
||||||
|
*/
|
||||||
|
@implementation CPDatePicker : CPControl
|
||||||
|
{
|
||||||
|
BOOL _isBordered @accessors(getter=isBordered, setter=setBordered:);
|
||||||
|
BOOL _isBezeled @accessors(getter=isBezeled, setter=setBezeled:);
|
||||||
|
BOOL _drawsBackground @accessors(property=drawsBackground);
|
||||||
|
CPDate _dateValue @accessors(property=dateValue);
|
||||||
|
CPDate _minDate @accessors(property=minDate);
|
||||||
|
CPDate _maxDate @accessors(property=maxDate);
|
||||||
|
CPFont _textFont @accessors(property=textFont);
|
||||||
|
CPLocale _locale @accessors(property=locale);
|
||||||
|
//CPCalendar _calendar @accessors(property=calendar);
|
||||||
|
CPTimeZone _timeZone @accessors(property=timeZone);
|
||||||
|
id _delegate @accessors(property=delegate);
|
||||||
|
CPInteger _datePickerElements @accessors(property=datePickerElements);
|
||||||
|
CPInteger _datePickerMode @accessors(property=datePickerMode);
|
||||||
|
CPInteger _datePickerStyle @accessors(property=datePickerStyle);
|
||||||
|
CPInteger _timeInterval @accessors(property=timeInterval);
|
||||||
|
|
||||||
|
BOOL _invokedByUserEvent;
|
||||||
|
unsigned _implementedCDatePickerDelegateMethods;
|
||||||
|
BOOL _isTextual;
|
||||||
|
id _datePickerComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Theme methods
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"datePicker";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"bezel-color": [CPColor clearColor],
|
||||||
|
@"border-width" : 1.0,
|
||||||
|
@"border-color": [CPColor clearColor],
|
||||||
|
@"content-inset": CGInsetMakeZero(),
|
||||||
|
@"bezel-inset": CGInsetMakeZero(),
|
||||||
|
@"datepicker-textfield-bezel-color": [CPColor clearColor],
|
||||||
|
@"min-size-datepicker-textfield": CGSizeMakeZero(),
|
||||||
|
@"content-inset-datepicker-textfield": CGInsetMakeZero(),
|
||||||
|
@"content-inset-datepicker-textfield-separator": CGInsetMakeZero(),
|
||||||
|
@"separator-content-inset": CGInsetMakeZero(),
|
||||||
|
@"date-hour-margin": 5.0,
|
||||||
|
@"stepper-margin": 5.0,
|
||||||
|
@"bezel-color-calendar": [CPColor clearColor],
|
||||||
|
@"title-text-color": [CPColor blackColor],
|
||||||
|
@"title-text-shadow-color": [CPColor clearColor],
|
||||||
|
@"title-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"title-font": [CPNull null],
|
||||||
|
@"weekday-text-color": [CPColor blackColor],
|
||||||
|
@"weekday-text-shadow-color": [CPColor clearColor],
|
||||||
|
@"weekday-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"weekday-font": [CPNull null],
|
||||||
|
@"arrow-image-left": [CPNull null],
|
||||||
|
@"arrow-image-right": [CPNull null],
|
||||||
|
@"arrow-image-left-highlighted": [CPNull null],
|
||||||
|
@"arrow-image-right-highlighted": [CPNull null],
|
||||||
|
@"arrow-inset": CGInsetMakeZero(),
|
||||||
|
@"circle-image": [CPNull null],
|
||||||
|
@"circle-image-highlighted": [CPNull null],
|
||||||
|
@"tile-text-color": [CPColor blackColor],
|
||||||
|
@"tile-text-shadow-color": [CPColor clearColor],
|
||||||
|
@"tile-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"tile-font": [CPNull null],
|
||||||
|
@"size-tile": CGSizeMakeZero(),
|
||||||
|
@"size-calendar": CGSizeMakeZero(),
|
||||||
|
@"size-header": CGSizeMakeZero(),
|
||||||
|
@"min-size-calendar": CGSizeMakeZero(),
|
||||||
|
@"max-size-calendar": CGSizeMakeZero(),
|
||||||
|
@"bezel-color-clock": [CPColor clearColor],
|
||||||
|
@"clock-text-color": [CPColor blackColor],
|
||||||
|
@"clock-text-shadow-color": [CPColor clearColor],
|
||||||
|
@"clock-text-shadow-offset": CGSizeMakeZero(),
|
||||||
|
@"clock-font": [CPNull null],
|
||||||
|
@"second-hand-image": [CPNull null],
|
||||||
|
@"hour-hand-image": [CPNull null],
|
||||||
|
@"middle-hand-image": [CPNull null],
|
||||||
|
@"minute-hand-image": [CPNull null],
|
||||||
|
@"size-clock": CGSizeMakeZero(),
|
||||||
|
@"second-hand-size": CGSizeMakeZero(),
|
||||||
|
@"hour-hand-size": CGSizeMakeZero(),
|
||||||
|
@"middle-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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Binding methods
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||||
|
{
|
||||||
|
if (theBinding == CPValueBinding || theBinding == CPMinValueBinding || theBinding == CPMaxValueBinding)
|
||||||
|
return [_CPDatePickerValueBinder class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:theBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding == CPValueBinding)
|
||||||
|
return @"dateValue";
|
||||||
|
|
||||||
|
if (aBinding == CPMinValueBinding)
|
||||||
|
return @"minDate";
|
||||||
|
|
||||||
|
if (aBinding == CPMaxValueBinding)
|
||||||
|
return @"maxDate";
|
||||||
|
|
||||||
|
return [super _replacementKeyPathForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_drawsBackground = YES;
|
||||||
|
_datePickerStyle = CPTextFieldAndStepperDatePickerStyle;
|
||||||
|
_datePickerMode = CPSingleDateMode;
|
||||||
|
_datePickerElements = CPYearMonthDayDatePickerElementFlag | CPHourMinuteSecondDatePickerElementFlag;
|
||||||
|
_timeInterval = 0;
|
||||||
|
_implementedCDatePickerDelegateMethods = 0;
|
||||||
|
|
||||||
|
[self setObjectValue:[CPDate date]];
|
||||||
|
_minDate = [CPDate distantPast];
|
||||||
|
_maxDate = [CPDate distantFuture];
|
||||||
|
|
||||||
|
[self setBezeled:YES];
|
||||||
|
[self setBordered:YES];
|
||||||
|
|
||||||
|
[self _init];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
if (!_locale)
|
||||||
|
_locale = [CPLocale currentLocale];
|
||||||
|
|
||||||
|
_datePickerComponent = nil;
|
||||||
|
|
||||||
|
[self _createComponents];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[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 Delegate methods
|
||||||
|
|
||||||
|
/*! Set the delegate of the datePicker
|
||||||
|
@param aDelegate delegate of the datePicker
|
||||||
|
*/
|
||||||
|
- (void)setDelegate:(id)aDelegate
|
||||||
|
{
|
||||||
|
_delegate = aDelegate;
|
||||||
|
_implementedCDatePickerDelegateMethods = 0;
|
||||||
|
|
||||||
|
// Look if the delegate implements or not the delegate methods
|
||||||
|
if ([_delegate respondsToSelector:@selector(datePicker:validateProposedDateValue:timeInterval:)])
|
||||||
|
_implementedCDatePickerDelegateMethods |= CPDatePicker_validateProposedDateValue_timeInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout method
|
||||||
|
|
||||||
|
/*! Layout the subviews
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[_datePickerComponent setNeedsLayout];
|
||||||
|
[_datePickerComponent setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Setter
|
||||||
|
|
||||||
|
/*! Return the objectValue of the datePicker. The objectValue should take the timeZoneEffect
|
||||||
|
*/
|
||||||
|
- (id)objectValue
|
||||||
|
{
|
||||||
|
// TODO : add timeZone effect. How to do it because js ???
|
||||||
|
return _dateValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the objectValue of the datePicker. It has to be a CPDate
|
||||||
|
@param aDateValue the dateValue
|
||||||
|
*/
|
||||||
|
- (void)setObjectValue:(CPDate)aValue
|
||||||
|
{
|
||||||
|
if (![aValue isKindOfClass:[CPDate class]])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self setDateValue:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the dateValue of the datePicker
|
||||||
|
@param aDateValue the dateValue
|
||||||
|
*/
|
||||||
|
- (void)setDateValue:(CPDate)aDateValue
|
||||||
|
{
|
||||||
|
if (aDateValue == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_invokedByUserEvent = NO;
|
||||||
|
[self _setDateValue:aDateValue timeInterval:_timeInterval];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the dateValue and the timeInterval. This method checks the min and max date of the datePicker also. It will call the delegate if possible.
|
||||||
|
@param aDateValue the dateValue
|
||||||
|
@param aTimeInterval the timeInterval
|
||||||
|
*/
|
||||||
|
- (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)
|
||||||
|
aDateValue = new Date (MAX(aDateValue, _minDate));
|
||||||
|
|
||||||
|
if (_maxDate)
|
||||||
|
aDateValue = new Date (MIN(aDateValue, _maxDate));
|
||||||
|
|
||||||
|
aTimeInterval = MAX(MIN(aTimeInterval, [_maxDate timeIntervalSinceDate:aDateValue]), [_minDate timeIntervalSinceDate:aDateValue]);
|
||||||
|
|
||||||
|
if ([aDateValue isEqualToDate:_dateValue] && aTimeInterval == _timeInterval)
|
||||||
|
{
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
|
||||||
|
{
|
||||||
|
// constrain timeInterval also
|
||||||
|
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;};
|
||||||
|
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;};
|
||||||
|
|
||||||
|
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"objectValue"];
|
||||||
|
[self willChangeValueForKey:@"dateValue"];
|
||||||
|
_dateValue = aDateValue;
|
||||||
|
[super setObjectValue:_dateValue];
|
||||||
|
[self didChangeValueForKey:@"objectValue"];
|
||||||
|
[self didChangeValueForKey:@"dateValue"];
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"timeInterval"];
|
||||||
|
_timeInterval = (_datePickerMode == CPSingleDateMode)? 0 : aTimeInterval;
|
||||||
|
[self didChangeValueForKey:@"timeInterval"];
|
||||||
|
|
||||||
|
if (_invokedByUserEvent)
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the minDate of the datePicker
|
||||||
|
@param aMinDate the minDate
|
||||||
|
*/
|
||||||
|
- (void)setMinDate:(CPDate)aMinDate
|
||||||
|
{
|
||||||
|
if (_minDate === aMinDate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"minDate"];
|
||||||
|
_minDate = aMinDate;
|
||||||
|
[self didChangeValueForKey:@"minDate"];
|
||||||
|
|
||||||
|
[self _setDateValue:_dateValue timeInterval:_timeInterval];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the maxDate of the datePicker
|
||||||
|
@param aMaxDate the maxDate
|
||||||
|
*/
|
||||||
|
- (void)setMaxDate:(CPDate)aMaxDate
|
||||||
|
{
|
||||||
|
if (_maxDate === aMaxDate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"maxDate"];
|
||||||
|
_maxDate = aMaxDate;
|
||||||
|
[self didChangeValueForKey:@"maxDate"];
|
||||||
|
|
||||||
|
[self _setDateValue:_dateValue timeInterval:_timeInterval];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the syle of the datePicker
|
||||||
|
@param aDatePickerStyle the datePicker style
|
||||||
|
*/
|
||||||
|
- (void)setDatePickerStyle:(CPInteger)aDatePickerStyle
|
||||||
|
{
|
||||||
|
if (_datePickerStyle === aDatePickerStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_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 setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the elements of the datePicker
|
||||||
|
@param aDatePickerElements the datePicker elements
|
||||||
|
*/
|
||||||
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||||
|
{
|
||||||
|
if (_datePickerElements === aDatePickerElements)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_datePickerElements = aDatePickerElements;
|
||||||
|
|
||||||
|
// Notify the component of the new value
|
||||||
|
[_datePickerComponent setDatePickerElements:_datePickerElements];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the mode of the datePicker
|
||||||
|
@param aDatePickerMode the datePicker mode
|
||||||
|
*/
|
||||||
|
- (void)setDatePickerMode:(CPInteger)aDatePickerMode
|
||||||
|
{
|
||||||
|
if (_datePickerMode === aDatePickerMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_datePickerMode = aDatePickerMode;
|
||||||
|
|
||||||
|
if (_datePickerMode == CPSingleDateMode)
|
||||||
|
[self _setDateValue:[self dateValue] timeInterval:0];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the timeInterval of the datePicker
|
||||||
|
@param aTimeInterval the timeInterval of the datePicker
|
||||||
|
*/
|
||||||
|
- (void)setTimeInterval:(CPInteger)aTimeInterval
|
||||||
|
{
|
||||||
|
if (_datePickerMode == CPSingleDateMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _setDateValue:[self dateValue] timeInterval:aTimeInterval];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the locale of the datePicker. This update laso the locale of the formatter.
|
||||||
|
@param aLocale the locale
|
||||||
|
*/
|
||||||
|
- (void)setLocale:(CPLocale)aLocale
|
||||||
|
{
|
||||||
|
if (_locale === aLocale)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_locale = aLocale;
|
||||||
|
|
||||||
|
if (_formatter)
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"locale"];
|
||||||
|
[_formatter setLocale:_locale];
|
||||||
|
[self didChangeValueForKey:@"locale"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will update the textFields (usefull when changing with a date with pm and am)
|
||||||
|
if (_isTextual)
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets whether the datepicker will have a bezeled border.
|
||||||
|
@param shouldBeBezeled \c YES means the datepicker will draw a bezeled border
|
||||||
|
*/
|
||||||
|
- (void)setBezeled:(BOOL)shouldBeBezeled
|
||||||
|
{
|
||||||
|
if (_isBezeled === shouldBeBezeled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isBezeled = shouldBeBezeled;
|
||||||
|
|
||||||
|
if (shouldBeBezeled)
|
||||||
|
[self setThemeState:CPThemeStateBezeled];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateBezeled];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets whether the datepicker will have a border drawn. (actually it does nothing)
|
||||||
|
@param shouldBeBordered \c YES makes the datepicker draw a border
|
||||||
|
*/
|
||||||
|
- (void)setBordered:(BOOL)shouldBeBordered
|
||||||
|
{
|
||||||
|
if (_isBordered === shouldBeBordered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isBordered = shouldBeBordered;
|
||||||
|
|
||||||
|
if (shouldBeBordered)
|
||||||
|
[self setThemeState:CPThemeStateBordered];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateBordered];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the font of the control.
|
||||||
|
@param aFont
|
||||||
|
*/
|
||||||
|
- (void)setTextFont:(CPFont)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.
|
||||||
|
@param a boolean. YES if the control should be enabled, otherwise NO.
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
[super setEnabled:aBoolean];
|
||||||
|
|
||||||
|
[_datePickerComponent setEnabled:aBoolean];
|
||||||
|
|
||||||
|
if (!aBoolean)
|
||||||
|
[self resignFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the background color of the datePicker
|
||||||
|
@param aColor
|
||||||
|
*/
|
||||||
|
- (void)setBackgroundColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
_backgroundColor = aColor;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the boolean drawsBackgroundColor
|
||||||
|
@param aBoolean
|
||||||
|
*/
|
||||||
|
- (void)setDrawsBackground:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
if (_drawsBackground === aBoolean)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"drawsBackground"];
|
||||||
|
_drawsBackground = aBoolean;
|
||||||
|
[self didChangeValueForKey:@"drawsBackground"];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the timeZone
|
||||||
|
@param aTimeZone
|
||||||
|
*/
|
||||||
|
- (void)setTimeZone:(CPTimeZone)aTimeZone
|
||||||
|
{
|
||||||
|
if (_timeZone === aTimeZone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"timeZone"];
|
||||||
|
_timeZone = aTimeZone;
|
||||||
|
[self didChangeValueForKey:@"timeZone"];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
|
||||||
|
[_datePickerComponent setDateValue:_dateValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark First responder methods
|
||||||
|
|
||||||
|
/*! Return YES if style is set to CPTextFieldAndStepperDatePickerStyle or CPTextFieldDatePickerStyle
|
||||||
|
*/
|
||||||
|
- (BOOL)becomeFirstResponder
|
||||||
|
{
|
||||||
|
if (_isTextual)
|
||||||
|
{
|
||||||
|
if (![super becomeFirstResponder])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[_datePickerComponent _selectTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return YES
|
||||||
|
*/
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return YES
|
||||||
|
*/
|
||||||
|
- (BOOL)resignFirstResponder
|
||||||
|
{
|
||||||
|
if (_isTextual)
|
||||||
|
[_datePickerComponent resignFirstResponder];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark getter
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c YES if the textfield is bezeled.
|
||||||
|
*/
|
||||||
|
- (BOOL)isBezeled
|
||||||
|
{
|
||||||
|
return [self hasThemeState:CPThemeStateBezeled];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c YES if the textfield has a border.
|
||||||
|
*/
|
||||||
|
- (BOOL)isBordered
|
||||||
|
{
|
||||||
|
return [self hasThemeState:CPThemeStateBordered];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the font of the control.
|
||||||
|
*/
|
||||||
|
- (CPFont)textFont
|
||||||
|
{
|
||||||
|
return [self font];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check if we are in the american format or not. Depending on the locale
|
||||||
|
*/
|
||||||
|
- (BOOL)_isAmericanFormat
|
||||||
|
{
|
||||||
|
return [[_locale objectForKey:CPLocaleCountryCode] isEqualToString:@"US"];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Key event
|
||||||
|
|
||||||
|
/*! Key down event
|
||||||
|
@param anEvent
|
||||||
|
*/
|
||||||
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_isTextual)
|
||||||
|
[_datePickerComponent keyDown:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
||||||
|
CPIntervalKey = @"CPIntervalKey",
|
||||||
|
CPMinDateKey = @"CPMinDateKey",
|
||||||
|
CPMaxDateKey = @"CPMaxDateKey",
|
||||||
|
CPBackgroundColorKey = @"CPBackgroundColorKey",
|
||||||
|
CPDrawsBackgroundKey = @"CPDrawsBackgroundKey",
|
||||||
|
CPTextFontKey = @"CPTextFontKey",
|
||||||
|
CPDatePickerElementsKey = @"CPDatePickerElementsKey",
|
||||||
|
CPDatePickerStyleKey = @"CPDatePickerStyleKey",
|
||||||
|
CPLocaleKey = @"CPLocaleKey",
|
||||||
|
CPBorderedKey = @"CPBorderedKey",
|
||||||
|
CPDateValueKey = @"CPDateValueKey";
|
||||||
|
|
||||||
|
@implementation CPDatePicker (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
||||||
|
[self setBordered:[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 setTextFont:[aCoder decodeObjectForKey:CPTextFontKey]];
|
||||||
|
[self setTimeInterval:[aCoder decodeDoubleForKey:CPIntervalKey]];
|
||||||
|
[self setDateValue:[aCoder decodeObjectForKey:CPDateValueKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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];
|
||||||
|
|
||||||
|
[aCoder encodeDouble:_timeInterval forKey:CPIntervalKey];
|
||||||
|
[aCoder encodeInt:_datePickerMode forKey:CPDatePickerModeKey];
|
||||||
|
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
|
||||||
|
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
|
||||||
|
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
|
||||||
|
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey];
|
||||||
|
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];
|
||||||
|
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
|
||||||
|
[aCoder encodeObject:_locale forKey:CPLocaleKey];
|
||||||
|
[aCoder encodeObject:_backgroundColor forKey:CPBackgroundColorKey];
|
||||||
|
[aCoder encodeObject:_drawsBackground forKey:CPDrawsBackgroundKey];
|
||||||
|
[aCoder encodeObject:_isBordered forKey:CPBorderedKey];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// FIXME: add support for CPEditorRegistrationProtocol as implemented for CPTextField
|
||||||
|
@implementation _CPDatePickerValueBinder : CPBinder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPDate (CPDatePickerAdditions)
|
||||||
|
|
||||||
|
- (int)_daysInMonth
|
||||||
|
{
|
||||||
|
return 32 - new Date(self.getFullYear(), self.getMonth(), 32).getDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_resetToMidnight
|
||||||
|
{
|
||||||
|
self.setHours(0);
|
||||||
|
self.setMinutes(0);
|
||||||
|
self.setSeconds(0);
|
||||||
|
self.setMilliseconds(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_resetToLastSeconds
|
||||||
|
{
|
||||||
|
self.setHours(23);
|
||||||
|
self.setMinutes(59);
|
||||||
|
self.setSeconds(59);
|
||||||
|
self.setMilliseconds(99);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
/* _CPDatePickerCalendar.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 "_CPDatePickerClock.j"
|
||||||
|
@import "_CPDatePickerBox.j"
|
||||||
|
@import "_CPDatePickerMonthView.j"
|
||||||
|
@import "_CPDatePickerHeaderView.j"
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
@global CPHourMinuteDatePickerElementFlag
|
||||||
|
@global CPHourMinuteSecondDatePickerElementFlag
|
||||||
|
@global CPTimeZoneDatePickerElementFlag
|
||||||
|
@global CPYearMonthDatePickerElementFlag
|
||||||
|
@global CPYearMonthDayDatePickerElementFlag
|
||||||
|
@global CPEraDatePickerElementFlag
|
||||||
|
|
||||||
|
@implementation _CPDatePickerCalendar : CPControl
|
||||||
|
{
|
||||||
|
_CPDatePickerMonthView _monthView;
|
||||||
|
_CPDatePickerHeaderView _headerView;
|
||||||
|
_CPDatePickerClock _datePickerClock;
|
||||||
|
_CPDatePickerBox _box;
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
CPInteger _startSelectionIndex;
|
||||||
|
CPInteger _currentSelectionIndex;
|
||||||
|
BOOL _hasClock;
|
||||||
|
BOOL _hasCalendar;
|
||||||
|
BOOL _isClockOnly;
|
||||||
|
CPInteger _datePickerElements @accessors(getter=datePickerElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Init method
|
||||||
|
|
||||||
|
/*! Init a _CPDatePickerCalendar
|
||||||
|
@param aFrame
|
||||||
|
@param aDatePicker
|
||||||
|
@return a new instance of _CPDatePickerCalendar
|
||||||
|
*/
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame withDatePicker:(CPDatePicker)aDatePicker
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
_datePickerElements = [_datePicker datePickerElements];
|
||||||
|
|
||||||
|
[self _init];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Init the object
|
||||||
|
*/
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
var sizeHeader = [_datePicker valueForThemeAttribute:@"size-header"],
|
||||||
|
sizeCalendar = [_datePicker valueForThemeAttribute:@"size-calendar"],
|
||||||
|
sizeClock = [_datePicker valueForThemeAttribute:@"size-clock"],
|
||||||
|
calendarClockMargin = [_datePicker valueForThemeAttribute:@"calendar-clock-margin"];
|
||||||
|
|
||||||
|
_hasClock = (_datePickerElements & CPHourMinuteSecondDatePickerElementFlag) || (_datePickerElements & CPHourMinuteDatePickerElementFlag);
|
||||||
|
_hasCalendar = (_datePickerElements & CPYearMonthDayDatePickerElementFlag) || (_datePickerElements & CPYearMonthDatePickerElementFlag);
|
||||||
|
_isClockOnly = _hasClock && !_hasCalendar;
|
||||||
|
|
||||||
|
if (_hasCalendar && !_box)
|
||||||
|
{
|
||||||
|
_box = [[_CPDatePickerBox alloc] initWithFrame:CGRectMake(0, 0, sizeCalendar.width, sizeHeader.height + sizeCalendar.height)];
|
||||||
|
[_box setDatePicker:_datePicker];
|
||||||
|
[self addSubview:_box];
|
||||||
|
|
||||||
|
_headerView = [[_CPDatePickerHeaderView alloc] initWithFrame:CGRectMake(0, 0, sizeHeader.width, sizeHeader.height) datePicker:_datePicker delegate:self];
|
||||||
|
[_box addSubview:_headerView];
|
||||||
|
|
||||||
|
_monthView = [[_CPDatePickerMonthView alloc] initWithFrame:CGRectMake(0, sizeHeader.height, sizeCalendar.width, sizeCalendar.height) datePicker:_datePicker delegate:self];
|
||||||
|
[_box addSubview:_monthView];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hasClock && !_datePickerClock)
|
||||||
|
{
|
||||||
|
_datePickerClock = [[_CPDatePickerClock alloc] initWithFrame:CGRectMake(0, 0, sizeClock.width, sizeClock.height) datePicker:_datePicker];
|
||||||
|
[self addSubview:_datePickerClock];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hasClock)
|
||||||
|
[_datePickerClock setDatePickerElements:_datePickerElements];
|
||||||
|
|
||||||
|
[self setDateValue:[_datePicker dateValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Responder methods
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Getter Setter methods
|
||||||
|
|
||||||
|
/*! Set the date value of the component. It sets the dateValue of the header and the monthView also
|
||||||
|
@param aDateValue
|
||||||
|
*/
|
||||||
|
- (void)setDateValue:(CPDate)aDateValue
|
||||||
|
{
|
||||||
|
var dateValue = [aDateValue copy];
|
||||||
|
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||||
|
|
||||||
|
[_monthView setMonthForDate:dateValue];
|
||||||
|
[_headerView setMonthForDate:[_monthView monthDate]];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set enabled
|
||||||
|
@param aBoolean
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
[super setEnabled:aBoolean];
|
||||||
|
|
||||||
|
[_datePickerClock setEnabled:aBoolean];
|
||||||
|
[_headerView setEnabled:aBoolean];
|
||||||
|
[_monthView setEnabled:aBoolean];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||||
|
{
|
||||||
|
if (_datePickerElements === aDatePickerElements)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_datePickerElements = aDatePickerElements;
|
||||||
|
|
||||||
|
[self _init];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
/*! Manager the subviews. It hides or not the clock.
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
var minSize = [_datePicker valueForThemeAttribute:@"min-size-calendar"],
|
||||||
|
sizeHeader = [_datePicker valueForThemeAttribute:@"size-header"],
|
||||||
|
sizeCalendar = [_datePicker valueForThemeAttribute:@"size-calendar"],
|
||||||
|
sizeClock = [_datePicker valueForThemeAttribute:@"size-clock"],
|
||||||
|
calendarClockMargin = [_datePicker valueForThemeAttribute:@"calendar-clock-margin"];
|
||||||
|
|
||||||
|
if (_hasClock)
|
||||||
|
{
|
||||||
|
if (!_isClockOnly)
|
||||||
|
{
|
||||||
|
var frameSize = CGSizeMakeCopy(minSize);
|
||||||
|
frameSize.width += sizeClock.width + calendarClockMargin;
|
||||||
|
|
||||||
|
[_datePicker setFrameSize:frameSize];
|
||||||
|
[_datePickerClock setFrameOrigin:CGPointMake(sizeCalendar.width + calendarClockMargin, [self bounds].size.height / 2 - sizeClock.height / 2)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_datePicker setFrameSize:sizeClock];
|
||||||
|
[_datePickerClock setFrameOrigin:CGPointMake(0, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_datePickerClock setHidden:NO];
|
||||||
|
[_datePickerClock setFrameSize:sizeClock];
|
||||||
|
[_datePickerClock setNeedsLayout];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_datePicker setFrameSize:minSize];
|
||||||
|
[_datePickerClock setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hasCalendar)
|
||||||
|
{
|
||||||
|
[_box setHidden:NO];
|
||||||
|
[_headerView setHidden:NO];
|
||||||
|
[_monthView setHidden:NO];
|
||||||
|
[_box setNeedsLayout];
|
||||||
|
[_box setNeedsDisplay:YES];
|
||||||
|
[_headerView setNeedsLayout];
|
||||||
|
[_monthView setNeedsLayout];
|
||||||
|
[_monthView setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_box setHidden:YES];
|
||||||
|
[_headerView setHidden:YES];
|
||||||
|
[_monthView setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setFrameSize:[_datePicker frameSize]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Action methods
|
||||||
|
|
||||||
|
/*! Move to the nextMonth without changing the dateValue of the datePicker
|
||||||
|
*/
|
||||||
|
- (void)_clickArrowNext:(id)sender
|
||||||
|
{
|
||||||
|
var currentEvent = [CPApp currentEvent],
|
||||||
|
modifierFlags = [currentEvent modifierFlags];
|
||||||
|
|
||||||
|
if (modifierFlags & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
|
||||||
|
{
|
||||||
|
var date = [[_monthView monthDate] copy];
|
||||||
|
date.setDate(1);
|
||||||
|
|
||||||
|
if (modifierFlags & CPAlternateKeyMask)
|
||||||
|
date.setUTCFullYear(date.getUTCFullYear() + 10);
|
||||||
|
else
|
||||||
|
date.setUTCFullYear(date.getUTCFullYear() + 1);
|
||||||
|
|
||||||
|
[self setDateValue:date];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self _displayNextMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_displayNextMonth
|
||||||
|
{
|
||||||
|
[self setDateValue:[_monthView nextMonth]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_displayPreviousMonth
|
||||||
|
{
|
||||||
|
[self setDateValue:[_monthView previousMonth]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Move to the previous month without changing the dateValue of the datePicker
|
||||||
|
*/
|
||||||
|
- (void)_clickArrowPrevious:(id)sender
|
||||||
|
{
|
||||||
|
var currentEvent = [CPApp currentEvent],
|
||||||
|
modifierFlags = [currentEvent modifierFlags];
|
||||||
|
|
||||||
|
if (modifierFlags & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
|
||||||
|
{
|
||||||
|
var date = [[_monthView monthDate] copy];
|
||||||
|
date.setDate(1);
|
||||||
|
|
||||||
|
if (modifierFlags & CPAlternateKeyMask)
|
||||||
|
date.setUTCFullYear(date.getUTCFullYear() - 10);
|
||||||
|
else
|
||||||
|
date.setUTCFullYear(date.getUTCFullYear() - 1);
|
||||||
|
|
||||||
|
[self setDateValue:date];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self _displayPreviousMonth];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Move to the current selected day
|
||||||
|
*/
|
||||||
|
- (void)_currentMonth:(id)sender
|
||||||
|
{
|
||||||
|
[self setDateValue:[_datePicker dateValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,611 @@
|
|||||||
|
/*
|
||||||
|
* _CPDatePickerClock.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/CPKeyedArchiver.j>
|
||||||
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
|
@import "CPView.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "CPImage.j"
|
||||||
|
@import "CALayer.j"
|
||||||
|
|
||||||
|
@class _CPCibCustomResource
|
||||||
|
@class CPDatePicker
|
||||||
|
@class HandImageLayer
|
||||||
|
@class HoursLayer
|
||||||
|
@class HandLayer
|
||||||
|
|
||||||
|
@global CPHourMinuteSecondDatePickerElementFlag
|
||||||
|
@global CPTextFieldAndStepperDatePickerStyle
|
||||||
|
@global CPTextFieldDatePickerStyle
|
||||||
|
|
||||||
|
var RADIANS = Math.PI / 180;
|
||||||
|
|
||||||
|
@typedef _CPDatePickerClockHand
|
||||||
|
_CPDatePickerClockHours = 1;
|
||||||
|
_CPDatePickerClockMinutes = 2;
|
||||||
|
_CPDatePickerClockSeconds = 3;
|
||||||
|
|
||||||
|
@implementation _CPDatePickerClock : CPControl
|
||||||
|
{
|
||||||
|
BOOL _isEnabled;
|
||||||
|
HoursLayer _rootLayer;
|
||||||
|
HandLayer _hourHandLayer;
|
||||||
|
HandLayer _minuteHandLayer;
|
||||||
|
HandLayer _secondHandLayer;
|
||||||
|
CALayer _middleHandLayer;
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame datePicker:(CPDatePicker)aDatePicker
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
_datePickerElements = [_datePicker datePickerElements];
|
||||||
|
_trackingHand = NO;
|
||||||
|
|
||||||
|
_PMAMTextField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-font" inState:CPThemeStateNormal] forThemeAttribute:@"font" inState:CPThemeStateNormal];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-color" inState:CPThemeStateNormal];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-shadow-color" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateNormal];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-shadow-offset" inState:CPThemeStateNormal] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateNormal];
|
||||||
|
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-font" inState:CPThemeStateDisabled] forThemeAttribute:@"font" inState:CPThemeStateDisabled];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled];
|
||||||
|
[_PMAMTextField setValue:[_datePicker valueForThemeAttribute:@"clock-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled];
|
||||||
|
|
||||||
|
[self addSubview:_PMAMTextField];
|
||||||
|
|
||||||
|
var middleHandSize = [_datePicker valueForThemeAttribute:@"middle-hand-size"],
|
||||||
|
minuteHandSize = [_datePicker valueForThemeAttribute:@"minute-hand-size"],
|
||||||
|
hourHandSize = [_datePicker valueForThemeAttribute:@"hour-hand-size"],
|
||||||
|
secondHandSize = [_datePicker valueForThemeAttribute:@"second-hand-size"];
|
||||||
|
|
||||||
|
// We use layer to make the rotation possible
|
||||||
|
_hourHandLayer = [[HandLayer alloc] initWithSize:hourHandSize];
|
||||||
|
[_hourHandLayer setBounds:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height)];
|
||||||
|
[_hourHandLayer setAnchorPoint:CGPointMakeZero()];
|
||||||
|
[_hourHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
||||||
|
|
||||||
|
_minuteHandLayer = [[HandLayer alloc] initWithSize:minuteHandSize];
|
||||||
|
[_minuteHandLayer setBounds:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height)];
|
||||||
|
[_minuteHandLayer setAnchorPoint:CGPointMakeZero()];
|
||||||
|
[_minuteHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
||||||
|
|
||||||
|
_secondHandLayer = [[HandLayer alloc] initWithSize:secondHandSize];
|
||||||
|
[_secondHandLayer setBounds:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height)];
|
||||||
|
[_secondHandLayer setAnchorPoint:CGPointMakeZero()];
|
||||||
|
[_secondHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
||||||
|
|
||||||
|
_middleHandLayer = [[HandLayer alloc] initWithSize:middleHandSize];
|
||||||
|
[_middleHandLayer setBounds:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height)];
|
||||||
|
[_middleHandLayer setAnchorPoint:CGPointMakeZero()];
|
||||||
|
[_middleHandLayer setPosition:CGPointMake(0.0, 0.0)];
|
||||||
|
|
||||||
|
_rootLayer = [[HoursLayer alloc] init];
|
||||||
|
[self setWantsLayer:YES];
|
||||||
|
[self setLayer:_rootLayer];
|
||||||
|
|
||||||
|
[self _initHands];
|
||||||
|
|
||||||
|
[_rootLayer addSublayer:_hourHandLayer];
|
||||||
|
[_rootLayer addSublayer:_minuteHandLayer];
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_initHands
|
||||||
|
{
|
||||||
|
var middleHandImage = [_datePicker currentValueForThemeAttribute:@"middle-hand-image"],
|
||||||
|
hourHandImage = [_datePicker currentValueForThemeAttribute:@"hour-hand-image"],
|
||||||
|
minuteHandImage = [_datePicker currentValueForThemeAttribute:@"minute-hand-image"],
|
||||||
|
secondHandImage = [_datePicker currentValueForThemeAttribute:@"second-hand-image"];
|
||||||
|
|
||||||
|
// If hand images are true CPImage, we have to duplicate them to avoid
|
||||||
|
// the multiple delegates bug when multiple clocks are displayed
|
||||||
|
|
||||||
|
if ([middleHandImage isKindOfClass:[CPImage class]])
|
||||||
|
middleHandImage = [middleHandImage duplicate];
|
||||||
|
|
||||||
|
if ([hourHandImage isKindOfClass:[CPImage class]])
|
||||||
|
hourHandImage = [hourHandImage duplicate];
|
||||||
|
|
||||||
|
if ([minuteHandImage isKindOfClass:[CPImage class]])
|
||||||
|
minuteHandImage = [minuteHandImage duplicate];
|
||||||
|
|
||||||
|
if ([secondHandImage isKindOfClass:[CPImage class]])
|
||||||
|
secondHandImage = [secondHandImage duplicate];
|
||||||
|
|
||||||
|
[_middleHandLayer setImage:middleHandImage];
|
||||||
|
[_hourHandLayer setImage:hourHandImage];
|
||||||
|
[_minuteHandLayer setImage:minuteHandImage];
|
||||||
|
[_secondHandLayer setImage:secondHandImage];
|
||||||
|
|
||||||
|
[_hourHandLayer setNeedsDisplay];
|
||||||
|
[_middleHandLayer setNeedsDisplay];
|
||||||
|
[_secondHandLayer setNeedsDisplay];
|
||||||
|
[_minuteHandLayer setNeedsDisplay];
|
||||||
|
|
||||||
|
[_rootLayer setFont:[_datePicker currentValueForThemeAttribute:@"clock-hours-font"]];
|
||||||
|
[_rootLayer setTextColor:[_datePicker currentValueForThemeAttribute:@"clock-hours-text-color"]];
|
||||||
|
[_rootLayer setRadius:[_datePicker currentValueForThemeAttribute:@"clock-hours-radius"]];
|
||||||
|
|
||||||
|
[_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 Accessors
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)shouldEnable
|
||||||
|
{
|
||||||
|
shouldEnable = !!shouldEnable;
|
||||||
|
|
||||||
|
if (shouldEnable === _isEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isEnabled = shouldEnable;
|
||||||
|
|
||||||
|
[self _initHands];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation HandLayer : CALayer
|
||||||
|
{
|
||||||
|
CPImage _image;
|
||||||
|
HandImageLayer _imageLayer;
|
||||||
|
float _rotationRadians;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Init methods
|
||||||
|
|
||||||
|
- (id)initWithSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_imageLayer = [HandImageLayer layer];
|
||||||
|
_rotationRadians = 0;
|
||||||
|
|
||||||
|
[_imageLayer setDelegate:self];
|
||||||
|
[_imageLayer setBounds:CGRectMake(0.0, 0.0, aSize.width, aSize.height)];
|
||||||
|
|
||||||
|
[self addSublayer:_imageLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Setter Getter methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the bounds of the layer. The imageLayer will be at the center of this bounds.
|
||||||
|
*/
|
||||||
|
- (void)setBounds:(CGRect)aRect
|
||||||
|
{
|
||||||
|
[super setBounds:aRect];
|
||||||
|
|
||||||
|
[_imageLayer setPosition:CGPointMake(CGRectGetMidX(aRect), CGRectGetMidY(aRect))];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
if (_image === anImage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([anImage isKindOfClass:[_CPCibCustomResource class]])
|
||||||
|
_image = [anImage imageFromCoder:nil];
|
||||||
|
else
|
||||||
|
_image = anImage;
|
||||||
|
|
||||||
|
[_imageLayer setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRotationRadians:(float)radians
|
||||||
|
{
|
||||||
|
if (_rotationRadians === radians)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_rotationRadians = radians;
|
||||||
|
|
||||||
|
[_imageLayer setAffineTransform:CGAffineTransformScale(
|
||||||
|
CGAffineTransformMakeRotation(_rotationRadians),
|
||||||
|
1.0, 1.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)imageDidLoad:(CPImage)anImage
|
||||||
|
{
|
||||||
|
[_imageLayer setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawLayer:(CALayer)aLayer inContext:(CGContext)aContext
|
||||||
|
{
|
||||||
|
if ([_image loadStatus] != CPImageLoadStatusCompleted)
|
||||||
|
[_image setDelegate:self];
|
||||||
|
else
|
||||||
|
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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,502 @@
|
|||||||
|
/* _CPDatePickerTextField.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 "CPControl.j"
|
||||||
|
@import "CPFont.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "CPStepper.j"
|
||||||
|
|
||||||
|
@import <Foundation/CPArray.j>
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPDate.j>
|
||||||
|
@import <Foundation/CPDateFormatter.j>
|
||||||
|
@import <Foundation/CPLocale.j>
|
||||||
|
|
||||||
|
@class CPDatePicker
|
||||||
|
@class _CPDatePickerElementView
|
||||||
|
|
||||||
|
@import "_CPDatePickerElementView.j"
|
||||||
|
|
||||||
|
@global CPSingleDateMode
|
||||||
|
@global CPRangeDateMode
|
||||||
|
|
||||||
|
@global CPTextFieldAndStepperDatePickerStyle
|
||||||
|
@global CPTextFieldDatePickerStyle
|
||||||
|
|
||||||
|
@global CPHourMinuteDatePickerElementFlag
|
||||||
|
@global CPHourMinuteSecondDatePickerElementFlag
|
||||||
|
@global CPTimeZoneDatePickerElementFlag
|
||||||
|
@global CPYearMonthDatePickerElementFlag
|
||||||
|
@global CPYearMonthDayDatePickerElementFlag
|
||||||
|
@global CPEraDatePickerElementFlag
|
||||||
|
|
||||||
|
var CPZeroKeyCode = 48,
|
||||||
|
CPNineKeyCode = 57,
|
||||||
|
CPMajAKeyCode = 65,
|
||||||
|
CPMajPKeyCode = 80,
|
||||||
|
CPAKeyCode = 97,
|
||||||
|
CPPKeyCode = 112;
|
||||||
|
|
||||||
|
// This class is used to represente the datePicker with the CPTextFieldAndStepperDatePickerStyle/CPTextFieldDatePickerStyle mode
|
||||||
|
@implementation _CPDatePickerTextField : CPControl
|
||||||
|
{
|
||||||
|
_CPDatePickerElementTextField _firstTextField @accessors(property=firstTextField);
|
||||||
|
_CPDatePickerElementTextField _lastTextField @accessors(property=lastTextField);
|
||||||
|
|
||||||
|
_CPDatePickerElementTextField _currentTextField;
|
||||||
|
_CPDatePickerElementView _datePickerElementView;
|
||||||
|
CPDatePicker _datePicker;
|
||||||
|
CPStepper _stepper;
|
||||||
|
CPInteger _datePickerElements @accessors(getter=datePickerElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Init
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame withDatePicker:(CPDatePicker)aDatePicker
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_datePicker = aDatePicker;
|
||||||
|
[self _init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_datePickerElements = [_datePicker datePickerElements];
|
||||||
|
|
||||||
|
_datePickerElementView = [[_CPDatePickerElementView alloc] initWithFrame:CGRectMakeZero() withDatePicker:_datePicker];
|
||||||
|
[self addSubview:_datePickerElementView];
|
||||||
|
|
||||||
|
_stepper = [CPStepper stepper];
|
||||||
|
[_stepper setTarget:self];
|
||||||
|
[_stepper setAction:@selector(_clickStepper:)];
|
||||||
|
[self addSubview:_stepper];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
if ([_datePicker currentValueForThemeAttribute:@"uses-focus-ring"])
|
||||||
|
{
|
||||||
|
// As with overflow:hidden, views are clipping their content, in order
|
||||||
|
// to show a focus ring (which is external to a view), we need to let
|
||||||
|
// content extend outside the view.
|
||||||
|
_datePicker._DOMElement.style.overflow = "visible";
|
||||||
|
_DOMElement.style.overflow = "visible";
|
||||||
|
_datePickerElementView._DOMElement.style.overflow = "visible";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override responder methods
|
||||||
|
|
||||||
|
- (BOOL)becomeFirstResponder
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)resignFirstResponder
|
||||||
|
{
|
||||||
|
// End the timer of editing
|
||||||
|
[_currentTextField _endEditing];
|
||||||
|
|
||||||
|
// Don't forget to unbind, otherwise several steppers will increase or decrease
|
||||||
|
[_currentTextField unbind:@"objectValue"];
|
||||||
|
[_currentTextField makeDeselectable];
|
||||||
|
_currentTextField = nil
|
||||||
|
|
||||||
|
// This is usefull when clicking on the stepper when the datePicker is not selected
|
||||||
|
[_stepper setObjectValue:0];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyView
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Setter Getter methods
|
||||||
|
|
||||||
|
/*! Set the value of the control
|
||||||
|
@param aDateValue
|
||||||
|
*/
|
||||||
|
- (void)setDateValue:(CPDate)aDateValue
|
||||||
|
{
|
||||||
|
var dateValue = [aDateValue copy];
|
||||||
|
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||||
|
[_datePickerElementView setDateValue:dateValue];
|
||||||
|
|
||||||
|
// Be sure to update the stepper value. We don't use -setObjectValue to avoid a binding update.
|
||||||
|
if (_currentTextField)
|
||||||
|
_stepper._value = [_currentTextField intValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set the widget enabled or not
|
||||||
|
@param aBoolean
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)aBoolean
|
||||||
|
{
|
||||||
|
[super setEnabled:aBoolean];
|
||||||
|
[_stepper setEnabled:aBoolean];
|
||||||
|
[_datePickerElementView setEnabled:aBoolean];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[super setTextColor:aColor];
|
||||||
|
[_datePickerElementView setTextColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
[self setFont:aFont];
|
||||||
|
[_datePickerElementView setTextFont:aFont];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||||
|
{
|
||||||
|
if (_datePickerElements === aDatePickerElements)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_datePickerElements = aDatePickerElements;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Notification methods
|
||||||
|
|
||||||
|
/*! This is called to when the user just changed the selected textField
|
||||||
|
@param aNotification
|
||||||
|
*/
|
||||||
|
- (void)_datePickerElementTextFieldBecomeFirstResponder:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
if ([[aNotification userInfo] objectForKey:@"textField"] == _currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _selectTextField:[[aNotification userInfo] objectForKey:@"textField"]];
|
||||||
|
|
||||||
|
// This is tricky, its to avoid to have the cursor
|
||||||
|
if ([[self window] firstResponder] != _datePicker)
|
||||||
|
[[self window] makeFirstResponder:_datePicker];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark SelectTextField action
|
||||||
|
|
||||||
|
- (void)_selectTextFieldWithFlags:(unsigned)flags
|
||||||
|
{
|
||||||
|
[_datePickerElementView _updateResponderTextField];
|
||||||
|
|
||||||
|
// We select the firstTextField when the datePicker becomes firstResponder if _currentTextField is null. It can be null just when using tab
|
||||||
|
if (!_currentTextField)
|
||||||
|
{
|
||||||
|
if (flags & CPShiftKeyMask)
|
||||||
|
[self _selectTextField:_lastTextField];
|
||||||
|
else
|
||||||
|
[self _selectTextField:_firstTextField];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Select a textField
|
||||||
|
@param aDatePickerElementTextField the textField
|
||||||
|
*/
|
||||||
|
- (void)_selectTextField:(_CPDatePickerElementTextField)aDatePickerElementTextField
|
||||||
|
{
|
||||||
|
if (_currentTextField == aDatePickerElementTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// End the timer of editing
|
||||||
|
[_currentTextField _endEditing];
|
||||||
|
|
||||||
|
// Don't forget to unbind, otherwise several steppers will increase or decrease
|
||||||
|
[_currentTextField unbind:@"objectValue"];
|
||||||
|
[_currentTextField makeDeselectable];
|
||||||
|
|
||||||
|
_currentTextField = aDatePickerElementTextField;
|
||||||
|
[_currentTextField makeSelectable];
|
||||||
|
|
||||||
|
// We cannot assign a value with the textField AM/PM
|
||||||
|
if ([_currentTextField dateType] != CPAMPMDateType)
|
||||||
|
{
|
||||||
|
// We update the value of the stepper dependind on the textField
|
||||||
|
[_stepper setObjectValue:[_currentTextField intValue]];
|
||||||
|
[_stepper setMaxValue:[_currentTextField maxNumber]];
|
||||||
|
[_stepper setMinValue:[_currentTextField minNumber]];
|
||||||
|
|
||||||
|
// We bind the stepper with textField
|
||||||
|
[_currentTextField bind:@"objectValue" toObject:_stepper withKeyPath:@"objectValue" options:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Events
|
||||||
|
|
||||||
|
/*! Called when the user click on the stepper
|
||||||
|
*/
|
||||||
|
- (void)_clickStepper:(id)sender
|
||||||
|
{
|
||||||
|
// Success when clicking on the stepper if the datePicker is not selected
|
||||||
|
if ([[self window] firstResponder] != _datePicker || !_currentTextField)
|
||||||
|
{
|
||||||
|
var isUp = NO;
|
||||||
|
|
||||||
|
if ([sender objectValue] == 1)
|
||||||
|
isUp = YES;
|
||||||
|
|
||||||
|
[self _selectTextField:_firstTextField];
|
||||||
|
[[self window] makeFirstResponder:_datePicker];
|
||||||
|
|
||||||
|
// Update the dateValue with the binding.
|
||||||
|
if (isUp)
|
||||||
|
[_stepper setDoubleValue:[_currentTextField intValue] + 1];
|
||||||
|
else
|
||||||
|
[_stepper setDoubleValue:[_currentTextField intValue] - 1];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_currentTextField dateType] != CPAMPMDateType)
|
||||||
|
{
|
||||||
|
// Make sure to get the good value, especially when we reach the maxDate or minDate
|
||||||
|
[sender setDoubleValue:[_currentTextField intValue]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// AM/PM behavior
|
||||||
|
if ([[_currentTextField stringValue] isEqualToString:@"PM"])
|
||||||
|
[_currentTextField setStringValue:@"AM"];
|
||||||
|
else
|
||||||
|
[_currentTextField setStringValue:@"PM"];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPDatePickerElementTextFieldAMPMChangedNotification object:_currentTextField userInfo:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
PerformKeyEquivalent event
|
||||||
|
We need to override that to handle the tab key
|
||||||
|
*/
|
||||||
|
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEnabled] || !_currentTextField || [[self window] firstResponder] != _datePicker)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
|
||||||
|
{
|
||||||
|
if ([anEvent modifierFlags] & CPShiftKeyMask)
|
||||||
|
[self insertBacktab:self];
|
||||||
|
else
|
||||||
|
[self insertTab:self];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
|
||||||
|
{
|
||||||
|
[self insertBacktab:self];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [super performKeyEquivalent:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertTab:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_currentTextField == _lastTextField)
|
||||||
|
[[self window] selectNextKeyView:self];
|
||||||
|
else
|
||||||
|
[self moveRight:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveRight:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _selectTextField:[_currentTextField nextTextField]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertBacktab:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_currentTextField == _firstTextField)
|
||||||
|
[[self window] selectPreviousKeyView:self];
|
||||||
|
else
|
||||||
|
[self moveLeft:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveLeft:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _selectTextField:[_currentTextField previousTextField]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveDown:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_currentTextField _invalidTimer];
|
||||||
|
[_stepper setDoubleValue:[_currentTextField intValue]];
|
||||||
|
[_stepper performClickDown:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveUp:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_currentTextField _invalidTimer];
|
||||||
|
[_stepper setDoubleValue:[_currentTextField intValue]];
|
||||||
|
[_stepper performClickUp:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertNewline:(id)sender
|
||||||
|
{
|
||||||
|
if (!_currentTextField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_currentTextField _endEditing];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! KeyDown event
|
||||||
|
We just care care about the event A/P and every numbers
|
||||||
|
*/
|
||||||
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self interpretKeyEvents:[anEvent]];
|
||||||
|
|
||||||
|
if ([_datePicker _isAmericanFormat] && [_currentTextField dateType] == CPAMPMDateType && ([anEvent keyCode] == CPAKeyCode || [anEvent keyCode] == CPPKeyCode || [anEvent keyCode] == CPMajAKeyCode || [anEvent keyCode] == CPMajPKeyCode))
|
||||||
|
{
|
||||||
|
if ([anEvent keyCode] == CPAKeyCode || [anEvent keyCode] == CPMajAKeyCode)
|
||||||
|
[_currentTextField setStringValue:@"AM"];
|
||||||
|
else
|
||||||
|
[_currentTextField setStringValue:@"PM"];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPDatePickerElementTextFieldAMPMChangedNotification object:_currentTextField userInfo:nil];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_currentTextField setValueForKeyEvent:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Layout methods
|
||||||
|
|
||||||
|
/*! Layout the subviews
|
||||||
|
*/
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[_datePicker _sizeToControlSize];
|
||||||
|
[self setFrameSize:[_datePicker frameSize]];
|
||||||
|
|
||||||
|
[super layoutSubviews];
|
||||||
|
|
||||||
|
var frameSize,
|
||||||
|
bezelInset = [_datePicker valueForThemeAttribute:@"bezel-inset" inState:[_datePicker themeState]];
|
||||||
|
|
||||||
|
// Check the mode to display or not the stepper
|
||||||
|
if ([_datePicker datePickerStyle] == CPTextFieldAndStepperDatePickerStyle)
|
||||||
|
{
|
||||||
|
[_stepper setHidden:NO];
|
||||||
|
[_stepper setControlSize:[_datePicker controlSize]];
|
||||||
|
|
||||||
|
frameSize = CGSizeMake(CGRectGetWidth([_datePicker frame]) - CGRectGetWidth([_stepper frame]) - [_datePicker currentValueForThemeAttribute:@"stepper-margin"], CGRectGetHeight([_datePicker frame]));
|
||||||
|
|
||||||
|
frameSize.width -= bezelInset.left;
|
||||||
|
frameSize.height -= bezelInset.top + bezelInset.bottom;
|
||||||
|
|
||||||
|
[_datePickerElementView setFrameSize:frameSize];
|
||||||
|
[_datePickerElementView setFrameOrigin:CGPointMake(bezelInset.left, bezelInset.top)];
|
||||||
|
|
||||||
|
[_stepper setFrameOrigin:CGPointMake(CGRectGetMaxX([_datePickerElementView frame]) + [_datePicker currentValueForThemeAttribute:@"stepper-margin"], bezelInset.top + CGRectGetHeight([_datePickerElementView frame]) / 2 - CGRectGetHeight([_stepper frame]) / 2)];
|
||||||
|
}
|
||||||
|
else if ([_datePicker datePickerStyle] == CPTextFieldDatePickerStyle)
|
||||||
|
{
|
||||||
|
frameSize = CGSizeMake(CGRectGetWidth([_datePicker frame]), CGRectGetHeight([_datePicker frame]));
|
||||||
|
|
||||||
|
frameSize.width -= bezelInset.left + bezelInset.right;
|
||||||
|
frameSize.height -= bezelInset.top + bezelInset.bottom;
|
||||||
|
|
||||||
|
[_datePickerElementView setFrameSize:frameSize];
|
||||||
|
[_datePickerElementView setFrameOrigin:CGPointMake(bezelInset.left, bezelInset.top)];
|
||||||
|
[_stepper setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: should be done in a self setControlSize
|
||||||
|
[_datePickerElementView setControlSize:[_datePicker controlSize]];
|
||||||
|
|
||||||
|
[_datePickerElementView setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Override observers
|
||||||
|
|
||||||
|
- (void)_removeObservers
|
||||||
|
{
|
||||||
|
if (!_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _removeObservers];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPDatePickerElementTextFieldBecomeFirstResponder object:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_addObservers
|
||||||
|
{
|
||||||
|
if (_isObserving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[super _addObservers];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_datePickerElementTextFieldBecomeFirstResponder:) name:CPDatePickerElementTextFieldBecomeFirstResponder object:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* CPDictionaryController.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Adapted from Cocotron, by Johannes Fortmann
|
||||||
|
*
|
||||||
|
* Created by Blair Duncan
|
||||||
|
* Copyright 2013, SGL Studio, BBDO Toronto 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 "CPArrayController.j"
|
||||||
|
|
||||||
|
@implementation CPDictionaryController : CPArrayController
|
||||||
|
{
|
||||||
|
CPDictionary _contentDictionary;
|
||||||
|
|
||||||
|
CPArray _includedKeys @accessors(property=includedKeys);
|
||||||
|
CPArray _excludedKeys @accessors(property=excludedKeys);
|
||||||
|
|
||||||
|
CPString _initialKey @accessors(property=initialKey);
|
||||||
|
id _initialValue @accessors(property=initialValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_initialKey = @"key";
|
||||||
|
_initialValue = @"value";
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)newObject
|
||||||
|
{
|
||||||
|
var keys = [_contentDictionary allKeys],
|
||||||
|
newKey = _initialKey,
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
if ([keys containsObject:newKey])
|
||||||
|
while ([keys containsObject:newKey])
|
||||||
|
newKey = [CPString stringWithFormat:@"%@%i", _initialKey, ++count];
|
||||||
|
|
||||||
|
return [self _newObjectWithKey:newKey value:_initialValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_newObjectWithKey:(CPString)aKey value:(id)aValue
|
||||||
|
{
|
||||||
|
var aNewObject = [_CPDictionaryControllerKeyValuePair new];
|
||||||
|
|
||||||
|
aNewObject._dictionary = _contentDictionary;
|
||||||
|
aNewObject._controller = self;
|
||||||
|
aNewObject._key = aKey;
|
||||||
|
|
||||||
|
if (aValue != nil)
|
||||||
|
[aNewObject setValue:aValue];
|
||||||
|
|
||||||
|
return aNewObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDictionary)contentDictionary
|
||||||
|
{
|
||||||
|
return _contentDictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContentDictionary:(CPDictionary)aDictionary
|
||||||
|
{
|
||||||
|
if (aDictionary == _contentDictionary)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([aDictionary isKindOfClass:[CPDictionary class]])
|
||||||
|
_contentDictionary = aDictionary;
|
||||||
|
else
|
||||||
|
_contentDictionary = nil;
|
||||||
|
|
||||||
|
var array = [CPArray array],
|
||||||
|
allKeys = [_contentDictionary allKeys];
|
||||||
|
|
||||||
|
[allKeys addObjectsFromArray:_includedKeys];
|
||||||
|
|
||||||
|
var iter = [[CPSet setWithArray:allKeys] objectEnumerator],
|
||||||
|
obj;
|
||||||
|
|
||||||
|
while ((obj = [iter nextObject]) != nil)
|
||||||
|
if (![_excludedKeys containsObject:obj])
|
||||||
|
[array addObject:[self _newObjectWithKey:obj value:nil]];
|
||||||
|
|
||||||
|
[super setContent:array];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
var CPIncludedKeys = @"CPIncludedKeys",
|
||||||
|
CPExcludedKeys = @"CPExcludedKeys";
|
||||||
|
|
||||||
|
@implementation CPDictionaryController (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_includedKeys = [aCoder decodeObjectForKey:CPIncludedKeys];
|
||||||
|
_excludedKeys = [aCoder decodeObjectForKey:CPExcludedKeys];
|
||||||
|
_initialKey = @"key";
|
||||||
|
_initialValue = @"value";
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_includedKeys forKey:CPIncludedKeys];
|
||||||
|
[aCoder encodeObject:_excludedKeys forKey:CPExcludedKeys];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPDictionaryControllerKeyValuePair : CPObject
|
||||||
|
{
|
||||||
|
CPString _key @accessors(property=key);
|
||||||
|
CPDictionary _dictionary @accessors(property=dictionary);
|
||||||
|
CPDictionaryController _controller @accessors(property=controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)value
|
||||||
|
{
|
||||||
|
return [_dictionary objectForKey:_key];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue
|
||||||
|
{
|
||||||
|
[_dictionary setObject:aValue forKey:_key];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isExplicitlyIncluded
|
||||||
|
{
|
||||||
|
return [[_controller _includedKeys] containsObject:_key];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
+41
-42
@@ -23,12 +23,16 @@
|
|||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
|
|
||||||
@import "CPApplication.j"
|
@import "CPAlert.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPSavePanel.j"
|
@import "CPSavePanel.j"
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
|
|
||||||
|
@class CPDocumentController
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@@ -125,7 +129,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_windowControllers = [];
|
_windowControllers = [];
|
||||||
_viewControllersForWindowControllers = [CPDictionary dictionary];
|
_viewControllersForWindowControllers = @{};
|
||||||
|
|
||||||
_hasUndoManager = YES;
|
_hasUndoManager = YES;
|
||||||
_changeCount = 0;
|
_changeCount = 0;
|
||||||
@@ -142,7 +146,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
@param anError not used
|
@param anError not used
|
||||||
@return the initialized document
|
@return the initialized document
|
||||||
*/
|
*/
|
||||||
- (id)initWithType:(CPString)aType error:({CPError})anError
|
- (id)initWithType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||||
{
|
{
|
||||||
self = [self init];
|
self = [self init];
|
||||||
|
|
||||||
@@ -211,7 +215,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
@throws CPUnsupportedMethodException if this method hasn't been overridden by the subclass
|
@throws CPUnsupportedMethodException if this method hasn't been overridden by the subclass
|
||||||
@return the document data
|
@return the document data
|
||||||
*/
|
*/
|
||||||
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
|
- (CPData)dataOfType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||||
{
|
{
|
||||||
[CPException raise:CPUnsupportedMethodException
|
[CPException raise:CPUnsupportedMethodException
|
||||||
reason:"dataOfType:error: must be overridden by the document subclass."];
|
reason:"dataOfType:error: must be overridden by the document subclass."];
|
||||||
@@ -240,11 +244,6 @@ var CPDocumentUntitledCount = 0;
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPWindowController)firstEligibleExistingWindowController
|
|
||||||
{
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating and managing window controllers
|
// Creating and managing window controllers
|
||||||
/*!
|
/*!
|
||||||
Creates the window controller for this document.
|
Creates the window controller for this document.
|
||||||
@@ -257,6 +256,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
- (void)makeViewAndWindowControllers
|
- (void)makeViewAndWindowControllers
|
||||||
{
|
{
|
||||||
var viewCibName = [self viewCibName],
|
var viewCibName = [self viewCibName],
|
||||||
|
windowCibName = [self windowCibName],
|
||||||
viewController = nil,
|
viewController = nil,
|
||||||
windowController = nil;
|
windowController = nil;
|
||||||
|
|
||||||
@@ -264,31 +264,21 @@ var CPDocumentUntitledCount = 0;
|
|||||||
if ([viewCibName length])
|
if ([viewCibName length])
|
||||||
viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
|
viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
|
||||||
|
|
||||||
// If we have a view controller, check if we have a free window for it.
|
// From a cib if we have one.
|
||||||
if (viewController)
|
if ([windowCibName length])
|
||||||
windowController = [self firstEligibleExistingWindowController];
|
windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
|
||||||
|
|
||||||
// If not, create one.
|
// If not you get a standard window capable of displaying multiple documents and view
|
||||||
if (!windowController)
|
else if (viewController)
|
||||||
{
|
{
|
||||||
var windowCibName = [self windowCibName];
|
var view = [viewController view],
|
||||||
|
viewFrame = [view frame];
|
||||||
|
|
||||||
// From a cib if we have one.
|
viewFrame.origin = CGPointMake(50, 50);
|
||||||
if ([windowCibName length])
|
|
||||||
windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
|
|
||||||
|
|
||||||
// If not you get a standard window capable of displaying multiple documents and view
|
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||||
else if (viewController)
|
|
||||||
{
|
|
||||||
var view = [viewController view],
|
|
||||||
viewFrame = [view frame];
|
|
||||||
|
|
||||||
viewFrame.origin = CGPointMake(50, 50);
|
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
||||||
|
|
||||||
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
|
||||||
|
|
||||||
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowController && viewController)
|
if (windowController && viewController)
|
||||||
@@ -525,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
|
||||||
{
|
{
|
||||||
@@ -550,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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,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
|
||||||
{
|
{
|
||||||
@@ -579,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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,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
|
||||||
{
|
{
|
||||||
@@ -607,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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -868,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];
|
||||||
|
|
||||||
@@ -911,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
|
|
||||||
@import "CPDocument.j"
|
@import "CPDocument.j"
|
||||||
@import "CPOpenPanel.j"
|
@import "CPOpenPanel.j"
|
||||||
|
@import "CPMenuItem.j"
|
||||||
|
@import "CPWindowController.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
|
||||||
var CPSharedDocumentController = nil;
|
var CPSharedDocumentController = nil;
|
||||||
@@ -102,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];
|
||||||
|
|
||||||
@@ -124,7 +128,7 @@ var CPSharedDocumentController = nil;
|
|||||||
@param anError not used
|
@param anError not used
|
||||||
@return the created document
|
@return the created document
|
||||||
*/
|
*/
|
||||||
- (CPDocument)makeUntitledDocumentOfType:(CPString)aType error:({CPError})anError
|
- (CPDocument)makeUntitledDocumentOfType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||||
{
|
{
|
||||||
return [[[self documentClassForType:aType] alloc] initWithType:aType error:anError];
|
return [[[self documentClassForType:aType] alloc] initWithType:aType error:anError];
|
||||||
}
|
}
|
||||||
@@ -144,7 +148,7 @@ var CPSharedDocumentController = nil;
|
|||||||
{
|
{
|
||||||
var type = [self typeForContentsOfURL:anAbsoluteURL error:anError];
|
var type = [self typeForContentsOfURL:anAbsoluteURL error:anError];
|
||||||
|
|
||||||
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:[CPDictionary dictionaryWithObject:shouldDisplay forKey:@"shouldDisplay"]];
|
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:@{ @"shouldDisplay": shouldDisplay }];
|
||||||
|
|
||||||
[self addDocument:result];
|
[self addDocument:result];
|
||||||
|
|
||||||
@@ -249,6 +253,14 @@ var CPSharedDocumentController = nil;
|
|||||||
return _documents;
|
return _documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the CPDocument object associated with the main window.
|
||||||
|
*/
|
||||||
|
- (CPDocument)currentDocument
|
||||||
|
{
|
||||||
|
return [[[CPApp mainWindow] windowController] document];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Adds \c aDocument under the control of the receiver.
|
Adds \c aDocument under the control of the receiver.
|
||||||
@param aDocument the document to add
|
@param aDocument the document to add
|
||||||
@@ -267,6 +279,33 @@ var CPSharedDocumentController = nil;
|
|||||||
[_documents removeObjectIdenticalTo:aDocument];
|
[_documents removeObjectIdenticalTo:aDocument];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the document object whose window controller
|
||||||
|
owns a specified window.
|
||||||
|
*/
|
||||||
|
- (CPDocument)documentForWindow:(CPWindow)aWindow
|
||||||
|
{
|
||||||
|
return [[aWindow windowController] document];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a Boolean value that indicates whether the receiver
|
||||||
|
has any documents with unsaved changes.
|
||||||
|
*/
|
||||||
|
- (BOOL)hasEditedDocuments
|
||||||
|
{
|
||||||
|
var iter = [_documents objectEnumerator],
|
||||||
|
obj;
|
||||||
|
|
||||||
|
while ((obj = [iter nextObject]) != nil)
|
||||||
|
{
|
||||||
|
if ([obj isDocumentEdited])
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (CPString)defaultType
|
- (CPString)defaultType
|
||||||
{
|
{
|
||||||
return [_documentTypes[0] objectForKey:@"CPBundleTypeName"];
|
return [_documentTypes[0] objectForKey:@"CPBundleTypeName"];
|
||||||
@@ -339,10 +378,10 @@ var CPSharedDocumentController = nil;
|
|||||||
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
|
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
|
||||||
{
|
{
|
||||||
var context = {
|
var context = {
|
||||||
delegate: aDelegate,
|
delegate: aDelegate,
|
||||||
selector: didCloseSelector,
|
selector: didCloseSelector,
|
||||||
context: info
|
context: info
|
||||||
};
|
};
|
||||||
|
|
||||||
[self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
|
[self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
|
||||||
}
|
}
|
||||||
@@ -363,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
|
||||||
|
|||||||
+37
-64
@@ -20,22 +20,17 @@
|
|||||||
* 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 "CPApplication.j"
|
@import "CPDragServer_Constants.j"
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPPasteboard.j"
|
@import "CPPasteboard.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
@import "CPWindow.j"
|
@import "CPWindow_Constants.j"
|
||||||
|
|
||||||
|
@class CPWindow // This file is imported by CPWindow.j
|
||||||
|
@class _CPDOMDataTransferPasteboard
|
||||||
|
|
||||||
CPDragOperationNone = 0;
|
@global CPApp
|
||||||
CPDragOperationCopy = 1 << 1;
|
|
||||||
CPDragOperationLink = 1 << 1;
|
|
||||||
CPDragOperationGeneric = 1 << 2;
|
|
||||||
CPDragOperationPrivate = 1 << 3;
|
|
||||||
CPDragOperationMove = 1 << 4;
|
|
||||||
CPDragOperationDelete = 1 << 5;
|
|
||||||
CPDragOperationEvery = -1;
|
|
||||||
|
|
||||||
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
||||||
|
|
||||||
@@ -72,7 +67,7 @@ var CPDragServerSource = nil,
|
|||||||
- (unsigned)draggingSourceOperationMask
|
- (unsigned)draggingSourceOperationMask
|
||||||
*/
|
*/
|
||||||
|
|
||||||
- (CPPoint)draggingLocation
|
- (CGPoint)draggingLocation
|
||||||
{
|
{
|
||||||
return [[CPDragServer sharedDragServer] draggingLocation];
|
return [[CPDragServer sharedDragServer] draggingLocation];
|
||||||
}
|
}
|
||||||
@@ -168,7 +163,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_draggedWindow = [[CPWindow alloc] initWithContentRect:_CGRectMakeZero() styleMask:CPBorderlessWindowMask];
|
_draggedWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessWindowMask];
|
||||||
|
|
||||||
[_draggedWindow setLevel:CPDraggingWindowLevel];
|
[_draggedWindow setLevel:CPDraggingWindowLevel];
|
||||||
}
|
}
|
||||||
@@ -206,7 +201,12 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
- (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
|
- (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
|
||||||
{
|
{
|
||||||
if (![CPPlatform supportsDragAndDrop])
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
[_draggedWindow setFrameOrigin:_CGPointMake(aGlobalLocation.x - _draggingOffset.width, aGlobalLocation.y - _draggingOffset.height)];
|
{
|
||||||
|
var frame = [_draggedWindow frame];
|
||||||
|
frame.origin.x = aGlobalLocation.x - _draggingOffset.width;
|
||||||
|
frame.origin.y = aGlobalLocation.y - _draggingOffset.height;
|
||||||
|
[_draggedWindow _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
|
||||||
|
}
|
||||||
|
|
||||||
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_movedTo_)
|
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_movedTo_)
|
||||||
[_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
|
[_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
|
||||||
@@ -253,7 +253,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
|
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
|
||||||
target:self
|
target:self
|
||||||
selector:@selector(_sendPeriodicDraggingUpdate:)
|
selector:@selector(_sendPeriodicDraggingUpdate:)
|
||||||
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
|
userInfo:@{ "platformWindow":aPlatformWindow, "location":aLocation }
|
||||||
repeats:NO];
|
repeats:NO];
|
||||||
|
|
||||||
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
|
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
|
||||||
@@ -270,10 +270,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
{
|
{
|
||||||
if ([scrollView hasVerticalScroller])
|
if ([scrollView hasVerticalScroller])
|
||||||
{
|
{
|
||||||
if (eventLocation.y < _CGRectGetMinY(insetBounds))
|
if (eventLocation.y < CGRectGetMinY(insetBounds))
|
||||||
deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y;
|
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
|
||||||
else if (eventLocation.y > _CGRectGetMaxY(insetBounds))
|
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
|
||||||
deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y;
|
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
|
||||||
if (deltaY < -insetBounds.size.height)
|
if (deltaY < -insetBounds.size.height)
|
||||||
deltaY = -insetBounds.size.height;
|
deltaY = -insetBounds.size.height;
|
||||||
if (deltaY > insetBounds.size.height)
|
if (deltaY > insetBounds.size.height)
|
||||||
@@ -282,17 +282,17 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
if ([scrollView hasHorizontalScroller])
|
if ([scrollView hasHorizontalScroller])
|
||||||
{
|
{
|
||||||
if (eventLocation.x < _CGRectGetMinX(insetBounds))
|
if (eventLocation.x < CGRectGetMinX(insetBounds))
|
||||||
deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x;
|
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
|
||||||
else if (eventLocation.x > _CGRectGetMaxX(insetBounds))
|
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
|
||||||
deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x;
|
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
|
||||||
if (deltaX < -insetBounds.size.width)
|
if (deltaX < -insetBounds.size.width)
|
||||||
deltaX = -insetBounds.size.width;
|
deltaX = -insetBounds.size.width;
|
||||||
if (deltaX > insetBounds.size.width)
|
if (deltaX > insetBounds.size.width)
|
||||||
deltaX = insetBounds.size.width;
|
deltaX = insetBounds.size.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
var scrollPoint = _CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
|
var scrollPoint = CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
|
||||||
|
|
||||||
[contentView scrollToPoint:scrollPoint];
|
[contentView scrollToPoint:scrollPoint];
|
||||||
[[scrollView _headerView] scrollPoint:scrollPoint];
|
[[scrollView _headerView] scrollPoint:scrollPoint];
|
||||||
@@ -370,22 +370,26 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
if (mouseDownWindow)
|
if (mouseDownWindow)
|
||||||
mouseDownEventLocation = [mouseDownWindow convertBaseToGlobal:mouseDownEventLocation];
|
mouseDownEventLocation = [mouseDownWindow convertBaseToGlobal:mouseDownEventLocation];
|
||||||
|
|
||||||
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
_draggingOffset = CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_draggingOffset = _CGSizeMakeZero();
|
_draggingOffset = CGSizeMakeZero();
|
||||||
|
|
||||||
if ([CPPlatform isBrowser])
|
if ([CPPlatform isBrowser])
|
||||||
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
||||||
|
|
||||||
[aView setFrameOrigin:_CGPointMakeZero()];
|
[aView setFrameOrigin:CGPointMakeZero()];
|
||||||
|
|
||||||
var mouseLocation = [CPEvent mouseLocation];
|
var mouseLocation = [CPEvent mouseLocation],
|
||||||
|
viewSize = [aView frameSize],
|
||||||
|
startDragLocationX = mouseLocation.x - _draggingOffset.width,
|
||||||
|
startDragLocationY = mouseLocation.y - _draggingOffset.height,
|
||||||
|
draggedWindowFrame = CGRectMake(startDragLocationX, startDragLocationY, viewSize.width, viewSize.height);
|
||||||
|
|
||||||
// Place it where the mouse pointer is.
|
// Place it where the mouse pointer is.
|
||||||
_startDragLocation = _CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height);
|
_startDragLocation = CGPointMake(startDragLocationX, startDragLocationY);
|
||||||
[_draggedWindow setFrameOrigin:_startDragLocation];
|
|
||||||
[_draggedWindow setFrameSize:[aView frame].size];
|
[_draggedWindow _setFrame:draggedWindowFrame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
|
||||||
|
|
||||||
[[_draggedWindow contentView] addSubview:aView];
|
[[_draggedWindow contentView] addSubview:aView];
|
||||||
|
|
||||||
@@ -434,7 +438,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
var imageSize = [anImage size];
|
var imageSize = [anImage size];
|
||||||
|
|
||||||
if (!_imageView)
|
if (!_imageView)
|
||||||
_imageView = [[CPImageView alloc] initWithFrame:_CGRectMake(0.0, 0.0, imageSize.width, imageSize.height)];
|
_imageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, imageSize.width, imageSize.height)];
|
||||||
|
|
||||||
[_imageView setImage:anImage];
|
[_imageView setImage:anImage];
|
||||||
|
|
||||||
@@ -461,6 +465,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
else if (type === CPKeyDown)
|
else if (type === CPKeyDown)
|
||||||
{
|
{
|
||||||
var characters = [anEvent characters];
|
var characters = [anEvent characters];
|
||||||
|
|
||||||
if (characters === CPEscapeFunctionKey)
|
if (characters === CPEscapeFunctionKey)
|
||||||
{
|
{
|
||||||
_dragOperation = CPDragOperationNone;
|
_dragOperation = CPDragOperationNone;
|
||||||
@@ -477,39 +482,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
// If we're not a mouse up, then we're going to want to grab the next event.
|
||||||
[CPApp setTarget:self selector:@selector(trackDragging:)
|
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
|
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
|
||||||
untilDate:nil inMode:0 dequeue:NO];
|
untilDate:nil inMode:0 dequeue:YES];
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation CPWindow (CPDraggingAdditions)
|
|
||||||
|
|
||||||
/* @ignore */
|
|
||||||
- (id)_dragHitTest:(CGPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
|
|
||||||
{
|
|
||||||
// If none of our views or ourselves has registered for drag events...
|
|
||||||
if (!_inclusiveRegisteredDraggedTypes)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
// We don't need to do this because the only place this gets called
|
|
||||||
// -_dragHitTest: in CPPlatformWindow does this already. Perhaps to
|
|
||||||
// be safe?
|
|
||||||
// if (![self containsPoint:aPoint])
|
|
||||||
// return nil;
|
|
||||||
|
|
||||||
var adjustedPoint = [self convertPlatformWindowToBase:aPoint],
|
|
||||||
hitView = [_windowView hitTest:adjustedPoint];
|
|
||||||
|
|
||||||
while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
|
|
||||||
hitView = [hitView superview];
|
|
||||||
|
|
||||||
if (hitView)
|
|
||||||
return hitView;
|
|
||||||
|
|
||||||
if ([aPasteboard availableTypeFromArray:[self registeredDraggedTypes]])
|
|
||||||
return self;
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* CPRange.h
|
* CPDragServer_Constants.j
|
||||||
* Foundation
|
* AppKit
|
||||||
*
|
*
|
||||||
* Created by Alexander Ljungberg.
|
* Created by Francisco Tolmasky.
|
||||||
* Copyright 2012, SlevenBits Ltd.
|
* Copyright 2008, 280 North, Inc.
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -20,8 +20,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _CPMaxRange(aRange) ((aRange).location + (aRange).length)
|
@typedef CPDragOperation
|
||||||
#define _CPMakeRange(aLocation, aLength) { location:(aLocation), length:aLength }
|
CPDragOperationNone = 0;
|
||||||
#define _CPMakeRangeCopy(aRange) { location:(aRange).location, length:(aRange).length }
|
CPDragOperationCopy = 1 << 1;
|
||||||
#define _CPEmptyRange(aRange) ((aRange).length === 0)
|
CPDragOperationLink = 1 << 1;
|
||||||
#define _CPLocationInRange(aLocation, aRange) (((aLocation) >= (aRange).location) && ((aLocation) < _CPMaxRange(aRange)))
|
CPDragOperationGeneric = 1 << 2;
|
||||||
|
CPDragOperationPrivate = 1 << 3;
|
||||||
|
CPDragOperationMove = 1 << 4;
|
||||||
|
CPDragOperationDelete = 1 << 5;
|
||||||
|
CPDragOperationEvery = -1;
|
||||||
+145
-163
@@ -20,162 +20,28 @@
|
|||||||
* 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 "CPEvent_Constants.j"
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import "CPText.j"
|
@import <Foundation/CPObjJRuntime.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
@import "CPCompatibility.j"
|
||||||
|
@import "CGGeometry.j"
|
||||||
|
@import "CPTrackingArea.j"
|
||||||
|
|
||||||
CPLeftMouseDown = 1;
|
@class CPTextField
|
||||||
CPLeftMouseUp = 2;
|
@class CPWindow
|
||||||
CPRightMouseDown = 3;
|
@class CPGraphicsContext
|
||||||
CPRightMouseUp = 4;
|
|
||||||
CPMouseMoved = 5;
|
|
||||||
CPLeftMouseDragged = 6;
|
|
||||||
CPRightMouseDragged = 7;
|
|
||||||
CPMouseEntered = 8;
|
|
||||||
CPMouseExited = 9;
|
|
||||||
CPKeyDown = 10;
|
|
||||||
CPKeyUp = 11;
|
|
||||||
CPFlagsChanged = 12;
|
|
||||||
CPAppKitDefined = 13;
|
|
||||||
CPSystemDefined = 14;
|
|
||||||
CPApplicationDefined = 15;
|
|
||||||
CPPeriodic = 16;
|
|
||||||
CPCursorUpdate = 17;
|
|
||||||
CPScrollWheel = 22;
|
|
||||||
CPOtherMouseDown = 25;
|
|
||||||
CPOtherMouseUp = 26;
|
|
||||||
CPOtherMouseDragged = 27;
|
|
||||||
|
|
||||||
// iPhone Event Types
|
@global CPApp
|
||||||
CPTouchStart = 28;
|
@global CPNewlineCharacter
|
||||||
CPTouchMove = 29;
|
@global CPCarriageReturnCharacter
|
||||||
CPTouchEnd = 30;
|
@global CPEnterCharacter
|
||||||
CPTouchCancel = 31;
|
|
||||||
|
|
||||||
CPAlphaShiftKeyMask = 1 << 16;
|
@typedef DOMEvent
|
||||||
CPShiftKeyMask = 1 << 17;
|
@typedef CPEventType
|
||||||
CPControlKeyMask = 1 << 18;
|
|
||||||
CPAlternateKeyMask = 1 << 19;
|
|
||||||
CPCommandKeyMask = 1 << 20;
|
|
||||||
CPNumericPadKeyMask = 1 << 21;
|
|
||||||
CPHelpKeyMask = 1 << 22;
|
|
||||||
CPFunctionKeyMask = 1 << 23;
|
|
||||||
CPDeviceIndependentModifierFlagsMask = 0xffff0000;
|
|
||||||
|
|
||||||
CPLeftMouseDownMask = 1 << CPLeftMouseDown;
|
|
||||||
CPLeftMouseUpMask = 1 << CPLeftMouseUp;
|
|
||||||
CPRightMouseDownMask = 1 << CPRightMouseDown;
|
|
||||||
CPRightMouseUpMask = 1 << CPRightMouseUp;
|
|
||||||
CPOtherMouseDownMask = 1 << CPOtherMouseDown;
|
|
||||||
CPOtherMouseUpMask = 1 << CPOtherMouseUp;
|
|
||||||
CPMouseMovedMask = 1 << CPMouseMoved;
|
|
||||||
CPLeftMouseDraggedMask = 1 << CPLeftMouseDragged;
|
|
||||||
CPRightMouseDraggedMask = 1 << CPRightMouseDragged;
|
|
||||||
CPOtherMouseDragged = 1 << CPOtherMouseDragged;
|
|
||||||
CPMouseEnteredMask = 1 << CPMouseEntered;
|
|
||||||
CPMouseExitedMask = 1 << CPMouseExited;
|
|
||||||
CPCursorUpdateMask = 1 << CPCursorUpdate;
|
|
||||||
CPKeyDownMask = 1 << CPKeyDown;
|
|
||||||
CPKeyUpMask = 1 << CPKeyUp;
|
|
||||||
CPFlagsChangedMask = 1 << CPFlagsChanged;
|
|
||||||
CPAppKitDefinedMask = 1 << CPAppKitDefined;
|
|
||||||
CPSystemDefinedMask = 1 << CPSystemDefined;
|
|
||||||
CPApplicationDefinedMask = 1 << CPApplicationDefined;
|
|
||||||
CPPeriodicMask = 1 << CPPeriodic;
|
|
||||||
CPScrollWheelMask = 1 << CPScrollWheel;
|
|
||||||
CPAnyEventMask = 0xffffffff;
|
|
||||||
|
|
||||||
CPUpArrowFunctionKey = "\uF700";
|
|
||||||
CPDownArrowFunctionKey = "\uF701";
|
|
||||||
CPLeftArrowFunctionKey = "\uF702";
|
|
||||||
CPRightArrowFunctionKey = "\uF703";
|
|
||||||
CPF1FunctionKey = "\uF704";
|
|
||||||
CPF2FunctionKey = "\uF705";
|
|
||||||
CPF3FunctionKey = "\uF706";
|
|
||||||
CPF4FunctionKey = "\uF707";
|
|
||||||
CPF5FunctionKey = "\uF708";
|
|
||||||
CPF6FunctionKey = "\uF709";
|
|
||||||
CPF7FunctionKey = "\uF70A";
|
|
||||||
CPF8FunctionKey = "\uF70B";
|
|
||||||
CPF9FunctionKey = "\uF70C";
|
|
||||||
CPF10FunctionKey = "\uF70D";
|
|
||||||
CPF11FunctionKey = "\uF70E";
|
|
||||||
CPF12FunctionKey = "\uF70F";
|
|
||||||
CPF13FunctionKey = "\uF710";
|
|
||||||
CPF14FunctionKey = "\uF711";
|
|
||||||
CPF15FunctionKey = "\uF712";
|
|
||||||
CPF16FunctionKey = "\uF713";
|
|
||||||
CPF17FunctionKey = "\uF714";
|
|
||||||
CPF18FunctionKey = "\uF715";
|
|
||||||
CPF19FunctionKey = "\uF716";
|
|
||||||
CPF20FunctionKey = "\uF717";
|
|
||||||
CPF21FunctionKey = "\uF718";
|
|
||||||
CPF22FunctionKey = "\uF719";
|
|
||||||
CPF23FunctionKey = "\uF71A";
|
|
||||||
CPF24FunctionKey = "\uF71B";
|
|
||||||
CPF25FunctionKey = "\uF71C";
|
|
||||||
CPF26FunctionKey = "\uF71D";
|
|
||||||
CPF27FunctionKey = "\uF71E";
|
|
||||||
CPF28FunctionKey = "\uF71F";
|
|
||||||
CPF29FunctionKey = "\uF720";
|
|
||||||
CPF30FunctionKey = "\uF721";
|
|
||||||
CPF31FunctionKey = "\uF722";
|
|
||||||
CPF32FunctionKey = "\uF723";
|
|
||||||
CPF33FunctionKey = "\uF724";
|
|
||||||
CPF34FunctionKey = "\uF725";
|
|
||||||
CPF35FunctionKey = "\uF726";
|
|
||||||
CPInsertFunctionKey = "\uF727";
|
|
||||||
CPDeleteFunctionKey = "\uF728";
|
|
||||||
CPHomeFunctionKey = "\uF729";
|
|
||||||
CPBeginFunctionKey = "\uF72A";
|
|
||||||
CPEndFunctionKey = "\uF72B";
|
|
||||||
CPPageUpFunctionKey = "\uF72C";
|
|
||||||
CPPageDownFunctionKey = "\uF72D";
|
|
||||||
CPPrintScreenFunctionKey = "\uF72E";
|
|
||||||
CPScrollLockFunctionKey = "\uF72F";
|
|
||||||
CPPauseFunctionKey = "\uF730";
|
|
||||||
CPSysReqFunctionKey = "\uF731";
|
|
||||||
CPBreakFunctionKey = "\uF732";
|
|
||||||
CPResetFunctionKey = "\uF733";
|
|
||||||
CPStopFunctionKey = "\uF734";
|
|
||||||
CPMenuFunctionKey = "\uF735";
|
|
||||||
CPUserFunctionKey = "\uF736";
|
|
||||||
CPSystemFunctionKey = "\uF737";
|
|
||||||
CPPrintFunctionKey = "\uF738";
|
|
||||||
CPClearLineFunctionKey = "\uF739";
|
|
||||||
CPClearDisplayFunctionKey = "\uF73A";
|
|
||||||
CPInsertLineFunctionKey = "\uF73B";
|
|
||||||
CPDeleteLineFunctionKey = "\uF73C";
|
|
||||||
CPInsertCharFunctionKey = "\uF73D";
|
|
||||||
CPDeleteCharFunctionKey = "\uF73E";
|
|
||||||
CPPrevFunctionKey = "\uF73F";
|
|
||||||
CPNextFunctionKey = "\uF740";
|
|
||||||
CPSelectFunctionKey = "\uF741";
|
|
||||||
CPExecuteFunctionKey = "\uF742";
|
|
||||||
CPUndoFunctionKey = "\uF743";
|
|
||||||
CPRedoFunctionKey = "\uF744";
|
|
||||||
CPFindFunctionKey = "\uF745";
|
|
||||||
CPHelpFunctionKey = "\uF746";
|
|
||||||
CPModeSwitchFunctionKey = "\uF747";
|
|
||||||
CPEscapeFunctionKey = "\u001B";
|
|
||||||
CPSpaceFunctionKey = "\u0020";
|
|
||||||
|
|
||||||
|
|
||||||
CPDOMEventDoubleClick = "dblclick";
|
|
||||||
CPDOMEventMouseDown = "mousedown";
|
|
||||||
CPDOMEventMouseUp = "mouseup";
|
|
||||||
CPDOMEventMouseMoved = "mousemove";
|
|
||||||
CPDOMEventMouseDragged = "mousedrag";
|
|
||||||
CPDOMEventKeyUp = "keyup";
|
|
||||||
CPDOMEventKeyDown = "keydown";
|
|
||||||
CPDOMEventKeyPress = "keypress";
|
|
||||||
CPDOMEventCopy = "copy";
|
|
||||||
CPDOMEventPaste = "paste";
|
|
||||||
CPDOMEventScrollWheel = "mousewheel";
|
|
||||||
CPDOMEventTouchStart = "touchstart";
|
|
||||||
CPDOMEventTouchMove = "touchmove";
|
|
||||||
CPDOMEventTouchEnd = "touchend";
|
|
||||||
CPDOMEventTouchCancel = "touchcancel";
|
|
||||||
|
|
||||||
var _CPEventPeriodicEventPeriod = 0,
|
var _CPEventPeriodicEventPeriod = 0,
|
||||||
_CPEventPeriodicEventTimer = nil,
|
_CPEventPeriodicEventTimer = nil,
|
||||||
@@ -190,7 +56,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
@implementation CPEvent : CPObject
|
@implementation CPEvent : CPObject
|
||||||
{
|
{
|
||||||
CPEventType _type;
|
CPEventType _type;
|
||||||
CPPoint _location;
|
CGPoint _location;
|
||||||
unsigned _modifierFlags;
|
unsigned _modifierFlags;
|
||||||
CPTimeInterval _timestamp;
|
CPTimeInterval _timestamp;
|
||||||
CPGraphicsContext _context;
|
CPGraphicsContext _context;
|
||||||
@@ -200,16 +66,27 @@ 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;
|
||||||
int _data1;
|
int _data1;
|
||||||
int _data2;
|
int _data2;
|
||||||
|
short _subtype;
|
||||||
|
|
||||||
float _deltaX;
|
float _deltaX;
|
||||||
float _deltaY;
|
float _deltaY;
|
||||||
float _deltaZ;
|
float _deltaZ;
|
||||||
|
float _scrollingDeltaX;
|
||||||
|
float _scrollingDeltaY;
|
||||||
|
BOOL _hasPreciseScrollingDeltas;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
BOOL _suppressCappuccinoCut;
|
||||||
|
BOOL _suppressCappuccinoPaste;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CPTrackingArea _trackingArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -269,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.
|
||||||
|
|
||||||
@@ -300,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,13 +208,13 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||||
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
||||||
{
|
{
|
||||||
if (self = [self _initWithType:anEventType])
|
if (self = [self _initWithType:anEventType])
|
||||||
{
|
{
|
||||||
_location = CPPointCreateCopy(aPoint);
|
_location = CGPointCreateCopy(aPoint);
|
||||||
_modifierFlags = modifierFlags;
|
_modifierFlags = modifierFlags;
|
||||||
_timestamp = aTimestamp;
|
_timestamp = aTimestamp;
|
||||||
_context = aGraphicsContext;
|
_context = aGraphicsContext;
|
||||||
@@ -328,13 +228,35 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
- (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 */
|
||||||
|
- (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
|
||||||
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
|
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
|
||||||
{
|
{
|
||||||
if (self = [self _initWithType:anEventType])
|
if (self = [self _initWithType:anEventType])
|
||||||
{
|
{
|
||||||
_location = CPPointCreateCopy(aPoint);
|
_location = CGPointCreateCopy(aPoint);
|
||||||
_modifierFlags = modifierFlags;
|
_modifierFlags = modifierFlags;
|
||||||
_timestamp = aTimestamp;
|
_timestamp = aTimestamp;
|
||||||
_context = aGraphicsContext;
|
_context = aGraphicsContext;
|
||||||
@@ -355,13 +277,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
{
|
{
|
||||||
if (self = [self _initWithType:anEventType])
|
if (self = [self _initWithType:anEventType])
|
||||||
{
|
{
|
||||||
_location = CPPointCreateCopy(aPoint);
|
_location = CGPointCreateCopy(aPoint);
|
||||||
_modifierFlags = modifierFlags;
|
_modifierFlags = modifierFlags;
|
||||||
_timestamp = aTimestamp;
|
_timestamp = aTimestamp;
|
||||||
_context = aGraphicsContext;
|
_context = aGraphicsContext;
|
||||||
_subtype = aSubtype;
|
_subtype = aSubtype;
|
||||||
_data1 = aData1;
|
_data1 = aData1;
|
||||||
_data2 = aData2;
|
_data2 = aData2;
|
||||||
|
_windowNumber = aWindowNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -377,7 +300,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
- (CGPoint)locationInWindow
|
- (CGPoint)locationInWindow
|
||||||
{
|
{
|
||||||
return _CGPointMakeCopy(_location);
|
return CGPointMakeCopy(_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)globalLocation
|
- (CGPoint)globalLocation
|
||||||
@@ -415,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.
|
||||||
*/
|
*/
|
||||||
@@ -554,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)
|
||||||
@@ -615,6 +571,24 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return !firstResponderIsText;
|
return !firstResponderIsText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return YES if this event is a part of processing a browser controlled cut or paste event
|
||||||
|
where the browser will go ahead and do the work of cutting or pasting within the input
|
||||||
|
element after processing of this event. The implication is that it should not be done by
|
||||||
|
the CPTextField (or whatever else is controlling the input) since this would result in
|
||||||
|
nothing being cut (because the field already cut the text out), or a double paste
|
||||||
|
(because the field pasted as well as the browser).
|
||||||
|
*/
|
||||||
|
- (BOOL)_platformIsEffectingCutOrPaste
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
return _suppressCappuccinoCut || _suppressCappuccinoPaste;
|
||||||
|
#else
|
||||||
|
return NO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Generates periodic events every \c aPeriod seconds.
|
Generates periodic events every \c aPeriod seconds.
|
||||||
|
|
||||||
@@ -634,7 +608,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
+ (void)stopPeriodicEvents
|
+ (void)stopPeriodicEvents
|
||||||
{
|
{
|
||||||
if (_CPEventPeriodicEventTimer === nil)
|
if (_CPEventPeriodicEventTimer == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
window.clearTimeout(_CPEventPeriodicEventTimer);
|
window.clearTimeout(_CPEventPeriodicEventTimer);
|
||||||
@@ -649,7 +623,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
case CPKeyDown:
|
case CPKeyDown:
|
||||||
case CPKeyUp:
|
case CPKeyUp:
|
||||||
case CPFlagsChanged:
|
case CPFlagsChanged:
|
||||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ chars=\"%@\" unmodchars=\"%@\" repeat=%d keyCode=%d", _type, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _characters, _charactersIgnoringModifiers, _isARepeat, _keyCode];
|
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ chars=\"%@\" unmodchars=\"%@\" repeat=%d keyCode=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _characters, _charactersIgnoringModifiers, _isARepeat, _keyCode];
|
||||||
case CPLeftMouseDown:
|
case CPLeftMouseDown:
|
||||||
case CPLeftMouseUp:
|
case CPLeftMouseUp:
|
||||||
case CPRightMouseDown:
|
case CPRightMouseDown:
|
||||||
@@ -659,17 +633,25 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
case CPRightMouseDragged:
|
case CPRightMouseDragged:
|
||||||
case CPMouseEntered:
|
case CPMouseEntered:
|
||||||
case CPMouseExited:
|
case CPMouseExited:
|
||||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ evNum=%d click=%d buttonNumber=%d pressure=%f", _type, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _eventNumber, _clickCount, [self buttonNumber], _pressure];
|
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ evNum=%d click=%d buttonNumber=%d pressure=%f", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _eventNumber, _clickCount, [self buttonNumber], _pressure];
|
||||||
default:
|
default:
|
||||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ subtype=%d data1=%d data2=%d", _type, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _subtype, _data1, _data2];
|
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ subtype=%d data1=%d data2=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _subtype, _data1, _data2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (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()
|
||||||
{
|
{
|
||||||
[CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:_CGPointMakeZero() modifierFlags:0 timestamp:[CPEvent currentTimestamp] windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
|
[CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:CGPointMakeZero() modifierFlags:0 timestamp:[CPEvent currentTimestamp] windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
var CPEventClass = [CPEvent class];
|
var CPEventClass = [CPEvent class];
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* CPEvent_Constants.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
CPLeftMouseDown = 1;
|
||||||
|
CPLeftMouseUp = 2;
|
||||||
|
CPRightMouseDown = 3;
|
||||||
|
CPRightMouseUp = 4;
|
||||||
|
CPMouseMoved = 5;
|
||||||
|
CPLeftMouseDragged = 6;
|
||||||
|
CPRightMouseDragged = 7;
|
||||||
|
CPMouseEntered = 8;
|
||||||
|
CPMouseExited = 9;
|
||||||
|
CPKeyDown = 10;
|
||||||
|
CPKeyUp = 11;
|
||||||
|
CPFlagsChanged = 12;
|
||||||
|
CPAppKitDefined = 13;
|
||||||
|
CPSystemDefined = 14;
|
||||||
|
CPApplicationDefined = 15;
|
||||||
|
CPPeriodic = 16;
|
||||||
|
CPCursorUpdate = 17;
|
||||||
|
CPScrollWheel = 22;
|
||||||
|
CPOtherMouseDown = 25;
|
||||||
|
CPOtherMouseUp = 26;
|
||||||
|
CPOtherMouseDragged = 27;
|
||||||
|
|
||||||
|
// iPhone Event Types
|
||||||
|
CPTouchStart = 28;
|
||||||
|
CPTouchMove = 29;
|
||||||
|
CPTouchEnd = 30;
|
||||||
|
CPTouchCancel = 31;
|
||||||
|
|
||||||
|
CPAlphaShiftKeyMask = 1 << 16;
|
||||||
|
CPShiftKeyMask = 1 << 17;
|
||||||
|
CPControlKeyMask = 1 << 18;
|
||||||
|
CPAlternateKeyMask = 1 << 19;
|
||||||
|
CPCommandKeyMask = 1 << 20;
|
||||||
|
CPNumericPadKeyMask = 1 << 21;
|
||||||
|
CPHelpKeyMask = 1 << 22;
|
||||||
|
CPFunctionKeyMask = 1 << 23;
|
||||||
|
CPDeviceIndependentModifierFlagsMask = 0xffff0000;
|
||||||
|
|
||||||
|
CPLeftMouseDownMask = 1 << CPLeftMouseDown;
|
||||||
|
CPLeftMouseUpMask = 1 << CPLeftMouseUp;
|
||||||
|
CPRightMouseDownMask = 1 << CPRightMouseDown;
|
||||||
|
CPRightMouseUpMask = 1 << CPRightMouseUp;
|
||||||
|
CPOtherMouseDownMask = 1 << CPOtherMouseDown;
|
||||||
|
CPOtherMouseUpMask = 1 << CPOtherMouseUp;
|
||||||
|
CPMouseMovedMask = 1 << CPMouseMoved;
|
||||||
|
CPLeftMouseDraggedMask = 1 << CPLeftMouseDragged;
|
||||||
|
CPRightMouseDraggedMask = 1 << CPRightMouseDragged;
|
||||||
|
CPOtherMouseDragged = 1 << CPOtherMouseDragged;
|
||||||
|
CPMouseEnteredMask = 1 << CPMouseEntered;
|
||||||
|
CPMouseExitedMask = 1 << CPMouseExited;
|
||||||
|
CPCursorUpdateMask = 1 << CPCursorUpdate;
|
||||||
|
CPKeyDownMask = 1 << CPKeyDown;
|
||||||
|
CPKeyUpMask = 1 << CPKeyUp;
|
||||||
|
CPFlagsChangedMask = 1 << CPFlagsChanged;
|
||||||
|
CPAppKitDefinedMask = 1 << CPAppKitDefined;
|
||||||
|
CPSystemDefinedMask = 1 << CPSystemDefined;
|
||||||
|
CPApplicationDefinedMask = 1 << CPApplicationDefined;
|
||||||
|
CPPeriodicMask = 1 << CPPeriodic;
|
||||||
|
CPScrollWheelMask = 1 << CPScrollWheel;
|
||||||
|
CPAnyEventMask = 0xffffffff;
|
||||||
|
|
||||||
|
CPUpArrowFunctionKey = "\uF700";
|
||||||
|
CPDownArrowFunctionKey = "\uF701";
|
||||||
|
CPLeftArrowFunctionKey = "\uF702";
|
||||||
|
CPRightArrowFunctionKey = "\uF703";
|
||||||
|
CPF1FunctionKey = "\uF704";
|
||||||
|
CPF2FunctionKey = "\uF705";
|
||||||
|
CPF3FunctionKey = "\uF706";
|
||||||
|
CPF4FunctionKey = "\uF707";
|
||||||
|
CPF5FunctionKey = "\uF708";
|
||||||
|
CPF6FunctionKey = "\uF709";
|
||||||
|
CPF7FunctionKey = "\uF70A";
|
||||||
|
CPF8FunctionKey = "\uF70B";
|
||||||
|
CPF9FunctionKey = "\uF70C";
|
||||||
|
CPF10FunctionKey = "\uF70D";
|
||||||
|
CPF11FunctionKey = "\uF70E";
|
||||||
|
CPF12FunctionKey = "\uF70F";
|
||||||
|
CPF13FunctionKey = "\uF710";
|
||||||
|
CPF14FunctionKey = "\uF711";
|
||||||
|
CPF15FunctionKey = "\uF712";
|
||||||
|
CPF16FunctionKey = "\uF713";
|
||||||
|
CPF17FunctionKey = "\uF714";
|
||||||
|
CPF18FunctionKey = "\uF715";
|
||||||
|
CPF19FunctionKey = "\uF716";
|
||||||
|
CPF20FunctionKey = "\uF717";
|
||||||
|
CPF21FunctionKey = "\uF718";
|
||||||
|
CPF22FunctionKey = "\uF719";
|
||||||
|
CPF23FunctionKey = "\uF71A";
|
||||||
|
CPF24FunctionKey = "\uF71B";
|
||||||
|
CPF25FunctionKey = "\uF71C";
|
||||||
|
CPF26FunctionKey = "\uF71D";
|
||||||
|
CPF27FunctionKey = "\uF71E";
|
||||||
|
CPF28FunctionKey = "\uF71F";
|
||||||
|
CPF29FunctionKey = "\uF720";
|
||||||
|
CPF30FunctionKey = "\uF721";
|
||||||
|
CPF31FunctionKey = "\uF722";
|
||||||
|
CPF32FunctionKey = "\uF723";
|
||||||
|
CPF33FunctionKey = "\uF724";
|
||||||
|
CPF34FunctionKey = "\uF725";
|
||||||
|
CPF35FunctionKey = "\uF726";
|
||||||
|
CPInsertFunctionKey = "\uF727";
|
||||||
|
CPDeleteFunctionKey = "\uF728";
|
||||||
|
CPHomeFunctionKey = "\uF729";
|
||||||
|
CPBeginFunctionKey = "\uF72A";
|
||||||
|
CPEndFunctionKey = "\uF72B";
|
||||||
|
CPPageUpFunctionKey = "\uF72C";
|
||||||
|
CPPageDownFunctionKey = "\uF72D";
|
||||||
|
CPPrintScreenFunctionKey = "\uF72E";
|
||||||
|
CPScrollLockFunctionKey = "\uF72F";
|
||||||
|
CPPauseFunctionKey = "\uF730";
|
||||||
|
CPSysReqFunctionKey = "\uF731";
|
||||||
|
CPBreakFunctionKey = "\uF732";
|
||||||
|
CPResetFunctionKey = "\uF733";
|
||||||
|
CPStopFunctionKey = "\uF734";
|
||||||
|
CPMenuFunctionKey = "\uF735";
|
||||||
|
CPUserFunctionKey = "\uF736";
|
||||||
|
CPSystemFunctionKey = "\uF737";
|
||||||
|
CPPrintFunctionKey = "\uF738";
|
||||||
|
CPClearLineFunctionKey = "\uF739";
|
||||||
|
CPClearDisplayFunctionKey = "\uF73A";
|
||||||
|
CPInsertLineFunctionKey = "\uF73B";
|
||||||
|
CPDeleteLineFunctionKey = "\uF73C";
|
||||||
|
CPInsertCharFunctionKey = "\uF73D";
|
||||||
|
CPDeleteCharFunctionKey = "\uF73E";
|
||||||
|
CPPrevFunctionKey = "\uF73F";
|
||||||
|
CPNextFunctionKey = "\uF740";
|
||||||
|
CPSelectFunctionKey = "\uF741";
|
||||||
|
CPExecuteFunctionKey = "\uF742";
|
||||||
|
CPUndoFunctionKey = "\uF743";
|
||||||
|
CPRedoFunctionKey = "\uF744";
|
||||||
|
CPFindFunctionKey = "\uF745";
|
||||||
|
CPHelpFunctionKey = "\uF746";
|
||||||
|
CPModeSwitchFunctionKey = "\uF747";
|
||||||
|
CPEscapeFunctionKey = "\u001B";
|
||||||
|
CPSpaceFunctionKey = "\u0020";
|
||||||
|
|
||||||
|
|
||||||
|
CPDOMEventDoubleClick = "dblclick";
|
||||||
|
CPDOMEventMouseDown = "mousedown";
|
||||||
|
CPDOMEventMouseUp = "mouseup";
|
||||||
|
CPDOMEventMouseMoved = "mousemove";
|
||||||
|
CPDOMEventMouseDragged = "mousedrag";
|
||||||
|
CPDOMEventKeyUp = "keyup";
|
||||||
|
CPDOMEventKeyDown = "keydown";
|
||||||
|
CPDOMEventKeyPress = "keypress";
|
||||||
|
CPDOMEventCopy = "copy";
|
||||||
|
CPDOMEventPaste = "paste";
|
||||||
|
CPDOMEventScrollWheel = "mousewheel";
|
||||||
|
CPDOMEventTouchStart = "touchstart";
|
||||||
|
CPDOMEventTouchMove = "touchmove";
|
||||||
|
CPDOMEventTouchEnd = "touchend";
|
||||||
|
CPDOMEventTouchCancel = "touchcancel";
|
||||||
@@ -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,206 +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;
|
|
||||||
DOMElement _DOMInnerObjectElement;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:aFrame];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
#if PLATFORM(DOM)
|
|
||||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
|
||||||
{
|
|
||||||
_DOMObjectElement = document.createElement(@"object");
|
|
||||||
_DOMObjectElement.width = @"100%";
|
|
||||||
_DOMObjectElement.height = @"100%";
|
|
||||||
_DOMObjectElement.style.top = @"0px";
|
|
||||||
_DOMObjectElement.style.left = @"0px";
|
|
||||||
_DOMObjectElement.type = @"application/x-shockwave-flash";
|
|
||||||
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
|
|
||||||
|
|
||||||
_DOMParamElement = document.createElement(@"param");
|
|
||||||
_DOMParamElement.name = @"movie";
|
|
||||||
|
|
||||||
_DOMInnerObjectElement = document.createElement(@"object");
|
|
||||||
_DOMInnerObjectElement.width = @"100%";
|
|
||||||
_DOMInnerObjectElement.height = @"100%";
|
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
|
||||||
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
|
|
||||||
|
|
||||||
_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];
|
|
||||||
_DOMInnerObjectElement.data = [aFlashMovie filename];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[self _rebuildIEObjects];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPFlashMovie)flashMovie
|
|
||||||
{
|
|
||||||
return _flashMovie;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFlashVars:(CPDictionary)aDictionary
|
|
||||||
{
|
|
||||||
var varString = @"",
|
|
||||||
enumerator = [aDictionary keyEnumerator],
|
|
||||||
key;
|
|
||||||
|
|
||||||
while ((key = [enumerator nextObject]) !== nil)
|
|
||||||
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
|
|
||||||
|
|
||||||
if (!_params)
|
|
||||||
_params = [CPDictionary dictionary];
|
|
||||||
|
|
||||||
[_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 = [CPDictionary dictionary];
|
|
||||||
|
|
||||||
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 classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- (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
|
|
||||||
+161
-17
@@ -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,18 +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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +287,7 @@ following:
|
|||||||
var systemSize = String(_CPFontSystemFontSize),
|
var systemSize = String(_CPFontSystemFontSize),
|
||||||
currentSize = String(CPFontCurrentSystemSize);
|
currentSize = String(CPFontCurrentSystemSize);
|
||||||
|
|
||||||
for (key in _CPSystemFontCache)
|
for (var key in _CPSystemFontCache)
|
||||||
{
|
{
|
||||||
if (_CPSystemFontCache.hasOwnProperty(key) &&
|
if (_CPSystemFontCache.hasOwnProperty(key) &&
|
||||||
(key.indexOf(systemSize) === 0 || key.indexOf(currentSize) === 0))
|
(key.indexOf(systemSize) === 0 || key.indexOf(currentSize) === 0))
|
||||||
@@ -281,7 +362,7 @@ following:
|
|||||||
that dynamically tracks the current system font size.
|
that dynamically tracks the current system font size.
|
||||||
@return the requested system font
|
@return the requested system font
|
||||||
*/
|
*/
|
||||||
+ (CPFont)systemFontOfSize:(CPSize)aSize
|
+ (CPFont)systemFontOfSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, NO);
|
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, NO);
|
||||||
}
|
}
|
||||||
@@ -293,7 +374,7 @@ following:
|
|||||||
that dynamically tracks the current system font size.
|
that dynamically tracks the current system font size.
|
||||||
@return the requested bold system font
|
@return the requested bold system font
|
||||||
*/
|
*/
|
||||||
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
|
+ (CPFont)boldSystemFontOfSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, YES);
|
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, YES);
|
||||||
}
|
}
|
||||||
@@ -312,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;
|
||||||
@@ -429,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",
|
||||||
@@ -452,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -466,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
|
||||||
|
|||||||
+218
-38
@@ -22,7 +22,14 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CPControl.j"
|
||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
|
@import "CPFontDescriptor.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
@class CPFontPanel
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
CPItalicFontMask = 1 << 0;
|
CPItalicFontMask = 1 << 0;
|
||||||
CPBoldFontMask = 1 << 1;
|
CPBoldFontMask = 1 << 1;
|
||||||
@@ -39,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
|
||||||
@@ -54,9 +74,11 @@ var CPSharedFontManager = nil,
|
|||||||
id _delegate @accessors(property=delegate);
|
id _delegate @accessors(property=delegate);
|
||||||
|
|
||||||
CPFont _selectedFont;
|
CPFont _selectedFont;
|
||||||
BOOL _multiple @accessors;
|
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
|
||||||
|
|
||||||
CPDictionary _activeChange;
|
CPDictionary _activeChange;
|
||||||
|
|
||||||
|
unsigned _fontAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting the Shared Font Manager
|
// Getting the Shared Font Manager
|
||||||
@@ -81,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
|
||||||
{
|
{
|
||||||
@@ -139,7 +170,7 @@ var CPSharedFontManager = nil,
|
|||||||
- (void)setSelectedFont:(CPFont)aFont isMultiple:(BOOL)aFlag
|
- (void)setSelectedFont:(CPFont)aFont isMultiple:(BOOL)aFlag
|
||||||
{
|
{
|
||||||
_selectedFont = aFont;
|
_selectedFont = aFont;
|
||||||
_isMultiple = aFlag;
|
_multiple = aFlag;
|
||||||
|
|
||||||
// TODO Notify CPFontPanel when it exists.
|
// TODO Notify CPFontPanel when it exists.
|
||||||
}
|
}
|
||||||
@@ -149,11 +180,6 @@ var CPSharedFontManager = nil,
|
|||||||
return _selectedFont;
|
return _selectedFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isMultiple
|
|
||||||
{
|
|
||||||
return _isMultiple;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)weightOfFont:(CPFont)aFont
|
- (int)weightOfFont:(CPFont)aFont
|
||||||
{
|
{
|
||||||
// TODO Weight 5 is a normal of book weight and 9 and above is bold, but it would be nice to be more
|
// TODO Weight 5 is a normal of book weight and 9 and above is bold, but it would be nice to be more
|
||||||
@@ -166,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)
|
||||||
@@ -211,7 +208,9 @@ var CPSharedFontManager = nil,
|
|||||||
|
|
||||||
- (@action)addFontTrait:(id)sender
|
- (@action)addFontTrait:(id)sender
|
||||||
{
|
{
|
||||||
_activeChange = [CPDictionary dictionaryWithObject:[sender tag] forKey:@"addTraits"];
|
var tag = [sender tag];
|
||||||
|
_activeChange = tag == nil ? @{} : @{ @"addTraits": tag };
|
||||||
|
_fontAction = CPAddTraitFontAction;
|
||||||
|
|
||||||
[self sendAction];
|
[self sendAction];
|
||||||
}
|
}
|
||||||
@@ -221,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,
|
||||||
|
|||||||
+59
-13
@@ -20,6 +20,16 @@
|
|||||||
* 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/CPException.j>
|
||||||
|
@import <Foundation/CPMutableArray.j>
|
||||||
|
|
||||||
|
@import "CGColor.j"
|
||||||
|
@import "CGColorSpace.j"
|
||||||
|
@import "CGGradient.j"
|
||||||
|
@import "CPBezierPath.j"
|
||||||
|
@import "CPGraphicsContext.j"
|
||||||
|
|
||||||
CPGradientDrawsBeforeStartingLocation = kCGGradientDrawsBeforeStartLocation;
|
CPGradientDrawsBeforeStartingLocation = kCGGradientDrawsBeforeStartLocation;
|
||||||
CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||||
|
|
||||||
@@ -31,6 +41,11 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
|||||||
CGGradient _gradient;
|
CGGradient _gradient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)initWithStartingColor:(CPColor)startingColor endingColor:(CPColor)endingColor
|
||||||
|
{
|
||||||
|
return [self initWithColors:[startingColor, endingColor]];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithColors:(CPArray)someColors
|
- (id)initWithColors:(CPArray)someColors
|
||||||
{
|
{
|
||||||
var count = [someColors count];
|
var count = [someColors count];
|
||||||
@@ -55,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,20 +90,32 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
|||||||
CGContextClipToRect(ctx, rect);
|
CGContextClipToRect(ctx, rect);
|
||||||
CGContextAddRect(ctx, rect);
|
CGContextAddRect(ctx, rect);
|
||||||
|
|
||||||
var startPoint,
|
[self _drawInRect:rect atAngle:angle];
|
||||||
|
|
||||||
|
CGContextRestoreGState(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore like draw in rect but apply no clipping.
|
||||||
|
*/
|
||||||
|
- (void)_drawInRect:(CGRect)rect atAngle:(float)angle
|
||||||
|
{
|
||||||
|
var ctx = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
|
||||||
|
startPoint,
|
||||||
endPoint;
|
endPoint;
|
||||||
|
|
||||||
// Modulo of negative values doesn't work as expected in JS.
|
// Modulo of negative values doesn't work as expected in JS.
|
||||||
angle = ((angle % 360.0) + 360.0) % 360.0;
|
angle = ((angle % 360.0) + 360.0) % 360.0;
|
||||||
|
|
||||||
if (angle < 90.0)
|
if (angle < 90.0)
|
||||||
startPoint = _CGPointMake(_CGRectGetMinX(rect), _CGRectGetMinY(rect));
|
startPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
|
||||||
else if (angle < 180.0)
|
else if (angle < 180.0)
|
||||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMinY(rect));
|
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
|
||||||
else if (angle < 270.0)
|
else if (angle < 270.0)
|
||||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
|
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
|
||||||
else
|
else
|
||||||
startPoint = _CGPointMake(_CGRectGetMinX(rect), _CGRectGetMaxY(rect));
|
startPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));
|
||||||
|
|
||||||
// A line segment comes out of the starting point at the given angle, with the first colour
|
// A line segment comes out of the starting point at the given angle, with the first colour
|
||||||
// at the starting point and the last at the end. To do what drawInRect: is supposed to do
|
// at the starting point and the last at the end. To do what drawInRect: is supposed to do
|
||||||
@@ -102,13 +130,31 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
|||||||
// This simplifies down to (in the first quadrant) rectWidth * cos(a) + rectHeight * sin(a).
|
// This simplifies down to (in the first quadrant) rectWidth * cos(a) + rectHeight * sin(a).
|
||||||
|
|
||||||
var radians = PI * angle / 180.0,
|
var radians = PI * angle / 180.0,
|
||||||
length = ABS(_CGRectGetWidth(rect) * COS(radians)) + ABS(_CGRectGetHeight(rect) * SIN(radians));
|
length = ABS(CGRectGetWidth(rect) * COS(radians)) + ABS(CGRectGetHeight(rect) * SIN(radians));
|
||||||
|
|
||||||
endPoint = _CGPointMake(startPoint.x + length * COS(radians),
|
endPoint = CGPointMake(startPoint.x + length * COS(radians),
|
||||||
startPoint.y + length * SIN(radians));
|
startPoint.y + length * SIN(radians));
|
||||||
|
|
||||||
[self drawFromPoint:startPoint toPoint:endPoint options:CPGradientDrawsBeforeStartingLocation | CPGradientDrawsAfterEndingLocation];
|
[self drawFromPoint:startPoint toPoint:endPoint options:CPGradientDrawsBeforeStartingLocation | CPGradientDrawsAfterEndingLocation];
|
||||||
CGContextRestoreGState(ctx);
|
}
|
||||||
|
|
||||||
|
- (void)drawInBezierPath:(CPBezierPath)aPath angle:(float)anAngle
|
||||||
|
{
|
||||||
|
[CPGraphicsContext saveGraphicsState];
|
||||||
|
|
||||||
|
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
// Nail down the path which CGContextDrawLinearGradient will cause to be filled.
|
||||||
|
// Note we don't do this by clipping to the path and then calling drawInRect:atAngle:
|
||||||
|
// as this would cut off any antialias of the drawing, plus any active context shadow.
|
||||||
|
CGContextBeginPath(ctx);
|
||||||
|
CGContextAddPath(ctx, aPath._path);
|
||||||
|
CGContextSetLineWidth(ctx, [aPath lineWidth]);
|
||||||
|
CGContextClosePath(ctx);
|
||||||
|
|
||||||
|
[self _drawInRect:[aPath bounds] atAngle:anAngle];
|
||||||
|
|
||||||
|
[CPGraphicsContext restoreGraphicsState];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawFromPoint:(NSPoint)startingPoint toPoint:(NSPoint)endingPoint options:(NSGradientDrawingOptions)options
|
- (void)drawFromPoint:(NSPoint)startingPoint toPoint:(NSPoint)endingPoint options:(NSGradientDrawingOptions)options
|
||||||
|
|||||||
+16
-16
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -60,9 +60,9 @@ function CPDrawColorTiledRects(
|
|||||||
if (sides.length != colors.length)
|
if (sides.length != colors.length)
|
||||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
|
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
|
||||||
|
|
||||||
var resultRect = _CGRectMakeCopy(boundsRect),
|
var resultRect = CGRectMakeCopy(boundsRect),
|
||||||
slice = _CGRectMakeZero(),
|
slice = CGRectMakeZero(),
|
||||||
remainder = _CGRectMakeZero(),
|
remainder = CGRectMakeZero(),
|
||||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
@@ -77,7 +77,7 @@ function CPDrawColorTiledRects(
|
|||||||
slice = CGRectIntersection(slice, clipRect);
|
slice = CGRectIntersection(slice, clipRect);
|
||||||
|
|
||||||
// Cocoa docs say that only slices that are within the clipRect are actually drawn
|
// Cocoa docs say that only slices that are within the clipRect are actually drawn
|
||||||
if (_CGRectIsEmpty(slice))
|
if (CGRectIsEmpty(slice))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var minX,
|
var minX,
|
||||||
@@ -88,23 +88,23 @@ function CPDrawColorTiledRects(
|
|||||||
if (side == CPMinXEdge || side == CPMaxXEdge)
|
if (side == CPMinXEdge || side == CPMaxXEdge)
|
||||||
{
|
{
|
||||||
// Make sure we have at least 1 pixel to draw a line
|
// Make sure we have at least 1 pixel to draw a line
|
||||||
if (_CGRectGetWidth(slice) < 1.0)
|
if (CGRectGetWidth(slice) < 1.0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
minX = _CGRectGetMinX(slice) + 0.5;
|
minX = CGRectGetMinX(slice) + 0.5;
|
||||||
maxX = minX;
|
maxX = minX;
|
||||||
minY = _CGRectGetMinY(slice);
|
minY = CGRectGetMinY(slice);
|
||||||
maxY = _CGRectGetMaxY(slice);
|
maxY = CGRectGetMaxY(slice);
|
||||||
}
|
}
|
||||||
else // CPMinYEdge || CPMaxYEdge
|
else // CPMinYEdge || CPMaxYEdge
|
||||||
{
|
{
|
||||||
// Make sure we have at least 1 pixel to draw a line
|
// Make sure we have at least 1 pixel to draw a line
|
||||||
if (_CGRectGetHeight(slice) < 1.0)
|
if (CGRectGetHeight(slice) < 1.0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
minX = _CGRectGetMinX(slice);
|
minX = CGRectGetMinX(slice);
|
||||||
maxX = _CGRectGetMaxX(slice);
|
maxX = CGRectGetMaxX(slice);
|
||||||
minY = _CGRectGetMinY(slice) + 0.5;
|
minY = CGRectGetMinY(slice) + 0.5;
|
||||||
maxY = minY;
|
maxY = minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ var CPGraphicsContextCurrent = nil,
|
|||||||
+ (void)restoreGraphicsState
|
+ (void)restoreGraphicsState
|
||||||
{
|
{
|
||||||
var lastContext = [CPGraphicsContextThreadStack lastObject];
|
var lastContext = [CPGraphicsContextThreadStack lastObject];
|
||||||
|
|
||||||
if (lastContext)
|
if (lastContext)
|
||||||
{
|
{
|
||||||
[lastContext restoreGraphicsState];
|
[lastContext restoreGraphicsState];
|
||||||
@@ -91,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];
|
||||||
|
|
||||||
|
|||||||
+524
-23
@@ -21,12 +21,32 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPBundle.j>
|
@import <Foundation/CPBundle.j>
|
||||||
@import <Foundation/CPGeometry.j>
|
|
||||||
@import <Foundation/CPNotificationCenter.j>
|
@import <Foundation/CPNotificationCenter.j>
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPRunLoop.j>
|
@import <Foundation/CPRunLoop.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
@import <Foundation/CPData.j>
|
||||||
|
@import <Foundation/CPKeyedArchiver.j>
|
||||||
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
|
|
||||||
|
@import "CGGeometry.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;
|
||||||
@@ -49,15 +69,42 @@ var imagesForNames = { },
|
|||||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||||
|
|
||||||
function CPImageInBundle(aFilename, aSize, aBundle)
|
/*!
|
||||||
|
Returns a resource image with a relative path and size
|
||||||
|
in a bundle.
|
||||||
|
|
||||||
|
@param filename A filename or relative path to a resource image.
|
||||||
|
@param width Width of the image. May be omitted.
|
||||||
|
@param height Height of the image. May be omitted if width is omitted.
|
||||||
|
@param size Instead of passing width/height, a CGSize may be passed.
|
||||||
|
@param bundle Bundle in which the image resource can be found.
|
||||||
|
If omitted, defaults to the main bundle.
|
||||||
|
@return CPImage
|
||||||
|
*/
|
||||||
|
function CPImageInBundle()
|
||||||
{
|
{
|
||||||
if (!aBundle)
|
var filename = arguments[0],
|
||||||
aBundle = [CPBundle mainBundle];
|
size = nil,
|
||||||
|
bundle = nil;
|
||||||
|
|
||||||
if (aSize)
|
if (typeof(arguments[1]) === "number")
|
||||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
|
{
|
||||||
|
size = CGSizeMake(arguments[1], arguments[2]);
|
||||||
|
bundle = arguments[3];
|
||||||
|
}
|
||||||
|
else if (typeof(arguments[1]) === "object")
|
||||||
|
{
|
||||||
|
size = arguments[1];
|
||||||
|
bundle = arguments[2];
|
||||||
|
}
|
||||||
|
|
||||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
if (!bundle)
|
||||||
|
bundle = [CPBundle mainBundle];
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
return [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:filename] size:size];
|
||||||
|
|
||||||
|
return [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:filename]];
|
||||||
}
|
}
|
||||||
|
|
||||||
function CPAppKitImage(aFilename, aSize)
|
function CPAppKitImage(aFilename, aSize)
|
||||||
@@ -88,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
|
||||||
@@ -105,19 +153,24 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the image, by associating it with a filename. The image
|
Initializes the image, by associating it with a filename. The image
|
||||||
denoted in \c aFilename is not actually loaded. It will
|
denoted in \c aFilename is not actually loaded. It will be loaded
|
||||||
be loaded once needed.
|
once needed.
|
||||||
|
|
||||||
@param aFilename the file containing the image
|
@param aFilename the file containing the image
|
||||||
@param aSize the image's size
|
@param aSize the image's size
|
||||||
@return the initialized image
|
@return the initialized image
|
||||||
*/
|
*/
|
||||||
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||||
{
|
{
|
||||||
|
// Quietly return nil like in Cocoa, rather than crashing later.
|
||||||
|
if (aFilename == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_size = CPSizeCreateCopy(aSize);
|
_size = CGSizeMakeCopy(aSize);
|
||||||
_filename = aFilename;
|
_filename = aFilename;
|
||||||
_loadStatus = CPImageLoadStatusInitialized;
|
_loadStatus = CPImageLoadStatusInitialized;
|
||||||
}
|
}
|
||||||
@@ -195,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);
|
||||||
@@ -224,7 +277,7 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
*/
|
*/
|
||||||
- (CGSize)size
|
- (CGSize)size
|
||||||
{
|
{
|
||||||
return _size;
|
return CGSizeMakeCopy(_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)imageNamed:(CPString)aName
|
+ (id)imageNamed:(CPString)aName
|
||||||
@@ -271,13 +324,34 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the underlying Image element for a single image.
|
||||||
|
*/
|
||||||
|
- (Image)image
|
||||||
|
{
|
||||||
|
return _image;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -359,6 +433,11 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isSingleImage
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isThreePartImage
|
- (BOOL)isThreePartImage
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
@@ -369,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],
|
||||||
@@ -408,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,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)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -441,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"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -452,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;
|
||||||
@@ -490,6 +970,11 @@ function CPAppKitImage(aFilename, aSize)
|
|||||||
return _isVertical;
|
return _isVertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isSingleImage
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isThreePartImage
|
- (BOOL)isThreePartImage
|
||||||
{
|
{
|
||||||
return YES;
|
return YES;
|
||||||
@@ -554,6 +1039,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
|||||||
return _imageSlices;
|
return _imageSlices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isSingleImage
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isThreePartImage
|
- (BOOL)isThreePartImage
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
@@ -586,3 +1076,14 @@ var CPNinePartImageImageSlicesKey = @"CPNinePartImageImageSlicesKey";
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation CPImage (Duplication)
|
||||||
|
|
||||||
|
- (CPImage)duplicate
|
||||||
|
{
|
||||||
|
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+122
-49
@@ -26,6 +26,12 @@
|
|||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPShadowView.j"
|
@import "CPShadowView.j"
|
||||||
|
|
||||||
|
@global CPImagesPboardType
|
||||||
|
@global appkit_tag_dom_elements
|
||||||
|
|
||||||
|
@global document
|
||||||
|
|
||||||
|
@typedef CPImageAlignment
|
||||||
CPImageAlignCenter = 0;
|
CPImageAlignCenter = 0;
|
||||||
CPImageAlignTop = 1;
|
CPImageAlignTop = 1;
|
||||||
CPImageAlignTopLeft = 2;
|
CPImageAlignTopLeft = 2;
|
||||||
@@ -67,12 +73,14 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding === CPValueBinding || theBinding === CPValueURLBinding || theBinding === CPValuePathBinding || theBinding === CPDataBinding)
|
if (aBinding === CPValueBinding || aBinding === CPValueURLBinding || aBinding === CPValuePathBinding || aBinding === CPDataBinding)
|
||||||
return [CPImageViewValueBinder class];
|
return [CPImageViewValueBinder class];
|
||||||
|
else if ([aBinding hasPrefix:CPEditableBinding])
|
||||||
|
return [CPMultipleValueAndBinding class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -82,26 +90,59 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
_DOMImageElement = document.createElement("img");
|
[self _createDOMImageElement];
|
||||||
_DOMImageElement.style.position = "absolute";
|
|
||||||
_DOMImageElement.style.left = "0px";
|
|
||||||
_DOMImageElement.style.top = "0px";
|
|
||||||
|
|
||||||
if ([CPPlatform supportsDragAndDrop])
|
|
||||||
{
|
|
||||||
_DOMImageElement.setAttribute("draggable", "true");
|
|
||||||
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
|
||||||
}
|
|
||||||
|
|
||||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
|
|
||||||
|
|
||||||
_DOMImageElement.style.visibility = "hidden";
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_createDOMImageElement
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var image = [self objectValue],
|
||||||
|
isCSSBasedImage = [image isCSSBased],
|
||||||
|
isIMGImageElement = _DOMImageElement && (_DOMImageElement.nodeName == "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.left = "0px";
|
||||||
|
_DOMImageElement.style.top = "0px";
|
||||||
|
|
||||||
|
if ([CPPlatform supportsDragAndDrop])
|
||||||
|
{
|
||||||
|
_DOMImageElement.setAttribute("draggable", "true");
|
||||||
|
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
||||||
|
}
|
||||||
|
|
||||||
|
_DOMImageElement.style.visibility = "hidden";
|
||||||
|
AppKitTagDOMElement(self, _DOMImageElement);
|
||||||
|
|
||||||
|
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the view's image.
|
Returns the view's image.
|
||||||
*/
|
*/
|
||||||
@@ -133,7 +174,15 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
var newImage = [self objectValue];
|
var newImage = [self objectValue];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
[self _createDOMImageElement];
|
||||||
|
|
||||||
|
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];
|
||||||
@@ -159,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];
|
||||||
@@ -248,7 +298,7 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned)imageScaling
|
- (CPUInteger)imageScaling
|
||||||
{
|
{
|
||||||
return [self currentValueForThemeAttribute:@"image-scaling"];
|
return [self currentValueForThemeAttribute:@"image-scaling"];
|
||||||
}
|
}
|
||||||
@@ -297,8 +347,8 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
y = 0.0,
|
y = 0.0,
|
||||||
insetWidth = (_hasShadow ? [_shadowView horizontalInset] : 0.0),
|
insetWidth = (_hasShadow ? [_shadowView horizontalInset] : 0.0),
|
||||||
insetHeight = (_hasShadow ? [_shadowView verticalInset] : 0.0),
|
insetHeight = (_hasShadow ? [_shadowView verticalInset] : 0.0),
|
||||||
boundsWidth = _CGRectGetWidth(bounds),
|
boundsWidth = CGRectGetWidth(bounds),
|
||||||
boundsHeight = _CGRectGetHeight(bounds),
|
boundsHeight = CGRectGetHeight(bounds),
|
||||||
width = boundsWidth - insetWidth,
|
width = boundsWidth - insetWidth,
|
||||||
height = boundsHeight - insetHeight;
|
height = boundsHeight - insetHeight;
|
||||||
|
|
||||||
@@ -396,10 +446,22 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
_imageRect = _CGRectMake(x, y, width, height);
|
#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);
|
||||||
|
|
||||||
if (_hasShadow)
|
if (_hasShadow)
|
||||||
[_shadowView setFrame:_CGRectMake(x - [_shadowView leftInset], y - [_shadowView topInset], width + insetWidth, height + insetHeight)];
|
[_shadowView setFrame:CGRectMake(x - [_shadowView leftInset], y - [_shadowView topInset], width + insetWidth, height + insetHeight)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
@@ -471,16 +533,30 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
|||||||
{
|
{
|
||||||
var image;
|
var image;
|
||||||
|
|
||||||
if (aBinding === CPDataBinding)
|
if (aValue == nil)
|
||||||
|
image = nil;
|
||||||
|
else if (aBinding === CPDataBinding)
|
||||||
image = [[CPImage alloc] initWithData:aValue];
|
image = [[CPImage alloc] initWithData:aValue];
|
||||||
else if (aBinding === CPValueURLBinding || aBinding === CPValuePathBinding)
|
else if (aBinding === CPValueURLBinding || aBinding === CPValuePathBinding)
|
||||||
image = [[CPImage alloc] initWithContentsOfFile:aValue];
|
image = [CPImage cachedImageWithContentsOfFile:aValue];
|
||||||
else if (aBinding === CPValueBinding)
|
else if (aBinding === CPValueBinding)
|
||||||
image = aValue;
|
image = aValue;
|
||||||
|
|
||||||
[_source setImage:image];
|
[_source setImage:image];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var image = [_source image];
|
||||||
|
|
||||||
|
if (aBinding === CPDataBinding)
|
||||||
|
return [image data];
|
||||||
|
else if (aBinding === CPValueURLBinding || aBinding === CPValuePathBinding)
|
||||||
|
return [image filename];
|
||||||
|
else if (aBinding === CPValueBinding)
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||||
@@ -498,28 +574,12 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
|
||||||
_DOMImageElement = document.createElement("img");
|
|
||||||
_DOMImageElement.style.position = "absolute";
|
|
||||||
_DOMImageElement.style.left = "0px";
|
|
||||||
_DOMImageElement.style.top = "0px";
|
|
||||||
_DOMImageElement.style.visibility = "hidden";
|
|
||||||
if ([CPPlatform supportsDragAndDrop])
|
|
||||||
{
|
|
||||||
_DOMImageElement.setAttribute("draggable", "true");
|
|
||||||
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(appkit_tag_dom_elements) !== "undefined" && !!appkit_tag_dom_elements)
|
|
||||||
_DOMImageElement.setAttribute("data-cappuccino-view", [self className]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
self = [super initWithCoder:aCoder];
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
_DOMElement.appendChild(_DOMImageElement);
|
[self _createDOMImageElement];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||||
@@ -545,17 +605,12 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
// We do this in order to avoid encoding the _shadowView, which
|
// We do this in order to avoid encoding the _shadowView, which
|
||||||
// should just automatically be created programmatically as needed.
|
// should just automatically be created programmatically as needed.
|
||||||
if (_shadowView)
|
if (_shadowView)
|
||||||
{
|
[_shadowView removeFromSuperview];
|
||||||
var actualSubviews = _subviews;
|
|
||||||
|
|
||||||
_subviews = [_subviews copy];
|
|
||||||
[_subviews removeObjectIdenticalTo:_shadowView];
|
|
||||||
}
|
|
||||||
|
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
if (_shadowView)
|
if (_shadowView)
|
||||||
_subviews = actualSubviews;
|
[self addSubview:_shadowView];
|
||||||
|
|
||||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||||
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
||||||
@@ -565,3 +620,21 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPImage (CachedImage)
|
||||||
|
|
||||||
|
+ (CPImage)cachedImageWithContentsOfFile:(CPString)aFile
|
||||||
|
{
|
||||||
|
var cached_name = [CPString stringWithFormat:@"%@_%d", [self class], [aFile hash]],
|
||||||
|
image = [CPImage imageNamed:cached_name];
|
||||||
|
|
||||||
|
if (!image)
|
||||||
|
{
|
||||||
|
image = [[CPImage alloc] initWithContentsOfFile:aFile];
|
||||||
|
[image setName:cached_name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
@@ -21,9 +21,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPArray.j>
|
||||||
|
|
||||||
@import "CPEvent.j"
|
@import "CPEvent_Constants.j"
|
||||||
|
@import "CPText.j"
|
||||||
|
|
||||||
CPStandardKeyBindings = {
|
CPStandardKeyBindings = {
|
||||||
@"@.": @"cancelOperation:",
|
@"@.": @"cancelOperation:",
|
||||||
|
|||||||
+430
-95
@@ -26,19 +26,23 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
|
@import <Foundation/CPInvocation.j>
|
||||||
@import <Foundation/CPValueTransformer.j>
|
@import <Foundation/CPValueTransformer.j>
|
||||||
|
@import <Foundation/CPKeyValueObserving.j>
|
||||||
|
|
||||||
|
@class CPButton
|
||||||
|
|
||||||
var exposedBindingsMap = [CPDictionary new],
|
var exposedBindingsMap = @{},
|
||||||
bindingsMap = [CPDictionary new];
|
bindingsMap = @{};
|
||||||
|
|
||||||
|
@typedef CPBindingOperationKind
|
||||||
var CPBindingOperationAnd = 0,
|
var CPBindingOperationAnd = 0,
|
||||||
CPBindingOperationOr = 1;
|
CPBindingOperationOr = 1;
|
||||||
|
|
||||||
@implementation CPBinder : CPObject
|
@implementation CPBinder : CPObject
|
||||||
{
|
{
|
||||||
CPDictionary _info;
|
CPDictionary _info;
|
||||||
id _source;
|
id _source @accessors(getter=source);
|
||||||
|
|
||||||
JSObject _suppressedNotifications;
|
JSObject _suppressedNotifications;
|
||||||
JSObject _placeholderForMarker;
|
JSObject _placeholderForMarker;
|
||||||
@@ -67,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];
|
||||||
@@ -94,9 +112,9 @@ var CPBindingOperationAnd = 0,
|
|||||||
if (!theBinding)
|
if (!theBinding)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var infoDictionary = theBinding._info,
|
var info = theBinding._info,
|
||||||
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
|
observedObject = [info objectForKey:CPObservedObjectKey],
|
||||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
|
keyPath = [info objectForKey:CPObservedKeyPathKey];
|
||||||
|
|
||||||
[observedObject removeObserver:theBinding forKeyPath:keyPath];
|
[observedObject removeObserver:theBinding forKeyPath:keyPath];
|
||||||
[bindings removeObjectForKey:aBinding];
|
[bindings removeObjectForKey:aBinding];
|
||||||
@@ -105,6 +123,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
+ (void)unbindAllForObject:(id)anObject
|
+ (void)unbindAllForObject:(id)anObject
|
||||||
{
|
{
|
||||||
var bindings = [bindingsMap objectForKey:[anObject UID]];
|
var bindings = [bindingsMap objectForKey:[anObject UID]];
|
||||||
|
|
||||||
if (!bindings)
|
if (!bindings)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -112,19 +131,24 @@ 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]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||||
{
|
{
|
||||||
self = [super init];
|
// We use [self init] here because subclasses override init. We can't override this method
|
||||||
|
// because their initialization has to occur before this method in this class is executed.
|
||||||
|
self = [self init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_source = aSource;
|
_source = aSource;
|
||||||
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
|
_info = @{
|
||||||
|
CPObservedObjectKey: aDestination,
|
||||||
|
CPObservedKeyPathKey: aKeyPath,
|
||||||
|
};
|
||||||
_suppressedNotifications = {};
|
_suppressedNotifications = {};
|
||||||
_placeholderForMarker = {};
|
_placeholderForMarker = {};
|
||||||
|
|
||||||
@@ -133,12 +157,13 @@ 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]];
|
||||||
|
|
||||||
if (!bindings)
|
if (!bindings)
|
||||||
{
|
{
|
||||||
bindings = [CPDictionary new];
|
bindings = @{};
|
||||||
[bindingsMap setObject:bindings forKey:[_source UID]];
|
[bindingsMap setObject:bindings forKey:[_source UID]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,21 +174,43 @@ 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
|
||||||
|
{
|
||||||
|
if (aValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||||
|
{
|
||||||
|
[CPException raise:CPGenericException
|
||||||
|
reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + aValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)theBinding
|
- (void)setValueFor:(CPString)theBinding
|
||||||
{
|
{
|
||||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||||
options = [_info objectForKey:CPOptionsKey],
|
options = [_info objectForKey:CPOptionsKey],
|
||||||
newValue = [destination valueForKeyPath:keyPath],
|
newValue = [destination valueForKeyPath:keyPath];
|
||||||
isPlaceholder = CPIsControllerMarker(newValue);
|
|
||||||
|
|
||||||
if (isPlaceholder)
|
if (CPIsControllerMarker(newValue))
|
||||||
{
|
{
|
||||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
[self raiseIfNotApplicable:newValue forKeyPath:keyPath options:options];
|
||||||
{
|
|
||||||
[CPException raise:CPGenericException
|
|
||||||
reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + newValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = [self _placeholderForMarker:newValue];
|
var value = [self _placeholderForMarker:newValue];
|
||||||
[self setPlaceholderValue:value withMarker:newValue forBinding:theBinding];
|
[self setPlaceholderValue:value withMarker:newValue forBinding:theBinding];
|
||||||
@@ -210,6 +257,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var objectSuppressions = _suppressedNotifications[[anObject UID]];
|
var objectSuppressions = _suppressedNotifications[[anObject UID]];
|
||||||
|
|
||||||
if (objectSuppressions && objectSuppressions[aKeyPath])
|
if (objectSuppressions && objectSuppressions[aKeyPath])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -228,6 +276,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
if (!valueTransformer)
|
if (!valueTransformer)
|
||||||
{
|
{
|
||||||
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
||||||
|
|
||||||
if (valueTransformerClass)
|
if (valueTransformerClass)
|
||||||
{
|
{
|
||||||
valueTransformer = [[valueTransformerClass alloc] init];
|
valueTransformer = [[valueTransformerClass alloc] init];
|
||||||
@@ -241,7 +290,11 @@ var CPBindingOperationAnd = 0,
|
|||||||
if (valueTransformer)
|
if (valueTransformer)
|
||||||
aValue = [valueTransformer transformedValue:aValue];
|
aValue = [valueTransformer transformedValue:aValue];
|
||||||
|
|
||||||
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
|
// 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
|
||||||
|
// of setting the placeholder that is based on the fact that the value is nil.
|
||||||
|
if ((aValue == nil || aValue === [CPNull null])
|
||||||
|
&& ![_source respondsToSelector:@selector(setPlaceholderString:)])
|
||||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||||
|
|
||||||
return aValue;
|
return aValue;
|
||||||
@@ -285,6 +338,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
|
|
||||||
var uid = [anObject UID],
|
var uid = [anObject UID],
|
||||||
objectSuppressions = _suppressedNotifications[uid];
|
objectSuppressions = _suppressedNotifications[uid];
|
||||||
|
|
||||||
if (!objectSuppressions)
|
if (!objectSuppressions)
|
||||||
_suppressedNotifications[uid] = objectSuppressions = {};
|
_suppressedNotifications[uid] = objectSuppressions = {};
|
||||||
|
|
||||||
@@ -301,6 +355,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
|
|
||||||
var uid = [anObject UID],
|
var uid = [anObject UID],
|
||||||
objectSuppressions = _suppressedNotifications[uid];
|
objectSuppressions = _suppressedNotifications[uid];
|
||||||
|
|
||||||
if (!objectSuppressions)
|
if (!objectSuppressions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -317,6 +372,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
optionName = CPBinderPlaceholderOptions[count],
|
optionName = CPBinderPlaceholderOptions[count],
|
||||||
isExplicit = [options containsKey:optionName],
|
isExplicit = [options containsKey:optionName],
|
||||||
placeholder = isExplicit ? [options objectForKey:optionName] : nil;
|
placeholder = isExplicit ? [options objectForKey:optionName] : nil;
|
||||||
|
|
||||||
[self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
|
[self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,11 +382,13 @@ var CPBindingOperationAnd = 0,
|
|||||||
[self _updatePlaceholdersWithOptions:options];
|
[self _updatePlaceholdersWithOptions:options];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_placeholderForMarker:aMarker
|
- (JSObject)_placeholderForMarker:(id)aMarker
|
||||||
{
|
{
|
||||||
var placeholder = _placeholderForMarker[aMarker];
|
var placeholder = _placeholderForMarker[[aMarker UID]];
|
||||||
|
|
||||||
if (placeholder)
|
if (placeholder)
|
||||||
return placeholder['value'];
|
return placeholder.value;
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,14 +396,14 @@ var CPBindingOperationAnd = 0,
|
|||||||
{
|
{
|
||||||
if (isDefault)
|
if (isDefault)
|
||||||
{
|
{
|
||||||
var existingPlaceholder = _placeholderForMarker[aMarker];
|
var existingPlaceholder = _placeholderForMarker[[aMarker UID]];
|
||||||
|
|
||||||
// Don't overwrite an explicitly set placeholder with a default.
|
// Don't overwrite an explicitly set placeholder with a default.
|
||||||
if (existingPlaceholder && !existingPlaceholder['isDefault'])
|
if (existingPlaceholder && !existingPlaceholder.isDefault)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_placeholderForMarker[aMarker] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
_placeholderForMarker[[aMarker UID]] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -357,11 +415,16 @@ var CPBindingOperationAnd = 0,
|
|||||||
[CPBinder exposeBinding:aBinding forClass:[self class]];
|
[CPBinder exposeBinding:aBinding forClass:[self class]];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
return [CPBinder class];
|
return [CPBinder class];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (CPArray)exposedBindings
|
- (CPArray)exposedBindings
|
||||||
{
|
{
|
||||||
var exposedBindings = [],
|
var exposedBindings = [],
|
||||||
@@ -390,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);
|
||||||
|
|
||||||
@@ -410,7 +478,7 @@ var CPBindingOperationAnd = 0,
|
|||||||
[binderClass unbind:aBinding forObject:self];
|
[binderClass unbind:aBinding forObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_replacementKeyPathForBinding:(CPString)binding
|
- (CPString)_replacementKeyPathForBinding:(CPString)binding
|
||||||
{
|
{
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
@@ -419,13 +487,13 @@ var CPBindingOperationAnd = 0,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ignore
|
@ignore
|
||||||
Provides stub implementations that simply call super for the "objectValue" binding
|
Provides stub implementations that simply calls super for the "objectValue" binding.
|
||||||
This class should not be necessary but assures backwards compliance with our old way of doing bindings
|
This class should not be necessary but assures backwards compliance with our old way of doing bindings.
|
||||||
Every class with a value binding should implement a subclass to handle it's specific value binding logic
|
|
||||||
|
IMPORTANT!
|
||||||
|
Every class with a value binding should implement a subclass to handle its specific value binding logic.
|
||||||
*/
|
*/
|
||||||
@implementation _CPValueBinder : CPBinder
|
@implementation _CPValueBinder : CPBinder
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)theBinding
|
- (void)setValueFor:(CPString)theBinding
|
||||||
{
|
{
|
||||||
@@ -439,8 +507,9 @@ var CPBindingOperationAnd = 0,
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPKeyValueOrBinding : CPBinder
|
@implementation _CPMultipleValueBooleanBinding : CPBinder
|
||||||
{
|
{
|
||||||
|
CPBindingOperationKind _operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)aBinding
|
- (void)setValueFor:(CPString)aBinding
|
||||||
@@ -450,7 +519,14 @@ var CPBindingOperationAnd = 0,
|
|||||||
if (!bindings)
|
if (!bindings)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
|
var baseBinding = aBinding.replace(/\d$/, "");
|
||||||
|
|
||||||
|
[_source setValue:[self resolveMultipleValuesForBinding:baseBinding bindings:bindings booleanOperation:_operation] forKey:baseBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseSetValueFor:(CPString)theBinding
|
||||||
|
{
|
||||||
|
// read-only
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||||
@@ -458,61 +534,146 @@ var CPBindingOperationAnd = 0,
|
|||||||
[self setValueFor:context];
|
[self setValueFor:context];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
- (BOOL)resolveMultipleValuesForBinding:(CPString)aBinding bindings:(CPDictionary)bindings booleanOperation:(CPBindingOperationKind)operation
|
||||||
|
|
||||||
@implementation _CPKeyValueAndBinding : CPBinder
|
|
||||||
{
|
{
|
||||||
}
|
var bindingName = aBinding,
|
||||||
|
|
||||||
- (void)setValueFor:(CPString)aBinding
|
|
||||||
{
|
|
||||||
var bindings = [bindingsMap objectForKey:[_source UID]];
|
|
||||||
|
|
||||||
if (!bindings)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context
|
|
||||||
{
|
|
||||||
[self setValueFor:context];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
var resolveMultipleValues = function(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation)
|
|
||||||
{
|
|
||||||
var bindingName = key,
|
|
||||||
theBinding,
|
theBinding,
|
||||||
count = 1;
|
count = 2;
|
||||||
|
|
||||||
while (theBinding = [bindings objectForKey:bindingName])
|
while (theBinding = [bindings objectForKey:bindingName])
|
||||||
{
|
{
|
||||||
var infoDictionary = theBinding._info,
|
var info = theBinding._info,
|
||||||
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
object = [info objectForKey:CPObservedObjectKey],
|
||||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
options = [infoDictionary objectForKey:CPOptionsKey];
|
options = [info objectForKey:CPOptionsKey],
|
||||||
|
value = [object valueForKeyPath:keyPath];
|
||||||
|
|
||||||
var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
|
if (CPIsControllerMarker(value))
|
||||||
|
{
|
||||||
|
[self raiseIfNotApplicable:value forKeyPath:keyPath options:options];
|
||||||
|
value = [theBinding _placeholderForMarker:value];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value = [theBinding transformValue:value withOptions:options];
|
||||||
|
|
||||||
if (value == operation)
|
if (operation === CPBindingOperationOr)
|
||||||
return operation;
|
{
|
||||||
|
// Any true condition means true for OR
|
||||||
|
if (value)
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
bindingName = [CPString stringWithFormat:@"%@%i", key, ++count];
|
// Any false condition means false for AND
|
||||||
|
else if (!value)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
bindingName = aBinding + (count++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !operation;
|
// If we get here, all OR conditions were false or all AND conditions were true
|
||||||
};
|
return operation === CPBindingOperationOr ? NO : YES;
|
||||||
|
}
|
||||||
|
|
||||||
var invokeAction = function(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
|
@end
|
||||||
|
|
||||||
|
@implementation CPMultipleValueAndBinding : _CPMultipleValueBooleanBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
{
|
{
|
||||||
var theBinding = [bindings objectForKey:targetKey],
|
if (self = [super init])
|
||||||
infoDictionary = theBinding._info,
|
_operation = CPBindingOperationAnd;
|
||||||
|
|
||||||
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
return self;
|
||||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
}
|
||||||
options = [infoDictionary objectForKey:CPOptionsKey],
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPMultipleValueOrBinding : _CPMultipleValueBooleanBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
_operation = CPBindingOperationOr;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMultipleValueActionBinding : CPBinder
|
||||||
|
{
|
||||||
|
CPString _argumentBinding;
|
||||||
|
CPString _targetBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValueFor:(CPString)theBinding
|
||||||
|
{
|
||||||
|
// Called when the binding is first created
|
||||||
|
[self checkForNullBinding:theBinding initializing:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseSetValueFor:(CPString)theBinding
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||||
|
{
|
||||||
|
// context is the binding name
|
||||||
|
[self checkForNullBinding:context initializing:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
When the value of a multiple-value argument binding changes,
|
||||||
|
if the binding is marked not to allow null arguments, we have to check
|
||||||
|
if the binding's value is nil and disable the button if it is.
|
||||||
|
Otherwise the button is enabled.
|
||||||
|
*/
|
||||||
|
- (void)checkForNullBinding:(CPString)theBinding initializing:(BOOL)isInitializing
|
||||||
|
{
|
||||||
|
// Only done for buttons
|
||||||
|
if (![_source isKindOfClass:CPButton])
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We start with the button enabled for the first argument during init,
|
||||||
|
// and subsequent checks can disable it.
|
||||||
|
if (isInitializing && theBinding === CPArgumentBinding)
|
||||||
|
[_source setEnabled:YES];
|
||||||
|
|
||||||
|
var bindings = [bindingsMap valueForKey:[_source UID]],
|
||||||
|
binding = [bindings objectForKey:theBinding],
|
||||||
|
info = binding._info,
|
||||||
|
options = [info objectForKey:CPOptionsKey];
|
||||||
|
|
||||||
|
if (![options valueForKey:CPAllowsNullArgumentBindingOption])
|
||||||
|
{
|
||||||
|
var object = [info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
|
value = [object valueForKeyPath:keyPath];
|
||||||
|
|
||||||
|
if (value == nil)
|
||||||
|
{
|
||||||
|
[_source setEnabled:NO];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a binding value changed and did not fail the null test, enable the button
|
||||||
|
if (!isInitializing)
|
||||||
|
[_source setEnabled:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)invokeAction
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap valueForKey:[_source UID]],
|
||||||
|
theBinding = [bindings objectForKey:CPTargetBinding],
|
||||||
|
|
||||||
|
info = theBinding._info,
|
||||||
|
object = [info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [info objectForKey:CPOptionsKey],
|
||||||
|
|
||||||
target = [object valueForKeyPath:keyPath],
|
target = [object valueForKeyPath:keyPath],
|
||||||
selector = [options objectForKey:CPSelectorNameBindingOption];
|
selector = [options objectForKey:CPSelectorNameBindingOption];
|
||||||
@@ -520,27 +681,194 @@ var invokeAction = function(/*CPString*/targetKey, /*CPString*/argumentKey, /*CP
|
|||||||
if (!target || !selector)
|
if (!target || !selector)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
|
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]],
|
||||||
[invocation setSelector:selector];
|
bindingName = CPArgumentBinding,
|
||||||
|
|
||||||
var bindingName = argumentKey,
|
|
||||||
count = 1;
|
count = 1;
|
||||||
|
|
||||||
while (theBinding = [bindings objectForKey:bindingName])
|
while (theBinding = [bindings objectForKey:bindingName])
|
||||||
{
|
{
|
||||||
infoDictionary = theBinding._info;
|
info = theBinding._info;
|
||||||
|
object = [info objectForKey:CPObservedObjectKey];
|
||||||
|
keyPath = [info objectForKey:CPObservedKeyPathKey];
|
||||||
|
|
||||||
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
|
[invocation setArgument:[object valueForKeyPath:keyPath] atIndex:++count];
|
||||||
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
|
|
||||||
|
|
||||||
if (object)
|
bindingName = CPArgumentBinding + count;
|
||||||
[invocation setArgument:object atIndex:++count];
|
|
||||||
|
|
||||||
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[invocation invoke];
|
[invocation setSelector:selector];
|
||||||
};
|
[invocation invokeWithTarget:target];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPActionBinding : _CPMultipleValueActionBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_argumentBinding = CPArgumentBinding;
|
||||||
|
_targetBinding = CPTargetBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPDoubleClickActionBinding : _CPMultipleValueActionBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_argumentBinding = CPArgumentBinding;
|
||||||
|
_targetBinding = CPTargetBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Abstract superclass for CPValueWithPatternBinding and CPTitleWithPatternBinding.
|
||||||
|
*/
|
||||||
|
@implementation _CPPatternBinding : CPBinder
|
||||||
|
{
|
||||||
|
CPString _bindingKey;
|
||||||
|
CPString _patternPlaceholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValueFor:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap valueForKey:[_source UID]];
|
||||||
|
|
||||||
|
if (!bindings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Strip off any trailing number from the binding name
|
||||||
|
var baseBinding = aBinding.replace(/\d$/, ""),
|
||||||
|
result = [self resolveMultipleValuesForBindings:bindings];
|
||||||
|
|
||||||
|
if (result.isPlaceholder)
|
||||||
|
[self setPlaceholderValue:result.value withMarker:result.marker forBinding:baseBinding];
|
||||||
|
else
|
||||||
|
[self setValue:result.value forBinding:baseBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseSetValueFor:(CPString)theBinding
|
||||||
|
{
|
||||||
|
// read-only
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||||
|
{
|
||||||
|
[self setValueFor:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (JSObject)resolveMultipleValuesForBindings:(CPDictionary)bindings
|
||||||
|
{
|
||||||
|
var theBinding,
|
||||||
|
result = { value:@"", isPlaceholder:NO, marker:nil };
|
||||||
|
|
||||||
|
for (var count = 1; theBinding = [bindings objectForKey:_bindingKey + count]; ++count)
|
||||||
|
{
|
||||||
|
var info = theBinding._info,
|
||||||
|
object = [info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [info objectForKey:CPOptionsKey],
|
||||||
|
value = [object valueForKeyPath:keyPath];
|
||||||
|
|
||||||
|
if (count === 1)
|
||||||
|
result.value = [options objectForKey:CPDisplayPatternBindingOption];
|
||||||
|
|
||||||
|
if (CPIsControllerMarker(value))
|
||||||
|
{
|
||||||
|
[self raiseIfNotApplicable:value forKeyPath:keyPath options:options];
|
||||||
|
|
||||||
|
result.isPlaceholder = YES;
|
||||||
|
result.marker = value;
|
||||||
|
|
||||||
|
value = [theBinding _placeholderForMarker:value];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value = [theBinding transformValue:value withOptions:options];
|
||||||
|
|
||||||
|
if (value == nil)
|
||||||
|
value = @"";
|
||||||
|
|
||||||
|
result.value = result.value.replace("%{" + _patternPlaceholder + count + "}@", [value description]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Users of this class must override setValue:forKey: and if the
|
||||||
|
key is CPDisplayPatternValueBinding, set the appropriate value
|
||||||
|
for the control class. For example, CPTextField uses setObjectValue.
|
||||||
|
*/
|
||||||
|
@implementation CPValueWithPatternBinding : _CPPatternBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_bindingKey = CPDisplayPatternValueBinding;
|
||||||
|
_patternPlaceholder = @"value";
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Users of this class must override setValue:forKey: and if the
|
||||||
|
key is CPDisplayPatternTitleBinding, set the appropriate value
|
||||||
|
for the control class. For example, CPBox uses setTitle.
|
||||||
|
*/
|
||||||
|
@implementation CPTitleWithPatternBinding : _CPPatternBinding
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_bindingKey = CPDisplayPatternTitleBinding;
|
||||||
|
_patternPlaceholder = @"title";
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPStateMarker : CPObject
|
||||||
|
{
|
||||||
|
CPString _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithName:(CPString)aName
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
_name = aName;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return "<" + _name + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
// Keys in options dictionary
|
// Keys in options dictionary
|
||||||
|
|
||||||
@@ -550,18 +878,23 @@ CPObservedKeyPathKey = @"CPObservedKeyPathKey";
|
|||||||
CPOptionsKey = @"CPOptionsKey";
|
CPOptionsKey = @"CPOptionsKey";
|
||||||
|
|
||||||
// special markers
|
// special markers
|
||||||
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
|
CPNoSelectionMarker = [[_CPStateMarker alloc] initWithName:@"NO SELECTION MARKER"];
|
||||||
CPNoSelectionMarker = @"CPNoSelectionMarker";
|
CPMultipleValuesMarker = [[_CPStateMarker alloc] initWithName:@"MULTIPLE VALUES MARKER"];
|
||||||
CPNotApplicableMarker = @"CPNotApplicableMarker";
|
CPNotApplicableMarker = [[_CPStateMarker alloc] initWithName:@"NOT APPLICABLE MARKER"];
|
||||||
CPNullMarker = @"CPNullMarker";
|
CPNullMarker = [[_CPStateMarker alloc] initWithName:@"NULL MARKER"];
|
||||||
|
|
||||||
// Binding name constants
|
// Binding name constants
|
||||||
CPAlignmentBinding = @"alignment";
|
CPAlignmentBinding = @"alignment";
|
||||||
|
CPArgumentBinding = @"argument";
|
||||||
CPContentArrayBinding = @"contentArray";
|
CPContentArrayBinding = @"contentArray";
|
||||||
CPContentBinding = @"content";
|
CPContentBinding = @"content";
|
||||||
CPContentObjectBinding = @"contentObject";
|
CPContentObjectBinding = @"contentObject";
|
||||||
CPContentObjectsBinding = @"contentObjects";
|
CPContentObjectsBinding = @"contentObjects";
|
||||||
CPContentValuesBinding = @"contentValues";
|
CPContentValuesBinding = @"contentValues";
|
||||||
|
CPDisplayPatternTitleBinding = @"displayPatternTitle";
|
||||||
|
CPDisplayPatternValueBinding = @"displayPatternValue";
|
||||||
|
CPDoubleClickArgumentBinding = @"doubleClickArgument";
|
||||||
|
CPDoubleClickTargetBinding = @"doubleClickTarget";
|
||||||
CPEditableBinding = @"editable";
|
CPEditableBinding = @"editable";
|
||||||
CPEnabledBinding = @"enabled";
|
CPEnabledBinding = @"enabled";
|
||||||
CPFontBinding = @"font";
|
CPFontBinding = @"font";
|
||||||
@@ -580,15 +913,17 @@ CPSelectedTagBinding = @"selectedTag";
|
|||||||
CPSelectedValueBinding = @"selectedValue";
|
CPSelectedValueBinding = @"selectedValue";
|
||||||
CPSelectedValuesBinding = @"selectedValues";
|
CPSelectedValuesBinding = @"selectedValues";
|
||||||
CPSelectionIndexesBinding = @"selectionIndexes";
|
CPSelectionIndexesBinding = @"selectionIndexes";
|
||||||
|
CPTargetBinding = @"target";
|
||||||
CPTextColorBinding = @"textColor";
|
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";
|
||||||
|
|
||||||
//Binding options constants
|
// Binding options constants
|
||||||
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
||||||
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
|
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
|
||||||
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
|
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
|
||||||
|
|||||||
+47
-87
@@ -21,25 +21,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
@import "CPWindow_Constants.j"
|
||||||
|
@import "CPSlider.j"
|
||||||
|
|
||||||
CPTickMarkBelow = 0;
|
@global CPApp
|
||||||
CPTickMarkAbove = 1;
|
|
||||||
CPTickMarkLeft = CPTickMarkAbove;
|
|
||||||
CPTickMarkRight = CPTickMarkBelow;
|
|
||||||
|
|
||||||
|
@typedef CPLevelIndicatorStyle
|
||||||
CPRelevancyLevelIndicatorStyle = 0;
|
CPRelevancyLevelIndicatorStyle = 0;
|
||||||
CPContinuousCapacityLevelIndicatorStyle = 1;
|
CPContinuousCapacityLevelIndicatorStyle = 1;
|
||||||
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
||||||
CPRatingLevelIndicatorStyle = 3;
|
CPRatingLevelIndicatorStyle = 3;
|
||||||
|
|
||||||
var _CPLevelIndicatorBezelColor = nil,
|
|
||||||
_CPLevelIndicatorSegmentEmptyColor = nil,
|
|
||||||
_CPLevelIndicatorSegmentNormalColor = nil,
|
|
||||||
_CPLevelIndicatorSegmentWarningColor = nil,
|
|
||||||
_CPLevelIndicatorSegmentCriticalColor = nil,
|
|
||||||
|
|
||||||
_CPLevelIndicatorSpacing = 1;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPLevelIndicator
|
@class CPLevelIndicator
|
||||||
@@ -62,57 +54,21 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
BOOL _isTracking;
|
BOOL _isTracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self !== [CPLevelIndicator class])
|
return "level-indicator";
|
||||||
return;
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
return @{
|
||||||
[
|
@"bezel-color": [CPNull null],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
|
@"color-empty": [CPNull null],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
|
@"color-normal": [CPNull null],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
|
@"color-warning": [CPNull null],
|
||||||
]
|
@"color-critical": [CPNull null],
|
||||||
isVertical:NO
|
@"spacing": 1.0,
|
||||||
]];
|
};
|
||||||
|
|
||||||
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
|
|
||||||
]
|
|
||||||
isVertical:NO
|
|
||||||
]];
|
|
||||||
|
|
||||||
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
|
|
||||||
]
|
|
||||||
isVertical:NO
|
|
||||||
]];
|
|
||||||
|
|
||||||
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
|
|
||||||
]
|
|
||||||
isVertical:NO
|
|
||||||
]];
|
|
||||||
|
|
||||||
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
|
|
||||||
]
|
|
||||||
isVertical:NO
|
|
||||||
]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -125,37 +81,42 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
_maxValue = 2;
|
_maxValue = 2;
|
||||||
_warningValue = 2;
|
_warningValue = 2;
|
||||||
_criticalValue = 2;
|
_criticalValue = 2;
|
||||||
|
|
||||||
[self _init];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_init
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
|
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
// TODO Make themable.
|
// TODO Make themable.
|
||||||
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
|
[bezelView setBackgroundColor:[self valueForThemeAttribute:@"bezel-color"]];
|
||||||
|
|
||||||
var segmentCount = _maxValue - _minValue;
|
var segmentCount = _maxValue - _minValue;
|
||||||
|
|
||||||
if (segmentCount <= 0)
|
if (segmentCount <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
var filledColor = [self valueForThemeAttribute:@"color-normal"],
|
||||||
value = [self doubleValue];
|
value = [self doubleValue];
|
||||||
|
|
||||||
if (value <= _criticalValue)
|
if (_warningValue < _criticalValue)
|
||||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
{
|
||||||
else if (value <= _warningValue)
|
if (value >= _criticalValue)
|
||||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
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++)
|
||||||
{
|
{
|
||||||
@@ -163,13 +124,13 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
positioned:CPWindowAbove
|
positioned:CPWindowAbove
|
||||||
relativeToEphemeralSubviewNamed:bezelView];
|
relativeToEphemeralSubviewNamed:bezelView];
|
||||||
|
|
||||||
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
|
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : [self valueForThemeAttribute:@"color-empty"]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||||
@@ -177,11 +138,11 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
// TODO Put into theme attributes.
|
// TODO Put into theme attributes.
|
||||||
var bezelHeight = 18,
|
var bezelHeight = 18,
|
||||||
segmentHeight = 17,
|
segmentHeight = 17,
|
||||||
bounds = _CGRectCreateCopy([self bounds]);
|
bounds = CGRectCreateCopy([self bounds]);
|
||||||
|
|
||||||
if (aViewName == "bezel")
|
if (aViewName == "bezel")
|
||||||
{
|
{
|
||||||
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
bounds.origin.y = (CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||||
bounds.size.height = bezelHeight;
|
bounds.size.height = bezelHeight;
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
@@ -191,20 +152,21 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
segmentCount = _maxValue - _minValue;
|
segmentCount = _maxValue - _minValue;
|
||||||
|
|
||||||
if (segment >= segmentCount)
|
if (segment >= segmentCount)
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
|
|
||||||
var basicSegmentWidth = bounds.size.width / segmentCount,
|
var basicSegmentWidth = bounds.size.width / segmentCount,
|
||||||
segmentFrame = CGRectCreateCopy([self bounds]);
|
segmentFrame = CGRectCreateCopy([self bounds]),
|
||||||
|
spacing = [self valueForThemeAttribute:@"spacing"];
|
||||||
|
|
||||||
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
segmentFrame.origin.y = (CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||||
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
|
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
|
||||||
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
|
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - spacing;
|
||||||
segmentFrame.size.height = segmentHeight;
|
segmentFrame.size.height = segmentHeight;
|
||||||
|
|
||||||
return segmentFrame;
|
return segmentFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -226,7 +188,7 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
return _isEditable;
|
return _isEditable;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)hitTest:(CPPoint)aPoint
|
- (CPView)hitTest:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
// Don't swallow clicks when displayed in a table.
|
// Don't swallow clicks when displayed in a table.
|
||||||
if (![self isEditable])
|
if (![self isEditable])
|
||||||
@@ -325,7 +287,7 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWarningValue:(double)warningValue;
|
- (void)setWarningValue:(double)warningValue
|
||||||
{
|
{
|
||||||
if (_warningValue === warningValue)
|
if (_warningValue === warningValue)
|
||||||
return;
|
return;
|
||||||
@@ -334,7 +296,7 @@ var _CPLevelIndicatorBezelColor = nil,
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCriticalValue:(double)criticalValue;
|
- (void)setCriticalValue:(double)criticalValue
|
||||||
{
|
{
|
||||||
if (_criticalValue === criticalValue)
|
if (_criticalValue === criticalValue)
|
||||||
return;
|
return;
|
||||||
@@ -388,8 +350,6 @@ var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
|
|||||||
|
|
||||||
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
|
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
|
||||||
|
|
||||||
[self _init];
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|||||||
+203
-60
@@ -25,12 +25,21 @@
|
|||||||
@import <Foundation/CPNotificationCenter.j>
|
@import <Foundation/CPNotificationCenter.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import "_CPMenuManager.j"
|
@import "CPKeyValueBinding.j"
|
||||||
@import "CPApplication.j"
|
|
||||||
@import "CPClipView.j"
|
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
@import "CPPanel.j"
|
|
||||||
|
|
||||||
|
@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";
|
||||||
@@ -38,12 +47,8 @@ CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
|
|||||||
|
|
||||||
CPMenuDidEndTrackingNotification = @"CPMenuDidEndTrackingNotification";
|
CPMenuDidEndTrackingNotification = @"CPMenuDidEndTrackingNotification";
|
||||||
|
|
||||||
var MENUBAR_HEIGHT = 28.0;
|
|
||||||
|
|
||||||
var _CPMenuBarVisible = NO,
|
var _CPMenuBarVisible = NO,
|
||||||
_CPMenuBarTitle = @"",
|
_CPMenuBarTitle = @"",
|
||||||
_CPMenuBarIconImage = nil,
|
|
||||||
_CPMenuBarIconImageAlphaValue = 1.0,
|
|
||||||
_CPMenuBarAttributes = nil,
|
_CPMenuBarAttributes = nil,
|
||||||
_CPMenuBarSharedWindow = nil;
|
_CPMenuBarSharedWindow = nil;
|
||||||
|
|
||||||
@@ -56,24 +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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing the Menu Bar
|
// Managing the Menu Bar
|
||||||
@@ -83,7 +91,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
if (self !== [CPMenu class])
|
if (self !== [CPMenu class])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
|
[[self class] setMenuBarAttributes:@{}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)menuBarVisible
|
+ (BOOL)menuBarVisible
|
||||||
@@ -109,8 +117,8 @@ var _CPMenuBarVisible = NO,
|
|||||||
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
|
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
|
||||||
|
|
||||||
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
|
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
|
||||||
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
|
[_CPMenuBarSharedWindow setIconImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-icon-image" forClass:_CPMenuView]];
|
||||||
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
|
[_CPMenuBarSharedWindow setIconImageAlphaValue:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-icon-image-alpha-value" forClass:_CPMenuView]];
|
||||||
|
|
||||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||||
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
||||||
@@ -154,6 +162,13 @@ var _CPMenuBarVisible = NO,
|
|||||||
return _CPMenuBarImage;
|
return _CPMenuBarImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)_setOrRemoveMenuBarAttribute:(id)aValue forKey:(id)aKey
|
||||||
|
{
|
||||||
|
if (aValue == nil)
|
||||||
|
[_CPMenuBarAttributes removeObjectForKey:aKey];
|
||||||
|
else
|
||||||
|
[_CPMenuBarAttributes setObject:aValue forKey:aKey];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)setMenuBarAttributes:(CPDictionary)attributes
|
+ (void)setMenuBarAttributes:(CPDictionary)attributes
|
||||||
{
|
{
|
||||||
@@ -178,8 +193,8 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
else if (!textColor && !titleColor)
|
else if (!textColor && !titleColor)
|
||||||
{
|
{
|
||||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextColor"];
|
||||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleColor"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!textShadowColor && titleShadowColor)
|
if (!textShadowColor && titleShadowColor)
|
||||||
@@ -190,18 +205,18 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
else if (!textShadowColor && !titleShadowColor)
|
else if (!textShadowColor && !titleShadowColor)
|
||||||
{
|
{
|
||||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextShadowColor"];
|
||||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleShadowColor"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!highlightColor)
|
if (!highlightColor)
|
||||||
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0 / 255.0 green:130.0 / 255.0 blue:186.0 / 255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightColor"];
|
||||||
|
|
||||||
if (!highlightTextColor)
|
if (!highlightTextColor)
|
||||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextColor"];
|
||||||
|
|
||||||
if (!highlightTextShadowColor)
|
if (!highlightTextShadowColor)
|
||||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||||
|
|
||||||
if (_CPMenuBarSharedWindow)
|
if (_CPMenuBarSharedWindow)
|
||||||
{
|
{
|
||||||
@@ -230,14 +245,14 @@ var _CPMenuBarVisible = NO,
|
|||||||
- (float)menuBarHeight
|
- (float)menuBarHeight
|
||||||
{
|
{
|
||||||
if (self === [CPApp mainMenu])
|
if (self === [CPApp mainMenu])
|
||||||
return MENUBAR_HEIGHT;
|
return [CPMenu menuBarHeight];
|
||||||
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)menuBarHeight
|
+ (float)menuBarHeight
|
||||||
{
|
{
|
||||||
return MENUBAR_HEIGHT;
|
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-height" forClass:_CPMenuView];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a CPMenu Object
|
// Creating a CPMenu Object
|
||||||
@@ -275,7 +290,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
@param aMenuItem the item to insert
|
@param aMenuItem the item to insert
|
||||||
@param anIndex the index in the menu to insert the item.
|
@param anIndex the index in the menu to insert the item.
|
||||||
*/
|
*/
|
||||||
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
|
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
[self insertObject:aMenuItem inItemsAtIndex:anIndex];
|
[self insertObject:aMenuItem inItemsAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
@@ -288,7 +303,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
@param anIndex the index location in the menu for the new item
|
@param anIndex the index location in the menu for the new item
|
||||||
@return the new menu item
|
@return the new menu item
|
||||||
*/
|
*/
|
||||||
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
|
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
|
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
|
||||||
|
|
||||||
@@ -332,7 +347,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
Removes the item at the specified index from the menu
|
Removes the item at the specified index from the menu
|
||||||
@param anIndex the index of the item to remove
|
@param anIndex the index of the item to remove
|
||||||
*/
|
*/
|
||||||
- (void)removeItemAtIndex:(unsigned)anIndex
|
- (void)removeItemAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
[self removeObjectFromItemsAtIndex:anIndex];
|
[self removeObjectFromItemsAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
@@ -352,7 +367,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
while (count--)
|
while (count--)
|
||||||
[_items[count] setMenu:nil];
|
[_items[count] setMenu:nil];
|
||||||
|
|
||||||
_highlightedIndex = CPNotFound;
|
[self _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
// Because we are changing _items directly, be sure to notify KVO
|
// Because we are changing _items directly, be sure to notify KVO
|
||||||
[self willChangeValueForKey:@"items"];
|
[self willChangeValueForKey:@"items"];
|
||||||
@@ -366,7 +381,12 @@ var _CPMenuBarVisible = NO,
|
|||||||
*/
|
*/
|
||||||
- (void)itemChanged:(CPMenuItem)aMenuItem
|
- (void)itemChanged:(CPMenuItem)aMenuItem
|
||||||
{
|
{
|
||||||
if ([aMenuItem menu] !== self)
|
/*
|
||||||
|
During cib unarchiving, menu items will have a reference to their menu,
|
||||||
|
but of course the items are still being unarchived and the menu's _items
|
||||||
|
have not yet been instantiated. In that case we will not do anything here.
|
||||||
|
*/
|
||||||
|
if ([aMenuItem menu] !== self || !_items)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
|
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
|
||||||
@@ -374,7 +394,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
postNotificationName:CPMenuDidChangeItemNotification
|
postNotificationName:CPMenuDidChangeItemNotification
|
||||||
object:self
|
object:self
|
||||||
userInfo:[CPDictionary dictionaryWithObject:[_items indexOfObjectIdenticalTo:aMenuItem] forKey:@"CPMenuItemIndex"]];
|
userInfo:@{ @"CPMenuItemIndex": [_items indexOfObjectIdenticalTo:aMenuItem] }];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finding Menu Items
|
// Finding Menu Items
|
||||||
@@ -607,15 +627,17 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Enables or disables the receiver’s menu items.
|
Enables or disables the receiver’s menu items.
|
||||||
If the target does not implement the menu item's action method the item is disabled.
|
If the item has no target, an action binding is checked. If the target does not implement
|
||||||
If the target responsds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
|
the menu item's action method or the binding's selector, the item is disabled.
|
||||||
|
If the target responds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
|
||||||
*/
|
*/
|
||||||
- (void)update
|
- (void)update
|
||||||
{
|
{
|
||||||
if (![self autoenablesItems])
|
if (!_autoenablesItems)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var items = [self itemArray];
|
var items = [self itemArray];
|
||||||
|
|
||||||
for (var i = 0; i < [items count]; i++)
|
for (var i = 0; i < [items count]; i++)
|
||||||
{
|
{
|
||||||
var item = [items objectAtIndex:i];
|
var item = [items objectAtIndex:i];
|
||||||
@@ -623,14 +645,51 @@ var _CPMenuBarVisible = NO,
|
|||||||
if ([item hasSubmenu])
|
if ([item hasSubmenu])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
// If there are enabled bindings for the item, they override anything else
|
||||||
|
var binder = [CPBinder getBinding:CPEnabledBinding forObject:item];
|
||||||
|
|
||||||
if (!validator || ![validator respondsToSelector:[item action]])
|
if (binder)
|
||||||
[item setEnabled:NO];
|
{
|
||||||
|
[binder setValueFor:CPEnabledBinding];
|
||||||
|
[[_menuWindow _menuView] tile];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validator = [CPApp targetForAction:[item action] to:[item target] from:item],
|
||||||
|
shouldBeEnabled = YES;
|
||||||
|
|
||||||
|
if (!validator)
|
||||||
|
{
|
||||||
|
// If targetForAction: returns nil, it could be that there is no action.
|
||||||
|
// If there is an action and nil is returned, no valid target could be found.
|
||||||
|
if ([item action] || [item target])
|
||||||
|
shouldBeEnabled = NO;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check to see if there is a target binding with an invalid selector
|
||||||
|
var info = [CPBinder infoForBinding:CPTargetBinding forObject:item];
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
var object = [info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [info objectForKey:CPOptionsKey],
|
||||||
|
target = [object valueForKeyPath:keyPath],
|
||||||
|
selector = [options valueForKey:CPSelectorNameBindingOption];
|
||||||
|
|
||||||
|
if (target && selector && ![target respondsToSelector:CPSelectorFromString(selector)])
|
||||||
|
shouldBeEnabled = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (![validator respondsToSelector:[item action]])
|
||||||
|
shouldBeEnabled = NO;
|
||||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||||
[item setEnabled:[validator validateMenuItem:item]];
|
shouldBeEnabled = [validator validateMenuItem:item];
|
||||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
shouldBeEnabled = [validator validateUserInterfaceItem:item];
|
||||||
|
|
||||||
|
[item setEnabled:shouldBeEnabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[_menuWindow _menuView] tile];
|
[[_menuWindow _menuView] tile];
|
||||||
@@ -675,7 +734,13 @@ var _CPMenuBarVisible = NO,
|
|||||||
// highlightedItem is always enabled. Do there exist edge cases: disabling on closing a menu,
|
// highlightedItem is always enabled. Do there exist edge cases: disabling on closing a menu,
|
||||||
// etc.? Requires further investigation and tests.
|
// etc.? Requires further investigation and tests.
|
||||||
if (highlightedItem && [highlightedItem isEnabled])
|
if (highlightedItem && [highlightedItem isEnabled])
|
||||||
|
{
|
||||||
|
// Perform any action binding
|
||||||
|
var binding = [CPBinder getBinding:CPTargetBinding forObject:highlightedItem];
|
||||||
|
[binding invokeAction];
|
||||||
|
|
||||||
[CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
|
[CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -803,6 +868,9 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||||
{
|
{
|
||||||
|
// This is needed when we are making several rights click
|
||||||
|
[[_CPMenuManager sharedMenuManager] cancelActiveMenu];
|
||||||
|
|
||||||
[aMenu _menuWillOpen];
|
[aMenu _menuWillOpen];
|
||||||
|
|
||||||
if (!aFont)
|
if (!aFont)
|
||||||
@@ -886,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
|
||||||
@@ -898,18 +976,16 @@ 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
|
||||||
{
|
{
|
||||||
var delegate = [self delegate];
|
// Remember which event caused this menu to close, if any. CPPopUpButton uses this to detect
|
||||||
|
// when a click on the button itself caused the menu to close.
|
||||||
|
_lastCloseEvent = [CPApp currentEvent];
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
[self _sendDelegateMenuDidClose];
|
||||||
[delegate menuDidClose:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling Tracking
|
// Handling Tracking
|
||||||
@@ -925,7 +1001,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
{
|
{
|
||||||
[CPApp sendEvent:[CPEvent
|
[CPApp sendEvent:[CPEvent
|
||||||
otherEventWithType:CPAppKitDefined
|
otherEventWithType:CPAppKitDefined
|
||||||
location:_CGPointMakeZero()
|
location:CGPointMakeZero()
|
||||||
modifierFlags:0
|
modifierFlags:0
|
||||||
timestamp:0
|
timestamp:0
|
||||||
windowNumber:0
|
windowNumber:0
|
||||||
@@ -1002,7 +1078,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
Sends the action of the menu item at the specified index.
|
Sends the action of the menu item at the specified index.
|
||||||
@param anIndex the index of the item
|
@param anIndex the index of the item
|
||||||
*/
|
*/
|
||||||
- (void)performActionForItemAtIndex:(unsigned)anIndex
|
- (void)performActionForItemAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
var item = _items[anIndex];
|
var item = _items[anIndex];
|
||||||
|
|
||||||
@@ -1055,7 +1131,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_menuWithName:(CPString)aName
|
- (CPMenu)_menuWithName:(CPString)aName
|
||||||
{
|
{
|
||||||
if (aName === _name)
|
if (aName === _name)
|
||||||
return self;
|
return self;
|
||||||
@@ -1073,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
|
||||||
@@ -1105,12 +1211,13 @@ var _CPMenuBarVisible = NO,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[aMenuItem setMenu:self];
|
[aMenuItem setMenu:self];
|
||||||
|
[self _highlightItemAtIndex:CPNotFound];
|
||||||
[_items insertObject:aMenuItem atIndex:anIndex];
|
[_items insertObject:aMenuItem atIndex:anIndex];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
postNotificationName:CPMenuDidAddItemNotification
|
postNotificationName:CPMenuDidAddItemNotification
|
||||||
object:self
|
object:self
|
||||||
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
|
userInfo:@{ @"CPMenuItemIndex": anIndex }];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
|
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
|
||||||
@@ -1119,12 +1226,13 @@ var _CPMenuBarVisible = NO,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[[_items objectAtIndex:anIndex] setMenu:nil];
|
[[_items objectAtIndex:anIndex] setMenu:nil];
|
||||||
|
[self _highlightItemAtIndex:CPNotFound];
|
||||||
[_items removeObjectAtIndex:anIndex];
|
[_items removeObjectAtIndex:anIndex];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
postNotificationName:CPMenuDidRemoveItemNotification
|
postNotificationName:CPMenuDidRemoveItemNotification
|
||||||
object:self
|
object:self
|
||||||
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
|
userInfo:@{ @"CPMenuItemIndex": anIndex }];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -1132,7 +1240,8 @@ var _CPMenuBarVisible = NO,
|
|||||||
var CPMenuTitleKey = @"CPMenuTitleKey",
|
var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||||
CPMenuNameKey = @"CPMenuNameKey",
|
CPMenuNameKey = @"CPMenuNameKey",
|
||||||
CPMenuItemsKey = @"CPMenuItemsKey",
|
CPMenuItemsKey = @"CPMenuItemsKey",
|
||||||
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey";
|
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey",
|
||||||
|
CPMenuAutoEnablesItemsKey = @"CPMenuAutoEnablesItemsKey";
|
||||||
|
|
||||||
@implementation CPMenu (CPCoding)
|
@implementation CPMenu (CPCoding)
|
||||||
|
|
||||||
@@ -1154,7 +1263,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
|||||||
|
|
||||||
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
|
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
|
||||||
|
|
||||||
_autoenablesItems = YES;
|
_autoenablesItems = ![aCoder containsValueForKey:CPMenuAutoEnablesItemsKey] || [aCoder decodeBoolForKey:CPMenuAutoEnablesItemsKey];
|
||||||
|
|
||||||
[self setMinimumWidth:0];
|
[self setMinimumWidth:0];
|
||||||
}
|
}
|
||||||
@@ -1177,6 +1286,40 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
|||||||
|
|
||||||
if (!_showsStateColumn)
|
if (!_showsStateColumn)
|
||||||
[aCoder encodeBool:_showsStateColumn forKey:CPMenuShowsStateColumnKey];
|
[aCoder encodeBool:_showsStateColumn forKey:CPMenuShowsStateColumnKey];
|
||||||
|
|
||||||
|
if (!_autoenablesItems)
|
||||||
|
[aCoder encodeBool:_autoenablesItems forKey:CPMenuAutoEnablesItemsKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
@end
|
||||||
|
|||||||
@@ -1,18 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* _CPMenuBarWindow.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
@import "_CPMenuWindow.j"
|
@import "_CPMenuManager.j"
|
||||||
|
|
||||||
|
@class _CPMenuView
|
||||||
|
@class CPMenu
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
var MENUBAR_HEIGHT = 28.0,
|
@global CPMenuDidAddItemNotification
|
||||||
MENUBAR_MARGIN = 10.0,
|
@global CPMenuDidChangeItemNotification
|
||||||
MENUBAR_LEFT_MARGIN = 10.0,
|
@global CPMenuDidRemoveItemNotification
|
||||||
MENUBAR_RIGHT_MARGIN = 10.0;
|
|
||||||
|
|
||||||
var _CPMenuBarWindowBackgroundColor = nil,
|
@global document
|
||||||
_CPMenuBarWindowFont = nil;
|
|
||||||
|
|
||||||
@implementation _CPMenuBarWindow : CPPanel
|
@implementation _CPMenuBarWindow : CPPanel
|
||||||
{
|
{
|
||||||
CPMenu _menu;
|
|
||||||
CPView _highlightView;
|
CPView _highlightView;
|
||||||
CPArray _menuItemViews;
|
CPArray _menuItemViews;
|
||||||
|
|
||||||
@@ -32,19 +54,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
CPColor _highlightTextShadowColor;
|
CPColor _highlightTextShadowColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self !== [_CPMenuBarWindow class])
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:[CPFont systemFontSize]];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (CPFont)font
|
+ (CPFont)font
|
||||||
{
|
{
|
||||||
return _CPMenuBarWindowFont;
|
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-font" forClass:_CPMenuView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -52,12 +64,14 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
// This only shows up in browser land, so don't bother calculating metrics in desktop.
|
// This only shows up in browser land, so don't bother calculating metrics in desktop.
|
||||||
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
|
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
|
||||||
|
|
||||||
contentRect.size.height = MENUBAR_HEIGHT;
|
contentRect.size.height = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView];
|
||||||
|
|
||||||
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
|
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
_constrainsToUsableScreen = NO;
|
||||||
|
|
||||||
[self setLevel:CPMainMenuWindowLevel];
|
[self setLevel:CPMainMenuWindowLevel];
|
||||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||||
|
|
||||||
@@ -118,15 +132,12 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
- (void)setColor:(CPColor)aColor
|
- (void)setColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
if (!aColor)
|
var targetView = [[CPTheme defaultTheme] valueForAttributeWithName:@"css-based" forClass:CPView] ? [[self contentView] superview] : [self contentView];
|
||||||
{
|
|
||||||
if (!_CPMenuBarWindowBackgroundColor)
|
|
||||||
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
|
|
||||||
|
|
||||||
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
|
if (!aColor)
|
||||||
}
|
[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
|
||||||
@@ -137,6 +148,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
_textColor = aColor;
|
_textColor = aColor;
|
||||||
|
|
||||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextColor:) withObject:_textColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTitleColor:(CPColor)aColor
|
- (void)setTitleColor:(CPColor)aColor
|
||||||
@@ -157,6 +169,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
_textShadowColor = aColor;
|
_textShadowColor = aColor;
|
||||||
|
|
||||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextShadowColor:) withObject:_textShadowColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTitleShadowColor:(CPColor)aColor
|
- (void)setTitleShadowColor:(CPColor)aColor
|
||||||
@@ -175,6 +188,8 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_highlightColor = aColor;
|
_highlightColor = aColor;
|
||||||
|
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightColor:) withObject:_highlightColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setHighlightTextColor:(CPColor)aColor
|
- (void)setHighlightTextColor:(CPColor)aColor
|
||||||
@@ -184,7 +199,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
_highlightTextColor = aColor;
|
_highlightTextColor = aColor;
|
||||||
|
|
||||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextColor:) withObject:_highlightTextColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||||
@@ -194,7 +209,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
_highlightTextShadowColor = aColor;
|
_highlightTextShadowColor = aColor;
|
||||||
|
|
||||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextShadowColor:) withObject:_highlightTextShadowColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMenu:(CPMenu)aMenu
|
- (void)setMenu:(CPMenu)aMenu
|
||||||
@@ -267,6 +282,16 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
[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];
|
||||||
@@ -316,6 +341,11 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
|
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
|
||||||
@@ -335,7 +365,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
- (CPFont)font
|
- (CPFont)font
|
||||||
{
|
{
|
||||||
[CPFont systemFontOfSize:[CPFont systemFontSize]];
|
return [CPFont systemFontOfSize:[CPFont systemFontSize]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tile
|
- (void)tile
|
||||||
@@ -344,7 +374,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
index = 0,
|
index = 0,
|
||||||
count = items.length,
|
count = items.length,
|
||||||
|
|
||||||
x = MENUBAR_LEFT_MARGIN,
|
x = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-left-margin" forClass:_CPMenuView],
|
||||||
y = 0.0,
|
y = 0.0,
|
||||||
isLeftAligned = YES;
|
isLeftAligned = YES;
|
||||||
|
|
||||||
@@ -354,7 +384,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
if ([item isSeparatorItem])
|
if ([item isSeparatorItem])
|
||||||
{
|
{
|
||||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
x = CGRectGetWidth([self frame]) - [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-right-margin" forClass:_CPMenuView];
|
||||||
isLeftAligned = NO;
|
isLeftAligned = NO;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -368,13 +398,13 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
if (isLeftAligned)
|
if (isLeftAligned)
|
||||||
{
|
{
|
||||||
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView])];
|
||||||
|
|
||||||
x += CGRectGetWidth([menuItemView frame]);
|
x += CGRectGetWidth([menuItemView frame]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView])];
|
||||||
|
|
||||||
x = CGRectGetMinX([menuItemView frame]);
|
x = CGRectGetMinX([menuItemView frame]);
|
||||||
}
|
}
|
||||||
@@ -402,7 +432,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
||||||
|
|
||||||
if (!_CGSizeEqualToSize(size, aRect.size))
|
if (!CGSizeEqualToSize(size, aRect.size))
|
||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,102 +482,3 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPMenuBarView : _CPMenuView
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
|
||||||
{
|
|
||||||
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
|
||||||
{
|
|
||||||
var bounds = [self bounds];
|
|
||||||
|
|
||||||
if (!CGRectContainsPoint(bounds, aPoint))
|
|
||||||
return CPNotFound;
|
|
||||||
|
|
||||||
var x = aPoint.x,
|
|
||||||
low = 0,
|
|
||||||
high = _visibleMenuItemInfos.length - 1;
|
|
||||||
|
|
||||||
while (low <= high)
|
|
||||||
{
|
|
||||||
var middle = FLOOR(low + (high - low) / 2),
|
|
||||||
info = _visibleMenuItemInfos[middle],
|
|
||||||
frame = [info.view frame];
|
|
||||||
|
|
||||||
if (x < CGRectGetMinX(frame))
|
|
||||||
high = middle - 1;
|
|
||||||
|
|
||||||
else if (x > CGRectGetMaxX(frame))
|
|
||||||
low = middle + 1;
|
|
||||||
|
|
||||||
else
|
|
||||||
return info.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CPNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tile
|
|
||||||
{
|
|
||||||
var items = [_menu itemArray],
|
|
||||||
index = 0,
|
|
||||||
count = items.length,
|
|
||||||
|
|
||||||
x = MENUBAR_LEFT_MARGIN,
|
|
||||||
y = 0.0,
|
|
||||||
isLeftAligned = YES;
|
|
||||||
|
|
||||||
for (; index < count; ++index)
|
|
||||||
{
|
|
||||||
var item = items[index];
|
|
||||||
|
|
||||||
if ([item isSeparatorItem])
|
|
||||||
{
|
|
||||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
|
||||||
isLeftAligned = NO;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([item isHidden])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var menuItemView = [item _menuItemView],
|
|
||||||
frame = [menuItemView frame];
|
|
||||||
|
|
||||||
if (isLeftAligned)
|
|
||||||
{
|
|
||||||
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
|
||||||
|
|
||||||
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
|
||||||
|
|
||||||
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bounds = [[self contentView] bounds],
|
|
||||||
titleFrame = [_titleField frame];
|
|
||||||
|
|
||||||
if ([_iconImageView isHidden])
|
|
||||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var iconFrame = [_iconImageView frame],
|
|
||||||
iconWidth = CGRectGetWidth(iconFrame),
|
|
||||||
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
|
||||||
|
|
||||||
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
|
||||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|||||||
+143
-55
@@ -1,16 +1,53 @@
|
|||||||
@import <Foundation/CPObject.j>
|
/*
|
||||||
|
* _CPMenuManager.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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>
|
||||||
|
@import <Foundation/CPNotificationCenter.j>
|
||||||
|
|
||||||
|
@import "CPEvent.j"
|
||||||
|
@import "CPKeyBinding.j"
|
||||||
|
|
||||||
|
@class CPWindow
|
||||||
|
@class _CPMenuWindow
|
||||||
|
@class _CPMenuView
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
@global CPMenuDidEndTrackingNotification
|
||||||
|
@global _CPMenuWindowMenuBarBackgroundStyle
|
||||||
|
@global _CPMenuWindowPopUpBackgroundStyle
|
||||||
|
|
||||||
_CPMenuManagerScrollingStateUp = -1;
|
_CPMenuManagerScrollingStateUp = -1;
|
||||||
_CPMenuManagerScrollingStateDown = 1;
|
_CPMenuManagerScrollingStateDown = 1;
|
||||||
_CPMenuManagerScrollingStateNone = 0;
|
_CPMenuManagerScrollingStateNone = 0;
|
||||||
|
|
||||||
var STICKY_TIME_INTERVAL = 0.5,
|
var STICKY_TIME_INTERVAL = 0.4,
|
||||||
SharedMenuManager = nil;
|
SharedMenuManager = nil;
|
||||||
|
|
||||||
@implementation _CPMenuManager: CPObject
|
@implementation _CPMenuManager: CPObject
|
||||||
{
|
{
|
||||||
CPTimeInterval _startTime;
|
CPTimeInterval _startTime;
|
||||||
|
CPEvent _openEvent;
|
||||||
BOOL _mouseWasDragged;
|
BOOL _mouseWasDragged;
|
||||||
int _scrollingState;
|
int _scrollingState;
|
||||||
CGPoint _lastGlobalLocation;
|
CGPoint _lastGlobalLocation;
|
||||||
@@ -26,6 +63,8 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
|
|
||||||
CPMenuItem _previousActiveItem;
|
CPMenuItem _previousActiveItem;
|
||||||
int _showTimerID;
|
int _showTimerID;
|
||||||
|
|
||||||
|
int _menuBarButtonItemIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (_CPMenuManager)sharedMenuManager
|
+ (_CPMenuManager)sharedMenuManager
|
||||||
@@ -67,6 +106,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
CPApp._activeMenu = menu;
|
CPApp._activeMenu = menu;
|
||||||
|
|
||||||
_startTime = [anEvent timestamp];
|
_startTime = [anEvent timestamp];
|
||||||
|
_openEvent = anEvent;
|
||||||
_scrollingState = _CPMenuManagerScrollingStateNone;
|
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||||
|
|
||||||
_constraintRect = aRect;
|
_constraintRect = aRect;
|
||||||
@@ -85,7 +125,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
||||||
|
|
||||||
_menuBarButtonItemIndex = activeItemIndex;
|
_menuBarButtonItemIndex = activeItemIndex;
|
||||||
_menuBarButtonMenuContainer = aMenuContainer;
|
// _menuBarButtonMenuContainer = aMenuContainer;
|
||||||
|
|
||||||
if ([activeItem _isMenuBarButton])
|
if ([activeItem _isMenuBarButton])
|
||||||
return [self trackMenuBarButtonEvent:anEvent];
|
return [self trackMenuBarButtonEvent:anEvent];
|
||||||
@@ -96,6 +136,11 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
[self trackEvent:anEvent];
|
[self trackEvent:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_trackAgain
|
||||||
|
{
|
||||||
|
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseDownMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)trackEvent:(CPEvent)anEvent
|
- (void)trackEvent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var type = [anEvent type],
|
var type = [anEvent type],
|
||||||
@@ -105,8 +150,6 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
if (type === CPAppKitDefined)
|
if (type === CPAppKitDefined)
|
||||||
return [self completeTracking];
|
return [self completeTracking];
|
||||||
|
|
||||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
|
||||||
|
|
||||||
if (type === CPKeyDown)
|
if (type === CPKeyDown)
|
||||||
{
|
{
|
||||||
var menu = trackingMenu,
|
var menu = trackingMenu,
|
||||||
@@ -122,23 +165,18 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
if ([menu numberOfItems])
|
if ([menu numberOfItems])
|
||||||
[self interpretKeyEvent:anEvent forMenu:menu];
|
[self interpretKeyEvent:anEvent forMenu:menu];
|
||||||
|
|
||||||
|
[self _trackAgain];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_keyBuffer)
|
|
||||||
{
|
|
||||||
if (([anEvent timestamp] - _startTime) > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] / 2))
|
|
||||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:YES];
|
|
||||||
|
|
||||||
if (type === CPPeriodic)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Periodic events don't have a valid location.
|
// Periodic events don't have a valid location.
|
||||||
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
||||||
|
|
||||||
if (!globalLocation)
|
if (!globalLocation)
|
||||||
|
{
|
||||||
|
[self _trackAgain];
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Find which menu window the mouse is currently on top of
|
// Find which menu window the mouse is currently on top of
|
||||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||||
@@ -149,6 +187,35 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Click outside the menu structure?
|
||||||
|
|
||||||
|
The event which caused the menu to open is not considered even if it's
|
||||||
|
technically a click outside of an open menu, since this would mean the same
|
||||||
|
click which opened the menu could also close it. This is actually common.
|
||||||
|
E.g. you click on a button and it opens a menu below itself.
|
||||||
|
*/
|
||||||
|
if (type === CPLeftMouseDown && _openEvent !== anEvent && (!activeMenuContainer || !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation)))
|
||||||
|
{
|
||||||
|
[self completeTracking];
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can close and interact with a control in a single click. E.g. you can have a menu open,
|
||||||
|
click on a button outside of it and have the menu immediately close and the button activate,
|
||||||
|
without having to click once to close the menu and once to activate the button.
|
||||||
|
|
||||||
|
Since we normally dequeue the event after tracking it, we'll have to put it back on the stack
|
||||||
|
in this special case. Note that it's important the event is executed /right now/, since certain
|
||||||
|
controls such as HTML upload buttons need a native click event at the top of the stack trace
|
||||||
|
to activate - it's not something we can fake later.
|
||||||
|
*/
|
||||||
|
[CPApp sendEvent:anEvent];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _trackAgain];
|
||||||
|
|
||||||
// unhighlight when mouse is moved off the menu
|
// unhighlight when mouse is moved off the menu
|
||||||
if (_lastGlobalLocation && CGRectContainsPoint([activeMenuContainer globalFrame], _lastGlobalLocation)
|
if (_lastGlobalLocation && CGRectContainsPoint([activeMenuContainer globalFrame], _lastGlobalLocation)
|
||||||
&& !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation))
|
&& !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation))
|
||||||
@@ -158,7 +225,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
_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;
|
||||||
@@ -185,9 +252,9 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
|
|
||||||
if (_lastMouseOverMenuView != mouseOverMenuView)
|
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||||
{
|
{
|
||||||
[mouseOverMenuView mouseExited:anEvent];
|
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||||
// FIXME: Possibly multiple of these?
|
// FIXME: Possibly multiple of these?
|
||||||
[_lastMouseOverMenuView mouseEntered:anEvent];
|
[mouseOverMenuView mouseEntered:anEvent];
|
||||||
|
|
||||||
_lastMouseOverMenuView = mouseOverMenuView;
|
_lastMouseOverMenuView = mouseOverMenuView;
|
||||||
}
|
}
|
||||||
@@ -216,7 +283,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
_lastMouseOverMenuView = nil;
|
_lastMouseOverMenuView = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeItemIndex != CPNotFound)
|
if (activeItemIndex !== CPNotFound)
|
||||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||||
|
|
||||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
|
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
|
||||||
@@ -287,7 +354,23 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
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];
|
||||||
|
|
||||||
@@ -342,6 +425,15 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
[menu cancelTracking];
|
[menu cancelTracking];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)cancelActiveMenu
|
||||||
|
{
|
||||||
|
if (CPApp._activeMenu)
|
||||||
|
{
|
||||||
|
[self completeTracking];
|
||||||
|
_menuContainerStack = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)completeTracking
|
- (void)completeTracking
|
||||||
{
|
{
|
||||||
var trackingMenu = [self trackingMenu];
|
var trackingMenu = [self trackingMenu];
|
||||||
@@ -392,8 +484,8 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
{
|
{
|
||||||
var menuContainer = _menuContainerStack[index],
|
var menuContainer = _menuContainerStack[index],
|
||||||
menuContainerFrame = [menuContainer globalFrame],
|
menuContainerFrame = [menuContainer globalFrame],
|
||||||
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
|
menuContainerMinX = CGRectGetMinX(menuContainerFrame),
|
||||||
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
|
menuContainerMaxX = CGRectGetMaxX(menuContainerFrame);
|
||||||
|
|
||||||
// If within the x bounds of this menu container, return it.
|
// If within the x bounds of this menu container, return it.
|
||||||
if (x < menuContainerMaxX && x >= menuContainerMinX)
|
if (x < menuContainerMaxX && x >= menuContainerMinX)
|
||||||
@@ -479,7 +571,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
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);
|
||||||
|
|
||||||
@@ -489,6 +581,9 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
}
|
}
|
||||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
|
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
|
||||||
{
|
{
|
||||||
|
if (([anEvent timestamp] - _startTime) > STICKY_TIME_INTERVAL)
|
||||||
|
_keyBuffer = nil;
|
||||||
|
|
||||||
if (!_keyBuffer)
|
if (!_keyBuffer)
|
||||||
{
|
{
|
||||||
_startTime = [anEvent timestamp];
|
_startTime = [anEvent timestamp];
|
||||||
@@ -500,17 +595,19 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
else
|
else
|
||||||
_keyBuffer += character;
|
_keyBuffer += character;
|
||||||
|
|
||||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:NO];
|
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu];
|
||||||
_lastGlobalLocation = Nil;
|
_lastGlobalLocation = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu clearBuffer:(BOOL)shouldClear
|
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu
|
||||||
{
|
{
|
||||||
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;
|
||||||
@@ -522,13 +619,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldClear)
|
_startTime = [CPEvent currentTimestamp];
|
||||||
{
|
|
||||||
[CPEvent stopPeriodicEvents];
|
|
||||||
_keyBuffer = Nil;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_startTime = [CPEvent currentTimestamp];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollToBeginningOfDocument:(CPMenu)menu
|
- (void)scrollToBeginningOfDocument:(CPMenu)menu
|
||||||
@@ -556,7 +647,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next = current + (last - first);
|
var next = current + (last - first);
|
||||||
|
|
||||||
if (next < [menu numberOfItems])
|
if (next < [menu numberOfItems])
|
||||||
[menu _highlightItemAtIndex:next];
|
[menu _highlightItemAtIndex:next];
|
||||||
@@ -584,7 +675,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next = current - (last - first);
|
var next = current - (last - first);
|
||||||
|
|
||||||
if (next < 0)
|
if (next < 0)
|
||||||
[menu _highlightItemAtIndex:0];
|
[menu _highlightItemAtIndex:0];
|
||||||
@@ -654,35 +745,32 @@ var STICKY_TIME_INTERVAL = 0.5,
|
|||||||
|
|
||||||
- (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];
|
||||||
|
else if (menu == [CPApp mainMenu])
|
||||||
var item = [menu highlightedItem];
|
[menu _highlightItemAtIndex:0];
|
||||||
|
|
||||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
|
||||||
[self moveDown:menu];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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)
|
index--;
|
||||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[menu _highlightItemAtIndex:index];
|
|
||||||
|
|
||||||
var item = [menu highlightedItem];
|
if (index >= 0)
|
||||||
|
[menu _highlightItemAtIndex:index];
|
||||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
else if (menu == [CPApp mainMenu])
|
||||||
[self moveUp:menu];
|
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertNewline:(CPMenu)menu
|
- (void)insertNewline:(CPMenu)menu
|
||||||
|
|||||||
+142
-82
@@ -1,5 +1,32 @@
|
|||||||
@import "CPWindow.j"
|
/*
|
||||||
|
* _CPMenuWindow.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPClipView.j"
|
||||||
|
@import "CPImageView.j"
|
||||||
|
@import "CPWindow.j"
|
||||||
|
@import "_CPMenuManager.j"
|
||||||
|
|
||||||
|
@class _CPMenuView
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
var _CPMenuWindowPool = [],
|
var _CPMenuWindowPool = [],
|
||||||
_CPMenuWindowPoolCapacity = 5,
|
_CPMenuWindowPoolCapacity = 5,
|
||||||
@@ -10,15 +37,6 @@ _CPMenuWindowMenuBarBackgroundStyle = 0;
|
|||||||
_CPMenuWindowPopUpBackgroundStyle = 1;
|
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||||
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||||
|
|
||||||
var STICKY_TIME_INTERVAL = 500,
|
|
||||||
|
|
||||||
TOP_MARGIN = 5.0,
|
|
||||||
LEFT_MARGIN = 1.0,
|
|
||||||
RIGHT_MARGIN = 1.0,
|
|
||||||
BOTTOM_MARGIN = 5.0,
|
|
||||||
|
|
||||||
SCROLL_INDICATOR_HEIGHT = 16.0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
@@ -57,32 +75,24 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
|
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
|
||||||
{
|
{
|
||||||
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
|
// FIXME :the poolMenuWindow is called too many times somewhere....
|
||||||
|
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity || [_CPMenuWindowPool containsObject:aMenuWindow])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_CPMenuWindowPool.push(aMenuWindow);
|
_CPMenuWindowPool.push(aMenuWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self !== [_CPMenuWindow class])
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
|
|
||||||
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
||||||
{
|
{
|
||||||
_constraintRect = _CGRectMakeZero();
|
_constraintRect = CGRectMakeZero();
|
||||||
_unconstrainedFrame = _CGRectMakeZero();
|
_unconstrainedFrame = CGRectMakeZero();
|
||||||
|
|
||||||
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
|
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
_constrainsToUsableScreen = NO;
|
||||||
|
|
||||||
[self setLevel:CPPopUpMenuWindowLevel];
|
[self setLevel:CPPopUpMenuWindowLevel];
|
||||||
[self setHasShadow:YES];
|
[self setHasShadow:YES];
|
||||||
[self setShadowStyle:CPMenuWindowShadowStyle];
|
[self setShadowStyle:CPMenuWindowShadowStyle];
|
||||||
@@ -92,22 +102,22 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
|
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake([_menuView valueForThemeAttribute:@"menu-window-margin-inset"].left, [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top, 0.0, 0.0)];
|
||||||
[_menuClipView setDocumentView:_menuView];
|
[_menuClipView setDocumentView:_menuView];
|
||||||
|
|
||||||
[contentView addSubview:_menuClipView];
|
[contentView addSubview:_menuClipView];
|
||||||
|
|
||||||
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
|
[_moreAboveView setImage:[_menuView valueForThemeAttribute:@"menu-window-more-above-image"]];
|
||||||
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
|
[_moreAboveView setFrameSize:[[_menuView valueForThemeAttribute:@"menu-window-more-above-image"] size]];
|
||||||
|
|
||||||
[contentView addSubview:_moreAboveView];
|
[contentView addSubview:_moreAboveView];
|
||||||
|
|
||||||
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
|
[_moreBelowView setImage:[_menuView valueForThemeAttribute:@"menu-window-more-below-image"]];
|
||||||
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
|
[_moreBelowView setFrameSize:[[_menuView valueForThemeAttribute:@"menu-window-more-below-image"] size]];
|
||||||
|
|
||||||
[contentView addSubview:_moreBelowView];
|
[contentView addSubview:_moreBelowView];
|
||||||
}
|
}
|
||||||
@@ -117,7 +127,7 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
+ (float)_standardLeftMargin
|
+ (float)_standardLeftMargin
|
||||||
{
|
{
|
||||||
return LEFT_MARGIN;
|
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-margin-inset" forClass:_CPMenuView].left;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFont:(CPFont)aFont
|
- (void)setFont:(CPFont)aFont
|
||||||
@@ -139,36 +149,10 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
var bundle = [CPBundle bundleForClass:[self class]];
|
var bundle = [CPBundle bundleForClass:[self class]];
|
||||||
|
|
||||||
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
|
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
|
||||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
color = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-pop-up-background-style-color" forClass:_CPMenuView];
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
|
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
|
||||||
]]];
|
|
||||||
|
|
||||||
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
||||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
color = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-menu-bar-background-style-color" forClass:_CPMenuView];
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
|
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
|
||||||
]]];
|
|
||||||
|
|
||||||
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
||||||
}
|
}
|
||||||
@@ -186,12 +170,13 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
[aMenu _setMenuWindow:self];
|
[aMenu _setMenuWindow:self];
|
||||||
[_menuView setMenu:aMenu];
|
[_menuView setMenu:aMenu];
|
||||||
|
|
||||||
var menuViewSize = [_menuView frame].size;
|
var menuViewSize = [_menuView frame].size,
|
||||||
|
marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"];
|
||||||
|
|
||||||
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
|
[self setFrameSize:CGSizeMake(marginInset.left + menuViewSize.width + marginInset.right, marginInset.top + menuViewSize.height + marginInset.bottom)];
|
||||||
|
|
||||||
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
||||||
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
|
[_menuClipView setFrame:CGRectMake(marginInset.left, marginInset.top, menuViewSize.width, menuViewSize.height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinWidth:(float)aWidth
|
- (void)setMinWidth:(float)aWidth
|
||||||
@@ -228,28 +213,30 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
- (CGRect)unconstrainedFrame
|
- (CGRect)unconstrainedFrame
|
||||||
{
|
{
|
||||||
return _CGRectMakeCopy(_unconstrainedFrame);
|
return CGRectMakeCopy(_unconstrainedFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
|
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
|
||||||
// the constrained frame into the unconstrained frame.
|
// the constrained frame into the unconstrained frame.
|
||||||
- (void)setFrameOrigin:(CGPoint)aPoint
|
- (void)setFrameOrigin:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
[super setFrame:_CGRectMake(aPoint.x, aPoint.y, _CGRectGetWidth(_unconstrainedFrame), _CGRectGetHeight(_unconstrainedFrame))];
|
[super setFrame:CGRectMake(aPoint.x, aPoint.y, CGRectGetWidth(_unconstrainedFrame), CGRectGetHeight(_unconstrainedFrame))];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrameSize:(CGSize)aSize
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[super setFrame:_CGRectMake(_CGRectGetMinX(_unconstrainedFrame), _CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
|
[super setFrame:CGRectMake(CGRectGetMinX(_unconstrainedFrame), CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||||
{
|
{
|
||||||
// FIXME: There are integral window issues with platform windows.
|
// FIXME: There are integral window issues with platform windows.
|
||||||
// FIXME: This gets called far too often.
|
// FIXME: This gets called far too often.
|
||||||
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
|
_unconstrainedFrame = CGRectMakeCopy(aFrame);
|
||||||
|
|
||||||
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect);
|
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect),
|
||||||
|
marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"],
|
||||||
|
scrollIndicatorHeight = [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"];
|
||||||
|
|
||||||
// We don't want to simply intersect the visible frame and the unconstrained frame.
|
// We don't want to simply intersect the visible frame and the unconstrained frame.
|
||||||
// We should be allowing as much of the width to fit as possible (pushing back and forward).
|
// We should be allowing as much of the width to fit as possible (pushing back and forward).
|
||||||
@@ -268,41 +255,41 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
|
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
|
||||||
|
|
||||||
// This needs to happen before changing the frame.
|
// This needs to happen before changing the frame.
|
||||||
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
|
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + marginInset.left, CGRectGetMinY(aFrame) + marginInset.top),
|
||||||
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
|
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + marginInset.top,
|
||||||
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
|
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - marginInset.bottom,
|
||||||
|
|
||||||
topMargin = TOP_MARGIN,
|
topMargin = marginInset.top,
|
||||||
bottomMargin = BOTTOM_MARGIN,
|
bottomMargin = marginInset.bottom,
|
||||||
|
|
||||||
contentView = [self contentView],
|
contentView = [self contentView],
|
||||||
bounds = [contentView bounds];
|
bounds = [contentView bounds];
|
||||||
|
|
||||||
if (moreAbove)
|
if (moreAbove)
|
||||||
{
|
{
|
||||||
topMargin += SCROLL_INDICATOR_HEIGHT;
|
topMargin += scrollIndicatorHeight;
|
||||||
|
|
||||||
var frame = [_moreAboveView frame];
|
var frame = [_moreAboveView frame];
|
||||||
|
|
||||||
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
|
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (marginInset.top + scrollIndicatorHeight - CGRectGetHeight(frame)) / 2.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_moreAboveView setHidden:!moreAbove];
|
[_moreAboveView setHidden:!moreAbove];
|
||||||
|
|
||||||
if (moreBelow)
|
if (moreBelow)
|
||||||
{
|
{
|
||||||
bottomMargin += SCROLL_INDICATOR_HEIGHT;
|
bottomMargin += scrollIndicatorHeight;
|
||||||
|
|
||||||
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
|
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - scrollIndicatorHeight - marginInset.bottom)];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_moreBelowView setHidden:!moreBelow];
|
[_moreBelowView setHidden:!moreBelow];
|
||||||
|
|
||||||
var clipFrame = CGRectMakeZero();
|
var clipFrame = CGRectMakeZero();
|
||||||
|
|
||||||
clipFrame.origin.x = LEFT_MARGIN;
|
clipFrame.origin.x = marginInset.left;
|
||||||
clipFrame.origin.y = topMargin;
|
clipFrame.origin.y = topMargin;
|
||||||
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN;
|
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - marginInset.left - marginInset.right;
|
||||||
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
|
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
|
||||||
|
|
||||||
[_menuClipView setFrame:clipFrame];
|
[_menuClipView setFrame:clipFrame];
|
||||||
@@ -398,15 +385,15 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||||
{
|
{
|
||||||
var frame = [self frame];
|
var frame = [self frame];
|
||||||
if (!CPRectContainsPoint(frame,aGlobalLocation) || ![self canScroll])
|
if (!CGRectContainsPoint(frame,aGlobalLocation) || ![self canScroll])
|
||||||
return _CPMenuManagerScrollingStateNone;
|
return _CPMenuManagerScrollingStateNone;
|
||||||
|
|
||||||
// If we're at or above of the top scroll indicator...
|
// If we're at or above of the top scroll indicator...
|
||||||
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT && ![_moreAboveView isHidden])
|
if (aGlobalLocation.y < CGRectGetMinY(frame) + [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top + [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"] && ![_moreAboveView isHidden])
|
||||||
return _CPMenuManagerScrollingStateUp;
|
return _CPMenuManagerScrollingStateUp;
|
||||||
|
|
||||||
// If we're at or below the bottom scroll indicator...
|
// If we're at or below the bottom scroll indicator...
|
||||||
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT && ![_moreBelowView isHidden])
|
if (aGlobalLocation.y > CGRectGetMaxY(frame) - [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].bottom - [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"] && ![_moreBelowView isHidden])
|
||||||
return _CPMenuManagerScrollingStateDown;
|
return _CPMenuManagerScrollingStateDown;
|
||||||
|
|
||||||
return _CPMenuManagerScrollingStateNone;
|
return _CPMenuManagerScrollingStateNone;
|
||||||
@@ -414,7 +401,7 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
- (float)deltaYForItemAtIndex:(int)anIndex
|
- (float)deltaYForItemAtIndex:(int)anIndex
|
||||||
{
|
{
|
||||||
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
return [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)rectForItemAtIndex:(int)anIndex
|
- (CGPoint)rectForItemAtIndex:(int)anIndex
|
||||||
@@ -426,13 +413,28 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
{
|
{
|
||||||
// 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
|
||||||
*/
|
*/
|
||||||
@@ -445,6 +447,48 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
CPFont _font @accessors(property=font);
|
CPFont _font @accessors(property=font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return "menu-view";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"menu-window-more-above-image": [CPNull null],
|
||||||
|
@"menu-window-more-below-image": [CPNull null],
|
||||||
|
@"menu-window-pop-up-background-style-color": [CPNull null],
|
||||||
|
@"menu-window-menu-bar-background-style-color": [CPNull null],
|
||||||
|
@"menu-window-margin-inset": CGInsetMake(5.0, 1.0, 1.0, 5.0),
|
||||||
|
@"menu-window-scroll-indicator-height": 16.0,
|
||||||
|
@"menu-bar-window-background-color": [CPNull null],
|
||||||
|
@"menu-bar-window-background-selected-color": [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-margin": 10.0,
|
||||||
|
@"menu-bar-window-left-margin": 10.0,
|
||||||
|
@"menu-bar-window-right-margin": 10.0,
|
||||||
|
@"menu-bar-text-color": [CPNull null],
|
||||||
|
@"menu-bar-title-color": [CPNull null],
|
||||||
|
@"menu-bar-text-shadow-color": [CPNull null],
|
||||||
|
@"menu-bar-title-shadow-color": [CPNull null],
|
||||||
|
@"menu-bar-highlight-color": [CPNull null],
|
||||||
|
@"menu-bar-highlight-text-color": [CPNull null],
|
||||||
|
@"menu-bar-highlight-text-shadow-color": [CPNull null],
|
||||||
|
@"menu-bar-height": 28.0,
|
||||||
|
@"menu-bar-icon-image": [CPNull null],
|
||||||
|
@"menu-bar-icon-image-alpha-value": 1.0,
|
||||||
|
@"menu-general-icon-new": [CPNull null],
|
||||||
|
@"menu-general-icon-save": [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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
- (unsigned)numberOfUnhiddenItems
|
- (unsigned)numberOfUnhiddenItems
|
||||||
{
|
{
|
||||||
return _visibleMenuItemInfos.length;
|
return _visibleMenuItemInfos.length;
|
||||||
@@ -528,6 +572,7 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
|
|
||||||
[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],
|
||||||
@@ -558,3 +603,18 @@ var STICKY_TIME_INTERVAL = 500,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@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
|
||||||
|
|||||||
@@ -25,29 +25,33 @@
|
|||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPMenu.j"
|
@import "CPText.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
@import "_CPMenuItemView.j"
|
@import "_CPMenuItemView.j"
|
||||||
|
|
||||||
|
@class CPMenu
|
||||||
|
|
||||||
var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
@global CPApp
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u238B" forKey:CPEscapeFunctionKey];
|
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21E5" forKey:CPTabCharacter];
|
var CPMenuItemStringRepresentationDictionary = @{
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21E4" forKey:CPBackTabCharacter];
|
CPEscapeFunctionKey: "\u238B",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2423" forKey:CPSpaceFunctionKey];
|
CPTabCharacter: "\u21E5",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u23CE" forKey:CPCarriageReturnCharacter];
|
CPBackTabCharacter: "\u21E4",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPBackspaceCharacter];
|
CPSpaceFunctionKey: "\u2423",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPDeleteFunctionKey];
|
CPCarriageReturnCharacter: "\u23CE",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2326" forKey:CPDeleteCharacter];
|
CPBackspaceCharacter: "\u232B",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21F1" forKey:CPHomeFunctionKey];
|
CPDeleteFunctionKey: "\u232B",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21F2" forKey:CPEndFunctionKey];
|
CPDeleteCharacter: "\u2326",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21DE" forKey:CPPageUpFunctionKey];
|
CPHomeFunctionKey: "\u21F1",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21DF" forKey:CPPageDownFunctionKey];
|
CPEndFunctionKey: "\u21F2",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2191" forKey:CPUpArrowFunctionKey];
|
CPPageUpFunctionKey: "\u21DE",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2193" forKey:CPDownArrowFunctionKey];
|
CPPageDownFunctionKey: "\u21DF",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2190" forKey:CPLeftArrowFunctionKey];
|
CPUpArrowFunctionKey: "\u2191",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2192" forKey:CPRightArrowFunctionKey];
|
CPDownArrowFunctionKey: "\u2193",
|
||||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2327" forKey:CPClearDisplayFunctionKey];
|
CPLeftArrowFunctionKey: "\u2190",
|
||||||
|
CPRightArrowFunctionKey: "\u2192",
|
||||||
|
CPClearDisplayFunctionKey: "\u2327",
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -101,6 +105,16 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
|||||||
_CPMenuItemView _menuItemView;
|
_CPMenuItemView _menuItemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if ([aBinding hasPrefix:CPEnabledBinding])
|
||||||
|
return [CPMultipleValueAndBinding class];
|
||||||
|
else if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
|
||||||
|
return [CPActionBinding class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
return [self initWithTitle:@"" action:nil keyEquivalent:nil];
|
return [self initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||||
@@ -152,6 +166,9 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
|||||||
if (_isEnabled === isEnabled)
|
if (_isEnabled === isEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!isEnabled && [self isHighlighted])
|
||||||
|
[_menu _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
_isEnabled = !!isEnabled;
|
_isEnabled = !!isEnabled;
|
||||||
|
|
||||||
[_menuItemView setDirty];
|
[_menuItemView setDirty];
|
||||||
@@ -488,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:)];
|
||||||
@@ -826,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];
|
||||||
@@ -880,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",
|
||||||
@@ -894,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",
|
||||||
@@ -938,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];
|
||||||
@@ -986,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);
|
||||||
|
|||||||
@@ -1,54 +1,62 @@
|
|||||||
@import "CPView.j"
|
/*
|
||||||
|
* _CPMenuItemMenuBarView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPControl.j"
|
||||||
|
@import "_CPImageAndTextView.j"
|
||||||
|
|
||||||
var HORIZONTAL_MARGIN = 8.0,
|
@class _CPMenuBarWindow
|
||||||
SUBMENU_INDICATOR_MARGIN = 3.0,
|
@class _CPMenuView
|
||||||
VERTICAL_MARGIN = 4.0;
|
@class CPMenuItem
|
||||||
|
|
||||||
var SelectionColor = nil,
|
|
||||||
SUBMENU_INDICATOR_COLOR = nil,
|
|
||||||
_CPMenuItemSelectionColor = nil,
|
|
||||||
_CPMenuItemTextShadowColor = nil,
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages = [],
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
|
||||||
|
|
||||||
@implementation _CPMenuItemMenuBarView : CPView
|
@implementation _CPMenuItemMenuBarView : CPView
|
||||||
{
|
{
|
||||||
|
CPColor _highlightColor @accessors(property=highlightColor);
|
||||||
|
CPColor _textColor @accessors(property=textColor);
|
||||||
|
CPColor _textShadowColor @accessors(property=textShadowColor);
|
||||||
|
CPColor _highlightTextColor @accessors(property=highlightTextColor);
|
||||||
|
CPColor _highlightTextShadowColor @accessors(property=highlightTextShadowColor);
|
||||||
|
|
||||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||||
|
|
||||||
CPFont _font;
|
CPFont _font;
|
||||||
CPColor _textColor;
|
|
||||||
CPColor _textShadowColor;
|
|
||||||
|
|
||||||
BOOL _isDirty;
|
BOOL _isDirty;
|
||||||
|
BOOL _shouldHighlight;
|
||||||
|
|
||||||
_CPImageAndTextView _imageAndTextView;
|
_CPImageAndTextView _imageAndTextView;
|
||||||
CPView _submenuIndicatorView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self !== [_CPMenuItemMenuBarView class])
|
return "menu-item-bar-view";
|
||||||
return;
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
|
return @{
|
||||||
|
@"horizontal-margin": 9.0,
|
||||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
@"submenu-indicator-margin": 3.0,
|
||||||
|
@"vertical-margin": 4.0,
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
};
|
||||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)view
|
+ (id)view
|
||||||
@@ -62,7 +70,7 @@ var SelectionColor = nil,
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake([self valueForThemeAttribute:@"horizontal-margin"], 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||||
[_imageAndTextView setImageOffset:3.0];
|
[_imageAndTextView setImageOffset:3.0];
|
||||||
@@ -71,86 +79,98 @@ var SelectionColor = nil,
|
|||||||
|
|
||||||
[self addSubview:_imageAndTextView];
|
[self addSubview:_imageAndTextView];
|
||||||
|
|
||||||
_submenuIndicatorView = [[_CPMenuItemMenuBarSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 9.0, 6.0)];
|
|
||||||
|
|
||||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
|
||||||
|
|
||||||
[self addSubview:_submenuIndicatorView];
|
|
||||||
|
|
||||||
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
_textColor = aColor;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
_textShadowColor = aColor;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlightTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
_highlightTextColor = aColor;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
_highlightTextShadowColor = aColor;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
- (CPColor)textColor
|
- (CPColor)textColor
|
||||||
{
|
{
|
||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return [CPColor lightGrayColor];
|
return [CPColor lightGrayColor];
|
||||||
|
|
||||||
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
return _textColor || [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-color" forClass:_CPMenuView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPColor)textShadowColor
|
- (CPColor)textShadowColor
|
||||||
{
|
{
|
||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return [CPColor colorWithWhite:0.8 alpha:0.8];
|
return [CPColor clearColor];
|
||||||
|
|
||||||
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
return _textShadowColor || [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-shadow-color" forClass:_CPMenuView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)highlightTextColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return [CPColor lightGrayColor];
|
||||||
|
|
||||||
|
return _highlightTextColor || [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-color" forClass:_CPMenuView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)highlightTextShadowColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return [CPColor clearColor];
|
||||||
|
|
||||||
|
return _highlightTextShadowColor || [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-shadow-color" forClass:_CPMenuView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)highlightColor
|
||||||
|
{
|
||||||
|
return _highlightColor || [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-background-selected-color" forClass:_CPMenuView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)update
|
- (void)update
|
||||||
{
|
{
|
||||||
var x = HORIZONTAL_MARGIN,
|
var x = [self valueForThemeAttribute:@"horizontal-margin"],
|
||||||
height = 0.0;
|
height = 0.0;
|
||||||
|
|
||||||
|
[_imageAndTextView setText:[_menuItem title]];
|
||||||
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
|
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
|
||||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
[_imageAndTextView setImage:[_menuItem image]];
|
|
||||||
[_imageAndTextView setText:[_menuItem title]];
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
|
||||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_imageAndTextView sizeToFit];
|
[_imageAndTextView sizeToFit];
|
||||||
|
|
||||||
var imageAndTextViewFrame = [_imageAndTextView frame];
|
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||||
|
|
||||||
imageAndTextViewFrame.origin.x = x;
|
imageAndTextViewFrame.origin.x = x;
|
||||||
x += CGRectGetWidth(imageAndTextViewFrame);
|
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame)) + 2.0 * [self valueForThemeAttribute:@"vertical-margin"];
|
||||||
|
|
||||||
var hasSubmenuIndicator = [_menuItem hasSubmenu] && [_menuItem action];
|
|
||||||
|
|
||||||
if (hasSubmenuIndicator)
|
|
||||||
{
|
|
||||||
[_submenuIndicatorView setHidden:NO];
|
|
||||||
[_submenuIndicatorView setColor:[self textColor]];
|
|
||||||
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
|
||||||
|
|
||||||
var submenuViewFrame = [_submenuIndicatorView frame];
|
|
||||||
|
|
||||||
submenuViewFrame.origin.x = x + SUBMENU_INDICATOR_MARGIN;
|
|
||||||
|
|
||||||
x = CGRectGetMaxX(submenuViewFrame);
|
|
||||||
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[_submenuIndicatorView setHidden:YES];
|
|
||||||
|
|
||||||
height += 2.0 * VERTICAL_MARGIN;
|
|
||||||
|
|
||||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||||
|
|
||||||
if (hasSubmenuIndicator)
|
|
||||||
{
|
|
||||||
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
|
|
||||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self setAutoresizesSubviews:NO];
|
[self setAutoresizesSubviews:NO];
|
||||||
[self setFrameSize:CGSizeMake(x + HORIZONTAL_MARGIN, height)];
|
[self setFrameSize:CGSizeMake(x + [self valueForThemeAttribute:@"horizontal-margin"], height)];
|
||||||
[self setAutoresizesSubviews:YES];
|
[self setAutoresizesSubviews:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)highlight:(BOOL)shouldHighlight
|
- (void)highlight:(BOOL)shouldHighlight
|
||||||
@@ -159,17 +179,20 @@ var SelectionColor = nil,
|
|||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
shouldHighlight = NO;
|
shouldHighlight = NO;
|
||||||
|
|
||||||
if (shouldHighlight)
|
_shouldHighlight = shouldHighlight;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if (_shouldHighlight)
|
||||||
{
|
{
|
||||||
if (![_menuItem _isMenuBarButton])
|
if (![_menuItem _isMenuBarButton])
|
||||||
[self setBackgroundColor:SelectionColor];
|
[self setBackgroundColor:[self highlightColor]];
|
||||||
|
|
||||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
[_imageAndTextView setTextColor:[self highlightTextColor]];
|
||||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
[_imageAndTextView setTextShadowColor:[self highlightTextShadowColor]];
|
||||||
|
|
||||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
|
||||||
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -178,60 +201,7 @@ var SelectionColor = nil,
|
|||||||
[_imageAndTextView setImage:[_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
|
||||||
[_submenuIndicatorView setColor:[self textColor]];
|
|
||||||
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPMenuItemMenuBarSubmenuIndicatorView : CPView
|
|
||||||
{
|
|
||||||
CPColor _color;
|
|
||||||
CPColor _shadowColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_color === aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_color = aColor;
|
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setShadowColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_shadowColor === aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_shadowColor = aColor;
|
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
|
||||||
{
|
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
|
||||||
bounds = [self bounds];
|
|
||||||
|
|
||||||
bounds.size.height -= 1.0;
|
|
||||||
bounds.size.width -= 2.0;
|
|
||||||
bounds.origin.x += 1.0;
|
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
|
||||||
|
|
||||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
|
||||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
|
|
||||||
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
|
|
||||||
|
|
||||||
CGContextClosePath(context);
|
|
||||||
|
|
||||||
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
|
|
||||||
CGContextSetFillColor(context, _color || [CPColor blackColor]);
|
|
||||||
CGContextFillPath(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|||||||
@@ -1,6 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* _CPMenuItemSeparatorView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@class _CPMenuItemStandardView
|
||||||
|
|
||||||
|
|
||||||
@implementation _CPMenuItemSeparatorView : CPView
|
@implementation _CPMenuItemSeparatorView : CPView
|
||||||
{
|
{
|
||||||
@@ -8,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
|
||||||
@@ -24,15 +49,28 @@
|
|||||||
- (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);
|
|
||||||
|
|
||||||
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
|
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]);
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,59 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* _CPMenuItemStandardView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
@import "CPImageView.j"
|
||||||
|
@import "_CPImageAndTextView.j"
|
||||||
|
|
||||||
|
@class CPMenuItem
|
||||||
|
|
||||||
var LEFT_MARGIN = 3.0,
|
|
||||||
RIGHT_MARGIN = 14.0 + 3.0,
|
|
||||||
STATE_COLUMN_WIDTH = 14.0,
|
|
||||||
INDENTATION_WIDTH = 17.0,
|
|
||||||
VERTICAL_MARGIN = 4.0,
|
|
||||||
|
|
||||||
RIGHT_COLUMNS_MARGIN = 30.0,
|
|
||||||
KEY_EQUIVALENT_MARGIN = 10.0;
|
|
||||||
|
|
||||||
var SUBMENU_INDICATOR_COLOR = nil,
|
|
||||||
_CPMenuItemSelectionColor = nil,
|
|
||||||
_CPMenuItemTextShadowColor = nil,
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages = [],
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
|
||||||
|
|
||||||
@implementation _CPMenuItemStandardView : CPView
|
@implementation _CPMenuItemStandardView : CPView
|
||||||
{
|
{
|
||||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||||
|
|
||||||
CPFont _font;
|
CPFont _font;
|
||||||
CPColor _textColor;
|
|
||||||
CPColor _textShadowColor;
|
|
||||||
|
|
||||||
CGSize _minSize @accessors(readonly, property=minSize);
|
CGSize _minSize @accessors(readonly, property=minSize);
|
||||||
BOOL _isDirty;
|
BOOL _isDirty;
|
||||||
|
BOOL _highlighted;
|
||||||
|
|
||||||
CPImageView _stateView;
|
CPImageView _stateView;
|
||||||
_CPImageAndTextView _imageAndTextView;
|
_CPImageAndTextView _imageAndTextView;
|
||||||
_CPImageAndTextView _keyEquivalentView;
|
_CPImageAndTextView _keyEquivalentView;
|
||||||
CPView _submenuIndicatorView;
|
CPView _submenuIndicatorView;
|
||||||
|
|
||||||
|
BOOL _hasSubmenuIndicatorImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self !== [_CPMenuItemStandardView class])
|
return "menu-item-standard-view";
|
||||||
return;
|
}
|
||||||
|
|
||||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
return @{
|
||||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
@"submenu-indicator-color": [CPNull null],
|
||||||
|
@"menu-item-selection-color": [CPNull null],
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
@"menu-item-text-shadow-color": [CPNull null],
|
||||||
|
@"menu-item-text-color": [CPNull null],
|
||||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
@"menu-item-disabled-text-color": [CPColor lightGrayColor],
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
@"menu-item-default-off-state-image": [CPNull null],
|
||||||
|
@"menu-item-default-off-state-highlighted-image": [CPNull null],
|
||||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
@"menu-item-default-on-state-image": [CPNull null],
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
@"menu-item-default-on-state-highlighted-image": [CPNull null],
|
||||||
|
@"menu-item-default-mixed-state-image": [CPNull null],
|
||||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
@"menu-item-default-mixed-state-highlighted-image": [CPNull null],
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
@"menu-item-separator-color": [CPNull null],
|
||||||
|
@"menu-item-separator-height": 1.0,
|
||||||
|
@"menu-item-separator-view-height": 10.0,
|
||||||
|
@"left-margin": 3.0,
|
||||||
|
@"right-margin": 17.0,
|
||||||
|
@"state-column-width": 14.0,
|
||||||
|
@"indentation-width": 17.0,
|
||||||
|
@"vertical-margin": 4.0,
|
||||||
|
@"vertical-offset": 0.0,
|
||||||
|
@"right-columns-margin": 30.0,
|
||||||
|
@"submenu-indicator-image": [CPNull null],
|
||||||
|
@"submenu-indicator-highlighted-image": [CPNull null]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)view
|
+ (id)view
|
||||||
@@ -63,7 +86,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
|
|
||||||
+ (float)_standardLeftMargin
|
+ (float)_standardLeftMargin
|
||||||
{
|
{
|
||||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
return [[CPTheme defaultTheme] valueForAttributeWithName:@"left-margin" forClass:[self class]] + [[CPTheme defaultTheme] valueForAttributeWithName:@"state-column-width" forClass:[self class]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -75,6 +98,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
_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];
|
||||||
|
|
||||||
@@ -93,9 +117,24 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
|
|
||||||
[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:SUBMENU_INDICATOR_COLOR];
|
|
||||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
|
||||||
[self addSubview:_submenuIndicatorView];
|
[self addSubview:_submenuIndicatorView];
|
||||||
@@ -109,9 +148,12 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
- (CPColor)textColor
|
- (CPColor)textColor
|
||||||
{
|
{
|
||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return [CPColor lightGrayColor];
|
return [self valueForThemeAttribute:@"menu-item-disabled-text-color"];
|
||||||
|
|
||||||
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
if (_highlighted)
|
||||||
|
return [CPColor whiteColor];
|
||||||
|
|
||||||
|
return [self valueForThemeAttribute:@"menu-item-text-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPColor)textShadowColor
|
- (CPColor)textShadowColor
|
||||||
@@ -119,7 +161,10 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
if (_highlighted)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [self valueForThemeAttribute:@"menu-item-text-shadow-color"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFont:(CPFont)aFont
|
- (void)setFont:(CPFont)aFont
|
||||||
@@ -127,23 +172,59 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
_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 = LEFT_MARGIN + [_menuItem indentationLevel] * 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)
|
||||||
{
|
{
|
||||||
[_stateView setHidden:NO];
|
[_stateView setHidden:NO];
|
||||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
//[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||||
|
|
||||||
x += STATE_COLUMN_WIDTH;
|
switch ([_menuItem state])
|
||||||
|
{
|
||||||
|
case CPOnState:
|
||||||
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPOffState:
|
||||||
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMixedState:
|
||||||
|
[_stateView setImage:[_menuItem mixedStateImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateViewFrameOrigin = [_stateView frameOrigin];
|
||||||
|
|
||||||
|
stateViewFrameOrigin.x = x;
|
||||||
|
[_stateView setFrameOrigin:stateViewFrameOrigin];
|
||||||
|
|
||||||
|
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]];
|
||||||
@@ -156,24 +237,24 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
|
|
||||||
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];
|
||||||
|
|
||||||
if (hasKeyEquivalent || hasSubmenu)
|
if (hasKeyEquivalent || hasSubmenu)
|
||||||
x += RIGHT_COLUMNS_MARGIN;
|
x += [self valueForThemeAttribute:@"right-columns-margin"];
|
||||||
|
|
||||||
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, VERTICAL_MARGIN)];
|
[_keyEquivalentView setFrameOrigin:CGPointMake(x, verticalMargin)];
|
||||||
[_keyEquivalentView sizeToFit];
|
[_keyEquivalentView sizeToFit];
|
||||||
|
|
||||||
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
||||||
@@ -183,13 +264,21 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
|
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
|
||||||
|
|
||||||
if (hasSubmenu)
|
if (hasSubmenu)
|
||||||
x += RIGHT_COLUMNS_MARGIN;
|
x += [self valueForThemeAttribute:@"right-columns-margin"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[_keyEquivalentView setHidden:YES];
|
[_keyEquivalentView setHidden:YES];
|
||||||
|
|
||||||
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];
|
||||||
@@ -202,17 +291,17 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
else
|
else
|
||||||
[_submenuIndicatorView setHidden:YES];
|
[_submenuIndicatorView setHidden:YES];
|
||||||
|
|
||||||
height += 2.0 * 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)
|
||||||
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
|
[_stateView setFrameSize:CGSizeMake([self valueForThemeAttribute:@"state-column-width"], height)];
|
||||||
|
|
||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +311,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
|
_minSize = CGSizeMake(x + [self valueForThemeAttribute:@"right-margin"], height);
|
||||||
|
|
||||||
[self setAutoresizesSubviews:NO];
|
[self setAutoresizesSubviews:NO];
|
||||||
[self setFrameSize:_minSize];
|
[self setFrameSize:_minSize];
|
||||||
@@ -235,42 +324,104 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_highlighted = shouldHighlight;
|
||||||
|
|
||||||
|
var correspondingControlSize = [[self font] controlSizeCorrespondingToFontSize];
|
||||||
|
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||||
|
|
||||||
if (shouldHighlight)
|
if (shouldHighlight)
|
||||||
{
|
{
|
||||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
[self setBackgroundColor:[self valueForThemeAttribute:@"menu-item-selection-color"]];
|
||||||
|
|
||||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
|
||||||
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
|
||||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
|
||||||
|
|
||||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
if (_hasSubmenuIndicatorImage)
|
||||||
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
|
[_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]];
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_keyEquivalentView setTextColor:[self textColor]];
|
|
||||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
|
||||||
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
if (_hasSubmenuIndicatorImage)
|
||||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
[_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])
|
||||||
{
|
{
|
||||||
if (shouldHighlight)
|
if (shouldHighlight)
|
||||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
{
|
||||||
|
switch ([_menuItem state])
|
||||||
|
{
|
||||||
|
case CPOnState:
|
||||||
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPOffState:
|
||||||
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMixedState:
|
||||||
|
[_stateView setImage:[_menuItem mixedImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-highlighted-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
{
|
||||||
|
switch ([_menuItem state])
|
||||||
|
{
|
||||||
|
case CPOnState:
|
||||||
|
[_stateView setImage:[_menuItem onStateImage] || [self valueForThemeAttribute:@"menu-item-default-on-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPOffState:
|
||||||
|
[_stateView setImage:[_menuItem offStateImage] || [self valueForThemeAttribute:@"menu-item-default-off-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPMixedState:
|
||||||
|
[_stateView setImage:[_menuItem mixedImage] || [self valueForThemeAttribute:@"menu-item-default-mixed-state-image" inState:CPControlSizeThemeStates[correspondingControlSize]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isHighlighted
|
||||||
|
{
|
||||||
|
return _highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
@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;
|
||||||
|
|||||||
@@ -1,22 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* _CPMenuItemView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 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 <AppKit/CPControl.j>
|
@import "CPControl.j"
|
||||||
|
|
||||||
@import "_CPMenuItemSeparatorView.j"
|
@import "_CPMenuItemSeparatorView.j"
|
||||||
@import "_CPMenuItemStandardView.j"
|
@import "_CPMenuItemStandardView.j"
|
||||||
@import "_CPMenuItemMenuBarView.j"
|
@import "_CPMenuItemMenuBarView.j"
|
||||||
|
|
||||||
|
@class CPMenuItem
|
||||||
var LEFT_MARGIN = 3.0,
|
@global CPApp
|
||||||
RIGHT_MARGIN = 16.0,
|
|
||||||
STATE_COLUMN_WIDTH = 14.0,
|
|
||||||
INDENTATION_WIDTH = 17.0,
|
|
||||||
VERTICAL_MARGIN = 4.0;
|
|
||||||
|
|
||||||
var _CPMenuItemSelectionColor = nil,
|
|
||||||
_CPMenuItemTextShadowColor = nil,
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages = [],
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
@@ -24,7 +35,7 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
@implementation _CPMenuItemView : CPView
|
@implementation _CPMenuItemView : CPView
|
||||||
{
|
{
|
||||||
CPMenuItem _menuItem;
|
CPMenuItem _menuItem;
|
||||||
CPView _view;
|
CPView _view @accessors(property=view, readonly);
|
||||||
|
|
||||||
CPFont _font;
|
CPFont _font;
|
||||||
CPColor _textColor;
|
CPColor _textColor;
|
||||||
@@ -38,31 +49,22 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
CPView _submenuView;
|
CPView _submenuView;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self !== [_CPMenuItemView class])
|
return "menu-item-view";
|
||||||
return;
|
|
||||||
|
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
|
||||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)leftMargin
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
return @{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not used in the Appkit
|
||||||
|
// + (float)leftMargin
|
||||||
|
// {
|
||||||
|
// return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||||
|
// }
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
@@ -111,7 +113,6 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
_view = menuItemView;
|
_view = menuItemView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ([_menuItem menu] == [CPApp mainMenu])
|
else if ([_menuItem menu] == [CPApp mainMenu])
|
||||||
{
|
{
|
||||||
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
||||||
@@ -219,8 +220,63 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setParentMenuHighlightColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(setHighlightColor:)])
|
||||||
|
[_view setHighlightColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setParentMenuHighlightTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(setHighlightTextColor:)])
|
||||||
|
[_view setHighlightTextColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setParentMenuHighlightTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(setHighlightTextShadowColor:)])
|
||||||
|
[_view setHighlightTextShadowColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setParentMenuTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(setTextColor:)])
|
||||||
|
[_view setTextColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setParentMenuTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(setTextShadowColor:)])
|
||||||
|
[_view setTextShadowColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
@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;
|
||||||
@@ -245,8 +301,6 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
CGContextMoveToPoint(context, 1.0, 4.0);
|
CGContextMoveToPoint(context, 1.0, 4.0);
|
||||||
CGContextAddLineToPoint(context, 9.0, 4.0);
|
CGContextAddLineToPoint(context, 9.0, 4.0);
|
||||||
CGContextAddLineToPoint(context, 5.0, 8.0);
|
CGContextAddLineToPoint(context, 5.0, 8.0);
|
||||||
CGContextAddLineToPoint(context, 1.0, 4.0);
|
|
||||||
|
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
|
|
||||||
CGContextSetFillColor(context, _color);
|
CGContextSetFillColor(context, _color);
|
||||||
|
|||||||
+181
-34
@@ -22,8 +22,13 @@
|
|||||||
|
|
||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPCountedSet.j>
|
@import <Foundation/CPCountedSet.j>
|
||||||
|
@import <Foundation/_CPCollectionKVCOperators.j>
|
||||||
|
|
||||||
@import "CPController.j"
|
@import "CPController.j"
|
||||||
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
|
@class _CPManagedProxy
|
||||||
|
@class CPPredicate;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@class
|
@class
|
||||||
@@ -45,11 +50,14 @@
|
|||||||
|
|
||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
BOOL _automaticallyPreparesContent;
|
BOOL _automaticallyPreparesContent;
|
||||||
|
BOOL _usesLazyFetching @accessors(getter=usesLazyFetching, setter=setUsesLazyFetching:);
|
||||||
|
BOOL _isUsingManagedProxy;
|
||||||
|
_CPManagedProxy _managedProxy;
|
||||||
|
|
||||||
CPCountedSet _observedKeys;
|
CPCountedSet _observedKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self !== [CPObjectController class])
|
if (self !== [CPObjectController class])
|
||||||
return;
|
return;
|
||||||
@@ -104,11 +112,13 @@
|
|||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
{
|
{
|
||||||
[self setContent:aContent];
|
|
||||||
[self setEditable:YES];
|
[self setEditable:YES];
|
||||||
[self setObjectClass:[CPMutableDictionary class]];
|
[self setObjectClass:[CPMutableDictionary class]];
|
||||||
|
|
||||||
_observedKeys = [[CPCountedSet alloc] init];
|
_observedKeys = [[CPCountedSet alloc] init];
|
||||||
|
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||||
|
|
||||||
|
[self setContent:aContent];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -175,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.
|
||||||
*/
|
*/
|
||||||
@@ -185,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
|
||||||
@@ -327,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.
|
||||||
*/
|
*/
|
||||||
@@ -359,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)
|
||||||
|
|
||||||
@@ -370,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];
|
||||||
}
|
}
|
||||||
@@ -394,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
|
||||||
@@ -455,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
|
||||||
@@ -516,8 +609,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
|
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
|
||||||
{
|
{
|
||||||
if (aKeyPath.indexOf("@") === 0)
|
if (aKeyPath.charAt(0) === "@")
|
||||||
{
|
{
|
||||||
|
// Simple collection operators are scalar and can't be proxied
|
||||||
|
if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
|
||||||
|
return;
|
||||||
|
|
||||||
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
|
||||||
|
|
||||||
proxy._options = options;
|
proxy._options = options;
|
||||||
@@ -540,8 +637,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
|
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
|
||||||
{
|
{
|
||||||
if (aKeyPath.indexOf("@") === 0)
|
if (aKeyPath.charAt(0) === "@")
|
||||||
{
|
{
|
||||||
|
// Simple collection operators are scalar and can't be proxied
|
||||||
|
if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
|
||||||
|
return;
|
||||||
|
|
||||||
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
|
||||||
index = [_observationProxies indexOfObject:proxy];
|
index = [_observationProxies indexOfObject:proxy];
|
||||||
|
|
||||||
@@ -560,13 +661,13 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
|
- (void)insertObject:(id)anObject atIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
for (var i = 0, count = [_observationProxies count]; i < count; i++)
|
for (var i = 0, count = [_observationProxies count]; i < count; i++)
|
||||||
{
|
{
|
||||||
var proxy = [_observationProxies objectAtIndex:i],
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
keyPath = [proxy keyPath],
|
keyPath = [proxy keyPath],
|
||||||
operator = keyPath.indexOf(".") === 0;
|
operator = keyPath.charAt(0) === ".";
|
||||||
|
|
||||||
if (operator)
|
if (operator)
|
||||||
[self willChangeValueForKey:keyPath];
|
[self willChangeValueForKey:keyPath];
|
||||||
@@ -580,7 +681,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
[super insertObject:anObject atIndex:anIndex];
|
[super insertObject:anObject atIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeObjectAtIndex:(unsigned)anIndex
|
- (void)removeObjectAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
var currentObject = [self objectAtIndex:anIndex];
|
var currentObject = [self objectAtIndex:anIndex];
|
||||||
|
|
||||||
@@ -588,7 +689,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
{
|
{
|
||||||
var proxy = [_observationProxies objectAtIndex:i],
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
keyPath = [proxy keyPath],
|
keyPath = [proxy keyPath],
|
||||||
operator = keyPath.indexOf(".") === 0;
|
operator = keyPath.charAt(0) === ".";
|
||||||
|
|
||||||
if (operator)
|
if (operator)
|
||||||
[self willChangeValueForKey:keyPath];
|
[self willChangeValueForKey:keyPath];
|
||||||
@@ -602,7 +703,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
[super removeObjectAtIndex:anIndex];
|
[super removeObjectAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
- (CPArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
||||||
{
|
{
|
||||||
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
|
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
|
||||||
}
|
}
|
||||||
@@ -617,7 +718,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
[self removeObjectAtIndex:[self count]];
|
[self removeObjectAtIndex:[self count]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
|
- (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(id)anObject
|
||||||
{
|
{
|
||||||
var currentObject = [self objectAtIndex:anIndex];
|
var currentObject = [self objectAtIndex:anIndex];
|
||||||
|
|
||||||
@@ -625,7 +726,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
{
|
{
|
||||||
var proxy = [_observationProxies objectAtIndex:i],
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
keyPath = [proxy keyPath],
|
keyPath = [proxy keyPath],
|
||||||
operator = keyPath.indexOf(".") === 0;
|
operator = keyPath.charAt(0) === ".";
|
||||||
|
|
||||||
if (operator)
|
if (operator)
|
||||||
[self willChangeValueForKey:keyPath];
|
[self willChangeValueForKey:keyPath];
|
||||||
@@ -657,7 +758,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
{
|
{
|
||||||
_cachedValues = [CPDictionary dictionary];
|
_cachedValues = @{};
|
||||||
_observationProxies = [CPArray array];
|
_observationProxies = [CPArray array];
|
||||||
_controller = aController;
|
_controller = aController;
|
||||||
_observedObjectsByKeyPath = {};
|
_observedObjectsByKeyPath = {};
|
||||||
@@ -691,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;
|
||||||
@@ -699,12 +800,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
|||||||
|
|
||||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||||
{
|
{
|
||||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath],
|
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||||
value = [self _controllerMarkerForValues:values];
|
|
||||||
|
|
||||||
[_cachedValues setObject:value forKey:theKeyPath];
|
// Simple collection operators like @count return a scalar value, not an array or set
|
||||||
|
if ([values isKindOfClass:CPArray] || [values isKindOfClass:CPSet])
|
||||||
|
{
|
||||||
|
var value = [self _controllerMarkerForValues:values];
|
||||||
|
[_cachedValues setObject:value forKey:theKeyPath];
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)valueForKey:(CPString)theKeyPath
|
- (id)valueForKey:(CPString)theKeyPath
|
||||||
@@ -731,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
|
||||||
@@ -790,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;
|
||||||
|
|
||||||
_observedObjects = 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
|
||||||
@@ -47,9 +47,9 @@
|
|||||||
var options = { directoryURL: [self directoryURL],
|
var options = { directoryURL: [self directoryURL],
|
||||||
canChooseFiles: [self canChooseFiles],
|
canChooseFiles: [self canChooseFiles],
|
||||||
canChooseDirectories: [self canChooseDirectories],
|
canChooseDirectories: [self canChooseDirectories],
|
||||||
allowsMultipleSelection: [self allowsMultipleSelection] };
|
allowsMultipleSelection: [self allowsMultipleSelection] },
|
||||||
|
|
||||||
var result = window.cpOpenPanel(options);
|
result = window.cpOpenPanel(options);
|
||||||
|
|
||||||
_URLs = result.URLs;
|
_URLs = result.URLs;
|
||||||
|
|
||||||
|
|||||||
+618
-404
File diff suppressed because it is too large
Load Diff
+24
-3
@@ -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;
|
||||||
@@ -116,7 +117,27 @@ CPDocModalWindowMask = 1 << 6;
|
|||||||
|
|
||||||
- (BOOL)canBecomeKeyWindow
|
- (BOOL)canBecomeKeyWindow
|
||||||
{
|
{
|
||||||
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
|
||||||
|
|||||||
+25
-79
@@ -22,9 +22,13 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
|
@import <Foundation/CPData.j>
|
||||||
@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";
|
||||||
@@ -40,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";
|
||||||
|
|
||||||
@@ -47,8 +54,7 @@ UTF8PboardType = @"public.utf8-plain-text";
|
|||||||
CPImagePboardType = @"CPImagePboardType";
|
CPImagePboardType = @"CPImagePboardType";
|
||||||
|
|
||||||
|
|
||||||
var CPPasteboards = nil,
|
var CPPasteboards = nil;
|
||||||
supportsNativePasteboard = NO;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -64,8 +70,6 @@ var CPPasteboards = nil,
|
|||||||
|
|
||||||
unsigned _changeCount;
|
unsigned _changeCount;
|
||||||
CPString _stateUID;
|
CPString _stateUID;
|
||||||
|
|
||||||
WebScriptObject _nativePasteboard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -78,10 +82,7 @@ var CPPasteboards = nil,
|
|||||||
|
|
||||||
[self setVersion:1.0];
|
[self setVersion:1.0];
|
||||||
|
|
||||||
CPPasteboards = [CPDictionary dictionary];
|
CPPasteboards = @{};
|
||||||
|
|
||||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
|
||||||
supportsNativePasteboard = YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -117,19 +118,13 @@ var CPPasteboards = nil,
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_name = aName;
|
// _name = aName;
|
||||||
_types = [];
|
_types = [];
|
||||||
|
|
||||||
_owners = [CPDictionary dictionary];
|
_owners = @{};
|
||||||
_provided = [CPDictionary dictionary];
|
_provided = @{};
|
||||||
|
|
||||||
_changeCount = 0;
|
_changeCount = 0;
|
||||||
|
|
||||||
if (supportsNativePasteboard)
|
|
||||||
{
|
|
||||||
_nativePasteboard = window.cpPasteboardWithName(aName);
|
|
||||||
[self _synchronizePasteboard];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -159,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,32 +164,19 @@ 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];
|
||||||
|
|
||||||
_owners = [CPDictionary dictionary];
|
_owners = @{};
|
||||||
_provided = [CPDictionary dictionary];
|
_provided = @{};
|
||||||
|
|
||||||
var count = _types.length;
|
if (anOwner)
|
||||||
|
|
||||||
while (count--)
|
|
||||||
[_owners setObject:anOwner forKey:_types[count]];
|
|
||||||
|
|
||||||
if (_nativePasteboard && shouldUpdate)
|
|
||||||
{
|
{
|
||||||
var nativeTypes = [types copy];
|
var count = _types.length;
|
||||||
if ([types containsObject:CPStringPboardType])
|
while (count--)
|
||||||
nativeTypes.push(UTF8PboardType);
|
[_owners setObject:anOwner forKey:_types[count]];
|
||||||
|
|
||||||
_nativePasteboard.declareTypes_(nativeTypes);
|
|
||||||
_changeCount = _nativePasteboard.changeCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ++_changeCount;
|
return ++_changeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,19 +215,23 @@ var CPPasteboards = nil,
|
|||||||
*/
|
*/
|
||||||
- (void)setString:(CPString)aString forType:(CPString)aType
|
- (void)setString:(CPString)aString forType:(CPString)aType
|
||||||
{
|
{
|
||||||
|
// Putting a non-string on the string pasteboard can lead to strange crashes.
|
||||||
|
if (aString && aString.isa && ![aString isKindOfClass:CPString])
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:"CPPasteboard setString:forType: must be called with a string."];
|
||||||
|
|
||||||
[self setPropertyList:aString forType:aType];
|
[self setPropertyList:aString forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determining Types
|
// Determining Types
|
||||||
/*!
|
/*!
|
||||||
Checks the pasteboard's types for a match with the types listen in the specified array. The array should
|
Checks the pasteboard's types for a match with the types listed in the specified array. The array should
|
||||||
be ordered by the requestor's most preferred data type first.
|
be ordered by the requestor's most preferred data type first.
|
||||||
@param anArray an array of requested types ordered by preference
|
@param anArray an array of requested types ordered by preference
|
||||||
@return the highest match with the pasteboard's supported types or \c nil if no match was found
|
@return the highest match with the pasteboard's supported types or \c nil if no match was found
|
||||||
*/
|
*/
|
||||||
- (CPString)availableTypeFromArray:(CPArray)anArray
|
- (CPString)availableTypeFromArray:(CPArray)anArray
|
||||||
{
|
{
|
||||||
return [[self types] firstObjectCommonWithArray:anArray];
|
return [anArray firstObjectCommonWithArray:[self types]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -262,7 +239,6 @@ var CPPasteboards = nil,
|
|||||||
*/
|
*/
|
||||||
- (CPArray)types
|
- (CPArray)types
|
||||||
{
|
{
|
||||||
[self _synchronizePasteboard];
|
|
||||||
return _types;
|
return _types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,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
|
||||||
|
|||||||
+75
-56
@@ -20,15 +20,12 @@
|
|||||||
* 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/CPGeometry.j>
|
@import "CGGeometry.j"
|
||||||
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
@import "CPKeyValueBinding.j"
|
@import "CPKeyValueBinding.j"
|
||||||
@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");
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -48,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"];
|
||||||
@@ -280,7 +284,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
Selects the item at the specified index
|
Selects the item at the specified index
|
||||||
@param anIndex the index of the item to select
|
@param anIndex the index of the item to select
|
||||||
*/
|
*/
|
||||||
- (void)setObjectValue:(int)anIndex
|
- (void)setObjectValue:(id)anIndex
|
||||||
{
|
{
|
||||||
var indexOfSelectedItem = [self objectValue];
|
var indexOfSelectedItem = [self objectValue];
|
||||||
|
|
||||||
@@ -345,7 +349,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
Returns the item at the specified index or \c nil if the item does not exist.
|
Returns the item at the specified index or \c nil if the item does not exist.
|
||||||
@param anIndex the index of the item to obtain
|
@param anIndex the index of the item to obtain
|
||||||
*/
|
*/
|
||||||
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
|
- (CPMenuItem)itemAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [[self menu] itemAtIndex:anIndex];
|
return [[self menu] itemAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
@@ -354,7 +358,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
Returns the title of the item at the specified index or \c nil if no item exists.
|
Returns the title of the item at the specified index or \c nil if no item exists.
|
||||||
@param anIndex the index of the item
|
@param anIndex the index of the item
|
||||||
*/
|
*/
|
||||||
- (CPString)itemTitleAtIndex:(unsigned)anIndex
|
- (CPString)itemTitleAtIndex:(CPUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [[[self menu] itemAtIndex:anIndex] title];
|
return [[[self menu] itemAtIndex:anIndex] title];
|
||||||
}
|
}
|
||||||
@@ -364,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -499,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];
|
||||||
@@ -668,10 +675,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
if (![self isEnabled] || ![self numberOfItems])
|
if (![self isEnabled] || ![self numberOfItems])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var menu = [self menu];
|
||||||
|
|
||||||
|
// Don't reopen the menu based on the same click which caused it to close, e.g. a click on this button.
|
||||||
|
if (menu._lastCloseEvent === anEvent)
|
||||||
|
return;
|
||||||
|
|
||||||
[self highlight:YES];
|
[self highlight:YES];
|
||||||
|
|
||||||
var menu = [self menu],
|
var bounds = [self bounds],
|
||||||
bounds = [self bounds],
|
|
||||||
minimumWidth = CGRectGetWidth(bounds);
|
minimumWidth = CGRectGetWidth(bounds);
|
||||||
|
|
||||||
// FIXME: setFont: should set the font on the menu.
|
// FIXME: setFont: should set the font on the menu.
|
||||||
@@ -680,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));
|
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;
|
||||||
|
|
||||||
@@ -769,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)
|
||||||
@@ -798,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
|
||||||
@@ -834,7 +855,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
[self _setContentValuesIfNeeded:contentArray];
|
[self _setContentValuesIfNeeded:contentArray];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)valueForBinding:(CPString)aBinding
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
return [self _content];
|
return [self _content];
|
||||||
}
|
}
|
||||||
@@ -843,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])
|
||||||
{
|
{
|
||||||
@@ -854,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
|
||||||
@@ -906,7 +947,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
- (void)setValue:(CPArray)aValue forBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
[super _setContent:aValue];
|
[super _setContent:aValue];
|
||||||
}
|
}
|
||||||
@@ -927,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
|
||||||
|
|||||||
+105
-70
@@ -28,8 +28,19 @@
|
|||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
@import "_CPAttachedWindow.j"
|
@import "CPViewController.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;
|
||||||
@@ -45,7 +56,7 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
/*! @ingroup appkit
|
/*! @ingroup appkit
|
||||||
@class CPPopover
|
@class CPPopover
|
||||||
|
|
||||||
This class represent a widget that displays a attached
|
This class represent a widget that displays a popover
|
||||||
view relative to another one.
|
view relative to another one.
|
||||||
|
|
||||||
Delegate can implement:
|
Delegate can implement:
|
||||||
@@ -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(property=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);
|
||||||
|
|
||||||
_CPAttachedWindow _attachedWindow;
|
_CPPopoverWindow _popoverWindow;
|
||||||
int _implementedDelegateMethods;
|
CPView _positioningView;
|
||||||
|
int _implementedDelegateMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -103,9 +115,10 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (CGRect)positioningRect
|
- (CGRect)positioningRect
|
||||||
{
|
{
|
||||||
if (![_attachedWindow isVisible])
|
if (![_popoverWindow isVisible])
|
||||||
return CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
return [_attachedWindow frame];
|
|
||||||
|
return [_popoverWindow frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Sets the frame of the popover
|
/*! Sets the frame of the popover
|
||||||
@@ -113,9 +126,10 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (void)setPositioningRect:(CGRect)aRect
|
- (void)setPositioningRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
if (![_attachedWindow isVisible])
|
if (![_popoverWindow isVisible])
|
||||||
return;
|
return;
|
||||||
[_attachedWindow setFrame:aRect];
|
|
||||||
|
[_popoverWindow setFrame:aRect];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -125,8 +139,6 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (CGSize)contentSize
|
- (CGSize)contentSize
|
||||||
{
|
{
|
||||||
if (![_attachedWindow isVisible])
|
|
||||||
return CGRectMakeZero();
|
|
||||||
return [[_contentViewController view] frameSize];
|
return [[_contentViewController view] frameSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,9 +147,12 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
|
|
||||||
@param aSize the desired size
|
@param aSize the desired size
|
||||||
*/
|
*/
|
||||||
- (void)setContentSize:(CPSize)aSize
|
- (void)setContentSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[[_contentViewController view] setFrameSize:aSize];
|
if (!_popoverWindow)
|
||||||
|
[[_contentViewController view] setFrameSize:aSize];
|
||||||
|
else
|
||||||
|
[_popoverWindow updateFrameWithSize:aSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -147,7 +162,21 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isShown
|
- (BOOL)isShown
|
||||||
{
|
{
|
||||||
return [_attachedWindow isVisible];
|
return [_popoverWindow isVisible];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set if the popover should animate for open/close actions.
|
||||||
|
|
||||||
|
@param shouldAnimate if YES, the popover will be animated.
|
||||||
|
*/
|
||||||
|
- (void)setAnimates:(BOOL)shouldAnimate
|
||||||
|
{
|
||||||
|
if (_animates == shouldAnimate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_animates = shouldAnimate;
|
||||||
|
[_popoverWindow setAnimates:_animates];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -164,10 +193,10 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_behavior = aBehavior;
|
_behavior = aBehavior;
|
||||||
[_attachedWindow setStyleMask:[self styleMaskForBehavior]];
|
[_popoverWindow setStyleMask:[self _styleMaskForBehavior]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id <CPPopoverDelegate>)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate === aDelegate)
|
if (_delegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
@@ -209,38 +238,38 @@ 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 ([_attachedWindow isClosing])
|
if ([_popoverWindow isClosing] || [_popoverWindow isOpening])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
_positioningView = positioningView;
|
||||||
[_delegate popoverWillShow:self];
|
|
||||||
|
|
||||||
if (!_attachedWindow)
|
if (!_popoverWindow)
|
||||||
{
|
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self _styleMaskForBehavior]];
|
||||||
_attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self styleMaskForBehavior]];
|
|
||||||
|
|
||||||
var parentWindow = [positioningView window];
|
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
||||||
|
[_popoverWindow setAppearance:_appearance];
|
||||||
|
[_popoverWindow setAnimates:_animates];
|
||||||
|
[_popoverWindow setDelegate:self];
|
||||||
|
[_popoverWindow setMovableByWindowBackground:NO];
|
||||||
|
[_popoverWindow setFrame:[_popoverWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||||
|
[_popoverWindow setContentView:[_contentViewController view]];
|
||||||
|
|
||||||
if (![parentWindow isKindOfClass:_CPAttachedWindow])
|
if (![self isShown])
|
||||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(parentWindowWillClose:) name:CPWindowWillCloseNotification object:parentWindow];
|
[self _popoverWillShow];
|
||||||
}
|
|
||||||
|
|
||||||
[_attachedWindow setAppearance:_appearance];
|
[_popoverWindow positionRelativeToRect:positioningRect ofView:positioningView preferredEdge:preferredEdge];
|
||||||
[_attachedWindow setAnimates:_animates];
|
|
||||||
[_attachedWindow setDelegate:self];
|
|
||||||
[_attachedWindow setMovableByWindowBackground:NO];
|
|
||||||
[_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
|
||||||
[_attachedWindow setContentView:[_contentViewController view]];
|
|
||||||
[_attachedWindow 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
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -256,16 +285,16 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
*/
|
*/
|
||||||
- (void)_close
|
- (void)_close
|
||||||
{
|
{
|
||||||
if ([_attachedWindow isClosing] || ![self isShown])
|
if ([_popoverWindow isClosing] || ![self isShown])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
[self _popoverWillClose];
|
||||||
[_delegate popoverWillClose:self];
|
|
||||||
|
|
||||||
[_attachedWindow close];
|
_positioningView = nil;
|
||||||
|
[_popoverWindow close];
|
||||||
|
|
||||||
// popoverDidClose will be sent from attachedWindowDidClose, since
|
// popoverDidClose will be sent from popoverWindowDidClose, since
|
||||||
// the attached window will close asynchronously when animating.
|
// the popover window will close asynchronously when animating.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -279,12 +308,11 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
*/
|
*/
|
||||||
- (IBAction)performClose:(id)sender
|
- (IBAction)performClose:(id)sender
|
||||||
{
|
{
|
||||||
if ([_attachedWindow isClosing])
|
if ([_popoverWindow isClosing])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
if (![self _popoverShouldClose])
|
||||||
if (![_delegate popoverShouldClose:self])
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
[self _close];
|
[self _close];
|
||||||
}
|
}
|
||||||
@@ -294,44 +322,51 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
#pragma mark Delegates
|
#pragma mark Delegates
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (BOOL)attachedWindowShouldClose:(_CPAttachedWindow)anAttachedWindow
|
- (BOOL)_popoverWindowShouldClose
|
||||||
{
|
{
|
||||||
[self performClose:self];
|
[self performClose:self];
|
||||||
|
|
||||||
// We return NO, because we want the CPPopover to determine
|
// We return NO, because we want the CPPopover to determine
|
||||||
// if the attached window can be closed and to give us a chance
|
// if the popover window can be closed and to give us a chance
|
||||||
// to send delegate messages.
|
// to send delegate messages.
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)attachedWindowDidClose:(_CPAttachedWindow)anAttachedWindow
|
- (void)_popoverWindowDidClose
|
||||||
{
|
{
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||||
[_delegate popoverDidClose:self];
|
[_delegate popoverDidClose:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @ignore */
|
/*! @ignore */
|
||||||
- (void)attachedWindowDidShow:(_CPAttachedWindow)anAttachedWindow
|
- (void)_popoverWindowDidShow
|
||||||
{
|
{
|
||||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||||
[_delegate popoverDidShow:self];
|
[_delegate popoverDidShow:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
#pragma mark -
|
- (BOOL)_popoverShouldClose
|
||||||
#pragma mark Notifications
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@ignore
|
|
||||||
|
|
||||||
This method is called only when a non-popover parent window
|
|
||||||
is closing. In that case popovers should order out.
|
|
||||||
*/
|
|
||||||
- (void)parentWindowWillClose:(CPNotification)aNotification
|
|
||||||
{
|
{
|
||||||
[_attachedWindow orderOut:nil];
|
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||||
[self performClose:nil];
|
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
|
||||||
@@ -347,7 +382,7 @@ Set the behavior of the CPPopover. It can be:
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPPopoverNeedsNewAttachedWindowKey = @"CPPopoverNeedsNewAttachedWindowKey",
|
var CPPopoverNeedsNewPopoverWindowKey = @"CPPopoverNeedsNewPopoverWindowKey",
|
||||||
CPPopoverAppearanceKey = @"CPPopoverAppearanceKey",
|
CPPopoverAppearanceKey = @"CPPopoverAppearanceKey",
|
||||||
CPPopoverAnimatesKey = @"CPPopoverAnimatesKey",
|
CPPopoverAnimatesKey = @"CPPopoverAnimatesKey",
|
||||||
CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey",
|
CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey",
|
||||||
|
|||||||
+170
-101
@@ -23,29 +23,27 @@
|
|||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPWindow_Constants.j"
|
||||||
|
|
||||||
|
|
||||||
|
@typedef CPProgressIndicatorStyle
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPProgressIndicatorStyle
|
@group CPProgressIndicatorStyle
|
||||||
*/
|
*/
|
||||||
CPProgressIndicatorBarStyle = 0;
|
CPProgressIndicatorBarStyle = 0;
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPProgressIndicatorStyle
|
@group CPProgressIndicatorStyle
|
||||||
*/
|
*/
|
||||||
CPProgressIndicatorSpinningStyle = 1;
|
CPProgressIndicatorSpinningStyle = 1;
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPProgressIndicatorStyle
|
@group CPProgressIndicatorStyle
|
||||||
*/
|
*/
|
||||||
CPProgressIndicatorHUDBarStyle = 2;
|
CPProgressIndicatorHUDBarStyle = 2;
|
||||||
|
|
||||||
var CPProgressIndicatorSpinningStyleColors = nil,
|
var CPProgressIndicatorSpinningStyleColors = [];
|
||||||
|
|
||||||
CPProgressIndicatorClassName = nil,
|
|
||||||
CPProgressIndicatorStyleIdentifiers = nil,
|
|
||||||
CPProgressIndicatorStyleSizes = nil;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -64,7 +62,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
CPControlSize _controlSize;
|
CPControlSize _controlSize;
|
||||||
|
|
||||||
BOOL _isIndeterminate;
|
BOOL _indeterminate;
|
||||||
CPProgressIndicatorStyle _style;
|
CPProgressIndicatorStyle _style;
|
||||||
|
|
||||||
BOOL _isAnimating;
|
BOOL _isAnimating;
|
||||||
@@ -73,66 +71,33 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
BOOL _isDisplayedWhenStopped;
|
BOOL _isDisplayedWhenStopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
+ (CPString)defaultThemeClass
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
{
|
||||||
if (self !== [CPProgressIndicator class])
|
return @"progress-indicator";
|
||||||
return;
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"indeterminate-bar-color": [CPNull null],
|
||||||
|
@"bar-color": [CPNull null],
|
||||||
|
@"default-height": 20,
|
||||||
|
@"bezel-color": [CPNull null],
|
||||||
|
@"spinning-mini-gif": [CPNull null],
|
||||||
|
@"spinning-small-gif": [CPNull null],
|
||||||
|
@"spinning-regular-gif": [CPNull null],
|
||||||
|
@"circular-border-color": [CPNull null],
|
||||||
|
@"circular-border-size": 1,
|
||||||
|
@"circular-color": [CPNull null]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
CPProgressIndicatorSpinningStyleColors = [];
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPValueBinding || aBinding === @"isIndeterminate")
|
||||||
|
return [_CPProgressIndicatorBinder class];
|
||||||
|
|
||||||
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
return [super _binderClassForBinding:aBinding];
|
||||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleMini.gif"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
|
||||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleSmall.gif"] size:CGSizeMake(32.0, 32.0)]];
|
|
||||||
CPProgressIndicatorSpinningStyleColors[CPRegularControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
|
||||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
|
|
||||||
|
|
||||||
CPProgressIndicatorBezelBorderViewPool = [];
|
|
||||||
|
|
||||||
var start = CPProgressIndicatorBarStyle,
|
|
||||||
end = CPProgressIndicatorHUDBarStyle;
|
|
||||||
|
|
||||||
for (; start <= end; ++start)
|
|
||||||
{
|
|
||||||
CPProgressIndicatorBezelBorderViewPool[start] = [];
|
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
|
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
|
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
CPProgressIndicatorClassName = [self className];
|
|
||||||
CPProgressIndicatorStyleIdentifiers = [];
|
|
||||||
|
|
||||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
|
|
||||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
|
|
||||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
|
|
||||||
|
|
||||||
var regularIdentifier = _CPControlIdentifierForControlSize(CPRegularControlSize),
|
|
||||||
smallIdentifier = _CPControlIdentifierForControlSize(CPSmallControlSize),
|
|
||||||
miniIdentifier = _CPControlIdentifierForControlSize(CPMiniControlSize);
|
|
||||||
|
|
||||||
CPProgressIndicatorStyleSizes = [];
|
|
||||||
|
|
||||||
// Bar Style
|
|
||||||
var prefixes = [
|
|
||||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
|
||||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
|
||||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
|
|
||||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
|
|
||||||
];
|
|
||||||
|
|
||||||
for (var i = 0, count = prefixes.length; i < count; i++)
|
|
||||||
{
|
|
||||||
var prefix = prefixes[i];
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -151,8 +116,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
_controlSize = CPRegularControlSize;
|
_controlSize = CPRegularControlSize;
|
||||||
|
|
||||||
[self updateBackgroundColor];
|
[self setNeedsLayout];
|
||||||
[self drawBar];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -314,12 +278,12 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
Specifies whether this progress indicator should be indeterminate or display progress based on it's max and min.
|
Specifies whether this progress indicator should be indeterminate or display progress based on it's max and min.
|
||||||
@param isDeterminate \c YES makes the indicator indeterminate
|
@param isDeterminate \c YES makes the indicator indeterminate
|
||||||
*/
|
*/
|
||||||
- (void)setIndeterminate:(BOOL)isIndeterminate
|
- (void)setIndeterminate:(BOOL)indeterminate
|
||||||
{
|
{
|
||||||
if (_isIndeterminate == isIndeterminate)
|
if (_indeterminate == indeterminate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isIndeterminate = isIndeterminate;
|
_indeterminate = indeterminate;
|
||||||
|
|
||||||
[self updateBackgroundColor];
|
[self updateBackgroundColor];
|
||||||
}
|
}
|
||||||
@@ -329,7 +293,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isIndeterminate
|
- (BOOL)isIndeterminate
|
||||||
{
|
{
|
||||||
return _isIndeterminate;
|
return _indeterminate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -343,6 +307,8 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
_style = aStyle;
|
_style = aStyle;
|
||||||
|
|
||||||
|
[self setTheme:(_style === CPProgressIndicatorHUDBarStyle) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||||
|
|
||||||
[self updateBackgroundColor];
|
[self updateBackgroundColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,8 +320,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
if (_style == CPProgressIndicatorSpinningStyle)
|
if (_style == CPProgressIndicatorSpinningStyle)
|
||||||
[self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
|
[self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
|
||||||
else
|
else
|
||||||
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), CPProgressIndicatorStyleSizes[
|
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), [self valueForThemeAttribute:@"default-height"])];
|
||||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] + _CPControlIdentifierForControlSize(_controlSize)][0].height)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -405,25 +370,13 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)drawBar
|
- (void)drawBar
|
||||||
{
|
{
|
||||||
if (_style == CPProgressIndicatorSpinningStyle)
|
[self setNeedsLayout];
|
||||||
return;
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
var barView = [self layoutEphemeralSubviewNamed:"bar-view"
|
|
||||||
positioned:CPWindowBelow
|
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
|
||||||
|
|
||||||
[barView setBackgroundColor:_CPControlThreePartImagePattern(
|
|
||||||
NO,
|
|
||||||
CPProgressIndicatorStyleSizes,
|
|
||||||
CPProgressIndicatorClassName,
|
|
||||||
@"Bar",
|
|
||||||
CPProgressIndicatorStyleIdentifiers[_style],
|
|
||||||
_CPControlIdentifierForControlSize(_controlSize))];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||||
@@ -436,7 +389,10 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
if (barWidth > 0.0 && barWidth < 4.0)
|
if (barWidth > 0.0 && barWidth < 4.0)
|
||||||
barWidth = 4.0;
|
barWidth = 4.0;
|
||||||
|
|
||||||
return _CGRectMake(0, 0, barWidth, 16.0);
|
if (_indeterminate)
|
||||||
|
barWidth = width;
|
||||||
|
|
||||||
|
return CGRectMake(0, 0, barWidth, [self valueForThemeAttribute:@"default-height"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
@@ -444,11 +400,26 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)updateBackgroundColor
|
- (void)updateBackgroundColor
|
||||||
|
{
|
||||||
|
if ([CPProgressIndicatorSpinningStyleColors count] === 0)
|
||||||
|
{
|
||||||
|
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [self valueForThemeAttribute:@"spinning-mini-gif"];
|
||||||
|
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [self valueForThemeAttribute:@"spinning-small-gif"];
|
||||||
|
CPProgressIndicatorSpinningStyleColors[CPRegularControlSize] = [self valueForThemeAttribute:@"spinning-regular-gif"];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
if (YES)//_isBezeled)
|
if (YES)//_isBezeled)
|
||||||
{
|
{
|
||||||
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
|
||||||
@@ -458,21 +429,70 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[self setBackgroundColor:_CPControlThreePartImagePattern(
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||||
NO,
|
|
||||||
CPProgressIndicatorStyleSizes,
|
|
||||||
CPProgressIndicatorClassName,
|
|
||||||
@"BezelBorder",
|
|
||||||
CPProgressIndicatorStyleIdentifiers[_style],
|
|
||||||
_CPControlIdentifierForControlSize(_controlSize))];
|
|
||||||
|
|
||||||
[self drawBar];
|
var barView = [self layoutEphemeralSubviewNamed:"bar-view"
|
||||||
|
positioned:CPWindowBelow
|
||||||
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
|
if (_indeterminate)
|
||||||
|
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"indeterminate-bar-color"]];
|
||||||
|
else
|
||||||
|
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"bar-color"]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[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
|
||||||
|
|
||||||
|
|
||||||
@@ -486,7 +506,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||||
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
||||||
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
||||||
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
|
_indeterminate = [aCoder decodeObjectForKey:@"_indeterminate"];
|
||||||
_style = [aCoder decodeIntForKey:@"_style"];
|
_style = [aCoder decodeIntForKey:@"_style"];
|
||||||
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
||||||
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
||||||
@@ -500,8 +520,8 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
// Don't encode the background colour. It can be recreated based on the flags and if encoded causes hardcoded
|
// Don't encode the background colour. It can be recreated based on the flags
|
||||||
// image paths in the cib while just wasting space.
|
// and if encoded causes hardcoded image paths in the cib while just wasting space.
|
||||||
var backgroundColor = [self backgroundColor];
|
var backgroundColor = [self backgroundColor];
|
||||||
[self setBackgroundColor:nil];
|
[self setBackgroundColor:nil];
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
@@ -511,7 +531,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
||||||
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
|
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
|
||||||
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
|
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
|
||||||
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
|
[aCoder encodeObject:_indeterminate forKey:@"_indeterminate"];
|
||||||
[aCoder encodeInt:_style forKey:@"_style"];
|
[aCoder encodeInt:_style forKey:@"_style"];
|
||||||
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
|
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
|
||||||
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
||||||
@@ -519,3 +539,52 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPProgressIndicatorBinder : CPBinder
|
||||||
|
|
||||||
|
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var value = aBinding === CPValueBinding ? 0.0 : YES;
|
||||||
|
|
||||||
|
[self _setPlaceholder:value forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||||
|
[self _setPlaceholder:value forMarker:CPNoSelectionMarker isDefault:YES];
|
||||||
|
[self _setPlaceholder:value forMarker:CPNotApplicableMarker isDefault:YES];
|
||||||
|
[self _setPlaceholder:value forMarker:CPNullMarker isDefault:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPValueBinding)
|
||||||
|
return [_source doubleValue];
|
||||||
|
else if (aBinding === @"isIndeterminate")
|
||||||
|
[_source isIndeterminate];
|
||||||
|
else
|
||||||
|
return [super valueForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPValueBinding)
|
||||||
|
[_source setDoubleValue:aValue];
|
||||||
|
else if (aBinding === @"isIndeterminate")
|
||||||
|
[_source setIndeterminate:aValue];
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (![self _setValue:aValue forBinding:aBinding])
|
||||||
|
[super setValue:aValue forBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (![self _setValue:aValue forBinding:aBinding])
|
||||||
|
[super setPlaceholderValue:aValue withMarker:aMarker forBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+309
-27
@@ -25,6 +25,11 @@
|
|||||||
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
|
|
||||||
|
@class CPRadioGroup
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
|
CPRadioImageOffset = 4.0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -62,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;
|
||||||
@@ -150,7 +164,7 @@ CPRadioImageOffset = 4.0;
|
|||||||
[_radioGroup _setSelectedRadio:self];
|
[_radioGroup _setSelectedRadio:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||||
{
|
{
|
||||||
[super sendAction:anAction to:anObject];
|
[super sendAction:anAction to:anObject];
|
||||||
|
|
||||||
@@ -158,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";
|
||||||
@@ -181,50 +260,164 @@ 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
|
||||||
|
|
||||||
@implementation CPRadioGroup : CPObject
|
@implementation CPRadioGroup : CPObject
|
||||||
{
|
{
|
||||||
CPSet _radios;
|
CPArray _radios;
|
||||||
CPRadio _selectedRadio;
|
CPRadio _selectedRadio;
|
||||||
|
|
||||||
|
BOOL _enabled @accessors(getter=enabled);
|
||||||
|
BOOL _hidden @accessors(getter=hidden);
|
||||||
|
|
||||||
id _target @accessors(property=target);
|
id _target @accessors(property=target);
|
||||||
SEL _action @accessors(property=action);
|
SEL _action @accessors(property=action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self !== [CPRadioGroup class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self exposeBinding:CPSelectedValueBinding];
|
||||||
|
[self exposeBinding:CPSelectedTagBinding];
|
||||||
|
[self exposeBinding:CPSelectedIndexBinding];
|
||||||
|
|
||||||
|
[self exposeBinding:CPEnabledBinding];
|
||||||
|
[self exposeBinding:CPHiddenBinding];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_radios = [CPSet set];
|
_radios = [];
|
||||||
_selectedRadio = nil;
|
_selectedRadio = nil;
|
||||||
|
_enabled = YES;
|
||||||
|
_hidden = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Selects the radio button at the given index within the group.
|
||||||
|
If index is -1, all of the radio buttons are turned off.
|
||||||
|
*/
|
||||||
|
- (void)selectRadioAtIndex:(int)index
|
||||||
|
{
|
||||||
|
if (index === -1)
|
||||||
|
[self _setSelectedRadio:nil];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var radio = [_radios objectAtIndex:index];
|
||||||
|
|
||||||
|
[self _setSelectedRadio:radio];
|
||||||
|
[radio setState:CPOnState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Selects the first radio button within the group with the given tag.
|
||||||
|
If a radio button with the given tag is found, selects it
|
||||||
|
and returns YES. Otherwise returns NO.
|
||||||
|
*/
|
||||||
|
- (BOOL)selectRadioWithTag:(int)tag
|
||||||
|
{
|
||||||
|
var index = [_radios indexOfObjectPassingTest:function(radio)
|
||||||
|
{
|
||||||
|
return [radio tag] === tag;
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (index !== CPNotFound)
|
||||||
|
{
|
||||||
|
[self selectRadioAtIndex:index];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the CPRadio that is currently selected within the group,
|
||||||
|
or nil if none are selected.
|
||||||
|
*/
|
||||||
|
- (CPRadio)selectedRadio
|
||||||
|
{
|
||||||
|
return _selectedRadio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the index of the selected radio within the array of radio buttons.
|
||||||
|
Buttons are numbered going left to right and top to bottom. Returns -1
|
||||||
|
if no radio within the group is selected.
|
||||||
|
*/
|
||||||
|
- (int)selectedRadioIndex
|
||||||
|
{
|
||||||
|
return [_radios indexOfObject:_selectedRadio];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)radios
|
||||||
|
{
|
||||||
|
return _radios;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)size
|
||||||
|
{
|
||||||
|
return [_radios count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)enabled
|
||||||
|
{
|
||||||
|
[_radios makeObjectsPerformSelector:@selector(setEnabled:) withObject:enabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHidden:(BOOL)hidden
|
||||||
|
{
|
||||||
|
[_radios makeObjectsPerformSelector:@selector(setHidden:) withObject:hidden];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Private
|
||||||
|
|
||||||
- (void)_addRadio:(CPRadio)aRadio
|
- (void)_addRadio:(CPRadio)aRadio
|
||||||
{
|
{
|
||||||
[_radios addObject:aRadio];
|
if ([_radios indexOfObject:aRadio] === CPNotFound)
|
||||||
|
[_radios addObject:aRadio];
|
||||||
|
|
||||||
if ([aRadio state] === CPOnState)
|
if ([aRadio state] === CPOnState)
|
||||||
[self _setSelectedRadio:aRadio];
|
[self _setSelectedRadio:aRadio];
|
||||||
@@ -238,23 +431,30 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
[_radios removeObject:aRadio];
|
[_radios removeObject:aRadio];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Selects the first radio button within the group with the given tag.
|
||||||
|
If a radio button with the given tag is found, selects it
|
||||||
|
and returns YES. Otherwise returns NO.
|
||||||
|
*/
|
||||||
|
- (void)_selectRadioWithTitle:(CPString)aTitle
|
||||||
|
{
|
||||||
|
var index = [_radios indexOfObjectPassingTest:function(radio)
|
||||||
|
{
|
||||||
|
return [radio title] === aTitle;
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self selectRadioAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_setSelectedRadio:(CPRadio)aRadio
|
- (void)_setSelectedRadio:(CPRadio)aRadio
|
||||||
{
|
{
|
||||||
if (_selectedRadio === aRadio)
|
if (_selectedRadio === aRadio)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_selectedRadio setState:CPOffState];
|
[_selectedRadio setState:CPOffState];
|
||||||
|
|
||||||
_selectedRadio = aRadio;
|
_selectedRadio = aRadio;
|
||||||
}
|
[_CPRadioGroupSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||||
|
|
||||||
- (CPRadio)selectedRadio
|
|
||||||
{
|
|
||||||
return _selectedRadio;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPArray)radios
|
|
||||||
{
|
|
||||||
return [_radios allObjects];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -284,3 +484,85 @@ var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPRadioGroup (BindingSupport)
|
||||||
|
|
||||||
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === CPSelectedValueBinding ||
|
||||||
|
aBinding === CPSelectedTagBinding ||
|
||||||
|
aBinding === CPSelectedIndexBinding)
|
||||||
|
{
|
||||||
|
var capitalizedBinding = aBinding.charAt(0).toUpperCase() + aBinding.substr(1);
|
||||||
|
|
||||||
|
return [CPClassFromString(@"_CPRadioGroup" + capitalizedBinding + "Binder") class];
|
||||||
|
}
|
||||||
|
else if ([aBinding hasPrefix:CPEnabledBinding])
|
||||||
|
return [CPMultipleValueAndBinding class];
|
||||||
|
else if ([aBinding hasPrefix:CPHiddenBinding])
|
||||||
|
return [CPMultipleValueOrBinding class];
|
||||||
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return (aBinding == CPSelectedIndexBinding ||
|
||||||
|
aBinding == CPSelectedTagBinding ||
|
||||||
|
aBinding == CPSelectedValueBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPRadioGroupSelectionBinder : CPBinder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[self setValue:aValue forBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPRadioGroupSelectedIndexBinder : _CPRadioGroupSelectionBinder
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source selectRadioAtIndex:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [_source selectedRadioIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPRadioGroupSelectedTagBinder : _CPRadioGroupSelectionBinder
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source selectRadioWithTag:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [[_source selectedRadio] tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPRadioGroupSelectedValueBinder : _CPRadioGroupSelectionBinder
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[_source _selectRadioWithTitle:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [[_source selectedRadio] title];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+20
-2
@@ -21,7 +21,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPObjJRuntime.j>
|
||||||
|
|
||||||
|
@import "CPEvent.j"
|
||||||
|
@import "CPCursor.j"
|
||||||
|
|
||||||
|
@class CPKeyBinding
|
||||||
|
@class CPMenu
|
||||||
|
|
||||||
CPDeleteKeyCode = 8;
|
CPDeleteKeyCode = 8;
|
||||||
CPTabKeyCode = 9;
|
CPTabKeyCode = 9;
|
||||||
@@ -195,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
|
||||||
@@ -352,7 +370,7 @@ CPDeleteForwardKeyCode = 46;
|
|||||||
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
||||||
CPResponderMenuKey = @"CPResponderMenuKey";
|
CPResponderMenuKey = @"CPResponderMenuKey";
|
||||||
|
|
||||||
@implementation CPResponder (CPCoding)
|
@implementation CPResponder (CPCoding) <CPCoding>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the responder with data from a coder.
|
Initializes the responder with data from a coder.
|
||||||
@@ -379,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];
|
||||||
|
|||||||
@@ -82,15 +82,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! @cond */
|
/*! @cond */
|
||||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (theBinding == CPValueBinding)
|
if (aBinding == CPValueBinding)
|
||||||
return [CPPredicateEditorValueBinder class];
|
return [CPPredicateEditorValueBinder class];
|
||||||
|
|
||||||
return [super _binderClassForBinding:theBinding];
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_replacementKeyPathForBinding:(CPString)aBinding
|
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||||
{
|
{
|
||||||
if (aBinding == CPValueBinding)
|
if (aBinding == CPValueBinding)
|
||||||
return @"predicate";
|
return @"predicate";
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
var children = [CPArray array],
|
var children = [CPArray array],
|
||||||
itemsCount = 0,
|
itemsCount = 0,
|
||||||
menuIndex = -1,
|
menuIndex = -1,
|
||||||
itemsArray,
|
itemArray,
|
||||||
|
|
||||||
templateView = [templateViews objectAtIndex:count],
|
templateView = [templateViews objectAtIndex:count],
|
||||||
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
|
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
|
||||||
@@ -360,7 +360,11 @@
|
|||||||
rootItems = [treeChild children];
|
rootItems = [treeChild children];
|
||||||
}
|
}
|
||||||
|
|
||||||
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
|
var row = @{
|
||||||
|
@"criteria": criteria,
|
||||||
|
@"displayValues": values,
|
||||||
|
@"rowType": rowType,
|
||||||
|
};
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@@ -480,7 +484,7 @@
|
|||||||
|
|
||||||
#pragma mark RuleEditor delegate methods
|
#pragma mark RuleEditor delegate methods
|
||||||
|
|
||||||
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
|
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(CPRuleEditorRowType)type
|
||||||
{
|
{
|
||||||
if (rowItem == nil)
|
if (rowItem == nil)
|
||||||
{
|
{
|
||||||
@@ -490,7 +494,7 @@
|
|||||||
return [[rowItem children] count];
|
return [[rowItem children] count];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
|
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(CPRuleEditorRowType)type
|
||||||
{
|
{
|
||||||
if (rowItem == nil)
|
if (rowItem == nil)
|
||||||
{
|
{
|
||||||
@@ -501,7 +505,7 @@
|
|||||||
return [[rowItem children] objectAtIndex:childIndex];
|
return [[rowItem children] objectAtIndex:childIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
|
- (id)_queryValueForItem:(id)rowItem inRow:(CPInteger)rowIndex
|
||||||
{
|
{
|
||||||
return [rowItem displayValue];
|
return [rowItem displayValue];
|
||||||
}
|
}
|
||||||
@@ -512,7 +516,7 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
|||||||
|
|
||||||
@implementation CPPredicateEditor (CPCoding)
|
@implementation CPPredicateEditor (CPCoding)
|
||||||
|
|
||||||
- (id)initWithCoder:(id)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
self = [super initWithCoder:aCoder];
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
@@ -527,7 +531,7 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)encodeWithCoder:(id)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
|
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
|
||||||
|
|||||||
@@ -20,6 +20,16 @@
|
|||||||
* 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/CPPredicate.j>
|
||||||
|
|
||||||
|
@import "CPCheckBox.j"
|
||||||
|
@import "CPPopUpButton.j"
|
||||||
|
@import "CPMenuItem.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
@import "CPDatePicker.j"
|
||||||
|
|
||||||
|
|
||||||
CPUndefinedAttributeType = 0;
|
CPUndefinedAttributeType = 0;
|
||||||
CPInteger16AttributeType = 100;
|
CPInteger16AttributeType = 100;
|
||||||
CPInteger32AttributeType = 200;
|
CPInteger32AttributeType = 200;
|
||||||
@@ -461,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];
|
||||||
|
|
||||||
@@ -477,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
|
||||||
@@ -583,7 +624,7 @@ CPTransformableAttributeType = 1800;
|
|||||||
|
|
||||||
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
|
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
|
||||||
{
|
{
|
||||||
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
|
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
|
||||||
count = [expressions count];
|
count = [expressions count];
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
@@ -669,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;
|
||||||
|
|
||||||
@@ -691,12 +735,12 @@ CPTransformableAttributeType = 1800;
|
|||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setOptions:(unsigned int)options
|
- (void)_setOptions:(unsigned)options
|
||||||
{
|
{
|
||||||
_predicateOptions = options;
|
_predicateOptions = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setModifier:(unsigned int)modifier
|
- (void)_setModifier:(unsigned)modifier
|
||||||
{
|
{
|
||||||
_predicateModifier = modifier;
|
_predicateModifier = modifier;
|
||||||
}
|
}
|
||||||
@@ -786,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 */
|
||||||
|
|||||||
+193
-135
@@ -20,35 +20,41 @@
|
|||||||
* 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 <AppKit/CPTextField.j>
|
|
||||||
@import <AppKit/CPViewAnimation.j>
|
|
||||||
@import <AppKit/CPView.j>
|
|
||||||
@import <Foundation/CPPredicate.j>
|
@import <Foundation/CPPredicate.j>
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPIndexSet.j>
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
|
||||||
|
@import "CPPasteboard.j"
|
||||||
|
@import "CPRuleEditor_Constants.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "CPViewAnimation.j"
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
@import "_CPRuleEditorViewSliceRow.j"
|
@import "_CPRuleEditorViewSliceRow.j"
|
||||||
@import "_CPRuleEditorLocalizer.j"
|
@import "_CPRuleEditorLocalizer.j"
|
||||||
|
|
||||||
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
@class CPCompoundPredicate
|
||||||
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
@class CPComparisonPredicate
|
||||||
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
|
||||||
CPRuleEditorPredicateOptions = "CPRuleEditorPredicateOptions";
|
|
||||||
CPRuleEditorPredicateOperatorType = "CPRuleEditorPredicateOperatorType";
|
|
||||||
CPRuleEditorPredicateCustomSelector = "CPRuleEditorPredicateCustomSelector";
|
|
||||||
CPRuleEditorPredicateCompoundType = "CPRuleEditorPredicateCompoundType";
|
|
||||||
|
|
||||||
CPRuleEditorRowsDidChangeNotification = "CPRuleEditorRowsDidChangeNotification";
|
@global CPDirectPredicateModifier
|
||||||
CPRuleEditorRulesDidChangeNotification = "CPRuleEditorRulesDidChangeNotification";
|
@global CPCaseInsensitivePredicateOption
|
||||||
|
@global CPOrPredicateType
|
||||||
|
|
||||||
CPRuleEditorNestingModeSingle = 0; // Only a single row is allowed. Plus/minus buttons will not be shown
|
@protocol CPRuleEditorDelegate <CPObject>
|
||||||
CPRuleEditorNestingModeList = 1; // Allows a single list, with no nesting and no compound rows
|
|
||||||
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
|
|
||||||
|
|
||||||
CPRuleEditorRowTypeSimple = 0;
|
@required
|
||||||
CPRuleEditorRowTypeCompound = 1;
|
- (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",
|
||||||
@@ -78,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 */
|
||||||
@@ -131,20 +138,30 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
return @"rule-editor";
|
return @"rule-editor";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
return @{
|
||||||
forKeys:[@"alternating-row-colors", @"selected-color", @"slice-top-border-color", @"slice-bottom-border-color", @"slice-last-bottom-border-color", @"font", @"add-image", @"remove-image"]];
|
@"alternating-row-colors": [CPNull null],
|
||||||
|
@"selected-color": [CPNull null],
|
||||||
|
@"slice-top-border-color": [CPNull null],
|
||||||
|
@"slice-bottom-border-color": [CPNull null],
|
||||||
|
@"slice-last-bottom-border-color": [CPNull null],
|
||||||
|
@"font": [CPFont systemFontOfSize:12],
|
||||||
|
@"font-color": [CPNull null],
|
||||||
|
@"add-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;
|
||||||
@@ -214,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.
|
||||||
@@ -397,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)
|
||||||
@@ -405,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]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,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])
|
||||||
@@ -462,7 +484,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
@param row The index of a row in the receiver.
|
@param row The index of a row in the receiver.
|
||||||
@return The currently chosen items for row @a row.
|
@return The currently chosen items for row @a row.
|
||||||
*/
|
*/
|
||||||
- (id)criteriaForRow:(int)row
|
- (id)criteriaForRow:(CPInteger)row
|
||||||
{
|
{
|
||||||
var rowcache = [self _rowCacheForIndex:row];
|
var rowcache = [self _rowCacheForIndex:row];
|
||||||
if (rowcache)
|
if (rowcache)
|
||||||
@@ -481,7 +503,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
@return The chosen values (strings, views, or menu items) for row row.
|
@return The chosen values (strings, views, or menu items) for row row.
|
||||||
@discussion The values returned are the same as those returned from the delegate method -#ruleEditor:displayValueForCriterion:inRow:
|
@discussion The values returned are the same as those returned from the delegate method -#ruleEditor:displayValueForCriterion:inRow:
|
||||||
*/
|
*/
|
||||||
- (CPMutableArray)displayValuesForRow:(int)row
|
- (CPMutableArray)displayValuesForRow:(CPInteger)row
|
||||||
{
|
{
|
||||||
var rowcache = [self _rowCacheForIndex:row];
|
var rowcache = [self _rowCacheForIndex:row];
|
||||||
if (rowcache)
|
if (rowcache)
|
||||||
@@ -504,7 +526,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
|||||||
@param rowIndex The index of a row in the receiver.
|
@param rowIndex The index of a row in the receiver.
|
||||||
@return The index of the parent of the row at @a rowIndex. If the row at @a rowIndex is a root row, returns @c -1.
|
@return The index of the parent of the row at @a rowIndex. If the row at @a rowIndex is a root row, returns @c -1.
|
||||||
*/
|
*/
|
||||||
- (int)parentRowForRow:(int)rowIndex
|
- (int)parentRowForRow:(CPInteger)rowIndex
|
||||||
{
|
{
|
||||||
if (rowIndex < 0 || rowIndex >= [self numberOfRows])
|
if (rowIndex < 0 || rowIndex >= [self numberOfRows])
|
||||||
[CPException raise:CPRangeException reason:_cmd + @" row " + rowIndex + " is out of range"];
|
[CPException raise:CPRangeException reason:_cmd + @" row " + rowIndex + " is out of range"];
|
||||||
@@ -545,7 +567,7 @@ TODO: implement
|
|||||||
@return The type of the row at @a rowIndex.
|
@return The type of the row at @a rowIndex.
|
||||||
@warning Raises a @c CPRangeException if rowIndex is less than @c 0 or greater than or equal to the number of rows.
|
@warning Raises a @c CPRangeException if rowIndex is less than @c 0 or greater than or equal to the number of rows.
|
||||||
*/
|
*/
|
||||||
- (CPRuleEditorRowType)rowTypeForRow:(int)rowIndex
|
- (CPRuleEditorRowType)rowTypeForRow:(CPInteger)rowIndex
|
||||||
{
|
{
|
||||||
if (rowIndex < 0 || rowIndex > [self numberOfRows])
|
if (rowIndex < 0 || rowIndex > [self numberOfRows])
|
||||||
[CPException raise:CPRangeException reason:_cmd + @"row " + rowIndex + " is out of range"];
|
[CPException raise:CPRangeException reason:_cmd + @"row " + rowIndex + " is out of range"];
|
||||||
@@ -566,7 +588,7 @@ TODO: implement
|
|||||||
@return The immediate subrows of the row at @a rowIndex.
|
@return The immediate subrows of the row at @a rowIndex.
|
||||||
@discussion Rows are numbered starting at @c 0.
|
@discussion Rows are numbered starting at @c 0.
|
||||||
*/
|
*/
|
||||||
- (CPIndexSet)subrowIndexesForRow:(int)rowIndex
|
- (CPIndexSet)subrowIndexesForRow:(CPInteger)rowIndex
|
||||||
{
|
{
|
||||||
var object;
|
var object;
|
||||||
|
|
||||||
@@ -692,7 +714,7 @@ TODO: implement
|
|||||||
@note Currently, @a shouldAnimate has no effect, rows are always animated when calling this method.
|
@note Currently, @a shouldAnimate has no effect, rows are always animated when calling this method.
|
||||||
@see addRow:
|
@see addRow:
|
||||||
*/
|
*/
|
||||||
- (void)insertRowAtIndex:(int)rowIndex withType:(unsigned int)rowType asSubrowOfRow:(int)parentRow animate:(BOOL)shouldAnimate
|
- (void)insertRowAtIndex:(int)rowIndex withType:(unsigned int)rowType asSubrowOfRow:(CPInteger)parentRow animate:(BOOL)shouldAnimate
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
TODO: raise exceptions if parentRow is greater than or equal to rowIndex, or if rowIndex would fall amongst the children of some other parent, or if the nesting mode forbids this configuration.
|
TODO: raise exceptions if parentRow is greater than or equal to rowIndex, or if rowIndex would fall amongst the children of some other parent, or if the nesting mode forbids this configuration.
|
||||||
@@ -800,7 +822,7 @@ TODO: implement
|
|||||||
*/
|
*/
|
||||||
- (CPPredicate)predicateForRow:(CPInteger)aRow
|
- (CPPredicate)predicateForRow:(CPInteger)aRow
|
||||||
{
|
{
|
||||||
var predicateParts = [CPDictionary dictionary],
|
var predicateParts = @{},
|
||||||
items = [self criteriaForRow:aRow],
|
items = [self criteriaForRow:aRow],
|
||||||
count = [items count],
|
count = [items count],
|
||||||
predicate,
|
predicate,
|
||||||
@@ -811,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];
|
||||||
@@ -830,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];
|
||||||
@@ -866,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
|
||||||
@@ -1145,7 +1167,7 @@ TODO: implement
|
|||||||
|
|
||||||
- (BOOL)_wantsRowAnimations
|
- (BOOL)_wantsRowAnimations
|
||||||
{
|
{
|
||||||
return (_currentAnimation !== nil);
|
return (_currentAnimation != nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateButtonVisibilities
|
- (void)_updateButtonVisibilities
|
||||||
@@ -1314,7 +1336,7 @@ TODO: implement
|
|||||||
return [_boundArrayOwner mutableArrayValueForKey:_boundArrayKeyPath];
|
return [_boundArrayOwner mutableArrayValueForKey:_boundArrayKeyPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_nextUnusedItems:(CPArray)items andValues:(CPArray)values forRow:(int)rowIndex forRowType:(unsigned int)type
|
- (BOOL)_nextUnusedItems:(CPArray)items andValues:(CPArray)values forRow:(CPInteger)rowIndex forRowType:(unsigned int)type
|
||||||
{
|
{
|
||||||
var parentItem = [items lastObject], // if empty items array, this is NULL aka the root item;
|
var parentItem = [items lastObject], // if empty items array, this is NULL aka the root item;
|
||||||
childrenCount = [self _queryNumberOfChildrenOfItem:parentItem withRowType:type],
|
childrenCount = [self _queryNumberOfChildrenOfItem:parentItem withRowType:type],
|
||||||
@@ -1376,7 +1398,7 @@ TODO: implement
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPMutableArray)_getItemsAndValuesToAddForRow:(int)rowIndex ofType:(CPRuleEditorRowType)type
|
- (CPMutableArray)_getItemsAndValuesToAddForRow:(CPInteger)rowIndex ofType:(CPRuleEditorRowType)type
|
||||||
{
|
{
|
||||||
//var cachedItemsAndValues = _itemsAndValuesToAddForRowType[type];
|
//var cachedItemsAndValues = _itemsAndValuesToAddForRowType[type];
|
||||||
//if (cachedItemsAndValues)
|
//if (cachedItemsAndValues)
|
||||||
@@ -1396,7 +1418,10 @@ TODO: implement
|
|||||||
{
|
{
|
||||||
var item = [items objectAtIndex:i],
|
var item = [items objectAtIndex:i],
|
||||||
value = [values objectAtIndex:i],
|
value = [values objectAtIndex:i],
|
||||||
itemAndValue = [CPDictionary dictionaryWithObjects:[item, value] forKeys:["item", "value"]];
|
itemAndValue = @{
|
||||||
|
"item": item,
|
||||||
|
"value": value,
|
||||||
|
};
|
||||||
|
|
||||||
[itemsAndValues addObject:itemAndValue];
|
[itemsAndValues addObject:itemAndValue];
|
||||||
}
|
}
|
||||||
@@ -1416,7 +1441,7 @@ TODO: implement
|
|||||||
[self insertRowAtIndex:insertIndex withType:type asSubrowOfRow:parentRowIndex animate:YES];
|
[self insertRowAtIndex:insertIndex withType:type asSubrowOfRow:parentRowIndex animate:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_insertNewRowAtIndex:(int)insertIndex ofType:(CPRuleEditorRowType)rowtype withParentRow:(int)parentRowIndex
|
- (id)_insertNewRowAtIndex:(int)insertIndex ofType:(CPRuleEditorRowType)rowtype withParentRow:(CPInteger)parentRowIndex
|
||||||
{
|
{
|
||||||
var row = [[[self rowClass] alloc] init],
|
var row = [[[self rowClass] alloc] init],
|
||||||
itemsandvalues = [self _getItemsAndValuesToAddForRow:insertIndex ofType:rowtype],
|
itemsandvalues = [self _getItemsAndValuesToAddForRow:insertIndex ofType:rowtype],
|
||||||
@@ -1512,26 +1537,13 @@ TODO: implement
|
|||||||
oldRows = [CPArray arrayWithArray:newRows];
|
oldRows = [CPArray arrayWithArray:newRows];
|
||||||
[oldRows removeObjectsInArray:changeNewValue];
|
[oldRows removeObjectsInArray:changeNewValue];
|
||||||
}
|
}
|
||||||
else if (changeKind === CPKeyValueChangeRemoval)
|
|
||||||
{
|
|
||||||
newRows = [self _subrowObjectsOfObject:object];
|
|
||||||
oldRows = [CPArray arrayWithArray:newRows];
|
|
||||||
var delIndexes = [change objectForKey:CPKeyValueChangeIndexesKey];
|
|
||||||
[oldRows insertObjects:delObjects atIndexes:changeOldValue]; // Pas sur que ce soit bon
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _changedRowArray:newRows withOldRowArray:oldRows forParent:object];
|
[self _changedRowArray:newRows withOldRowArray:oldRows forParent:object];
|
||||||
[self _reconfigureSubviewsAnimate:[self _wantsRowAnimations]];
|
[self _reconfigureSubviewsAnimate:[self _wantsRowAnimations]];
|
||||||
}
|
}
|
||||||
else if (context === itemsContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (context === valuesContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_changedItem:(id)fromItem toItem:(id)toItem inRow:(int)aRow atCriteriaIndex:(int)fromItemIndex
|
- (void)_changedItem:(id)fromItem toItem:(id)toItem inRow:(CPInteger)aRow atCriteriaIndex:(int)fromItemIndex
|
||||||
{
|
{
|
||||||
var criteria = [self criteriaForRow:aRow],
|
var criteria = [self criteriaForRow:aRow],
|
||||||
displayValues = [self displayValuesForRow:aRow],
|
displayValues = [self displayValuesForRow:aRow],
|
||||||
@@ -1695,7 +1707,7 @@ TODO: implement
|
|||||||
[super bind:aBinding toObject:observableController withKeyPath:aKeyPath options:options];
|
[super bind:aBinding toObject:observableController withKeyPath:aKeyPath options:options];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)unbind:(id)object
|
- (void)unbind:(CPString)object
|
||||||
{
|
{
|
||||||
_rowClass = [_CPRuleEditorRowObject class];
|
_rowClass = [_CPRuleEditorRowObject class];
|
||||||
[super unbind:object];
|
[super unbind:object];
|
||||||
@@ -1703,8 +1715,8 @@ TODO: implement
|
|||||||
|
|
||||||
- (void)_setBoundDataSource:(id)datasource withKeyPath:(CPString)keyPath options:(CPDictionary)options
|
- (void)_setBoundDataSource:(id)datasource withKeyPath:(CPString)keyPath options:(CPDictionary)options
|
||||||
{
|
{
|
||||||
if ([observableController respondsToSelector:@selector(objectClass)])
|
if ([datasource respondsToSelector:@selector(objectClass)])
|
||||||
_rowClass = [observableController objectClass];
|
_rowClass = [datasource objectClass];
|
||||||
|
|
||||||
_boundArrayKeyPath = keyPath;
|
_boundArrayKeyPath = keyPath;
|
||||||
_boundArrayOwner = datasource;
|
_boundArrayOwner = datasource;
|
||||||
@@ -1727,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;
|
||||||
@@ -1742,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];
|
||||||
@@ -1784,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];
|
||||||
@@ -1793,7 +1804,7 @@ TODO: implement
|
|||||||
|
|
||||||
if (animate)
|
if (animate)
|
||||||
{
|
{
|
||||||
var animation = [CPDictionary dictionary];
|
var animation = @{};
|
||||||
[animation setObject:aslice forKey:CPViewAnimationTargetKey];
|
[animation setObject:aslice forKey:CPViewAnimationTargetKey];
|
||||||
[animation setObject:startRect forKey:CPViewAnimationStartFrameKey];
|
[animation setObject:startRect forKey:CPViewAnimationStartFrameKey];
|
||||||
[animation setObject:targetRect forKey:CPViewAnimationEndFrameKey];
|
[animation setObject:targetRect forKey:CPViewAnimationEndFrameKey];
|
||||||
@@ -1876,29 +1887,49 @@ 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
|
||||||
{
|
{
|
||||||
return @"Add Compound row";
|
return [_standardLocalizer localizedStringForString:@"Add compound row"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)_toolTipForAddSimpleRowButton
|
- (CPString)_toolTipForAddSimpleRowButton
|
||||||
{
|
{
|
||||||
return @"Add row";
|
return [_standardLocalizer localizedStringForString:@"Add row"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)_toolTipForDeleteRowButton
|
- (CPString)_toolTipForDeleteRowButton
|
||||||
{
|
{
|
||||||
return @"Delete row";
|
return [_standardLocalizer localizedStringForString:@"Delete row"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateSliceIndentations
|
- (void)_updateSliceIndentations
|
||||||
@@ -2016,7 +2047,7 @@ TODO: implement
|
|||||||
return [_ruleDelegate ruleEditor:self child:childIndex forCriterion:item withRowType:type];
|
return [_ruleDelegate ruleEditor:self child:childIndex forCriterion:item withRowType:type];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_queryValueForItem:(id)item inRow:(int)row
|
- (id)_queryValueForItem:(id)item inRow:(CPInteger)row
|
||||||
{
|
{
|
||||||
return [_ruleDelegate ruleEditor:self displayValueForCriterion:item inRow:row];
|
return [_ruleDelegate ruleEditor:self displayValueForCriterion:item inRow:row];
|
||||||
}
|
}
|
||||||
@@ -2037,12 +2068,12 @@ TODO: implement
|
|||||||
_alignmentGridWidth = width;
|
_alignmentGridWidth = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_validateItem:(id)item value:(id)value inRow:(int)row
|
- (BOOL)_validateItem:(id)item value:(id)value inRow:(CPInteger)row
|
||||||
{
|
{
|
||||||
return [self _queryCanSelectItem:item displayValue:value inRow:row];
|
return [self _queryCanSelectItem:item displayValue:value inRow:row];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_queryCanSelectItem:(id)item displayValue:(id)value inRow:(int)row
|
- (BOOL)_queryCanSelectItem:(id)item displayValue:(id)value inRow:(CPInteger)row
|
||||||
{
|
{
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@@ -2058,7 +2089,7 @@ TODO: implement
|
|||||||
[super setNeedsDisplay:flag];
|
[super setNeedsDisplay:flag];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrameSize:(CPSize)size
|
- (void)setFrameSize:(CGSize)size
|
||||||
{
|
{
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
@@ -2090,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];
|
||||||
@@ -2098,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
|
||||||
@@ -2126,7 +2157,7 @@ TODO: implement
|
|||||||
[dragview setBackgroundColor:[firstSlice backgroundColor]];
|
[dragview setBackgroundColor:[firstSlice backgroundColor]];
|
||||||
[dragview setAlphaValue:0.7];
|
[dragview setAlphaValue:0.7];
|
||||||
|
|
||||||
dragPoint = CPMakePoint(0, firstIndex * _sliceHeight);
|
dragPoint = CGPointMake(0, firstIndex * _sliceHeight);
|
||||||
|
|
||||||
[self dragView:dragview
|
[self dragView:dragview
|
||||||
at:dragPoint
|
at:dragPoint
|
||||||
@@ -2139,7 +2170,7 @@ TODO: implement
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPDragOperation)draggingEntered:(id < CPDraggingInfo >)sender
|
- (CPDragOperation)draggingEntered:(id /*< CPDraggingInfo >*/)sender
|
||||||
{
|
{
|
||||||
if ([sender draggingSource] === self)
|
if ([sender draggingSource] === self)
|
||||||
{
|
{
|
||||||
@@ -2169,14 +2200,14 @@ TODO: implement
|
|||||||
_subviewIndexOfDropLine = CPNotFound;
|
_subviewIndexOfDropLine = CPNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPDragOperation)draggingUpdated:(id <CPDraggingInfo>)sender
|
- (CPDragOperation)draggingUpdated:(id /*<CPDraggingInfo>*/)sender
|
||||||
{
|
{
|
||||||
var point = [self convertPoint:[sender draggingLocation] fromView:nil],
|
var point = [self convertPoint:[sender draggingLocation] fromView:nil],
|
||||||
y = point.y + _sliceHeight / 2,
|
y = point.y + _sliceHeight / 2,
|
||||||
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];
|
||||||
@@ -2188,7 +2219,7 @@ TODO: implement
|
|||||||
if (_subviewIndexOfDropLine !== CPNotFound && _subviewIndexOfDropLine < numberOfRows)
|
if (_subviewIndexOfDropLine !== CPNotFound && _subviewIndexOfDropLine < numberOfRows)
|
||||||
{
|
{
|
||||||
var previousBelowSlice = [_slices objectAtIndex:_subviewIndexOfDropLine];
|
var previousBelowSlice = [_slices objectAtIndex:_subviewIndexOfDropLine];
|
||||||
[previousBelowSlice setFrameOrigin:CPMakePoint(0, [previousBelowSlice rowIndex] * _sliceHeight)];
|
[previousBelowSlice setFrameOrigin:CGPointMake(0, [previousBelowSlice rowIndex] * _sliceHeight)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indexOfDropLine <= _lastRow && indexOfDropLine < numberOfRows)
|
if (indexOfDropLine <= _lastRow && indexOfDropLine < numberOfRows)
|
||||||
@@ -2206,12 +2237,12 @@ TODO: implement
|
|||||||
return CPDragOperationMove;
|
return CPDragOperationMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)prepareForDragOperation:(id < CPDraggingInfo >)sender
|
- (BOOL)prepareForDragOperation:(id /*< CPDraggingInfo >*/)sender
|
||||||
{
|
{
|
||||||
return (_subviewIndexOfDropLine !== CPNotFound);
|
return (_subviewIndexOfDropLine !== CPNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)performDragOperation:(id < CPDraggingInfo >)info
|
- (BOOL)performDragOperation:(id /*< CPDraggingInfo >*/)info
|
||||||
{
|
{
|
||||||
var aboveInsertIndexCount = 0,
|
var aboveInsertIndexCount = 0,
|
||||||
object,
|
object,
|
||||||
@@ -2254,7 +2285,7 @@ TODO: implement
|
|||||||
return [CPIndexSet indexSetWithIndex:CPDragOperationMove];
|
return [CPIndexSet indexSetWithIndex:CPDragOperationMove];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)draggedView:(CPView)dragView endedAt:(CPPoint)aPoint operation:(CPDragOperation)operation
|
- (void)draggedView:(CPView)dragView endedAt:(CGPoint)aPoint operation:(CPDragOperation)operation
|
||||||
{
|
{
|
||||||
_draggingRows = nil;
|
_draggingRows = nil;
|
||||||
|
|
||||||
@@ -2273,7 +2304,7 @@ TODO: implement
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setWindow:(id)window
|
- (void)_setWindow:(CPWindow)window
|
||||||
{
|
{
|
||||||
[super _setWindow:window];
|
[super _setWindow:window];
|
||||||
}
|
}
|
||||||
@@ -2290,7 +2321,7 @@ TODO: implement
|
|||||||
|
|
||||||
- (void)_postRowCountChangedNotificationOfType:(CPString)notificationName indexes:indexes
|
- (void)_postRowCountChangedNotificationOfType:(CPString)notificationName indexes:indexes
|
||||||
{
|
{
|
||||||
var userInfo = [CPDictionary dictionaryWithObject:indexes forKey:"indexes"];
|
var userInfo = indexes == nil ? @{} : @{ "indexes": indexes };
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo];
|
[[CPNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:userInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2336,7 +2367,7 @@ TODO: implement
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_getAllAvailableItems:(id)items values:(id)values asChildrenOfItem:(id)parentItem inRow:(int)aRow
|
- (void)_getAllAvailableItems:(id)items values:(id)values asChildrenOfItem:(id)parentItem inRow:(CPInteger)aRow
|
||||||
{
|
{
|
||||||
var type,
|
var type,
|
||||||
indexofCriterion,
|
indexofCriterion,
|
||||||
@@ -2355,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)
|
||||||
{
|
{
|
||||||
@@ -2388,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",
|
||||||
@@ -2411,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];
|
||||||
@@ -2437,7 +2495,7 @@ var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)encodeWithCoder:(id)coder
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
[super encodeWithCoder:coder];
|
[super encodeWithCoder:coder];
|
||||||
|
|
||||||
@@ -2492,10 +2550,10 @@ var CriteriaKey = @"criteria",
|
|||||||
return "<" + [self className] + ">\nsubrows = " + [subrows description] + "\ncriteria = " + [criteria description] + "\ndisplayValues = " + [displayValues description];
|
return "<" + [self className] + ">\nsubrows = " + [subrows description] + "\ncriteria = " + [criteria description] + "\ndisplayValues = " + [displayValues description];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithCoder:(id)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];
|
||||||
@@ -2506,7 +2564,7 @@ var CriteriaKey = @"criteria",
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)encodeWithCoder:(id)coder
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
[coder encodeObject:subrows forKey:SubrowsKey];
|
[coder encodeObject:subrows forKey:SubrowsKey];
|
||||||
[coder encodeObject:criteria forKey:CriteriaKey];
|
[coder encodeObject:criteria forKey:CriteriaKey];
|
||||||
@@ -2545,7 +2603,7 @@ var CPBoundArrayKey = @"CPBoundArray";
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithCoder:(id)coder
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
boundArray = [coder decodeObjectForKey:CPBoundArrayKey];
|
boundArray = [coder decodeObjectForKey:CPBoundArrayKey];
|
||||||
@@ -2553,7 +2611,7 @@ var CPBoundArrayKey = @"CPBoundArray";
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)encodeWithCoder:(id)coder
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
[coder encodeObject:boundArray forKey:CPBoundArrayKey];
|
[coder encodeObject:boundArray forKey:CPBoundArrayKey];
|
||||||
}
|
}
|
||||||
@@ -2578,7 +2636,7 @@ var dropSeparatorColor = [CPColor colorWithHexString:@"4886ca"];
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CPRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
CGContextSetFillColor(context, dropSeparatorColor);
|
CGContextSetFillColor(context, dropSeparatorColor);
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* CPRuleEditor_Constants.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by cacaodev.
|
||||||
|
* Copyright 2011, cacaodev.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
||||||
|
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
||||||
|
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
||||||
|
CPRuleEditorPredicateOptions = "CPRuleEditorPredicateOptions";
|
||||||
|
CPRuleEditorPredicateOperatorType = "CPRuleEditorPredicateOperatorType";
|
||||||
|
CPRuleEditorPredicateCustomSelector = "CPRuleEditorPredicateCustomSelector";
|
||||||
|
CPRuleEditorPredicateCompoundType = "CPRuleEditorPredicateCompoundType";
|
||||||
|
|
||||||
|
CPRuleEditorRowsDidChangeNotification = "CPRuleEditorRowsDidChangeNotification";
|
||||||
|
CPRuleEditorRulesDidChangeNotification = "CPRuleEditorRulesDidChangeNotification";
|
||||||
|
|
||||||
|
CPRuleEditorNestingModeSingle = 0; // Only a single row is allowed. Plus/minus buttons will not be shown
|
||||||
|
CPRuleEditorNestingModeList = 1; // Allows a single list, with no nesting and no compound rows
|
||||||
|
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
|
||||||
|
|
||||||
|
@typedef CPRuleEditorRowType
|
||||||
|
CPRuleEditorRowTypeSimple = 0;
|
||||||
|
CPRuleEditorRowTypeCompound = 1;
|
||||||
@@ -1,9 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
* Created by cacaodev@gmail.com.
|
* Created by cacaodev@gmail.com.
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
* 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@class _CPPredicateEditorTree;
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@implementation _CPPredicateEditorRowNode : CPObject
|
@implementation _CPPredicateEditorRowNode : CPObject
|
||||||
{
|
{
|
||||||
_CPPredicateEditorTree tree @accessors;
|
_CPPredicateEditorTree tree @accessors;
|
||||||
@@ -115,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];
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* Created by cacaodev@gmail.com.
|
* Created by cacaodev@gmail.com.
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
* 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 <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
@class CPPredicateEditorRowTemplate
|
||||||
|
|
||||||
@implementation _CPPredicateEditorTree : CPObject
|
@implementation _CPPredicateEditorTree : CPObject
|
||||||
{
|
{
|
||||||
CPPredicateEditorRowTemplate template @accessors;
|
CPPredicateEditorRowTemplate template @accessors;
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* Created by cacaodev@gmail.com.
|
* Created by cacaodev@gmail.com.
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
* 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 <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
@import <Foundation/CPURLConnection.j>
|
||||||
|
@import <Foundation/CPURLRequest.j>
|
||||||
|
|
||||||
var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||||
|
|
||||||
@@ -13,7 +29,7 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
|||||||
{
|
{
|
||||||
CPDictionary _dictionary @accessors(property=dictionary);
|
CPDictionary _dictionary @accessors(property=dictionary);
|
||||||
CPURLConnection connection;
|
CPURLConnection connection;
|
||||||
CPURLRequest resquest;
|
CPURLRequest request;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadContentOfURL:(CPURL)aURL
|
- (void)loadContentOfURL:(CPURL)aURL
|
||||||
@@ -24,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;
|
||||||
|
|
||||||
@@ -35,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;
|
||||||
@@ -43,7 +59,7 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
|||||||
|
|
||||||
- (void)loadContent:(CPString)aContent
|
- (void)loadContent:(CPString)aContent
|
||||||
{
|
{
|
||||||
var dict = [CPDictionary dictionary],
|
var dict = @{},
|
||||||
lines = [aContent componentsSeparatedByString:"\n"],
|
lines = [aContent componentsSeparatedByString:"\n"],
|
||||||
count = [lines count];
|
count = [lines count];
|
||||||
|
|
||||||
@@ -67,13 +83,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aString;
|
return aString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
@@ -1,178 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by cacaodev@gmail.com.
|
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import "CPPopUpButton.j"
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
var style = _DOMElement.style;
|
|
||||||
style.border = "1px solid " + BORDER_COLOR;
|
|
||||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)hitTest:(CPPoint)point
|
|
||||||
{
|
|
||||||
if (!CPRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)sliceIsEditable
|
|
||||||
{
|
|
||||||
var superview = [self superview];
|
|
||||||
return ![superview isKindOfClass:[_CPRuleEditorViewSlice]] || [superview isEditable];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trackMouse:(CPEvent)theEvent
|
|
||||||
{
|
|
||||||
if (![self sliceIsEditable])
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
|
||||||
var style = _DOMElement.style,
|
|
||||||
radiusCSS = radius + "px";
|
|
||||||
|
|
||||||
style.borderRadius = radiusCSS;
|
|
||||||
|
|
||||||
[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];
|
|
||||||
|
|
||||||
var style = _DOMElement.style;
|
|
||||||
style.border = "1px solid " + BORDER_COLOR;
|
|
||||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
[super layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,17 +1,35 @@
|
|||||||
/*
|
/*
|
||||||
* Created by cacaodev@gmail.com.
|
* Created by cacaodev@gmail.com.
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
* 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 "CPView.j"
|
||||||
|
|
||||||
|
@class CPRuleEditor
|
||||||
|
|
||||||
@implementation _CPRuleEditorViewSlice : CPView
|
@implementation _CPRuleEditorViewSlice : CPView
|
||||||
{
|
{
|
||||||
CPRuleEditor _ruleEditor;
|
CPRuleEditor _ruleEditor;
|
||||||
int _indentation @accessors(property=indentation);
|
int _indentation @accessors(property=indentation);
|
||||||
int _rowIndex @accessors(property=rowIndex);
|
int _rowIndex @accessors(property=rowIndex);
|
||||||
CPRect _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:);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeFromSuperview
|
- (void)removeFromSuperview
|
||||||
@@ -36,19 +54,19 @@
|
|||||||
if (select == _selected)
|
if (select == _selected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
var selector = select ? @selector(setThemeState:) : @selector(unsetThemeState:);
|
||||||
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
|
[[self subviews] makeObjectsPerformSelector:selector withObject:CPThemeStateSelectedDataView];
|
||||||
_selected = select;
|
_selected = select;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CPRect)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])
|
||||||
_backgroundColor = [_ruleEditor _selectedRowColor];
|
_backgroundColor = [_ruleEditor _selectedRowColor];
|
||||||
else
|
else
|
||||||
@@ -61,33 +79,33 @@
|
|||||||
CGContextSetFillColor(context, _backgroundColor);
|
CGContextSetFillColor(context, _backgroundColor);
|
||||||
CGContextFillRect(context, rect);
|
CGContextFillRect(context, rect);
|
||||||
|
|
||||||
// Draw Top Border
|
// Draw Top Border
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextMoveToPoint(context, 0, 0);
|
CGContextMoveToPoint(context, 0, 0);
|
||||||
CGContextAddLineToPoint(context, maxX, 0);
|
CGContextAddLineToPoint(context, maxX, 0);
|
||||||
CGContextClosePath(context);
|
|
||||||
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
|
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
// Draw Bottom Border
|
// Draw Bottom Border
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextMoveToPoint(context, 0, maxY);
|
CGContextMoveToPoint(context, 0, maxY);
|
||||||
CGContextAddLineToPoint(context, maxX, maxY);
|
CGContextAddLineToPoint(context, maxX, maxY);
|
||||||
CGContextClosePath(context);
|
|
||||||
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
|
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
|
||||||
|
|
||||||
CGContextSetStrokeColor(context, bottomColor);
|
CGContextSetStrokeColor(context, bottomColor);
|
||||||
CGContextStrokePath(context);
|
CGContextStrokePath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)theEvent
|
- (void)mouseDown:(CPEvent)theEvent
|
||||||
{
|
{
|
||||||
if (editable)
|
if (_editable)
|
||||||
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
|
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseUp:(CPEvent)theEvent
|
- (void)mouseUp:(CPEvent)theEvent
|
||||||
{
|
{
|
||||||
if (editable)
|
if (_editable)
|
||||||
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
|
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* Created by cacaodev@gmail.com.
|
* Created by cacaodev@gmail.com.
|
||||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
* 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 "CPRuleEditor_Constants.j"
|
||||||
@import "_CPRuleEditorViewSlice.j"
|
@import "_CPRuleEditorViewSlice.j"
|
||||||
@import "_CPRuleEditorPopUpButton.j"
|
|
||||||
@import "CPRuleEditor.j"
|
|
||||||
|
|
||||||
var CONTROL_HEIGHT = 16.,
|
@import "CPButton.j"
|
||||||
BUTTON_HEIGHT = 16.;
|
@import "CPDatePicker.j"
|
||||||
|
@import "CPPopUpButton.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
@global CPMiniControlSize
|
||||||
|
@global CPSmallControlSize
|
||||||
|
|
||||||
@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;
|
||||||
BOOL editable;
|
|
||||||
CPRuleEditorRowType _rowType @accessors;
|
|
||||||
CPRuleEditorRowType _plusButtonRowType;
|
CPRuleEditorRowType _rowType @accessors;
|
||||||
|
CPRuleEditorRowType _plusButtonRowType;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
||||||
@@ -33,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;
|
||||||
@@ -70,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];
|
||||||
|
|
||||||
@@ -81,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];
|
||||||
|
|
||||||
@@ -91,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];
|
||||||
@@ -121,17 +142,18 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
return [CPMenuItem separatorItem];
|
return [CPMenuItem separatorItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
- (CPTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
||||||
{
|
{
|
||||||
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CPMakeRect(0, 0, 200, CONTROL_HEIGHT)],
|
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()],
|
||||||
refont = [_ruleEditor font],
|
ruleEditorFont = [_ruleEditor font],
|
||||||
font = [CPFont fontWithName:[refont familyName] size:[refont 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];
|
||||||
|
|
||||||
|
[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];
|
||||||
[textField sizeToFit];
|
|
||||||
|
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
@@ -142,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;
|
||||||
|
|
||||||
@@ -153,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])
|
||||||
{
|
{
|
||||||
@@ -186,8 +209,7 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
- (void)_reconfigureSubviews
|
- (void)_reconfigureSubviews
|
||||||
{
|
{
|
||||||
var ruleItems,
|
var criteria,
|
||||||
criteria,
|
|
||||||
repObject,
|
repObject,
|
||||||
menuItem,
|
menuItem,
|
||||||
ruleView,
|
ruleView,
|
||||||
@@ -254,7 +276,11 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
|
repObject = @{
|
||||||
|
@"item": childItem,
|
||||||
|
@"value": childValue,
|
||||||
|
@"indexInCriteria": i
|
||||||
|
};
|
||||||
[menuItem setRepresentedObject:repObject];
|
[menuItem setRepresentedObject:repObject];
|
||||||
[menuItems addObject:menuItem];
|
[menuItems addObject:menuItem];
|
||||||
}
|
}
|
||||||
@@ -286,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];
|
||||||
|
|
||||||
@@ -300,7 +334,7 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
|
|
||||||
[_correspondingRuleItems setArray:ruleItems];
|
[_correspondingRuleItems setArray:ruleItems];
|
||||||
|
|
||||||
if (!editable)
|
if (!_editable)
|
||||||
[self _updateEnabledStateForSubviews];
|
[self _updateEnabledStateForSubviews];
|
||||||
|
|
||||||
[self _relayoutSubviewsWidthChanged:YES];
|
[self _relayoutSubviewsWidthChanged:YES];
|
||||||
@@ -310,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
|
||||||
@@ -329,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)
|
||||||
@@ -351,15 +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;
|
||||||
// small positioning fix
|
|
||||||
if ([ruleOptionView isKindOfClass:CPTextField])
|
|
||||||
{
|
|
||||||
optionFrame.origin.y += 2;
|
|
||||||
[_ruleOptionViews[i] setValue:CGInsetMake(7, 7, 7, 8) forThemeAttribute:@"content-inset"];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (widthChanged)
|
if (widthChanged)
|
||||||
{
|
{
|
||||||
@@ -390,14 +417,9 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
[self _setRowTypeToAddFromPlusButton:type];
|
[self _setRowTypeToAddFromPlusButton:type];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isEditable
|
|
||||||
{
|
|
||||||
return editable;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setEditable:(BOOL)value
|
- (void)setEditable:(BOOL)value
|
||||||
{
|
{
|
||||||
editable = value;
|
[super setEditable:value]
|
||||||
// [self _updateEnabledStateForSubviews];
|
// [self _updateEnabledStateForSubviews];
|
||||||
[self _updateButtonVisibilities];
|
[self _updateButtonVisibilities];
|
||||||
}
|
}
|
||||||
@@ -473,22 +495,36 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
[self layoutSubviews];
|
[self layoutSubviews];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CPRect)rect
|
- (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
|
||||||
{
|
{
|
||||||
[super drawRect:rect];
|
[super drawRect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_isRulePopup:(CPView)view
|
- (BOOL)_isRulePopup:(CPView)view
|
||||||
{
|
{
|
||||||
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
|
if ([view isKindOfClass:[CPPopUpButton class]])
|
||||||
return YES;
|
return YES;
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_isRuleStaticTextField:(CPView)view
|
|
||||||
{
|
|
||||||
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
|
|
||||||
return YES;
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,30 +541,3 @@ var CONTROL_HEIGHT = 16.,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPRuleEditorTextField : CPTextField
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:frame];
|
|
||||||
if (self != nil)
|
|
||||||
{
|
|
||||||
[self setBordered:NO];
|
|
||||||
[self setEditable:NO];
|
|
||||||
[self setDrawsBackground:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)hitTest:(CPPoint)point
|
|
||||||
{
|
|
||||||
if (!CPRectContainsPoint([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];
|
||||||
|
|||||||
+2
-2
@@ -43,9 +43,9 @@
|
|||||||
- (CGRect)visibleFrame
|
- (CGRect)visibleFrame
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
return CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
||||||
#else
|
#else
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+264
-127
@@ -30,52 +30,64 @@
|
|||||||
@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 _isSystemUsingOverlayScrollers = function()
|
var _isBrowserUsingOverlayScrollers = function()
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
var inner = document.createElement('p'),
|
/*
|
||||||
outer = document.createElement('div');
|
Even if the system supports overlay (Lion) scrollers,
|
||||||
|
the browser (e.g. FireFox *cough*) may not.
|
||||||
|
|
||||||
inner.style.width = "100%";
|
To determine if the browser is using overlay scrollbars,
|
||||||
inner.style.height = "200px";
|
we put a <p> element inside a shorter <div> and set its
|
||||||
|
overflow to scroll. If the browser is using visible scrollers,
|
||||||
|
the outer div's clientWidth will less than the offsetWidth, because
|
||||||
|
clientWidth does not include scrollbars, whereas offsetWidth does.
|
||||||
|
So if clientWidth === offsetWidth, the scrollers must be overlay.
|
||||||
|
Even IE gets this right.
|
||||||
|
*/
|
||||||
|
var outer = document.createElement('div'),
|
||||||
|
inner = document.createElement('p');
|
||||||
|
|
||||||
|
// position it absolute so it doesn't affect existing DOM elements
|
||||||
outer.style.position = "absolute";
|
outer.style.position = "absolute";
|
||||||
outer.style.top = "0px";
|
outer.style.top = "0px";
|
||||||
outer.style.left = "0px";
|
outer.style.left = "0px";
|
||||||
outer.style.visibility = "hidden";
|
outer.style.visibility = "hidden";
|
||||||
outer.style.width = "200px";
|
outer.style.width = "200px";
|
||||||
outer.style.height = "150px";
|
outer.style.height = "150px";
|
||||||
outer.style.overflow = "hidden";
|
outer.style.overflow = "scroll";
|
||||||
outer.appendChild (inner);
|
|
||||||
|
|
||||||
document.body.appendChild (outer);
|
inner.style.width = "100%";
|
||||||
var w1 = inner.offsetWidth;
|
inner.style.height = "200px";
|
||||||
outer.style.overflow = 'scroll';
|
outer.appendChild(inner);
|
||||||
var w2 = inner.offsetWidth;
|
|
||||||
if (w1 == w2)
|
|
||||||
w2 = outer.clientWidth;
|
|
||||||
|
|
||||||
document.body.removeChild (outer);
|
document.body.appendChild(outer);
|
||||||
|
|
||||||
return (w1 - w2 == 0);
|
var usingOverlayScrollers = outer.clientWidth === outer.offsetWidth;
|
||||||
|
|
||||||
|
document.body.removeChild(outer);
|
||||||
|
|
||||||
|
return usingOverlayScrollers;
|
||||||
#else
|
#else
|
||||||
return NO;
|
return NO;
|
||||||
#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,
|
||||||
@@ -85,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,8 +149,8 @@ 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 = _isSystemUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
CPScrollerStyleGlobal = _isBrowserUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
||||||
else
|
else
|
||||||
CPScrollerStyleGlobal = globalValue;
|
CPScrollerStyleGlobal = globalValue;
|
||||||
}
|
}
|
||||||
@@ -143,39 +162,71 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
|
|
||||||
+ (CPDictionary)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithJSObject:{
|
return @{
|
||||||
@"bottom-corner-color": [CPColor whiteColor],
|
@"bottom-corner-color": [CPColor whiteColor],
|
||||||
@"border-color": [CPColor blackColor]
|
@"border-color": [CPColor blackColor]
|
||||||
}];
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! 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
|
||||||
{
|
{
|
||||||
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType: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],
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -186,10 +237,10 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
|||||||
{
|
{
|
||||||
case CPLineBorder:
|
case CPLineBorder:
|
||||||
case CPBezelBorder:
|
case CPBezelBorder:
|
||||||
return _CGRectInset(bounds, 1.0, 1.0);
|
return CGRectInset(bounds, 1.0, 1.0);
|
||||||
|
|
||||||
case CPGrooveBorder:
|
case CPGrooveBorder:
|
||||||
bounds = _CGRectInset(bounds, 2.0, 2.0);
|
bounds = CGRectInset(bounds, 2.0, 2.0);
|
||||||
++bounds.origin.y;
|
++bounds.origin.y;
|
||||||
--bounds.size.height;
|
--bounds.size.height;
|
||||||
return bounds;
|
return bounds;
|
||||||
@@ -203,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;
|
||||||
}
|
}
|
||||||
@@ -213,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];
|
||||||
@@ -254,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;
|
||||||
@@ -291,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;
|
||||||
@@ -299,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:)])
|
||||||
@@ -309,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;
|
||||||
}
|
}
|
||||||
@@ -320,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;
|
||||||
@@ -517,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];
|
||||||
@@ -582,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];
|
||||||
@@ -859,13 +905,13 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
- (CGRect)_cornerViewFrame
|
- (CGRect)_cornerViewFrame
|
||||||
{
|
{
|
||||||
if (!_cornerView)
|
if (!_cornerView)
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
|
|
||||||
var bounds = [self _insetBounds],
|
var bounds = [self _insetBounds],
|
||||||
frame = [_cornerView frame];
|
frame = [_cornerView frame];
|
||||||
|
|
||||||
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
frame.origin.x = CGRectGetMaxX(bounds) - CGRectGetWidth(frame);
|
||||||
frame.origin.y = _CGRectGetMinY(bounds);
|
frame.origin.y = CGRectGetMinY(bounds);
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@@ -876,14 +922,14 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
var headerView = [self _headerView];
|
var headerView = [self _headerView];
|
||||||
|
|
||||||
if (!headerView)
|
if (!headerView)
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
|
|
||||||
var frame = [self _insetBounds];
|
var frame = [self _insetBounds];
|
||||||
|
|
||||||
frame.size.height = _CGRectGetHeight([headerView frame]);
|
frame.size.height = CGRectGetHeight([headerView frame]);
|
||||||
|
|
||||||
if (SHOULD_SHOW_CORNER_VIEW())
|
if (SHOULD_SHOW_CORNER_VIEW())
|
||||||
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
frame.size.width -= CGRectGetWidth([self _cornerViewFrame]);
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@@ -899,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;
|
||||||
}
|
}
|
||||||
@@ -924,18 +970,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CPScrollerDecrementPage:
|
case CPScrollerDecrementPage:
|
||||||
contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
contentBounds.origin.y -= CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPScrollerIncrementPage:
|
case CPScrollerIncrementPage:
|
||||||
contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
contentBounds.origin.y += CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We want integral bounds!
|
// We want integral bounds!
|
||||||
case CPScrollerKnobSlot:
|
case CPScrollerKnobSlot:
|
||||||
case CPScrollerKnob:
|
case CPScrollerKnob:
|
||||||
default:
|
default:
|
||||||
contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
contentBounds.origin.y = ROUND(value * (CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[self _sendDelegateMessages];
|
[self _sendDelegateMessages];
|
||||||
@@ -961,18 +1007,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CPScrollerDecrementPage:
|
case CPScrollerDecrementPage:
|
||||||
contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
contentBounds.origin.x -= CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPScrollerIncrementPage:
|
case CPScrollerIncrementPage:
|
||||||
contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
contentBounds.origin.x += CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// We want integral bounds!
|
// We want integral bounds!
|
||||||
case CPScrollerKnobSlot:
|
case CPScrollerKnobSlot:
|
||||||
case CPScrollerKnob:
|
case CPScrollerKnob:
|
||||||
default:
|
default:
|
||||||
contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
|
contentBounds.origin.x = ROUND(value * (CGRectGetWidth(documentFrame) - CGRectGetWidth(contentBounds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[self _sendDelegateMessages];
|
[self _sendDelegateMessages];
|
||||||
@@ -1096,7 +1142,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
}
|
}
|
||||||
|
|
||||||
[_contentView setFrame:[self _insetBounds]];
|
[_contentView setFrame:[self _insetBounds]];
|
||||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
[_headerClipView setFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
--_recursionCount;
|
--_recursionCount;
|
||||||
|
|
||||||
@@ -1106,14 +1152,14 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
var documentFrame = [documentView frame], // the size of the whole document
|
var documentFrame = [documentView frame], // the size of the whole document
|
||||||
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||||
headerClipViewFrame = [self _headerClipViewFrame],
|
headerClipViewFrame = [self _headerClipViewFrame],
|
||||||
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
headerClipViewHeight = CGRectGetHeight(headerClipViewFrame);
|
||||||
|
|
||||||
contentFrame.origin.y += headerClipViewHeight;
|
contentFrame.origin.y += headerClipViewHeight;
|
||||||
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 = _CGRectGetWidth([_verticalScroller frame]),
|
verticalScrollerWidth = [_verticalScroller scrollerWidth],
|
||||||
horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]),
|
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),
|
||||||
@@ -1162,18 +1208,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
if (shouldShowVerticalScroller)
|
if (shouldShowVerticalScroller)
|
||||||
{
|
{
|
||||||
var verticalScrollerY =
|
var verticalScrollerY =
|
||||||
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
|
MAX(CGRectGetMinY(contentFrame), MAX(CGRectGetMaxY([self _cornerViewFrame]), CGRectGetMaxY(headerClipViewFrame)));
|
||||||
|
|
||||||
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
|
var verticalScrollerHeight = CGRectGetMaxY(contentFrame) - verticalScrollerY;
|
||||||
|
|
||||||
// Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
|
// Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
|
||||||
if (_scrollerStyle === CPScrollerStyleOverlay && hasHorizontalScroll)
|
if (_scrollerStyle === CPScrollerStyleOverlay && hasHorizontalScroll)
|
||||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
verticalScrollerHeight -= horizontalScrollerHeight;
|
||||||
|
|
||||||
var documentHeight = _CGRectGetHeight(documentFrame);
|
var documentHeight = CGRectGetHeight(documentFrame);
|
||||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||||
[_verticalScroller setKnobProportion:documentHeight > 0 ? _CGRectGetHeight(contentFrame) / documentHeight : 1.0];
|
[_verticalScroller setKnobProportion:documentHeight > 0 ? CGRectGetHeight(contentFrame) / documentHeight : 1.0];
|
||||||
[_verticalScroller setFrame:_CGRectMake(_CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
|
[_verticalScroller setFrame:CGRectMake(CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
|
||||||
}
|
}
|
||||||
else if (wasShowingVerticalScroller)
|
else if (wasShowingVerticalScroller)
|
||||||
{
|
{
|
||||||
@@ -1183,16 +1229,16 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
|
|
||||||
if (shouldShowHorizontalScroller)
|
if (shouldShowHorizontalScroller)
|
||||||
{
|
{
|
||||||
var horizontalScrollerWidth = _CGRectGetWidth(contentFrame);
|
var horizontalScrollerWidth = CGRectGetWidth(contentFrame);
|
||||||
// Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
|
// Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
|
||||||
if (_scrollerStyle === CPScrollerStyleOverlay && hasVerticalScroll)
|
if (_scrollerStyle === CPScrollerStyleOverlay && hasVerticalScroll)
|
||||||
horizontalScrollerWidth -= verticalScrollerWidth;
|
horizontalScrollerWidth -= verticalScrollerWidth;
|
||||||
|
|
||||||
var documentWidth = _CGRectGetWidth(documentFrame);
|
var documentWidth = CGRectGetWidth(documentFrame);
|
||||||
|
|
||||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||||
[_horizontalScroller setKnobProportion:documentWidth > 0 ? _CGRectGetWidth(contentFrame) / documentWidth : 1.0];
|
[_horizontalScroller setKnobProportion:documentWidth > 0 ? CGRectGetWidth(contentFrame) / documentWidth : 1.0];
|
||||||
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
|
[_horizontalScroller setFrame:CGRectMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
|
||||||
}
|
}
|
||||||
else if (wasShowingHorizontalScroller)
|
else if (wasShowingHorizontalScroller)
|
||||||
{
|
{
|
||||||
@@ -1241,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];
|
||||||
}
|
}
|
||||||
@@ -1252,11 +1298,46 @@ 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)drawRect:(CPRect)aRect
|
|
||||||
|
- (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
|
||||||
{
|
{
|
||||||
[super drawRect:aRect];
|
[super drawRect:aRect];
|
||||||
|
|
||||||
@@ -1272,7 +1353,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
{
|
{
|
||||||
case CPLineBorder:
|
case CPLineBorder:
|
||||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
||||||
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
|
CGContextStrokeRect(context, CGRectInset(strokeRect, 0.5, 0.5));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPBezelBorder:
|
case CPBezelBorder:
|
||||||
@@ -1290,10 +1371,10 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
|
|
||||||
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var minX = _CGRectGetMinX(aRect),
|
var minX = CGRectGetMinX(aRect),
|
||||||
maxX = _CGRectGetMaxX(aRect),
|
maxX = CGRectGetMaxX(aRect),
|
||||||
minY = _CGRectGetMinY(aRect),
|
minY = CGRectGetMinY(aRect),
|
||||||
maxY = _CGRectGetMaxY(aRect),
|
maxY = CGRectGetMaxY(aRect),
|
||||||
y = minY + 0.5;
|
y = minY + 0.5;
|
||||||
|
|
||||||
// Slightly darker line on top.
|
// Slightly darker line on top.
|
||||||
@@ -1324,10 +1405,10 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
|
|
||||||
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
||||||
{
|
{
|
||||||
var minX = _CGRectGetMinX(aRect),
|
var minX = CGRectGetMinX(aRect),
|
||||||
maxX = _CGRectGetMaxX(aRect),
|
maxX = CGRectGetMaxX(aRect),
|
||||||
minY = _CGRectGetMinY(aRect),
|
minY = CGRectGetMinY(aRect),
|
||||||
maxY = _CGRectGetMaxY(aRect);
|
maxY = CGRectGetMaxY(aRect);
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
|
||||||
@@ -1357,11 +1438,11 @@ Notifies the delegate when the scroll view has finished scrolling.
|
|||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextSetStrokeColor(context, [CPColor whiteColor]);
|
CGContextSetStrokeColor(context, [CPColor whiteColor]);
|
||||||
|
|
||||||
var rect = _CGRectOffset(aRect, 1.0, 1.0);
|
var rect = CGRectOffset(aRect, 1.0, 1.0);
|
||||||
|
|
||||||
rect.size.width -= 1.0;
|
rect.size.width -= 1.0;
|
||||||
rect.size.height -= 1.0;
|
rect.size.height -= 1.0;
|
||||||
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
|
CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||||
@@ -1389,35 +1470,44 @@ 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
|
||||||
{
|
{
|
||||||
var contentBounds = [_contentView bounds];
|
var contentBounds = [_contentView bounds];
|
||||||
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
[self moveByOffset:CGSizeMake(0.0, -(CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollPageDown:(id)sender
|
- (void)scrollPageDown:(id)sender
|
||||||
{
|
{
|
||||||
var contentBounds = [_contentView bounds];
|
var contentBounds = [_contentView bounds];
|
||||||
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
[self moveByOffset:CGSizeMake(0.0, CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollToBeginningOfDocument:(id)sender
|
- (void)scrollToBeginningOfDocument:(id)sender
|
||||||
{
|
{
|
||||||
[_contentView scrollToPoint:_CGPointMakeZero()];
|
[_contentView scrollToPoint:CGPointMakeZero()];
|
||||||
[_headerClipView scrollToPoint:_CGPointMakeZero()];
|
[_headerClipView scrollToPoint:CGPointMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollToEndOfDocument:(id)sender
|
- (void)scrollToEndOfDocument:(id)sender
|
||||||
{
|
{
|
||||||
var contentBounds = [_contentView bounds],
|
var contentBounds = [_contentView bounds],
|
||||||
documentFrame = [[self documentView] frame],
|
documentFrame = [[self documentView] frame],
|
||||||
scrollPoint = _CGPointMake(0.0, _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
|
scrollPoint = CGPointMake(0.0, CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds));
|
||||||
|
|
||||||
[_contentView scrollToPoint:scrollPoint];
|
[_contentView scrollToPoint:scrollPoint];
|
||||||
[_headerClipView scrollToPoint:_CGPointMakeZero()];
|
[_headerClipView scrollToPoint:CGPointMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)moveLeft:(id)sender
|
- (void)moveLeft:(id)sender
|
||||||
@@ -1454,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",
|
||||||
@@ -1526,6 +1661,8 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
|||||||
*/
|
*/
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
|
[super awakeFromCib];
|
||||||
|
|
||||||
[self _updateScrollerStyle];
|
[self _updateScrollerStyle];
|
||||||
[self _updateCornerAndHeaderView];
|
[self _updateCornerAndHeaderView];
|
||||||
}
|
}
|
||||||
|
|||||||
+125
-124
@@ -25,9 +25,15 @@
|
|||||||
|
|
||||||
#include "../Foundation/Foundation.h"
|
#include "../Foundation/Foundation.h"
|
||||||
|
|
||||||
|
@import "CPAnimation.j"
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
@import "CPWindow_Constants.j"
|
||||||
|
@import "CPViewAnimation.j"
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
// CPScroller Constants
|
// CPScroller Constants
|
||||||
|
@typedef CPScrollerPart
|
||||||
CPScrollerNoPart = 0;
|
CPScrollerNoPart = 0;
|
||||||
CPScrollerDecrementPage = 1;
|
CPScrollerDecrementPage = 1;
|
||||||
CPScrollerKnob = 2;
|
CPScrollerKnob = 2;
|
||||||
@@ -39,25 +45,24 @@ 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 = {};
|
||||||
|
|
||||||
|
var _CACHED_THEME_SCROLLER = nil; // This is used by the class methods to pull the theme attributes.
|
||||||
|
|
||||||
NAMES_FOR_PARTS[CPScrollerDecrementLine] = @"decrement-line";
|
NAMES_FOR_PARTS[CPScrollerDecrementLine] = @"decrement-line";
|
||||||
NAMES_FOR_PARTS[CPScrollerIncrementLine] = @"increment-line";
|
NAMES_FOR_PARTS[CPScrollerIncrementLine] = @"increment-line";
|
||||||
NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
|
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;
|
||||||
|
|
||||||
@@ -69,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;
|
||||||
|
|
||||||
@@ -101,21 +110,21 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
return "scroller";
|
return "scroller";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithJSObject:{
|
return @{
|
||||||
@"scroller-width": 7.0,
|
@"scroller-width": 7.0,
|
||||||
@"knob-slot-color": [CPNull null],
|
@"knob-slot-color": [CPNull null],
|
||||||
@"decrement-line-color": [CPNull null],
|
@"decrement-line-color": [CPNull null],
|
||||||
@"increment-line-color": [CPNull null],
|
@"increment-line-color": [CPNull null],
|
||||||
@"knob-color": [CPNull null],
|
@"knob-color": [CPNull null],
|
||||||
@"decrement-line-size":_CGSizeMakeZero(),
|
@"decrement-line-size": CGSizeMakeZero(),
|
||||||
@"increment-line-size":_CGSizeMakeZero(),
|
@"increment-line-size": CGSizeMakeZero(),
|
||||||
@"track-inset":_CGInsetMakeZero(),
|
@"track-inset": CGInsetMakeZero(),
|
||||||
@"knob-inset": _CGInsetMakeZero(),
|
@"knob-inset": CGInsetMakeZero(),
|
||||||
@"minimum-knob-length":21.0,
|
@"minimum-knob-length": 21.0,
|
||||||
@"track-border-overlay": 9.0
|
@"track-border-overlay": 9.0
|
||||||
}];
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)scrollerWidth
|
+ (float)scrollerWidth
|
||||||
@@ -126,13 +135,15 @@ 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
|
||||||
{
|
{
|
||||||
var scroller = [[self alloc] init];
|
if (!_CACHED_THEME_SCROLLER)
|
||||||
|
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||||
|
|
||||||
if (aStyle == CPScrollerStyleLegacy)
|
if (aStyle == CPScrollerStyleLegacy)
|
||||||
return [scroller valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
return [_CACHED_THEME_SCROLLER valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||||
return [scroller currentValueForThemeAttribute:@"scroller-width"];
|
|
||||||
|
return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"scroller-width"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -140,7 +151,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
*/
|
*/
|
||||||
+ (float)scrollerOverlay
|
+ (float)scrollerOverlay
|
||||||
{
|
{
|
||||||
return [[[self alloc] init] currentValueForThemeAttribute:@"track-border-overlay"];
|
if (!_CACHED_THEME_SCROLLER)
|
||||||
|
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||||
|
|
||||||
|
return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"track-border-overlay"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -160,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];
|
||||||
@@ -170,14 +183,20 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
_allowFadingOut = YES;
|
_allowFadingOut = YES;
|
||||||
_isMouseOver = NO;
|
_isMouseOver = NO;
|
||||||
_style = CPScrollerStyleOverlay;
|
_style = CPScrollerStyleOverlay;
|
||||||
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
|
|
||||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
|
var paramAnimFadeOut = @{
|
||||||
|
CPViewAnimationTargetKey: self,
|
||||||
|
CPViewAnimationEffectKey: CPViewAnimationFadeOutEffect,
|
||||||
|
};
|
||||||
|
|
||||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||||
[_animationScroller setDelegate:self];
|
[_animationScroller setDelegate:self];
|
||||||
[self setAlphaValue:0.0];
|
[self setAlphaValue:0.0];
|
||||||
[self _calculateIsVertical];
|
|
||||||
|
// We have to choose an orientation. If for some bizarre reason width === height,
|
||||||
|
// punt and choose vertical.
|
||||||
|
[self _setIsVertical:CGRectGetHeight(aFrame) >= CGRectGetWidth(aFrame)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -190,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;
|
||||||
}
|
}
|
||||||
@@ -199,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;
|
||||||
@@ -208,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];
|
||||||
}
|
}
|
||||||
@@ -217,7 +237,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
[self unsetThemeState:CPThemeStateScrollViewLegacy];
|
[self unsetThemeState:CPThemeStateScrollViewLegacy];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self _adjustScrollerSize];
|
//[self _adjustScrollerSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setObjectValue:(id)aValue
|
- (void)setObjectValue:(id)aValue
|
||||||
@@ -225,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
|
||||||
*/
|
*/
|
||||||
@@ -263,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));
|
||||||
|
|
||||||
@@ -304,7 +301,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||||
{
|
{
|
||||||
if (aPart == CPScrollerNoPart)
|
if (aPart == CPScrollerNoPart)
|
||||||
return _CGRectMakeZero();
|
return CGRectMakeZero();
|
||||||
|
|
||||||
return _partRects[aPart];
|
return _partRects[aPart];
|
||||||
}
|
}
|
||||||
@@ -321,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))
|
||||||
@@ -374,8 +371,8 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
||||||
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
||||||
width = _CGRectGetWidth(bounds),
|
width = CGRectGetWidth(bounds),
|
||||||
height = _CGRectGetHeight(bounds);
|
height = CGRectGetHeight(bounds);
|
||||||
|
|
||||||
if ([self isVertical])
|
if ([self isVertical])
|
||||||
{
|
{
|
||||||
@@ -385,25 +382,26 @@ 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);
|
||||||
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
|
_partRects[CPScrollerIncrementPage] = CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
|
||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotSize);
|
_partRects[CPScrollerKnobSlot] = CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotSize);
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
_partRects[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
_partRects[CPScrollerIncrementLine] = CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||||
|
|
||||||
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||||
|
|
||||||
if (height < decrementLineSize.height + incrementLineSize.height - 2)
|
if (height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||||
{
|
{
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
_partRects[CPScrollerKnobSlot] = CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -414,25 +412,26 @@ 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);
|
||||||
_partRects[CPScrollerIncrementPage] = _CGRectMake(knobLocation + knobWidth, 0.0, width - (knobLocation + knobWidth) - effectiveIncrementLineWidth, height);
|
_partRects[CPScrollerIncrementPage] = CGRectMake(knobLocation + knobWidth, 0.0, width - (knobLocation + knobWidth) - effectiveIncrementLineWidth, height);
|
||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
|
_partRects[CPScrollerKnobSlot] = CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
_partRects[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
_partRects[CPScrollerIncrementLine] = CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||||
|
|
||||||
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||||
|
|
||||||
if (width < decrementLineSize.width + incrementLineSize.width - 2)
|
if (width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||||
{
|
{
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotSize);
|
_partRects[CPScrollerKnobSlot] = CGRectMake(0.0, 0.0, width, slotSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,9 +464,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
*/
|
*/
|
||||||
- (void)fadeOut
|
- (void)fadeOut
|
||||||
{
|
{
|
||||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
|
||||||
return;
|
|
||||||
|
|
||||||
[_animationScroller startAnimation];
|
[_animationScroller startAnimation];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +496,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||||
{
|
{
|
||||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[view setHitTests:NO];
|
[view setHitTests:NO];
|
||||||
|
|
||||||
@@ -514,7 +510,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
[view setHitTests:NO];
|
[view setHitTests:NO];
|
||||||
|
|
||||||
@@ -523,6 +519,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
|
[self _adjustScrollerSize];
|
||||||
[self checkSpaceForParts];
|
[self checkSpaceForParts];
|
||||||
|
|
||||||
var index = 0,
|
var index = 0,
|
||||||
@@ -588,7 +585,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
{
|
{
|
||||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||||
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
|
remainder = ![self isVertical] ? (CGRectGetWidth(knobSlotRect) - CGRectGetWidth(knobRect)) : (CGRectGetHeight(knobSlotRect) - CGRectGetHeight(knobRect));
|
||||||
|
|
||||||
if (remainder <= 0)
|
if (remainder <= 0)
|
||||||
[self setFloatValue:0.0];
|
[self setFloatValue:0.0];
|
||||||
@@ -633,20 +630,20 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
if ([anEvent modifierFlags] & CPAlternateKeyMask)
|
if ([anEvent modifierFlags] & CPAlternateKeyMask)
|
||||||
{
|
{
|
||||||
if (_trackingPart == CPScrollerDecrementLine)
|
if (_trackingPart === CPScrollerDecrementLine)
|
||||||
_hitPart = CPScrollerDecrementPage;
|
_hitPart = CPScrollerDecrementPage;
|
||||||
|
|
||||||
else if (_trackingPart == CPScrollerIncrementLine)
|
else if (_trackingPart === CPScrollerIncrementLine)
|
||||||
_hitPart = CPScrollerIncrementPage;
|
_hitPart = CPScrollerIncrementPage;
|
||||||
|
|
||||||
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
else if (_trackingPart === CPScrollerDecrementPage || _trackingPart === CPScrollerIncrementPage)
|
||||||
{
|
{
|
||||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||||
knobWidth = ![self isVertical] ? _CGRectGetWidth(knobRect) : _CGRectGetHeight(knobRect),
|
knobWidth = ![self isVertical] ? CGRectGetWidth(knobRect) : CGRectGetHeight(knobRect),
|
||||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||||
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
|
remainder = (![self isVertical] ? CGRectGetWidth(knobSlotRect) : CGRectGetHeight(knobSlotRect)) - knobWidth;
|
||||||
|
|
||||||
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
||||||
|
|
||||||
_hitPart = CPScrollerKnob;
|
_hitPart = CPScrollerKnob;
|
||||||
|
|
||||||
@@ -667,11 +664,11 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
{
|
{
|
||||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
if (_trackingPart === CPScrollerDecrementPage || _trackingPart === CPScrollerIncrementPage)
|
||||||
{
|
{
|
||||||
var hitPart = [self testPart:[anEvent locationInWindow]];
|
var hitPart = [self testPart:[anEvent locationInWindow]];
|
||||||
|
|
||||||
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
|
if (hitPart === CPScrollerDecrementPage || hitPart === CPScrollerIncrementPage)
|
||||||
{
|
{
|
||||||
_trackingPart = hitPart;
|
_trackingPart = hitPart;
|
||||||
_hitPart = hitPart;
|
_hitPart = hitPart;
|
||||||
@@ -687,18 +684,13 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_calculateIsVertical
|
- (void)_setIsVertical:(BOOL)isVertical
|
||||||
{
|
{
|
||||||
// Recalculate isVertical.
|
_isVertical = isVertical;
|
||||||
var bounds = [self bounds],
|
|
||||||
width = _CGRectGetWidth(bounds),
|
|
||||||
height = _CGRectGetHeight(bounds);
|
|
||||||
|
|
||||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
if (_isVertical)
|
||||||
|
|
||||||
if (_isVertical === 1)
|
|
||||||
[self setThemeState:CPThemeStateVertical];
|
[self setThemeState:CPThemeStateVertical];
|
||||||
else if (_isVertical === 0)
|
else
|
||||||
[self unsetThemeState:CPThemeStateVertical];
|
[self unsetThemeState:CPThemeStateVertical];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,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];
|
||||||
}
|
}
|
||||||
@@ -733,12 +725,14 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
switch (_hitPart)
|
switch (_hitPart)
|
||||||
{
|
{
|
||||||
case CPScrollerKnob: return [self trackKnob:anEvent];
|
case CPScrollerKnob:
|
||||||
|
return [self trackKnob:anEvent];
|
||||||
|
|
||||||
case CPScrollerDecrementLine:
|
case CPScrollerDecrementLine:
|
||||||
case CPScrollerIncrementLine:
|
case CPScrollerIncrementLine:
|
||||||
case CPScrollerDecrementPage:
|
case CPScrollerDecrementPage:
|
||||||
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
|
case CPScrollerIncrementPage:
|
||||||
|
return [self trackScrollButtons:anEvent];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,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
|
||||||
@@ -786,9 +790,9 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
var CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||||
|
|
||||||
@implementation CPScroller (CPCoding)
|
@implementation CPScroller (CPCoding)
|
||||||
|
|
||||||
@@ -796,11 +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])
|
||||||
@@ -813,17 +812,19 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
|||||||
_allowFadingOut = YES;
|
_allowFadingOut = YES;
|
||||||
_isMouseOver = NO;
|
_isMouseOver = NO;
|
||||||
|
|
||||||
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
|
var paramAnimFadeOut = @{
|
||||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
|
CPViewAnimationTargetKey: self,
|
||||||
|
CPViewAnimationEffectKey: CPViewAnimationFadeOutEffect,
|
||||||
|
};
|
||||||
|
|
||||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||||
[_animationScroller setDelegate:self];
|
[_animationScroller setDelegate:self];
|
||||||
[self setAlphaValue:0.0];
|
[self setAlphaValue:0.0];
|
||||||
|
|
||||||
[self _calculateIsVertical];
|
|
||||||
|
|
||||||
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
|
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
|
||||||
|
|
||||||
|
[self _setIsVertical:[aCoder decodeBoolForKey:CPScrollerIsVerticalKey]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -833,7 +834,7 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
[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];
|
||||||
}
|
}
|
||||||
|
|||||||
+413
-89
@@ -21,26 +21,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
|
@import "CPMenu.j"
|
||||||
|
@import "CPMenuItem.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
@import "CPAnimationContext.j"
|
||||||
|
@import "CPViewAnimator.j"
|
||||||
|
@import "CPArrayController.j"
|
||||||
|
|
||||||
|
@class CPUserDefaults
|
||||||
|
@class CALayer
|
||||||
|
|
||||||
|
@global CPApp
|
||||||
|
|
||||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||||
|
|
||||||
var CPSearchFieldSearchImage = nil,
|
|
||||||
CPSearchFieldFindImage = nil,
|
|
||||||
CPSearchFieldCancelImage = nil,
|
|
||||||
CPSearchFieldCancelPressedImage = nil;
|
|
||||||
|
|
||||||
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
|
|
||||||
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
|
|
||||||
BUTTON_DEFAULT_HEIGHT = 22.0;
|
|
||||||
|
|
||||||
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
||||||
|
|
||||||
var RECENT_SEARCH_PREFIX = @" ";
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPSearchField
|
@class CPSearchField
|
||||||
@@ -63,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
|
||||||
@@ -70,16 +72,28 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
return @"searchfield"
|
return @"searchfield"
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
if (self !== [CPSearchField class])
|
return @{
|
||||||
return;
|
@"image-search": [CPNull null],
|
||||||
|
@"image-find": [CPNull null],
|
||||||
|
@"image-cancel": [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)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
{
|
||||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
if (aBinding === CPPredicateBinding)
|
||||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
return [_CPSearchFieldPredicateBinder class];
|
||||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
|
||||||
|
return [super _binderClassForBinding:aBinding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame
|
- (id)initWithFrame:(CGRect)frame
|
||||||
@@ -92,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;
|
||||||
@@ -122,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
|
||||||
@@ -170,7 +193,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
- (void)resetSearchButton
|
- (void)resetSearchButton
|
||||||
{
|
{
|
||||||
var button = [self searchButton],
|
var button = [self searchButton],
|
||||||
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
|
searchButtonImage = (_searchMenuTemplate == nil) ? [self currentValueForThemeAttribute:@"image-search"] : [self currentValueForThemeAttribute:@"image-find"];
|
||||||
|
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||||
@@ -193,6 +216,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||||
[_cancelButton setTarget:self];
|
[_cancelButton setTarget:self];
|
||||||
[_cancelButton setAction:@selector(cancelOperation:)];
|
[_cancelButton setAction:@selector(cancelOperation:)];
|
||||||
|
[_cancelButton setButtonType:CPMomentaryChangeButton];
|
||||||
[self _updateCancelButtonVisibility];
|
[self _updateCancelButtonVisibility];
|
||||||
[self addSubview:_cancelButton];
|
[self addSubview:_cancelButton];
|
||||||
}
|
}
|
||||||
@@ -216,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:CPSearchFieldCancelImage];
|
[button setImage:[self currentValueForThemeAttribute:@"image-cancel"]];
|
||||||
[button setAlternateImage:CPSearchFieldCancelPressedImage];
|
[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:)];
|
||||||
@@ -233,22 +257,23 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
var leftOffset = 0,
|
var leftOffset = 0,
|
||||||
width = _CGRectGetWidth(rect),
|
width = CGRectGetWidth(rect),
|
||||||
bounds = [self bounds];
|
bounds = [self bounds];
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
var cancelRect = [self cancelButtonRectForBounds:bounds];
|
var cancelRect = [self cancelButtonRectForBounds:bounds];
|
||||||
width = _CGRectGetMinX(cancelRect) - leftOffset;
|
width = CGRectGetMinX(cancelRect) - leftOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
|
return CGRectMake(leftOffset, CGRectGetMinY(rect), width, CGRectGetHeight(rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -258,7 +283,18 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
*/
|
*/
|
||||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
|
var themedRectFunction = [self _potentialCurrentValueForThemeAttribute:@"search-button-rect-function"];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -268,7 +304,10 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
*/
|
*/
|
||||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
|
var size = [[self _potentialCurrentValueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero(),
|
||||||
|
inset = [self _potentialCurrentValueForThemeAttribute:@"image-cancel-inset"];
|
||||||
|
|
||||||
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,8 +496,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
[self sendAction:[self action] to:[self target]];
|
[self sendAction:[self action] to:[self target]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)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];
|
||||||
@@ -482,7 +521,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
- (CPView)hitTest:(CGPoint)aPoint
|
- (CPView)hitTest:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
// Make sure a hit anywhere within the search field returns the search field itself
|
// Make sure a hit anywhere within the search field returns the search field itself
|
||||||
if (_CGRectContainsPoint([self frame], aPoint))
|
if (CGRectContainsPoint([self frame], aPoint))
|
||||||
return self;
|
return self;
|
||||||
else
|
else
|
||||||
return nil;
|
return nil;
|
||||||
@@ -498,7 +537,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
var location = [anEvent locationInWindow],
|
var location = [anEvent locationInWindow],
|
||||||
point = [self convertPoint:location fromView:nil];
|
point = [self convertPoint:location fromView:nil];
|
||||||
|
|
||||||
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
if (CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||||
{
|
{
|
||||||
if (_searchMenuTemplate == nil)
|
if (_searchMenuTemplate == nil)
|
||||||
{
|
{
|
||||||
@@ -510,26 +549,23 @@ var RECENT_SEARCH_PREFIX = @" ";
|
|||||||
else
|
else
|
||||||
[self _showMenu];
|
[self _showMenu];
|
||||||
}
|
}
|
||||||
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
else if (CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||||
[_cancelButton mouseDown:anEvent];
|
[_cancelButton mouseDown:anEvent];
|
||||||
else
|
else
|
||||||
[super mouseDown:anEvent];
|
[super mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
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 = CPMakePoint(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
|
||||||
|
|
||||||
|
|||||||
+441
-206
File diff suppressed because it is too large
Load Diff
+12
-30
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CGGeometry.j"
|
||||||
|
@import "CPColor.j"
|
||||||
|
@import "CPGraphicsContext.j"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@deprecated
|
@deprecated
|
||||||
@@ -31,11 +34,9 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPShadow : CPObject
|
@implementation CPShadow : CPObject
|
||||||
{
|
{
|
||||||
CPSize _offset;
|
CGSize _offset @accessors(property=shadowOffset);
|
||||||
float _blurRadius;
|
float _blurRadius @accessors(property=shadowBlurRadius);
|
||||||
CPColor _color;
|
CPColor _color @accessors(property=shadowColor);
|
||||||
|
|
||||||
CPString _cssString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -51,7 +52,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_initWithOffset:(CPSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
|
- (id)_initWithOffset:(CGSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
@@ -60,35 +61,16 @@
|
|||||||
_offset = anOffset;
|
_offset = anOffset;
|
||||||
_blurRadius = aBlurRadius;
|
_blurRadius = aBlurRadius;
|
||||||
_color = aColor;
|
_color = aColor;
|
||||||
|
|
||||||
_cssString = [_color cssString] + " " + ROUND(anOffset.width) + @"px " + ROUND(anOffset.height) + @"px " + ROUND(_blurRadius) + @"px";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)set
|
||||||
Returns the shadow's offset.
|
|
||||||
*/
|
|
||||||
- (CGSize)shadowOffset
|
|
||||||
{
|
{
|
||||||
return _offset;
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
CGContextSetShadowWithColor(context, _offset, _blurRadius, _color);
|
||||||
Returns the shadow's blur radius
|
|
||||||
*/
|
|
||||||
- (float)shadowBlurRadius
|
|
||||||
{
|
|
||||||
return _blurRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the shadow's color.
|
|
||||||
*/
|
|
||||||
- (CPColor)shadowColor
|
|
||||||
{
|
|
||||||
return _color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -96,7 +78,7 @@
|
|||||||
*/
|
*/
|
||||||
- (CPString)cssString
|
- (CPString)cssString
|
||||||
{
|
{
|
||||||
return _cssString;
|
return [_color cssString] + " " + ROUND(_offset.width) + @"px " + ROUND(_offset.height) + @"px " + ROUND(_blurRadius) + @"px";
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+42
-70
@@ -24,25 +24,15 @@
|
|||||||
|
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPImageView.j"
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@typedef CPShadowWeight
|
||||||
CPLightShadow = 0;
|
CPLightShadow = 0;
|
||||||
CPHeavyShadow = 1;
|
CPHeavyShadow = 1;
|
||||||
|
|
||||||
var CPShadowViewLightBackgroundColor = nil,
|
CPThemeStateShadowViewLight = CPThemeState("shadowview-style-light");
|
||||||
CPShadowViewHeavyBackgroundColor = nil;
|
CPThemeStateShadowViewHeavy = CPThemeState("shadowview-style-heavy");
|
||||||
|
|
||||||
var LIGHT_LEFT_INSET = 3.0,
|
|
||||||
LIGHT_RIGHT_INSET = 3.0,
|
|
||||||
LIGHT_TOP_INSET = 3.0,
|
|
||||||
LIGHT_BOTTOM_INSET = 5.0,
|
|
||||||
|
|
||||||
HEAVY_LEFT_INSET = 7.0,
|
|
||||||
HEAVY_RIGHT_INSET = 7.0,
|
|
||||||
HEAVY_TOP_INSET = 5.0,
|
|
||||||
HEAVY_BOTTOM_INSET = 5.0;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -52,40 +42,25 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
CPShadowWeight _weight;
|
CPShadowWeight _weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self !== [CPShadowView class])
|
return "shadow-view";
|
||||||
return;
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:[self class]];
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return @{
|
||||||
|
@"bezel-color": [CPNull null],
|
||||||
|
@"content-inset": CGInsetMakeZero()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
CPShadowViewLightBackgroundColor = CPColorWithImages([
|
+ (CGRect)frameForContentFrame:(CGRect)aFrame withWeight:(CPShadowWeight)aWeight
|
||||||
[@"CPShadowView/CPShadowViewLightTopLeft.png", 9.0, 9.0, bundle],
|
{
|
||||||
[@"CPShadowView/CPShadowViewLightTop.png", 1.0, 9.0, bundle],
|
var shadowView = [CPShadowView new],
|
||||||
[@"CPShadowView/CPShadowViewLightTopRight.png", 9.0, 9.0, bundle],
|
inset = [shadowView valueForThemeAttribute:@"content-inset" inState:(aWeight == CPLightShadow) ? CPThemeStateShadowViewLight : CPThemeStateShadowViewHeavy];
|
||||||
|
|
||||||
[@"CPShadowView/CPShadowViewLightLeft.png", 9.0, 1.0, bundle],
|
return CGRectMake(CGRectGetMinX(aFrame) - inset.left, CGRectGetMinY(aFrame) - inset.top, CGRectGetWidth(aFrame) + inset.left + inset.right, CGRectGetHeight(aFrame) + inset.top + inset.bottom);
|
||||||
nil,
|
|
||||||
[@"CPShadowView/CPShadowViewLightRight.png", 9.0, 1.0, bundle],
|
|
||||||
|
|
||||||
[@"CPShadowView/CPShadowViewLightBottomLeft.png", 9.0, 9.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewLightBottom.png", 1.0, 9.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewLightBottomRight.png", 9.0, 9.0, bundle]
|
|
||||||
]);
|
|
||||||
|
|
||||||
CPShadowViewHeavyBackgroundColor = CPColorWithImages([
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyTopLeft.png", 17.0, 17.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyTop.png", 1.0, 17.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyTopRight.png", 17.0, 17.0, bundle],
|
|
||||||
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyLeft.png", 17.0, 1.0, bundle],
|
|
||||||
nil,
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyRight.png", 17.0, 1.0, bundle],
|
|
||||||
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyBottomLeft.png", 17.0, 17.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyBottom.png", 1.0, 17.0, bundle],
|
|
||||||
[@"CPShadowView/CPShadowViewHeavyBottomRight.png", 17.0, 17.0, bundle]
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)shadowViewEnclosingView:(CPView)aView
|
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||||
@@ -102,15 +77,16 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
[shadowView setWeight:aWeight];
|
[shadowView setWeight:aWeight];
|
||||||
|
|
||||||
var size = [shadowView frame].size,
|
var size = [shadowView frame].size,
|
||||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
inset = [shadowView currentValueForThemeAttribute:@"content-inset"],
|
||||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
width = size.width - inset.left - inset.right,
|
||||||
|
height = size.height - inset.top - inset.bottom,
|
||||||
enclosingView = [aView superview];
|
enclosingView = [aView superview];
|
||||||
|
|
||||||
[shadowView setHitTests:[aView hitTests]];
|
[shadowView setHitTests:[aView hitTests]];
|
||||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||||
[aView removeFromSuperview];
|
[aView removeFromSuperview];
|
||||||
[shadowView addSubview:aView];
|
[shadowView addSubview:aView];
|
||||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
[aView setFrame:CGRectMake(inset.left, inset.top, width, height)];
|
||||||
[enclosingView addSubview:shadowView];
|
[enclosingView addSubview:shadowView];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,9 +99,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_weight = CPLightShadow;
|
[self setWeight:CPLightShadow];
|
||||||
|
|
||||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
|
||||||
|
|
||||||
[self setHitTests:NO];
|
[self setHitTests:NO];
|
||||||
}
|
}
|
||||||
@@ -141,54 +115,45 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
_weight = aWeight;
|
_weight = aWeight;
|
||||||
|
|
||||||
if (_weight == CPLightShadow)
|
if (_weight == CPLightShadow)
|
||||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
[self setThemeState:CPThemeStateShadowViewLight];
|
||||||
|
|
||||||
else
|
else
|
||||||
[self setBackgroundColor:CPShadowViewHeavyBackgroundColor];
|
[self setThemeState:CPThemeStateShadowViewHeavy];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)leftInset
|
- (float)leftInset
|
||||||
{
|
{
|
||||||
return _weight == CPLightShadow ? LIGHT_LEFT_INSET : HEAVY_LEFT_INSET;
|
return [self currentValueForThemeAttribute:@"content-inset"].left;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)rightInset
|
- (float)rightInset
|
||||||
{
|
{
|
||||||
return _weight == CPLightShadow ? LIGHT_RIGHT_INSET : HEAVY_RIGHT_INSET;
|
return [self currentValueForThemeAttribute:@"content-inset"].right;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)topInset
|
- (float)topInset
|
||||||
{
|
{
|
||||||
return _weight == CPLightShadow ? LIGHT_TOP_INSET : HEAVY_TOP_INSET;
|
return [self currentValueForThemeAttribute:@"content-inset"].top;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)bottomInset
|
- (float)bottomInset
|
||||||
{
|
{
|
||||||
return _weight == CPLightShadow ? LIGHT_BOTTOM_INSET : HEAVY_BOTTOM_INSET;
|
return [self currentValueForThemeAttribute:@"content-inset"].bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)horizontalInset
|
- (float)horizontalInset
|
||||||
{
|
{
|
||||||
if (_weight == CPLightShadow)
|
var currentContentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||||
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
|
|
||||||
|
|
||||||
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
|
return currentContentInset.left + currentContentInset.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)verticalInset
|
- (float)verticalInset
|
||||||
{
|
{
|
||||||
if (_weight == CPLightShadow)
|
var currentContentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||||
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
|
|
||||||
|
|
||||||
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
|
return currentContentInset.top + currentContentInset.bottom;
|
||||||
}
|
|
||||||
|
|
||||||
+ (CGRect)frameForContentFrame:(CGRect)aFrame withWeight:(CPShadowWeight)aWeight
|
|
||||||
{
|
|
||||||
if (aWeight == CPLightShadow)
|
|
||||||
return CGRectMake(_CGRectGetMinX(aFrame) - LIGHT_LEFT_INSET, _CGRectGetMinY(aFrame) - LIGHT_TOP_INSET, _CGRectGetWidth(aFrame) + LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET, _CGRectGetHeight(aFrame) + LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET);
|
|
||||||
else
|
|
||||||
return CGRectMake(_CGRectGetMinX(aFrame) - HEAVY_LEFT_INSET, _CGRectGetMinY(aFrame) - HEAVY_TOP_INSET, _CGRectGetWidth(aFrame) + HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET, _CGRectGetHeight(aFrame) + HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)frameForContentFrame:(CGRect)aFrame
|
- (CGRect)frameForContentFrame:(CGRect)aFrame
|
||||||
@@ -201,4 +166,11 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
[self setFrame:[self frameForContentFrame:aFrame]];
|
[self setFrame:[self frameForContentFrame:aFrame]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[super layoutSubviews];
|
||||||
|
|
||||||
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+818
-153
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user