mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-10 12:47:13 +00:00
Compare commits
1161
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7662f89193 | ||
|
|
dbb59f57ea | ||
|
|
c1f538ece5 | ||
|
|
b4cabc97d1 | ||
|
|
cf2e66d7fe | ||
|
|
e511638962 | ||
|
|
8419001810 | ||
|
|
e058d2e143 | ||
|
|
616f0c61ef | ||
|
|
d0ef8a2885 | ||
|
|
985db21ed9 | ||
|
|
d0460ad202 | ||
|
|
8ca7227185 | ||
|
|
6c8a21c1cc | ||
|
|
4a82dbc34d | ||
|
|
1cec1b0637 | ||
|
|
abd9506d40 | ||
|
|
8f7a32141b | ||
|
|
ff067374bc | ||
|
|
6cbfa30652 | ||
|
|
f5a1a6725d | ||
|
|
2508fa7a97 | ||
|
|
0b351ac2d7 | ||
|
|
24b44c2acf | ||
|
|
8f70cebefc | ||
|
|
6e7fc5c887 | ||
|
|
7f53d15e75 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 | ||
|
|
0bbaec0829 | ||
|
|
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 | ||
|
|
7d0d1056c0 | ||
|
|
21146ff49f | ||
|
|
b76eedfc0e | ||
|
|
c547117223 | ||
|
|
fc2132485d | ||
|
|
71cc825038 | ||
|
|
59d1da77c2 | ||
|
|
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 | ||
|
|
347e9cc811 | ||
|
|
1a26fbf6f4 | ||
|
|
fc0689fc3c | ||
|
|
5b28d5f457 | ||
|
|
e17253d592 | ||
|
|
00fea3e02f | ||
|
|
6a72855de8 | ||
|
|
ce62e32dfa | ||
|
|
2cc3521989 | ||
|
|
9f85d2bdb3 | ||
|
|
24d6e581a6 | ||
|
|
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 |
@@ -11,3 +11,7 @@ xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
*.xCodeSupport/
|
||||
*.XcodeSupport/
|
||||
*XcodeSupport/
|
||||
Tests/Manual/**/*.xcodeproj
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
before_install:
|
||||
- jdk_switcher use openjdk6
|
||||
install: ./bootstrap.sh --quiet --noprompt --directory ./narwhal
|
||||
script: jake test
|
||||
env: PATH=$HOME/build/$TRAVIS_REPO_SLUG/narwhal/bin:$PATH CAPP_BUILD=$HOME/build/$TRAVIS_REPO_SLUG/Build NARWHAL_ENGINE=rhino
|
||||
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
@import "CPController.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPDatePicker.j"
|
||||
@import "CPDocument.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPEvent.j"
|
||||
|
||||
+14
-14
@@ -106,7 +106,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
_itemViews = [];
|
||||
_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;
|
||||
@@ -258,18 +258,18 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
var width = _CGRectGetWidth([self frame]);
|
||||
var width = CGRectGetWidth([self frame]);
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
if (width !== _CGRectGetWidth([self frame]))
|
||||
if (width !== CGRectGetWidth([self frame]))
|
||||
[self _invalidateItemsStartingAtIndex:0];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
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)
|
||||
return;
|
||||
@@ -278,7 +278,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
|
||||
var index = _dirtyItemIndex,
|
||||
count = _itemViews.length,
|
||||
width = _CGRectGetWidth([self bounds]),
|
||||
width = CGRectGetWidth([self bounds]),
|
||||
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.
|
||||
@@ -293,7 +293,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
y = CGRectGetMaxY([itemView frame]);
|
||||
}
|
||||
|
||||
[self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), y)];
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), y)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -310,7 +310,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
|
||||
- (id)initWithAccordionView:(CPAccordionView)anAccordionView
|
||||
{
|
||||
self = [super initWithFrame:_CGRectMakeZero()];
|
||||
self = [super initWithFrame:CGRectMakeZero()];
|
||||
|
||||
if (self)
|
||||
{
|
||||
@@ -376,21 +376,21 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
|
||||
- (void)setFrameY:(float)aY width:(float)aWidth
|
||||
{
|
||||
var headerHeight = _CGRectGetHeight([_headerView frame]);
|
||||
var headerHeight = CGRectGetHeight([_headerView frame]);
|
||||
|
||||
// Size to fit or something?
|
||||
[_headerView setFrameSize:_CGSizeMake(aWidth, headerHeight)];
|
||||
[_contentView setFrameOrigin:_CGPointMake(0.0, headerHeight)];
|
||||
[_headerView setFrameSize:CGSizeMake(aWidth, headerHeight)];
|
||||
[_contentView setFrameOrigin:CGPointMake(0.0, headerHeight)];
|
||||
|
||||
if ([self isCollapsed])
|
||||
[self setFrame:_CGRectMake(0.0, aY, aWidth, headerHeight)];
|
||||
[self setFrame:CGRectMake(0.0, aY, aWidth, headerHeight)];
|
||||
|
||||
else
|
||||
{
|
||||
var contentHeight = _CGRectGetHeight([_contentView frame]);
|
||||
var contentHeight = CGRectGetHeight([_contentView frame]);
|
||||
|
||||
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
|
||||
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
||||
[_contentView setFrameSize:CGSizeMake(aWidth, contentHeight)];
|
||||
[self setFrame:CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+104
-76
@@ -91,15 +91,16 @@ var bottomHeight = 71;
|
||||
CPView _accessoryView @accessors(property=accessoryView);
|
||||
CPImage _icon @accessors(property=icon);
|
||||
|
||||
CPArray _buttons @accessors(property=buttons,readonly);
|
||||
CPCheckBox _suppressionButton @accessors(property=suppressionButton,readonly);
|
||||
CPArray _buttons @accessors(property=buttons, readonly);
|
||||
CPCheckBox _suppressionButton @accessors(property=suppressionButton, readonly);
|
||||
|
||||
id _delegate @accessors(property=delegate);
|
||||
id _modalDelegate;
|
||||
SEL _didEndSelector;
|
||||
SEL _didEndSelector @accessors(property=didEndSelector);
|
||||
Function _didEndBlock;
|
||||
|
||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||
CPWindow _window @accessors(property=window,readonly);
|
||||
CPWindow _window @accessors(property=window, readonly);
|
||||
int _defaultWindowStyle;
|
||||
|
||||
CPImageView _alertImageView;
|
||||
@@ -224,16 +225,15 @@ var bottomHeight = 71;
|
||||
}
|
||||
|
||||
|
||||
/*! @deprecated
|
||||
*/
|
||||
- (void)setWindowStyle:(int)aStyle
|
||||
/*! @deprecated */
|
||||
- (void)setWindowStyle:(int)style
|
||||
{
|
||||
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
|
||||
{
|
||||
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
|
||||
@@ -242,18 +242,19 @@ var bottomHeight = 71;
|
||||
|
||||
|
||||
/*!
|
||||
set the text of the alert's message
|
||||
Set the text of the alert's message.
|
||||
|
||||
@param aText CPString containing the text
|
||||
*/
|
||||
- (void)setMessageText:(CPString)aText
|
||||
- (void)setMessageText:(CPString)text
|
||||
{
|
||||
[_messageLabel setStringValue:aText];
|
||||
[_messageLabel setStringValue:text];
|
||||
_needsLayout = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
return the content of the message text
|
||||
Return the content of the message text.
|
||||
|
||||
@return CPString containing the message text
|
||||
*/
|
||||
- (CPString)messageText
|
||||
@@ -262,13 +263,13 @@ var bottomHeight = 71;
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
*/
|
||||
- (void)setInformativeText:(CPString)aText
|
||||
- (void)setInformativeText:(CPString)text
|
||||
{
|
||||
[_informativeLabel setStringValue:aText];
|
||||
[_informativeLabel setStringValue:text];
|
||||
_needsLayout = YES;
|
||||
}
|
||||
|
||||
@@ -285,6 +286,7 @@ var bottomHeight = 71;
|
||||
/*!
|
||||
Sets the title of the alert window.
|
||||
This API is not present in Cocoa.
|
||||
|
||||
@param aTitle CPString containing the window title
|
||||
*/
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
@@ -294,7 +296,7 @@ var bottomHeight = 71;
|
||||
}
|
||||
|
||||
/*!
|
||||
set the accessory view
|
||||
Set the accessory view.
|
||||
|
||||
@param aView the accessory view
|
||||
*/
|
||||
@@ -305,7 +307,7 @@ var bottomHeight = 71;
|
||||
}
|
||||
|
||||
/*!
|
||||
set if alert shows the suppression button
|
||||
Set if the alert shows the suppression button.
|
||||
|
||||
@param shouldShowSuppressionButton YES or NO
|
||||
*/
|
||||
@@ -469,10 +471,6 @@ var bottomHeight = 71;
|
||||
panelSize.height = minimumSize.height;
|
||||
|
||||
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
|
||||
|
||||
if ([_window styleMask] & _CPModalWindowMask)
|
||||
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height / 2 + buttonOffset;
|
||||
|
||||
offsetX = panelSize.width - inset.right;
|
||||
|
||||
switch ([_window styleMask])
|
||||
@@ -600,6 +598,17 @@ var bottomHeight = 71;
|
||||
[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.
|
||||
|
||||
@@ -634,6 +643,20 @@ var bottomHeight = 71;
|
||||
[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
|
||||
|
||||
/*!
|
||||
@@ -644,8 +667,9 @@ var bottomHeight = 71;
|
||||
var frame = CGRectMakeZero();
|
||||
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 setPlatformWindow:[[CPApp keyWindow] platformWindow]];
|
||||
|
||||
if (_title)
|
||||
[_window setTitle:_title];
|
||||
@@ -700,14 +724,28 @@ var bottomHeight = 71;
|
||||
*/
|
||||
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
|
||||
{
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
if (_didEndBlock)
|
||||
{
|
||||
if (typeof(_didEndBlock) === "function")
|
||||
_didEndBlock(self, returnCode);
|
||||
else
|
||||
CPLog.warn("%s: didEnd block is not a function", [self description]);
|
||||
|
||||
_modalDelegate = nil;
|
||||
_didEndSelector = nil;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
// didEnd blocks are transient
|
||||
_didEndBlock = nil;
|
||||
}
|
||||
else if (_modalDelegate)
|
||||
{
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
}
|
||||
else if (_delegate)
|
||||
{
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_delegate, _didEndSelector, self, returnCode);
|
||||
else if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -719,52 +757,42 @@ var bottomHeight = 71;
|
||||
return @"alert";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
|
||||
CPJustifiedTextAlignment, [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,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
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",
|
||||
@"modal-window-button-margin-y",
|
||||
@"modal-window-button-margin-x",
|
||||
@"standard-window-button-margin-y",
|
||||
@"standard-window-button-margin-x"
|
||||
]];
|
||||
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
|
||||
|
||||
@@ -236,7 +236,9 @@ ACTUAL_FRAME_RATE = 0;
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
_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];
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+85
-93
@@ -20,10 +20,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/CPRange.h"
|
||||
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@import "CPApplication_Constants.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPCursor.j"
|
||||
@@ -36,29 +35,12 @@
|
||||
@import "CPPanel.j"
|
||||
@import "CPPlatform.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
||||
CPEventModifierFlags = 0;
|
||||
|
||||
CPApp = nil;
|
||||
|
||||
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
||||
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
||||
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
||||
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
||||
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
||||
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
||||
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||
|
||||
CPTerminateNow = YES;
|
||||
CPTerminateCancel = NO;
|
||||
CPTerminateLater = -1; // not currently supported
|
||||
|
||||
CPRunStoppedResponse = -1000;
|
||||
CPRunAbortedResponse = -1001;
|
||||
CPRunContinuesResponse = -1002;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPApplication
|
||||
@@ -87,6 +69,7 @@ CPRunContinuesResponse = -1002;
|
||||
@implementation CPApplication : CPResponder
|
||||
{
|
||||
CPArray _eventListeners;
|
||||
int _eventListenerInsertionIndex;
|
||||
|
||||
CPEvent _currentEvent;
|
||||
CPWindow _lastMouseMoveWindow;
|
||||
@@ -144,6 +127,7 @@ CPRunContinuesResponse = -1002;
|
||||
if (self)
|
||||
{
|
||||
_eventListeners = [];
|
||||
_eventListenerInsertionIndex = 0;
|
||||
|
||||
_windows = [[CPNull null]];
|
||||
}
|
||||
@@ -173,7 +157,8 @@ CPRunContinuesResponse = -1002;
|
||||
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
|
||||
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
|
||||
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
|
||||
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
|
||||
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:),
|
||||
CPApplicationDidChangeScreenParametersNotification, @selector(applicationDidChangeScreenParameters:)
|
||||
],
|
||||
count = [delegateNotifications count];
|
||||
|
||||
@@ -371,22 +356,32 @@ CPRunContinuesResponse = -1002;
|
||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||
|
||||
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
|
||||
aboutPanelController = [CPWindowController alloc],
|
||||
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
|
||||
aboutPanel = [aboutPanelController window],
|
||||
contentView = [aboutPanel contentView],
|
||||
imageView = [contentView viewWithTag:1],
|
||||
applicationLabel = [contentView viewWithTag:2],
|
||||
versionLabel = [contentView viewWithTag:3],
|
||||
copyrightLabel = [contentView viewWithTag:4],
|
||||
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
||||
var windowWidth = 275,
|
||||
windowHeight = 223,
|
||||
imgWidth = 100,
|
||||
imgHeight = 100,
|
||||
interField = 8,
|
||||
aboutPanel = [[CPWindow alloc] initWithContentRect:CGRectMake(0, 0, windowWidth, windowHeight) styleMask:CPClosableWindowMask],
|
||||
imageView = [[CPImageView alloc] initWithFrame:CGRectMake((windowWidth / 2) - (imgWidth / 2), interField, imgWidth, imgHeight)],
|
||||
applicationLabel = [[CPTextField alloc] initWithFrame:CGRectMake(17, imgHeight + 16, windowWidth - 34, 24)],
|
||||
versionLabel = [[CPTextField alloc] initWithFrame:CGRectMake(17, imgHeight + 48, windowWidth - 34, 16)],
|
||||
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 setAlignment:CPCenterTextAlignment];
|
||||
[versionLabel setFont:[CPFont systemFontOfSize:[CPFont systemFontSize] - 1]];
|
||||
[versionLabel setAlignment:CPCenterTextAlignment];
|
||||
[copyrightLabel setFont:[CPFont systemFontOfSize:[CPFont systemFontSize] - 1]];
|
||||
[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
|
||||
size:CGSizeMake(256, 256)]];
|
||||
@@ -400,7 +395,7 @@ CPRunContinuesResponse = -1002;
|
||||
else
|
||||
[versionLabel setStringValue:@""];
|
||||
|
||||
[copyrightLabel setStringValue:copyright || ""];
|
||||
[copyrightLabel setStringValue:copyright || @""];
|
||||
[aboutPanel center];
|
||||
|
||||
_aboutPanel = aboutPanel;
|
||||
@@ -509,6 +504,8 @@ CPRunContinuesResponse = -1002;
|
||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||
{
|
||||
_eventListeners.splice(count, 1);
|
||||
if (count <= _eventListenerInsertionIndex)
|
||||
_eventListenerInsertionIndex--;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -556,7 +553,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
// [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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -574,8 +571,8 @@ CPRunContinuesResponse = -1002;
|
||||
/* @ignore */
|
||||
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
||||
[[self mainMenu] performKeyEquivalent:anEvent];
|
||||
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
||||
[[self mainMenu] performKeyEquivalent:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -589,45 +586,10 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
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
|
||||
|
||||
// The key equivalent was handled.
|
||||
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]))
|
||||
{
|
||||
var listener = _eventListeners.pop();
|
||||
listener._callback(anEvent);
|
||||
|
||||
if (listener._dequeue)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ([anEvent type] == CPMouseMoved)
|
||||
{
|
||||
@@ -637,6 +599,34 @@ CPRunContinuesResponse = -1002;
|
||||
_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;
|
||||
|
||||
if (theWindow)
|
||||
[theWindow sendEvent:anEvent];
|
||||
}
|
||||
@@ -687,7 +677,7 @@ CPRunContinuesResponse = -1002;
|
||||
- (CPArray)windows
|
||||
{
|
||||
// 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)];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -915,6 +905,12 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
/*!
|
||||
Fires a callback function when an event matching a given mask occurs.
|
||||
|
||||
If multiple callbacks are set which match the same event, later callbacks
|
||||
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).
|
||||
@@ -924,13 +920,18 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
{
|
||||
_eventListeners.push(_CPEventListenerMake(aMask, aCallback, shouldDequeue));
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, aCallback, shouldDequeue));
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
||||
If multiple callbacks are set which match the same event, later callbacks
|
||||
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 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.
|
||||
@@ -941,7 +942,7 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (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); }, shouldDequeue));
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -959,10 +960,10 @@ CPRunContinuesResponse = -1002;
|
||||
@param aSheet the window to display as a sheet
|
||||
@param aWindow the window that will hold the sheet as a child
|
||||
@param aModalDelegate
|
||||
@param aDidEndSelector
|
||||
@param aContextInfo
|
||||
@param didEndSelector
|
||||
@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])
|
||||
{
|
||||
@@ -970,17 +971,8 @@ CPRunContinuesResponse = -1002;
|
||||
return;
|
||||
}
|
||||
|
||||
[aSheet._windowView _enableSheet:YES];
|
||||
|
||||
// -dw- if a sheet is already visible, we skip this since it serves no purpose and causes
|
||||
// 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];
|
||||
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:didEndSelector contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1005,7 +997,7 @@ CPRunContinuesResponse = -1002;
|
||||
var aWindow = [_windows objectAtIndex:count],
|
||||
context = aWindow._sheetContext;
|
||||
|
||||
if (context != nil && context["sheet"] === sheet)
|
||||
if (context && context["sheet"] === sheet)
|
||||
{
|
||||
context["returnCode"] = returnCode;
|
||||
[aWindow _endSheet];
|
||||
@@ -1350,8 +1342,8 @@ var _CPAppBootstrapperActions = nil;
|
||||
if (mainCibFile)
|
||||
{
|
||||
[mainBundle loadCibFile:mainCibFile
|
||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
||||
loadDelegate:self];
|
||||
externalNameTable:@{ CPCibOwner: CPApp }
|
||||
loadDelegate:self];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -1428,7 +1420,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (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
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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";
|
||||
|
||||
CPTerminateNow = YES;
|
||||
CPTerminateCancel = NO;
|
||||
CPTerminateLater = -1; // not currently supported
|
||||
|
||||
CPRunStoppedResponse = -1000;
|
||||
CPRunAbortedResponse = -1001;
|
||||
CPRunContinuesResponse = -1002;
|
||||
+39
-16
@@ -65,51 +65,51 @@
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingContentArray
|
||||
{
|
||||
return [CPSet setWithObjects:"content"];
|
||||
return [CPSet setWithObjects:@"content"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
||||
{
|
||||
// Also depends on "filterPredicate" but we'll handle that manually.
|
||||
return [CPSet setWithObjects:"content", "sortDescriptors"];
|
||||
return [CPSet setWithObjects:@"content", @"sortDescriptors"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelection
|
||||
{
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
|
||||
{
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
|
||||
{
|
||||
// When the arranged objects change, selection preservation may cause the indexes
|
||||
// to change.
|
||||
return [CPSet setWithObjects:"arrangedObjects"];
|
||||
return [CPSet setWithObjects:@"arrangedObjects"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
|
||||
{
|
||||
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
||||
{
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
|
||||
{
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
|
||||
{
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
return [CPSet setWithObjects:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
|
||||
@@ -744,6 +744,7 @@
|
||||
return;
|
||||
|
||||
var willClearPredicate = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
@@ -792,10 +793,18 @@
|
||||
// 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"];
|
||||
|
||||
if (willClearPredicate)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
// TODO: Remove this line when granular notifications are implemented
|
||||
[proxy setAdding:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -811,6 +820,7 @@
|
||||
return;
|
||||
|
||||
var willClearPredicate = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
@@ -848,9 +858,15 @@
|
||||
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
||||
|
||||
var proxy = [_CPKVOProxy proxyForObject:self];
|
||||
[proxy setAdding:YES];
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
|
||||
if (willClearPredicate)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
[proxy setAdding:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -897,7 +913,9 @@
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
[self insert:sender];
|
||||
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
||||
|
||||
[self addObject:newObject];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -909,9 +927,13 @@
|
||||
if (![self canInsert])
|
||||
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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1073,12 +1095,12 @@
|
||||
|
||||
@implementation CPArrayController (CPBinder)
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding == @"contentArray")
|
||||
if (aBinding == @"contentArray")
|
||||
return [_CPArrayControllerContentBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1114,6 +1136,7 @@
|
||||
}
|
||||
|
||||
var isPlaceholder = CPIsControllerMarker(newValue);
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
|
||||
+59
-5
@@ -48,6 +48,8 @@ var DefaultLineWidth = 1.0;
|
||||
{
|
||||
CGPath _path;
|
||||
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.
|
||||
*/
|
||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)aRect
|
||||
{
|
||||
var path = [self bezierPath];
|
||||
|
||||
[path appendBezierPathWithOvalInRect:rect];
|
||||
[path appendBezierPathWithOvalInRect:aRect];
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -73,11 +75,20 @@ var DefaultLineWidth = 1.0;
|
||||
/*!
|
||||
Create a new CPBezierPath object initialized with a rectangular path.
|
||||
*/
|
||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)aRect
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -136,6 +147,8 @@ var DefaultLineWidth = 1.0;
|
||||
{
|
||||
_path = CGPathCreateMutable();
|
||||
_lineWidth = [[self class] defaultLineWidth];
|
||||
_lineDashesPhase = 0;
|
||||
_lineDashes = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -168,7 +181,7 @@ var DefaultLineWidth = 1.0;
|
||||
- (CGRect)bounds
|
||||
{
|
||||
// TODO: this should return this. The controlPointBounds is not a tight fit.
|
||||
// return CGPathGetPathBoundingBox(_path);
|
||||
// return CGPathGetBoundingBox(_path);
|
||||
|
||||
return [self controlPointBounds];
|
||||
}
|
||||
@@ -196,6 +209,7 @@ var DefaultLineWidth = 1.0;
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||
CGContextStrokePath(ctx);
|
||||
}
|
||||
|
||||
@@ -209,10 +223,50 @@ var DefaultLineWidth = 1.0;
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||
CGContextClosePath(ctx);
|
||||
CGContextFillPath(ctx);
|
||||
}
|
||||
|
||||
/*!
|
||||
Cocoa compatibility.
|
||||
*/
|
||||
- (void)getLineDash:(CPArrayRef)patternRef count:(NSInteger)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:(NSInteger)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.
|
||||
*/
|
||||
|
||||
+91
-34
@@ -63,6 +63,33 @@ CPBelowBottom = 6;
|
||||
CPTextField _titleView;
|
||||
}
|
||||
|
||||
+ (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(),
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)boxEnclosingView:(CPView)aView
|
||||
{
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
@@ -78,24 +105,6 @@ CPBelowBottom = 6;
|
||||
return box;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"box";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], 1.0, 3.0, CGSizeMakeZero(), 6.0, [CPNull null], CGSizeMakeZero()]
|
||||
forKeys:[ @"background-color",
|
||||
@"border-color",
|
||||
@"border-width",
|
||||
@"corner-radius",
|
||||
@"inner-shadow-offset",
|
||||
@"inner-shadow-size",
|
||||
@"inner-shadow-color",
|
||||
@"content-margin"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
@@ -279,7 +288,14 @@ CPBelowBottom = 6;
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], contentMargin.width + borderWidth, contentMargin.height + borderWidth)];
|
||||
[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)
|
||||
[self replaceSubview:_contentView with:aView];
|
||||
else
|
||||
[self addSubview:aView];
|
||||
|
||||
_contentView = aView;
|
||||
}
|
||||
@@ -411,9 +427,17 @@ CPBelowBottom = 6;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forKey:(CPString)aKey
|
||||
{
|
||||
if (aKey === CPDisplayPatternTitleBinding)
|
||||
[self setTitle:aValue || @""];
|
||||
else
|
||||
[super setValue:aValue forKey:aKey];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
var bounds = CGRectMakeCopy([self bounds]);
|
||||
var bounds = [self bounds];
|
||||
|
||||
switch (_boxType)
|
||||
{
|
||||
@@ -421,9 +445,9 @@ CPBelowBottom = 6;
|
||||
// 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.
|
||||
if (CGRectGetWidth(bounds) === 5.0)
|
||||
return [self _drawVerticalSeperatorInRect:bounds];
|
||||
return [self _drawVerticalSeparatorInRect:bounds];
|
||||
else if (CGRectGetHeight(bounds) === 5.0)
|
||||
return [self _drawHorizontalSeperatorInRect:bounds];
|
||||
return [self _drawHorizontalSeparatorInRect:bounds];
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -438,6 +462,13 @@ CPBelowBottom = 6;
|
||||
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)
|
||||
{
|
||||
case CPBezelBorder:
|
||||
@@ -455,7 +486,7 @@ CPBelowBottom = 6;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
|
||||
- (void)_drawHorizontalSeparatorInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
@@ -467,7 +498,7 @@ CPBelowBottom = 6;
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
|
||||
- (void)_drawVerticalSeparatorInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
@@ -504,22 +535,51 @@ CPBelowBottom = 6;
|
||||
shadowSize = [self valueForThemeAttribute:@"inner-shadow-size"],
|
||||
shadowColor = [self valueForThemeAttribute:@"inner-shadow-color"];
|
||||
|
||||
var baseRect = aRect;
|
||||
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||
|
||||
// clip the canvas to the actual content view in order to only display inner shadow
|
||||
CGContextBeginPath(context);
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, cornerRadius, cornerRadius, YES, YES, YES, YES));
|
||||
CGContextClip(context);
|
||||
CGContextSaveGState(context);
|
||||
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
|
||||
CGContextSetShadowWithColor(context, shadowOffset, shadowSize, shadowColor);
|
||||
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
|
||||
{
|
||||
@@ -529,9 +589,6 @@ CPBelowBottom = 6;
|
||||
CGContextFillRect(context, aRect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
|
||||
+46
-42
@@ -71,13 +71,13 @@
|
||||
return "browser";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
return @{
|
||||
@"image-control-resize": [CPNull null],
|
||||
@"image-control-leaf": [CPNull null],
|
||||
@"image-control-leaf-pressed": [CPNull null]
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -171,7 +171,7 @@
|
||||
[self addColumn];
|
||||
}
|
||||
|
||||
- (void)setLastColumn:(int)columnIndex
|
||||
- (void)setLastColumn:(CPInteger)columnIndex
|
||||
{
|
||||
if (columnIndex >= _tableViews.length)
|
||||
return;
|
||||
@@ -179,6 +179,11 @@
|
||||
var oldValue = _tableViews.length - 1,
|
||||
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
||||
|
||||
if (columnIndex > 0)
|
||||
[_tableViews[columnIndex - 1] setNeedsDisplay:YES];
|
||||
|
||||
[_tableViews[columnIndex] setNeedsDisplay:YES];
|
||||
|
||||
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
@@ -286,7 +291,7 @@
|
||||
[aTableView addTableColumn:column];
|
||||
}
|
||||
|
||||
- (void)reloadColumn:(int)column
|
||||
- (void)reloadColumn:(CPInteger)column
|
||||
{
|
||||
[[self tableViewInColumn:column] reloadData];
|
||||
}
|
||||
@@ -354,7 +359,7 @@
|
||||
|
||||
// ITEMS
|
||||
|
||||
- (id)itemAtRow:(int)row inColumn:(int)column
|
||||
- (id)itemAtRow:(CPInteger)row inColumn:(CPInteger)column
|
||||
{
|
||||
return [_tableDelegates[column] childAtIndex:row];
|
||||
}
|
||||
@@ -364,7 +369,7 @@
|
||||
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
|
||||
}
|
||||
|
||||
- (id)parentForItemsInColumn:(int)column
|
||||
- (id)parentForItemsInColumn:(CPInteger)column
|
||||
{
|
||||
return [_tableDelegates[column] _item];
|
||||
}
|
||||
@@ -426,11 +431,26 @@
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var column = [self selectedColumn];
|
||||
if (column === -1)
|
||||
var key = [anEvent charactersIgnoringModifiers],
|
||||
column = [self selectedColumn];
|
||||
|
||||
if (column === CPNotFound)
|
||||
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
|
||||
@@ -632,7 +652,7 @@
|
||||
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||
@@ -640,7 +660,7 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
@@ -648,7 +668,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
@@ -751,7 +771,7 @@
|
||||
CPBrowser _browser @accessors;
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)aFrame
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
@@ -805,6 +825,14 @@
|
||||
return _browser;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)_isFocused
|
||||
{
|
||||
return ([super _isFocused] || [_browser tableViewInColumn:[_browser selectedColumn]] === self);
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||
{
|
||||
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
||||
@@ -829,30 +857,6 @@
|
||||
[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
|
||||
|
||||
@@ -898,12 +902,12 @@
|
||||
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
||||
}
|
||||
|
||||
- (id)childAtIndex:(unsigned)index
|
||||
- (id)childAtIndex:(CPUInteger)index
|
||||
{
|
||||
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:)])
|
||||
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
||||
@@ -911,7 +915,7 @@
|
||||
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:)])
|
||||
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||
@@ -991,7 +995,7 @@
|
||||
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||
}
|
||||
|
||||
- (void)initWithCoder:(CPCoder)aCoder
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
|
||||
+70
-46
@@ -60,11 +60,11 @@ CPMomentaryPushInButton = 7;
|
||||
CPMomentaryPushButton = 0;
|
||||
CPMomentaryLight = 7;
|
||||
|
||||
CPNoButtonMask = 0;
|
||||
CPContentsButtonMask = 1;
|
||||
CPPushInButtonMask = 2;
|
||||
CPGrayButtonMask = 4;
|
||||
CPBackgroundButtonMask = 8;
|
||||
CPNoButtonMask = 0;
|
||||
CPContentsButtonMask = 1;
|
||||
CPPushInButtonMask = 2;
|
||||
CPGrayButtonMask = 4;
|
||||
CPBackgroundButtonMask = 8;
|
||||
|
||||
CPNoCellMask = CPNoButtonMask;
|
||||
CPContentsCellMask = CPContentsButtonMask;
|
||||
@@ -72,16 +72,19 @@ CPPushInCellMask = CPPushInButtonMask;
|
||||
CPChangeGrayCellMask = CPGrayButtonMask;
|
||||
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
||||
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
|
||||
|
||||
// add all future correspondance between bezel styles and theme state here.
|
||||
var CPButtonBezelStyleStateMap = [CPDictionary dictionaryWithObjects:[CPButtonStateBezelStyleRounded, nil]
|
||||
forKeys:[CPRoundedBezelStyle, CPRoundRectBezelStyle]];
|
||||
|
||||
var CPButtonBezelStyleStateMap = @{
|
||||
CPRoundedBezelStyle: CPButtonStateBezelStyleRounded,
|
||||
CPRoundRectBezelStyle: [CPNull null],
|
||||
};
|
||||
|
||||
/// @cond IGNORE
|
||||
CPButtonDefaultHeight = 25.0;
|
||||
CPButtonImageOffset = 3.0;
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -117,6 +120,14 @@ CPButtonImageOffset = 3.0;
|
||||
BOOL _isTracking;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
|
||||
return [CPActionBinding class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (id)buttonWithTitle:(CPString)aTitle
|
||||
{
|
||||
return [self buttonWithTitle:aTitle theme:[CPTheme defaultTheme]];
|
||||
@@ -138,10 +149,15 @@ CPButtonImageOffset = 3.0;
|
||||
return @"button";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
return @{
|
||||
@"image": [CPNull null],
|
||||
@"image-offset": 0.0,
|
||||
@"bezel-inset": CGInsetMakeZero(),
|
||||
@"content-inset": CGInsetMakeZero(),
|
||||
@"bezel-color": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -222,7 +238,7 @@ CPButtonImageOffset = 3.0;
|
||||
else if (![anObjectValue isKindOfClass:[CPNumber class]])
|
||||
anObjectValue = CPOnState;
|
||||
else if (anObjectValue >= CPOnState)
|
||||
anObjectValue = CPOnState
|
||||
anObjectValue = CPOnState;
|
||||
else if (anObjectValue < CPOffState)
|
||||
if ([self allowsMixedState])
|
||||
anObjectValue = CPMixedState;
|
||||
@@ -276,7 +292,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:
|
||||
\c CPOffState, \c CPOnState, \c CPMixedState
|
||||
*/
|
||||
@@ -432,38 +448,47 @@ CPButtonImageOffset = 3.0;
|
||||
{
|
||||
switch (aButtonType)
|
||||
{
|
||||
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
case CPMomentaryLightButton:
|
||||
[self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
case CPMomentaryPushInButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
case CPMomentaryPushInButton:
|
||||
[self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
case CPMomentaryChangeButton: [self setHighlightsBy:CPContentsCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
case CPMomentaryChangeButton:
|
||||
[self setHighlightsBy:CPContentsCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
case CPPushOnPushOffButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
|
||||
break;
|
||||
case CPPushOnPushOffButton:
|
||||
[self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
|
||||
break;
|
||||
|
||||
case CPOnOffButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
break;
|
||||
case CPOnOffButton:
|
||||
[self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
break;
|
||||
|
||||
case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
break;
|
||||
case CPToggleButton:
|
||||
[self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
break;
|
||||
|
||||
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
|
||||
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
|
||||
case CPSwitchButton:
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
|
||||
|
||||
case CPRadioButton: [CPException raise:CPInvalidArgumentException
|
||||
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
|
||||
case CPRadioButton:
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
|
||||
|
||||
default: [CPException raise:CPInvalidArgumentException
|
||||
reason:"Unknown button type."];
|
||||
default:
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:"Unknown button type."];
|
||||
}
|
||||
|
||||
[self setImageDimsWhenDisabled:YES];
|
||||
@@ -523,6 +548,7 @@ CPButtonImageOffset = 3.0;
|
||||
_isTracking = YES;
|
||||
|
||||
var startedTracking = [super startTrackingAt:aPoint];
|
||||
|
||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
@@ -537,6 +563,7 @@ CPButtonImageOffset = 3.0;
|
||||
else
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
@@ -578,7 +605,7 @@ CPButtonImageOffset = 3.0;
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, contentInset);
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
@@ -589,7 +616,7 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, bezelInset);
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
@@ -649,14 +676,14 @@ CPButtonImageOffset = 3.0;
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
else
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -989,6 +1016,3 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//@import "CPCheckBox.j"
|
||||
//@import "CPRadio.j"
|
||||
|
||||
+12
-19
@@ -79,26 +79,19 @@
|
||||
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],
|
||||
[CPNull null],
|
||||
[CPNull null],
|
||||
[CPNull null]]
|
||||
forKeys:[ @"resize-control-inset",
|
||||
@"resize-control-size",
|
||||
@"resize-control-color",
|
||||
@"bezel-color",
|
||||
@"button-bezel-color",
|
||||
@"button-text-color",
|
||||
@"button-image-plus",
|
||||
@"button-image-minus",
|
||||
@"button-image-action"]];
|
||||
return @{
|
||||
@"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
|
||||
|
||||
+3
-3
@@ -44,12 +44,12 @@ CPCheckBoxImageOffset = 4.0;
|
||||
return @"check-box";
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding === CPValueBinding)
|
||||
if (aBinding === CPValueBinding)
|
||||
return [_CPCheckBoxValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
|
||||
+33
-22
@@ -45,10 +45,10 @@
|
||||
if (_documentView == aView)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPViewFrameDidChangeNotification
|
||||
@@ -67,24 +67,30 @@
|
||||
if (_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];
|
||||
[self _observeDocumentView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_observeDocumentView
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[_documentView setPostsFrameChangedNotifications:YES];
|
||||
[_documentView setPostsBoundsChangedNotifications:YES];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewFrameChanged:)
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewBoundsChanged:)
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
object:_documentView];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the document view.
|
||||
*/
|
||||
@@ -102,19 +108,19 @@
|
||||
- (CGPoint)constrainScrollPoint:(CGPoint)aPoint
|
||||
{
|
||||
if (!_documentView)
|
||||
return _CGPointMakeZero();
|
||||
return CGPointMakeZero();
|
||||
|
||||
var documentFrame = [_documentView frame];
|
||||
|
||||
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.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)));
|
||||
|
||||
return aPoint;
|
||||
}
|
||||
|
||||
- (void)setBoundsOrigin:(CGPoint)aPoint
|
||||
{
|
||||
if (_CGPointEqualToPoint(_bounds.origin, aPoint))
|
||||
if (CGPointEqualToPoint(_bounds.origin, aPoint))
|
||||
return;
|
||||
|
||||
[super setBoundsOrigin:aPoint];
|
||||
@@ -234,7 +240,12 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
||||
- (id)initWithCoder:(CPCoder)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];
|
||||
[self _observeDocumentView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+574
-227
File diff suppressed because it is too large
Load Diff
@@ -22,13 +22,38 @@
|
||||
|
||||
@import "CPViewController.j"
|
||||
|
||||
|
||||
/*!
|
||||
Represents an object inside a CPCollectionView.
|
||||
*/
|
||||
@implementation CPCollectionViewItem : CPViewController
|
||||
{
|
||||
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
|
||||
|
||||
+91
-23
@@ -156,11 +156,15 @@ var cachedBlackColor,
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new color in HSB space.
|
||||
Creates a new color based on the given HSB components.
|
||||
|
||||
@param hue the hue value
|
||||
@param saturation the saturation value
|
||||
@param brightness the brightness value
|
||||
Note: earlier versions of this method took a hue component as degrees between 0-360,
|
||||
and saturation and brightness components as percent between 0-100. This method has
|
||||
now been corrected to take all components in the 0-1 range as in Cocoa.
|
||||
|
||||
@param hue the hue component (0.0-1.0)
|
||||
@param saturation the saturation component (0.0-1.0)
|
||||
@param brightness the brightness component (0.0-1.0)
|
||||
|
||||
@return the initialized color
|
||||
*/
|
||||
@@ -169,25 +173,61 @@ var cachedBlackColor,
|
||||
return [self colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Calibrated colors are not supported in Cappuccino.
|
||||
|
||||
This method has the same result as [CPColor colorWithHue:saturation:brightness:alpha:].
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
|
||||
{
|
||||
return [self colorWithHue:hue saturation:saturation brightness:brightness alpha:alpha];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new color based on the given HSB components.
|
||||
|
||||
Note: earlier versions of this method took a hue component as degrees between 0-360,
|
||||
and saturation and brightness components as percent between 0-100. This method has
|
||||
now been corrected to take all components in the 0-1 range as in Cocoa.
|
||||
|
||||
@param hue the hue component (0.0-1.0)
|
||||
@param saturation the saturation component (0.0-1.0)
|
||||
@param brightness the brightness component (0.0-1.0)
|
||||
@param alpha the opacity component (0.0-1.0)
|
||||
|
||||
@return the initialized color
|
||||
*/
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
|
||||
{
|
||||
// Clamp values.
|
||||
hue = MAX(MIN(hue, 1.0), 0.0);
|
||||
saturation = MAX(MIN(saturation, 1.0), 0.0);
|
||||
brightness = MAX(MIN(brightness, 1.0), 0.0);
|
||||
|
||||
if (saturation === 0.0)
|
||||
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
|
||||
return [CPColor colorWithCalibratedWhite:brightness alpha:alpha];
|
||||
|
||||
var f = hue % 60,
|
||||
p = (brightness * (100 - saturation)) / 10000,
|
||||
q = (brightness * (6000 - saturation * f)) / 600000,
|
||||
t = (brightness * (6000 - saturation * (60 -f))) / 600000,
|
||||
b = brightness / 100.0;
|
||||
var f = (hue * 360) % 60,
|
||||
p = (brightness * (1 - saturation)),
|
||||
q = (brightness * (60 - saturation * f)) / 60,
|
||||
t = (brightness * (60 - saturation * (60 - f))) / 60,
|
||||
b = brightness;
|
||||
|
||||
switch (FLOOR(hue / 60))
|
||||
switch (FLOOR(hue * 6))
|
||||
{
|
||||
case 0: return [CPColor colorWithCalibratedRed:b green:t blue:p alpha:alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed:q green:b blue:p alpha:alpha];
|
||||
case 2: return [CPColor colorWithCalibratedRed:p green:b blue:t alpha:alpha];
|
||||
case 3: return [CPColor colorWithCalibratedRed:p green:q blue:b alpha:alpha];
|
||||
case 4: return [CPColor colorWithCalibratedRed:t green:p blue:b alpha:alpha];
|
||||
case 5: return [CPColor colorWithCalibratedRed:b green:p blue:q alpha:alpha];
|
||||
case 0:
|
||||
case 6:
|
||||
return [CPColor colorWithCalibratedRed:b green:t blue:p alpha:alpha];
|
||||
case 1:
|
||||
return [CPColor colorWithCalibratedRed:q green:b blue:p alpha:alpha];
|
||||
case 2:
|
||||
return [CPColor colorWithCalibratedRed:p green:b blue:t alpha:alpha];
|
||||
case 3:
|
||||
return [CPColor colorWithCalibratedRed:p green:q blue:b alpha:alpha];
|
||||
case 4:
|
||||
return [CPColor colorWithCalibratedRed:t green:p blue:b alpha:alpha];
|
||||
case 5:
|
||||
return [CPColor colorWithCalibratedRed:b green:p blue:q alpha:alpha];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +615,9 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Returns an array with the HSB values for this color.
|
||||
|
||||
The values are expressed as fractions between 0.0-1.0.
|
||||
|
||||
The index values are ordered as:
|
||||
<pre>
|
||||
<b>Index</b> <b>Component</b>
|
||||
@@ -621,12 +664,36 @@ var cachedBlackColor,
|
||||
}
|
||||
|
||||
return [
|
||||
ROUND(hue * 360.0),
|
||||
ROUND(saturation * 100.0),
|
||||
ROUND(brightness * 100.0)
|
||||
hue,
|
||||
saturation,
|
||||
brightness
|
||||
];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the hue component, the H in HSB, of the receiver.
|
||||
*/
|
||||
- (float)hueComponent
|
||||
{
|
||||
return [self hsbComponents][0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the saturation component, the S in HSB, of the receiver.
|
||||
*/
|
||||
- (float)saturationComponent
|
||||
{
|
||||
return [self hsbComponents][1];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the brightness component, the B in HSB, of the receiver.
|
||||
*/
|
||||
- (float)brightnessComponent
|
||||
{
|
||||
return [self hsbComponents][2];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the CSS representation of this color. The color will
|
||||
be in one of the following forms:
|
||||
@@ -1069,7 +1136,8 @@ function CPColorWithImages()
|
||||
return imageFromSlices(args[0], args[1], imageFactory);
|
||||
|
||||
case 3:
|
||||
return [CPColor colorWithPatternImage:imageFactory(args[0], args[1], args[2])];
|
||||
case 4:
|
||||
return [CPColor colorWithPatternImage:imageFactory(args[0], args[1], args[2], args[3])];
|
||||
|
||||
default:
|
||||
throw("ERROR: Invalid argument count: " + args.length);
|
||||
@@ -1084,7 +1152,7 @@ var imageFromSlices = function(slices, isVertical, imageFactory)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? imageFactory(slice[0], slice[1], slice[2]) : nil);
|
||||
imageSlices.push(slice ? imageFactory(slice[0], slice[1], slice[2], slice[3]) : nil);
|
||||
}
|
||||
|
||||
switch (slices.length)
|
||||
@@ -1302,7 +1370,7 @@ var cloneObject = function(object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
clone[key] = object[key].slice(0);
|
||||
else if (typeof(object) === "object")
|
||||
else if (typeof(object[key]) === "object")
|
||||
clone[key] = cloneObject(object[key]);
|
||||
else
|
||||
clone[key] = object[key];
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
@import "CPButton.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPSlider
|
||||
@@ -575,7 +576,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
[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],
|
||||
pasteboard = [aSender draggingPasteboard],
|
||||
@@ -614,7 +615,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
return _colorPanel;
|
||||
}
|
||||
|
||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
||||
- (void)performDragOperation:(id /*<CPDraggingInfo>*/)aSender
|
||||
{
|
||||
var pasteboard = [aSender draggingPasteboard];
|
||||
|
||||
|
||||
+10
-10
@@ -115,12 +115,12 @@
|
||||
|
||||
- (id)initView
|
||||
{
|
||||
var aFrame = _CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
var aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
|
||||
_pickerView = [[CPView alloc] initWithFrame:aFrame];
|
||||
[_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:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"]]] forThemeAttribute:@"track-color"];
|
||||
@@ -133,7 +133,7 @@
|
||||
[_brightnessSlider setAction:@selector(brightnessSliderDidChange:)];
|
||||
[_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 setAutoresizingMask:(CPViewWidthSizable | CPViewHeightSizable)];
|
||||
|
||||
@@ -158,12 +158,12 @@
|
||||
brightness = [_brightnessSlider floatValue];
|
||||
|
||||
[_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],
|
||||
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];
|
||||
}
|
||||
@@ -194,10 +194,10 @@
|
||||
var hsb = [newColor hsbComponents];
|
||||
|
||||
[_hueSaturationView setPositionToColor:newColor];
|
||||
[_brightnessSlider setFloatValue:hsb[2]];
|
||||
[_hueSaturationView setWheelBrightness:hsb[2] / 100.0];
|
||||
[_brightnessSlider setFloatValue: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
|
||||
@@ -366,8 +366,8 @@
|
||||
{
|
||||
var hsb = [aColor hsbComponents],
|
||||
bounds = [self bounds],
|
||||
angle = [self degreesToRadians:hsb[0]],
|
||||
distance = (hsb[1] / 100.0) * _radius;
|
||||
angle = [self degreesToRadians:hsb[0] * 360.0],
|
||||
distance = hsb[1] * _radius;
|
||||
|
||||
[self setAngle:angle distance:distance];
|
||||
}
|
||||
|
||||
+26
-32
@@ -45,12 +45,12 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
CPColor _color;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding == CPValueBinding)
|
||||
if (aBinding == CPValueBinding)
|
||||
return [CPColorWellValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -58,10 +58,15 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
return @"colorwell";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), [CPNull null], _CGInsetMake(3.0, 3.0, 3.0, 3.0), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"bezel-color", @"content-inset", @"content-border-inset", @"content-border-color"]];
|
||||
return @{
|
||||
@"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
|
||||
@@ -244,21 +249,21 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, contentInset);
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, bezelInset);
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGRect)contentBorderRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, contentBorderInset);
|
||||
return CGRectInsetByInset(bounds, contentBorderInset);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
@@ -278,7 +283,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -315,7 +320,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var placeholderColor = [CPColor blueColor];
|
||||
var placeholderColor = [CPColor blackColor];
|
||||
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
@@ -323,30 +328,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination valueForKeyPath:keyPath],
|
||||
isPlaceholder = CPIsControllerMarker(newValue);
|
||||
return [_source color];
|
||||
}
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)theBinding
|
||||
{
|
||||
[_source setColor:aValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
}
|
||||
|
||||
[_source setColor:newValue];
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setColor:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+21
-16
@@ -58,17 +58,20 @@ var CPComboBoxTextSubview = @"text",
|
||||
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 [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -168,7 +171,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
#pragma mark Setting a Delegate
|
||||
|
||||
- (id < CPComboBoxDelegate >)delegate
|
||||
- (id /*< CPComboBoxDelegate >*/)delegate
|
||||
{
|
||||
return [super delegate];
|
||||
}
|
||||
@@ -179,7 +182,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
protocol, in actual fact it doesn't. Also note that the same
|
||||
delegate may conform to the NSTextFieldDelegate protocol.
|
||||
*/
|
||||
- (void)setDelegate:(id < CPComboBoxDelegate >)aDelegate
|
||||
- (void)setDelegate:(id /*< CPComboBoxDelegate >*/)aDelegate
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
@@ -228,7 +231,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
#pragma mark Setting a Data Source
|
||||
|
||||
- (id < CPComboBoxDataSource >)dataSource
|
||||
- (id /*< CPComboBoxDataSource >*/)dataSource
|
||||
{
|
||||
if (!_usesDataSource)
|
||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||
@@ -236,7 +239,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
return _dataSource;
|
||||
}
|
||||
|
||||
- (void)setDataSource:(id < CPComboBoxDataSource >)aSource
|
||||
- (void)setDataSource:(id /*< CPComboBoxDataSource >*/)aSource
|
||||
{
|
||||
if (!_usesDataSource)
|
||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||
@@ -851,7 +854,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
{
|
||||
if (aName === "popup-button-view")
|
||||
{
|
||||
var view = [[_CPComboBoxPopUpButton alloc] initWithFrame:_CGRectMakeZero() comboBox:self];
|
||||
var view = [[_CPComboBoxPopUpButton alloc] initWithFrame:CGRectMakeZero() comboBox:self];
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -1111,7 +1114,7 @@ var CPComboBoxCompletionTest = function(object, index, context)
|
||||
*/
|
||||
@implementation _CPComboBoxContentBinder : CPBinder
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
@@ -1153,13 +1156,15 @@ var CPComboBoxCompletionTest = function(object, index, context)
|
||||
else
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
|
||||
switch (theBinding)
|
||||
switch (aBinding)
|
||||
{
|
||||
case CPContentBinding: [_source setContent:newValue];
|
||||
break;
|
||||
case CPContentBinding:
|
||||
[_source setContent:newValue];
|
||||
break;
|
||||
|
||||
case CPContentValuesBinding: [_source setContentValues:newValue];
|
||||
break;
|
||||
case CPContentValuesBinding:
|
||||
[_source setContentValues:newValue];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+122
-65
@@ -38,58 +38,68 @@ CPWindowsOperatingSystem = 1;
|
||||
CPOtherOperatingSystem = 2;
|
||||
|
||||
// Features
|
||||
CPCSSRGBAFeature = 1 << 5;
|
||||
CPCSSRGBAFeature = 5;
|
||||
|
||||
CPHTMLCanvasFeature = 1 << 6;
|
||||
CPHTMLContentEditableFeature = 1 << 7;
|
||||
CPHTMLDragAndDropFeature = 1 << 8;
|
||||
CPHTMLCanvasFeature = 6;
|
||||
CPHTMLContentEditableFeature = 7;
|
||||
CPHTMLDragAndDropFeature = 8;
|
||||
|
||||
CPJavaScriptInnerTextFeature = 1 << 9;
|
||||
CPJavaScriptTextContentFeature = 1 << 10;
|
||||
CPJavaScriptClipboardEventsFeature = 1 << 11;
|
||||
CPJavaScriptClipboardAccessFeature = 1 << 12;
|
||||
CPJavaScriptCanvasDrawFeature = 1 << 13;
|
||||
CPJavaScriptCanvasTransformFeature = 1 << 14;
|
||||
CPJavaScriptInnerTextFeature = 9;
|
||||
CPJavaScriptTextContentFeature = 10;
|
||||
// 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.
|
||||
CPJavaScriptClipboardEventsFeature = 11;
|
||||
// window.clipboardData exists and can be read and written to at any time using window.clipboardData.getData/setData.
|
||||
CPJavaScriptClipboardAccessFeature = 12;
|
||||
CPJavaScriptCanvasDrawFeature = 13;
|
||||
CPJavaScriptCanvasTransformFeature = 14;
|
||||
|
||||
CPVMLFeature = 1 << 15;
|
||||
CPVMLFeature = 15;
|
||||
|
||||
CPJavaScriptRemedialKeySupport = 1 << 16;
|
||||
CPJavaScriptShadowFeature = 1 << 20;
|
||||
CPJavaScriptRemedialKeySupport = 16;
|
||||
CPJavaScriptShadowFeature = 20;
|
||||
|
||||
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
||||
CPJavaScriptMouseWheelValues_8_15 = 1 << 23;
|
||||
CPJavaScriptNegativeMouseWheelValues = 22;
|
||||
CPJavaScriptMouseWheelValues_8_15 = 23;
|
||||
|
||||
CPOpacityRequiresFilterFeature = 1 << 24;
|
||||
CPOpacityRequiresFilterFeature = 24;
|
||||
|
||||
//Internet explorer does not allow dynamically changing the type of an input element
|
||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
||||
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
||||
// Internet explorer does not allow dynamically changing the type of an input element
|
||||
CPInputTypeCanBeChangedFeature = 25;
|
||||
CPHTML5DragAndDropSourceYOffBy1 = 26;
|
||||
|
||||
CPSOPDisabledFromFileURLs = 1 << 27;
|
||||
CPSOPDisabledFromFileURLs = 27;
|
||||
|
||||
// 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.
|
||||
CPInput1PxLeftPadding = 1 << 29;
|
||||
CPInputOnInputEventFeature = 1 << 30;
|
||||
CPInput1PxLeftPadding = 29;
|
||||
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
|
||||
// (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
|
||||
CPFileAPIFeature = 31;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
var USER_AGENT = "",
|
||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||
PLATFORM_FEATURES = 0,
|
||||
PLATFORM_FEATURES = [],
|
||||
PLATFORM_BUGS = 0,
|
||||
PLATFORM_STYLE_JS_PROPERTIES = {};
|
||||
|
||||
// default these features to true
|
||||
|
||||
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
||||
PLATFORM_FEATURES |= CPInputSetFontOutsideOfDOM;
|
||||
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = YES;
|
||||
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
||||
|
||||
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
@@ -99,7 +109,7 @@ if (typeof window !== "undefined" && window.opera)
|
||||
{
|
||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
}
|
||||
|
||||
// Internet Explorer
|
||||
@@ -108,16 +118,19 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
|
||||
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
||||
|
||||
// Features we can only be sure of with IE (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPVMLFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
PLATFORM_FEATURES[CPVMLFeature] = YES;
|
||||
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||
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.
|
||||
PLATFORM_FEATURES &= ~CPInputSetFontOutsideOfDOM;
|
||||
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = NO;
|
||||
|
||||
// IE allows free clipboard access.
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
|
||||
}
|
||||
|
||||
// WebKit
|
||||
@@ -126,15 +139,12 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
PLATFORM_ENGINE = CPWebKitBrowserEngine;
|
||||
|
||||
// Features we can only be sure of with WebKit (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
||||
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||
PLATFORM_FEATURES[CPHTMLContentEditableFeature] = YES;
|
||||
|
||||
if (USER_AGENT.indexOf("Chrome") === -1)
|
||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardEventsFeature] = YES;
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = NO;
|
||||
PLATFORM_FEATURES[CPJavaScriptShadowFeature] = YES;
|
||||
|
||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||
@@ -144,22 +154,29 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
||||
|
||||
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:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=21548
|
||||
if (![CPPlatform isBrowser])
|
||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
||||
PLATFORM_FEATURES[CPJavaScriptRemedialKeySupport] = YES;
|
||||
|
||||
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.
|
||||
if (majorVersion < 537)
|
||||
PLATFORM_FEATURES |= CPInput1PxLeftPadding;
|
||||
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
|
||||
if (majorVersion > 533)
|
||||
@@ -177,59 +194,85 @@ else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
|
||||
var index = USER_AGENT.indexOf("Firefox"),
|
||||
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
||||
|
||||
if (version >= 3.0)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||
|
||||
if (version < 3.0)
|
||||
PLATFORM_FEATURES |= CPJavaScriptMouseWheelValues_8_15;
|
||||
PLATFORM_FEATURES[CPJavaScriptMouseWheelValues_8_15] = YES;
|
||||
|
||||
// Some day this might be fixed and should be version prefixed. No known fixed version yet.
|
||||
PLATFORM_FEATURES |= CPInput1PxLeftPadding;
|
||||
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
||||
|
||||
// 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")
|
||||
{
|
||||
var canvasElement = document.createElement("canvas");
|
||||
// Detect Canvas Support
|
||||
|
||||
// Detect canvas support
|
||||
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");
|
||||
|
||||
if (context && context.setTransform && context.transform)
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasTransformFeature] = YES;
|
||||
}
|
||||
|
||||
var DOMElement = document.createElement("div");
|
||||
|
||||
// Detect whether we have innerText or textContent (or neither)
|
||||
if (DOMElement.innerText != undefined)
|
||||
PLATFORM_FEATURES |= CPJavaScriptInnerTextFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptInnerTextFeature] = YES;
|
||||
else if (DOMElement.textContent != undefined)
|
||||
PLATFORM_FEATURES |= CPJavaScriptTextContentFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptTextContentFeature] = YES;
|
||||
|
||||
var DOMInputElement = document.createElement("input");
|
||||
|
||||
if ("oninput" in DOMInputElement)
|
||||
PLATFORM_FEATURES |= CPInputOnInputEventFeature;
|
||||
PLATFORM_FEATURES[CPInputOnInputEventFeature] = YES;
|
||||
else if (typeof DOMInputElement.setAttribute === "function")
|
||||
{
|
||||
DOMInputElement.setAttribute("oninput", "return;");
|
||||
|
||||
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)
|
||||
{
|
||||
return PLATFORM_FEATURES & aFeature;
|
||||
return !!PLATFORM_FEATURES[aFeature];
|
||||
}
|
||||
|
||||
function CPPlatformHasBug(aBug)
|
||||
@@ -308,6 +351,20 @@ function CPBrowserStyleProperty(aProperty)
|
||||
|
||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil;
|
||||
break;
|
||||
|
||||
case 'transformorigin':
|
||||
|
||||
var candidates = {
|
||||
'WebkitTransform' : 'WebkitTransformOrigin',
|
||||
'MozTransform' : 'MozTransformOrigin',
|
||||
'OTransform' : 'OTransformOrigin',
|
||||
'msTransform' : 'MSTransformOrigin',
|
||||
'transform' : 'transformOrigin'
|
||||
};
|
||||
|
||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
|
||||
break;
|
||||
|
||||
default:
|
||||
var prefixes = ["Webkit", "Moz", "O", "ms"],
|
||||
strippedProperty = aProperty.split('-').join(' '),
|
||||
|
||||
+72
-36
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import <Foundation/CPFormatter.j>
|
||||
@import <Foundation/CPTimer.j>
|
||||
|
||||
@@ -112,28 +110,19 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPLeftTextAlignment,
|
||||
CPTopVerticalTextAlignment,
|
||||
CPLineBreakByClipping,
|
||||
[CPColor blackColor],
|
||||
[CPFont systemFontOfSize:CPFontCurrentSystemSize],
|
||||
[CPNull null],
|
||||
_CGSizeMakeZero(),
|
||||
CPImageLeft,
|
||||
CPScaleToFit,
|
||||
_CGSizeMakeZero(),
|
||||
_CGSizeMake(-1.0, -1.0)]
|
||||
forKeys:[@"alignment",
|
||||
@"vertical-alignment",
|
||||
@"line-break-mode",
|
||||
@"text-color",
|
||||
@"font",
|
||||
@"text-shadow-color",
|
||||
@"text-shadow-offset",
|
||||
@"image-position",
|
||||
@"image-scaling",
|
||||
@"min-size",
|
||||
@"max-size"]];
|
||||
return @{
|
||||
@"alignment": CPLeftTextAlignment,
|
||||
@"vertical-alignment": CPTopVerticalTextAlignment,
|
||||
@"line-break-mode": CPLineBreakByClipping,
|
||||
@"text-color": [CPColor blackColor],
|
||||
@"font": [CPFont systemFontOfSize:CPFontCurrentSystemSize],
|
||||
@"text-shadow-color": [CPNull null],
|
||||
@"text-shadow-offset": CGSizeMakeZero(),
|
||||
@"image-position": CPImageLeft,
|
||||
@"image-scaling": CPScaleToFit,
|
||||
@"min-size": CGSizeMakeZero(),
|
||||
@"max-size": CGSizeMake(-1.0, -1.0),
|
||||
};
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
@@ -152,12 +141,14 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self exposeBinding:@"enabled"];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding === CPValueBinding)
|
||||
if (aBinding === CPValueBinding)
|
||||
return [_CPValueBinder class];
|
||||
else if ([aBinding hasPrefix:CPEnabledBinding])
|
||||
return [CPMultipleValueAndBinding class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -239,6 +230,9 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
|
||||
var binding = [CPBinder getBinding:CPTargetBinding forObject:self];
|
||||
[binding invokeAction];
|
||||
|
||||
return [CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
@@ -328,11 +322,11 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
_previousTrackingLocation = currentLocation;
|
||||
}
|
||||
|
||||
- (void)setState:(int)state
|
||||
- (void)setState:(CPInteger)state
|
||||
{
|
||||
}
|
||||
|
||||
- (int)nextState
|
||||
- (CPInteger)nextState
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -536,7 +530,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
return (_value === undefined || _value === nil) ? @"" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -557,10 +551,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
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 (!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
|
||||
}
|
||||
}
|
||||
@@ -613,7 +607,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
if ([note object] != self)
|
||||
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
|
||||
@@ -622,7 +616,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
if ([note object] != self)
|
||||
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
|
||||
@@ -633,7 +627,49 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -819,7 +855,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
/*!
|
||||
Returns the image scaling of the control.
|
||||
*/
|
||||
- (CPImageScaling)imageScaling
|
||||
- (CPUInteger)imageScaling
|
||||
{
|
||||
return [self valueForThemeAttribute:@"image-scaling"];
|
||||
}
|
||||
|
||||
+6
-3
@@ -116,7 +116,8 @@ var currentCursor = nil,
|
||||
|
||||
- (void)push
|
||||
{
|
||||
currentCursor = cursorStack.push(self);
|
||||
cursorStack.push(self);
|
||||
currentCursor = self;
|
||||
}
|
||||
|
||||
- (void)set
|
||||
@@ -162,8 +163,10 @@ var currentCursor = nil,
|
||||
|
||||
if (doesHaveImage)
|
||||
{
|
||||
var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath];
|
||||
cssString = [CPString stringWithFormat:@"url(%@cursors/%@.cur), %@", themeResourcePath, cursorName, aString];
|
||||
var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath],
|
||||
extension = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) ? @"cur" : @"png";
|
||||
|
||||
cssString = [CPString stringWithFormat:@"url(%@cursors/%@.%@), %@", themeResourcePath, cursorName, extension, aString];
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
@@ -0,0 +1,691 @@
|
||||
/* 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/CPDateFormatter.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);
|
||||
|
||||
_CPDatePickerTextField _datePickerTextfield;
|
||||
_CPDatePickerCalendar _datePickerCalendar;
|
||||
unsigned _implementedCDatePickerDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#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(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#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];
|
||||
|
||||
if (!_timeZone)
|
||||
_timeZone = [CPTimeZone systemTimeZone];
|
||||
|
||||
_datePickerTextfield = [[_CPDatePickerTextField alloc] initWithFrame:[self bounds] withDatePicker:self];
|
||||
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
[self addSubview:_datePickerTextfield];
|
||||
|
||||
_datePickerCalendar = [[_CPDatePickerCalendar alloc] initWithFrame:[self bounds] withDatePicker:self];
|
||||
[_datePickerCalendar setDateValue:_dateValue];
|
||||
[_datePickerCalendar setHidden:YES];
|
||||
[self addSubview:_datePickerCalendar];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
{
|
||||
[_datePickerTextfield setHidden:NO];
|
||||
[_datePickerCalendar setHidden:YES];
|
||||
[_datePickerTextfield setNeedsLayout];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_datePickerCalendar setHidden:NO];
|
||||
[_datePickerTextfield setHidden:YES];
|
||||
[_datePickerCalendar setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark 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 ofhe datePier. It has to be a CPDate
|
||||
@param aDateValue the dateValue
|
||||
*/
|
||||
- (void)setObjectValue:(CPDate)aValue
|
||||
{
|
||||
[self setDateValue:aValue];
|
||||
}
|
||||
|
||||
/* Set the dateValue of the datePicker
|
||||
@param aDateValue the dateValue
|
||||
*/
|
||||
- (void)setDateValue:(CPDate)aDateValue
|
||||
{
|
||||
if (aDateValue == nil)
|
||||
return;
|
||||
|
||||
[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
|
||||
{
|
||||
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)
|
||||
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"];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
else
|
||||
[_datePickerCalendar setDateValue:_dateValue];
|
||||
}
|
||||
|
||||
/*! Set the minDate of the datePicker
|
||||
@param aMinDate the minDate
|
||||
*/
|
||||
- (void)setMinDate:(CPDate)aMinDate
|
||||
{
|
||||
[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
|
||||
{
|
||||
[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
|
||||
{
|
||||
_datePickerStyle = aDatePickerStyle;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*! Set the elements of the datePicker
|
||||
@param aDatePickerElements the datePicker elements
|
||||
*/
|
||||
- (void)setDatePickerElements:(CPInteger)aDatePickerElements
|
||||
{
|
||||
_datePickerElements = aDatePickerElements;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*! Set the mode of the datePicker
|
||||
@param aDatePickerMode the datePicker mode
|
||||
*/
|
||||
- (void)setDatePickerMode:(CPInteger)aDatePickerMode
|
||||
{
|
||||
_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
|
||||
{
|
||||
_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)
|
||||
[_datePickerTextfield 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
|
||||
{
|
||||
_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
|
||||
{
|
||||
_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];
|
||||
}
|
||||
|
||||
/*! 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];
|
||||
|
||||
[_datePickerTextfield setEnabled:aBoolean];
|
||||
[_datePickerCalendar setEnabled:aBoolean];
|
||||
}
|
||||
|
||||
/*! 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
|
||||
{
|
||||
[self willChangeValueForKey:@"drawsBackground"];
|
||||
_drawsBackground = aBoolean;
|
||||
[self didChangeValueForKey:@"drawsBackground"];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*! Set the timeZone
|
||||
@param aTimeZone
|
||||
*/
|
||||
- (void)setTimeZone:(CPTimeZone)aTimeZone
|
||||
{
|
||||
[self willChangeValueForKey:@"timeZone"];
|
||||
_timeZone = aTimeZone;
|
||||
[self didChangeValueForKey:@"timeZone"];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark First responder methods
|
||||
|
||||
/*! Return YES if style is set to CPTextFieldAndStepperDatePickerStyle or CPTextFieldDatePickerStyle
|
||||
*/
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield _selecteTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
||||
else
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*! Return YES
|
||||
*/
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*! Return YES
|
||||
*/
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield 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"];
|
||||
}
|
||||
|
||||
/*! Check if we are in the english format or not. Depending on the locale
|
||||
*/
|
||||
- (BOOL)_isEnglishFormat
|
||||
{
|
||||
return [[_locale objectForKey:CPLocaleLanguageCode] isEqualToString:@"en"];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Key event
|
||||
|
||||
/*! Key down event
|
||||
@param anEvent
|
||||
*/
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield 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)
|
||||
{
|
||||
_textFont = [aCoder decodeObjectForKey:CPTextFontKey];
|
||||
_minDate = [aCoder decodeObjectForKey:CPMinDateKey] || [CPDate distantPast];
|
||||
_maxDate = [aCoder decodeObjectForKey:CPMaxDateKey] || [CPDate distantFuture];
|
||||
_timeInterval = [aCoder decodeDoubleForKey:CPIntervalKey];
|
||||
_datePickerMode = [aCoder decodeIntForKey:CPDatePickerModeKey];
|
||||
_datePickerElements = [aCoder decodeIntForKey:CPDatePickerElementsKey];
|
||||
_datePickerStyle = [aCoder decodeIntForKey:CPDatePickerStyleKey];
|
||||
_locale = [aCoder decodeObjectForKey:CPLocaleKey];
|
||||
_dateValue = [aCoder decodeObjectForKey:CPDateValueKey];
|
||||
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
||||
_drawsBackground = [aCoder decodeBoolForKey:CPDrawsBackgroundKey];
|
||||
_isBordered = [aCoder decodeBoolForKey:CPBorderedKey];
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[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
|
||||
|
||||
@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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* _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 "CPView.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CALayer.j"
|
||||
|
||||
|
||||
@class _CPCibCustomResource
|
||||
@class CPDatePicker
|
||||
|
||||
@global CPHourMinuteSecondDatePickerElementFlag
|
||||
@global CPTextFieldAndStepperDatePickerStyle
|
||||
@global CPTextFieldDatePickerStyle
|
||||
|
||||
var RADIANS = Math.PI / 180;
|
||||
|
||||
|
||||
@implementation _CPDatePickerClock : CPView
|
||||
{
|
||||
BOOL _isEnabled;
|
||||
CALayer _rootLayer;
|
||||
CALayer _hourHandLayer;
|
||||
CALayer _minuteHandLayer;
|
||||
CALayer _secondHandLayer;
|
||||
CALayer _middleHandLayer;
|
||||
CPDatePicker _datePicker;
|
||||
CPTextField _PMAMTextField;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame datePicker:(CPDatePicker)aDatePicker
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_datePicker = aDatePicker;
|
||||
|
||||
_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 = [CALayer layer];
|
||||
[self setWantsLayer:YES];
|
||||
[self setLayer:_rootLayer];
|
||||
|
||||
[_hourHandLayer setNeedsDisplay];
|
||||
[_middleHandLayer setNeedsDisplay];
|
||||
[_secondHandLayer setNeedsDisplay];
|
||||
[_minuteHandLayer setNeedsDisplay];
|
||||
|
||||
[_rootLayer addSublayer:_hourHandLayer];
|
||||
[_rootLayer addSublayer:_minuteHandLayer];
|
||||
[_rootLayer addSublayer:_secondHandLayer];
|
||||
[_rootLayer addSublayer:_middleHandLayer];
|
||||
|
||||
[_rootLayer setNeedsDisplay];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Layout methods
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if ([_datePicker datePickerStyle] == CPTextFieldAndStepperDatePickerStyle || [_datePicker datePickerStyle] == CPTextFieldDatePickerStyle)
|
||||
return;
|
||||
|
||||
[super layoutSubviews];
|
||||
|
||||
var bounds = [self bounds],
|
||||
dateValue = [[_datePicker dateValue] copy];
|
||||
|
||||
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||
|
||||
[self setBackgroundColor:[_datePicker currentValueForThemeAttribute:@"bezel-color-clock"]];
|
||||
[_middleHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"middle-hand-image"]];
|
||||
[_hourHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"hour-hand-image"]];
|
||||
[_minuteHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"minute-hand-image"]];
|
||||
[_secondHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"second-hand-image"]];
|
||||
|
||||
if ([_datePicker _isEnglishFormat])
|
||||
{
|
||||
if (dateValue.getHours() > 11)
|
||||
[_PMAMTextField setStringValue:@"PM"]
|
||||
else
|
||||
[_PMAMTextField setStringValue:@"AM"];
|
||||
|
||||
[_PMAMTextField sizeToFit];
|
||||
[_PMAMTextField setFrameOrigin:CGPointMake(bounds.size.width / 2 - [_PMAMTextField frameSize].width / 2, bounds.size.height / 2 + 15)];
|
||||
[_PMAMTextField setHidden:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_PMAMTextField setHidden:YES];
|
||||
}
|
||||
|
||||
[_hourHandLayer setRotationRadians:[self _hourPositionRadianForDate:dateValue]];
|
||||
[_minuteHandLayer setRotationRadians:[self _minutePositionRadianForDate:dateValue]];
|
||||
[_secondHandLayer setRotationRadians:[self _secondPositionRadianForDate:dateValue]];
|
||||
|
||||
[_PMAMTextField setEnabled:_isEnabled];
|
||||
[_hourHandLayer setEnabled:_isEnabled];
|
||||
[_middleHandLayer setEnabled:_isEnabled];
|
||||
[_secondHandLayer setEnabled:_isEnabled];
|
||||
[_minuteHandLayer setEnabled:_isEnabled];
|
||||
|
||||
// Check if we have to display the hand second
|
||||
if (([_datePicker datePickerElements] & CPHourMinuteSecondDatePickerElementFlag) == CPHourMinuteSecondDatePickerElementFlag)
|
||||
[_secondHandLayer setHidden:NO];
|
||||
else
|
||||
[_secondHandLayer setHidden:YES];
|
||||
|
||||
[_rootLayer setNeedsDisplay];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (float)_hourPositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
var hours = aDate.getHours() + aDate.getMinutes() / 60;
|
||||
|
||||
return (360 * hours / 12) * RADIANS;
|
||||
}
|
||||
|
||||
- (float)_secondPositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
return (360 * aDate.getSeconds() / 60) * RADIANS;
|
||||
}
|
||||
|
||||
- (float)_minutePositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
var minutes = aDate.getMinutes() + aDate.getSeconds() / 60;
|
||||
|
||||
return (360 * minutes / 60) * RADIANS;
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)shouldEnable
|
||||
{
|
||||
shouldEnable = !!shouldEnable;
|
||||
|
||||
if (shouldEnable === _isEnabled)
|
||||
return;
|
||||
|
||||
_isEnabled = shouldEnable;
|
||||
[self setNeedsLayout];
|
||||
|
||||
// FIXME: This is a workaround for an apparent bug in CALayer.
|
||||
// Without pumping the event loop, the sublayers of _rootLayer
|
||||
// (the hands) are not redrawn until an event occurs.
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation HandLayer : CALayer
|
||||
{
|
||||
BOOL _isEnabled @accessors(setter=setEnabled:, getter=isEnabled);
|
||||
|
||||
CPImage _image;
|
||||
CALayer _imageLayer;
|
||||
float _rotationRadians;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
- (id)initWithSize:(CGSize)aSize
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_isEnabled = YES;
|
||||
_imageLayer = [CALayer layer];
|
||||
_rotationRadians = 0;
|
||||
|
||||
[_imageLayer setDelegate:self];
|
||||
[_imageLayer setBounds:CGRectMake(0.0, 0.0, aSize.width, aSize.height)];
|
||||
|
||||
[self addSublayer:_imageLayer];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#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)setEnabled:(BOOL)shouldEnable
|
||||
{
|
||||
shouldEnable = !!shouldEnable;
|
||||
|
||||
if (_isEnabled === shouldEnable)
|
||||
return;
|
||||
|
||||
_isEnabled = shouldEnable;
|
||||
[self setNeedsDisplay];
|
||||
[_imageLayer setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (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);
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
+12
-26
@@ -129,7 +129,7 @@ var CPDocumentUntitledCount = 0;
|
||||
if (self)
|
||||
{
|
||||
_windowControllers = [];
|
||||
_viewControllersForWindowControllers = [CPDictionary dictionary];
|
||||
_viewControllersForWindowControllers = @{};
|
||||
|
||||
_hasUndoManager = YES;
|
||||
_changeCount = 0;
|
||||
@@ -244,11 +244,6 @@ var CPDocumentUntitledCount = 0;
|
||||
{
|
||||
}
|
||||
|
||||
- (CPWindowController)firstEligibleExistingWindowController
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Creating and managing window controllers
|
||||
/*!
|
||||
Creates the window controller for this document.
|
||||
@@ -261,6 +256,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (void)makeViewAndWindowControllers
|
||||
{
|
||||
var viewCibName = [self viewCibName],
|
||||
windowCibName = [self windowCibName],
|
||||
viewController = nil,
|
||||
windowController = nil;
|
||||
|
||||
@@ -268,31 +264,21 @@ var CPDocumentUntitledCount = 0;
|
||||
if ([viewCibName length])
|
||||
viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
|
||||
|
||||
// If we have a view controller, check if we have a free window for it.
|
||||
if (viewController)
|
||||
windowController = [self firstEligibleExistingWindowController];
|
||||
// From a cib if we have one.
|
||||
if ([windowCibName length])
|
||||
windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
|
||||
|
||||
// If not, create one.
|
||||
if (!windowController)
|
||||
// If not you get a standard window capable of displaying multiple documents and view
|
||||
else if (viewController)
|
||||
{
|
||||
var windowCibName = [self windowCibName];
|
||||
var view = [viewController view],
|
||||
viewFrame = [view frame];
|
||||
|
||||
// From a cib if we have one.
|
||||
if ([windowCibName length])
|
||||
windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
|
||||
viewFrame.origin = CGPointMake(50, 50);
|
||||
|
||||
// If not you get a standard window capable of displaying multiple documents and view
|
||||
else if (viewController)
|
||||
{
|
||||
var view = [viewController view],
|
||||
viewFrame = [view frame];
|
||||
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||
|
||||
viewFrame.origin = CGPointMake(50, 50);
|
||||
|
||||
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||
|
||||
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
||||
}
|
||||
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
||||
}
|
||||
|
||||
if (windowController && viewController)
|
||||
|
||||
@@ -148,7 +148,7 @@ var CPSharedDocumentController = nil;
|
||||
{
|
||||
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];
|
||||
|
||||
@@ -253,6 +253,14 @@ var CPSharedDocumentController = nil;
|
||||
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.
|
||||
@param aDocument the document to add
|
||||
@@ -271,6 +279,33 @@ var CPSharedDocumentController = nil;
|
||||
[_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
|
||||
{
|
||||
return [_documentTypes[0] objectForKey:@"CPBundleTypeName"];
|
||||
|
||||
+31
-53
@@ -25,8 +25,9 @@
|
||||
@import "CPImageView.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
@class CPWindow // This file is imported by CPWindow.j
|
||||
@class _CPDOMDataTransferPasteboard
|
||||
|
||||
@global CPApp
|
||||
@@ -162,7 +163,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
if (self)
|
||||
{
|
||||
_draggedWindow = [[CPWindow alloc] initWithContentRect:_CGRectMakeZero() styleMask:CPBorderlessWindowMask];
|
||||
_draggedWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessWindowMask];
|
||||
|
||||
[_draggedWindow setLevel:CPDraggingWindowLevel];
|
||||
}
|
||||
@@ -200,7 +201,12 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
- (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
|
||||
{
|
||||
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_)
|
||||
[_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
|
||||
@@ -247,7 +253,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
|
||||
target:self
|
||||
selector:@selector(_sendPeriodicDraggingUpdate:)
|
||||
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
|
||||
userInfo:@{ "platformWindow":aPlatformWindow, "location":aLocation }
|
||||
repeats:NO];
|
||||
|
||||
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
|
||||
@@ -264,10 +270,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
{
|
||||
if ([scrollView hasVerticalScroller])
|
||||
{
|
||||
if (eventLocation.y < _CGRectGetMinY(insetBounds))
|
||||
deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y;
|
||||
else if (eventLocation.y > _CGRectGetMaxY(insetBounds))
|
||||
deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y;
|
||||
if (eventLocation.y < CGRectGetMinY(insetBounds))
|
||||
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
|
||||
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
|
||||
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
|
||||
if (deltaY < -insetBounds.size.height)
|
||||
deltaY = -insetBounds.size.height;
|
||||
if (deltaY > insetBounds.size.height)
|
||||
@@ -276,17 +282,17 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
if ([scrollView hasHorizontalScroller])
|
||||
{
|
||||
if (eventLocation.x < _CGRectGetMinX(insetBounds))
|
||||
deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x;
|
||||
else if (eventLocation.x > _CGRectGetMaxX(insetBounds))
|
||||
deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x;
|
||||
if (eventLocation.x < CGRectGetMinX(insetBounds))
|
||||
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
|
||||
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
|
||||
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
|
||||
if (deltaX < -insetBounds.size.width)
|
||||
deltaX = -insetBounds.size.width;
|
||||
if (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];
|
||||
[[scrollView _headerView] scrollPoint:scrollPoint];
|
||||
@@ -364,22 +370,26 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
if (mouseDownWindow)
|
||||
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
|
||||
_draggingOffset = _CGSizeMakeZero();
|
||||
_draggingOffset = CGSizeMakeZero();
|
||||
|
||||
if ([CPPlatform isBrowser])
|
||||
[_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.
|
||||
_startDragLocation = _CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height);
|
||||
[_draggedWindow setFrameOrigin:_startDragLocation];
|
||||
[_draggedWindow setFrameSize:[aView frame].size];
|
||||
_startDragLocation = CGPointMake(startDragLocationX, startDragLocationY);
|
||||
|
||||
[_draggedWindow _setFrame:draggedWindowFrame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
|
||||
|
||||
[[_draggedWindow contentView] addSubview:aView];
|
||||
|
||||
@@ -428,7 +438,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
var imageSize = [anImage size];
|
||||
|
||||
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];
|
||||
|
||||
@@ -476,35 +486,3 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+25
-2
@@ -68,6 +68,11 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
float _deltaX;
|
||||
float _deltaY;
|
||||
float _deltaZ;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
BOOL _suppressCappuccinoCut;
|
||||
BOOL _suppressCappuccinoPaste;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -235,7 +240,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
*/
|
||||
- (CGPoint)locationInWindow
|
||||
{
|
||||
return _CGPointMakeCopy(_location);
|
||||
return CGPointMakeCopy(_location);
|
||||
}
|
||||
|
||||
- (CGPoint)globalLocation
|
||||
@@ -473,6 +478,24 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
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.
|
||||
|
||||
@@ -527,7 +550,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
|
||||
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];
|
||||
|
||||
+19
-13
@@ -38,7 +38,6 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _DOMParamElement;
|
||||
DOMElement _DOMObjectElement;
|
||||
DOMElement _DOMInnerObjectElement;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -52,22 +51,16 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_DOMObjectElement = document.createElement(@"object");
|
||||
_DOMObjectElement.id = [self elementID];
|
||||
_DOMObjectElement.width = @"100%";
|
||||
_DOMObjectElement.height = @"100%";
|
||||
_DOMObjectElement.style.top = @"0px";
|
||||
_DOMObjectElement.style.left = @"0px";
|
||||
_DOMObjectElement.type = @"application/x-shockwave-flash";
|
||||
_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);
|
||||
}
|
||||
@@ -89,7 +82,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_DOMParamElement.value = [aFlashMovie filename];
|
||||
_DOMInnerObjectElement.data = [aFlashMovie filename];
|
||||
_DOMObjectElement.data = [aFlashMovie filename];
|
||||
}
|
||||
else
|
||||
[self _rebuildIEObjects];
|
||||
@@ -107,11 +100,14 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
enumerator = [aDictionary keyEnumerator],
|
||||
key;
|
||||
|
||||
while ((key = [enumerator nextObject]) !== nil)
|
||||
if (key = [enumerator nextObject])
|
||||
varString = [varString stringByAppendingFormat:@"%@=%@", key, [aDictionary objectForKey:key]];
|
||||
|
||||
while (key = [enumerator nextObject])
|
||||
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
|
||||
|
||||
if (!_params)
|
||||
_params = [CPDictionary dictionary];
|
||||
_params = @{};
|
||||
|
||||
[_params setObject:varString forKey:@"flashvars"];
|
||||
[self setParameters:_params];
|
||||
@@ -141,7 +137,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_paramElements = [CPDictionary dictionary];
|
||||
_paramElements = @{};
|
||||
|
||||
var enumerator = [_params keyEnumerator],
|
||||
key;
|
||||
@@ -184,10 +180,20 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
_DOMObjectElement = document.createElement(@"object");
|
||||
_DOMElement.appendChild(_DOMObjectElement);
|
||||
|
||||
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
||||
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object id=%@ classid=%@ width=%@ height=%@>%@</object>", [self elementID], IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (CPString)elementID
|
||||
{
|
||||
return @"CPFV_" + [self UID];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(CPEvent)sommit
|
||||
{
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
+9
-7
@@ -37,12 +37,12 @@ CPFontCurrentSystemSize = -1;
|
||||
// For internal use only by this class and subclasses
|
||||
_CPFontSystemFacePlaceholder = "_CPFontSystemFacePlaceholder";
|
||||
|
||||
var _CPFontCache = {},
|
||||
_CPSystemFontCache = {},
|
||||
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
||||
_CPFontSystemFontSize = 12,
|
||||
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
||||
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
|
||||
var _CPFontCache = {},
|
||||
_CPSystemFontCache = {},
|
||||
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
||||
_CPFontSystemFontSize = 12,
|
||||
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
||||
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
|
||||
|
||||
|
||||
#define _CPRealFontSize(aSize) (aSize <= 0 ? _CPFontSystemFontSize : aSize)
|
||||
@@ -181,8 +181,10 @@ following:
|
||||
{
|
||||
case CPSmallControlSize:
|
||||
return _CPFontSystemFontSize - 1;
|
||||
|
||||
case CPMiniControlSize:
|
||||
return _CPFontSystemFontSize - 2;
|
||||
|
||||
case CPRegularControlSize:
|
||||
default:
|
||||
return _CPFontSystemFontSize;
|
||||
@@ -206,7 +208,7 @@ following:
|
||||
var systemSize = String(_CPFontSystemFontSize),
|
||||
currentSize = String(CPFontCurrentSystemSize);
|
||||
|
||||
for (key in _CPSystemFontCache)
|
||||
for (var key in _CPSystemFontCache)
|
||||
{
|
||||
if (_CPSystemFontCache.hasOwnProperty(key) &&
|
||||
(key.indexOf(systemSize) === 0 || key.indexOf(currentSize) === 0))
|
||||
|
||||
@@ -208,7 +208,8 @@ var CPSharedFontManager = nil,
|
||||
|
||||
- (@action)addFontTrait:(id)sender
|
||||
{
|
||||
_activeChange = [CPDictionary dictionaryWithObject:[sender tag] forKey:@"addTraits"];
|
||||
var tag = [sender tag];
|
||||
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
|
||||
|
||||
[self sendAction];
|
||||
}
|
||||
|
||||
+44
-8
@@ -27,6 +27,7 @@
|
||||
@import "CGColor.j"
|
||||
@import "CGColorSpace.j"
|
||||
@import "CGGradient.j"
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
CPGradientDrawsBeforeStartingLocation = kCGGradientDrawsBeforeStartLocation;
|
||||
@@ -40,6 +41,11 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
CGGradient _gradient;
|
||||
}
|
||||
|
||||
- (id)initWithStartingColor:(CPColor)startingColor endingColor:(CPColor)endingColor
|
||||
{
|
||||
return [self initWithColors:[startingColor, endingColor]];
|
||||
}
|
||||
|
||||
- (id)initWithColors:(CPArray)someColors
|
||||
{
|
||||
var count = [someColors count];
|
||||
@@ -83,20 +89,32 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
CGContextClipToRect(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;
|
||||
|
||||
// Modulo of negative values doesn't work as expected in JS.
|
||||
angle = ((angle % 360.0) + 360.0) % 360.0;
|
||||
|
||||
if (angle < 90.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMinX(rect), _CGRectGetMinY(rect));
|
||||
startPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
|
||||
else if (angle < 180.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMinY(rect));
|
||||
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
|
||||
else if (angle < 270.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
|
||||
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
|
||||
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
|
||||
// at the starting point and the last at the end. To do what drawInRect: is supposed to do
|
||||
@@ -111,13 +129,31 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
// This simplifies down to (in the first quadrant) rectWidth * cos(a) + rectHeight * sin(a).
|
||||
|
||||
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));
|
||||
|
||||
[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
|
||||
|
||||
+12
-12
@@ -60,9 +60,9 @@ function CPDrawColorTiledRects(
|
||||
if (sides.length != colors.length)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
|
||||
|
||||
var resultRect = _CGRectMakeCopy(boundsRect),
|
||||
slice = _CGRectMakeZero(),
|
||||
remainder = _CGRectMakeZero(),
|
||||
var resultRect = CGRectMakeCopy(boundsRect),
|
||||
slice = CGRectMakeZero(),
|
||||
remainder = CGRectMakeZero(),
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSaveGState(context);
|
||||
@@ -77,7 +77,7 @@ function CPDrawColorTiledRects(
|
||||
slice = CGRectIntersection(slice, clipRect);
|
||||
|
||||
// Cocoa docs say that only slices that are within the clipRect are actually drawn
|
||||
if (_CGRectIsEmpty(slice))
|
||||
if (CGRectIsEmpty(slice))
|
||||
continue;
|
||||
|
||||
var minX,
|
||||
@@ -88,23 +88,23 @@ function CPDrawColorTiledRects(
|
||||
if (side == CPMinXEdge || side == CPMaxXEdge)
|
||||
{
|
||||
// Make sure we have at least 1 pixel to draw a line
|
||||
if (_CGRectGetWidth(slice) < 1.0)
|
||||
if (CGRectGetWidth(slice) < 1.0)
|
||||
continue;
|
||||
|
||||
minX = _CGRectGetMinX(slice) + 0.5;
|
||||
minX = CGRectGetMinX(slice) + 0.5;
|
||||
maxX = minX;
|
||||
minY = _CGRectGetMinY(slice);
|
||||
maxY = _CGRectGetMaxY(slice);
|
||||
minY = CGRectGetMinY(slice);
|
||||
maxY = CGRectGetMaxY(slice);
|
||||
}
|
||||
else // CPMinYEdge || CPMaxYEdge
|
||||
{
|
||||
// Make sure we have at least 1 pixel to draw a line
|
||||
if (_CGRectGetHeight(slice) < 1.0)
|
||||
if (CGRectGetHeight(slice) < 1.0)
|
||||
continue;
|
||||
|
||||
minX = _CGRectGetMinX(slice);
|
||||
maxX = _CGRectGetMaxX(slice);
|
||||
minY = _CGRectGetMinY(slice) + 0.5;
|
||||
minX = CGRectGetMinX(slice);
|
||||
maxX = CGRectGetMaxX(slice);
|
||||
minY = CGRectGetMinY(slice) + 0.5;
|
||||
maxY = minY;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ var CPGraphicsContextCurrent = nil,
|
||||
+ (void)restoreGraphicsState
|
||||
{
|
||||
var lastContext = [CPGraphicsContextThreadStack lastObject];
|
||||
|
||||
if (lastContext)
|
||||
{
|
||||
[lastContext restoreGraphicsState];
|
||||
|
||||
+32
-4
@@ -71,7 +71,7 @@ function CPImageInBundle()
|
||||
|
||||
if (typeof(arguments[1]) === "number")
|
||||
{
|
||||
if (arguments[1] !== nil && arguments[1] === undefined)
|
||||
if (arguments[1] !== nil && arguments[1] !== undefined)
|
||||
size = CGSizeMake(arguments[1], arguments[2]);
|
||||
|
||||
bundle = arguments[3];
|
||||
@@ -136,19 +136,24 @@ function CPAppKitImage(aFilename, aSize)
|
||||
|
||||
/*!
|
||||
Initializes the image, by associating it with a filename. The image
|
||||
denoted in \c aFilename is not actually loaded. It will
|
||||
be loaded once needed.
|
||||
denoted in \c aFilename is not actually loaded. It will be loaded
|
||||
once needed.
|
||||
|
||||
@param aFilename the file containing the image
|
||||
@param aSize the image's size
|
||||
@return the initialized image
|
||||
*/
|
||||
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||
{
|
||||
// Quietly return nil like in Cocoa, rather than crashing later.
|
||||
if (aFilename === undefined || aFilename === nil)
|
||||
return nil;
|
||||
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = CGSizeCreateCopy(aSize);
|
||||
_size = CGSizeMakeCopy(aSize);
|
||||
_filename = aFilename;
|
||||
_loadStatus = CPImageLoadStatusInitialized;
|
||||
}
|
||||
@@ -302,6 +307,14 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return _name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the underlying Image element for a single image.
|
||||
*/
|
||||
- (Image)image
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's delegate.
|
||||
@param the delegate
|
||||
@@ -390,6 +403,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
@@ -521,6 +539,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return _isVertical;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return YES;
|
||||
@@ -585,6 +608,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
return _imageSlices;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
|
||||
+75
-48
@@ -70,12 +70,14 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
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];
|
||||
else if ([aBinding hasPrefix:CPEditableBinding])
|
||||
return [CPMultipleValueAndBinding class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -85,26 +87,37 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
if (self)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement = document.createElement("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";
|
||||
}
|
||||
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
|
||||
|
||||
_DOMImageElement.style.visibility = "hidden";
|
||||
[self _createDOMImageElement];
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_createDOMImageElement
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMImageElement)
|
||||
return;
|
||||
|
||||
_DOMImageElement = document.createElement("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.
|
||||
*/
|
||||
@@ -136,6 +149,9 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
var newImage = [self objectValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (!_DOMImageElement)
|
||||
[self _createDOMImageElement];
|
||||
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||
#endif
|
||||
|
||||
@@ -251,7 +267,7 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (unsigned)imageScaling
|
||||
- (CPUInteger)imageScaling
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image-scaling"];
|
||||
}
|
||||
@@ -300,8 +316,8 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
y = 0.0,
|
||||
insetWidth = (_hasShadow ? [_shadowView horizontalInset] : 0.0),
|
||||
insetHeight = (_hasShadow ? [_shadowView verticalInset] : 0.0),
|
||||
boundsWidth = _CGRectGetWidth(bounds),
|
||||
boundsHeight = _CGRectGetHeight(bounds),
|
||||
boundsWidth = CGRectGetWidth(bounds),
|
||||
boundsHeight = CGRectGetHeight(bounds),
|
||||
width = boundsWidth - insetWidth,
|
||||
height = boundsHeight - insetHeight;
|
||||
|
||||
@@ -399,10 +415,10 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
_imageRect = _CGRectMake(x, y, width, height);
|
||||
_imageRect = CGRectMake(x, y, width, height);
|
||||
|
||||
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
|
||||
@@ -474,16 +490,30 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
{
|
||||
var image;
|
||||
|
||||
if (aBinding === CPDataBinding)
|
||||
if (aValue == nil)
|
||||
image = nil;
|
||||
else if (aBinding === CPDataBinding)
|
||||
image = [[CPImage alloc] initWithData:aValue];
|
||||
else if (aBinding === CPValueURLBinding || aBinding === CPValuePathBinding)
|
||||
image = [[CPImage alloc] initWithContentsOfFile:aValue];
|
||||
image = [CPImage cachedImageWithContentsOfFile:aValue];
|
||||
else if (aBinding === CPValueBinding)
|
||||
image = aValue;
|
||||
|
||||
[_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
|
||||
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
@@ -501,28 +531,12 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
*/
|
||||
- (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];
|
||||
|
||||
if (self)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.appendChild(_DOMImageElement);
|
||||
[self _createDOMImageElement];
|
||||
#endif
|
||||
|
||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||
@@ -548,17 +562,12 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
// We do this in order to avoid encoding the _shadowView, which
|
||||
// should just automatically be created programmatically as needed.
|
||||
if (_shadowView)
|
||||
{
|
||||
var actualSubviews = _subviews;
|
||||
|
||||
_subviews = [_subviews copy];
|
||||
[_subviews removeObjectIdenticalTo:_shadowView];
|
||||
}
|
||||
[_shadowView removeFromSuperview];
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
if (_shadowView)
|
||||
_subviews = actualSubviews;
|
||||
[self addSubview:_shadowView];
|
||||
|
||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
||||
@@ -568,3 +577,21 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+383
-93
@@ -26,12 +26,14 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPInvocation.j>
|
||||
@import <Foundation/CPValueTransformer.j>
|
||||
@import <Foundation/CPKeyValueObserving.j>
|
||||
|
||||
@class CPButton
|
||||
|
||||
var exposedBindingsMap = [CPDictionary new],
|
||||
bindingsMap = [CPDictionary new];
|
||||
var exposedBindingsMap = @{},
|
||||
bindingsMap = @{};
|
||||
|
||||
var CPBindingOperationAnd = 0,
|
||||
CPBindingOperationOr = 1;
|
||||
@@ -39,7 +41,7 @@ var CPBindingOperationAnd = 0,
|
||||
@implementation CPBinder : CPObject
|
||||
{
|
||||
CPDictionary _info;
|
||||
id _source;
|
||||
id _source @accessors(getter=source);
|
||||
|
||||
JSObject _suppressedNotifications;
|
||||
JSObject _placeholderForMarker;
|
||||
@@ -95,9 +97,9 @@ var CPBindingOperationAnd = 0,
|
||||
if (!theBinding)
|
||||
return;
|
||||
|
||||
var infoDictionary = theBinding._info,
|
||||
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
|
||||
var info = theBinding._info,
|
||||
observedObject = [info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [info objectForKey:CPObservedKeyPathKey];
|
||||
|
||||
[observedObject removeObserver:theBinding forKeyPath:keyPath];
|
||||
[bindings removeObjectForKey:aBinding];
|
||||
@@ -106,6 +108,7 @@ var CPBindingOperationAnd = 0,
|
||||
+ (void)unbindAllForObject:(id)anObject
|
||||
{
|
||||
var bindings = [bindingsMap objectForKey:[anObject UID]];
|
||||
|
||||
if (!bindings)
|
||||
return;
|
||||
|
||||
@@ -120,12 +123,17 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
- (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)
|
||||
{
|
||||
_source = aSource;
|
||||
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
|
||||
_info = @{
|
||||
CPObservedObjectKey: aDestination,
|
||||
CPObservedKeyPathKey: aKeyPath,
|
||||
};
|
||||
_suppressedNotifications = {};
|
||||
_placeholderForMarker = {};
|
||||
|
||||
@@ -137,9 +145,10 @@ var CPBindingOperationAnd = 0,
|
||||
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
|
||||
|
||||
var bindings = [bindingsMap objectForKey:[_source UID]];
|
||||
|
||||
if (!bindings)
|
||||
{
|
||||
bindings = [CPDictionary new];
|
||||
bindings = @{};
|
||||
[bindingsMap setObject:bindings forKey:[_source UID]];
|
||||
}
|
||||
|
||||
@@ -150,21 +159,25 @@ var CPBindingOperationAnd = 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination valueForKeyPath:keyPath],
|
||||
isPlaceholder = CPIsControllerMarker(newValue);
|
||||
newValue = [destination valueForKeyPath:keyPath];
|
||||
|
||||
if (isPlaceholder)
|
||||
if (CPIsControllerMarker(newValue))
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + newValue];
|
||||
}
|
||||
[self raiseIfNotApplicable:newValue forKeyPath:keyPath options:options];
|
||||
|
||||
var value = [self _placeholderForMarker:newValue];
|
||||
[self setPlaceholderValue:value withMarker:newValue forBinding:theBinding];
|
||||
@@ -211,6 +224,7 @@ var CPBindingOperationAnd = 0,
|
||||
return;
|
||||
|
||||
var objectSuppressions = _suppressedNotifications[[anObject UID]];
|
||||
|
||||
if (objectSuppressions && objectSuppressions[aKeyPath])
|
||||
return;
|
||||
|
||||
@@ -229,6 +243,7 @@ var CPBindingOperationAnd = 0,
|
||||
if (!valueTransformer)
|
||||
{
|
||||
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
||||
|
||||
if (valueTransformerClass)
|
||||
{
|
||||
valueTransformer = [[valueTransformerClass alloc] init];
|
||||
@@ -242,7 +257,11 @@ var CPBindingOperationAnd = 0,
|
||||
if (valueTransformer)
|
||||
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 === undefined || aValue === nil || aValue === [CPNull null])
|
||||
&& ![_source respondsToSelector:@selector(setPlaceholderString:)])
|
||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
|
||||
return aValue;
|
||||
@@ -286,6 +305,7 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
|
||||
if (!objectSuppressions)
|
||||
_suppressedNotifications[uid] = objectSuppressions = {};
|
||||
|
||||
@@ -302,6 +322,7 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
|
||||
if (!objectSuppressions)
|
||||
return;
|
||||
|
||||
@@ -318,6 +339,7 @@ var CPBindingOperationAnd = 0,
|
||||
optionName = CPBinderPlaceholderOptions[count],
|
||||
isExplicit = [options containsKey:optionName],
|
||||
placeholder = isExplicit ? [options objectForKey:optionName] : nil;
|
||||
|
||||
[self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
|
||||
}
|
||||
}
|
||||
@@ -327,11 +349,13 @@ var CPBindingOperationAnd = 0,
|
||||
[self _updatePlaceholdersWithOptions:options];
|
||||
}
|
||||
|
||||
- (void)_placeholderForMarker:aMarker
|
||||
- (JSObject)_placeholderForMarker:(id)aMarker
|
||||
{
|
||||
var placeholder = _placeholderForMarker[aMarker];
|
||||
var placeholder = _placeholderForMarker[[aMarker UID]];
|
||||
|
||||
if (placeholder)
|
||||
return placeholder['value'];
|
||||
return placeholder.value;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -339,14 +363,14 @@ var CPBindingOperationAnd = 0,
|
||||
{
|
||||
if (isDefault)
|
||||
{
|
||||
var existingPlaceholder = _placeholderForMarker[aMarker];
|
||||
var existingPlaceholder = _placeholderForMarker[[aMarker UID]];
|
||||
|
||||
// Don't overwrite an explicitly set placeholder with a default.
|
||||
if (existingPlaceholder && !existingPlaceholder['isDefault'])
|
||||
if (existingPlaceholder && !existingPlaceholder.isDefault)
|
||||
return;
|
||||
}
|
||||
|
||||
_placeholderForMarker[aMarker] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
||||
_placeholderForMarker[[aMarker UID]] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -358,7 +382,7 @@ var CPBindingOperationAnd = 0,
|
||||
[CPBinder exposeBinding:aBinding forClass:[self class]];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
return [CPBinder class];
|
||||
}
|
||||
@@ -411,7 +435,7 @@ var CPBindingOperationAnd = 0,
|
||||
[binderClass unbind:aBinding forObject:self];
|
||||
}
|
||||
|
||||
- (id)_replacementKeyPathForBinding:(CPString)binding
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)binding
|
||||
{
|
||||
return binding;
|
||||
}
|
||||
@@ -420,13 +444,13 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Provides stub implementations that simply call super for the "objectValue" binding
|
||||
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
|
||||
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.
|
||||
|
||||
IMPORTANT!
|
||||
Every class with a value binding should implement a subclass to handle its specific value binding logic.
|
||||
*/
|
||||
@implementation _CPValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
{
|
||||
@@ -440,8 +464,9 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPKeyValueOrBinding : CPBinder
|
||||
@implementation _CPMultipleValueBooleanBinding : CPBinder
|
||||
{
|
||||
CPBindingOperationKind _operation;
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
@@ -451,7 +476,14 @@ var CPBindingOperationAnd = 0,
|
||||
if (!bindings)
|
||||
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
|
||||
@@ -459,61 +491,146 @@ var CPBindingOperationAnd = 0,
|
||||
[self setValueFor:context];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPKeyValueAndBinding : CPBinder
|
||||
- (BOOL)resolveMultipleValuesForBinding:(CPString)aBinding bindings:(CPDictionary)bindings booleanOperation:(CPBindingOperationKind)operation
|
||||
{
|
||||
}
|
||||
|
||||
- (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,
|
||||
var bindingName = aBinding,
|
||||
theBinding,
|
||||
count = 1;
|
||||
count = 2;
|
||||
|
||||
while (theBinding = [bindings objectForKey:bindingName])
|
||||
{
|
||||
var infoDictionary = theBinding._info,
|
||||
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
||||
options = [infoDictionary objectForKey:CPOptionsKey];
|
||||
var info = theBinding._info,
|
||||
object = [info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [info objectForKey:CPObservedKeyPathKey],
|
||||
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)
|
||||
return operation;
|
||||
if (operation === CPBindingOperationOr)
|
||||
{
|
||||
// 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],
|
||||
infoDictionary = theBinding._info,
|
||||
if (self = [super init])
|
||||
_operation = CPBindingOperationAnd;
|
||||
|
||||
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
||||
options = [infoDictionary objectForKey:CPOptionsKey],
|
||||
return self;
|
||||
}
|
||||
|
||||
@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 || value === undefined)
|
||||
{
|
||||
[_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],
|
||||
selector = [options objectForKey:CPSelectorNameBindingOption];
|
||||
@@ -521,27 +638,194 @@ var invokeAction = function(/*CPString*/targetKey, /*CPString*/argumentKey, /*CP
|
||||
if (!target || !selector)
|
||||
return;
|
||||
|
||||
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
|
||||
[invocation setSelector:selector];
|
||||
|
||||
var bindingName = argumentKey,
|
||||
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]],
|
||||
bindingName = CPArgumentBinding,
|
||||
count = 1;
|
||||
|
||||
while (theBinding = [bindings objectForKey:bindingName])
|
||||
{
|
||||
infoDictionary = theBinding._info;
|
||||
info = theBinding._info;
|
||||
object = [info objectForKey:CPObservedObjectKey];
|
||||
keyPath = [info objectForKey:CPObservedKeyPathKey];
|
||||
|
||||
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
|
||||
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
|
||||
[invocation setArgument:[object valueForKeyPath:keyPath] atIndex:++count];
|
||||
|
||||
if (object)
|
||||
[invocation setArgument:object atIndex:++count];
|
||||
|
||||
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
|
||||
bindingName = CPArgumentBinding + 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 === undefined)
|
||||
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
|
||||
|
||||
@@ -551,18 +835,23 @@ CPObservedKeyPathKey = @"CPObservedKeyPathKey";
|
||||
CPOptionsKey = @"CPOptionsKey";
|
||||
|
||||
// special markers
|
||||
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
|
||||
CPNoSelectionMarker = @"CPNoSelectionMarker";
|
||||
CPNotApplicableMarker = @"CPNotApplicableMarker";
|
||||
CPNullMarker = @"CPNullMarker";
|
||||
CPNoSelectionMarker = [[_CPStateMarker alloc] initWithName:@"NO SELECTION MARKER"];
|
||||
CPMultipleValuesMarker = [[_CPStateMarker alloc] initWithName:@"MULTIPLE VALUES MARKER"];
|
||||
CPNotApplicableMarker = [[_CPStateMarker alloc] initWithName:@"NOT APPLICABLE MARKER"];
|
||||
CPNullMarker = [[_CPStateMarker alloc] initWithName:@"NULL MARKER"];
|
||||
|
||||
// Binding name constants
|
||||
CPAlignmentBinding = @"alignment";
|
||||
CPArgumentBinding = @"argument";
|
||||
CPContentArrayBinding = @"contentArray";
|
||||
CPContentBinding = @"content";
|
||||
CPContentObjectBinding = @"contentObject";
|
||||
CPContentObjectsBinding = @"contentObjects";
|
||||
CPContentValuesBinding = @"contentValues";
|
||||
CPDisplayPatternTitleBinding = @"displayPatternTitle";
|
||||
CPDisplayPatternValueBinding = @"displayPatternValue";
|
||||
CPDoubleClickArgumentBinding = @"doubleClickArgument";
|
||||
CPDoubleClickTargetBinding = @"doubleClickTarget";
|
||||
CPEditableBinding = @"editable";
|
||||
CPEnabledBinding = @"enabled";
|
||||
CPFontBinding = @"font";
|
||||
@@ -581,6 +870,7 @@ CPSelectedTagBinding = @"selectedTag";
|
||||
CPSelectedValueBinding = @"selectedValue";
|
||||
CPSelectedValuesBinding = @"selectedValues";
|
||||
CPSelectionIndexesBinding = @"selectionIndexes";
|
||||
CPTargetBinding = @"target";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPTitleBinding = @"title";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
@@ -589,7 +879,7 @@ CPValueURLBinding = @"valueURL";
|
||||
CPValuePathBinding = @"valuePath";
|
||||
CPDataBinding = @"data";
|
||||
|
||||
//Binding options constants
|
||||
// Binding options constants
|
||||
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
||||
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
|
||||
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
|
||||
|
||||
+15
-23
@@ -62,18 +62,18 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
return "level-indicator";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjectsAndKeys:[CPNull null], @"bezel-color",
|
||||
[CPNull null], @"color-empty",
|
||||
[CPNull null], @"color-normal",
|
||||
[CPNull null], @"color-warning",
|
||||
[CPNull null], @"color-critical",
|
||||
1.0, @"spacing"];
|
||||
return @{
|
||||
@"bezel-color": [CPNull null],
|
||||
@"color-empty": [CPNull null],
|
||||
@"color-normal": [CPNull null],
|
||||
@"color-warning": [CPNull null],
|
||||
@"color-critical": [CPNull null],
|
||||
@"spacing": 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
@@ -84,17 +84,11 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
_maxValue = 2;
|
||||
_warningValue = 2;
|
||||
_criticalValue = 2;
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
|
||||
@@ -128,7 +122,7 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
@@ -136,11 +130,11 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
// TODO Put into theme attributes.
|
||||
var bezelHeight = 18,
|
||||
segmentHeight = 17,
|
||||
bounds = _CGRectCreateCopy([self bounds]);
|
||||
bounds = CGRectCreateCopy([self bounds]);
|
||||
|
||||
if (aViewName == "bezel")
|
||||
{
|
||||
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||
bounds.origin.y = (CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||
bounds.size.height = bezelHeight;
|
||||
return bounds;
|
||||
}
|
||||
@@ -150,13 +144,13 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segment >= segmentCount)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var basicSegmentWidth = bounds.size.width / segmentCount,
|
||||
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.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - spacing;
|
||||
segmentFrame.size.height = segmentHeight;
|
||||
@@ -164,7 +158,7 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
return segmentFrame;
|
||||
}
|
||||
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -348,8 +342,6 @@ var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
|
||||
|
||||
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
+101
-29
@@ -25,6 +25,7 @@
|
||||
@import <Foundation/CPNotificationCenter.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPKeyValueBinding.j"
|
||||
@import "CPMenuItem.j"
|
||||
|
||||
@global CPApp
|
||||
@@ -67,6 +68,8 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
|
||||
CPEvent _lastCloseEvent;
|
||||
}
|
||||
|
||||
// Managing the Menu Bar
|
||||
@@ -76,7 +79,7 @@ var _CPMenuBarVisible = NO,
|
||||
if (self !== [CPMenu class])
|
||||
return;
|
||||
|
||||
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
|
||||
[[self class] setMenuBarAttributes:@{}];
|
||||
}
|
||||
|
||||
+ (BOOL)menuBarVisible
|
||||
@@ -147,6 +150,13 @@ var _CPMenuBarVisible = NO,
|
||||
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
|
||||
{
|
||||
@@ -171,8 +181,8 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
else if (!textColor && !titleColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextColor"];
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleColor"];
|
||||
}
|
||||
|
||||
if (!textShadowColor && titleShadowColor)
|
||||
@@ -183,18 +193,18 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
else if (!textShadowColor && !titleShadowColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextShadowColor"];
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleShadowColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextShadowColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleShadowColor"];
|
||||
}
|
||||
|
||||
if (!highlightColor)
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightColor"];
|
||||
|
||||
if (!highlightTextColor)
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
|
||||
if (!highlightTextShadowColor)
|
||||
[_CPMenuBarAttributes setObject:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
if (_CPMenuBarSharedWindow)
|
||||
{
|
||||
@@ -223,7 +233,7 @@ var _CPMenuBarVisible = NO,
|
||||
- (float)menuBarHeight
|
||||
{
|
||||
if (self === [CPApp mainMenu])
|
||||
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-height" forClass:_CPMenuView];
|
||||
return [CPMenu menuBarHeight];
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
@@ -268,7 +278,7 @@ var _CPMenuBarVisible = NO,
|
||||
@param aMenuItem the item to insert
|
||||
@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];
|
||||
}
|
||||
@@ -281,7 +291,7 @@ var _CPMenuBarVisible = NO,
|
||||
@param anIndex the index location in the menu for the new 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];
|
||||
|
||||
@@ -325,7 +335,7 @@ var _CPMenuBarVisible = NO,
|
||||
Removes the item at the specified index from the menu
|
||||
@param anIndex the index of the item to remove
|
||||
*/
|
||||
- (void)removeItemAtIndex:(unsigned)anIndex
|
||||
- (void)removeItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
[self removeObjectFromItemsAtIndex:anIndex];
|
||||
}
|
||||
@@ -345,7 +355,7 @@ var _CPMenuBarVisible = NO,
|
||||
while (count--)
|
||||
[_items[count] setMenu:nil];
|
||||
|
||||
_highlightedIndex = CPNotFound;
|
||||
[self _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
// Because we are changing _items directly, be sure to notify KVO
|
||||
[self willChangeValueForKey:@"items"];
|
||||
@@ -359,7 +369,12 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (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;
|
||||
|
||||
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
|
||||
@@ -367,7 +382,7 @@ var _CPMenuBarVisible = NO,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidChangeItemNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:[_items indexOfObjectIdenticalTo:aMenuItem] forKey:@"CPMenuItemIndex"]];
|
||||
userInfo:@{ @"CPMenuItemIndex": [_items indexOfObjectIdenticalTo:aMenuItem] }];
|
||||
}
|
||||
|
||||
// Finding Menu Items
|
||||
@@ -600,15 +615,17 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
/*!
|
||||
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 target responsds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
|
||||
If the item has no target, an action binding is checked. If the target does not implement
|
||||
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
|
||||
{
|
||||
if (![self autoenablesItems])
|
||||
if (!_autoenablesItems)
|
||||
return;
|
||||
|
||||
var items = [self itemArray];
|
||||
|
||||
for (var i = 0; i < [items count]; i++)
|
||||
{
|
||||
var item = [items objectAtIndex:i];
|
||||
@@ -616,14 +633,50 @@ var _CPMenuBarVisible = NO,
|
||||
if ([item hasSubmenu])
|
||||
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]])
|
||||
[item setEnabled:NO];
|
||||
if (binder)
|
||||
{
|
||||
[binder setValueFor:CPEnabledBinding];
|
||||
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:)])
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
shouldBeEnabled = [validator validateMenuItem:item];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
shouldBeEnabled = [validator validateUserInterfaceItem:item];
|
||||
|
||||
[item setEnabled:shouldBeEnabled];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
@@ -668,7 +721,13 @@ var _CPMenuBarVisible = NO,
|
||||
// highlightedItem is always enabled. Do there exist edge cases: disabling on closing a menu,
|
||||
// etc.? Requires further investigation and tests.
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -796,6 +855,9 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (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];
|
||||
|
||||
if (!aFont)
|
||||
@@ -899,6 +961,10 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
- (void)_menuDidClose
|
||||
{
|
||||
// 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];
|
||||
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
@@ -918,7 +984,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
[CPApp sendEvent:[CPEvent
|
||||
otherEventWithType:CPAppKitDefined
|
||||
location:_CGPointMakeZero()
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
@@ -995,7 +1061,7 @@ var _CPMenuBarVisible = NO,
|
||||
Sends the action of the menu item at the specified index.
|
||||
@param anIndex the index of the item
|
||||
*/
|
||||
- (void)performActionForItemAtIndex:(unsigned)anIndex
|
||||
- (void)performActionForItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
var item = _items[anIndex];
|
||||
|
||||
@@ -1098,12 +1164,13 @@ var _CPMenuBarVisible = NO,
|
||||
return;
|
||||
|
||||
[aMenuItem setMenu:self];
|
||||
[self _highlightItemAtIndex:CPNotFound];
|
||||
[_items insertObject:aMenuItem atIndex:anIndex];
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidAddItemNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
|
||||
userInfo:@{ @"CPMenuItemIndex": anIndex }];
|
||||
}
|
||||
|
||||
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
|
||||
@@ -1112,12 +1179,13 @@ var _CPMenuBarVisible = NO,
|
||||
return;
|
||||
|
||||
[[_items objectAtIndex:anIndex] setMenu:nil];
|
||||
[self _highlightItemAtIndex:CPNotFound];
|
||||
[_items removeObjectAtIndex:anIndex];
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidRemoveItemNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
|
||||
userInfo:@{ @"CPMenuItemIndex": anIndex }];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1125,7 +1193,8 @@ var _CPMenuBarVisible = NO,
|
||||
var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
CPMenuNameKey = @"CPMenuNameKey",
|
||||
CPMenuItemsKey = @"CPMenuItemsKey",
|
||||
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey";
|
||||
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey",
|
||||
CPMenuAutoEnablesItemsKey = @"CPMenuAutoEnablesItemsKey";
|
||||
|
||||
@implementation CPMenu (CPCoding)
|
||||
|
||||
@@ -1147,7 +1216,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
|
||||
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
|
||||
|
||||
_autoenablesItems = YES;
|
||||
_autoenablesItems = ![aCoder containsValueForKey:CPMenuAutoEnablesItemsKey] || [aCoder decodeBoolForKey:CPMenuAutoEnablesItemsKey];
|
||||
|
||||
[self setMinimumWidth:0];
|
||||
}
|
||||
@@ -1170,6 +1239,9 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
|
||||
if (!_showsStateColumn)
|
||||
[aCoder encodeBool:_showsStateColumn forKey:CPMenuShowsStateColumnKey];
|
||||
|
||||
if (!_autoenablesItems)
|
||||
[aCoder encodeBool:_autoenablesItems forKey:CPMenuAutoEnablesItemsKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
_constrainsToUsableScreen = NO;
|
||||
|
||||
[self setLevel:CPMainMenuWindowLevel];
|
||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||
|
||||
@@ -141,6 +143,7 @@
|
||||
_textColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextColor:) withObject:_textColor];
|
||||
}
|
||||
|
||||
- (void)setTitleColor:(CPColor)aColor
|
||||
@@ -161,6 +164,7 @@
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextShadowColor:) withObject:_textShadowColor];
|
||||
}
|
||||
|
||||
- (void)setTitleShadowColor:(CPColor)aColor
|
||||
@@ -179,6 +183,8 @@
|
||||
return;
|
||||
|
||||
_highlightColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightColor:) withObject:_highlightColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextColor:(CPColor)aColor
|
||||
@@ -188,7 +194,7 @@
|
||||
|
||||
_highlightTextColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextColor:) withObject:_highlightTextColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||
@@ -198,7 +204,7 @@
|
||||
|
||||
_highlightTextShadowColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextShadowColor:) withObject:_highlightTextShadowColor];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
@@ -411,7 +417,7 @@
|
||||
|
||||
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
||||
|
||||
if (!_CGSizeEqualToSize(size, aRect.size))
|
||||
if (!CGSizeEqualToSize(size, aRect.size))
|
||||
[self tile];
|
||||
}
|
||||
|
||||
|
||||
@@ -39,12 +39,13 @@ _CPMenuManagerScrollingStateUp = -1;
|
||||
_CPMenuManagerScrollingStateDown = 1;
|
||||
_CPMenuManagerScrollingStateNone = 0;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 0.5,
|
||||
var STICKY_TIME_INTERVAL = 0.4,
|
||||
SharedMenuManager = nil;
|
||||
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
CPEvent _openEvent;
|
||||
BOOL _mouseWasDragged;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
@@ -103,6 +104,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];
|
||||
_openEvent = anEvent;
|
||||
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||
|
||||
_constraintRect = aRect;
|
||||
@@ -132,6 +134,11 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
[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
|
||||
{
|
||||
var type = [anEvent type],
|
||||
@@ -141,8 +148,6 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
if (type === CPAppKitDefined)
|
||||
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)
|
||||
{
|
||||
var menu = trackingMenu,
|
||||
@@ -158,6 +163,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
if ([menu numberOfItems])
|
||||
[self interpretKeyEvent:anEvent forMenu:menu];
|
||||
|
||||
[self _trackAgain];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +171,10 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
||||
|
||||
if (!globalLocation)
|
||||
{
|
||||
[self _trackAgain];
|
||||
return;
|
||||
}
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||
@@ -176,15 +185,35 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
if (_keyBuffer)
|
||||
{
|
||||
if (([anEvent timestamp] - _startTime) > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] / 2))
|
||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:YES];
|
||||
/*
|
||||
Click outside the menu structure?
|
||||
|
||||
if (type === CPPeriodic)
|
||||
return;
|
||||
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
|
||||
if (_lastGlobalLocation && CGRectContainsPoint([activeMenuContainer globalFrame], _lastGlobalLocation)
|
||||
&& !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation))
|
||||
@@ -221,9 +250,9 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
|
||||
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||
{
|
||||
[mouseOverMenuView mouseExited:anEvent];
|
||||
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||
// FIXME: Possibly multiple of these?
|
||||
[_lastMouseOverMenuView mouseEntered:anEvent];
|
||||
[mouseOverMenuView mouseEntered:anEvent];
|
||||
|
||||
_lastMouseOverMenuView = mouseOverMenuView;
|
||||
}
|
||||
@@ -252,7 +281,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
_lastMouseOverMenuView = nil;
|
||||
}
|
||||
|
||||
if (activeItemIndex != CPNotFound)
|
||||
if (activeItemIndex !== CPNotFound)
|
||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||
|
||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
|
||||
@@ -378,6 +407,15 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
[menu cancelTracking];
|
||||
}
|
||||
|
||||
- (void)cancelActiveMenu
|
||||
{
|
||||
if (CPApp._activeMenu)
|
||||
{
|
||||
[self completeTracking];
|
||||
_menuContainerStack = [];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)completeTracking
|
||||
{
|
||||
var trackingMenu = [self trackingMenu];
|
||||
@@ -428,8 +466,8 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
{
|
||||
var menuContainer = _menuContainerStack[index],
|
||||
menuContainerFrame = [menuContainer globalFrame],
|
||||
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
|
||||
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
|
||||
menuContainerMinX = CGRectGetMinX(menuContainerFrame),
|
||||
menuContainerMaxX = CGRectGetMaxX(menuContainerFrame);
|
||||
|
||||
// If within the x bounds of this menu container, return it.
|
||||
if (x < menuContainerMaxX && x >= menuContainerMinX)
|
||||
@@ -525,6 +563,9 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
}
|
||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
|
||||
{
|
||||
if (([anEvent timestamp] - _startTime) > STICKY_TIME_INTERVAL)
|
||||
_keyBuffer = nil;
|
||||
|
||||
if (!_keyBuffer)
|
||||
{
|
||||
_startTime = [anEvent timestamp];
|
||||
@@ -536,12 +577,12 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
else
|
||||
_keyBuffer += character;
|
||||
|
||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:NO];
|
||||
_lastGlobalLocation = Nil;
|
||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu];
|
||||
_lastGlobalLocation = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu clearBuffer:(BOOL)shouldClear
|
||||
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu
|
||||
{
|
||||
var iter = [[menu itemArray] objectEnumerator],
|
||||
obj;
|
||||
@@ -558,13 +599,7 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldClear)
|
||||
{
|
||||
[CPEvent stopPeriodicEvents];
|
||||
_keyBuffer = Nil;
|
||||
}
|
||||
else
|
||||
_startTime = [CPEvent currentTimestamp];
|
||||
_startTime = [CPEvent currentTimestamp];
|
||||
}
|
||||
|
||||
- (void)scrollToBeginningOfDocument:(CPMenu)menu
|
||||
@@ -701,6 +736,8 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveDown:menu];
|
||||
}
|
||||
else if (menu == [CPApp mainMenu])
|
||||
[menu _highlightItemAtIndex:0];
|
||||
}
|
||||
|
||||
- (void)moveUp:(CPMenu)menu
|
||||
@@ -709,10 +746,12 @@ var STICKY_TIME_INTERVAL = 0.5,
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
if (index != CPNotFound)
|
||||
if (index != CPNotFound || menu == [CPApp mainMenu])
|
||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[menu _highlightItemAtIndex:index];
|
||||
|
||||
var item = [menu highlightedItem];
|
||||
|
||||
@@ -34,8 +34,6 @@ _CPMenuWindowMenuBarBackgroundStyle = 0;
|
||||
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@@ -74,7 +72,8 @@ var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
+ (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;
|
||||
|
||||
_CPMenuWindowPool.push(aMenuWindow);
|
||||
@@ -82,13 +81,15 @@ var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
_constraintRect = _CGRectMakeZero();
|
||||
_unconstrainedFrame = _CGRectMakeZero();
|
||||
_constraintRect = CGRectMakeZero();
|
||||
_unconstrainedFrame = CGRectMakeZero();
|
||||
|
||||
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_constrainsToUsableScreen = NO;
|
||||
|
||||
[self setLevel:CPPopUpMenuWindowLevel];
|
||||
[self setHasShadow:YES];
|
||||
[self setShadowStyle:CPMenuWindowShadowStyle];
|
||||
@@ -209,26 +210,26 @@ var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
- (CGRect)unconstrainedFrame
|
||||
{
|
||||
return _CGRectMakeCopy(_unconstrainedFrame);
|
||||
return CGRectMakeCopy(_unconstrainedFrame);
|
||||
}
|
||||
|
||||
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
|
||||
// the constrained frame into the unconstrained frame.
|
||||
- (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
|
||||
{
|
||||
[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
|
||||
{
|
||||
// FIXME: There are integral window issues with platform windows.
|
||||
// FIXME: This gets called far too often.
|
||||
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
|
||||
_unconstrainedFrame = CGRectMakeCopy(aFrame);
|
||||
|
||||
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect),
|
||||
marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"],
|
||||
@@ -434,41 +435,36 @@ var STICKY_TIME_INTERVAL = 500;
|
||||
return "menu-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null], CGInsetMake(5.0, 1.0, 1.0, 5.0), 16.0,
|
||||
[CPNull null], [CPNull null], [CPNull null], 30.0, 10.0, 10.0, 10.0,
|
||||
[CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], 28.0, [CPNull null], 1.0,
|
||||
[CPNull null], [CPNull null], [CPNull null]]
|
||||
forKeys:[ @"menu-window-more-above-image",
|
||||
@"menu-window-more-below-image",
|
||||
@"menu-window-pop-up-background-style-color",
|
||||
@"menu-window-menu-bar-background-style-color",
|
||||
@"menu-window-margin-inset",
|
||||
@"menu-window-scroll-indicator-height",
|
||||
|
||||
@"menu-bar-window-background-color",
|
||||
@"menu-bar-window-background-selected-color",
|
||||
@"menu-bar-window-font",
|
||||
@"menu-bar-window-height",
|
||||
@"menu-bar-window-margin",
|
||||
@"menu-bar-window-left-margin",
|
||||
@"menu-bar-window-right-margin",
|
||||
|
||||
@"menu-bar-text-color",
|
||||
@"menu-bar-title-color",
|
||||
@"menu-bar-text-shadow-color",
|
||||
@"menu-bar-title-shadow-color",
|
||||
@"menu-bar-highlight-color",
|
||||
@"menu-bar-highlight-text-color",
|
||||
@"menu-bar-highlight-text-shadow-color",
|
||||
@"menu-bar-height",
|
||||
@"menu-bar-icon-image",
|
||||
@"menu-bar-icon-image-alpha-value",
|
||||
|
||||
@"menu-general-icon-new",
|
||||
@"menu-general-icon-save",
|
||||
@"menu-general-icon-open"]];
|
||||
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-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],
|
||||
};
|
||||
}
|
||||
|
||||
- (unsigned)numberOfUnhiddenItems
|
||||
|
||||
@@ -33,25 +33,25 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionaryWithObjectsAndKeys:
|
||||
"\u238B", CPEscapeFunctionKey,
|
||||
"\u21E5", CPTabCharacter,
|
||||
"\u21E4", CPBackTabCharacter,
|
||||
"\u2423", CPSpaceFunctionKey,
|
||||
"\u23CE", CPCarriageReturnCharacter,
|
||||
"\u232B", CPBackspaceCharacter,
|
||||
"\u232B", CPDeleteFunctionKey,
|
||||
"\u2326", CPDeleteCharacter,
|
||||
"\u21F1", CPHomeFunctionKey,
|
||||
"\u21F2", CPEndFunctionKey,
|
||||
"\u21DE", CPPageUpFunctionKey,
|
||||
"\u21DF", CPPageDownFunctionKey,
|
||||
"\u2191", CPUpArrowFunctionKey,
|
||||
"\u2193", CPDownArrowFunctionKey,
|
||||
"\u2190", CPLeftArrowFunctionKey,
|
||||
"\u2192", CPRightArrowFunctionKey,
|
||||
"\u2327", CPClearDisplayFunctionKey
|
||||
];
|
||||
var CPMenuItemStringRepresentationDictionary = @{
|
||||
CPEscapeFunctionKey: "\u238B",
|
||||
CPTabCharacter: "\u21E5",
|
||||
CPBackTabCharacter: "\u21E4",
|
||||
CPSpaceFunctionKey: "\u2423",
|
||||
CPCarriageReturnCharacter: "\u23CE",
|
||||
CPBackspaceCharacter: "\u232B",
|
||||
CPDeleteFunctionKey: "\u232B",
|
||||
CPDeleteCharacter: "\u2326",
|
||||
CPHomeFunctionKey: "\u21F1",
|
||||
CPEndFunctionKey: "\u21F2",
|
||||
CPPageUpFunctionKey: "\u21DE",
|
||||
CPPageDownFunctionKey: "\u21DF",
|
||||
CPUpArrowFunctionKey: "\u2191",
|
||||
CPDownArrowFunctionKey: "\u2193",
|
||||
CPLeftArrowFunctionKey: "\u2190",
|
||||
CPRightArrowFunctionKey: "\u2192",
|
||||
CPClearDisplayFunctionKey: "\u2327",
|
||||
};
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -105,6 +105,16 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionaryWithObjec
|
||||
_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
|
||||
{
|
||||
return [self initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||
@@ -156,6 +166,9 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionaryWithObjec
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
|
||||
if (!isEnabled && [self isHighlighted])
|
||||
[_menu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
_isEnabled = !!isEnabled;
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
@@ -28,16 +28,20 @@
|
||||
|
||||
@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);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
|
||||
BOOL _isDirty;
|
||||
BOOL _shouldHighlight;
|
||||
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
CPView _submenuIndicatorView;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -45,15 +49,13 @@
|
||||
return "menu-item-bar-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], 8.0, 3.0, 4.0]
|
||||
forKeys:[ @"submenu-indicator-color",
|
||||
@"menu-item-selection-color",
|
||||
@"menu-item-text-shadow-color",
|
||||
@"horizontal-margin",
|
||||
@"submenu-indicator-margin",
|
||||
@"vertical-margin"]];
|
||||
return @{
|
||||
@"horizontal-margin": 9.0,
|
||||
@"submenu-indicator-margin": 3.0,
|
||||
@"vertical-margin": 4.0,
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
@@ -76,32 +78,71 @@
|
||||
|
||||
[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];
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
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
|
||||
{
|
||||
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
|
||||
@@ -109,53 +150,26 @@
|
||||
var x = [self valueForThemeAttribute:@"horizontal-margin"],
|
||||
height = 0.0;
|
||||
|
||||
[_imageAndTextView setText:[_menuItem title]];
|
||||
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
|
||||
[_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 setImage:[_menuItem image]];
|
||||
[_imageAndTextView sizeToFit];
|
||||
|
||||
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||
|
||||
imageAndTextViewFrame.origin.x = x;
|
||||
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
||||
|
||||
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 + [self valueForThemeAttribute:@"submenu-indicator-margin"];
|
||||
|
||||
x = CGRectGetMaxX(submenuViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||
}
|
||||
else
|
||||
[_submenuIndicatorView setHidden:YES];
|
||||
|
||||
height += 2.0 * [self valueForThemeAttribute:@"vertical-margin"];
|
||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame)) + 2.0 * [self valueForThemeAttribute:@"vertical-margin"];
|
||||
|
||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||
|
||||
if (hasSubmenuIndicator)
|
||||
{
|
||||
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
|
||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||
}
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:CGSizeMake(x + [self valueForThemeAttribute:@"horizontal-margin"], height)];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
@@ -164,17 +178,20 @@
|
||||
if (![_menuItem isEnabled])
|
||||
shouldHighlight = NO;
|
||||
|
||||
if (shouldHighlight)
|
||||
_shouldHighlight = shouldHighlight;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (_shouldHighlight)
|
||||
{
|
||||
if (![_menuItem _isMenuBarButton])
|
||||
[self setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-background-selected-color" forClass:_CPMenuView]];
|
||||
[self setBackgroundColor:[self highlightColor]];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self valueForThemeAttribute:@"menu-item-text-shadow-color"]];
|
||||
|
||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
|
||||
[_imageAndTextView setTextColor:[self highlightTextColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self highlightTextShadowColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,60 +200,7 @@
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
|
||||
[_submenuIndicatorView setColor:[self textColor]];
|
||||
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class _CPMenuItemStandardView
|
||||
|
||||
|
||||
@implementation _CPMenuItemSeparatorView : CPView
|
||||
{
|
||||
@@ -52,7 +54,7 @@
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
|
||||
CGContextSetStrokeColor(context, [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-item-separator-color" forClass:_CPMenuItemStandardView]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
|
||||
CGSize _minSize @accessors(readonly, property=minSize);
|
||||
BOOL _isDirty;
|
||||
BOOL _highlighted;
|
||||
|
||||
CPImageView _stateView;
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
@@ -46,24 +45,27 @@
|
||||
return "menu-item-standard-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], 3.0, 17.0, 14.0, 17.0, 4.0, 30.0]
|
||||
forKeys:[ @"submenu-indicator-color",
|
||||
@"menu-item-selection-color",
|
||||
@"menu-item-text-shadow-color",
|
||||
@"menu-item-default-off-state-image",
|
||||
@"menu-item-default-off-state-highlighted-image",
|
||||
@"menu-item-default-on-state-image",
|
||||
@"menu-item-default-on-state-highlighted-image",
|
||||
@"menu-item-default-mixed-state-image",
|
||||
@"menu-item-default-mixed-state-highlighted-image",
|
||||
@"left-margin",
|
||||
@"right-margin",
|
||||
@"state-column-width",
|
||||
@"indentation-width",
|
||||
@"vertical-margin",
|
||||
@"right-columns-margin"]];
|
||||
return @{
|
||||
@"submenu-indicator-color": [CPNull null],
|
||||
@"menu-item-selection-color": [CPNull null],
|
||||
@"menu-item-text-shadow-color": [CPNull null],
|
||||
@"menu-item-text-color": [CPNull null],
|
||||
@"menu-item-default-off-state-image": [CPNull null],
|
||||
@"menu-item-default-off-state-highlighted-image": [CPNull null],
|
||||
@"menu-item-default-on-state-image": [CPNull null],
|
||||
@"menu-item-default-on-state-highlighted-image": [CPNull null],
|
||||
@"menu-item-default-mixed-state-image": [CPNull null],
|
||||
@"menu-item-default-mixed-state-highlighted-image": [CPNull null],
|
||||
@"menu-item-separator-color": [CPNull null],
|
||||
@"left-margin": 3.0,
|
||||
@"right-margin": 17.0,
|
||||
@"state-column-width": 14.0,
|
||||
@"indentation-width": 17.0,
|
||||
@"vertical-margin": 4.0,
|
||||
@"right-columns-margin": 30.0,
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
@@ -121,7 +123,10 @@
|
||||
if (![_menuItem isEnabled])
|
||||
return [CPColor lightGrayColor];
|
||||
|
||||
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
|
||||
@@ -129,7 +134,10 @@
|
||||
if (![_menuItem isEnabled])
|
||||
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
|
||||
@@ -263,29 +271,24 @@
|
||||
if (![_menuItem isEnabled])
|
||||
return;
|
||||
|
||||
_highlighted = shouldHighlight;
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
|
||||
if (shouldHighlight)
|
||||
{
|
||||
[self setBackgroundColor:[self valueForThemeAttribute:@"menu-item-selection-color"]];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self valueForThemeAttribute:@"menu-item-text-shadow-color"]];
|
||||
[_keyEquivalentView setTextShadowColor:[self valueForThemeAttribute:@"menu-item-text-shadow-color"]];
|
||||
[_submenuIndicatorView setColor:[self textColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
if ([[_menuItem menu] showsStateColumn])
|
||||
@@ -333,6 +336,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isHighlighted
|
||||
{
|
||||
return _highlighted;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
||||
|
||||
@@ -28,19 +28,13 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
// var LEFT_MARGIN = 3.0,
|
||||
// RIGHT_MARGIN = 16.0,
|
||||
// STATE_COLUMN_WIDTH = 14.0,
|
||||
// INDENTATION_WIDTH = 17.0,
|
||||
// VERTICAL_MARGIN = 4.0;
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@implementation _CPMenuItemView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem;
|
||||
CPView _view;
|
||||
CPView _view @accessors(property=view, readonly);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
@@ -59,10 +53,9 @@
|
||||
return "menu-item-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[]
|
||||
forKeys:[]];
|
||||
return @{};
|
||||
}
|
||||
|
||||
// Not used in the Appkit
|
||||
@@ -119,7 +112,6 @@
|
||||
_view = menuItemView;
|
||||
}
|
||||
}
|
||||
|
||||
else if ([_menuItem menu] == [CPApp mainMenu])
|
||||
{
|
||||
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
||||
@@ -227,6 +219,36 @@
|
||||
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
|
||||
|
||||
@implementation _CPMenuItemArrowView : CPView
|
||||
@@ -253,8 +275,6 @@
|
||||
CGContextMoveToPoint(context, 1.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 5.0, 8.0);
|
||||
CGContextAddLineToPoint(context, 1.0, 4.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, _color);
|
||||
|
||||
+33
-16
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPCountedSet.j>
|
||||
@import <Foundation/_CPCollectionKVCOperators.j>
|
||||
|
||||
@import "CPController.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@@ -50,7 +51,7 @@
|
||||
CPCountedSet _observedKeys;
|
||||
}
|
||||
|
||||
+ (id)initialize
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [CPObjectController class])
|
||||
return;
|
||||
@@ -105,11 +106,13 @@
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
[self setContent:aContent];
|
||||
[self setEditable:YES];
|
||||
[self setObjectClass:[CPMutableDictionary class]];
|
||||
|
||||
_observedKeys = [[CPCountedSet alloc] init];
|
||||
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||
|
||||
[self setContent:aContent];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -517,8 +520,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (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];
|
||||
|
||||
proxy._options = options;
|
||||
@@ -541,8 +548,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (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],
|
||||
index = [_observationProxies indexOfObject:proxy];
|
||||
|
||||
@@ -561,13 +572,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++)
|
||||
{
|
||||
var proxy = [_observationProxies objectAtIndex:i],
|
||||
keyPath = [proxy keyPath],
|
||||
operator = keyPath.indexOf(".") === 0;
|
||||
operator = keyPath.charAt(0) === ".";
|
||||
|
||||
if (operator)
|
||||
[self willChangeValueForKey:keyPath];
|
||||
@@ -581,7 +592,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
[super insertObject:anObject atIndex:anIndex];
|
||||
}
|
||||
|
||||
- (void)removeObjectAtIndex:(unsigned)anIndex
|
||||
- (void)removeObjectAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
var currentObject = [self objectAtIndex:anIndex];
|
||||
|
||||
@@ -589,7 +600,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
var proxy = [_observationProxies objectAtIndex:i],
|
||||
keyPath = [proxy keyPath],
|
||||
operator = keyPath.indexOf(".") === 0;
|
||||
operator = keyPath.charAt(0) === ".";
|
||||
|
||||
if (operator)
|
||||
[self willChangeValueForKey:keyPath];
|
||||
@@ -603,7 +614,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
[super removeObjectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
||||
- (CPArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
||||
{
|
||||
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
|
||||
}
|
||||
@@ -618,7 +629,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
[self removeObjectAtIndex:[self count]];
|
||||
}
|
||||
|
||||
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
|
||||
- (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(id)anObject
|
||||
{
|
||||
var currentObject = [self objectAtIndex:anIndex];
|
||||
|
||||
@@ -626,7 +637,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
var proxy = [_observationProxies objectAtIndex:i],
|
||||
keyPath = [proxy keyPath],
|
||||
operator = keyPath.indexOf(".") === 0;
|
||||
operator = keyPath.charAt(0) === ".";
|
||||
|
||||
if (operator)
|
||||
[self willChangeValueForKey:keyPath];
|
||||
@@ -658,7 +669,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_cachedValues = [CPDictionary dictionary];
|
||||
_cachedValues = @{};
|
||||
_observationProxies = [CPArray array];
|
||||
_controller = aController;
|
||||
_observedObjectsByKeyPath = {};
|
||||
@@ -700,12 +711,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath],
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
|
||||
[_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
|
||||
|
||||
+146
-67
@@ -35,22 +35,24 @@ CPOutlineViewItemWillExpandNotification = @"CPOutlineViewItemWillExpandN
|
||||
CPOutlineViewSelectionDidChangeNotification = @"CPOutlineViewSelectionDidChangeNotification";
|
||||
CPOutlineViewSelectionIsChangingNotification = @"CPOutlineViewSelectionIsChangingNotification";
|
||||
|
||||
var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ = 1 << 1,
|
||||
CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_ = 1 << 2,
|
||||
var CPOutlineViewDataSource_outlineView_objectValue_forTableColumn_byItem_ = 1 << 1,
|
||||
CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ = 1 << 2,
|
||||
CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_ = 1 << 3,
|
||||
|
||||
CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_ = 1 << 3,
|
||||
CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_ = 1 << 4,
|
||||
CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_ = 1 << 5,
|
||||
CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_ = 1 << 6,
|
||||
CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_ = 1 << 4,
|
||||
CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_ = 1 << 5,
|
||||
CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_ = 1 << 6,
|
||||
CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_ = 1 << 7,
|
||||
|
||||
CPOutlineViewDataSource_outlineView_itemForPersistentObject_ = 1 << 7,
|
||||
CPOutlineViewDataSource_outlineView_persistentObjectForItem_ = 1 << 8,
|
||||
CPOutlineViewDataSource_outlineView_itemForPersistentObject_ = 1 << 8,
|
||||
CPOutlineViewDataSource_outlineView_persistentObjectForItem_ = 1 << 9,
|
||||
|
||||
CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_ = 1 << 9,
|
||||
CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_ = 1 << 10,
|
||||
|
||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
|
||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 11;
|
||||
|
||||
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
|
||||
CPOutlineViewDelegate_outlineView_viewForTableColumn_item_ = 1 << 26,
|
||||
CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2,
|
||||
CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3,
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4,
|
||||
@@ -230,12 +232,12 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
if (![aDataSource respondsToSelector:@selector(outlineView:numberOfChildrenOfItem:)])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:numberOfChildrenOfItem:'"];
|
||||
|
||||
if (![aDataSource respondsToSelector:@selector(outlineView:objectValueForTableColumn:byItem:)])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:objectValueForTableColumn:byItem:'"];
|
||||
|
||||
_outlineViewDataSource = aDataSource;
|
||||
_implementedOutlineViewDataSourceMethods = 0;
|
||||
|
||||
if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:objectValueForTableColumn:byItem:)])
|
||||
_implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_objectValue_forTableColumn_byItem_;
|
||||
|
||||
if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:setObjectValue:forTableColumn:byItem:)])
|
||||
_implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_;
|
||||
|
||||
@@ -350,6 +352,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
*/
|
||||
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
|
||||
{
|
||||
if ([self _delegateRespondsToShouldExpandItem])
|
||||
if ([_outlineViewDelegate outlineView:self shouldExpandItem:anItem] == NO)
|
||||
return;
|
||||
|
||||
var itemInfo = null;
|
||||
|
||||
if (!anItem)
|
||||
@@ -425,6 +431,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
if (!anItem)
|
||||
return;
|
||||
|
||||
if ([self _delegateRespondsToShouldCollapseItem])
|
||||
if ([_outlineViewDelegate outlineView:self shouldCollapseItem:anItem] == NO)
|
||||
return;
|
||||
|
||||
var itemInfo = _itemInfosForItems[[anItem UID]];
|
||||
|
||||
if (!itemInfo)
|
||||
@@ -708,27 +718,36 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
{
|
||||
var theItem = [self itemAtRow:aRow];
|
||||
if (![self isExpandable:theItem] || ![self _shouldShowOutlineDisclosureControlForItem:theItem])
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var dataViewFrame = [self _frameOfOutlineDataViewAtRow:aRow],
|
||||
disclosureWidth = _CGRectGetWidth([_disclosureControlPrototype frame]),
|
||||
frame = _CGRectMake(_CGRectGetMinX(dataViewFrame) - disclosureWidth, _CGRectGetMinY(dataViewFrame), disclosureWidth, _CGRectGetHeight(dataViewFrame));
|
||||
disclosureWidth = CGRectGetWidth([_disclosureControlPrototype frame]),
|
||||
frame = CGRectMake(CGRectGetMinX(dataViewFrame) - disclosureWidth, CGRectGetMinY(dataViewFrame), disclosureWidth, CGRectGetHeight(dataViewFrame));
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Select or deselect rows, this is overridden because we need to change the color or the outline control.
|
||||
Select or deselect rows, this is overridden because we need to change the color of the outline control.
|
||||
*/
|
||||
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
|
||||
- (void)_setSelectedRowIndexes:(CPIndexSet)rows
|
||||
{
|
||||
[super _performSelection:select forRow:rowIndex context:context];
|
||||
if (_disclosureControlsForRows.length)
|
||||
{
|
||||
var indexes = [_selectedRowIndexes copy];
|
||||
[indexes removeIndexesInRange:CPMakeRange(_disclosureControlsForRows.length, _itemsForRows.length - _disclosureControlsForRows.length)];
|
||||
[[_disclosureControlsForRows objectsAtIndexes:indexes] makeObjectsPerformSelector:@selector(unsetThemeState:) withObject:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
var control = _disclosureControlsForRows[rowIndex],
|
||||
selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[super _setSelectedRowIndexes:rows];
|
||||
|
||||
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||
if (_disclosureControlsForRows.length)
|
||||
{
|
||||
var indexes = [_selectedRowIndexes copy];
|
||||
[indexes removeIndexesInRange:CPMakeRange(_disclosureControlsForRows.length, _itemsForRows.length - _disclosureControlsForRows.length)];
|
||||
[[_disclosureControlsForRows objectsAtIndexes:indexes] makeObjectsPerformSelector:@selector(setThemeState:) withObject:CPThemeStateSelected];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -870,6 +889,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
var delegateMethods = [
|
||||
CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_viewForTableColumn_item_ , @selector(outlineView:viewForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
|
||||
@@ -962,6 +982,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
name:CPOutlineViewItemDidCollapseNotification
|
||||
object:self];
|
||||
|
||||
[self _updateIsViewBased];
|
||||
|
||||
if ([self _delegateRespondsToDataViewForTableColumn])
|
||||
CPLog.warn("outlineView:dataViewForTableColumn:item: is deprecated. You should use -outlineView:viewForTableColumn:item: where you can request the view with -makeViewWithIdentifier:owner:");
|
||||
}
|
||||
|
||||
- (BOOL)_sendDelegateDeleteKeyPressed
|
||||
@@ -1054,12 +1078,12 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
@ignore
|
||||
We need to offset the dataview and add the disclosure triangle.
|
||||
*/
|
||||
- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CGPoint)theDragViewOffset
|
||||
- (CPView)_dragViewForColumn:(CPInteger)theColumnIndex event:(CPEvent)theDragEvent offset:(CGPoint)theDragViewOffset
|
||||
{
|
||||
var dragView = [[_CPColumnDragView alloc] initWithLineColor:[self gridColor]],
|
||||
tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex],
|
||||
defaultRowHeight = [self valueForThemeAttribute:@"default-row-height"],
|
||||
bounds = _CGRectMake(0.0, 0.0, [tableColumn width], _CGRectGetHeight([self exposedRect]) + defaultRowHeight),
|
||||
bounds = CGRectMake(0.0, 0.0, [tableColumn width], CGRectGetHeight([self exposedRect]) + defaultRowHeight),
|
||||
columnRect = [self rectOfColumn:theColumnIndex],
|
||||
headerView = [tableColumn headerView],
|
||||
row = [_exposedRows firstIndex];
|
||||
@@ -1073,7 +1097,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
dataViewFrame.origin.x = 0.0;
|
||||
|
||||
// Offset by table header height - scroll position
|
||||
dataViewFrame.origin.y = ( _CGRectGetMinY(dataViewFrame) - _CGRectGetMinY([self exposedRect]) ) + defaultRowHeight;
|
||||
dataViewFrame.origin.y = (CGRectGetMinY(dataViewFrame) - CGRectGetMinY([self exposedRect])) + defaultRowHeight;
|
||||
[dataView setFrame:dataViewFrame];
|
||||
|
||||
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
|
||||
@@ -1097,7 +1121,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
// Add the column header view
|
||||
var headerFrame = [headerView frame];
|
||||
headerFrame.origin = _CGPointMakeZero();
|
||||
headerFrame.origin = CGPointMakeZero();
|
||||
|
||||
var columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame];
|
||||
[columnHeaderView setStringValue:[headerView stringValue]];
|
||||
@@ -1187,7 +1211,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CGPoint)theOffset
|
||||
- (id)_parentItemForUpperRow:(CPInteger)theUpperRowIndex andLowerRow:(CPInteger)theLowerRowIndex atMouseOffset:(CGPoint)theOffset
|
||||
{
|
||||
if (_shouldRetargetItem)
|
||||
return _retargetedItem;
|
||||
@@ -1217,7 +1241,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CGRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CGPoint)theOffset
|
||||
- (CGRect)_rectForDropHighlightViewBetweenUpperRow:(CPInteger)theUpperRowIndex andLowerRow:(CPInteger)theLowerRowIndex offset:(CGPoint)theOffset
|
||||
{
|
||||
// Call super and the update x to reflect the current indentation level
|
||||
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
|
||||
@@ -1303,7 +1327,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
var disclosureControlFrame = [self frameOfOutlineDisclosureControlAtRow:row];
|
||||
|
||||
if (_CGRectIsEmpty(disclosureControlFrame))
|
||||
if (CGRectIsEmpty(disclosureControlFrame))
|
||||
continue;
|
||||
|
||||
var control = [self _dequeueDisclosureControl];
|
||||
@@ -1360,7 +1384,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
- (void)_toggleFromDisclosureControl:(CPControl)aControl
|
||||
{
|
||||
var controlFrame = [aControl frame],
|
||||
item = [self itemAtRow:[self rowAtPoint:_CGPointMake(_CGRectGetMinX(controlFrame), _CGRectGetMidY(controlFrame))]];
|
||||
item = [self itemAtRow:[self rowAtPoint:CGPointMake(CGRectGetMinX(controlFrame), CGRectGetMidY(controlFrame))]];
|
||||
|
||||
if ([self isItemExpanded:item])
|
||||
[self collapseItem:item];
|
||||
@@ -1441,7 +1465,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1452,7 +1476,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemDidExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1463,7 +1487,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillCollapseNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1474,7 +1498,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemDidCollapseNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
@@ -1533,6 +1557,59 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
|
||||
- (CPView)_sendDelegateViewForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
|
||||
{
|
||||
return [_outlineViewDelegate outlineView:self viewForTableColumn:aTableColumn item:[self itemAtRow:aRow]];
|
||||
}
|
||||
|
||||
- (CPView)_sendDelegateDataViewForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
|
||||
{
|
||||
return [_outlineViewDelegate outlineView:self dataViewForTableColumn:aTableColumn item:[self itemAtRow:aRow]];
|
||||
}
|
||||
|
||||
- (BOOL)_dataSourceRespondsToObjectValueForTableColumn
|
||||
{
|
||||
return _implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_objectValue_forTableColumn_byItem_;
|
||||
}
|
||||
|
||||
- (BOOL)_delegateRespondsToViewForTableColumn
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_viewForTableColumn_item_;
|
||||
}
|
||||
|
||||
- (BOOL)_delegateRespondsToDataViewForTableColumn
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
|
||||
}
|
||||
|
||||
- (BOOL)_delegateRespondsToShouldExpandItem
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldExpandItem_;
|
||||
}
|
||||
|
||||
- (BOOL)_delegateRespondsToShouldCollapseItem
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldCollapseItem_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Return YES if the delegate implements outlineView:selectionIndexesForProposedSelection
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToSelectionIndexesForProposedSelection
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Return YES if the delegate implements outlineView:shouldSelectItem:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToShouldSelectRow
|
||||
{
|
||||
return _implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
@@ -1730,7 +1807,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||
}
|
||||
|
||||
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CGPoint)theOffset
|
||||
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(CPInteger)theRow offset:(CGPoint)theOffset
|
||||
{
|
||||
if (_outlineView._shouldRetargetChildIndex)
|
||||
return _outlineView._retargedChildIndex;
|
||||
@@ -1754,7 +1831,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return childIndex;
|
||||
}
|
||||
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CGPoint)theOffset
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(CPInteger)theRow offset:(CGPoint)theOffset
|
||||
{
|
||||
if (theDropOperation === CPTableViewDropAbove)
|
||||
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
|
||||
@@ -1762,8 +1839,8 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView itemAtRow:theRow];
|
||||
}
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
|
||||
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id /*< CPDraggingInfo >*/)theInfo
|
||||
proposedRow:(CPInteger)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
|
||||
return CPDragOperationNone;
|
||||
@@ -1782,7 +1859,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id /*<CPDraggingInfo>*/)theInfo row:(CPInteger)theRow dropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
|
||||
return NO;
|
||||
@@ -1826,22 +1903,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
|
||||
{
|
||||
var dataView = nil;
|
||||
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
item:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (!dataView)
|
||||
dataView = [theTableColumn dataViewForRow:theRow];
|
||||
|
||||
return dataView;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow
|
||||
- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(CPInteger)theRow
|
||||
{
|
||||
return SHOULD_SELECT_ITEM(_outlineView, [_outlineView itemAtRow:theRow]);
|
||||
}
|
||||
@@ -1851,7 +1913,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return SELECTION_SHOULD_CHANGE(_outlineView);
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(CPInteger)aRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldEditTableColumn:aColumn item:[_outlineView itemAtRow:aRow]];
|
||||
@@ -1859,7 +1921,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
|
||||
- (float)tableView:(CPTableView)theTableView heightOfRow:(CPInteger)theRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
|
||||
@@ -1867,7 +1929,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [theTableView rowHeight];
|
||||
}
|
||||
|
||||
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
|
||||
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRowIndex
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_))
|
||||
{
|
||||
@@ -1876,7 +1938,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)aRow
|
||||
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(CPInteger)aRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]];
|
||||
@@ -1884,7 +1946,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aTableColumn row:(int)aRow
|
||||
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_menuForTableColumn_item_))
|
||||
{
|
||||
@@ -1897,6 +1959,22 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView menu] || [[_outlineView class] defaultMenu];
|
||||
}
|
||||
|
||||
- (CPIndexSet)tableView:(CPTableView)aTableView selectionIndexesForProposedSelection:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView selectionIndexesForProposedSelection:anIndexSet];
|
||||
|
||||
return anIndexSet;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldSelectTableColumn:(CPTableColumn)aTableColumn
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectTableColumn:aTableColumn];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDisclosureButton : CPButton
|
||||
@@ -1914,7 +1992,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setState:(CPState)aState
|
||||
- (void)setState:(CPInteger)aState
|
||||
{
|
||||
[super setState:aState];
|
||||
|
||||
@@ -1929,14 +2007,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
width = CGRectGetWidth(bounds),
|
||||
height = CGRectGetHeight(bounds);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
if (_angle)
|
||||
{
|
||||
var centre = _CGPointMake(FLOOR(width / 2.0), FLOOR(height / 2.0));
|
||||
var centre = CGPointMake(FLOOR(width / 2.0), FLOOR(height / 2.0));
|
||||
CGContextTranslateCTM(context, centre.x, centre.y);
|
||||
CGContextRotateCTM(context, _angle);
|
||||
CGContextTranslateCTM(context, -centre.x, -centre.y);
|
||||
@@ -1948,9 +2026,8 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
CGContextAddLineToPoint(context, 0.0, 0.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context,
|
||||
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
|
||||
[self hasThemeState:CPThemeStateHighlighted]));
|
||||
@@ -1958,8 +2035,8 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
|
||||
if (_angle === 0.0)
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
|
||||
@@ -2001,6 +2078,8 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
|
||||
|
||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||
[super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
|
||||
|
||||
[self _updateIsViewBased];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ CPDocModalWindowMask = 1 << 6;
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+18
-11
@@ -79,7 +79,7 @@ var CPPasteboards = nil,
|
||||
|
||||
[self setVersion:1.0];
|
||||
|
||||
CPPasteboards = [CPDictionary dictionary];
|
||||
CPPasteboards = @{};
|
||||
|
||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
||||
supportsNativePasteboard = YES;
|
||||
@@ -121,8 +121,8 @@ var CPPasteboards = nil,
|
||||
// _name = aName;
|
||||
_types = [];
|
||||
|
||||
_owners = [CPDictionary dictionary];
|
||||
_provided = [CPDictionary dictionary];
|
||||
_owners = @{};
|
||||
_provided = @{};
|
||||
|
||||
_changeCount = 0;
|
||||
|
||||
@@ -188,13 +188,15 @@ var CPPasteboards = nil,
|
||||
{
|
||||
[_types setArray:types];
|
||||
|
||||
_owners = [CPDictionary dictionary];
|
||||
_provided = [CPDictionary dictionary];
|
||||
_owners = @{};
|
||||
_provided = @{};
|
||||
|
||||
var count = _types.length;
|
||||
|
||||
while (count--)
|
||||
[_owners setObject:anOwner forKey:_types[count]];
|
||||
if (anOwner)
|
||||
{
|
||||
var count = _types.length;
|
||||
while (count--)
|
||||
[_owners setObject:anOwner forKey:_types[count]];
|
||||
}
|
||||
|
||||
if (_nativePasteboard && shouldUpdate)
|
||||
{
|
||||
@@ -205,6 +207,7 @@ var CPPasteboards = nil,
|
||||
_nativePasteboard.declareTypes_(nativeTypes);
|
||||
_changeCount = _nativePasteboard.changeCount();
|
||||
}
|
||||
|
||||
return ++_changeCount;
|
||||
}
|
||||
|
||||
@@ -243,19 +246,23 @@ var CPPasteboards = nil,
|
||||
*/
|
||||
- (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];
|
||||
}
|
||||
|
||||
// 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.
|
||||
@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
|
||||
*/
|
||||
- (CPString)availableTypeFromArray:(CPArray)anArray
|
||||
{
|
||||
return [[self types] firstObjectCommonWithArray:anArray];
|
||||
return [anArray firstObjectCommonWithArray:[self types]];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+13
-8
@@ -279,7 +279,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
Selects the item at the specified index
|
||||
@param anIndex the index of the item to select
|
||||
*/
|
||||
- (void)setObjectValue:(int)anIndex
|
||||
- (void)setObjectValue:(id)anIndex
|
||||
{
|
||||
var indexOfSelectedItem = [self objectValue];
|
||||
|
||||
@@ -344,7 +344,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
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
|
||||
*/
|
||||
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
|
||||
- (CPMenuItem)itemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
return [[self menu] itemAtIndex:anIndex];
|
||||
}
|
||||
@@ -353,7 +353,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
Returns the title of the item at the specified index or \c nil if no item exists.
|
||||
@param anIndex the index of the item
|
||||
*/
|
||||
- (CPString)itemTitleAtIndex:(unsigned)anIndex
|
||||
- (CPString)itemTitleAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
return [[[self menu] itemAtIndex:anIndex] title];
|
||||
}
|
||||
@@ -667,10 +667,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
if (![self isEnabled] || ![self numberOfItems])
|
||||
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];
|
||||
|
||||
var menu = [self menu],
|
||||
bounds = [self bounds],
|
||||
var bounds = [self bounds],
|
||||
minimumWidth = CGRectGetWidth(bounds);
|
||||
|
||||
// FIXME: setFont: should set the font on the menu.
|
||||
@@ -679,7 +684,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
if ([self pullsDown])
|
||||
{
|
||||
var positionedItem = nil,
|
||||
location = CGPointMake(0.0, CGRectGetMaxY(bounds));
|
||||
location = CGPointMake(0.0, CGRectGetMaxY(bounds) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -833,7 +838,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
[self _setContentValuesIfNeeded:contentArray];
|
||||
}
|
||||
|
||||
- (void)valueForBinding:(CPString)aBinding
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [self _content];
|
||||
}
|
||||
@@ -905,7 +910,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
- (void)setValue:(CPArray)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[super _setContent:aValue];
|
||||
}
|
||||
|
||||
+16
-1
@@ -63,7 +63,7 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(property=animates);
|
||||
BOOL _animates @accessors(getter=animates);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
@@ -153,6 +153,20 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
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];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the behavior of the CPPopover. It can be:
|
||||
|
||||
@@ -224,6 +238,7 @@ Set the behavior of the CPPopover. It can be:
|
||||
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self styleMaskForBehavior]];
|
||||
}
|
||||
|
||||
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
||||
[_popoverWindow setAppearance:_appearance];
|
||||
[_popoverWindow setAnimates:_animates];
|
||||
[_popoverWindow setDelegate:self];
|
||||
|
||||
@@ -30,19 +30,19 @@
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorBarStyle = 0;
|
||||
CPProgressIndicatorBarStyle = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorSpinningStyle = 1;
|
||||
CPProgressIndicatorSpinningStyle = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorHUDBarStyle = 2;
|
||||
CPProgressIndicatorHUDBarStyle = 2;
|
||||
|
||||
var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
var CPProgressIndicatorSpinningStyleColors = [];
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -61,7 +61,7 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
|
||||
CPControlSize _controlSize;
|
||||
|
||||
BOOL _isIndeterminate;
|
||||
BOOL _indeterminate;
|
||||
CPProgressIndicatorStyle _style;
|
||||
|
||||
BOOL _isAnimating;
|
||||
@@ -77,8 +77,23 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], 25, [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
||||
forKeys:[@"indeterminate-bar-color", @"bar-color", @"default-height", @"bezel-color", @"spinning-mini-gif", @"spinning-small-gif", @"spinning-regular-gif"]];
|
||||
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],
|
||||
};
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPValueBinding || aBinding === @"isIndeterminate")
|
||||
return [_CPProgressIndicatorBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -259,12 +274,12 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
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
|
||||
*/
|
||||
- (void)setIndeterminate:(BOOL)isIndeterminate
|
||||
- (void)setIndeterminate:(BOOL)indeterminate
|
||||
{
|
||||
if (_isIndeterminate == isIndeterminate)
|
||||
if (_indeterminate == indeterminate)
|
||||
return;
|
||||
|
||||
_isIndeterminate = isIndeterminate;
|
||||
_indeterminate = indeterminate;
|
||||
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
@@ -274,7 +289,7 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
*/
|
||||
- (BOOL)isIndeterminate
|
||||
{
|
||||
return _isIndeterminate;
|
||||
return _indeterminate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -356,7 +371,7 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
@@ -369,10 +384,10 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
if (barWidth > 0.0 && barWidth < 4.0)
|
||||
barWidth = 4.0;
|
||||
|
||||
if (_isIndeterminate)
|
||||
if (_indeterminate)
|
||||
barWidth = width;
|
||||
|
||||
return _CGRectMake(0, 0, barWidth, [self valueForThemeAttribute:@"default-height"]);
|
||||
return CGRectMake(0, 0, barWidth, [self valueForThemeAttribute:@"default-height"]);
|
||||
}
|
||||
|
||||
return nil;
|
||||
@@ -381,17 +396,18 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
/* @ignore */
|
||||
- (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
|
||||
{
|
||||
CPProgressIndicatorSpinningStyleColors = [];
|
||||
|
||||
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [self valueForThemeAttribute:@"spinning-mini-gif"];
|
||||
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [self valueForThemeAttribute:@"spinning-small-gif"];
|
||||
CPProgressIndicatorSpinningStyleColors[CPRegularControlSize] = [self valueForThemeAttribute:@"spinning-regular-gif"];
|
||||
|
||||
if (YES)//_isBezeled)
|
||||
{
|
||||
if (_style == CPProgressIndicatorSpinningStyle)
|
||||
@@ -411,11 +427,10 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
if (_isIndeterminate)
|
||||
if (_indeterminate)
|
||||
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"indeterminate-bar-color"]];
|
||||
else
|
||||
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"bar-color"]];
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -435,7 +450,7 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
||||
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
||||
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
|
||||
_indeterminate = [aCoder decodeObjectForKey:@"_indeterminate"];
|
||||
_style = [aCoder decodeIntForKey:@"_style"];
|
||||
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
||||
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
||||
@@ -449,8 +464,8 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// Don't encode the background colour. It can be recreated based on the flags and if encoded causes hardcoded
|
||||
// image paths in the cib while just wasting space.
|
||||
// Don't encode the background colour. It can be recreated based on the flags
|
||||
// and if encoded causes hardcoded image paths in the cib while just wasting space.
|
||||
var backgroundColor = [self backgroundColor];
|
||||
[self setBackgroundColor:nil];
|
||||
[super encodeWithCoder:aCoder];
|
||||
@@ -460,7 +475,7 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
||||
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
|
||||
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
|
||||
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
|
||||
[aCoder encodeObject:_indeterminate forKey:@"_indeterminate"];
|
||||
[aCoder encodeInt:_style forKey:@"_style"];
|
||||
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
||||
@@ -468,3 +483,52 @@ var CPProgressIndicatorSpinningStyleColors = nil;
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+211
-14
@@ -152,7 +152,7 @@ CPRadioImageOffset = 4.0;
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[super sendAction:anAction to:anObject];
|
||||
|
||||
@@ -204,29 +204,122 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
|
||||
@implementation CPRadioGroup : CPObject
|
||||
{
|
||||
CPSet _radios;
|
||||
CPArray _radios;
|
||||
CPRadio _selectedRadio;
|
||||
|
||||
BOOL _enabled @accessors(getter=enabled);
|
||||
BOOL _hidden @accessors(getter=hidden);
|
||||
|
||||
id _target @accessors(property=target);
|
||||
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
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_radios = [CPSet set];
|
||||
_radios = [];
|
||||
_selectedRadio = nil;
|
||||
_enabled = YES;
|
||||
_hidden = NO;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
[_radios addObject:aRadio];
|
||||
if ([_radios indexOfObject:aRadio] === CPNotFound)
|
||||
[_radios addObject:aRadio];
|
||||
|
||||
if ([aRadio state] === CPOnState)
|
||||
[self _setSelectedRadio:aRadio];
|
||||
@@ -240,23 +333,30 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
[_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
|
||||
{
|
||||
if (_selectedRadio === aRadio)
|
||||
return;
|
||||
|
||||
[_selectedRadio setState:CPOffState];
|
||||
|
||||
_selectedRadio = aRadio;
|
||||
}
|
||||
|
||||
- (CPRadio)selectedRadio
|
||||
{
|
||||
return _selectedRadio;
|
||||
}
|
||||
|
||||
- (CPArray)radios
|
||||
{
|
||||
return [_radios allObjects];
|
||||
[_CPRadioGroupSelectionBinder reverseSetValueForObject:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -286,3 +386,100 @@ var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
|
||||
}
|
||||
|
||||
@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];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var binderForObject = {};
|
||||
|
||||
@implementation _CPRadioGroupSelectionBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors;
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
binderForObject[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = binderForObject[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[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
|
||||
|
||||
@@ -356,7 +356,7 @@ CPDeleteForwardKeyCode = 46;
|
||||
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
||||
CPResponderMenuKey = @"CPResponderMenuKey";
|
||||
|
||||
@implementation CPResponder (CPCoding)
|
||||
@implementation CPResponder (CPCoding) <CPCoding>
|
||||
|
||||
/*!
|
||||
Initializes the responder with data from a coder.
|
||||
|
||||
@@ -82,15 +82,15 @@
|
||||
}
|
||||
|
||||
/*! @cond */
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding == CPValueBinding)
|
||||
if (aBinding == CPValueBinding)
|
||||
return [CPPredicateEditorValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return @"predicate";
|
||||
@@ -360,7 +360,11 @@
|
||||
rootItems = [treeChild children];
|
||||
}
|
||||
|
||||
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
|
||||
var row = @{
|
||||
@"criteria": criteria,
|
||||
@"displayValues": values,
|
||||
@"rowType": rowType,
|
||||
};
|
||||
|
||||
return row;
|
||||
}
|
||||
@@ -480,7 +484,7 @@
|
||||
|
||||
#pragma mark RuleEditor delegate methods
|
||||
|
||||
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
|
||||
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(CPRuleEditorRowType)type
|
||||
{
|
||||
if (rowItem == nil)
|
||||
{
|
||||
@@ -490,7 +494,7 @@
|
||||
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)
|
||||
{
|
||||
@@ -501,7 +505,7 @@
|
||||
return [[rowItem children] objectAtIndex:childIndex];
|
||||
}
|
||||
|
||||
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
|
||||
- (id)_queryValueForItem:(id)rowItem inRow:(CPInteger)rowIndex
|
||||
{
|
||||
return [rowItem displayValue];
|
||||
}
|
||||
@@ -512,7 +516,7 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
|
||||
@implementation CPPredicateEditor (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(id)aCoder
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
@@ -527,7 +531,7 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)aCoder
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
|
||||
|
||||
@@ -702,12 +702,12 @@ CPTransformableAttributeType = 1800;
|
||||
return textField;
|
||||
}
|
||||
|
||||
- (void)_setOptions:(unsigned int)options
|
||||
- (void)_setOptions:(unsigned)options
|
||||
{
|
||||
_predicateOptions = options;
|
||||
}
|
||||
|
||||
- (void)_setModifier:(unsigned int)modifier
|
||||
- (void)_setModifier:(unsigned)modifier
|
||||
{
|
||||
_predicateModifier = modifier;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPRuleEditor_Constants.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@@ -121,10 +122,18 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
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]]
|
||||
forKeys:[@"alternating-row-colors", @"selected-color", @"slice-top-border-color", @"slice-bottom-border-color", @"slice-last-bottom-border-color", @"font", @"add-image", @"remove-image"]];
|
||||
return @{
|
||||
@"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": [CPNull null],
|
||||
@"add-image": [CPNull null],
|
||||
@"remove-image": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
@@ -452,7 +461,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
@param row The index of a row in the receiver.
|
||||
@return The currently chosen items for row @a row.
|
||||
*/
|
||||
- (id)criteriaForRow:(int)row
|
||||
- (id)criteriaForRow:(CPInteger)row
|
||||
{
|
||||
var rowcache = [self _rowCacheForIndex:row];
|
||||
if (rowcache)
|
||||
@@ -471,7 +480,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
@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:
|
||||
*/
|
||||
- (CPMutableArray)displayValuesForRow:(int)row
|
||||
- (CPMutableArray)displayValuesForRow:(CPInteger)row
|
||||
{
|
||||
var rowcache = [self _rowCacheForIndex:row];
|
||||
if (rowcache)
|
||||
@@ -494,7 +503,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
@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.
|
||||
*/
|
||||
- (int)parentRowForRow:(int)rowIndex
|
||||
- (int)parentRowForRow:(CPInteger)rowIndex
|
||||
{
|
||||
if (rowIndex < 0 || rowIndex >= [self numberOfRows])
|
||||
[CPException raise:CPRangeException reason:_cmd + @" row " + rowIndex + " is out of range"];
|
||||
@@ -535,7 +544,7 @@ TODO: implement
|
||||
@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.
|
||||
*/
|
||||
- (CPRuleEditorRowType)rowTypeForRow:(int)rowIndex
|
||||
- (CPRuleEditorRowType)rowTypeForRow:(CPInteger)rowIndex
|
||||
{
|
||||
if (rowIndex < 0 || rowIndex > [self numberOfRows])
|
||||
[CPException raise:CPRangeException reason:_cmd + @"row " + rowIndex + " is out of range"];
|
||||
@@ -556,7 +565,7 @@ TODO: implement
|
||||
@return The immediate subrows of the row at @a rowIndex.
|
||||
@discussion Rows are numbered starting at @c 0.
|
||||
*/
|
||||
- (CPIndexSet)subrowIndexesForRow:(int)rowIndex
|
||||
- (CPIndexSet)subrowIndexesForRow:(CPInteger)rowIndex
|
||||
{
|
||||
var object;
|
||||
|
||||
@@ -682,7 +691,7 @@ TODO: implement
|
||||
@note Currently, @a shouldAnimate has no effect, rows are always animated when calling this method.
|
||||
@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.
|
||||
@@ -790,7 +799,7 @@ TODO: implement
|
||||
*/
|
||||
- (CPPredicate)predicateForRow:(CPInteger)aRow
|
||||
{
|
||||
var predicateParts = [CPDictionary dictionary],
|
||||
var predicateParts = @{},
|
||||
items = [self criteriaForRow:aRow],
|
||||
count = [items count],
|
||||
predicate,
|
||||
@@ -1304,7 +1313,7 @@ TODO: implement
|
||||
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;
|
||||
childrenCount = [self _queryNumberOfChildrenOfItem:parentItem withRowType:type],
|
||||
@@ -1366,7 +1375,7 @@ TODO: implement
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPMutableArray)_getItemsAndValuesToAddForRow:(int)rowIndex ofType:(CPRuleEditorRowType)type
|
||||
- (CPMutableArray)_getItemsAndValuesToAddForRow:(CPInteger)rowIndex ofType:(CPRuleEditorRowType)type
|
||||
{
|
||||
//var cachedItemsAndValues = _itemsAndValuesToAddForRowType[type];
|
||||
//if (cachedItemsAndValues)
|
||||
@@ -1386,7 +1395,10 @@ TODO: implement
|
||||
{
|
||||
var item = [items objectAtIndex:i],
|
||||
value = [values objectAtIndex:i],
|
||||
itemAndValue = [CPDictionary dictionaryWithObjects:[item, value] forKeys:["item", "value"]];
|
||||
itemAndValue = @{
|
||||
"item": item,
|
||||
"value": value,
|
||||
};
|
||||
|
||||
[itemsAndValues addObject:itemAndValue];
|
||||
}
|
||||
@@ -1406,7 +1418,7 @@ TODO: implement
|
||||
[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],
|
||||
itemsandvalues = [self _getItemsAndValuesToAddForRow:insertIndex ofType:rowtype],
|
||||
@@ -1508,7 +1520,7 @@ TODO: implement
|
||||
}
|
||||
}
|
||||
|
||||
- (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],
|
||||
displayValues = [self displayValuesForRow:aRow],
|
||||
@@ -1672,7 +1684,7 @@ TODO: implement
|
||||
[super bind:aBinding toObject:observableController withKeyPath:aKeyPath options:options];
|
||||
}
|
||||
|
||||
- (void)unbind:(id)object
|
||||
- (void)unbind:(CPString)object
|
||||
{
|
||||
_rowClass = [_CPRuleEditorRowObject class];
|
||||
[super unbind:object];
|
||||
@@ -1770,7 +1782,7 @@ TODO: implement
|
||||
|
||||
if (animate)
|
||||
{
|
||||
var animation = [CPDictionary dictionary];
|
||||
var animation = @{};
|
||||
[animation setObject:aslice forKey:CPViewAnimationTargetKey];
|
||||
[animation setObject:startRect forKey:CPViewAnimationStartFrameKey];
|
||||
[animation setObject:targetRect forKey:CPViewAnimationEndFrameKey];
|
||||
@@ -1865,17 +1877,17 @@ TODO: implement
|
||||
|
||||
- (CPString)_toolTipForAddCompoundRowButton
|
||||
{
|
||||
return @"Add Compound row";
|
||||
return [_standardLocalizer localizedStringForString:@"Add compound row"];
|
||||
}
|
||||
|
||||
- (CPString)_toolTipForAddSimpleRowButton
|
||||
{
|
||||
return @"Add row";
|
||||
return [_standardLocalizer localizedStringForString:@"Add row"];
|
||||
}
|
||||
|
||||
- (CPString)_toolTipForDeleteRowButton
|
||||
{
|
||||
return @"Delete row";
|
||||
return [_standardLocalizer localizedStringForString:@"Delete row"];
|
||||
}
|
||||
|
||||
- (void)_updateSliceIndentations
|
||||
@@ -1993,7 +2005,7 @@ TODO: implement
|
||||
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];
|
||||
}
|
||||
@@ -2014,12 +2026,12 @@ TODO: implement
|
||||
_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];
|
||||
}
|
||||
|
||||
- (BOOL)_queryCanSelectItem:(id)item displayValue:(id)value inRow:(int)row
|
||||
- (BOOL)_queryCanSelectItem:(id)item displayValue:(id)value inRow:(CPInteger)row
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
@@ -2116,7 +2128,7 @@ TODO: implement
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPDragOperation)draggingEntered:(id < CPDraggingInfo >)sender
|
||||
- (CPDragOperation)draggingEntered:(id /*< CPDraggingInfo >*/)sender
|
||||
{
|
||||
if ([sender draggingSource] === self)
|
||||
{
|
||||
@@ -2146,7 +2158,7 @@ TODO: implement
|
||||
_subviewIndexOfDropLine = CPNotFound;
|
||||
}
|
||||
|
||||
- (CPDragOperation)draggingUpdated:(id <CPDraggingInfo>)sender
|
||||
- (CPDragOperation)draggingUpdated:(id /*<CPDraggingInfo>*/)sender
|
||||
{
|
||||
var point = [self convertPoint:[sender draggingLocation] fromView:nil],
|
||||
y = point.y + _sliceHeight / 2,
|
||||
@@ -2183,12 +2195,12 @@ TODO: implement
|
||||
return CPDragOperationMove;
|
||||
}
|
||||
|
||||
- (BOOL)prepareForDragOperation:(id < CPDraggingInfo >)sender
|
||||
- (BOOL)prepareForDragOperation:(id /*< CPDraggingInfo >*/)sender
|
||||
{
|
||||
return (_subviewIndexOfDropLine !== CPNotFound);
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id < CPDraggingInfo >)info
|
||||
- (BOOL)performDragOperation:(id /*< CPDraggingInfo >*/)info
|
||||
{
|
||||
var aboveInsertIndexCount = 0,
|
||||
object,
|
||||
@@ -2250,7 +2262,7 @@ TODO: implement
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_setWindow:(id)window
|
||||
- (void)_setWindow:(CPWindow)window
|
||||
{
|
||||
[super _setWindow:window];
|
||||
}
|
||||
@@ -2267,7 +2279,7 @@ TODO: implement
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
@@ -2313,7 +2325,7 @@ TODO: implement
|
||||
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,
|
||||
indexofCriterion,
|
||||
@@ -2414,7 +2426,7 @@ var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)coder
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
@@ -2469,7 +2481,7 @@ var CriteriaKey = @"criteria",
|
||||
return "<" + [self className] + ">\nsubrows = " + [subrows description] + "\ncriteria = " + [criteria description] + "\ndisplayValues = " + [displayValues description];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(id)coder
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
self = [super init];
|
||||
if (self !== nil)
|
||||
@@ -2483,7 +2495,7 @@ var CriteriaKey = @"criteria",
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)coder
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[coder encodeObject:subrows forKey:SubrowsKey];
|
||||
[coder encodeObject:criteria forKey:CriteriaKey];
|
||||
@@ -2522,7 +2534,7 @@ var CPBoundArrayKey = @"CPBoundArray";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(id)coder
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
if (self = [super init])
|
||||
boundArray = [coder decodeObjectForKey:CPBoundArrayKey];
|
||||
@@ -2530,7 +2542,7 @@ var CPBoundArrayKey = @"CPBoundArray";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)coder
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[coder encodeObject:boundArray forKey:CPBoundArrayKey];
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)
|
||||
|
||||
- (void)loadContent:(CPString)aContent
|
||||
{
|
||||
var dict = [CPDictionary dictionary],
|
||||
var dict = @{},
|
||||
lines = [aContent componentsSeparatedByString:"\n"],
|
||||
count = [lines count];
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ else if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CGPoint)point
|
||||
- (CPView)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CGRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
||||
return nil;
|
||||
@@ -100,12 +100,12 @@ else if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return ![superview isKindOfClass:[_CPRuleEditorViewSlice]] || [superview isEditable];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)theEvent
|
||||
- (void)trackMouse:(CPEvent)theEvent
|
||||
{
|
||||
if (![self sliceIsEditable])
|
||||
return NO;
|
||||
return;
|
||||
|
||||
return [super trackMouse:theEvent];
|
||||
[super trackMouse:theEvent];
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
if (select == _selected)
|
||||
return;
|
||||
|
||||
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
|
||||
var selector = select ? @selector(setThemeState:) : @selector(unsetThemeState:);
|
||||
[[self subviews] makeObjectsPerformSelector:selector withObject:CPThemeStateSelectedDataView];
|
||||
_selected = select;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
maxX = CGRectGetWidth(bounds),
|
||||
maxY = CGRectGetHeight(bounds);
|
||||
|
||||
// Draw background
|
||||
// Draw background
|
||||
if ([self _isSelected])
|
||||
_backgroundColor = [_ruleEditor _selectedRowColor];
|
||||
else
|
||||
@@ -78,20 +78,20 @@
|
||||
CGContextSetFillColor(context, _backgroundColor);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
// Draw Top Border
|
||||
// Draw Top Border
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, 0);
|
||||
CGContextAddLineToPoint(context, maxX, 0);
|
||||
CGContextClosePath(context);
|
||||
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
// Draw Bottom Border
|
||||
// Draw Bottom Border
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, maxY);
|
||||
CGContextAddLineToPoint(context, maxX, maxY);
|
||||
CGContextClosePath(context);
|
||||
|
||||
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
|
||||
|
||||
CGContextSetStrokeColor(context, bottomColor);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@@ -271,7 +271,11 @@ var CONTROL_HEIGHT = 16.,
|
||||
}
|
||||
}
|
||||
|
||||
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
|
||||
repObject = @{
|
||||
@"item": childItem,
|
||||
@"value": childValue,
|
||||
@"indexInCriteria": i
|
||||
};
|
||||
[menuItem setRepresentedObject:repObject];
|
||||
[menuItems addObject:menuItem];
|
||||
}
|
||||
@@ -518,7 +522,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CGPoint)point
|
||||
- (CPView)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CGRectContainsPoint([self frame], point))
|
||||
return nil;
|
||||
|
||||
+2
-2
@@ -43,9 +43,9 @@
|
||||
- (CGRect)visibleFrame
|
||||
{
|
||||
#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
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+81
-71
@@ -34,34 +34,44 @@
|
||||
|
||||
|
||||
/*! @ignore */
|
||||
var _isSystemUsingOverlayScrollers = function()
|
||||
var _isBrowserUsingOverlayScrollers = function()
|
||||
{
|
||||
#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%";
|
||||
inner.style.height = "200px";
|
||||
To determine if the browser is using overlay scrollbars,
|
||||
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.top = "0px";
|
||||
outer.style.left = "0px";
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "200px";
|
||||
outer.style.height = "150px";
|
||||
outer.style.overflow = "hidden";
|
||||
outer.appendChild (inner);
|
||||
outer.style.overflow = "scroll";
|
||||
|
||||
document.body.appendChild (outer);
|
||||
var w1 = inner.offsetWidth;
|
||||
outer.style.overflow = 'scroll';
|
||||
var w2 = inner.offsetWidth;
|
||||
if (w1 == w2)
|
||||
w2 = outer.clientWidth;
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
outer.appendChild(inner);
|
||||
|
||||
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
|
||||
return NO;
|
||||
#endif
|
||||
@@ -130,8 +140,8 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
|
||||
var globalValue = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPScrollersGlobalStyle"];
|
||||
|
||||
if (globalValue == nil || globalValue == -1)
|
||||
CPScrollerStyleGlobal = _isSystemUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
||||
if (globalValue === nil || globalValue === -1)
|
||||
CPScrollerStyleGlobal = _isBrowserUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
|
||||
else
|
||||
CPScrollerStyleGlobal = globalValue;
|
||||
}
|
||||
@@ -143,15 +153,15 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"bottom-corner-color": [CPColor whiteColor],
|
||||
@"border-color": [CPColor blackColor]
|
||||
}];
|
||||
return @{
|
||||
@"bottom-corner-color": [CPColor whiteColor],
|
||||
@"border-color": [CPColor blackColor]
|
||||
};
|
||||
}
|
||||
|
||||
+ (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],
|
||||
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if (hFlag)
|
||||
@@ -165,10 +175,10 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
|
||||
+ (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],
|
||||
var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
||||
widthInset = contentSize.width - bounds.size.width,
|
||||
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)
|
||||
@@ -186,10 +196,10 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
{
|
||||
case CPLineBorder:
|
||||
case CPBezelBorder:
|
||||
return _CGRectInset(bounds, 1.0, 1.0);
|
||||
return CGRectInset(bounds, 1.0, 1.0);
|
||||
|
||||
case CPGrooveBorder:
|
||||
bounds = _CGRectInset(bounds, 2.0, 2.0);
|
||||
bounds = CGRectInset(bounds, 2.0, 2.0);
|
||||
++bounds.origin.y;
|
||||
--bounds.size.height;
|
||||
return bounds;
|
||||
@@ -517,8 +527,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
{
|
||||
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 horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle])];
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1), [CPScroller scrollerWidthInStyle:_scrollerStyle])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle])];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -582,8 +592,8 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
{
|
||||
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 verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidthInStyle:_scrollerStyle], _CGRectGetHeight(bounds))];
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, [CPScroller scrollerWidthInStyle:_scrollerStyle], MAX(CGRectGetHeight(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidthInStyle:_scrollerStyle], CGRectGetHeight(bounds))];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -859,13 +869,13 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
- (CGRect)_cornerViewFrame
|
||||
{
|
||||
if (!_cornerView)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var bounds = [self _insetBounds],
|
||||
frame = [_cornerView frame];
|
||||
|
||||
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
||||
frame.origin.y = _CGRectGetMinY(bounds);
|
||||
frame.origin.x = CGRectGetMaxX(bounds) - CGRectGetWidth(frame);
|
||||
frame.origin.y = CGRectGetMinY(bounds);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -876,14 +886,14 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
var headerView = [self _headerView];
|
||||
|
||||
if (!headerView)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var frame = [self _insetBounds];
|
||||
|
||||
frame.size.height = _CGRectGetHeight([headerView frame]);
|
||||
frame.size.height = CGRectGetHeight([headerView frame]);
|
||||
|
||||
if (SHOULD_SHOW_CORNER_VIEW())
|
||||
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
||||
frame.size.width -= CGRectGetWidth([self _cornerViewFrame]);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -924,18 +934,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
break;
|
||||
|
||||
case CPScrollerDecrementPage:
|
||||
contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
contentBounds.origin.y -= CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
case CPScrollerIncrementPage:
|
||||
contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
contentBounds.origin.y += CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
// We want integral bounds!
|
||||
case CPScrollerKnobSlot:
|
||||
case CPScrollerKnob:
|
||||
default:
|
||||
contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
||||
contentBounds.origin.y = ROUND(value * (CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
@@ -961,18 +971,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
break;
|
||||
|
||||
case CPScrollerDecrementPage:
|
||||
contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
contentBounds.origin.x -= CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
break;
|
||||
|
||||
case CPScrollerIncrementPage:
|
||||
contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
contentBounds.origin.x += CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
break;
|
||||
|
||||
// We want integral bounds!
|
||||
case CPScrollerKnobSlot:
|
||||
case CPScrollerKnob:
|
||||
default:
|
||||
contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
|
||||
contentBounds.origin.x = ROUND(value * (CGRectGetWidth(documentFrame) - CGRectGetWidth(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
@@ -1096,7 +1106,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
}
|
||||
|
||||
[_contentView setFrame:[self _insetBounds]];
|
||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||
[_headerClipView setFrame:CGRectMakeZero()];
|
||||
|
||||
--_recursionCount;
|
||||
|
||||
@@ -1106,12 +1116,12 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
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)
|
||||
headerClipViewFrame = [self _headerClipViewFrame],
|
||||
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
||||
headerClipViewHeight = CGRectGetHeight(headerClipViewFrame);
|
||||
|
||||
contentFrame.origin.y += headerClipViewHeight;
|
||||
contentFrame.size.height -= headerClipViewHeight;
|
||||
|
||||
var difference = _CGSizeMake(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentFrame), _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentFrame)),
|
||||
var difference = CGSizeMake(CGRectGetWidth(documentFrame) - CGRectGetWidth(contentFrame), CGRectGetHeight(documentFrame) - CGRectGetHeight(contentFrame)),
|
||||
verticalScrollerWidth = [CPScroller scrollerWidthInStyle:[_verticalScroller style]],
|
||||
horizontalScrollerHeight = [CPScroller scrollerWidthInStyle:[_horizontalScroller style]],
|
||||
hasVerticalScroll = difference.height > 0.0,
|
||||
@@ -1162,18 +1172,18 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
if (shouldShowVerticalScroller)
|
||||
{
|
||||
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.
|
||||
if (_scrollerStyle === CPScrollerStyleOverlay && hasHorizontalScroll)
|
||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
||||
|
||||
var documentHeight = _CGRectGetHeight(documentFrame);
|
||||
var documentHeight = CGRectGetHeight(documentFrame);
|
||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||
[_verticalScroller setKnobProportion:documentHeight > 0 ? _CGRectGetHeight(contentFrame) / documentHeight : 1.0];
|
||||
[_verticalScroller setFrame:_CGRectMake(_CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
|
||||
[_verticalScroller setKnobProportion:documentHeight > 0 ? CGRectGetHeight(contentFrame) / documentHeight : 1.0];
|
||||
[_verticalScroller setFrame:CGRectMake(CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
|
||||
}
|
||||
else if (wasShowingVerticalScroller)
|
||||
{
|
||||
@@ -1183,16 +1193,16 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
|
||||
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.
|
||||
if (_scrollerStyle === CPScrollerStyleOverlay && hasVerticalScroll)
|
||||
horizontalScrollerWidth -= verticalScrollerWidth;
|
||||
|
||||
var documentWidth = _CGRectGetWidth(documentFrame);
|
||||
var documentWidth = CGRectGetWidth(documentFrame);
|
||||
|
||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||
[_horizontalScroller setKnobProportion:documentWidth > 0 ? _CGRectGetWidth(contentFrame) / documentWidth : 1.0];
|
||||
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
|
||||
[_horizontalScroller setKnobProportion:documentWidth > 0 ? CGRectGetWidth(contentFrame) / documentWidth : 1.0];
|
||||
[_horizontalScroller setFrame:CGRectMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
|
||||
}
|
||||
else if (wasShowingHorizontalScroller)
|
||||
{
|
||||
@@ -1272,7 +1282,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
{
|
||||
case CPLineBorder:
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
||||
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
|
||||
CGContextStrokeRect(context, CGRectInset(strokeRect, 0.5, 0.5));
|
||||
break;
|
||||
|
||||
case CPBezelBorder:
|
||||
@@ -1290,10 +1300,10 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
|
||||
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
var minX = _CGRectGetMinX(aRect),
|
||||
maxX = _CGRectGetMaxX(aRect),
|
||||
minY = _CGRectGetMinY(aRect),
|
||||
maxY = _CGRectGetMaxY(aRect),
|
||||
var minX = CGRectGetMinX(aRect),
|
||||
maxX = CGRectGetMaxX(aRect),
|
||||
minY = CGRectGetMinY(aRect),
|
||||
maxY = CGRectGetMaxY(aRect),
|
||||
y = minY + 0.5;
|
||||
|
||||
// Slightly darker line on top.
|
||||
@@ -1324,10 +1334,10 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
|
||||
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
var minX = _CGRectGetMinX(aRect),
|
||||
maxX = _CGRectGetMaxX(aRect),
|
||||
minY = _CGRectGetMinY(aRect),
|
||||
maxY = _CGRectGetMaxY(aRect);
|
||||
var minX = CGRectGetMinX(aRect),
|
||||
maxX = CGRectGetMaxX(aRect),
|
||||
minY = CGRectGetMinY(aRect),
|
||||
maxY = CGRectGetMaxY(aRect);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
|
||||
@@ -1357,11 +1367,11 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
CGContextBeginPath(context);
|
||||
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.height -= 1.0;
|
||||
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
|
||||
CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||
@@ -1395,29 +1405,29 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
- (void)scrollPageUp:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||
[self moveByOffset:CGSizeMake(0.0, -(CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||
}
|
||||
|
||||
- (void)scrollPageDown:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||
[self moveByOffset:CGSizeMake(0.0, CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||
}
|
||||
|
||||
- (void)scrollToBeginningOfDocument:(id)sender
|
||||
{
|
||||
[_contentView scrollToPoint:_CGPointMakeZero()];
|
||||
[_headerClipView scrollToPoint:_CGPointMakeZero()];
|
||||
[_contentView scrollToPoint:CGPointMakeZero()];
|
||||
[_headerClipView scrollToPoint:CGPointMakeZero()];
|
||||
}
|
||||
|
||||
- (void)scrollToEndOfDocument:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds],
|
||||
documentFrame = [[self documentView] frame],
|
||||
scrollPoint = _CGPointMake(0.0, _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
|
||||
scrollPoint = CGPointMake(0.0, CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds));
|
||||
|
||||
[_contentView scrollToPoint:scrollPoint];
|
||||
[_headerClipView scrollToPoint:_CGPointMakeZero()];
|
||||
[_headerClipView scrollToPoint:CGPointMakeZero()];
|
||||
}
|
||||
|
||||
- (void)moveLeft:(id)sender
|
||||
|
||||
+86
-73
@@ -57,6 +57,8 @@ var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScroll
|
||||
NAMES_FOR_PARTS = {},
|
||||
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[CPScrollerIncrementLine] = @"increment-line";
|
||||
NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
|
||||
@@ -106,21 +108,21 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
return "scroller";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"scroller-width": 7.0,
|
||||
@"knob-slot-color": [CPNull null],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPNull null],
|
||||
@"decrement-line-size":_CGSizeMakeZero(),
|
||||
@"increment-line-size":_CGSizeMakeZero(),
|
||||
@"track-inset":_CGInsetMakeZero(),
|
||||
@"knob-inset": _CGInsetMakeZero(),
|
||||
@"minimum-knob-length":21.0,
|
||||
@"track-border-overlay": 9.0
|
||||
}];
|
||||
return @{
|
||||
@"scroller-width": 7.0,
|
||||
@"knob-slot-color": [CPNull null],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPNull null],
|
||||
@"decrement-line-size": CGSizeMakeZero(),
|
||||
@"increment-line-size": CGSizeMakeZero(),
|
||||
@"track-inset": CGInsetMakeZero(),
|
||||
@"knob-inset": CGInsetMakeZero(),
|
||||
@"minimum-knob-length": 21.0,
|
||||
@"track-border-overlay": 9.0
|
||||
};
|
||||
}
|
||||
|
||||
+ (float)scrollerWidth
|
||||
@@ -133,11 +135,13 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
*/
|
||||
+ (float)scrollerWidthInStyle:(int)aStyle
|
||||
{
|
||||
var scroller = [[self alloc] init];
|
||||
if (!_CACHED_THEME_SCROLLER)
|
||||
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||
|
||||
if (aStyle == CPScrollerStyleLegacy)
|
||||
return [scroller valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||
return [scroller currentValueForThemeAttribute:@"scroller-width"];
|
||||
return [_CACHED_THEME_SCROLLER valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||
|
||||
return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"scroller-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -145,7 +149,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
*/
|
||||
+ (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"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -175,14 +182,20 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
_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 setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[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;
|
||||
@@ -309,7 +322,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
if (aPart == CPScrollerNoPart)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
return _partRects[aPart];
|
||||
}
|
||||
@@ -379,8 +392,8 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
||||
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
width = CGRectGetWidth(bounds),
|
||||
height = CGRectGetHeight(bounds);
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
@@ -394,21 +407,21 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
||||
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = _CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
|
||||
_partRects[CPScrollerKnob] = _CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
|
||||
_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[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
|
||||
_partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
|
||||
_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[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||
|
||||
if (height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
||||
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -423,21 +436,21 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
knobHeight = height - knobInset.top - knobInset.bottom,
|
||||
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = _CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
|
||||
_partRects[CPScrollerKnob] = _CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
|
||||
_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[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
|
||||
_partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
|
||||
_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[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||
|
||||
if (width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotSize);
|
||||
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = CGRectMake(0.0, 0.0, width, slotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,7 +518,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -519,7 +532,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -594,7 +607,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
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)
|
||||
[self setFloatValue:0.0];
|
||||
@@ -639,20 +652,20 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
if ([anEvent modifierFlags] & CPAlternateKeyMask)
|
||||
{
|
||||
if (_trackingPart == CPScrollerDecrementLine)
|
||||
if (_trackingPart === CPScrollerDecrementLine)
|
||||
_hitPart = CPScrollerDecrementPage;
|
||||
|
||||
else if (_trackingPart == CPScrollerIncrementLine)
|
||||
else if (_trackingPart === CPScrollerIncrementLine)
|
||||
_hitPart = CPScrollerIncrementPage;
|
||||
|
||||
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
else if (_trackingPart === CPScrollerDecrementPage || _trackingPart === CPScrollerIncrementPage)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
knobWidth = ![self isVertical] ? _CGRectGetWidth(knobRect) : _CGRectGetHeight(knobRect),
|
||||
knobWidth = ![self isVertical] ? CGRectGetWidth(knobRect) : CGRectGetHeight(knobRect),
|
||||
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;
|
||||
|
||||
@@ -673,11 +686,11 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
{
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
if (_trackingPart === CPScrollerDecrementPage || _trackingPart === CPScrollerIncrementPage)
|
||||
{
|
||||
var hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
|
||||
if (hitPart === CPScrollerDecrementPage || hitPart === CPScrollerIncrementPage)
|
||||
{
|
||||
_trackingPart = hitPart;
|
||||
_hitPart = hitPart;
|
||||
@@ -693,18 +706,13 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
}
|
||||
|
||||
- (void)_calculateIsVertical
|
||||
- (void)_setIsVertical:(BOOL)isVertical
|
||||
{
|
||||
// Recalculate isVertical.
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
_isVertical = isVertical;
|
||||
|
||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
||||
|
||||
if (_isVertical === 1)
|
||||
if (_isVertical)
|
||||
[self setThemeState:CPThemeStateVertical];
|
||||
else if (_isVertical === 0)
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateVertical];
|
||||
}
|
||||
|
||||
@@ -739,12 +747,14 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
switch (_hitPart)
|
||||
{
|
||||
case CPScrollerKnob: return [self trackKnob:anEvent];
|
||||
case CPScrollerKnob:
|
||||
return [self trackKnob:anEvent];
|
||||
|
||||
case CPScrollerDecrementLine:
|
||||
case CPScrollerIncrementLine:
|
||||
case CPScrollerDecrementPage:
|
||||
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
|
||||
case CPScrollerIncrementPage:
|
||||
return [self trackScrollButtons:anEvent];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,9 +802,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||
|
||||
@implementation CPScroller (CPCoding)
|
||||
|
||||
@@ -803,7 +814,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
|
||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
||||
|
||||
@@ -819,17 +829,19 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
|
||||
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
|
||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
|
||||
var paramAnimFadeOut = @{
|
||||
CPViewAnimationTargetKey: self,
|
||||
CPViewAnimationEffectKey: CPViewAnimationFadeOutEffect,
|
||||
};
|
||||
|
||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[self setAlphaValue:0.0];
|
||||
|
||||
[self _calculateIsVertical];
|
||||
|
||||
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
|
||||
|
||||
[self _setIsVertical:[aCoder decodeBoolForKey:CPScrollerIsVerticalKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -840,6 +852,7 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeInt:_isVertical forKey:CPScrollerIsVerticalKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
|
||||
}
|
||||
|
||||
+12
-13
@@ -69,13 +69,12 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:
|
||||
{
|
||||
return @{
|
||||
@"image-search": [CPNull null],
|
||||
@"image-find": [CPNull null],
|
||||
@"image-cancel": [CPNull null],
|
||||
@"image-cancel-pressed": [CPNull null]
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
@@ -230,22 +229,22 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
||||
{
|
||||
var leftOffset = 0,
|
||||
width = _CGRectGetWidth(rect),
|
||||
width = CGRectGetWidth(rect),
|
||||
bounds = [self bounds];
|
||||
|
||||
if (_searchButton)
|
||||
{
|
||||
var searchBounds = [self searchButtonRectForBounds:bounds];
|
||||
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
|
||||
leftOffset = CGRectGetMaxX(searchBounds) + 2;
|
||||
}
|
||||
|
||||
if (_cancelButton)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -257,7 +256,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
{
|
||||
var size = [[self valueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero();
|
||||
|
||||
return _CGRectMake(5, (_CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||
return CGRectMake(5, (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -269,7 +268,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
{
|
||||
var size = [[self valueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero();
|
||||
|
||||
return _CGRectMake(_CGRectGetWidth(rect) - size.width - 5, (_CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||
return CGRectMake(CGRectGetWidth(rect) - size.width - 5, (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||
}
|
||||
|
||||
// Managing Menu Templates
|
||||
@@ -459,7 +458,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[super sendAction:anAction to:anObject];
|
||||
|
||||
@@ -483,7 +482,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
// 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;
|
||||
else
|
||||
return nil;
|
||||
@@ -499,7 +498,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
var location = [anEvent locationInWindow],
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||
if (CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||
{
|
||||
if (_searchMenuTemplate == nil)
|
||||
{
|
||||
@@ -511,7 +510,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
else
|
||||
[self _showMenu];
|
||||
}
|
||||
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||
else if (CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||
[_cancelButton mouseDown:anEvent];
|
||||
else
|
||||
[super mouseDown:anEvent];
|
||||
|
||||
+126
-5
@@ -56,10 +56,35 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return "segmented-control";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPImageScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
|
||||
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
|
||||
return @{
|
||||
@"alignment": CPCenterTextAlignment,
|
||||
@"vertical-alignment": CPCenterVerticalTextAlignment,
|
||||
@"image-position": CPImageLeft,
|
||||
@"image-scaling": CPImageScaleNone,
|
||||
@"bezel-inset": CGInsetMakeZero(),
|
||||
@"content-inset": CGInsetMakeZero(),
|
||||
@"left-segment-bezel-color": [CPNull null],
|
||||
@"right-segment-bezel-color": [CPNull null],
|
||||
@"center-segment-bezel-color": [CPNull null],
|
||||
@"divider-bezel-color": [CPNull null],
|
||||
@"divider-thickness": 1.0,
|
||||
@"default-height": 24.0,
|
||||
};
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if ([self _isSelectionBinding:aBinding])
|
||||
return [_CPSegmentedControlBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (BOOL)_isSelectionBinding:(CPString)aBinding
|
||||
{
|
||||
return (aBinding === CPSelectedIndexBinding || aBinding === CPSelectedLabelBinding || aBinding === CPSelectedTagBinding);
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aRect
|
||||
@@ -79,6 +104,19 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
{
|
||||
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
|
||||
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
|
||||
else
|
||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPSegmentedControlBinder reverseSetValueForObject:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the tag of the selected segment.
|
||||
*/
|
||||
@@ -177,6 +215,21 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)_selectSegmentWithLabel:(CPString)aLabel
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].label == aLabel)
|
||||
{
|
||||
[self setSelectedSegment:index];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Specifying Tracking Mode
|
||||
|
||||
- (BOOL)isTracking
|
||||
@@ -511,9 +564,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if ([aName hasPrefix:@"segment-content"])
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -891,6 +944,74 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
@end
|
||||
|
||||
var CPSegmentedControlBindersMap = {},
|
||||
CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
|
||||
|
||||
@implementation _CPSegmentedControlBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors(readonly, getter=selectionBinding);
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = CPSegmentedControlBindersMap[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder selectionBinding]];
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
CPSegmentedControlBindersMap[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[self _setPlaceholder:CPSegmentedControlNoSelectionPlaceholder forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPSegmentedControlNoSelectionPlaceholder forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPSegmentedControlNoSelectionPlaceholder forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPSegmentedControlNoSelectionPlaceholder forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aValue == CPSegmentedControlNoSelectionPlaceholder)
|
||||
[_source setSelected:NO forSegment:[_source selectedSegment]];
|
||||
else
|
||||
[self setValue:aValue forBinding:aBinding];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectedIndexBinding)
|
||||
[_source setSelectedSegment:aValue];
|
||||
else if (aBinding == CPSelectedTagBinding)
|
||||
[_source selectSegmentWithTag:aValue];
|
||||
else if (aBinding == CPSelectedLabelBinding)
|
||||
[_source _selectSegmentWithLabel:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
var selectedIndex = [_source selectedSegment];
|
||||
|
||||
if (aBinding == CPSelectedIndexBinding)
|
||||
return selectedIndex;
|
||||
else if (aBinding == CPSelectedTagBinding)
|
||||
return [_source tagForSegment:selectedIndex];
|
||||
else if (aBinding == CPSelectedLabelBinding)
|
||||
return [_source labelForSegment:selectedIndex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPSegmentItem : CPObject
|
||||
{
|
||||
|
||||
+7
-28
@@ -31,11 +31,9 @@
|
||||
*/
|
||||
@implementation CPShadow : CPObject
|
||||
{
|
||||
CGSize _offset;
|
||||
float _blurRadius;
|
||||
CPColor _color;
|
||||
|
||||
CPString _cssString;
|
||||
CGSize _offset @accessors(property=shadowOffset);
|
||||
float _blurRadius @accessors(property=shadowBlurRadius);
|
||||
CPColor _color @accessors(property=shadowColor);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -60,35 +58,16 @@
|
||||
_offset = anOffset;
|
||||
_blurRadius = aBlurRadius;
|
||||
_color = aColor;
|
||||
|
||||
_cssString = [_color cssString] + " " + ROUND(anOffset.width) + @"px " + ROUND(anOffset.height) + @"px " + ROUND(_blurRadius) + @"px";
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the shadow's offset.
|
||||
*/
|
||||
- (CGSize)shadowOffset
|
||||
- (void)set
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
/*!
|
||||
Returns the shadow's blur radius
|
||||
*/
|
||||
- (float)shadowBlurRadius
|
||||
{
|
||||
return _blurRadius;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the shadow's color.
|
||||
*/
|
||||
- (CPColor)shadowColor
|
||||
{
|
||||
return _color;
|
||||
CGContextSetShadowWithColor(context, _offset, _blurRadius, _color);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -96,7 +75,7 @@
|
||||
*/
|
||||
- (CPString)cssString
|
||||
{
|
||||
return _cssString;
|
||||
return [_color cssString] + " " + ROUND(_offset.width) + @"px " + ROUND(_offset.height) + @"px " + ROUND(_blurRadius) + @"px";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -47,13 +47,12 @@ CPThemeStateShadowViewHeavy = CPThemeState("shadowview-style-heavy");
|
||||
return "shadow-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:
|
||||
{
|
||||
return @{
|
||||
@"bezel-color": [CPNull null],
|
||||
@"content-inset": CGInsetMakeZero()
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
+ (CGRect)frameForContentFrame:(CGRect)aFrame withWeight:(CPShadowWeight)aWeight
|
||||
@@ -61,7 +60,7 @@ CPThemeStateShadowViewHeavy = CPThemeState("shadowview-style-heavy");
|
||||
var shadowView = [CPShadowView new],
|
||||
inset = [shadowView valueForThemeAttribute:@"content-inset" inState:(aWeight == CPLightShadow) ? CPThemeStateShadowViewLight : CPThemeStateShadowViewHeavy];
|
||||
|
||||
return CGRectMake(_CGRectGetMinX(aFrame) - inset.left, _CGRectGetMinY(aFrame) - inset.top, _CGRectGetWidth(aFrame) + inset.left + inset.right, _CGRectGetHeight(aFrame) + inset.top + inset.bottom);
|
||||
return CGRectMake(CGRectGetMinX(aFrame) - inset.left, CGRectGetMinY(aFrame) - inset.top, CGRectGetWidth(aFrame) + inset.left + inset.right, CGRectGetHeight(aFrame) + inset.top + inset.bottom);
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||
|
||||
+32
-28
@@ -49,10 +49,14 @@ CPCircularSlider = 1;
|
||||
return "slider";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], _CGSizeMakeZero(), 0.0, [CPNull null]]
|
||||
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
|
||||
return @{
|
||||
@"knob-color": [CPNull null],
|
||||
@"knob-size": CGSizeMakeZero(),
|
||||
@"track-width": 0.0,
|
||||
@"track-color": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -158,16 +162,16 @@ CPCircularSlider = 1;
|
||||
var trackWidth = [self currentValueForThemeAttribute:@"track-width"];
|
||||
|
||||
if (trackWidth <= 0)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
bounds.origin.x = (_CGRectGetWidth(bounds) - trackWidth) / 2.0;
|
||||
bounds.origin.x = (CGRectGetWidth(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.width = trackWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
bounds.origin.y = (_CGRectGetHeight(bounds) - trackWidth) / 2.0;
|
||||
bounds.origin.y = (CGRectGetHeight(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.height = trackWidth;
|
||||
}
|
||||
}
|
||||
@@ -180,13 +184,13 @@ CPCircularSlider = 1;
|
||||
var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
|
||||
|
||||
if (knobSize.width <= 0 || knobSize.height <= 0)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
|
||||
var knobRect = CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
// No track, do our best to approximate a place for this thing.
|
||||
if (!trackRect || _CGRectIsEmpty(trackRect))
|
||||
if (!trackRect || CGRectIsEmpty(trackRect))
|
||||
trackRect = bounds;
|
||||
|
||||
if ([self hasThemeState:CPThemeStateCircular])
|
||||
@@ -199,13 +203,13 @@ CPCircularSlider = 1;
|
||||
}
|
||||
else if ([self isVertical])
|
||||
{
|
||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
knobRect.origin.x = CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (CGRectGetHeight(trackRect) - knobSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
knobRect.origin.x = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetWidth(trackRect) - knobSize.width);
|
||||
knobRect.origin.y = _CGRectGetMidY(trackRect) - knobSize.height / 2.0;
|
||||
knobRect.origin.x = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (CGRectGetWidth(trackRect) - knobSize.width);
|
||||
knobRect.origin.y = CGRectGetMidY(trackRect) - knobSize.height / 2.0;
|
||||
}
|
||||
|
||||
return knobRect;
|
||||
@@ -256,8 +260,8 @@ CPCircularSlider = 1;
|
||||
{
|
||||
// Recalculate isVertical.
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
width = CGRectGetWidth(bounds),
|
||||
height = CGRectGetHeight(bounds);
|
||||
|
||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
||||
|
||||
@@ -302,55 +306,55 @@ CPCircularSlider = 1;
|
||||
|
||||
if ([self hasThemeState:CPThemeStateCircular])
|
||||
{
|
||||
var knobWidth = _CGRectGetWidth(knobRect);
|
||||
var knobWidth = CGRectGetWidth(knobRect);
|
||||
|
||||
trackRect.origin.x += knobWidth / 2;
|
||||
trackRect.size.width -= knobWidth;
|
||||
|
||||
var minValue = [self minValue],
|
||||
dx = aPoint.x - _CGRectGetMidX(trackRect),
|
||||
dy = aPoint.y - _CGRectGetMidY(trackRect);
|
||||
dx = aPoint.x - CGRectGetMidX(trackRect),
|
||||
dy = aPoint.y - CGRectGetMidY(trackRect);
|
||||
|
||||
return MAX(0.0, MIN(1.0, 1.0 - (3 * PI_2 - ATAN2(dy, dx)) % PI2 / PI2)) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else if ([self isVertical])
|
||||
{
|
||||
var knobHeight = _CGRectGetHeight(knobRect);
|
||||
var knobHeight = CGRectGetHeight(knobRect);
|
||||
|
||||
trackRect.origin.y += knobHeight / 2;
|
||||
trackRect.size.height -= knobHeight;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
return MAX(0.0, MIN(1.0, (CGRectGetMaxY(trackRect) - aPoint.y) / CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var knobWidth = _CGRectGetWidth(knobRect);
|
||||
var knobWidth = CGRectGetWidth(knobRect);
|
||||
|
||||
trackRect.origin.x += knobWidth / 2;
|
||||
trackRect.size.width -= knobWidth;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.x - _CGRectGetMinX(trackRect)) / _CGRectGetWidth(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
return MAX(0.0, MIN(1.0, (aPoint.x - CGRectGetMinX(trackRect)) / CGRectGetWidth(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
|
||||
knobRect = [self knobRectForBounds:CGRectMakeCopy(bounds)];
|
||||
|
||||
if (_CGRectContainsPoint(knobRect, aPoint))
|
||||
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
||||
if (CGRectContainsPoint(knobRect, aPoint))
|
||||
_dragOffset = CGSizeMake(CGRectGetMidX(knobRect) - aPoint.x, CGRectGetMidY(knobRect) - aPoint.y);
|
||||
else
|
||||
{
|
||||
var trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
|
||||
if (trackRect && CGRectContainsPoint(trackRect, aPoint))
|
||||
{
|
||||
_dragOffset = _CGSizeMakeZero();
|
||||
_dragOffset = CGSizeMakeZero();
|
||||
|
||||
[self setObjectValue:[self _valueAtPoint:aPoint]];
|
||||
}
|
||||
@@ -369,7 +373,7 @@ CPCircularSlider = 1;
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
|
||||
[self setObjectValue:[self _valueAtPoint:CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
CPTextField _hexLabel;
|
||||
CPTextField _hexValue;
|
||||
|
||||
CPTextField _hexValue;
|
||||
CPTextField _redValue;
|
||||
CPTextField _greenValue;
|
||||
CPTextField _blueValue;
|
||||
@@ -146,7 +145,7 @@
|
||||
[_hueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 143, aFrame.size.width - 70, 20)];
|
||||
[_hueSlider setMaxValue:359.0];
|
||||
[_hueSlider setMaxValue:0.999];
|
||||
[_hueSlider setMinValue:0.0];
|
||||
[_hueSlider setTarget:self];
|
||||
[_hueSlider setAction:@selector(sliderChanged:)];
|
||||
@@ -165,7 +164,7 @@
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_saturationSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 168, aFrame.size.width - 70, 20)];
|
||||
[_saturationSlider setMaxValue:100.0];
|
||||
[_saturationSlider setMaxValue:1.0];
|
||||
[_saturationSlider setMinValue:0.0];
|
||||
[_saturationSlider setTarget:self];
|
||||
[_saturationSlider setAction:@selector(sliderChanged:)];
|
||||
@@ -184,7 +183,7 @@
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 194, aFrame.size.width - 70, 20)];
|
||||
[_brightnessSlider setMaxValue:100.0];
|
||||
[_brightnessSlider setMaxValue:1.0];
|
||||
[_brightnessSlider setMinValue:0.0];
|
||||
[_brightnessSlider setTarget:self];
|
||||
[_brightnessSlider setAction:@selector(sliderChanged:)];
|
||||
@@ -282,6 +281,9 @@
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (!aColor)
|
||||
[CPException raise:CPInvalidArgumentException reason:"aColor can't be nil"];
|
||||
|
||||
[self updateRGBSliders:aColor];
|
||||
[self updateHSBSliders:aColor];
|
||||
[self updateHex:aColor];
|
||||
@@ -313,9 +315,9 @@
|
||||
|
||||
- (void)updateLabels
|
||||
{
|
||||
[_hueValue setStringValue:ROUND([_hueSlider floatValue])];
|
||||
[_saturationValue setStringValue:ROUND([_saturationSlider floatValue])];
|
||||
[_brightnessValue setStringValue:ROUND([_brightnessSlider floatValue])];
|
||||
[_hueValue setStringValue:ROUND([_hueSlider floatValue] * 360.0)];
|
||||
[_saturationValue setStringValue:ROUND([_saturationSlider floatValue] * 100.0)];
|
||||
[_brightnessValue setStringValue:ROUND([_brightnessSlider floatValue] * 100.0)];
|
||||
|
||||
[_redValue setStringValue:ROUND([_redSlider floatValue] * 255)];
|
||||
[_greenValue setStringValue:ROUND([_greenSlider floatValue] * 255)];
|
||||
@@ -363,15 +365,15 @@
|
||||
[self sliderChanged:_blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360) / 360.0, 0)];
|
||||
[self sliderChanged:_hueSlider];
|
||||
break;
|
||||
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100) / 100.0, 0)];
|
||||
[self sliderChanged:_saturationSlider];
|
||||
break;
|
||||
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100) / 100.0, 0)];
|
||||
[self sliderChanged:_brightnessSlider];
|
||||
break;
|
||||
}
|
||||
|
||||
+22
-18
@@ -103,18 +103,15 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
return @"splitview";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[1.0,
|
||||
10.0,
|
||||
[CPColor grayColor],
|
||||
[CPNull null],
|
||||
[CPNull null]]
|
||||
forKeys:[@"divider-thickness",
|
||||
@"pane-divider-thickness",
|
||||
@"pane-divider-color",
|
||||
@"horizontal-divider-color",
|
||||
@"vertical-divider-color"]];
|
||||
return @{
|
||||
@"divider-thickness": 1.0,
|
||||
@"pane-divider-thickness": 10.0,
|
||||
@"pane-divider-color": [CPColor grayColor],
|
||||
@"horizontal-divider-color": [CPNull null],
|
||||
@"vertical-divider-color": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -337,8 +334,8 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
}
|
||||
|
||||
[self _setupDOMDivider];
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -998,7 +995,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
@param unsigned int - The divider index the button bar will be assigned to.
|
||||
*/
|
||||
// FIXME Should be renamed to setButtonBar:ofDividerAtIndex:.
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(CPUInteger)dividerIndex
|
||||
{
|
||||
if (!aButtonBar)
|
||||
{
|
||||
@@ -1032,7 +1029,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = [CPDictionary dictionaryWithObject:_currentDivider forKey:@"CPSplitViewDividerIndex"];
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification
|
||||
object:self
|
||||
@@ -1044,7 +1041,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = [CPDictionary dictionaryWithObject:_currentDivider forKey:@"CPSplitViewDividerIndex"];
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification
|
||||
object:self
|
||||
@@ -1113,7 +1110,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
*/
|
||||
- (void)_restoreFromAutosaveIfNeeded
|
||||
{
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize && !_CGSizeEqualToSize([self frameSize], _shouldRestoreFromAutosaveUnlessFrameSize))
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize && !CGSizeEqualToSize([self frameSize], _shouldRestoreFromAutosaveUnlessFrameSize))
|
||||
{
|
||||
[self _restoreFromAutosave];
|
||||
}
|
||||
@@ -1160,7 +1157,14 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
|
||||
for (var i = 0, count = [preCollapseArray count]; i < count; i++)
|
||||
[_preCollapsePositions setObject:preCollapseArray[i] forKey:i + ""];
|
||||
{
|
||||
var item = preCollapseArray[i];
|
||||
|
||||
if (item === nil)
|
||||
[_preCollapsePositions removeObjectForKey:String(i)];
|
||||
else
|
||||
[_preCollapsePositions setObject:item forKey:String(i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-15
@@ -55,7 +55,7 @@
|
||||
*/
|
||||
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||
{
|
||||
var stepper = [[CPStepper alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var stepper = [[CPStepper alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[stepper setDoubleValue:aValue];
|
||||
[stepper setMinValue:aMinValue];
|
||||
@@ -80,15 +80,15 @@
|
||||
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (theBinding == CPValueBinding || theBinding == CPMinValueBinding || theBinding == CPMaxValueBinding)
|
||||
if (aBinding == CPValueBinding || aBinding == CPMinValueBinding || aBinding == CPMaxValueBinding)
|
||||
return [_CPStepperValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return @"doubleValue";
|
||||
@@ -122,14 +122,14 @@
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_buttonUp = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_buttonUp = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_buttonUp setContinuous:_autorepeat];
|
||||
[_buttonUp setTarget:self];
|
||||
[_buttonUp setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonUp setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonUp];
|
||||
|
||||
_buttonDown = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_buttonDown = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_buttonDown setContinuous:_autorepeat];
|
||||
[_buttonDown setTarget:self];
|
||||
[_buttonDown setAction:@selector(_buttonDidClick:)];
|
||||
@@ -161,8 +161,8 @@
|
||||
{
|
||||
var upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
minSize = _CGSizeMake(upSize.width, upSize.height + downSize.height),
|
||||
frame = _CGRectMakeCopy(aFrame);
|
||||
minSize = CGSizeMake(upSize.width, upSize.height + downSize.height),
|
||||
frame = CGRectMakeCopy(aFrame);
|
||||
|
||||
frame.size.width = MAX(minSize.width, frame.size.width);
|
||||
frame.size.height = MAX(minSize.height, frame.size.height);
|
||||
@@ -175,8 +175,8 @@
|
||||
var aFrame = [self frame],
|
||||
upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
upFrame = _CGRectMake(aFrame.size.width - upSize.width, 0, upSize.width, upSize.height),
|
||||
downFrame = _CGRectMake(aFrame.size.width - downSize.width, upSize.height, downSize.width, downSize.height);
|
||||
upFrame = CGRectMake(aFrame.size.width - upSize.width, 0, upSize.width, upSize.height),
|
||||
downFrame = CGRectMake(aFrame.size.width - downSize.width, upSize.height, downSize.width, downSize.height);
|
||||
|
||||
[_buttonUp setFrame:upFrame];
|
||||
[_buttonDown setFrame:downFrame];
|
||||
@@ -213,7 +213,7 @@
|
||||
Set the current value of the stepper.
|
||||
@param aValue a float containing the value
|
||||
*/
|
||||
- (void)setDoubleValue:(float)aValue
|
||||
- (void)setDoubleValue:(double)aValue
|
||||
{
|
||||
if (aValue > _maxValue)
|
||||
[super setDoubleValue:_valueWraps ? _minValue : _maxValue];
|
||||
@@ -267,10 +267,14 @@
|
||||
return @"stepper";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], _CGSizeMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button", @"up-button-size", @"down-button-size"]];
|
||||
return @{
|
||||
@"bezel-color-up-button": [CPNull null],
|
||||
@"bezel-color-down-button": [CPNull null],
|
||||
@"up-button-size": CGSizeMakeZero(),
|
||||
@"down-button-size": CGSizeMakeZero(),
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+39
-21
@@ -79,11 +79,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
_selectedIndex = CPNotFound;
|
||||
|
||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:_CGRectMake(0, 0, 0, 0)];
|
||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
|
||||
[_tabs setHitTests:NO];
|
||||
|
||||
var height = [_tabs valueForThemeAttribute:@"default-height"];
|
||||
[_tabs setFrameSize:_CGSizeMake(0, height)];
|
||||
[_tabs setFrameSize:CGSizeMake(0, height)];
|
||||
|
||||
_box = [[CPBox alloc] initWithFrame:[self bounds]];
|
||||
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
||||
@@ -107,7 +107,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
@param aTabViewItem the item to insert
|
||||
@param anIndex the index for the item
|
||||
*/
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
|
||||
{
|
||||
[_items insertObject:aTabViewItem atIndex:anIndex];
|
||||
|
||||
@@ -183,7 +183,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
Returns the CPTabViewItem at the specified index.
|
||||
@return a tab view item, or nil
|
||||
*/
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
return [_items objectAtIndex:anIndex];
|
||||
}
|
||||
@@ -270,7 +270,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
Selects the item at the specified index.
|
||||
@param anIndex the index of the item to display.
|
||||
*/
|
||||
- (BOOL)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||
- (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
if (anIndex === _selectedIndex)
|
||||
return;
|
||||
@@ -373,11 +373,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
else
|
||||
{
|
||||
var aFrame = [self frame],
|
||||
segmentedHeight = _CGRectGetHeight([_tabs frame]),
|
||||
segmentedHeight = CGRectGetHeight([_tabs frame]),
|
||||
origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
|
||||
|
||||
[_box setFrame:_CGRectMake(0, origin, _CGRectGetWidth(aFrame),
|
||||
_CGRectGetHeight(aFrame) - segmentedHeight / 2)];
|
||||
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
|
||||
CGRectGetHeight(aFrame) - segmentedHeight / 2)];
|
||||
|
||||
[self _repositionTabs];
|
||||
}
|
||||
@@ -447,13 +447,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
- (void)_repositionTabs
|
||||
{
|
||||
var horizontalCenterOfSelf = _CGRectGetWidth([self bounds]) / 2,
|
||||
verticalCenterOfTabs = _CGRectGetHeight([_tabs bounds]) / 2;
|
||||
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
|
||||
verticalCenterOfTabs = CGRectGetHeight([_tabs bounds]) / 2;
|
||||
|
||||
if (_type === CPBottomTabsBezelBorder)
|
||||
[_tabs setCenter:_CGPointMake(horizontalCenterOfSelf, _CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
|
||||
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
|
||||
else
|
||||
[_tabs setCenter:_CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
||||
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
||||
}
|
||||
|
||||
- (void)_setSelectedIndex:(CPNumber)index
|
||||
@@ -504,25 +504,43 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
[_items makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
|
||||
[self _updateItems];
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
|
||||
[self setTabViewType:[aCoder decodeIntForKey:CPTabViewTypeKey]];
|
||||
|
||||
[self setNeedsLayout];
|
||||
self.selectOnAwake = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
_type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
// This cannot be run in initWithCoder because it might call selectTabViewItem:, which is
|
||||
// not safe to call before the views of the tab views items are fully decoded.
|
||||
[self _updateItems];
|
||||
|
||||
if (self.selectOnAwake)
|
||||
{
|
||||
[self selectTabViewItem:self.selectOnAwake];
|
||||
delete self.selectOnAwake;
|
||||
}
|
||||
|
||||
var type = _type;
|
||||
_type = nil;
|
||||
[self setTabViewType:type];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// Don't bother to encode the CPBox. We will recreate it on decode and its content view is already
|
||||
// stored by the tab view item. Not encoding _box makes the resulting archive smaller and reduces
|
||||
// the surface for decoding bugs (of which we've had many in tab view).
|
||||
var subviews = [self subviews];
|
||||
[_box removeFromSuperview];
|
||||
[super encodeWithCoder:aCoder];
|
||||
[self setSubviews:subviews];
|
||||
|
||||
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
|
||||
|
||||
|
||||
+14
-26
@@ -52,7 +52,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
CPTableView _tableView;
|
||||
CPView _headerView;
|
||||
CPView _dataView;
|
||||
Object _dataViewData;
|
||||
CPData _dataViewData;
|
||||
|
||||
float _width;
|
||||
float _minWidth;
|
||||
@@ -86,7 +86,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_dataViewData = { };
|
||||
_dataViewData = nil;
|
||||
|
||||
_width = 100.0;
|
||||
_minWidth = 10.0;
|
||||
@@ -283,7 +283,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var width = _CGRectGetWidth([_headerView frame]);
|
||||
var width = CGRectGetWidth([_headerView frame]);
|
||||
|
||||
if (width < [self minWidth])
|
||||
[self setMinWidth:width];
|
||||
@@ -395,12 +395,12 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
- (void)setDataView:(CPView)aView
|
||||
{
|
||||
if (_dataView)
|
||||
_dataViewData[[_dataView UID]] = nil;
|
||||
_dataViewData = nil;
|
||||
|
||||
[aView setThemeState:CPThemeStateTableDataView];
|
||||
|
||||
_dataView = aView;
|
||||
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
_dataViewData = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
}
|
||||
|
||||
- (CPView)dataView
|
||||
@@ -416,7 +416,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
to be invoked with row equal to -1 in cases where no actual row is involved but the table
|
||||
view needs to get some generic cell info.
|
||||
*/
|
||||
- (id)dataViewForRow:(int)aRowIndex
|
||||
- (id)dataViewForRow:(CPInteger)aRowIndex
|
||||
{
|
||||
return [self dataView];
|
||||
}
|
||||
@@ -424,24 +424,12 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (id)_newDataViewForRow:(int)aRowIndex
|
||||
- (id)_newDataView
|
||||
{
|
||||
var dataView = [self dataViewForRow:aRowIndex],
|
||||
dataViewUID = [dataView UID];
|
||||
if (!_dataViewData)
|
||||
return nil;
|
||||
|
||||
var x = [self tableView]._cachedDataViews[dataViewUID];
|
||||
if (x && x.length)
|
||||
return x.pop();
|
||||
|
||||
// if we haven't cached an archive of the data view, do it now
|
||||
if (!_dataViewData[dataViewUID])
|
||||
_dataViewData[dataViewUID] = [CPKeyedArchiver archivedDataWithRootObject:dataView];
|
||||
|
||||
// unarchive the data view cache
|
||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||
newDataView.identifier = dataViewUID;
|
||||
|
||||
// make sure only we have control over the size and placement
|
||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData];
|
||||
[newDataView setAutoresizingMask:CPViewNotSizable];
|
||||
|
||||
return newDataView;
|
||||
@@ -560,7 +548,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||
object:[self tableView]
|
||||
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
||||
userInfo:@{ @"CPTableColumn": self, @"CPOldWidth": oldWidth }];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -607,7 +595,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
@implementation CPTableColumn (Bindings)
|
||||
|
||||
+ (id)_binderClassForBinding:(CPString)aBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return [CPTableColumnValueBinder class];
|
||||
@@ -757,7 +745,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
_dataViewData = { };
|
||||
_dataViewData = nil;
|
||||
|
||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||
@@ -840,7 +828,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (id)dataCellForRow:(int)row
|
||||
- (id)dataCellForRow:(CPInteger)row
|
||||
{
|
||||
[CPException raise:CPUnsupportedMethodException
|
||||
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
|
||||
|
||||
+87
-55
@@ -43,13 +43,21 @@
|
||||
return @"columnHeader";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], CPLeftTextAlignment, CPLineBreakByTruncatingTail, CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
|
||||
forKeys:[@"background-color", @"text-alignment", @"line-break-mode", @"text-inset", @"text-color", @"font", @"text-shadow-color", @"text-shadow-offset"]];
|
||||
return @{
|
||||
@"background-color": [CPNull null],
|
||||
@"text-alignment": CPLeftTextAlignment,
|
||||
@"line-break-mode": CPLineBreakByTruncatingTail,
|
||||
@"text-inset": CGInsetMakeZero(),
|
||||
@"text-color": [CPNull null],
|
||||
@"font": [CPNull null],
|
||||
@"text-shadow-color": [CPNull null],
|
||||
@"text-shadow-offset": CGSizeMakeZero()
|
||||
};
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)frame
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
@@ -61,7 +69,7 @@
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_textField setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
@@ -79,7 +87,7 @@
|
||||
var inset = [self currentValueForThemeAttribute:@"text-inset"],
|
||||
bounds = [self bounds];
|
||||
|
||||
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
|
||||
[_textField setFrame:CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
|
||||
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||
[_textField setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||
@@ -221,6 +229,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
CGPoint _previousTrackingLocation;
|
||||
int _activeColumn;
|
||||
int _pressedColumn;
|
||||
int _lastDragDestinationColumnIndex;
|
||||
|
||||
BOOL _isResizing;
|
||||
BOOL _isDragging;
|
||||
@@ -237,16 +246,19 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return @"tableHeaderRow";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
|
||||
forKeys:[@"background-color", @"divider-color"]];
|
||||
return @{
|
||||
@"background-color": [CPNull null],
|
||||
@"divider-color": [CPColor grayColor],
|
||||
@"divider-thickness": 1.0
|
||||
};
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_mouseDownLocation = _CGPointMakeZero();
|
||||
_previousTrackingLocation = _CGPointMakeZero();
|
||||
_mouseDownLocation = CGPointMakeZero();
|
||||
_previousTrackingLocation = CGPointMakeZero();
|
||||
_activeColumn = -1;
|
||||
_pressedColumn = -1;
|
||||
|
||||
@@ -275,13 +287,13 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
|
||||
}
|
||||
|
||||
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||
- (CGRect)headerRectOfColumn:(CPInteger)aColumnIndex
|
||||
{
|
||||
var headerRect = CGRectMakeCopy([self bounds]),
|
||||
columnRect = [_tableView rectOfColumn:aColumnIndex];
|
||||
|
||||
headerRect.origin.x = _CGRectGetMinX(columnRect);
|
||||
headerRect.size.width = _CGRectGetWidth(columnRect);
|
||||
headerRect.origin.x = CGRectGetMinX(columnRect);
|
||||
headerRect.size.width = CGRectGetWidth(columnRect);
|
||||
|
||||
return headerRect;
|
||||
}
|
||||
@@ -296,14 +308,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return _drawsColumnLines;
|
||||
}
|
||||
|
||||
- (CGRect)_cursorRectForColumn:(int)column
|
||||
- (CGRect)_cursorRectForColumn:(CPInteger)column
|
||||
{
|
||||
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var rect = [self headerRectOfColumn:column];
|
||||
|
||||
rect.origin.x = _CGRectGetMaxX(rect) - 5;
|
||||
rect.origin.x = CGRectGetMaxX(rect) - 5;
|
||||
rect.size.width = 20;
|
||||
|
||||
return rect;
|
||||
@@ -321,6 +333,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[column] headerView];
|
||||
[headerView setThemeState:CPThemeStateHighlighted];
|
||||
|
||||
if (_tableView._editingCellIndex || _tableView._editingColumn == column)
|
||||
[[self window] makeFirstResponder:_tableView];
|
||||
}
|
||||
|
||||
_pressedColumn = column;
|
||||
@@ -340,7 +355,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
currentLocation.x -= 5.0;
|
||||
|
||||
var columnIndex = [self columnAtPoint:currentLocation],
|
||||
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||
shouldResize = [self shouldResizeTableColumn:columnIndex at:CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
@@ -368,7 +383,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
_mouseDownLocation = currentLocation;
|
||||
_activeColumn = columnIndex;
|
||||
|
||||
[_tableView _sendDelegateDidMouseDownInHeader:columnIndex];
|
||||
[_tableView _sendDelegateMouseDownInHeaderOfTableColumn:columnIndex];
|
||||
|
||||
if (shouldResize)
|
||||
[self startResizingTableColumn:columnIndex at:currentLocation];
|
||||
@@ -384,7 +399,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self continueResizingTableColumn:_activeColumn at:currentLocation];
|
||||
else
|
||||
{
|
||||
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||
if (_activeColumn === columnIndex && CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||
{
|
||||
if (_isTrackingColumn && _pressedColumn !== -1)
|
||||
{
|
||||
@@ -402,24 +417,25 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (void)startTrackingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
_lastDragDestinationColumnIndex = -1;
|
||||
[self _setPressedColumn:aColumnIndex];
|
||||
}
|
||||
|
||||
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (BOOL)continueTrackingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
|
||||
{
|
||||
var columnRect = [self headerRectOfColumn:aColumnIndex],
|
||||
offset = _CGPointMakeZero(),
|
||||
offset = CGPointMakeZero(),
|
||||
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
|
||||
viewLocation = _CGPointMakeZero();
|
||||
viewLocation = CGPointMakeZero();
|
||||
|
||||
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
|
||||
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
|
||||
viewLocation.x = ( CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
|
||||
viewLocation.y = CGRectGetMinY(columnRect) + offset.y;
|
||||
|
||||
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
|
||||
[self dragView:view at:viewLocation offset:CGSizeMakeZero() event:[CPApp currentEvent]
|
||||
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
|
||||
|
||||
return NO;
|
||||
@@ -428,21 +444,21 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (BOOL)_shouldStopTrackingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
return _isTrackingColumn && _activeColumn === aColumnIndex &&
|
||||
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
|
||||
CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
|
||||
}
|
||||
|
||||
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (void)stopTrackingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
[self _setPressedColumn:CPNotFound];
|
||||
[self _updateResizeCursor:[CPApp currentEvent]];
|
||||
}
|
||||
|
||||
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (BOOL)_shouldDragTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
|
||||
return ABS(aPoint.x - _mouseDownLocation.x) >= 10.0 && [_tableView _sendDelegateShouldReorderColumn:aColumnIndex toColumn:-1];
|
||||
}
|
||||
|
||||
- (CGRect)_headerRectOfLastVisibleColumn
|
||||
@@ -475,10 +491,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
frame.origin = [self convertPoint:frame.origin fromView:nil];
|
||||
|
||||
// This effectively clamps the value between the minimum and maximum
|
||||
frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
|
||||
frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect)));
|
||||
|
||||
// Make sure the column cannot move vertically
|
||||
frame.origin.y = _CGRectGetMinY(lastColumnRect);
|
||||
frame.origin.y = CGRectGetMinY(lastColumnRect);
|
||||
|
||||
// Convert the calculated origin back to the window coordinate system
|
||||
frame.origin = [self convertPoint:frame.origin toView:nil];
|
||||
@@ -488,11 +504,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[dragWindow setFrame:frame];
|
||||
}
|
||||
|
||||
- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
|
||||
- (void)_moveColumn:(CPInteger)aFromIndex toColumn:(CPInteger)aToIndex
|
||||
{
|
||||
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||
_activeColumn = aToIndex;
|
||||
_pressedColumn = _activeColumn;
|
||||
if ([_tableView _sendDelegateShouldReorderColumn:aFromIndex toColumn:aToIndex])
|
||||
{
|
||||
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||
_activeColumn = aToIndex;
|
||||
_pressedColumn = _activeColumn;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
|
||||
@@ -517,9 +536,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
var hoverPoint = CGPointCreateCopy(aPoint);
|
||||
|
||||
if (aPoint.x < _previousTrackingLocation.x)
|
||||
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||
hoverPoint = CGPointMake(CGRectGetMinX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
|
||||
else if (aPoint.x > _previousTrackingLocation.x)
|
||||
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||
hoverPoint = CGPointMake(CGRectGetMaxX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
|
||||
|
||||
// Convert the hover point from the global coordinate system to windows' coordinate system
|
||||
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
|
||||
@@ -528,14 +547,21 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
var hoveredColumn = [self columnAtPoint:hoverPoint];
|
||||
|
||||
if (hoveredColumn !== -1)
|
||||
if (hoveredColumn !== _lastDragDestinationColumnIndex && hoveredColumn !== -1)
|
||||
{
|
||||
var columnRect = [self headerRectOfColumn:hoveredColumn],
|
||||
columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
|
||||
columnCenterPoint = [self convertPoint:CGPointMake(CGRectGetMidX(columnRect), CGRectGetMidY(columnRect)) fromView:self];
|
||||
|
||||
if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
|
||||
{
|
||||
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
|
||||
_lastDragDestinationColumnIndex = hoveredColumn;
|
||||
}
|
||||
else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
|
||||
{
|
||||
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
|
||||
_lastDragDestinationColumnIndex = hoveredColumn;
|
||||
}
|
||||
}
|
||||
|
||||
_previousTrackingLocation = aPoint;
|
||||
@@ -551,9 +577,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self stopTrackingTableColumn:_activeColumn at:aLocation];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[_tableView _enqueueDraggingViews];
|
||||
}
|
||||
|
||||
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (BOOL)shouldResizeTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
if (_isResizing)
|
||||
return YES;
|
||||
@@ -561,10 +589,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
if (_isTrackingColumn)
|
||||
return NO;
|
||||
|
||||
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
|
||||
return [_tableView allowsColumnResizing] && CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
|
||||
}
|
||||
|
||||
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (void)startResizingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
_isResizing = YES;
|
||||
|
||||
@@ -574,7 +602,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[_tableView setDisableAutomaticResizing:YES];
|
||||
}
|
||||
|
||||
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (void)continueResizingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
|
||||
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
|
||||
@@ -594,7 +622,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
- (void)stopResizingTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
|
||||
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||
@@ -617,7 +645,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||
overColumn = [self columnAtPoint:mouseOverLocation];
|
||||
|
||||
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
|
||||
width = [tableColumn width];
|
||||
@@ -652,7 +680,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
count = [tableColumns count];
|
||||
count = [tableColumns count],
|
||||
lineThickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
@@ -662,7 +691,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
// Make space for the gridline on the right.
|
||||
frame.origin.x -= 0.5;
|
||||
frame.size.width -= 1.0;
|
||||
frame.size.width -= lineThickness;
|
||||
frame.size.height -= 0.5;
|
||||
// Note: we're not adding in intercell spacing here. This setting only affects the regular
|
||||
// table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
|
||||
@@ -687,9 +716,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
tableColumns = [_tableView tableColumns],
|
||||
exposedTableColumns = _tableView._exposedColumns,
|
||||
firstIndex = [exposedTableColumns firstIndex],
|
||||
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1),
|
||||
lineThickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
CGContextSetLineWidth(context, 1);
|
||||
CGContextSetLineWidth(context, lineThickness);
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
|
||||
|
||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||
@@ -699,17 +729,19 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
columnMaxX;
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
for (; columnArrayIndex < columnArrayCount; columnArrayIndex++)
|
||||
{
|
||||
// grab each column rect and add vertical lines
|
||||
var columnIndex = columnsArray[columnArrayIndex],
|
||||
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||
|
||||
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||
columnMaxX = CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)) - 1.0);
|
||||
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5 * lineThickness, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5 * lineThickness, ROUND(CGRectGetMaxY(columnToStroke)) - 1.0);
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
|
||||
+1590
-565
File diff suppressed because it is too large
Load Diff
@@ -28,3 +28,14 @@ CPFormFeedCharacter = "\u000c";
|
||||
CPCarriageReturnCharacter = "\u000d";
|
||||
CPBackTabCharacter = "\u0019";
|
||||
CPDeleteCharacter = "\u007f";
|
||||
|
||||
CPIllegalTextMovement = 0;
|
||||
CPOtherTextMovement = 0;
|
||||
CPReturnTextMovement = 16;
|
||||
CPTabTextMovement = 17;
|
||||
CPBacktabTextMovement = 18;
|
||||
CPLeftTextMovement = 19;
|
||||
CPRightTextMovement = 20;
|
||||
CPUpTextMovement = 21;
|
||||
CPDownTextMovement = 22;
|
||||
CPCancelTextMovement = 23;
|
||||
+428
-156
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
@import "CPCompatibility.j"
|
||||
@@ -61,26 +59,33 @@ function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resig
|
||||
if (owner && domElement != inputElement.parentNode)
|
||||
return;
|
||||
|
||||
if (!resigning && [[owner window] isKeyWindow])
|
||||
var ownerWindow = [owner window];
|
||||
|
||||
if (!resigning && [ownerWindow isKeyWindow])
|
||||
{
|
||||
/*
|
||||
Browsers blur text fields when a click occurs anywhere outside the text field. That is normal for browsers, but in Cocoa the key view retains focus unless the click target accepts first responder. So if we lost focus but were not told to resign and our window is still key, restore focus.
|
||||
Browsers blur text fields when a click occurs anywhere outside the text field. That is normal for browsers, but in Cocoa the key view retains focus unless the click target accepts first responder. So if we lost focus but were not told to resign and our window is still key, restore focus,
|
||||
but only if the text field is completely within the browser window. If we restore focus when it
|
||||
is off screen, the entire body scrolls out of our control.
|
||||
*/
|
||||
window.setTimeout(function()
|
||||
if ([owner _isWithinUsablePlatformRect])
|
||||
{
|
||||
inputElement.focus();
|
||||
}, 0.0);
|
||||
window.setTimeout(function()
|
||||
{
|
||||
inputElement.focus();
|
||||
}, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
CPTextFieldHandleBlur(anEvent, AT_REF(owner));
|
||||
AT_DEREF(didBlurRef, YES);
|
||||
CPTextFieldHandleBlur(anEvent, @ref(owner));
|
||||
@deref(didBlurRef) = YES;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function CPTextFieldHandleBlur(anEvent, ownerRef)
|
||||
{
|
||||
AT_DEREF(ownerRef, nil);
|
||||
@deref(ownerRef) = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
@@ -129,6 +134,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPControlSize _controlSize;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPValueBinding)
|
||||
return [_CPTextFieldValueBinder class];
|
||||
else if ([aBinding hasPrefix:CPDisplayPatternValueBinding])
|
||||
return [_CPTextFieldPatternValueBinder class];
|
||||
else if ([aBinding hasPrefix:CPEditableBinding])
|
||||
return [CPMultipleValueAndBinding class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (CPTextField)textFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth
|
||||
{
|
||||
return [self textFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[CPTheme defaultTheme]];
|
||||
@@ -192,21 +209,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return "textfield";
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
if (theBinding === CPValueBinding)
|
||||
return [_CPTextFieldValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
return @{
|
||||
@"bezel-inset": CGInsetMakeZero(),
|
||||
@"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
|
||||
@"bezel-color": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(1.0, 0.0, 0.0, 0.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
#if PLATFORM(DOM)
|
||||
- (DOMElement)_inputElement
|
||||
{
|
||||
@@ -226,10 +237,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return CPTextFieldBlurFunction(
|
||||
anEvent,
|
||||
CPTextFieldInputOwner,
|
||||
CPTextFieldInputOwner._DOMElement,
|
||||
CPTextFieldInputOwner ? CPTextFieldInputOwner._DOMElement : nil,
|
||||
CPTextFieldDOMInputElement,
|
||||
CPTextFieldInputResigning,
|
||||
AT_REF(CPTextFieldInputDidBlur));
|
||||
@ref(CPTextFieldInputDidBlur));
|
||||
};
|
||||
|
||||
if (CPFeatureIsCompatible(CPInputOnInputEventFeature))
|
||||
@@ -240,7 +251,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return;
|
||||
|
||||
var cappEvent = [CPEvent keyEventWithType:CPKeyUp
|
||||
location:_CGPointMakeZero()
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:[CPEvent currentTimestamp]
|
||||
windowNumber:[[CPApp keyWindow] windowNumber]
|
||||
@@ -340,9 +351,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateEditable];
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEditable && [[self window] firstResponder] === self)
|
||||
// We only allow first responder status if the field is enable, and editable or selectable.
|
||||
if (!(shouldBeEditable && ![self isSelectable]) && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
|
||||
if (shouldBeEditable)
|
||||
[self setThemeState:CPThemeStateEditable];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateEditable];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -361,7 +377,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
[super setEnabled:shouldBeEnabled];
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
// We only allow first responder status if the field is enabled.
|
||||
if (!shouldBeEnabled && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
@@ -512,33 +528,49 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return _textFieldBackgroundColor;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
/*! @ignore */
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return [self isEditable] && [self isEnabled];
|
||||
return [self isEnabled] && ([self isEditable] || [self isSelectable]) && [self _isWithinUsablePlatformRect];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
/*! @ignore */
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return NO;
|
||||
|
||||
// As long as we are the first responder we need to monitor the key status of our window.
|
||||
[self _setObserveWindowKeyNotifications:YES];
|
||||
|
||||
_isEditing = NO;
|
||||
|
||||
if ([[self window] isKeyWindow])
|
||||
[self _becomeFirstKeyResponder];
|
||||
if ([[self window] isKeyWindow] && [self isEditable])
|
||||
return [self _becomeFirstKeyResponder];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*
|
||||
A text field can be the first responder without necessarily being the focus of keyboard input. For example, it might be the first responder of window A but window B is the main and key window. It's important we don't put a focused input field into a text field in a non-key window, even if that field is the first responder, because the key window might also have a first responder text field which the user will expect to receive keyboard input.
|
||||
|
||||
Since a first responder but non-key window text field can't receive input it should not even look like an active text field (Cocoa has a "slightly active" text field look it uses when another window is the key window, but Cappuccino doesn't today.)
|
||||
|
||||
It's also possible for a text field to be non-editable but selectable in which case it can also become the first responder -
|
||||
this is what allows text to be copied from it.
|
||||
*/
|
||||
- (void)_becomeFirstKeyResponder
|
||||
- (BOOL)_becomeFirstKeyResponder
|
||||
{
|
||||
// If the text field is still not completely on screen, refuse to become
|
||||
// first responder, because the browser will scroll it into view out of our control.
|
||||
if (![self _isWithinUsablePlatformRect])
|
||||
return NO;
|
||||
|
||||
// A selectable but non-editable text field may be the first responder, but never the
|
||||
// first key responder (first key responder indicating editability.)
|
||||
if (![self isEditable])
|
||||
return NO;
|
||||
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -563,11 +595,16 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
switch ([self alignment])
|
||||
{
|
||||
case CPCenterTextAlignment: element.style.textAlign = "center";
|
||||
break;
|
||||
case CPRightTextAlignment: element.style.textAlign = "right";
|
||||
break;
|
||||
default: element.style.textAlign = "left";
|
||||
case CPCenterTextAlignment:
|
||||
element.style.textAlign = "center";
|
||||
break;
|
||||
|
||||
case CPRightTextAlignment:
|
||||
element.style.textAlign = "right";
|
||||
break;
|
||||
|
||||
default:
|
||||
element.style.textAlign = "left";
|
||||
}
|
||||
|
||||
var contentRect = [self contentRectForBounds:[self bounds]],
|
||||
@@ -576,31 +613,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
switch (verticalAlign)
|
||||
{
|
||||
case CPTopVerticalTextAlignment:
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px";
|
||||
var topPoint = CGRectGetMinY(contentRect) + "px";
|
||||
break;
|
||||
|
||||
case CPCenterVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
|
||||
var topPoint = (CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
|
||||
break;
|
||||
|
||||
case CPBottomVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMaxY(contentRect) - lineHeight) + "px";
|
||||
var topPoint = (CGRectGetMaxY(contentRect) - lineHeight) + "px";
|
||||
break;
|
||||
|
||||
default:
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px";
|
||||
var topPoint = CGRectGetMinY(contentRect) + "px";
|
||||
break;
|
||||
}
|
||||
|
||||
element.style.top = topPoint;
|
||||
var left = _CGRectGetMinX(contentRect);
|
||||
|
||||
var left = CGRectGetMinX(contentRect);
|
||||
|
||||
// If the browser has a built in left padding, compensate for it. We need the input text to be exactly on top of the original text.
|
||||
if (CPFeatureIsCompatible(CPInput1PxLeftPadding))
|
||||
left -= 1;
|
||||
|
||||
element.style.left = left + "px";
|
||||
element.style.width = _CGRectGetWidth(contentRect) + "px";
|
||||
element.style.width = CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = ROUND(lineHeight) + "px";
|
||||
element.style.lineHeight = ROUND(lineHeight) + "px";
|
||||
element.style.verticalAlign = "top";
|
||||
@@ -612,8 +650,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (!CPFeatureIsCompatible(CPInputSetFontOutsideOfDOM))
|
||||
element.style.font = [font cssString];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
|
||||
if (document.attachEvent)
|
||||
@@ -647,30 +683,34 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
/*! @ignore */
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement],
|
||||
newValue = element.value,
|
||||
error = @"";
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
// We might have been the first responder without actually editing.
|
||||
if (_isEditing && CPTextFieldInputOwner === self)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
}
|
||||
var element = [self _inputElement],
|
||||
newValue = element.value,
|
||||
error = @"";
|
||||
|
||||
// If there is a formatter, always give it a chance to reject the resignation,
|
||||
// even if the value has not changed.
|
||||
if ([self _valueIsValid:newValue] === NO)
|
||||
{
|
||||
element.focus();
|
||||
return NO;
|
||||
}
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
}
|
||||
|
||||
// If there is a formatter, always give it a chance to reject the resignation,
|
||||
// even if the value has not changed.
|
||||
if ([self _valueIsValid:newValue] === NO)
|
||||
{
|
||||
element.focus();
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// When we are no longer the first responder we don't worry about the key status of our window anymore.
|
||||
@@ -679,10 +719,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self _resignFirstKeyResponder];
|
||||
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
if ([self isEditable])
|
||||
{
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
|
||||
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
@@ -755,8 +798,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)_windowDidBecomeKey:(CPNotification)aNotification
|
||||
{
|
||||
if ([[self window] isKeyWindow] && [[self window] firstResponder] === self)
|
||||
[self _becomeFirstKeyResponder];
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
var wind = [self window];
|
||||
|
||||
if ([wind isKeyWindow] && [wind firstResponder] === self)
|
||||
if (![self _becomeFirstKeyResponder])
|
||||
[wind makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
- (BOOL)_valueIsValid:(CPString)aValue
|
||||
@@ -765,7 +814,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
var error = @"";
|
||||
|
||||
if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO)
|
||||
if ([self _setStringValue:aValue isNewValue:NO errorDescription:@ref(error)] === NO)
|
||||
{
|
||||
var acceptInvalidValue = NO;
|
||||
|
||||
@@ -791,13 +840,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
/*!
|
||||
Only text fields that can become first responder accepts first mouse.
|
||||
Only text fields that can become first responder accept first mouse.
|
||||
*/
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
{
|
||||
return [self acceptsFirstResponder];
|
||||
}
|
||||
|
||||
- (void)_didEdit
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
// Don't track! (ever?)
|
||||
@@ -824,7 +884,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||
if (![self isEnabled] || !([self isSelectable] || [self isEditable]))
|
||||
[[self nextResponder] mouseUp:anEvent];
|
||||
else if ([self isSelectable])
|
||||
{
|
||||
@@ -836,13 +896,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldCachedSelectStartFunction = nil
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
}
|
||||
|
||||
// TODO clickCount === 2 should select the clicked word.
|
||||
|
||||
if ([[CPApp currentEvent] clickCount] === 3)
|
||||
{
|
||||
[self selectText:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||
if (![self isEnabled] || !([self isSelectable] || [self isEditable]))
|
||||
[[self nextResponder] mouseDragged:anEvent];
|
||||
else if ([self isSelectable])
|
||||
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
@@ -850,26 +919,21 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
[self _didEdit];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
@@ -902,11 +966,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
[self _didEdit];
|
||||
}
|
||||
|
||||
if ([self _valueIsValid:_stringValue])
|
||||
@@ -919,7 +987,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
|
||||
}
|
||||
|
||||
// If there is no target action, or the sendAction call returns
|
||||
@@ -945,6 +1013,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
|
||||
{
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var oldValue = _stringValue,
|
||||
@@ -957,13 +1028,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
// NOTE: _stringValue is now the current input element value
|
||||
if (oldValue !== _stringValue)
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
[self _didEdit];
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1006,7 +1071,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
This should only be invoked when the underlying text element's value has changed.
|
||||
*/
|
||||
@@ -1015,8 +1079,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
/*!
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
If there is a formatter and formatting fails, returns NO. Otherwise returns YES.
|
||||
*/
|
||||
@@ -1032,7 +1095,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
var object = nil;
|
||||
|
||||
if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError])
|
||||
if ([formatter getObjectValue:@ref(object) forString:aValue errorDescription:anError])
|
||||
objectValue = object;
|
||||
else
|
||||
{
|
||||
@@ -1071,14 +1134,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
// Formatting failed, get an "empty" object by formatting an empty string.
|
||||
// If that fails, the value is undefined.
|
||||
if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
||||
if ([formatter getObjectValue:@ref(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined;
|
||||
|
||||
[super setObjectValue:value];
|
||||
_stringValue = (value === nil || value === undefined) ? @"" : String(value);
|
||||
}
|
||||
else
|
||||
_stringValue = formattedString;
|
||||
}
|
||||
|
||||
_stringValue = [self stringValue];
|
||||
else
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
@@ -1158,7 +1224,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||
lineBreakMode = [self lineBreakMode],
|
||||
text = (_stringValue || @" "),
|
||||
textSize = _CGSizeMakeCopy(frameSize),
|
||||
textSize = CGSizeMakeCopy(frameSize),
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
textSize.width -= contentInset.left + contentInset.right;
|
||||
@@ -1212,22 +1278,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)_selectText:(id)sender immediately:(BOOL)immediately
|
||||
{
|
||||
// Selecting the text in a field makes it the first responder
|
||||
if (([self isEditable] || [self isSelectable]))
|
||||
if ([self isEditable] || [self isSelectable])
|
||||
{
|
||||
var wind = [self window];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement];
|
||||
|
||||
if ([wind firstResponder] === self)
|
||||
if ([self isEditable])
|
||||
{
|
||||
if (immediately)
|
||||
element.select();
|
||||
else
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
var element = [self _inputElement];
|
||||
|
||||
if ([wind firstResponder] === self)
|
||||
{
|
||||
if (immediately)
|
||||
element.select();
|
||||
else
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
}
|
||||
else if (wind !== nil && [wind makeFirstResponder:self])
|
||||
[self _selectText:sender immediately:immediately];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setSelectedRange:CPMakeRange(0, _stringValue.length)];
|
||||
}
|
||||
else if (wind !== nil && [wind makeFirstResponder:self])
|
||||
[self _selectText:sender immediately:immediately];
|
||||
#else
|
||||
// Even if we can't actually select the text we need to preserve the first
|
||||
// responder side effect.
|
||||
@@ -1240,36 +1313,70 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)copy:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
// First write to the Cappuccino clipboard.
|
||||
var stringToCopy = nil;
|
||||
|
||||
if ([self isEditable])
|
||||
{
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 1)
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
stringForPasting = [_stringValue substringWithRange:selectedRange];
|
||||
stringToCopy = [_stringValue substringWithRange:selectedRange];
|
||||
}
|
||||
else
|
||||
{
|
||||
// selectedRange won't work if we're displaying our text using a <div>. Instead we have to ask the browser
|
||||
// what's selected and hope it's right in a Cappuccino context as well.
|
||||
#if PLATFORM(DOM)
|
||||
stringToCopy = [[[self window] platformWindow] _selectedText];
|
||||
#endif
|
||||
}
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringToCopy forType:CPStringPboardType];
|
||||
|
||||
if ([CPPlatform isBrowser])
|
||||
{
|
||||
// Then also allow the browser to capture the copied text into the system clipboard.
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cut:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self copy:sender];
|
||||
|
||||
if (![self isEditable])
|
||||
return;
|
||||
|
||||
if (![[CPApp currentEvent] _platformIsEffectingCutOrPaste])
|
||||
{
|
||||
[self copy:sender];
|
||||
[self deleteBackward:sender];
|
||||
}
|
||||
// If we don't have an oninput listener, we won't detect the change made by the cut and need to fake a key up "soon".
|
||||
else if (!CPFeatureIsCompatible(CPInputOnInputEventFeature))
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
else
|
||||
{
|
||||
// Allow the browser's standard cut handling. This should also result in the deleteBackward: happening.
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
// If we don't have an oninput listener, we won't detect the change made by the cut and need to fake a key up "soon".
|
||||
if (!CPFeatureIsCompatible(CPInputOnInputEventFeature))
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paste:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
if (![[CPApp currentEvent] _platformIsEffectingCutOrPaste])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
@@ -1283,15 +1390,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self _didEdit];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
}
|
||||
// If we don't have an oninput listener, we won't detect the change made by the cut and need to fake a key up "soon".
|
||||
else if (!CPFeatureIsCompatible(CPInputOnInputEventFeature))
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
else
|
||||
{
|
||||
// Allow the browser's standard paste handling.
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
if (!CPFeatureIsCompatible(CPInputOnInputEventFeature))
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPRange)selectedRange
|
||||
{
|
||||
// TODO Need a way to figure out the selected range if we're not using an input. Need
|
||||
// to get whole document selection and somehow see which part is inside of this text field.
|
||||
if ([[self window] firstResponder] !== self)
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
@@ -1335,35 +1451,48 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
if (![self isEditable])
|
||||
{
|
||||
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||
{
|
||||
inputElement.selectionStart = aRange.location;
|
||||
inputElement.selectionEnd = CPMaxRange(aRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
existingRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
// No input element - selectable text field only.
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
||||
|
||||
if (range.inRange(existingRange))
|
||||
if (contentView)
|
||||
[contentView setSelectedRange:aRange];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input element
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
{
|
||||
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||
{
|
||||
range.collapse(true);
|
||||
range.move('character', aRange.location);
|
||||
range.moveEnd('character', aRange.length);
|
||||
range.select();
|
||||
inputElement.selectionStart = aRange.location;
|
||||
inputElement.selectionEnd = CPMaxRange(aRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
existingRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
|
||||
if (range.inRange(existingRange))
|
||||
{
|
||||
range.collapse(true);
|
||||
range.move('character', aRange.location);
|
||||
range.moveEnd('character', aRange.length);
|
||||
range.select();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1374,18 +1503,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
{
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 2)
|
||||
return;
|
||||
if (selectedRange.length < 1)
|
||||
{
|
||||
if (selectedRange.location < 1)
|
||||
return;
|
||||
|
||||
selectedRange.location += 1;
|
||||
selectedRange.length -= 1;
|
||||
// Delete a single element backward from the insertion point if there's no selection.
|
||||
selectedRange.location -= 1;
|
||||
selectedRange.length += 1;
|
||||
}
|
||||
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
[self _didEdit];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// Since we just performed the deletion manually, we don't need the browser to do anything else.
|
||||
// (Previously we would allow the event to propagate for the browser to delete 1 character only,
|
||||
// and we'd delete the rest manually. But this meant that if deleteBackward: was called without
|
||||
// it being a browser backspace event, 1 character would be left behind.)
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)delete:(id)sender
|
||||
{
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
// delete: only works when there's a selection (as opposed to deleteForward: and deleteBackward:).
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 1)
|
||||
return;
|
||||
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
[self _didEdit];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// Since we just performed the deletion manually, we don't need the browser to do anything else.
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)deleteForward:(id)sender
|
||||
{
|
||||
if (!([self isEnabled] && [self isEditable]))
|
||||
return;
|
||||
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 1)
|
||||
{
|
||||
if (selectedRange.location + 1 >= _stringValue.length)
|
||||
return;
|
||||
|
||||
selectedRange.length += 1;
|
||||
}
|
||||
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
[self _didEdit];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// Since we just performed the deletion manually, we don't need the browser to do anything else.
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark Setting the Delegate
|
||||
@@ -1452,14 +1647,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, contentInset);
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, bezelInset);
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
@@ -1477,7 +1672,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -1485,7 +1680,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
else
|
||||
{
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -1552,6 +1747,65 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Overrides
|
||||
|
||||
- (void)viewDidHide
|
||||
{
|
||||
[super viewDidHide];
|
||||
|
||||
if ([[self window] firstResponder] === self)
|
||||
[self _resignFirstKeyResponder];
|
||||
}
|
||||
|
||||
- (void)viewDidUnhide
|
||||
{
|
||||
[super viewDidUnhide];
|
||||
|
||||
if ([self isEditable] && [[self window] firstResponder] === self)
|
||||
[self _becomeFirstKeyResponder];
|
||||
}
|
||||
|
||||
- (BOOL)validateUserInterfaceItem:(id /*<CPValidatedUserInterfaceItem>*/)anItem
|
||||
{
|
||||
var theAction = [anItem action];
|
||||
|
||||
if (![self isEditable] && (theAction == @selector(cut:) || theAction == @selector(paste:) || theAction == @selector(delete:)))
|
||||
return NO;
|
||||
|
||||
// FIXME - [self selectedRange] is always empty if we're not an editable field, so we must assume yes here.
|
||||
if (![self isEditable])
|
||||
return YES;
|
||||
|
||||
if (theAction == @selector(copy:) || theAction == @selector(cut:) || theAction == @selector(delete:))
|
||||
return [self selectedRange].length;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (BOOL)_isWithinUsablePlatformRect
|
||||
{
|
||||
// Make sure the text field is completely within the platform window
|
||||
// so the browser will not scroll it into view.
|
||||
|
||||
var wind = [self window];
|
||||
|
||||
// If the field is not yet within a window, it can't be first responder
|
||||
if (!wind)
|
||||
return NO;
|
||||
|
||||
var frame = [self convertRectToBase:[self bounds]],
|
||||
usableRect = [[wind platformWindow] usableContentFrame];
|
||||
|
||||
frame.origin = [wind convertBaseToGlobal:frame.origin];
|
||||
|
||||
return (CGRectGetMinX(frame) >= CGRectGetMinX(usableRect) &&
|
||||
CGRectGetMaxX(frame) <= CGRectGetMaxX(usableRect) &&
|
||||
CGRectGetMinY(frame) >= CGRectGetMinY(usableRect) &&
|
||||
CGRectGetMaxY(frame) <= CGRectGetMaxY(usableRect));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var secureStringForString = function(aString)
|
||||
@@ -1628,10 +1882,8 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
@end
|
||||
|
||||
@implementation _CPTextFieldValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
@@ -1649,8 +1901,28 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (!aValue || (aValue.isa && [aValue isMemberOfClass:CPNull]))
|
||||
[_source setPlaceholderString:[self _placeholderForMarker:CPNullMarker]];
|
||||
|
||||
[_source setObjectValue:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTextFieldPatternValueBinder : CPValueWithPatternBinding
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setPlaceholderString:aValue];
|
||||
[_source setObjectValue:nil];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (!aValue || (aValue.isa && [aValue isMemberOfClass:CPNull]))
|
||||
[_source setPlaceholderString:[self _placeholderForMarker:CPNullMarker]];
|
||||
|
||||
[_source setObjectValue:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+37
-30
@@ -85,7 +85,7 @@ var CPThemesByName = { },
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_attributes = [CPDictionary dictionary];
|
||||
_attributes = @{};
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
}
|
||||
@@ -270,7 +270,7 @@ var CPThemesByName = { },
|
||||
|
||||
if (!attributes)
|
||||
{
|
||||
attributes = [CPDictionary dictionary];
|
||||
attributes = @{};
|
||||
|
||||
[_attributes setObject:attributes forKey:aClass];
|
||||
}
|
||||
@@ -404,25 +404,25 @@ function CPThemeStateName(aState)
|
||||
return name;
|
||||
}
|
||||
|
||||
CPThemeStateNames[0] = "normal";
|
||||
CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHovered = CPThemeState("hovered");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
CPThemeStateEditing = CPThemeState("editing");
|
||||
CPThemeStateVertical = CPThemeState("vertical");
|
||||
CPThemeStateDefault = CPThemeState("default");
|
||||
CPThemeStateCircular = CPThemeState("circular");
|
||||
CPThemeStateAutocompleting = CPThemeState("autocompleting");
|
||||
CPThemeStateMainWindow = CPThemeState("mainWindow");
|
||||
CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
CPThemeStateNames[0] = "normal";
|
||||
CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHovered = CPThemeState("hovered");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
CPThemeStateEditing = CPThemeState("editing");
|
||||
CPThemeStateVertical = CPThemeState("vertical");
|
||||
CPThemeStateDefault = CPThemeState("default");
|
||||
CPThemeStateCircular = CPThemeState("circular");
|
||||
CPThemeStateAutocompleting = CPThemeState("autocompleting");
|
||||
CPThemeStateMainWindow = CPThemeState("mainWindow");
|
||||
CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
|
||||
@implementation _CPThemeAttribute : CPObject
|
||||
{
|
||||
@@ -431,7 +431,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
CPDictionary _values @accessors(readonly, getter=values);
|
||||
|
||||
JSObject _cache;
|
||||
_CPThemeAttribute _parentAttribute;
|
||||
_CPThemeAttribute _themeDefaultAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
@@ -443,7 +443,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
_cache = { };
|
||||
_name = aName;
|
||||
_defaultValue = aDefaultValue;
|
||||
_values = [CPDictionary dictionary];
|
||||
_values = @{};
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -474,9 +474,9 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
_cache = {};
|
||||
|
||||
if (aValue === undefined || aValue === nil)
|
||||
_values = [CPDictionary dictionary];
|
||||
_values = @{};
|
||||
else
|
||||
_values = [CPDictionary dictionaryWithObject:aValue forKey:String(CPThemeStateNormal)];
|
||||
_values = @{ String(CPThemeStateNormal): aValue };
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forState:(CPThemeState)aState
|
||||
@@ -542,11 +542,18 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
}
|
||||
|
||||
if (value === undefined || value === nil)
|
||||
value = [_parentAttribute valueForState:aState];
|
||||
value = [_themeDefaultAttribute valueForState:aState];
|
||||
|
||||
if (value === undefined || value === nil)
|
||||
{
|
||||
value = _defaultValue;
|
||||
|
||||
// Class theme attributes cannot use nil because it's a dictionary.
|
||||
// So transform CPNull into nil.
|
||||
if (value === [CPNull null])
|
||||
value = nil;
|
||||
}
|
||||
|
||||
_cache[aState] = value;
|
||||
|
||||
return value;
|
||||
@@ -554,11 +561,11 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
|
||||
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_parentAttribute === anAttribute)
|
||||
if (_themeDefaultAttribute === anAttribute)
|
||||
return;
|
||||
|
||||
_cache = { };
|
||||
_parentAttribute = anAttribute;
|
||||
_themeDefaultAttribute = anAttribute;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
@@ -585,7 +592,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
|
||||
_name = [aCoder decodeObjectForKey:@"name"];
|
||||
_defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
|
||||
_values = [CPDictionary dictionary];
|
||||
_values = @{};
|
||||
|
||||
if ([aCoder containsValueForKey:@"value"])
|
||||
{
|
||||
@@ -633,7 +640,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
}
|
||||
else
|
||||
{
|
||||
var encodedValues = [CPDictionary dictionary];
|
||||
var encodedValues = @{};
|
||||
|
||||
while (count--)
|
||||
{
|
||||
|
||||
Executable → Regular
+275
-77
@@ -20,22 +20,22 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/CPRange.h"
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import <Foundation/CPCharacterSet.j>
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
@import <Foundation/CPTimer.j>
|
||||
|
||||
@import "_CPAutocompleteMenu.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPAutocompleteMenu.j"
|
||||
|
||||
@global CPApp
|
||||
@global CPTextFieldDidFocusNotification
|
||||
@global CPTextFieldDidBlurNotification
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
@@ -59,6 +59,9 @@ var CPScrollDestinationNone = 0,
|
||||
CPScrollDestinationLeft = 1,
|
||||
CPScrollDestinationRight = 2;
|
||||
|
||||
CPTokenFieldDisclosureButtonType = 0;
|
||||
CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
@implementation CPTokenField : CPTextField
|
||||
{
|
||||
CPScrollView _tokenScrollView;
|
||||
@@ -76,6 +79,8 @@ var CPScrollDestinationNone = 0,
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _shouldNotifyTarget;
|
||||
|
||||
int _buttonType @accessors(property=buttonType);
|
||||
}
|
||||
|
||||
+ (CPCharacterSet)defaultTokenizingCharacterSet
|
||||
@@ -93,9 +98,9 @@ var CPScrollDestinationNone = 0,
|
||||
return "tokenfield";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObject:_CGInsetMakeZero() forKey:@"editor-inset"];
|
||||
return @{ @"editor-inset": CGInsetMakeZero() };
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
@@ -104,6 +109,7 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
_completionDelay = [[self class] defaultCompletionDelay];
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
_buttonType = CPTokenFieldDisclosureButtonType;
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
@@ -118,7 +124,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedRange = _CPMakeRange(0, 0);
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
var frame = [self frame];
|
||||
|
||||
@@ -208,7 +214,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
if (delegateApprovedObjectsCount)
|
||||
location += delegateApprovedObjectsCount;
|
||||
_selectedRange = _CPMakeRange(location, 0);
|
||||
_selectedRange = CPMakeRange(location, 0);
|
||||
|
||||
[self _inputElement].value = @"";
|
||||
[self setNeedsLayout];
|
||||
@@ -228,12 +234,12 @@ var CPScrollDestinationNone = 0,
|
||||
if (indexOfToken == CPNotFound)
|
||||
{
|
||||
if (!extend)
|
||||
_selectedRange = _CPMakeRange([[self _tokens] count], 0);
|
||||
_selectedRange = CPMakeRange([[self _tokens] count], 0);
|
||||
}
|
||||
else if (extend)
|
||||
_selectedRange = CPUnionRange(_selectedRange, _CPMakeRange(indexOfToken, 1));
|
||||
_selectedRange = CPUnionRange(_selectedRange, CPMakeRange(indexOfToken, 1));
|
||||
else
|
||||
_selectedRange = _CPMakeRange(indexOfToken, 1);
|
||||
_selectedRange = CPMakeRange(indexOfToken, 1);
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -243,7 +249,7 @@ var CPScrollDestinationNone = 0,
|
||||
var indexOfToken = [[self _tokens] indexOfObject:token];
|
||||
|
||||
if (CPLocationInRange(indexOfToken, _selectedRange))
|
||||
_selectedRange = _CPMakeRange(MAX(indexOfToken, _selectedRange.location), MIN(_selectedRange.length, indexOfToken - _selectedRange.location));
|
||||
_selectedRange = CPMakeRange(MAX(indexOfToken, _selectedRange.location), MIN(_selectedRange.length, indexOfToken - _selectedRange.location));
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -296,7 +302,7 @@ var CPScrollDestinationNone = 0,
|
||||
[self setObjectValue:tokens];
|
||||
// setObjectValue moves the cursor to the end of the selection. We want it to stay
|
||||
// where the selected tokens were.
|
||||
_selectedRange = _CPMakeRange(collapsedSelection, 0);
|
||||
_selectedRange = CPMakeRange(collapsedSelection, 0);
|
||||
|
||||
[self _controlTextDidChange];
|
||||
}
|
||||
@@ -323,14 +329,21 @@ var CPScrollDestinationNone = 0,
|
||||
// As long as we are the first responder we need to monitor the key status of our window.
|
||||
[self _setObserveWindowKeyNotifications:YES];
|
||||
|
||||
[self scrollRectToVisible:[self bounds]];
|
||||
|
||||
if ([[self window] isKeyWindow])
|
||||
[self _becomeFirstKeyResponder];
|
||||
return [self _becomeFirstKeyResponder];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_becomeFirstKeyResponder
|
||||
- (BOOL)_becomeFirstKeyResponder
|
||||
{
|
||||
// If the token field is still not completely on screen, refuse to become
|
||||
// first responder, because the browser will scroll it into view out of our control.
|
||||
if (![self _isWithinUsablePlatformRect])
|
||||
return NO;
|
||||
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -350,11 +363,16 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
switch ([self alignment])
|
||||
{
|
||||
case CPCenterTextAlignment: element.style.textAlign = "center";
|
||||
break;
|
||||
case CPRightTextAlignment: element.style.textAlign = "right";
|
||||
break;
|
||||
default: element.style.textAlign = "left";
|
||||
case CPCenterTextAlignment:
|
||||
element.style.textAlign = "center";
|
||||
break;
|
||||
|
||||
case CPRightTextAlignment:
|
||||
element.style.textAlign = "right";
|
||||
break;
|
||||
|
||||
default:
|
||||
element.style.textAlign = "left";
|
||||
}
|
||||
|
||||
var contentRect = [self contentRectForBounds:[self bounds]];
|
||||
@@ -364,16 +382,21 @@ var CPScrollDestinationNone = 0,
|
||||
element.style.width = CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = [font defaultLineHeightForFont] + "px";
|
||||
|
||||
[_tokenScrollView documentView]._DOMElement.appendChild(element);
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
element.focus();
|
||||
CPTokenFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
[_tokenScrollView documentView]._DOMElement.appendChild(element);
|
||||
|
||||
//post CPControlTextDidBeginEditingNotification
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
//post CPControlTextDidBeginEditingNotification
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
element.focus();
|
||||
CPTokenFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
}, 0.0);
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
@@ -389,6 +412,8 @@ var CPScrollDestinationNone = 0,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
@@ -403,12 +428,14 @@ var CPScrollDestinationNone = 0,
|
||||
if (_shouldNotifyTarget)
|
||||
{
|
||||
_shouldNotifyTarget = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
|
||||
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -470,7 +497,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
- (void)_mouseUpOnToken:(_CPTokenFieldToken)aToken withEvent:(CPEvent)anEvent
|
||||
{
|
||||
if (_mouseDownEvent && _CGPointEqualToPoint([_mouseDownEvent locationInWindow], [anEvent locationInWindow]))
|
||||
if (_mouseDownEvent && CGPointEqualToPoint([_mouseDownEvent locationInWindow], [anEvent locationInWindow]))
|
||||
{
|
||||
[self _selectToken:aToken byExtendingSelection:[anEvent modifierFlags] & CPShiftKeyMask];
|
||||
[[self window] makeFirstResponder:self];
|
||||
@@ -561,7 +588,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
if (newToken === nil)
|
||||
{
|
||||
newToken = [[_CPTokenFieldToken alloc] init];
|
||||
newToken = [_CPTokenFieldToken new];
|
||||
[newToken setTokenField:self];
|
||||
[newToken setRepresentedObject:tokenObject];
|
||||
[newToken setStringValue:tokenValue];
|
||||
@@ -618,7 +645,7 @@ var CPScrollDestinationNone = 0,
|
||||
[[self _tokens] makeObjectsPerformSelector:@selector(setEditable:) withObject:shouldBeEditable];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
_shouldNotifyTarget = NO;
|
||||
[super sendAction:anAction to:anObject];
|
||||
@@ -626,7 +653,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
// Incredible hack to disable supers implementation
|
||||
// so it cannot change our object value and break the tokenfield
|
||||
- (void)_setStringValue:(id)aValue
|
||||
- (BOOL)_setStringValue:(CPString)aValue
|
||||
{
|
||||
}
|
||||
|
||||
@@ -652,10 +679,10 @@ var CPScrollDestinationNone = 0,
|
||||
return CPTextFieldBlurFunction(
|
||||
anEvent,
|
||||
CPTokenFieldInputOwner,
|
||||
[CPTokenFieldInputOwner._tokenScrollView documentView]._DOMElement,
|
||||
CPTokenFieldInputOwner ? [CPTokenFieldInputOwner._tokenScrollView documentView]._DOMElement : nil,
|
||||
CPTokenFieldDOMInputElement,
|
||||
CPTokenFieldInputResigning,
|
||||
AT_REF(CPTokenFieldInputDidBlur));
|
||||
@ref(CPTokenFieldInputDidBlur));
|
||||
};
|
||||
|
||||
// FIXME make this not onblur
|
||||
@@ -806,7 +833,7 @@ var CPScrollDestinationNone = 0,
|
||||
if (_selectedRange.length)
|
||||
{
|
||||
// Place the cursor at the end of the selection and collapse.
|
||||
_selectedRange.location = _CPMaxRange(_selectedRange);
|
||||
_selectedRange.location = CPMaxRange(_selectedRange);
|
||||
_selectedRange.length = 0;
|
||||
}
|
||||
else
|
||||
@@ -827,7 +854,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
- (void)moveRightAndModifySelection:(id)sender
|
||||
{
|
||||
if (_CPMaxRange(_selectedRange) < [[self _tokens] count] && [self _editorValue] == "")
|
||||
if (CPMaxRange(_selectedRange) < [[self _tokens] count] && [self _editorValue] == "")
|
||||
{
|
||||
// Leave the selection location in place but include the next token to the right.
|
||||
_selectedRange.length++;
|
||||
@@ -906,7 +933,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
// Finish any editing.
|
||||
[self _autocomplete];
|
||||
_selectedRange = _CPMakeRange(0, [[self _tokens] count]);
|
||||
_selectedRange = CPMakeRange(0, [[self _tokens] count]);
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -998,7 +1025,7 @@ var CPScrollDestinationNone = 0,
|
||||
return;
|
||||
|
||||
// Move each token into the right position.
|
||||
var contentRect = _CGRectMakeCopy([contentView bounds]),
|
||||
var contentRect = CGRectMakeCopy([contentView bounds]),
|
||||
contentOrigin = contentRect.origin,
|
||||
contentSize = contentRect.size,
|
||||
offset = CGPointMake(contentOrigin.x, contentOrigin.y),
|
||||
@@ -1015,11 +1042,11 @@ var CPScrollDestinationNone = 0,
|
||||
// Get the height of a typical token, or a token token if you will.
|
||||
[tokenToken sizeToFit];
|
||||
|
||||
var tokenHeight = _CGRectGetHeight([tokenToken bounds]);
|
||||
var tokenHeight = CGRectGetHeight([tokenToken bounds]);
|
||||
|
||||
var fitAndFrame = function(width, height)
|
||||
{
|
||||
var r = _CGRectMake(0, 0, width, height);
|
||||
var r = CGRectMake(0, 0, width, height);
|
||||
|
||||
if (offset.x + width >= contentSize.width && offset.x > contentOrigin.x)
|
||||
{
|
||||
@@ -1032,8 +1059,8 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
// Make sure the frame fits.
|
||||
var scrollHeight = offset.y + tokenHeight + CEIL(spaceBetweenTokens.height / 2.0);
|
||||
if (_CGRectGetHeight([contentView bounds]) < scrollHeight)
|
||||
[contentView setFrameSize:_CGSizeMake(_CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
|
||||
if (CGRectGetHeight([contentView bounds]) < scrollHeight)
|
||||
[contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
|
||||
|
||||
offset.x += width + spaceBetweenTokens.width;
|
||||
|
||||
@@ -1067,12 +1094,12 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
// When editing, always scroll to the cursor.
|
||||
if (_selectedRange.length == 0)
|
||||
[[_tokenScrollView documentView] scrollPoint:_CGPointMake(0, _inputFrame.origin.y)];
|
||||
[[_tokenScrollView documentView] scrollPoint:CGPointMake(0, _inputFrame.origin.y)];
|
||||
};
|
||||
|
||||
for (var i = 0, count = [tokens count]; i < count; i++)
|
||||
{
|
||||
if (isEditing && !_selectedRange.length && i == _CPMaxRange(_selectedRange))
|
||||
if (isEditing && !_selectedRange.length && i == CPMaxRange(_selectedRange))
|
||||
placeEditor(false);
|
||||
|
||||
var tokenView = [tokens objectAtIndex:i];
|
||||
@@ -1089,9 +1116,11 @@ var CPScrollDestinationNone = 0,
|
||||
tokenFrame = fitAndFrame(tokenViewSize.width, tokenViewSize.height);
|
||||
|
||||
[tokenView setFrame:tokenFrame];
|
||||
|
||||
[tokenView setButtonType:_buttonType];
|
||||
}
|
||||
|
||||
if (isEditing && !_selectedRange.length && _CPMaxRange(_selectedRange) >= [tokens count])
|
||||
if (isEditing && !_selectedRange.length && CPMaxRange(_selectedRange) >= [tokens count])
|
||||
placeEditor(true);
|
||||
|
||||
// Hide the editor if there are selected tokens, but still keep it active
|
||||
@@ -1112,8 +1141,8 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
// Trim off any excess height downwards (in case we shrank).
|
||||
var scrollHeight = offset.y + tokenHeight;
|
||||
if (_CGRectGetHeight([contentView bounds]) > scrollHeight)
|
||||
[contentView setFrameSize:_CGSizeMake(_CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
|
||||
if (CGRectGetHeight([contentView bounds]) > scrollHeight)
|
||||
[contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
|
||||
|
||||
if (_shouldScrollTo !== CPScrollDestinationNone)
|
||||
{
|
||||
@@ -1125,7 +1154,7 @@ var CPScrollDestinationNone = 0,
|
||||
if (scrollToToken === CPScrollDestinationLeft)
|
||||
scrollToToken = tokens[_selectedRange.location]
|
||||
else if (scrollToToken === CPScrollDestinationRight)
|
||||
scrollToToken = tokens[MAX(0, _CPMaxRange(_selectedRange) - 1)];
|
||||
scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
|
||||
[self _scrollTokenViewToVisible:scrollToToken];
|
||||
}
|
||||
|
||||
@@ -1138,7 +1167,7 @@ var CPScrollDestinationNone = 0,
|
||||
if (!aToken)
|
||||
return;
|
||||
|
||||
return [[_tokenScrollView documentView] scrollPoint:_CGPointMake(0, [aToken frameOrigin].y)];
|
||||
return [[_tokenScrollView documentView] scrollPoint:CGPointMake(0, [aToken frameOrigin].y)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1170,7 +1199,7 @@ var CPScrollDestinationNone = 0,
|
||||
- (CGPoint)_completionOrigin:(_CPAutocompleteMenu)anAutocompleteMenu
|
||||
{
|
||||
var relativeFrame = _inputFrame ? [[_tokenScrollView documentView] convertRect:_inputFrame toView:self ] : [self bounds];
|
||||
return _CGPointMake(_CGRectGetMinX(relativeFrame), _CGRectGetMaxY(relativeFrame));
|
||||
return CGPointMake(CGRectGetMinX(relativeFrame), CGRectGetMaxY(relativeFrame));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1241,6 +1270,30 @@ var CPScrollDestinationNone = 0,
|
||||
return aString;
|
||||
}
|
||||
|
||||
- (BOOL)_hasMenuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
return [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPMenu)_menuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
{
|
||||
var hasMenu = [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
if (hasMenu)
|
||||
return [delegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// We put the string on the pasteboard before calling this delegate method.
|
||||
// By default, we write the NSStringPboardType as well as an array of NSStrings.
|
||||
// - (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard;
|
||||
@@ -1265,13 +1318,25 @@ var CPScrollDestinationNone = 0,
|
||||
[_autocompleteMenu _hideCompletions];
|
||||
}
|
||||
|
||||
|
||||
- (void)setButtonType:(int)aButtonType
|
||||
{
|
||||
if (_buttonType === aButtonType)
|
||||
return;
|
||||
|
||||
_buttonType = aButtonType;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTokenFieldToken : CPTextField
|
||||
{
|
||||
_CPTokenFieldTokenCloseButton _deleteButton;
|
||||
CPTokenField _tokenField;
|
||||
id _representedObject;
|
||||
_CPTokenFieldTokenCloseButton _deleteButton;
|
||||
_CPTokenFieldTokenDisclosureButton _disclosureButton;
|
||||
CPTokenField _tokenField;
|
||||
id _representedObject;
|
||||
int _buttonType;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -1288,12 +1353,10 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
[self setEditable:NO];
|
||||
[self setHighlighted:NO];
|
||||
[self setBezeled:YES];
|
||||
[self setButtonType:CPTokenFieldDisclosureButtonType];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1317,6 +1380,7 @@ var CPScrollDestinationNone = 0,
|
||||
- (void)setRepresentedObject:(id)representedObject
|
||||
{
|
||||
_representedObject = representedObject;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
@@ -1329,9 +1393,12 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
var r = [super setThemeState:aState];
|
||||
|
||||
// Share hover state with the delete button.
|
||||
if (r && aState === CPThemeStateHovered)
|
||||
[_deleteButton setThemeState:aState];
|
||||
// Share hover state with the disclosure and delete buttons.
|
||||
if (aState & CPThemeStateHovered)
|
||||
{
|
||||
[_disclosureButton setThemeState:CPThemeStateHovered];
|
||||
[_deleteButton setThemeState:CPThemeStateHovered];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1340,16 +1407,19 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
var r = [super unsetThemeState:aState];
|
||||
|
||||
// Share hover state with the delete button.
|
||||
if (r && aState === CPThemeStateHovered)
|
||||
[_deleteButton unsetThemeState:aState];
|
||||
// Share hover state with the disclosure and delete button.
|
||||
if (aState & CPThemeStateHovered)
|
||||
{
|
||||
[_disclosureButton unsetThemeState:CPThemeStateHovered];
|
||||
[_deleteButton unsetThemeState:CPThemeStateHovered];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
{
|
||||
var size = _CGSizeMakeZero(),
|
||||
var size = CGSizeMakeZero(),
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
@@ -1360,6 +1430,47 @@ var CPScrollDestinationNone = 0,
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)setButtonType:(int)aButtonType
|
||||
{
|
||||
if (_buttonType === aButtonType)
|
||||
return;
|
||||
|
||||
_buttonType = aButtonType;
|
||||
|
||||
if (_buttonType === CPTokenFieldDisclosureButtonType)
|
||||
{
|
||||
if (_deleteButton)
|
||||
{
|
||||
[_deleteButton removeFromSuperview];
|
||||
_deleteButton = nil;
|
||||
}
|
||||
|
||||
if (!_disclosureButton)
|
||||
{
|
||||
_disclosureButton = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_disclosureButton];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_disclosureButton)
|
||||
{
|
||||
[_disclosureButton removeFromSuperview];
|
||||
_disclosureButton = nil;
|
||||
}
|
||||
|
||||
if (!_deleteButton)
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
[_deleteButton setTarget:self];
|
||||
[_deleteButton setAction:@selector(_delete:)];
|
||||
}
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
@@ -1368,17 +1479,33 @@ var CPScrollDestinationNone = 0,
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (bezelView)
|
||||
if (bezelView && _tokenField)
|
||||
{
|
||||
[_deleteButton setTarget:self];
|
||||
[_deleteButton setAction:@selector(_delete:)];
|
||||
[_deleteButton setEnabled:[self isEditable]];
|
||||
switch (_buttonType)
|
||||
{
|
||||
case CPTokenFieldDisclosureButtonType:
|
||||
var shouldBeEnabled = [self hasMenu];
|
||||
[_disclosureButton setHidden:!shouldBeEnabled];
|
||||
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
if (shouldBeEnabled)
|
||||
[_disclosureButton setMenu:[self menu]];
|
||||
|
||||
[_deleteButton setFrame:_CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_disclosureButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_disclosureButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_disclosureButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
break;
|
||||
case CPTokenFieldDeleteButtonType:
|
||||
[_deleteButton setEnabled:[self isEditable] && [self isEnabled]];
|
||||
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_deleteButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1398,20 +1525,27 @@ var CPScrollDestinationNone = 0,
|
||||
[_tokenField _deleteToken:self];
|
||||
}
|
||||
|
||||
- (BOOL)hasMenu
|
||||
{
|
||||
return [_tokenField _hasMenuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
- (CPMenu)menu
|
||||
{
|
||||
return [_tokenField _menuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
Theming hook.
|
||||
*/
|
||||
@implementation _CPTokenFieldTokenCloseButton : CPButton
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
var attributes = [CPButton themeAttributes];
|
||||
|
||||
[attributes setObject:_CGPointMake(15, 5) forKey:@"offset"];
|
||||
[attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
|
||||
|
||||
return attributes;
|
||||
}
|
||||
@@ -1421,11 +1555,73 @@ var CPScrollDestinationNone = 0,
|
||||
return "tokenfield-token-close-button";
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTokenFieldTokenDisclosureButton : CPPopUpButton
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
var attributes = [CPButton themeAttributes];
|
||||
|
||||
[attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "tokenfield-token-disclosure-button";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [self initWithFrame:aFrame pullsDown:YES])
|
||||
{
|
||||
[self setBordered:YES];
|
||||
[super setTitle:@""];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
- (void)synchronizeTitleAndSelectedItem
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay",
|
||||
CPTokenFieldButtonTypeKey = "CPTokenFieldButtonTypeKey";
|
||||
|
||||
@implementation CPTokenField (CPCoding)
|
||||
|
||||
@@ -1437,6 +1633,7 @@ var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSe
|
||||
{
|
||||
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
|
||||
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
|
||||
_buttonType = [aCoder decodeIntForKey:CPTokenFieldButtonTypeKey] || CPTokenFieldDisclosureButtonType;
|
||||
|
||||
[self _init];
|
||||
|
||||
@@ -1453,6 +1650,7 @@ var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSe
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
[aCoder encodeInt:_buttonType forKey:CPTokenFieldButtonTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+35
-52
@@ -93,7 +93,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
BOOL _showsBaselineSeparator;
|
||||
BOOL _allowsUserCustomization;
|
||||
BOOL _isVisible;
|
||||
int _sizeMode @accessors(property=sizeMode);
|
||||
CPToolbarSizeMode _sizeMode @accessors(property=sizeMode);
|
||||
int _desiredHeight;
|
||||
|
||||
id _delegate;
|
||||
@@ -118,8 +118,8 @@ var CPToolbarsByIdentifier = nil,
|
||||
if (self !== [CPToolbar class])
|
||||
return;
|
||||
|
||||
CPToolbarsByIdentifier = [CPDictionary dictionary];
|
||||
CPToolbarConfigurationsByIdentifier = [CPDictionary dictionary];
|
||||
CPToolbarsByIdentifier = @{};
|
||||
CPToolbarConfigurationsByIdentifier = @{};
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -165,15 +165,6 @@ var CPToolbarsByIdentifier = nil,
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Sets the toolbar's display mode. NOT YET IMPLEMENTED.
|
||||
*/
|
||||
- (void)setDisplayMode:(CPToolbarDisplayMode)aDisplayMode
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the toolbar's identifier
|
||||
*/
|
||||
@@ -230,7 +221,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
- (void)_setWindow:(CPWindow)aWindow
|
||||
{
|
||||
if (_window)
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self object:_window];
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:_CPWindowDidChangeFirstResponderNotification object:_window];
|
||||
|
||||
_window = aWindow;
|
||||
|
||||
@@ -603,27 +594,19 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
return @"toolbar-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[10.0,
|
||||
20.0,
|
||||
[CPNull null],
|
||||
[CPNull null],
|
||||
_CGInsetMake(4.0, 4.0, 4.0, 10),
|
||||
59.0,
|
||||
46.0,
|
||||
[CPNull null],
|
||||
CGRectMake(0.0, 0.0, 2.0, 32.0)]
|
||||
forKeys:[
|
||||
@"item-margin",
|
||||
@"extra-item-width",
|
||||
@"extra-item-extra-image",
|
||||
@"extra-item-extra-alternate-image",
|
||||
@"content-inset",
|
||||
@"regular-size-height",
|
||||
@"small-size-height",
|
||||
@"image-item-separator-color",
|
||||
@"image-item-separator-size"]];
|
||||
return @{
|
||||
@"item-margin": 10.0,
|
||||
@"extra-item-width": 20.0,
|
||||
@"extra-item-extra-image": [CPNull null],
|
||||
@"extra-item-extra-alternate-image": [CPNull null],
|
||||
@"content-inset": CGInsetMake(4.0, 4.0, 4.0, 10),
|
||||
@"regular-size-height": 59.0,
|
||||
@"small-size-height": 46.0,
|
||||
@"image-item-separator-color": [CPNull null],
|
||||
@"image-item-separator-size": CGRectMake(0.0, 0.0, 2.0, 32.0),
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -637,7 +620,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
_labelColor = [CPColor blackColor];
|
||||
_labelShadowColor = [CPColor colorWithWhite:1.0 alpha:0.75];
|
||||
|
||||
_additionalItemsButton = [[CPPopUpButton alloc] initWithFrame:_CGRectMake(0.0, 0.0, 10.0, 15.0) pullsDown:YES];
|
||||
_additionalItemsButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 15.0) pullsDown:YES];
|
||||
[_additionalItemsButton setBordered:NO];
|
||||
|
||||
[_additionalItemsButton setImagePosition:CPImageOnly];
|
||||
@@ -687,7 +670,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
{
|
||||
// We begin by recalculating the visible items.
|
||||
var items = [_toolbar items],
|
||||
itemsWidth = _CGRectGetWidth([self bounds]),
|
||||
itemsWidth = CGRectGetWidth([self bounds]),
|
||||
minWidth = _minWidth,
|
||||
// FIXME: This should be a CPSet.
|
||||
invisibleItemsSortedByPriority = [];
|
||||
@@ -774,7 +757,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
// static width (min==max). This handles the case where the user did setView:
|
||||
// with a view of a different size than minSize/maxSize
|
||||
else
|
||||
[view setFrameSize:_CGSizeMake(minSize.width, height)];
|
||||
[view setFrameSize:CGSizeMake(minSize.width, height)];
|
||||
|
||||
[view setHidden:NO];
|
||||
}
|
||||
@@ -809,7 +792,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
remainingSpace += proposedWidth - constrainedWidth;
|
||||
}
|
||||
|
||||
[view setFrameSize:_CGSizeMake(constrainedWidth, height)];
|
||||
[view setFrameSize:CGSizeMake(constrainedWidth, height)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,9 +806,9 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var view = [self viewForItem:_visibleItems[index]],
|
||||
viewWidth = _CGRectGetWidth([view frame]);
|
||||
viewWidth = CGRectGetWidth([view frame]);
|
||||
|
||||
[view setFrame:_CGRectMake(x, y, viewWidth, height)];
|
||||
[view setFrame:CGRectMake(x, y, viewWidth, height)];
|
||||
|
||||
x += viewWidth + [self valueForThemeAttribute:@"item-margin"];
|
||||
}
|
||||
@@ -859,7 +842,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
if (needsAdditionalItemsButton)
|
||||
{
|
||||
[_additionalItemsButton setFrameOrigin:_CGPointMake(itemsWidth + 5.0, (_CGRectGetHeight([self bounds]) - _CGRectGetHeight([_additionalItemsButton frame])) / 2.0)];
|
||||
[_additionalItemsButton setFrameOrigin:CGPointMake(itemsWidth + 5.0, (CGRectGetHeight([self bounds]) - CGRectGetHeight([_additionalItemsButton frame])) / 2.0)];
|
||||
|
||||
[self addSubview:_additionalItemsButton];
|
||||
|
||||
@@ -1002,12 +985,12 @@ var LABEL_MARGIN = 2.0;
|
||||
{
|
||||
_toolbarItem = aToolbarItem;
|
||||
|
||||
_labelField = [[CPTextField alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_labelField setFont:[CPFont systemFontOfSize:11.0]];
|
||||
[_labelField setTextColor:[self FIXME_labelColor]];
|
||||
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||
[_labelField setTextShadowOffset:_CGSizeMake(0.0, 1.0)];
|
||||
[_labelField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_labelField setAutoresizingMask:CPViewWidthSizable | CPViewMinXMargin];
|
||||
|
||||
[self addSubview:_labelField];
|
||||
@@ -1109,8 +1092,8 @@ var LABEL_MARGIN = 2.0;
|
||||
[_labelField setHidden:iconOnly];
|
||||
[_view setHidden:labelOnly];
|
||||
|
||||
_minSize = _CGSizeMake(MAX(_labelSize.width, minSize.width), (labelOnly ? 0 : minSize.height) + (iconOnly ? 0 : _labelSize.height + LABEL_MARGIN));
|
||||
_maxSize = _CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
|
||||
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), (labelOnly ? 0 : minSize.height) + (iconOnly ? 0 : _labelSize.height + LABEL_MARGIN));
|
||||
_maxSize = CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
@@ -1124,14 +1107,14 @@ var LABEL_MARGIN = 2.0;
|
||||
return;
|
||||
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds);
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
if (identifier === CPToolbarSeparatorItemIdentifier)
|
||||
{
|
||||
var itemSeparatorColor = [_toolbar valueForThemeAttribute:@"image-item-separator-color"],
|
||||
itemSeparatorSize = [_toolbar valueForThemeAttribute:@"image-item-separator-size"];
|
||||
|
||||
[_view setFrame:_CGRectMake(ROUND((width - itemSeparatorSize.size.width) / 2.0), 0.0, itemSeparatorSize.size.width, _CGRectGetHeight(bounds))];
|
||||
[_view setFrame:CGRectMake(ROUND((width - itemSeparatorSize.size.width) / 2.0), 0.0, itemSeparatorSize.size.width, CGRectGetHeight(bounds))];
|
||||
[_view setBackgroundColor:itemSeparatorColor];
|
||||
|
||||
return;
|
||||
@@ -1141,17 +1124,17 @@ var LABEL_MARGIN = 2.0;
|
||||
var view = _view || _imageView,
|
||||
itemMaxSize = [_toolbarItem maxSize],
|
||||
iconOnly = [[_toolbarItem toolbar] displayMode] === CPToolbarDisplayModeIconOnly,
|
||||
height = _CGRectGetHeight(bounds) - (iconOnly ? 0 : _labelSize.height),
|
||||
height = CGRectGetHeight(bounds) - (iconOnly ? 0 : _labelSize.height),
|
||||
viewWidth = MIN(itemMaxSize.width, width),
|
||||
viewHeight = MIN(itemMaxSize.height, height);
|
||||
|
||||
[view setFrame:_CGRectMake(ROUND((width - viewWidth) / 2.0),
|
||||
[view setFrame:CGRectMake(ROUND((width - viewWidth) / 2.0),
|
||||
ROUND((height - viewHeight) / 2.0),
|
||||
viewWidth,
|
||||
viewHeight)];
|
||||
|
||||
// Label is always drawn at the bottom of the view. So if the view is really tall but the icon is tiny, the icon is centred above the label while the label remains on the bottom.
|
||||
[_labelField setFrameOrigin:_CGPointMake(ROUND((width - _labelSize.width) / 2.0), _CGRectGetHeight(bounds) - _labelSize.height)];
|
||||
[_labelField setFrameOrigin:CGPointMake(ROUND((width - _labelSize.width) / 2.0), CGRectGetHeight(bounds) - _labelSize.height)];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
@@ -1218,7 +1201,7 @@ var LABEL_MARGIN = 2.0;
|
||||
if (alternateImage)
|
||||
[_imageView setImage:alternateImage];
|
||||
|
||||
[_labelField setTextShadowOffset:_CGSizeMakeZero()];
|
||||
[_labelField setTextShadowOffset:CGSizeMakeZero()];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1227,13 +1210,13 @@ var LABEL_MARGIN = 2.0;
|
||||
if (image)
|
||||
[_imageView setImage:image];
|
||||
|
||||
[_labelField setTextShadowOffset:_CGSizeMake(0.0, 1.0)];
|
||||
[_labelField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
}
|
||||
|
||||
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)aSender
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)aSender
|
||||
{
|
||||
[CPApp sendAction:anAction to:aSender from:_toolbarItem];
|
||||
}
|
||||
|
||||
+456
-127
File diff suppressed because it is too large
Load Diff
@@ -59,8 +59,12 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
|
||||
For example:
|
||||
<pre>
|
||||
var animation = [CPDictionary dictionaryWithObjects:[myViewToAnimate, aStartFrame, anEndFrame, CPViewAnimationFadeInEffect]
|
||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationStartFrameKey, CPViewAnimationEndFrameKey, CPViewAnimationEffectKey]];
|
||||
var animation = @{
|
||||
CPViewAnimationTargetKey: myViewToAnimate,
|
||||
CPViewAnimationStartFrameKey: aStartFrame,
|
||||
CPViewAnimationEndFrameKey: anEndFrame,
|
||||
CPViewAnimationEffectKey: CPViewAnimationFadeInEffect,
|
||||
};
|
||||
</pre>
|
||||
|
||||
If you pass nil instead of an array of dictionaries you should later call setViewAnimations:.
|
||||
@@ -101,7 +105,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
[super startAnimation];
|
||||
}
|
||||
|
||||
- (void)setCurrentProgress:(CPAnimationProgress)progress
|
||||
- (void)setCurrentProgress:(float)progress
|
||||
{
|
||||
[super setCurrentProgress:progress];
|
||||
|
||||
@@ -112,7 +116,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero(),
|
||||
differenceFrame = CGRectMakeZero(),
|
||||
value = [super currentValue];
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
@@ -120,7 +124,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = _CGRectMakeZero();
|
||||
var intermediateFrame = CGRectMakeZero();
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * value;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * value;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * value;
|
||||
@@ -136,7 +140,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * value];
|
||||
|
||||
if (progress === 1.0)
|
||||
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
[self _targetView:view setHidden:CGRectIsEmpty(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +161,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:0.0];
|
||||
|
||||
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
[self _targetView:view setHidden:CGRectIsEmpty(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
|
||||
[super stopAnimation];
|
||||
|
||||
@@ -85,7 +85,7 @@ var CPViewControllerCachedCibs;
|
||||
if (self !== [CPViewController class])
|
||||
return;
|
||||
|
||||
CPViewControllerCachedCibs = [CPDictionary dictionary];
|
||||
CPViewControllerCachedCibs = @{};
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -103,7 +103,7 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner
|
||||
{
|
||||
return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||
return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:@{ CPCibOwner: anOwner }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -128,7 +128,7 @@ var CPViewControllerCachedCibs;
|
||||
// Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
|
||||
_cibName = aCibNameOrNil;
|
||||
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
|
||||
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
_cibExternalNameTable = anExternalNameTable || @{ CPCibOwner: self };
|
||||
|
||||
_isLoading = NO;
|
||||
_isLazy = NO;
|
||||
@@ -298,7 +298,7 @@ var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||
var bundlePath = [aCoder decodeObjectForKey:CPViewControllerBundleKey];
|
||||
_cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
|
||||
|
||||
_cibExternalNameTable = [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
_cibExternalNameTable = @{ CPCibOwner: self };
|
||||
_isLazy = YES;
|
||||
}
|
||||
|
||||
|
||||
+43
-10
@@ -241,8 +241,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
if (_effectiveScrollMode !== CPWebViewScrollAppKit)
|
||||
return;
|
||||
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
var win = [self DOMWindow];
|
||||
|
||||
if (win && win.addEventListener)
|
||||
{
|
||||
@@ -258,6 +257,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
};
|
||||
|
||||
win.addEventListener("DOMMouseScroll", scrollEventHandler, false);
|
||||
win.addEventListener("wheel", scrollEventHandler, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,8 +277,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
var win = [self DOMWindow];
|
||||
|
||||
if (win && win.document && win.document.body)
|
||||
{
|
||||
@@ -579,6 +578,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
|
||||
_mainFrameURL = URLString;
|
||||
[_forwardStack removeAllObjects];
|
||||
|
||||
@@ -596,6 +596,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
if (_mainFrameURL)
|
||||
[_forwardStack addObject:_mainFrameURL];
|
||||
|
||||
_mainFrameURL = [_backwardStack lastObject];
|
||||
[_backwardStack removeLastObject];
|
||||
|
||||
@@ -603,6 +604,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -617,6 +619,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
|
||||
_mainFrameURL = [_forwardStack lastObject];
|
||||
[_forwardStack removeLastObject];
|
||||
|
||||
@@ -624,6 +627,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -671,7 +675,14 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
*/
|
||||
- (DOMWindow)DOMWindow
|
||||
{
|
||||
return (_iframe.contentDocument && _iframe.contentDocument.defaultView) || _iframe.contentWindow;
|
||||
try
|
||||
{
|
||||
return (_iframe.contentDocument && _iframe.contentDocument.defaultView) || _iframe.contentWindow;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -682,6 +693,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
- (CPWebScriptObject)windowScriptObject
|
||||
{
|
||||
var win = [self DOMWindow];
|
||||
|
||||
if (!_wso || win != [_wso window])
|
||||
{
|
||||
if (win)
|
||||
@@ -689,6 +701,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
else
|
||||
_wso = nil;
|
||||
}
|
||||
|
||||
return _wso;
|
||||
}
|
||||
|
||||
@@ -726,6 +739,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
- (DOMCSSStyleDeclaration)computedStyleForElement:(DOMElement)element pseudoElement:(CPString)pseudoElement
|
||||
{
|
||||
var win = [[self windowScriptObject] window];
|
||||
|
||||
if (win)
|
||||
{
|
||||
// FIXME: IE version?
|
||||
@@ -758,6 +772,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
if (drawsBackground == _drawsBackground)
|
||||
return;
|
||||
|
||||
_drawsBackground = drawsBackground;
|
||||
|
||||
[self _applyBackgroundColor];
|
||||
@@ -863,38 +878,47 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
return _downloadDelegate;
|
||||
}
|
||||
|
||||
- (void)setDownloadDelegate:(id)anObject
|
||||
{
|
||||
_downloadDelegate = anObject;
|
||||
}
|
||||
|
||||
- (id)frameLoadDelegate
|
||||
{
|
||||
return _frameLoadDelegate;
|
||||
}
|
||||
|
||||
- (void)setFrameLoadDelegate:(id)anObject
|
||||
{
|
||||
_frameLoadDelegate = anObject;
|
||||
}
|
||||
|
||||
- (id)policyDelegate
|
||||
{
|
||||
return _policyDelegate;
|
||||
}
|
||||
|
||||
- (void)setPolicyDelegate:(id)anObject
|
||||
{
|
||||
_policyDelegate = anObject;
|
||||
}
|
||||
|
||||
- (id)resourceLoadDelegate
|
||||
{
|
||||
return _resourceLoadDelegate;
|
||||
}
|
||||
|
||||
- (void)setResourceLoadDelegate:(id)anObject
|
||||
{
|
||||
_resourceLoadDelegate = anObject;
|
||||
}
|
||||
|
||||
- (id)UIDelegate
|
||||
{
|
||||
return _UIDelegate;
|
||||
}
|
||||
|
||||
- (void)setUIDelegate:(id)anObject
|
||||
{
|
||||
_UIDelegate = anObject;
|
||||
@@ -921,6 +945,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
{
|
||||
_window = aWindow;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -935,9 +960,12 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
// Would using "with" be better here?
|
||||
if (typeof _window[methodName] == "function")
|
||||
{
|
||||
try {
|
||||
return _window[methodName].apply(args);
|
||||
} catch (e) {
|
||||
try
|
||||
{
|
||||
return _window[methodName].apply(_window, args);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -951,11 +979,15 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
*/
|
||||
- (id)evaluateWebScript:(CPString)script
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
return _window.eval(script);
|
||||
} catch (e) {
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// FIX ME: if we fail inside here, shouldn't we return an exception?
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1030,6 +1062,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
- (BOOL)_passesSameOriginPolicy
|
||||
{
|
||||
var documentURL = [CPURL URLWithString:window.location.href];
|
||||
|
||||
if ([documentURL isFileURL] && CPFeatureIsCompatible(CPSOPDisabledFromFileURLs))
|
||||
return YES;
|
||||
|
||||
|
||||
+3587
-12
File diff suppressed because it is too large
Load Diff
@@ -189,3 +189,10 @@ CPWindowPositionFlexibleRight = 1 << 19;
|
||||
CPWindowPositionFlexibleLeft = 1 << 20;
|
||||
CPWindowPositionFlexibleBottom = 1 << 21;
|
||||
CPWindowPositionFlexibleTop = 1 << 22;
|
||||
|
||||
CPStandardWindowShadowStyle = 0;
|
||||
CPMenuWindowShadowStyle = 1;
|
||||
CPPanelWindowShadowStyle = 2;
|
||||
CPCustomWindowShadowStyle = 3;
|
||||
|
||||
CPWindowConstrainToScreen = YES;
|
||||
|
||||
@@ -32,10 +32,11 @@
|
||||
return @"bordeless-bridge-window-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPColor grayColor]]
|
||||
forKeys:[@"toolbar-background-color"]];
|
||||
return @{
|
||||
@"toolbar-background-color": [CPColor grayColor],
|
||||
};
|
||||
}
|
||||
|
||||
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
@implementation _CPDocModalWindowView : _CPWindowView
|
||||
{
|
||||
CPView _bodyView;
|
||||
CPView _shadowView;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -34,10 +33,23 @@
|
||||
return @"doc-modal-window-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPColor whiteColor], 8]
|
||||
forKeys:[ @"body-color", @"height-shadow"]];
|
||||
return @{
|
||||
@"body-color": [CPColor whiteColor],
|
||||
@"shadow-height": 8,
|
||||
};
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
/*
|
||||
This window view class draws a frame.
|
||||
So we have to inset the content rect to be inside the frame.
|
||||
*/
|
||||
var contentRect = [super contentRectForFrameRect:aFrameRect];
|
||||
|
||||
return CGRectInset(contentRect, 1.0, 1.0);
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
@@ -48,34 +60,25 @@
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
_bodyView = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, _CGRectGetWidth(bounds), _CGRectGetHeight(bounds))];
|
||||
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), CGRectGetHeight(bounds))];
|
||||
|
||||
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_bodyView setHitTests:NO];
|
||||
|
||||
[self addSubview:_bodyView];
|
||||
|
||||
_shadowView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, _CGRectGetWidth(bounds), [self valueForThemeAttribute:@"height-shadow"])];
|
||||
[_shadowView setAutoresizingMask:CPViewWidthSizable];
|
||||
[self addSubview:_shadowView];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
return aFrameRect;
|
||||
return [[self class] contentRectForFrameRect:aFrameRect];
|
||||
}
|
||||
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
return aContentRect;
|
||||
}
|
||||
|
||||
- (void)_enableSheet:(BOOL)enable
|
||||
{
|
||||
// do nothing, already a sheet
|
||||
return [[self class] frameRectForContentRect:aContentRect];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -85,9 +88,11 @@
|
||||
var bounds = [self bounds];
|
||||
|
||||
[_bodyView setBackgroundColor:[self valueForThemeAttribute:@"body-color"]];
|
||||
}
|
||||
|
||||
[_shadowView setFrame:CGRectMake(0,0, _CGRectGetWidth(bounds), [self valueForThemeAttribute:@"height-shadow"])];
|
||||
[_shadowView setBackgroundColor:[self valueForThemeAttribute:@"attached-sheet-shadow-color"]];
|
||||
- (int)bodyOffset
|
||||
{
|
||||
return [_bodyView frame].origin.y;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,6 +36,22 @@
|
||||
return @"hud-window-view";
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
/*
|
||||
This window view class draws a frame.
|
||||
So we have to inset the content rect to be inside the frame.
|
||||
The top coordinate has already been adjusted by _CPTitleableWindowView.
|
||||
*/
|
||||
var contentRect = [super contentRectForFrameRect:aFrameRect];
|
||||
|
||||
contentRect.origin.x += 1;
|
||||
contentRect.size.width -= 2;
|
||||
contentRect.size.height -= 1;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = [[self class] contentRectForFrameRect:aFrameRect];
|
||||
@@ -111,7 +127,7 @@
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
{
|
||||
return _CGSizeMake(0.0, [[self class] titleBarHeight]);
|
||||
return CGSizeMake(0.0, [[self class] titleBarHeight]);
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
@@ -120,22 +136,22 @@
|
||||
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds);
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
[_titleField setFrame:_CGRectMake(20.0, 0, width - 40.0, [self toolbarOffset].height)];
|
||||
[_titleField setFrame:CGRectMake(20.0, 0, width - 40.0, [self toolbarOffset].height)];
|
||||
|
||||
var maxY = [self toolbarMaxY];
|
||||
if ([_titleField isHidden])
|
||||
maxY -= ([self toolbarOffset]).height;
|
||||
|
||||
var contentRect = _CGRectMake(0.0, maxY, width, _CGRectGetHeight(bounds) - maxY);
|
||||
var contentRect = CGRectMake(0.0, maxY, width, CGRectGetHeight(bounds) - maxY);
|
||||
|
||||
[[theWindow contentView] setFrame:contentRect];
|
||||
}
|
||||
|
||||
- (void)_enableSheet:(BOOL)enable
|
||||
- (void)_enableSheet:(BOOL)enable inWindow:(CPWindow)parentWindow
|
||||
{
|
||||
[super _enableSheet:enable];
|
||||
// No need to call super, it just deals with the shadow view, which we don't want
|
||||
|
||||
[_closeButton setHidden:enable];
|
||||
[_titleField setHidden:enable];
|
||||
@@ -148,15 +164,17 @@
|
||||
if (enable)
|
||||
dy = -dy;
|
||||
|
||||
var newHeight = _CGRectGetMaxY(frame) + dy,
|
||||
newWidth = _CGRectGetMaxX(frame);
|
||||
var newHeight = CGRectGetMaxY(frame) + dy,
|
||||
newWidth = CGRectGetMaxX(frame);
|
||||
|
||||
frame.size.height += dy;
|
||||
|
||||
[self setFrameSize:_CGSizeMake(newWidth, newHeight)];
|
||||
[self setFrameSize:CGSizeMake(newWidth, newHeight)];
|
||||
[self tile];
|
||||
[theWindow setFrame:frame display:NO animate:NO];
|
||||
[theWindow setMovableByWindowBackground:!enable];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
|
||||
@@ -22,19 +22,13 @@
|
||||
|
||||
@import <Foundation/CPGeometry.j>
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CGGradient.j"
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
@global CPPopoverAppearanceMinimal
|
||||
|
||||
#define ALIGN_STROKE(point) (FLOOR(point) === (point) ? (point) + halfStrokeWidth : (point))
|
||||
#define ALIGN_COORD(point) (FLOOR(point))
|
||||
|
||||
var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
_CPPopoverWindowViewRadius = 5.0,
|
||||
_CPPopoverWindowViewStrokeWidth = 1.0,
|
||||
_CPPopoverWindowViewShadowSize = _CGSizeMake(0, 6),
|
||||
_CPPopoverWindowViewShadowBlur = 15.0;
|
||||
var _CPPopoverWindowViewDefaultCursorSize = CGSizeMake(16, 10);
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
@@ -51,6 +45,25 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
CGSize _cursorSize;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"popover-window-view";
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"background-gradient": [CPNull null],
|
||||
@"background-gradient-hud": [CPNull null],
|
||||
@"stroke-color": [CPNull null],
|
||||
@"stroke-color-hud": [CPNull null],
|
||||
@"border-radius": 5.0,
|
||||
@"stroke-width": 1.0,
|
||||
@"shadow-size": CGSizeMake(0, 6),
|
||||
@"shadow-blur": 15.0
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the contentView frame from a given window frame
|
||||
|
||||
@@ -58,7 +71,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
*/
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = _CGRectMakeCopy(aFrameRect),
|
||||
var contentRect = CGRectMakeCopy(aFrameRect),
|
||||
modifierX = 16,
|
||||
modifierY = 19;
|
||||
|
||||
@@ -66,7 +79,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
//
|
||||
// @comment: If we use this, each time we open the popover, the content
|
||||
// view is reduced a little over and over
|
||||
// return _CGRectInset(contentRect, modifierX, modifierY);
|
||||
// return CGRectInset(contentRect, modifierX, modifierY);
|
||||
|
||||
contentRect.origin.x += modifierX;
|
||||
contentRect.origin.y += modifierY;
|
||||
@@ -83,7 +96,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = _CGRectMakeCopy(aContentRect),
|
||||
var frameRect = CGRectMakeCopy(aContentRect),
|
||||
modifierX = 16,
|
||||
modifierY = 19;
|
||||
|
||||
@@ -91,7 +104,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
// @comment: If we use this, each time we open the popover, the content
|
||||
//
|
||||
// view is reduced a little over and over
|
||||
// return _CGRectOffset(frameRect, modifierX, modifierY);
|
||||
// return CGRectOffset(frameRect, modifierX, modifierY);
|
||||
|
||||
frameRect.origin.x -= modifierX;
|
||||
frameRect.origin.y -= modifierY;
|
||||
@@ -111,7 +124,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
_arrowOffsetX = 0.0;
|
||||
_arrowOffsetY = 0.0;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_cursorSize = _CGSizeMakeCopy(_CPPopoverWindowViewDefaultCursorSize);
|
||||
_cursorSize = CGSizeMakeCopy(_CPPopoverWindowViewDefaultCursorSize);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -122,7 +135,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
*/
|
||||
- (void)hideCursor
|
||||
{
|
||||
_cursorSize = _CGSizeMakeZero();
|
||||
_cursorSize = CGSizeMakeZero();
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -131,7 +144,7 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
*/
|
||||
- (void)showCursor
|
||||
{
|
||||
_cursorSize = _CGSizeMakeCopy(_CPPopoverWindowViewDefaultCursorSize);
|
||||
_cursorSize = CGSizeMakeCopy(_CPPopoverWindowViewDefaultCursorSize);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -143,42 +156,27 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = _CPPopoverWindowViewRadius,
|
||||
radius = [self valueForThemeAttribute:@"border-radius"],
|
||||
arrowWidth = _cursorSize.width,
|
||||
arrowHeight = _cursorSize.height,
|
||||
strokeWidth = _CPPopoverWindowViewStrokeWidth,
|
||||
strokeWidth = [self valueForThemeAttribute:@"stroke-width"],
|
||||
halfStrokeWidth = strokeWidth / 2.0,
|
||||
strokeColor,
|
||||
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
|
||||
shadowSize = _CPPopoverWindowViewShadowSize,
|
||||
shadowBlur = _CPPopoverWindowViewShadowBlur,
|
||||
shadowSize = [self valueForThemeAttribute:@"shadow-size"],
|
||||
shadowBlur = [self valueForThemeAttribute:@"shadow-blur"],
|
||||
gradient,
|
||||
frame = [self bounds];
|
||||
|
||||
if (_appearance == CPPopoverAppearanceMinimal)
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
[
|
||||
(254.0 / 255), (254.0 / 255), (254.0 / 255), 0.93,
|
||||
(231.0 / 255), (231.0 / 255), (231.0 / 255), 0.93
|
||||
],
|
||||
[0, 1],
|
||||
2
|
||||
);
|
||||
strokeColor = [CPColor colorWithHexString:@"B8B8B8"];
|
||||
gradient = [self valueForThemeAttribute:@"background-gradient"];
|
||||
strokeColor = [self valueForThemeAttribute:@"stroke-color"];
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
[
|
||||
(38.0 / 255), (38.0 / 255), (38.0 / 255), 0.93,
|
||||
(18.0 / 255), (18.0 / 255), (18.0 / 255), 0.93
|
||||
],
|
||||
[0, 1],
|
||||
2);
|
||||
strokeColor = [CPColor colorWithHexString:@"222222"];
|
||||
gradient = [self valueForThemeAttribute:@"background-gradient-hud"];
|
||||
strokeColor = [self valueForThemeAttribute:@"stroke-color-hud"];
|
||||
}
|
||||
|
||||
// fix rect to take care of stroke and shadow
|
||||
@@ -189,45 +187,48 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
|
||||
CGContextDrawLinearGradient(context, gradient, _CGPointMake(_CGRectGetMidX(frame), 0.0), _CGPointMake(_CGRectGetMidX(frame), frame.size.height), 0);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), 0.0), CGPointMake(CGRectGetMidX(frame), frame.size.height), 0);
|
||||
|
||||
var xMin = _CGRectGetMinX(frame),
|
||||
xMax = _CGRectGetMaxX(frame),
|
||||
yMin = _CGRectGetMinY(frame),
|
||||
yMax = _CGRectGetMaxY(frame),
|
||||
arrowMinX = ALIGN_COORD(xMin + radius + strokeWidth),
|
||||
arrowMaxX = ALIGN_COORD(xMax - radius - strokeWidth),
|
||||
arrowMinY = ALIGN_COORD(yMin + radius + strokeWidth),
|
||||
arrowMaxY = ALIGN_COORD(yMax - radius + strokeWidth),
|
||||
arrowAnchor = _CGPointMakeZero(),
|
||||
arrowStart = _CGPointMakeZero(),
|
||||
pt = _CGPointMakeZero();
|
||||
var xMin = CGRectGetMinX(frame),
|
||||
xMax = CGRectGetMaxX(frame),
|
||||
yMin = CGRectGetMinY(frame),
|
||||
yMax = CGRectGetMaxY(frame),
|
||||
arrowMinX = CGAlignCoordinate(xMin + radius + strokeWidth),
|
||||
arrowMaxX = CGAlignCoordinate(xMax - radius - strokeWidth),
|
||||
arrowMinY = CGAlignCoordinate(yMin + radius + strokeWidth),
|
||||
arrowMaxY = CGAlignCoordinate(yMax - radius + strokeWidth),
|
||||
arrowAnchor = CGPointMakeZero(),
|
||||
arrowStart = CGPointMakeZero(),
|
||||
pt = CGPointMakeZero();
|
||||
|
||||
// draw!
|
||||
var path = CGPathCreateMutable();
|
||||
|
||||
switch (_preferredEdge)
|
||||
{
|
||||
case CPMinXEdge:
|
||||
case CPMaxXEdge:
|
||||
// origin nw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.x = CGAlignCoordinate(xMin + radius);
|
||||
pt.y = yMin;
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
CGPathMoveToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// ne
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, yMin, xMax, ALIGN_COORD(yMin + radius));
|
||||
pt.x = CGAlignCoordinate(xMax - radius);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, xMax, yMin, xMax, CGAlignCoordinate(yMin + radius));
|
||||
|
||||
if (_preferredEdge === CPMinXEdge)
|
||||
{
|
||||
// arrow CPMinXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMax);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
arrowAnchor.x = CGAlignStroke(xMax, strokeWidth);
|
||||
arrowAnchor.y = CGAlignCoordinate((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to top edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y - (arrowWidth / 2));
|
||||
pt.y = CGAlignCoordinate(arrowAnchor.y - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.y <= arrowMinY)
|
||||
@@ -236,40 +237,40 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
pt.y = arrowMaxY - arrowWidth;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = _CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// top edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x + arrowHeight);
|
||||
pt.x = CGAlignStroke(arrowAnchor.x + arrowHeight, strokeWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// point -> bottom edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y + arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
pt.y = CGAlignCoordinate(arrowStart.y + arrowWidth);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// se
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
pt.y = CGAlignCoordinate(yMax - radius);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, pt.x, yMax, CGAlignCoordinate(xMax - radius), yMax);
|
||||
|
||||
// sw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.x = CGAlignCoordinate(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, xMin, pt.y, xMin, CGAlignCoordinate(yMax - radius));
|
||||
|
||||
if (_preferredEdge === CPMaxXEdge)
|
||||
{
|
||||
// arrow CPMaxXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMin);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
arrowAnchor.x = CGAlignStroke(xMin, strokeWidth);
|
||||
arrowAnchor.y = CGAlignCoordinate((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to bottom edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y + (arrowWidth / 2));
|
||||
pt.y = CGAlignCoordinate(arrowAnchor.y + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.y - arrowWidth) < arrowMinY)
|
||||
@@ -278,47 +279,47 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
pt.y = arrowMaxY;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = _CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// bottom edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x - arrowHeight);
|
||||
pt.x = CGAlignStroke(arrowAnchor.x - arrowHeight, strokeWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// point -> top edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y - arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
pt.y = CGAlignCoordinate(arrowStart.y - arrowWidth);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// nw
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
pt.y = CGAlignCoordinate(yMin + radius);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, pt.x, yMin, CGAlignCoordinate(xMin + radius), yMin);
|
||||
break;
|
||||
|
||||
case CPMaxYEdge:
|
||||
case CPMinYEdge:
|
||||
// origin sw
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
pt.y = CGAlignCoordinate(yMax - radius);
|
||||
CGPathMoveToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// nw
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
pt.y = CGAlignCoordinate(yMin + radius);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, pt.x, yMin, CGAlignCoordinate(xMin + radius), yMin);
|
||||
|
||||
if (_preferredEdge === CPMaxYEdge)
|
||||
{
|
||||
// arrow CPMaxYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMin + _arrowOffsetY);
|
||||
arrowAnchor.x = CGAlignCoordinate((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = CGAlignStroke(yMin + _arrowOffsetY, strokeWidth);
|
||||
|
||||
// to left edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x - (arrowWidth / 2));
|
||||
pt.x = CGAlignCoordinate(arrowAnchor.x - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.x < arrowMinX)
|
||||
@@ -327,40 +328,40 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
pt.x = arrowMaxX - arrowWidth;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = _CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// left edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y - arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
pt.y = CGAlignStroke(arrowAnchor.y - arrowHeight, strokeWidth);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// point -> right edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x + arrowWidth);
|
||||
pt.x = CGAlignCoordinate(arrowStart.x + arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// ne
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
pt.x = CGAlignCoordinate(xMax - radius);
|
||||
pt.y = yMin;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, pt.y, xMax, ALIGN_COORD(yMin + radius));
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, xMax, pt.y, xMax, CGAlignCoordinate(yMin + radius));
|
||||
|
||||
// se
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
pt.y = CGAlignCoordinate(yMax - radius);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, pt.x, yMax, CGAlignCoordinate(xMax - radius), yMax);
|
||||
|
||||
if (_preferredEdge === CPMinYEdge)
|
||||
{
|
||||
// arrow CPMinYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMax + _arrowOffsetY);
|
||||
arrowAnchor.x = CGAlignCoordinate((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = CGAlignStroke(yMax + _arrowOffsetY, strokeWidth);
|
||||
|
||||
// to right edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x + (arrowWidth / 2));
|
||||
pt.x = CGAlignCoordinate(arrowAnchor.x + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.x - arrowWidth) < arrowMinX)
|
||||
@@ -369,34 +370,36 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
pt.x = arrowMaxX;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = _CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// right edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y + arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
pt.y = CGAlignStroke(arrowAnchor.y + arrowHeight, strokeWidth);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
|
||||
// point -> left edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x - arrowWidth);
|
||||
pt.x = CGAlignCoordinate(arrowStart.x - arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// sw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.x = CGAlignCoordinate(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
CGPathAddLineToPoint(path, NULL, pt.x, pt.y);
|
||||
CGPathAddCurveToPoint(path, NULL, pt.x, pt.y, xMin, pt.y, xMin, CGAlignCoordinate(yMax - radius));
|
||||
break;
|
||||
|
||||
default:
|
||||
// no computed edge means standard rounded rect
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(frame, radius, radius, YES, YES, YES, YES));
|
||||
CGPathAddPath(path, NULL, CGPathWithRoundedRectangleInRect(frame, radius, radius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextAddPath(context, path);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextAddPath(context, path);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user