mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-10 20:57:11 +00:00
Compare commits
791
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
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 | ||
|
|
bd2a7b2b7b | ||
|
|
fc8ca14743 | ||
|
|
15cf818b1e | ||
|
|
cf9b630401 | ||
|
|
3cc6b8dfbe | ||
|
|
bf6ce64209 | ||
|
|
949af39041 | ||
|
|
2104c838bd | ||
|
|
ee1c7a5f01 | ||
|
|
6d77faa7dd | ||
|
|
f4dc139675 | ||
|
|
73d62029ba | ||
|
|
b38f845643 | ||
|
|
cdef68034d | ||
|
|
467036bf34 | ||
|
|
934dedecd2 | ||
|
|
bd96d1b5e2 | ||
|
|
01920e674d | ||
|
|
0ec218a599 | ||
|
|
db21168a93 | ||
|
|
606205b58d | ||
|
|
1aa0956b4d | ||
|
|
d400617c1b | ||
|
|
056a00e54e | ||
|
|
0b7e92aa53 | ||
|
|
9cb2c758c7 | ||
|
|
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 | ||
|
|
cc9ff15142 | ||
|
|
4c756c7cbf | ||
|
|
100f1b0b41 | ||
|
|
d9117bd9a0 | ||
|
|
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 | ||
|
|
27bb85bb00 | ||
|
|
d268013bf0 | ||
|
|
835367e1bf | ||
|
|
054421c978 | ||
|
|
1649ea64cc | ||
|
|
7154252dff | ||
|
|
d9e7912162 | ||
|
|
2a580c675a | ||
|
|
9f66de8422 | ||
|
|
b26542136e | ||
|
|
c135905e64 | ||
|
|
b7b7d33597 | ||
|
|
097d8e9b97 | ||
|
|
8c811ba9ca | ||
|
|
b6cf557483 | ||
|
|
3562aed899 | ||
|
|
07222e92c2 | ||
|
|
011c3c9c5b | ||
|
|
28b77fa02b | ||
|
|
a9ec90713e | ||
|
|
8663b7b3fa | ||
|
|
3ef5cfe846 | ||
|
|
05fa505bb6 | ||
|
|
5c3adfda29 | ||
|
|
0013375eea | ||
|
|
31c06771f3 | ||
|
|
6f57b8a2de | ||
|
|
bd6d2e71e7 | ||
|
|
da9333e884 | ||
|
|
af11431b09 | ||
|
|
16134aa0de | ||
|
|
ffbd9815d5 | ||
|
|
ab692bb15d | ||
|
|
085654e751 | ||
|
|
5b3386af2f | ||
|
|
d6545627aa | ||
|
|
cb63013197 | ||
|
|
5d2e4bf7cc | ||
|
|
a4fb2deece | ||
|
|
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 | ||
|
|
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 | ||
|
|
fc9001353f | ||
|
|
6a8cba521b | ||
|
|
471641c228 | ||
|
|
887421c9fa | ||
|
|
cbe8659cc7 | ||
|
|
b28429f940 | ||
|
|
956a4c341c | ||
|
|
5b05dc92a1 | ||
|
|
8bcbeb0aa9 | ||
|
|
472848da91 | ||
|
|
5200f945fe | ||
|
|
a736bb4e93 | ||
|
|
00f60ccaa4 | ||
|
|
6d1c4a9570 | ||
|
|
c6a0e209ad | ||
|
|
be4a168601 | ||
|
|
2c10671fe4 | ||
|
|
b791289dfe | ||
|
|
c4370240f8 | ||
|
|
fd0bdcba67 | ||
|
|
f805b6bfa6 | ||
|
|
4188b274f7 | ||
|
|
bf1e720ebc | ||
|
|
599351b56d | ||
|
|
84f42bdd05 | ||
|
|
75b72d601a | ||
|
|
d2143844e3 | ||
|
|
ce7e5122e0 | ||
|
|
0268f9865c | ||
|
|
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 | ||
|
|
169f8eaad1 | ||
|
|
854780a22a | ||
|
|
b1883d7204 | ||
|
|
74be583fbb | ||
|
|
4bc54c45a3 | ||
|
|
56ec9dbb10 | ||
|
|
5d08ddadfa | ||
|
|
cd54687f41 | ||
|
|
899cd22999 | ||
|
|
3aadc958eb | ||
|
|
79dde7bb9b | ||
|
|
7d8e9dfc60 | ||
|
|
e623776f5d | ||
|
|
230988b90d | ||
|
|
a6f4e20078 | ||
|
|
02b7198e9b | ||
|
|
64cb4ddb14 | ||
|
|
238b6c8e57 | ||
|
|
ba372029f9 | ||
|
|
a774e52988 | ||
|
|
b6feecae70 | ||
|
|
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,6 @@ xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
*.xCodeSupport/
|
||||
*.XcodeSupport/
|
||||
*XcodeSupport/
|
||||
*.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)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
-52
@@ -91,15 +91,15 @@ 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;
|
||||
|
||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||
CPWindow _window @accessors(property=window,readonly);
|
||||
CPWindow _window @accessors(property=window, readonly);
|
||||
int _defaultWindowStyle;
|
||||
|
||||
CPImageView _alertImageView;
|
||||
@@ -469,10 +469,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])
|
||||
@@ -644,8 +640,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];
|
||||
@@ -721,50 +718,40 @@ var bottomHeight = 71;
|
||||
|
||||
+ (id)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
|
||||
|
||||
+77
-46
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/CPRange.h"
|
||||
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@import "CPCompatibility.j"
|
||||
@@ -36,6 +34,7 @@
|
||||
@import "CPPanel.j"
|
||||
@import "CPPlatform.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
||||
@@ -87,6 +86,7 @@ CPRunContinuesResponse = -1002;
|
||||
@implementation CPApplication : CPResponder
|
||||
{
|
||||
CPArray _eventListeners;
|
||||
int _eventListenerInsertionIndex;
|
||||
|
||||
CPEvent _currentEvent;
|
||||
CPWindow _lastMouseMoveWindow;
|
||||
@@ -144,6 +144,7 @@ CPRunContinuesResponse = -1002;
|
||||
if (self)
|
||||
{
|
||||
_eventListeners = [];
|
||||
_eventListenerInsertionIndex = 0;
|
||||
|
||||
_windows = [[CPNull null]];
|
||||
}
|
||||
@@ -371,22 +372,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 +411,7 @@ CPRunContinuesResponse = -1002;
|
||||
else
|
||||
[versionLabel setStringValue:@""];
|
||||
|
||||
[copyrightLabel setStringValue:copyright || ""];
|
||||
[copyrightLabel setStringValue:copyright || @""];
|
||||
[aboutPanel center];
|
||||
|
||||
_aboutPanel = aboutPanel;
|
||||
@@ -509,6 +520,8 @@ CPRunContinuesResponse = -1002;
|
||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||
{
|
||||
_eventListeners.splice(count, 1);
|
||||
if (count <= _eventListenerInsertionIndex)
|
||||
_eventListenerInsertionIndex--;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -556,7 +569,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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -617,18 +630,6 @@ CPRunContinuesResponse = -1002;
|
||||
[[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)
|
||||
{
|
||||
if (theWindow !== _lastMouseMoveWindow)
|
||||
@@ -637,6 +638,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 +716,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 +944,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 +959,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 +981,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 +999,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 +1010,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 +1036,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,7 +1381,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
if (mainCibFile)
|
||||
{
|
||||
[mainBundle loadCibFile:mainCibFile
|
||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
||||
externalNameTable:@{ CPCibOwner: CPApp }
|
||||
loadDelegate:self];
|
||||
|
||||
return YES;
|
||||
|
||||
+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])
|
||||
|
||||
+57
-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;
|
||||
}
|
||||
@@ -168,7 +179,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 +207,7 @@ var DefaultLineWidth = 1.0;
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||
CGContextStrokePath(ctx);
|
||||
}
|
||||
|
||||
@@ -209,10 +221,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";
|
||||
}
|
||||
|
||||
+ (id)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",
|
||||
|
||||
+33
-29
@@ -73,11 +73,11 @@
|
||||
|
||||
+ (id)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
|
||||
@@ -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)];
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
+35
-20
@@ -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]];
|
||||
@@ -140,8 +151,13 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
+ (id)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;
|
||||
@@ -523,6 +539,7 @@ CPButtonImageOffset = 3.0;
|
||||
_isTracking = YES;
|
||||
|
||||
var startedTracking = [super startTrackingAt:aPoint];
|
||||
|
||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
@@ -537,6 +554,7 @@ CPButtonImageOffset = 3.0;
|
||||
else
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
@@ -578,7 +596,7 @@ CPButtonImageOffset = 3.0;
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, contentInset);
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
@@ -589,7 +607,7 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
return _CGRectInsetByInset(bounds, bezelInset);
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
@@ -649,14 +667,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 +1007,3 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//@import "CPCheckBox.j"
|
||||
//@import "CPRadio.j"
|
||||
|
||||
+11
-18
@@ -81,24 +81,17 @@
|
||||
|
||||
+ (id)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;
|
||||
}
|
||||
|
||||
+568
-225
@@ -28,12 +28,10 @@
|
||||
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPDragServer_Constants.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPClipView
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPCollectionView
|
||||
@@ -45,7 +43,7 @@
|
||||
@par Delegate Methods
|
||||
|
||||
@delegate - (void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
||||
Called when the selection in the collection view has changed.
|
||||
DEPRECATED: Please do not use.
|
||||
@param collectionView the collection view who's selection changed
|
||||
|
||||
@delegate - (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||
@@ -67,6 +65,8 @@
|
||||
@return an array of drag types (CPString)
|
||||
*/
|
||||
|
||||
var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
@implementation CPCollectionView : CPView
|
||||
{
|
||||
CPArray _content;
|
||||
@@ -103,6 +103,17 @@
|
||||
id _delegate;
|
||||
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _needsMinMaxItemSizeUpdate;
|
||||
CGSize _storedFrameSize;
|
||||
|
||||
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
|
||||
BOOL _lockResizing;
|
||||
|
||||
CPInteger _currentDropIndex;
|
||||
CPDragOperation _currentDragOperation;
|
||||
|
||||
_CPCollectionViewDropIndicator _dropView;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -111,74 +122,95 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
_items = [];
|
||||
_content = [];
|
||||
_maxNumberOfRows = 0;
|
||||
_maxNumberOfColumns = 0;
|
||||
|
||||
_cachedItems = [];
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
_minItemSize = CGSizeMakeZero();
|
||||
_maxItemSize = CGSizeMakeZero();
|
||||
|
||||
[self setBackgroundColors:nil];
|
||||
|
||||
_verticalMargin = 5.0;
|
||||
_tileWidth = -1.0;
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
_allowsEmptySelection = YES;
|
||||
_isSelectable = YES;
|
||||
_allowsEmptySelection = YES;
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_content = [];
|
||||
|
||||
_items = [];
|
||||
_cachedItems = [];
|
||||
|
||||
_numberOfColumns = CPNotFound;
|
||||
_numberOfRows = CPNotFound;
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
_storedFrameSize = CGSizeMakeZero();
|
||||
|
||||
_needsMinMaxItemSizeUpdate = YES;
|
||||
_uniformSubviewsResizing = NO;
|
||||
_lockResizing = NO;
|
||||
|
||||
_currentDropIndex = -1;
|
||||
_currentDragOperation = CPDragOperationNone;
|
||||
_dropView = nil;
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setAutoresizingMask:0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the item prototype to \c anItem
|
||||
@param anItem the new item prototype.
|
||||
|
||||
The item prototype should implement the CPCoding protocol
|
||||
because the item is copied by archiving and unarchiving the
|
||||
prototypal view.
|
||||
@note
|
||||
- If anItem is located in an external cib file, representedObject, outlets, and bindings will be automatically restored when an item is created.
|
||||
- If anItem and its view belong to the same cib as the collection view, the item prototype should implement the CPCoding protocol because the item is copied by archiving and unarchiving the prototypal view.
|
||||
@note
|
||||
Bindings won't be restored through archiving, instead you need to subclass the -representedObject: method and update the view there.
|
||||
|
||||
Example:
|
||||
@par Example:
|
||||
|
||||
<pre>
|
||||
@implement MyCustomView : CPCollectionViewItem
|
||||
{
|
||||
CPArray items @accessors;
|
||||
}
|
||||
@code
|
||||
@implementation MyCustomPrototypeItem: CPCollectionViewItem
|
||||
{
|
||||
@outlet CPTextField textField;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
if (self)
|
||||
{
|
||||
items = [];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
items = [aCoder decodeObjectForKey:@"KEY"];
|
||||
return self;
|
||||
}
|
||||
textField = [aCoder decodeObjectForKey:@"TextField"];
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:items forKey:@"KEY"];
|
||||
[super encodeWithCoder:aCoder];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
</pre>
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeConditionalObject:textField forKey:@"TextField"];
|
||||
}
|
||||
|
||||
This will allow the collection view to create multiple 'clean' copies
|
||||
of the item prototype which will maintain the original values for item
|
||||
and all of the properties archived by the super class.
|
||||
- (void)setRepresentedObject:(id)anObject
|
||||
{
|
||||
[super setRepresentedObject:anObject];
|
||||
[textField setStringValue:[anObject objectForKey:@"value"]];
|
||||
[[self view] setColor:[anObject objectForKey:@"color"]];
|
||||
}
|
||||
|
||||
@end
|
||||
@endcode
|
||||
|
||||
@param anItem the new item prototype
|
||||
*/
|
||||
- (void)setItemPrototype:(CPCollectionViewItem)anItem
|
||||
{
|
||||
@@ -187,7 +219,7 @@
|
||||
_itemForDragging = nil;
|
||||
_itemPrototype = anItem;
|
||||
|
||||
[self reloadContent];
|
||||
[self _reloadContentCachingRemovedItems:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -210,13 +242,7 @@
|
||||
item = _cachedItems.pop();
|
||||
|
||||
else
|
||||
{
|
||||
if (!_itemData)
|
||||
if (_itemPrototype)
|
||||
_itemData = [CPKeyedArchiver archivedDataWithRootObject:_itemPrototype];
|
||||
|
||||
item = [CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
|
||||
}
|
||||
item = [_itemPrototype copy];
|
||||
|
||||
[item setRepresentedObject:anObject];
|
||||
[[item view] setFrameSize:_itemSize];
|
||||
@@ -371,7 +397,10 @@
|
||||
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||
{
|
||||
CPLog.warn("The delegate method collectionViewDidChangeSelection: is deprecated and will be removed in a future version, please bind to selectionIndexes instead.");
|
||||
[_delegate collectionViewDidChangeSelection:self];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -382,8 +411,13 @@
|
||||
return [_selectionIndexes copy];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)reloadContent
|
||||
{
|
||||
[self _reloadContentCachingRemovedItems:YES];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_reloadContentCachingRemovedItems:(BOOL)shouldCache
|
||||
{
|
||||
// Remove current views
|
||||
var count = _items.length;
|
||||
@@ -393,7 +427,8 @@
|
||||
[[_items[count] view] removeFromSuperview];
|
||||
[_items[count] setSelected:NO];
|
||||
|
||||
_cachedItems.push(_items[count]);
|
||||
if (shouldCache)
|
||||
_cachedItems.push(_items[count]);
|
||||
}
|
||||
|
||||
_items = [];
|
||||
@@ -417,91 +452,166 @@
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < count)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
[self tile];
|
||||
[self tileIfNeeded:NO];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)tile
|
||||
- (void)resizeSubviewsWithOldSize:(CPSize)oldBoundsSize
|
||||
{
|
||||
var width = CGRectGetWidth([self bounds]);
|
||||
// Desactivate subviews autoresizing
|
||||
}
|
||||
|
||||
if (width == _tileWidth)
|
||||
- (void)resizeWithOldSuperviewSize:(CPSize)oldBoundsSize
|
||||
{
|
||||
if (_lockResizing)
|
||||
return;
|
||||
|
||||
// We try to fit as many views per row as possible. Any remaining space is then
|
||||
// either proportioned out to the views (if their minSize != maxSize) or used as
|
||||
// margin
|
||||
var itemSize = CGSizeMakeCopy(_minItemSize);
|
||||
_lockResizing = YES;
|
||||
|
||||
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
|
||||
[self tile];
|
||||
|
||||
if (_maxNumberOfColumns > 0)
|
||||
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
|
||||
|
||||
var remaining = width - _numberOfColumns * itemSize.width,
|
||||
itemsNeedSizeUpdate = NO;
|
||||
|
||||
if (remaining > 0 && itemSize.width < _maxItemSize.width)
|
||||
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
|
||||
|
||||
// When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width.
|
||||
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
|
||||
itemSize.width = MIN(_maxItemSize.width, width);
|
||||
|
||||
if (!CGSizeEqualToSize(_itemSize, itemSize))
|
||||
{
|
||||
_itemSize = itemSize;
|
||||
itemsNeedSizeUpdate = YES;
|
||||
}
|
||||
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
|
||||
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
|
||||
|
||||
_numberOfRows = CEIL(count / _numberOfColumns);
|
||||
|
||||
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
|
||||
|
||||
var x = _horizontalMargin,
|
||||
y = -itemSize.height;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
if (index % _numberOfColumns == 0)
|
||||
{
|
||||
x = _horizontalMargin;
|
||||
y += _verticalMargin + itemSize.height;
|
||||
}
|
||||
|
||||
var view = [_items[index] view];
|
||||
|
||||
[view setFrameOrigin:CGPointMake(x, y)];
|
||||
|
||||
if (itemsNeedSizeUpdate)
|
||||
[view setFrameSize:_itemSize];
|
||||
|
||||
x += itemSize.width + _horizontalMargin;
|
||||
}
|
||||
|
||||
var superview = [self superview],
|
||||
proposedHeight = y + itemSize.height + _verticalMargin;
|
||||
|
||||
if ([superview isKindOfClass:[CPClipView class]])
|
||||
{
|
||||
var superviewSize = [superview bounds].size;
|
||||
proposedHeight = MAX(superviewSize.height, proposedHeight);
|
||||
}
|
||||
|
||||
_tileWidth = width;
|
||||
[self setFrameSize:CGSizeMake(width, proposedHeight)];
|
||||
_tileWidth = -1.0;
|
||||
_lockResizing = NO;
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
- (void)tile
|
||||
{
|
||||
[self tile];
|
||||
[self tileIfNeeded:!_uniformSubviewsResizing];
|
||||
}
|
||||
|
||||
- (void)tileIfNeeded:(BOOL)lazyFlag
|
||||
{
|
||||
var frameSize = [[self superview] frameSize],
|
||||
count = _items.length,
|
||||
oldNumberOfColumns = _numberOfColumns,
|
||||
oldNumberOfRows = _numberOfRows,
|
||||
oldItemSize = _itemSize,
|
||||
storedFrameSize = _storedFrameSize;
|
||||
|
||||
// No need to tile if we are not yet placed in the view hierarchy.
|
||||
if (!frameSize)
|
||||
return;
|
||||
|
||||
[self _updateMinMaxItemSizeIfNeeded];
|
||||
|
||||
[self _computeGridWithSize:frameSize count:@ref(count)];
|
||||
|
||||
//CPLog.debug("frameSize="+CPStringFromSize(frameSize) + "itemSize="+CPStringFromSize(itemSize) + " ncols=" + colsRowsCount[0] +" nrows="+ colsRowsCount[1]+" displayCount="+ colsRowsCount[2]);
|
||||
|
||||
[self setFrameSize:_storedFrameSize];
|
||||
|
||||
//CPLog.debug("OLD " + oldNumberOfColumns + " NEW " + _numberOfColumns);
|
||||
if (!lazyFlag ||
|
||||
_numberOfColumns !== oldNumberOfColumns ||
|
||||
_numberOfRows !== oldNumberOfRows ||
|
||||
!CGSizeEqualToSize(_itemSize, oldItemSize))
|
||||
|
||||
[self displayItems:_items frameSize:_storedFrameSize itemSize:_itemSize columns:_numberOfColumns rows:_numberOfRows count:count];
|
||||
}
|
||||
|
||||
- (void)_computeGridWithSize:(CGSize)aSuperviewSize count:(Function)countRef
|
||||
{
|
||||
var width = aSuperviewSize.width,
|
||||
height = aSuperviewSize.height,
|
||||
itemSize = CGSizeMakeCopy(_minItemSize),
|
||||
maxItemSizeWidth = _maxItemSize.width,
|
||||
maxItemSizeHeight = _maxItemSize.height,
|
||||
itemsCount = [_items count],
|
||||
numberOfRows,
|
||||
numberOfColumns;
|
||||
|
||||
numberOfColumns = FLOOR(width / itemSize.width);
|
||||
|
||||
if (maxItemSizeWidth == 0)
|
||||
numberOfColumns = MIN(numberOfColumns, _maxNumberOfColumns);
|
||||
|
||||
if (_maxNumberOfColumns > 0)
|
||||
numberOfColumns = MIN(MIN(_maxNumberOfColumns, itemsCount), numberOfColumns);
|
||||
|
||||
numberOfColumns = MAX(1.0, numberOfColumns);
|
||||
|
||||
itemSize.width = FLOOR(width / numberOfColumns);
|
||||
|
||||
if (maxItemSizeWidth > 0)
|
||||
{
|
||||
itemSize.width = MIN(maxItemSizeWidth, itemSize.width);
|
||||
|
||||
if (numberOfColumns == 1)
|
||||
itemSize.width = MIN(maxItemSizeWidth, width);
|
||||
}
|
||||
|
||||
numberOfRows = CEIL(itemsCount / numberOfColumns);
|
||||
|
||||
if (_maxNumberOfRows > 0)
|
||||
numberOfRows = MIN(numberOfRows, _maxNumberOfRows);
|
||||
|
||||
height = MAX(height, numberOfRows * (_minItemSize.height + _verticalMargin));
|
||||
|
||||
var itemSizeHeight = FLOOR(height / numberOfRows);
|
||||
|
||||
if (maxItemSizeHeight > 0)
|
||||
itemSizeHeight = MIN(itemSizeHeight, maxItemSizeHeight);
|
||||
|
||||
_itemSize = CGSizeMake(MAX(_minItemSize.width, itemSize.width), MAX(_minItemSize.height, itemSizeHeight));
|
||||
_storedFrameSize = CGSizeMake(MAX(width, _minItemSize.width), height);
|
||||
_numberOfColumns = numberOfColumns;
|
||||
_numberOfRows = numberOfRows;
|
||||
countRef(MIN(itemsCount, numberOfColumns * numberOfRows));
|
||||
}
|
||||
|
||||
- (void)displayItems:(CPArray)displayItems frameSize:(CGSize)aFrameSize itemSize:(CGSize)anItemSize columns:(CPInteger)numberOfColumns rows:(CPInteger)numberOfRows count:(CPInteger)displayCount
|
||||
{
|
||||
// CPLog.debug("DISPLAY ITEMS " + numberOfColumns + " " + numberOfRows);
|
||||
|
||||
_horizontalMargin = _uniformSubviewsResizing ? FLOOR((aFrameSize.width - numberOfColumns * anItemSize.width) / (numberOfColumns + 1)) : HORIZONTAL_MARGIN;
|
||||
|
||||
var x = _horizontalMargin,
|
||||
y = -anItemSize.height;
|
||||
|
||||
[displayItems enumerateObjectsUsingBlock:function(item, idx, stop)
|
||||
{
|
||||
var view = [item view];
|
||||
|
||||
if (idx >= displayCount)
|
||||
{
|
||||
[view setFrameOrigin:CGPointMake(-anItemSize.width, -anItemSize.height)];
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx % numberOfColumns == 0)
|
||||
{
|
||||
x = _horizontalMargin;
|
||||
y += _verticalMargin + anItemSize.height;
|
||||
}
|
||||
|
||||
[view setFrameOrigin:CGPointMake(x, y)];
|
||||
[view setFrameSize:anItemSize];
|
||||
|
||||
x += anItemSize.width + _horizontalMargin;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_updateMinMaxItemSizeIfNeeded
|
||||
{
|
||||
if (!_needsMinMaxItemSizeUpdate)
|
||||
return;
|
||||
|
||||
var prototypeView;
|
||||
|
||||
if (_itemPrototype && (prototypeView = [_itemPrototype view]))
|
||||
{
|
||||
if (_minItemSize.width == 0)
|
||||
_minItemSize.width = [prototypeView frameSize].width;
|
||||
|
||||
if (_minItemSize.height == 0)
|
||||
_minItemSize.height = [prototypeView frameSize].height;
|
||||
|
||||
if (_maxItemSize.height == 0 && !([prototypeView autoresizingMask] & CPViewHeightSizable))
|
||||
_maxItemSize.height = [prototypeView frameSize].height;
|
||||
|
||||
if (_maxItemSize.width == 0 && !([prototypeView autoresizingMask] & CPViewWidthSizable))
|
||||
_maxItemSize.width = [prototypeView frameSize].width;
|
||||
|
||||
_needsMinMaxItemSizeUpdate = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Laying Out the Collection View
|
||||
@@ -574,11 +684,15 @@
|
||||
{
|
||||
if (aSize === nil || aSize === undefined)
|
||||
[CPException raise:CPInvalidArgumentException reason:"Invalid value provided for minimum size"];
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, aSize))
|
||||
return;
|
||||
|
||||
_minItemSize = CGSizeMakeCopy(aSize);
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
_needsMinMaxItemSizeUpdate = YES;
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -601,6 +715,9 @@
|
||||
|
||||
_maxItemSize = CGSizeMakeCopy(aSize);
|
||||
|
||||
// if (_maxItemSize.width == 0 || _maxItemSize.height == 0)
|
||||
// _needsMinMaxItemSizeUpdate = YES;
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -620,7 +737,7 @@
|
||||
_backgroundColors = backgroundColors;
|
||||
|
||||
if (!_backgroundColors)
|
||||
_backgroundColors = [CPColor whiteColor];
|
||||
_backgroundColors = [[CPColor whiteColor]];
|
||||
|
||||
if ([_backgroundColors count] === 1)
|
||||
[self setBackgroundColor:_backgroundColors[0]];
|
||||
@@ -692,65 +809,6 @@
|
||||
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
// Don't crash if we never registered the intial click.
|
||||
if (!_mouseDownEvent)
|
||||
return;
|
||||
|
||||
var locationInWindow = [anEvent locationInWindow],
|
||||
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
|
||||
|
||||
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
|
||||
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
|
||||
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
||||
return;
|
||||
|
||||
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||
return;
|
||||
|
||||
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
|
||||
if (![_selectionIndexes count])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
||||
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||
return;
|
||||
|
||||
// Set up the pasteboard
|
||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||
|
||||
if (!_itemForDragging)
|
||||
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||
else
|
||||
[_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||
|
||||
var view = [_itemForDragging view];
|
||||
|
||||
[view setFrameSize:_itemSize];
|
||||
[view setAlphaValue:0.7];
|
||||
|
||||
[self dragView:view
|
||||
at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
|
||||
offset:CGSizeMakeZero()
|
||||
event:_mouseDownEvent
|
||||
pasteboard:nil
|
||||
source:self
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Places the selected items on the specified pasteboard. The items are requested from the collection's delegate.
|
||||
@param aPasteboard the pasteboard to put the items on
|
||||
@param aType the format the pasteboard data
|
||||
*/
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
[aPasteboard setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
||||
}
|
||||
|
||||
// Cappuccino Additions
|
||||
|
||||
/*!
|
||||
@@ -768,6 +826,13 @@
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)setUniformSubviewsResizing:(float)flag
|
||||
{
|
||||
_uniformSubviewsResizing = flag;
|
||||
[self tileIfNeeded:NO];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Gets the collection view's current vertical spacing between elements.
|
||||
*/
|
||||
@@ -810,10 +875,17 @@
|
||||
|
||||
- (int)_indexAtPoint:(CGPoint)thePoint
|
||||
{
|
||||
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
|
||||
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
|
||||
var column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
|
||||
|
||||
return row * _numberOfColumns + column;
|
||||
if (column < _numberOfColumns)
|
||||
{
|
||||
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin));
|
||||
|
||||
if (row < _numberOfRows)
|
||||
return (row * _numberOfColumns + column);
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
|
||||
@@ -844,11 +916,304 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (DragAndDrop)
|
||||
/*
|
||||
TODO: dropOperation is not supported yet. The visible drop operation is like CPCollectionViewDropBefore.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Places the selected items on the specified pasteboard. The items are requested from the collection's delegate.
|
||||
@param aPasteboard the pasteboard to put the items on
|
||||
@param aType the format the pasteboard data
|
||||
*/
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
[aPasteboard setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
||||
}
|
||||
|
||||
- (void)_createDropIndicatorIfNeeded
|
||||
{
|
||||
// Create and position the drop indicator view.
|
||||
|
||||
if (!_dropView)
|
||||
_dropView = [[_CPCollectionViewDropIndicator alloc] initWithFrame:CGRectMake(-8, -8, 0, 0)];
|
||||
|
||||
[_dropView setFrameSize:CGSizeMake(10, _itemSize.height + _verticalMargin)];
|
||||
[self addSubview:_dropView];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
// Don't crash if we never registered the intial click.
|
||||
if (!_mouseDownEvent)
|
||||
return;
|
||||
|
||||
[self _createDropIndicatorIfNeeded];
|
||||
|
||||
var locationInWindow = [anEvent locationInWindow],
|
||||
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
|
||||
|
||||
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
|
||||
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
|
||||
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
||||
return;
|
||||
|
||||
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||
return;
|
||||
|
||||
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
|
||||
if (![_selectionIndexes count])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
||||
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||
return;
|
||||
|
||||
// Set up the pasteboard
|
||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||
|
||||
var dragImageOffset = CGSizeMakeZero(),
|
||||
view = [self _draggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
|
||||
|
||||
[view setFrameSize:_itemSize];
|
||||
[view setAlphaValue:0.7];
|
||||
|
||||
var dragLocation = [self convertPoint:locationInWindow fromView:nil],
|
||||
dragPoint = CGPointMake(dragLocation.x - _itemSize.width / 2 , dragLocation.y - _itemSize.height / 2);
|
||||
|
||||
[self dragView:view
|
||||
at:dragPoint
|
||||
offset:dragImageOffset
|
||||
event:_mouseDownEvent
|
||||
pasteboard:nil
|
||||
source:self
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
- (CPView)_draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)offset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
|
||||
return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
||||
|
||||
return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
var idx = _content[[indexes firstIndex]];
|
||||
|
||||
if (!_itemForDragging)
|
||||
_itemForDragging = [self newItemForRepresentedObject:idx];
|
||||
else
|
||||
[_itemForDragging setRepresentedObject:idx];
|
||||
|
||||
return [_itemForDragging view];
|
||||
}
|
||||
|
||||
- (BOOL)_canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
|
||||
{
|
||||
if ([self respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
|
||||
return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPDragOperation)draggingEntered:(id)draggingInfo
|
||||
{
|
||||
var dropIndex = -1,
|
||||
dropIndexRef = @ref(dropIndex),
|
||||
dragOp = [self _validateDragWithInfo:draggingInfo dropIndex:dropIndexRef dropOperation:1];
|
||||
|
||||
dropIndex = dropIndexRef();
|
||||
|
||||
[self _createDropIndicatorIfNeeded];
|
||||
|
||||
[self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:dragOp newDropIndex:dropIndex newDropOperation:1];
|
||||
|
||||
return _currentDragOperation;
|
||||
}
|
||||
|
||||
- (CPDragOperation)draggingUpdated:(id)draggingInfo
|
||||
{
|
||||
if (![self _dropIndexDidChange:draggingInfo])
|
||||
return _currentDragOperation;
|
||||
|
||||
var dropIndex,
|
||||
dropIndexRef = @ref(dropIndex);
|
||||
|
||||
var dragOperation = [self _validateDragWithInfo:draggingInfo dropIndex:dropIndexRef dropOperation:1];
|
||||
|
||||
dropIndex = dropIndexRef();
|
||||
|
||||
[self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:dragOperation newDropIndex:dropIndex newDropOperation:1];
|
||||
|
||||
return dragOperation;
|
||||
}
|
||||
|
||||
- (CPDragOperation)_validateDragWithInfo:(id)draggingInfo dropIndex:(Function)dropIndexRef dropOperation:(int)dropOperation
|
||||
{
|
||||
var result = CPDragOperationMove,
|
||||
dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:dropOperation];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
|
||||
{
|
||||
var dropIndexRef2 = @ref(dropIndex);
|
||||
|
||||
result = [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
|
||||
|
||||
if (result !== CPDragOperationNone)
|
||||
{
|
||||
dropIndex = dropIndexRef2();
|
||||
}
|
||||
}
|
||||
|
||||
dropIndexRef(dropIndex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id)draggingInfo
|
||||
{
|
||||
[self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:0 newDropIndex:-1 newDropOperation:1];
|
||||
}
|
||||
|
||||
- (void)draggingEnded:(id)draggingInfo
|
||||
{
|
||||
[self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:0 newDropIndex:-1 newDropOperation:1];
|
||||
}
|
||||
|
||||
/*
|
||||
Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
||||
- (BOOL)_writeItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pboard
|
||||
{
|
||||
if ([self respondsToSelector:@selector(collectionView:writeItemsAtIndexes:toPasteboard:)])
|
||||
return [_delegate collectionView:self writeItemsAtIndexes:indexes toPasteboard:pboard];
|
||||
|
||||
return NO;
|
||||
}
|
||||
*/
|
||||
|
||||
- (BOOL)performDragOperation:(id)draggingInfo
|
||||
{
|
||||
var result = NO;
|
||||
|
||||
if (_currentDragOperation && _currentDropIndex !== -1)
|
||||
result = [_delegate collectionView:self acceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
|
||||
|
||||
[self draggingEnded:draggingInfo]; // Is this correct ?
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)_updateDragAndDropStateWithDraggingInfo:(id)draggingInfo newDragOperation:(CPDragOperation)dragOperation newDropIndex:(CPInteger)dropIndex newDropOperation:(CPInteger)dropOperation
|
||||
{
|
||||
_currentDropIndex = dropIndex;
|
||||
_currentDragOperation = dragOperation;
|
||||
|
||||
var frameOrigin,
|
||||
dropviewFrameWidth = CGRectGetWidth([_dropView frame]);
|
||||
|
||||
if (_currentDropIndex == -1 || _currentDragOperation == CPDragOperationNone)
|
||||
frameOrigin = CGPointMake(-dropviewFrameWidth, 0);
|
||||
else if (_currentDropIndex == 0)
|
||||
frameOrigin = CGPointMake(0, 0);
|
||||
else
|
||||
{
|
||||
var offset;
|
||||
|
||||
if ((_currentDropIndex % _numberOfColumns) !== 0 || _currentDropIndex == [_items count])
|
||||
{
|
||||
dropIndex = _currentDropIndex - 1;
|
||||
offset = (_horizontalMargin - dropviewFrameWidth) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = - _itemSize.width - dropviewFrameWidth - (_horizontalMargin - dropviewFrameWidth) / 2;
|
||||
}
|
||||
|
||||
var rect = [self frameForItemAtIndex:dropIndex];
|
||||
|
||||
frameOrigin = CGPointMake(CGRectGetMaxX(rect) + offset, rect.origin.y - _verticalMargin);
|
||||
}
|
||||
|
||||
[_dropView setFrameOrigin:frameOrigin];
|
||||
}
|
||||
|
||||
- (BOOL)_dropIndexDidChange:(id)draggingInfo
|
||||
{
|
||||
var dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:1];
|
||||
|
||||
if (dropIndex == CPNotFound)
|
||||
dropIndex = [[self content] count];
|
||||
|
||||
return (_currentDropIndex !== dropIndex)
|
||||
}
|
||||
|
||||
- (CPInteger)_dropIndexForDraggingInfo:(id)draggingInfo proposedDropOperation:(int)dropOperation
|
||||
{
|
||||
var location = [self convertPoint:[draggingInfo draggingLocation] fromView:nil],
|
||||
locationX = location.x + _itemSize.width / 2;
|
||||
|
||||
var column = MIN(FLOOR(locationX / (_itemSize.width + _horizontalMargin)), _numberOfColumns),
|
||||
row = FLOOR(location.y / (_itemSize.height + _verticalMargin));
|
||||
|
||||
if (row >= _numberOfRows - 1)
|
||||
{
|
||||
if (row >= _numberOfRows)
|
||||
{
|
||||
row = _numberOfRows - 1;
|
||||
column = _numberOfColumns;
|
||||
}
|
||||
|
||||
return MIN((row * _numberOfColumns + column), [_items count]);
|
||||
}
|
||||
|
||||
return (row * _numberOfColumns + column);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCollectionViewDropIndicator : CPView
|
||||
{
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
width = CGRectGetWidth(aRect),
|
||||
circleRect = CGRectMake(1, 1, width - 2, width - 2);
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]);
|
||||
CGContextSetFillColor(context, [CPColor whiteColor]);
|
||||
CGContextSetLineWidth(context, 3);
|
||||
|
||||
//draw white under the circle thing
|
||||
CGContextFillRect(context, circleRect);
|
||||
|
||||
//draw the circle thing
|
||||
CGContextStrokeEllipseInRect(context, circleRect);
|
||||
|
||||
//then draw the line
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, FLOOR(width / 2), CGRectGetMinY(aRect) + width);
|
||||
CGContextAddLineToPoint(context, FLOOR(width / 2), CGRectGetHeight(aRect));
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (KeyboardInteraction)
|
||||
|
||||
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
|
||||
{
|
||||
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
|
||||
var count = [[self items] count];
|
||||
|
||||
if (count === 0)
|
||||
return;
|
||||
|
||||
anIndex = MIN(MAX(anIndex, 0), count - 1);
|
||||
|
||||
if (_allowsMultipleSelection && shouldExpand)
|
||||
{
|
||||
@@ -873,7 +1238,7 @@
|
||||
{
|
||||
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
|
||||
|
||||
if (!CGRectIsNull(frame))
|
||||
if (!CGRectIsEmpty(frame))
|
||||
[self scrollRectToVisible:frame];
|
||||
}
|
||||
|
||||
@@ -953,6 +1318,11 @@
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
|
||||
- (void)setAutoresizingMask:(int)aMask
|
||||
{
|
||||
[super setAutoresizingMask:0];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (Deprecated)
|
||||
@@ -987,35 +1357,12 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
||||
|
||||
@implementation CPCollectionView (CPCoding)
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
var prototypeView = [_itemPrototype view];
|
||||
if (prototypeView && (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())))
|
||||
{
|
||||
var item = _itemPrototype;
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
_minItemSize = [prototypeView frameSize];
|
||||
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
_maxItemSize = [prototypeView frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_items = [];
|
||||
_content = [];
|
||||
|
||||
_cachedItems = [];
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
|
||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
|
||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
@@ -1029,11 +1376,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
||||
|
||||
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
||||
|
||||
_tileWidth = -1.0;
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
_allowsEmptySelection = YES;
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -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
|
||||
|
||||
+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];
|
||||
}
|
||||
|
||||
+25
-31
@@ -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
|
||||
@@ -60,8 +60,13 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
+ (id)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
|
||||
|
||||
+16
-11
@@ -60,15 +60,18 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
+ (id)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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+78
-63
@@ -38,58 +38,58 @@ 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;
|
||||
CPJavaScriptClipboardEventsFeature = 11;
|
||||
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;
|
||||
|
||||
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 +99,7 @@ if (typeof window !== "undefined" && window.opera)
|
||||
{
|
||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
}
|
||||
|
||||
// Internet Explorer
|
||||
@@ -108,16 +108,16 @@ 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;
|
||||
}
|
||||
|
||||
// WebKit
|
||||
@@ -126,15 +126,15 @@ 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[CPHTMLDragAndDropFeature] = YES;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardEventsFeature] = YES;
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
|
||||
PLATFORM_FEATURES[CPJavaScriptShadowFeature] = YES;
|
||||
|
||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||
@@ -144,22 +144,22 @@ 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;
|
||||
|
||||
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
|
||||
if (majorVersion > 533)
|
||||
@@ -177,59 +177,74 @@ 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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
+26
-32
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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,7 @@ 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:@{ "CPFieldEditor": [note object] }];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+4
-2
@@ -162,8 +162,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);
|
||||
unsigned _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";
|
||||
}
|
||||
|
||||
+ (id)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-color": [CPColor clearColor],
|
||||
@"hour-hand-color": [CPColor clearColor],
|
||||
@"middle-hand-color": [CPColor clearColor],
|
||||
@"minute-hand-color": [CPColor clearColor],
|
||||
@"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];
|
||||
}
|
||||
|
||||
- (id)_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
|
||||
*/
|
||||
- (void)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:(CPDate)aDatePickerStyle
|
||||
{
|
||||
_datePickerStyle = aDatePickerStyle;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*! Set the elements of the datePicker
|
||||
@param aDatePickerElements the datePicker elements
|
||||
*/
|
||||
- (void)setDatePickerElements:(CPDate)aDatePickerElements
|
||||
{
|
||||
_datePickerElements = aDatePickerElements;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*! Set the mode of the datePicker
|
||||
@param aDatePickerMode the datePicker mode
|
||||
*/
|
||||
- (void)setDatePickerMode:(CPDate)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,287 @@
|
||||
/* _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 CPDatePicker
|
||||
|
||||
@global CPHourMinuteSecondDatePickerElementFlag
|
||||
|
||||
@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
|
||||
|
||||
/*! Init a new _CPDatePickerClock
|
||||
@param aFrame
|
||||
@param aDatePicker
|
||||
@return a new instance of _CPDatePickerClock
|
||||
*/
|
||||
- (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
|
||||
|
||||
/*! Layout the subviews
|
||||
*/
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
var bounds = [self bounds],
|
||||
dateValue = [[_datePicker dateValue] copy];
|
||||
|
||||
[dateValue _dateWithTimeZone:[_datePicker timeZone]];
|
||||
|
||||
[self setBackgroundColor:[_datePicker valueForThemeAttribute:@"bezel-color-clock" inState:[_datePicker themeState]]];
|
||||
[_middleHandLayer setBackgroundHandColor:[_datePicker valueForThemeAttribute:@"middle-hand-color" inState:[_datePicker themeState]]];
|
||||
[_hourHandLayer setBackgroundHandColor:[_datePicker valueForThemeAttribute:@"hour-hand-color" inState:[_datePicker themeState]]];
|
||||
[_minuteHandLayer setBackgroundHandColor:[_datePicker valueForThemeAttribute:@"minute-hand-color" inState:[_datePicker themeState]]];
|
||||
[_secondHandLayer setBackgroundHandColor:[_datePicker valueForThemeAttribute:@"second-hand-color" inState:[_datePicker themeState]]];
|
||||
|
||||
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]];
|
||||
|
||||
// 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 Getter Setter methods
|
||||
|
||||
/*! Return the radian position of the hour
|
||||
*/
|
||||
- (float)_hourPositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
var hours = aDate.getHours() + aDate.getMinutes() / 60;
|
||||
|
||||
return (360 * hours / 12) * (Math.PI / 180)
|
||||
}
|
||||
|
||||
/*! Return the radian position of the second
|
||||
*/
|
||||
- (float)_secondPositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
return (360 * aDate.getSeconds() / 60) * (Math.PI / 180)
|
||||
}
|
||||
|
||||
/*! Return the radian position of the minute
|
||||
*/
|
||||
- (float)_minutePositionRadianForDate:(CPDate)aDate
|
||||
{
|
||||
var minutes = aDate.getMinutes() + aDate.getSeconds() / 60;
|
||||
|
||||
return (360 * minutes / 60) * (Math.PI / 180)
|
||||
}
|
||||
|
||||
/*! Set enabled
|
||||
@param aBoolean
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)aBoolean
|
||||
{
|
||||
_isEnabled = aBoolean;
|
||||
[_PMAMTextField setEnabled:aBoolean];
|
||||
[_hourHandLayer setEnabled:aBoolean];
|
||||
[_middleHandLayer setEnabled:aBoolean];
|
||||
[_secondHandLayer setEnabled:aBoolean];
|
||||
[_minuteHandLayer setEnabled:aBoolean];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation HandLayer : CALayer
|
||||
{
|
||||
BOOL _isEnabled @accessors(setter=setEnabled:, getter=isEnabled);
|
||||
|
||||
CALayer _imageLayer;
|
||||
float _rotationRadians;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
/*! Init a new hand layer with an image. The image will be draw in a ImageLayer
|
||||
@param anImage
|
||||
@return a new instance of handLayer
|
||||
*/
|
||||
- (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
|
||||
@param aRect
|
||||
*/
|
||||
- (void)setBounds:(CGRect)aRect
|
||||
{
|
||||
[super setBounds:aRect];
|
||||
|
||||
[_imageLayer setPosition:CGPointMake(CGRectGetMidX(aRect), CGRectGetMidY(aRect))];
|
||||
}
|
||||
|
||||
/*! Set the rotation of the imageLayer
|
||||
@param radians
|
||||
*/
|
||||
- (void)setRotationRadians:(float)radians
|
||||
{
|
||||
if (_rotationRadians == radians)
|
||||
return;
|
||||
|
||||
_rotationRadians = radians;
|
||||
|
||||
[_imageLayer setAffineTransform:CGAffineTransformScale(
|
||||
CGAffineTransformMakeRotation(_rotationRadians),
|
||||
1.0, 1.0)];
|
||||
}
|
||||
|
||||
- (void)setBackgroundHandColor:(CPColor)aColor
|
||||
{
|
||||
[_imageLayer setBackgroundColor:aColor];
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)aBoolean
|
||||
{
|
||||
_isEnabled = aBoolean;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
@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
|
||||
+1
-1
@@ -129,7 +129,7 @@ var CPDocumentUntitledCount = 0;
|
||||
if (self)
|
||||
{
|
||||
_windowControllers = [];
|
||||
_viewControllersForWindowControllers = [CPDictionary dictionary];
|
||||
_viewControllersForWindowControllers = @{};
|
||||
|
||||
_hasUndoManager = YES;
|
||||
_changeCount = 0;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
+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
|
||||
|
||||
+2
-2
@@ -235,7 +235,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
*/
|
||||
- (CGPoint)locationInWindow
|
||||
{
|
||||
return _CGPointMakeCopy(_location);
|
||||
return CGPointMakeCopy(_location);
|
||||
}
|
||||
|
||||
- (CGPoint)globalLocation
|
||||
@@ -527,7 +527,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:(id)sommit
|
||||
{
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
+8
-6
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
+25
-2
@@ -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];
|
||||
@@ -148,7 +148,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = CGSizeCreateCopy(aSize);
|
||||
_size = CGSizeMakeCopy(aSize);
|
||||
_filename = aFilename;
|
||||
_loadStatus = CPImageLoadStatusInitialized;
|
||||
}
|
||||
@@ -302,6 +302,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 +398,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
@@ -521,6 +534,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return _isVertical;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return YES;
|
||||
@@ -585,6 +603,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
return _imageSlices;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
|
||||
+43
-9
@@ -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
|
||||
@@ -300,8 +302,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 +401,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 +476,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];
|
||||
}
|
||||
|
||||
- (void)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",
|
||||
@@ -568,3 +584,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";
|
||||
|
||||
+14
-22
@@ -64,16 +64,16 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
|
||||
+ (id)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];
|
||||
}
|
||||
|
||||
+73
-18
@@ -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;
|
||||
}
|
||||
@@ -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,8 +615,9 @@ 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
|
||||
{
|
||||
@@ -609,6 +625,7 @@ var _CPMenuBarVisible = NO,
|
||||
return;
|
||||
|
||||
var items = [self itemArray];
|
||||
|
||||
for (var i = 0; i < [items count]; i++)
|
||||
{
|
||||
var item = [items objectAtIndex:i];
|
||||
@@ -618,7 +635,31 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
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])
|
||||
[item setEnabled: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)])
|
||||
[item setEnabled:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (![validator respondsToSelector:[item action]])
|
||||
[item setEnabled:NO];
|
||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
@@ -668,7 +709,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];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -804,6 +851,8 @@ var _CPMenuBarVisible = NO,
|
||||
var theWindow = [aView window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:aMenu font:aFont];
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuWindow];
|
||||
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
var constraintRect = [CPMenu _constraintRectForView:aView],
|
||||
@@ -899,6 +948,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 +971,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
[CPApp sendEvent:[CPEvent
|
||||
otherEventWithType:CPAppKitDefined
|
||||
location:_CGPointMakeZero()
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
@@ -1098,12 +1151,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 +1166,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
|
||||
|
||||
@@ -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)
|
||||
@@ -428,8 +457,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 +554,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 +568,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 +590,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 +727,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 +737,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
|
||||
*/
|
||||
@@ -82,13 +80,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 +209,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"],
|
||||
@@ -436,39 +436,34 @@ var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
+ (id)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];
|
||||
|
||||
@@ -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
|
||||
@@ -47,13 +51,11 @@
|
||||
|
||||
+ (id)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;
|
||||
}
|
||||
|
||||
- (CPColor)setTextColor:(CPColor)aColor
|
||||
{
|
||||
_textColor = aColor;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CPColor)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
_textShadowColor = aColor;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CPColor)setHighlightTextColor:(CPColor)aColor
|
||||
{
|
||||
_highlightTextColor = aColor;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CPColor)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;
|
||||
@@ -48,22 +47,25 @@
|
||||
|
||||
+ (id)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;
|
||||
@@ -61,8 +55,7 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[]
|
||||
forKeys:[]];
|
||||
return @{};
|
||||
}
|
||||
|
||||
// Not used in the Appkit
|
||||
@@ -227,6 +220,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 +276,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);
|
||||
|
||||
+28
-11
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPCountedSet.j>
|
||||
@import <Foundation/_CPCollectionKVCOperators.j>
|
||||
|
||||
@import "CPController.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@@ -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];
|
||||
|
||||
@@ -567,7 +578,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];
|
||||
@@ -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];
|
||||
@@ -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
|
||||
|
||||
+79
-52
@@ -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_;
|
||||
|
||||
@@ -708,27 +710,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 +881,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 +974,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
|
||||
@@ -1059,7 +1075,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
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 +1089,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 +1113,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]];
|
||||
@@ -1303,7 +1319,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
var disclosureControlFrame = [self frameOfOutlineDisclosureControlAtRow:row];
|
||||
|
||||
if (_CGRectIsEmpty(disclosureControlFrame))
|
||||
if (CGRectIsEmpty(disclosureControlFrame))
|
||||
continue;
|
||||
|
||||
var control = [self _dequeueDisclosureControl];
|
||||
@@ -1360,7 +1376,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 +1457,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1452,7 +1468,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemDidExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1463,7 +1479,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillCollapseNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1474,7 +1490,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 +1549,31 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
|
||||
- (CPView)_viewForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
|
||||
{
|
||||
return [_outlineViewDelegate outlineView:self viewForTableColumn:aTableColumn item:[self itemAtRow:aRow]];
|
||||
}
|
||||
|
||||
- (CPView)_dataViewForTableColumn:(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_;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
@@ -1826,21 +1867,6 @@ 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
|
||||
{
|
||||
return SHOULD_SELECT_ITEM(_outlineView, [_outlineView itemAtRow:theRow]);
|
||||
@@ -1929,14 +1955,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 +1974,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 +1983,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 +2026,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
|
||||
|
||||
@@ -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,8 +188,8 @@ var CPPasteboards = nil,
|
||||
{
|
||||
[_types setArray:types];
|
||||
|
||||
_owners = [CPDictionary dictionary];
|
||||
_provided = [CPDictionary dictionary];
|
||||
_owners = @{};
|
||||
_provided = @{};
|
||||
|
||||
var count = _types.length;
|
||||
|
||||
@@ -248,14 +248,14 @@ var CPPasteboards = nil,
|
||||
|
||||
// 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]];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
+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
|
||||
|
||||
+210
-13
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -123,8 +124,16 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
|
||||
+ (id)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
|
||||
@@ -790,7 +799,7 @@ TODO: implement
|
||||
*/
|
||||
- (CPPredicate)predicateForRow:(CPInteger)aRow
|
||||
{
|
||||
var predicateParts = [CPDictionary dictionary],
|
||||
var predicateParts = @{},
|
||||
items = [self criteriaForRow:aRow],
|
||||
count = [items count],
|
||||
predicate,
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
|
||||
+54
-54
@@ -143,15 +143,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 +165,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 +186,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 +517,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 +582,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 +859,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 +876,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 +924,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 +961,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 +1096,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
}
|
||||
|
||||
[_contentView setFrame:[self _insetBounds]];
|
||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||
[_headerClipView setFrame:CGRectMakeZero()];
|
||||
|
||||
--_recursionCount;
|
||||
|
||||
@@ -1106,12 +1106,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 +1162,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 +1183,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 +1272,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 +1290,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 +1324,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 +1357,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 +1395,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
|
||||
|
||||
+84
-72
@@ -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";
|
||||
@@ -108,19 +110,19 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
+ (id)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,19 @@ 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 +321,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
if (aPart == CPScrollerNoPart)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
return _partRects[aPart];
|
||||
}
|
||||
@@ -379,8 +391,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 +406,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 +435,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 +517,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 +531,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 +606,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 +651,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 +685,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 +705,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 +746,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 +801,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 +813,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
|
||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
||||
|
||||
@@ -819,17 +828,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 +851,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];
|
||||
}
|
||||
|
||||
+11
-12
@@ -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
|
||||
@@ -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];
|
||||
|
||||
+125
-4
@@ -58,8 +58,33 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
+ (id)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
|
||||
|
||||
@@ -49,11 +49,10 @@ CPThemeStateShadowViewHeavy = CPThemeState("shadowview-style-heavy");
|
||||
|
||||
+ (id)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
|
||||
|
||||
+31
-27
@@ -51,8 +51,12 @@ CPCircularSlider = 1;
|
||||
|
||||
+ (id)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;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,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 +165,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 +184,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 +282,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 +316,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 +366,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;
|
||||
}
|
||||
|
||||
+20
-16
@@ -105,16 +105,13 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
+ (id)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
|
||||
}
|
||||
|
||||
@@ -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)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-13
@@ -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];
|
||||
@@ -269,8 +269,12 @@
|
||||
|
||||
+ (id)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
|
||||
|
||||
+36
-18
@@ -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]];
|
||||
@@ -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];
|
||||
|
||||
|
||||
+11
-23
@@ -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
|
||||
@@ -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
|
||||
@@ -757,7 +745,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
_dataViewData = { };
|
||||
_dataViewData = nil;
|
||||
|
||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||
|
||||
+64
-35
@@ -45,8 +45,16 @@
|
||||
|
||||
+ (id)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
|
||||
@@ -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;
|
||||
@@ -239,14 +248,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
|
||||
forKeys:[@"background-color", @"divider-color"]];
|
||||
return @{
|
||||
@"background-color": [CPNull null],
|
||||
@"divider-color": [CPColor grayColor],
|
||||
};
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_mouseDownLocation = _CGPointMakeZero();
|
||||
_previousTrackingLocation = _CGPointMakeZero();
|
||||
_mouseDownLocation = CGPointMakeZero();
|
||||
_previousTrackingLocation = CGPointMakeZero();
|
||||
_activeColumn = -1;
|
||||
_pressedColumn = -1;
|
||||
|
||||
@@ -280,8 +291,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
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;
|
||||
}
|
||||
@@ -299,11 +310,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (CGRect)_cursorRectForColumn:(int)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 +332,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[column] headerView];
|
||||
[headerView setThemeState:CPThemeStateHighlighted];
|
||||
|
||||
if (_tableView._editingColumn == column)
|
||||
[[self window] makeFirstResponder:_tableView];
|
||||
}
|
||||
|
||||
_pressedColumn = column;
|
||||
@@ -340,7 +354,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)
|
||||
{
|
||||
@@ -384,7 +398,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)
|
||||
{
|
||||
@@ -404,6 +418,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
_lastDragDestinationColumnIndex = -1;
|
||||
[self _setPressedColumn:aColumnIndex];
|
||||
}
|
||||
|
||||
@@ -412,14 +427,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
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;
|
||||
@@ -431,7 +446,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (BOOL)_shouldStopTrackingTableColumn:(int)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
|
||||
@@ -442,7 +457,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
|
||||
return ABS(aPoint.x - _mouseDownLocation.x) >= 10.0 && [_tableView _shouldReorderColumn:aColumnIndex toColumn:-1];
|
||||
}
|
||||
|
||||
- (CGRect)_headerRectOfLastVisibleColumn
|
||||
@@ -475,10 +490,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];
|
||||
@@ -490,9 +505,12 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
|
||||
{
|
||||
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||
_activeColumn = aToIndex;
|
||||
_pressedColumn = _activeColumn;
|
||||
if ([_tableView _shouldReorderColumn:aFromIndex toColumn:aToIndex])
|
||||
{
|
||||
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||
_activeColumn = aToIndex;
|
||||
_pressedColumn = _activeColumn;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
|
||||
@@ -517,9 +535,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 +546,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,6 +576,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self stopTrackingTableColumn:_activeColumn at:aLocation];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[_tableView _enqueueDraggingViews];
|
||||
}
|
||||
|
||||
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
@@ -561,7 +588,7 @@ 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
|
||||
@@ -617,7 +644,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];
|
||||
@@ -699,17 +726,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, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(CGRectGetMaxY(columnToStroke)) - 1.0);
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
|
||||
+812
-241
File diff suppressed because it is too large
Load Diff
+117
-51
@@ -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,18 +209,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return "textfield";
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
{
|
||||
if (theBinding === CPValueBinding)
|
||||
return [_CPTextFieldValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(1.0, 0.0, 0.0, 0.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
return @{
|
||||
@"bezel-inset": CGInsetMakeZero(),
|
||||
@"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
|
||||
@"bezel-color": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -226,10 +238,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 +252,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return;
|
||||
|
||||
var cappEvent = [CPEvent keyEventWithType:CPKeyUp
|
||||
location:_CGPointMakeZero()
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:[CPEvent currentTimestamp]
|
||||
windowNumber:[[CPApp keyWindow] windowNumber]
|
||||
@@ -343,6 +355,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEditable && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
|
||||
if (shouldBeEditable)
|
||||
[self setThemeState:CPThemeStateEditable];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateEditable];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -515,7 +532,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
/* @ignore */
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return [self isEditable] && [self isEnabled];
|
||||
return [self isEditable] && [self isEnabled] && [self _isWithinUsablePlatformRect];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -527,7 +544,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
_isEditing = NO;
|
||||
|
||||
if ([[self window] isKeyWindow])
|
||||
[self _becomeFirstKeyResponder];
|
||||
return [self _becomeFirstKeyResponder];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -537,8 +554,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
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.)
|
||||
*/
|
||||
- (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;
|
||||
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -563,11 +585,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 +603,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 +640,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (!CPFeatureIsCompatible(CPInputSetFontOutsideOfDOM))
|
||||
element.style.font = [font cssString];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
|
||||
if (document.attachEvent)
|
||||
@@ -647,6 +673,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -756,7 +784,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)_windowDidBecomeKey:(CPNotification)aNotification
|
||||
{
|
||||
if ([[self window] isKeyWindow] && [[self window] firstResponder] === self)
|
||||
[self _becomeFirstKeyResponder];
|
||||
if (![self _becomeFirstKeyResponder])
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
- (BOOL)_valueIsValid:(CPString)aValue
|
||||
@@ -765,7 +794,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;
|
||||
|
||||
@@ -1032,7 +1061,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,7 +1100,7 @@ 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];
|
||||
@@ -1158,7 +1187,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;
|
||||
@@ -1452,14 +1481,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 +1506,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 +1514,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
else
|
||||
{
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -1552,6 +1581,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
}
|
||||
|
||||
#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],
|
||||
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 +1676,8 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
@end
|
||||
|
||||
@implementation _CPTextFieldValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPBinder)aBinding
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
@@ -1649,8 +1695,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--)
|
||||
{
|
||||
|
||||
+264
-72
@@ -20,20 +20,18 @@
|
||||
* 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
|
||||
|
||||
@@ -59,6 +57,9 @@ var CPScrollDestinationNone = 0,
|
||||
CPScrollDestinationLeft = 1,
|
||||
CPScrollDestinationRight = 2;
|
||||
|
||||
CPTokenFieldDisclosureButtonType = 0;
|
||||
CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
@implementation CPTokenField : CPTextField
|
||||
{
|
||||
CPScrollView _tokenScrollView;
|
||||
@@ -76,6 +77,8 @@ var CPScrollDestinationNone = 0,
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _shouldNotifyTarget;
|
||||
|
||||
int _buttonType @accessors(property=buttonType);
|
||||
}
|
||||
|
||||
+ (CPCharacterSet)defaultTokenizingCharacterSet
|
||||
@@ -95,7 +98,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObject:_CGInsetMakeZero() forKey:@"editor-inset"];
|
||||
return @{ @"editor-inset": CGInsetMakeZero() };
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
@@ -104,6 +107,7 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
_completionDelay = [[self class] defaultCompletionDelay];
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
_buttonType = CPTokenFieldDisclosureButtonType;
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
@@ -118,7 +122,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedRange = _CPMakeRange(0, 0);
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
var frame = [self frame];
|
||||
|
||||
@@ -208,7 +212,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
if (delegateApprovedObjectsCount)
|
||||
location += delegateApprovedObjectsCount;
|
||||
_selectedRange = _CPMakeRange(location, 0);
|
||||
_selectedRange = CPMakeRange(location, 0);
|
||||
|
||||
[self _inputElement].value = @"";
|
||||
[self setNeedsLayout];
|
||||
@@ -228,12 +232,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 +247,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 +300,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 +327,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 +361,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 +380,19 @@ 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);
|
||||
}, 0.0);
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
@@ -389,6 +408,8 @@ var CPScrollDestinationNone = 0,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
@@ -470,7 +491,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 +582,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
if (newToken === nil)
|
||||
{
|
||||
newToken = [[_CPTokenFieldToken alloc] init];
|
||||
newToken = [_CPTokenFieldToken new];
|
||||
[newToken setTokenField:self];
|
||||
[newToken setRepresentedObject:tokenObject];
|
||||
[newToken setStringValue:tokenValue];
|
||||
@@ -652,10 +673,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 +827,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 +848,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 +927,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 +1019,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 +1036,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 +1053,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 +1088,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 +1110,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 +1135,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 +1148,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 +1161,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 +1193,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 +1264,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 +1312,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 +1347,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 +1374,7 @@ var CPScrollDestinationNone = 0,
|
||||
- (void)setRepresentedObject:(id)representedObject
|
||||
{
|
||||
_representedObject = representedObject;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
@@ -1329,9 +1387,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 +1401,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 +1424,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 +1473,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,11 +1519,18 @@ var CPScrollDestinationNone = 0,
|
||||
[_tokenField _deleteToken:self];
|
||||
}
|
||||
|
||||
- (BOOL)hasMenu
|
||||
{
|
||||
return [_tokenField _hasMenuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
- (CPMenu)menu
|
||||
{
|
||||
return [_tokenField _menuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
Theming hook.
|
||||
*/
|
||||
@implementation _CPTokenFieldTokenCloseButton : CPButton
|
||||
{
|
||||
}
|
||||
@@ -1411,7 +1539,7 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
var attributes = [CPButton themeAttributes];
|
||||
|
||||
[attributes setObject:_CGPointMake(15, 5) forKey:@"offset"];
|
||||
[attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
|
||||
|
||||
return attributes;
|
||||
}
|
||||
@@ -1421,11 +1549,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
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)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 +1627,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 +1644,7 @@ var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSe
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
[aCoder encodeInt:_buttonType forKey:CPTokenFieldButtonTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+32
-40
@@ -118,8 +118,8 @@ var CPToolbarsByIdentifier = nil,
|
||||
if (self !== [CPToolbar class])
|
||||
return;
|
||||
|
||||
CPToolbarsByIdentifier = [CPDictionary dictionary];
|
||||
CPToolbarConfigurationsByIdentifier = [CPDictionary dictionary];
|
||||
CPToolbarsByIdentifier = @{};
|
||||
CPToolbarConfigurationsByIdentifier = @{};
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -230,7 +230,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;
|
||||
|
||||
@@ -605,25 +605,17 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
+ (id)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 +629,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 +679,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 +766,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 +801,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
remainingSpace += proposedWidth - constrainedWidth;
|
||||
}
|
||||
|
||||
[view setFrameSize:_CGSizeMake(constrainedWidth, height)];
|
||||
[view setFrameSize:CGSizeMake(constrainedWidth, height)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,9 +815,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 +851,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 +994,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 +1101,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 +1116,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 +1133,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 +1210,7 @@ var LABEL_MARGIN = 2.0;
|
||||
if (alternateImage)
|
||||
[_imageView setImage:alternateImage];
|
||||
|
||||
[_labelField setTextShadowOffset:_CGSizeMakeZero()];
|
||||
[_labelField setTextShadowOffset:CGSizeMakeZero()];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1227,7 +1219,7 @@ 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]];
|
||||
|
||||
+164
-100
@@ -30,6 +30,7 @@
|
||||
@import "CPGraphicsContext.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPTheme.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPDisplayServer.j"
|
||||
|
||||
@class _CPToolTip
|
||||
@@ -41,9 +42,6 @@
|
||||
@class CPScrollView
|
||||
|
||||
@global appkit_tag_dom_elements
|
||||
@global CPWindowAbove
|
||||
@global CPBorderlessWindowMask
|
||||
@global CPScreenSaverWindowLevel
|
||||
|
||||
/*
|
||||
@global
|
||||
@@ -136,6 +134,7 @@ var CPViewFlags = { },
|
||||
CPGraphicsContext _graphicsContext;
|
||||
|
||||
int _tag;
|
||||
CPString _identifier @accessors(property=identifier);
|
||||
|
||||
CGRect _frame;
|
||||
CGRect _bounds;
|
||||
@@ -229,6 +228,14 @@ var CPViewFlags = { },
|
||||
CachedNotificationCenter = [CPNotificationCenter defaultCenter];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if ([aBinding hasPrefix:CPHiddenBinding])
|
||||
return [CPMultipleValueOrBinding class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (void)_setupViewFlags
|
||||
{
|
||||
var theClass = [self class],
|
||||
@@ -287,8 +294,8 @@ var CPViewFlags = { },
|
||||
|
||||
if (self)
|
||||
{
|
||||
var width = _CGRectGetWidth(aFrame),
|
||||
height = _CGRectGetHeight(aFrame);
|
||||
var width = CGRectGetWidth(aFrame),
|
||||
height = CGRectGetHeight(aFrame);
|
||||
|
||||
_subviews = [];
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
@@ -296,8 +303,8 @@ var CPViewFlags = { },
|
||||
|
||||
_tag = -1;
|
||||
|
||||
_frame = _CGRectMakeCopy(aFrame);
|
||||
_bounds = _CGRectMake(0.0, 0.0, width, height);
|
||||
_frame = CGRectMakeCopy(aFrame);
|
||||
_bounds = CGRectMake(0.0, 0.0, width, height);
|
||||
|
||||
_autoresizingMask = CPViewNotSizable;
|
||||
_autoresizesSubviews = YES;
|
||||
@@ -310,7 +317,7 @@ var CPViewFlags = { },
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement = DOMElementPrototype.cloneNode(false);
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame));
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, CGRectGetMinX(aFrame), CGRectGetMinY(aFrame));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
|
||||
|
||||
if (typeof(appkit_tag_dom_elements) !== "undefined" && !!appkit_tag_dom_elements)
|
||||
@@ -366,9 +373,9 @@ var CPViewFlags = { },
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMElement.addEventListener)
|
||||
{
|
||||
_DOMElement.addEventListener("mouseover", _toolTipFunctionIn, NO);
|
||||
_DOMElement.addEventListener("keypress", _toolTipFunctionOut, NO);
|
||||
_DOMElement.addEventListener("mouseout", _toolTipFunctionOut, NO);
|
||||
_DOMElement.addEventListener("mouseover", _toolTipFunctionIn, YES);
|
||||
_DOMElement.addEventListener("keypress", _toolTipFunctionOut, YES);
|
||||
_DOMElement.addEventListener("mouseout", _toolTipFunctionOut, YES);
|
||||
}
|
||||
else if (_DOMElement.attachEvent)
|
||||
{
|
||||
@@ -393,9 +400,9 @@ var CPViewFlags = { },
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMElement.removeEventListener)
|
||||
{
|
||||
_DOMElement.removeEventListener("mouseover", _toolTipFunctionIn, NO);
|
||||
_DOMElement.removeEventListener("keypress", _toolTipFunctionOut, NO);
|
||||
_DOMElement.removeEventListener("mouseout", _toolTipFunctionOut, NO);
|
||||
_DOMElement.removeEventListener("mouseover", _toolTipFunctionIn, YES);
|
||||
_DOMElement.removeEventListener("keypress", _toolTipFunctionOut, YES);
|
||||
_DOMElement.removeEventListener("mouseout", _toolTipFunctionOut, YES);
|
||||
}
|
||||
else if (_DOMElement.detachEvent)
|
||||
{
|
||||
@@ -469,6 +476,10 @@ var CPViewFlags = { },
|
||||
{
|
||||
if (aSubview === self)
|
||||
[CPException raise:CPInvalidArgumentException reason:"can't add a view as a subview of itself"];
|
||||
#if DEBUG
|
||||
if (!aSubview._superview && _subviews.indexOf(aSubview) !== CPNotFound)
|
||||
[CPException raise:CPInvalidArgumentException reason:"can't insert a subview in duplicate (probably partially decoded)"];
|
||||
#endif
|
||||
|
||||
// We will have to adjust the z-index of all views starting at this index.
|
||||
var count = _subviews.length;
|
||||
@@ -559,10 +570,10 @@ var CPViewFlags = { },
|
||||
|
||||
[_superview willRemoveSubview:self];
|
||||
|
||||
[_superview._subviews removeObject:self];
|
||||
[_superview._subviews removeObjectIdenticalTo:self];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
|
||||
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
|
||||
#endif
|
||||
_superview = nil;
|
||||
|
||||
@@ -818,7 +829,7 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (void)setFrame:(CGRect)aFrame
|
||||
{
|
||||
if (_CGRectEqualToRect(_frame, aFrame))
|
||||
if (CGRectEqualToRect(_frame, aFrame))
|
||||
return;
|
||||
|
||||
_inhibitFrameAndBoundsChangedNotifications = YES;
|
||||
@@ -838,17 +849,17 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (CGRect)frame
|
||||
{
|
||||
return _CGRectMakeCopy(_frame);
|
||||
return CGRectMakeCopy(_frame);
|
||||
}
|
||||
|
||||
- (CGPoint)frameOrigin
|
||||
{
|
||||
return _CGPointMakeCopy(_frame.origin);
|
||||
return CGPointMakeCopy(_frame.origin);
|
||||
}
|
||||
|
||||
- (CGSize)frameSize
|
||||
{
|
||||
return _CGSizeMakeCopy(_frame.size);
|
||||
return CGSizeMakeCopy(_frame.size);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -883,7 +894,7 @@ var CPViewFlags = { },
|
||||
{
|
||||
var origin = _frame.origin;
|
||||
|
||||
if (!aPoint || _CGPointEqualToPoint(origin, aPoint))
|
||||
if (!aPoint || CGPointEqualToPoint(origin, aPoint))
|
||||
return;
|
||||
|
||||
origin.x = aPoint.x;
|
||||
@@ -909,10 +920,10 @@ var CPViewFlags = { },
|
||||
{
|
||||
var size = _frame.size;
|
||||
|
||||
if (!aSize || _CGSizeEqualToSize(size, aSize))
|
||||
if (!aSize || CGSizeEqualToSize(size, aSize))
|
||||
return;
|
||||
|
||||
var oldSize = _CGSizeMakeCopy(size);
|
||||
var oldSize = CGSizeMakeCopy(size);
|
||||
|
||||
size.width = aSize.width;
|
||||
size.height = aSize.height;
|
||||
@@ -1049,7 +1060,7 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (void)setBounds:(CGRect)bounds
|
||||
{
|
||||
if (_CGRectEqualToRect(_bounds, bounds))
|
||||
if (CGRectEqualToRect(_bounds, bounds))
|
||||
return;
|
||||
|
||||
_inhibitFrameAndBoundsChangedNotifications = YES;
|
||||
@@ -1069,17 +1080,17 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (CGRect)bounds
|
||||
{
|
||||
return _CGRectMakeCopy(_bounds);
|
||||
return CGRectMakeCopy(_bounds);
|
||||
}
|
||||
|
||||
- (CGPoint)boundsOrigin
|
||||
{
|
||||
return _CGPointMakeCopy(_bounds.origin);
|
||||
return CGPointMakeCopy(_bounds.origin);
|
||||
}
|
||||
|
||||
- (CGSize)boundsSize
|
||||
{
|
||||
return _CGSizeMakeCopy(_bounds.size);
|
||||
return CGSizeMakeCopy(_bounds.size);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1092,7 +1103,7 @@ var CPViewFlags = { },
|
||||
{
|
||||
var origin = _bounds.origin;
|
||||
|
||||
if (_CGPointEqualToPoint(origin, aPoint))
|
||||
if (CGPointEqualToPoint(origin, aPoint))
|
||||
return;
|
||||
|
||||
origin.x = aPoint.x;
|
||||
@@ -1100,7 +1111,7 @@ var CPViewFlags = { },
|
||||
|
||||
if (origin.x != 0 || origin.y != 0)
|
||||
{
|
||||
_boundsTransform = _CGAffineTransformMakeTranslation(-origin.x, -origin.y);
|
||||
_boundsTransform = CGAffineTransformMakeTranslation(-origin.x, -origin.y);
|
||||
_inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform);
|
||||
}
|
||||
else
|
||||
@@ -1135,12 +1146,12 @@ var CPViewFlags = { },
|
||||
{
|
||||
var size = _bounds.size;
|
||||
|
||||
if (_CGSizeEqualToSize(size, aSize))
|
||||
if (CGSizeEqualToSize(size, aSize))
|
||||
return;
|
||||
|
||||
var frameSize = _frame.size;
|
||||
|
||||
if (!_CGSizeEqualToSize(size, frameSize))
|
||||
if (!CGSizeEqualToSize(size, frameSize))
|
||||
{
|
||||
var origin = _bounds.origin;
|
||||
|
||||
@@ -1151,7 +1162,7 @@ var CPViewFlags = { },
|
||||
size.width = aSize.width;
|
||||
size.height = aSize.height;
|
||||
|
||||
if (!_CGSizeEqualToSize(size, frameSize))
|
||||
if (!CGSizeEqualToSize(size, frameSize))
|
||||
{
|
||||
var origin = _bounds.origin;
|
||||
|
||||
@@ -1176,21 +1187,29 @@ var CPViewFlags = { },
|
||||
return;
|
||||
|
||||
var frame = _superview._frame,
|
||||
newFrame = _CGRectMakeCopy(_frame),
|
||||
dX = (_CGRectGetWidth(frame) - aSize.width) /
|
||||
(((mask & CPViewMinXMargin) ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
|
||||
dY = (_CGRectGetHeight(frame) - aSize.height) /
|
||||
((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0));
|
||||
newFrame = CGRectMakeCopy(_frame),
|
||||
dX = frame.size.width - aSize.width,
|
||||
dY = frame.size.height - aSize.height,
|
||||
evenFractionX = 1.0 / ((mask & CPViewMinXMargin ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
|
||||
evenFractionY = 1.0 / ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0)),
|
||||
baseX = (mask & CPViewMinXMargin ? _frame.origin.x : 0) +
|
||||
(mask & CPViewWidthSizable ? _frame.size.width : 0) +
|
||||
(mask & CPViewMaxXMargin ? aSize.width - _frame.size.width - _frame.origin.x : 0),
|
||||
baseY = (mask & CPViewMinYMargin ? _frame.origin.y : 0) +
|
||||
(mask & CPViewHeightSizable ? _frame.size.height : 0) +
|
||||
(mask & CPViewMaxYMargin ? aSize.height - _frame.size.height - _frame.origin.y : 0);
|
||||
|
||||
if (mask & CPViewMinXMargin)
|
||||
newFrame.origin.x += dX;
|
||||
newFrame.origin.x += dX * (baseX > 0 ? _frame.origin.x / baseX : evenFractionX);
|
||||
|
||||
if (mask & CPViewWidthSizable)
|
||||
newFrame.size.width += dX;
|
||||
newFrame.size.width += dX * (baseX > 0 ? _frame.size.width / baseX : evenFractionX);
|
||||
|
||||
if (mask & CPViewMinYMargin)
|
||||
newFrame.origin.y += dY;
|
||||
newFrame.origin.y += dY * (baseY > 0 ? _frame.origin.y / baseY : evenFractionY);
|
||||
|
||||
if (mask & CPViewHeightSizable)
|
||||
newFrame.size.height += dY;
|
||||
newFrame.size.height += dY * (baseY > 0 ? _frame.size.height / baseY : evenFractionY);
|
||||
|
||||
[self setFrame:newFrame];
|
||||
}
|
||||
@@ -1359,6 +1378,7 @@ var CPViewFlags = { },
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
[self _notifyViewDidUnhide];
|
||||
}
|
||||
}
|
||||
@@ -1494,7 +1514,7 @@ var CPViewFlags = { },
|
||||
|
||||
/*!
|
||||
Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.<br/>
|
||||
Returns \c YES by default.
|
||||
Returns \c NO by default.
|
||||
@return \c YES, if the view object accepts first mouse-down event. \c NO, otherwise.
|
||||
*/
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
@@ -1527,15 +1547,15 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
if (_isHidden || !_hitTests || !_CGRectContainsPoint(_frame, aPoint))
|
||||
if (_isHidden || !_hitTests || !CGRectContainsPoint(_frame, aPoint))
|
||||
return nil;
|
||||
|
||||
var view = nil,
|
||||
i = _subviews.length,
|
||||
adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame));
|
||||
adjustedPoint = CGPointMake(aPoint.x - CGRectGetMinX(_frame), aPoint.y - CGRectGetMinY(_frame));
|
||||
|
||||
if (_inverseBoundsTransform)
|
||||
adjustedPoint = _CGPointApplyAffineTransform(adjustedPoint, _inverseBoundsTransform);
|
||||
adjustedPoint = CGPointApplyAffineTransform(adjustedPoint, _inverseBoundsTransform);
|
||||
|
||||
while (i--)
|
||||
if (view = [_subviews[i] hitTest:adjustedPoint])
|
||||
@@ -1570,6 +1590,7 @@ var CPViewFlags = { },
|
||||
- (void)rightMouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var menu = [self menuForEvent:anEvent];
|
||||
|
||||
if (menu)
|
||||
[CPMenu popUpContextMenu:menu withEvent:anEvent forView:self];
|
||||
else if ([[self nextResponder] isKindOfClass:CPView])
|
||||
@@ -1973,9 +1994,6 @@ setFrameOrigin:
|
||||
return;
|
||||
|
||||
_postsFrameChangedNotifications = shouldPostFrameChangedNotifications;
|
||||
|
||||
if (_postsFrameChangedNotifications)
|
||||
[CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2006,9 +2024,6 @@ setBoundsOrigin:
|
||||
return;
|
||||
|
||||
_postsBoundsChangedNotifications = shouldPostBoundsChangedNotifications;
|
||||
|
||||
if (_postsBoundsChangedNotifications)
|
||||
[CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2121,20 +2136,20 @@ setBoundsOrigin:
|
||||
if (!(_viewClassFlags & CPViewHasCustomDrawRect))
|
||||
return;
|
||||
|
||||
if (_CGRectIsEmpty(aRect))
|
||||
if (CGRectIsEmpty(aRect))
|
||||
return;
|
||||
|
||||
if (_dirtyRect && !_CGRectIsEmpty(_dirtyRect))
|
||||
if (_dirtyRect && !CGRectIsEmpty(_dirtyRect))
|
||||
_dirtyRect = CGRectUnion(aRect, _dirtyRect);
|
||||
else
|
||||
_dirtyRect = _CGRectMakeCopy(aRect);
|
||||
_dirtyRect = CGRectMakeCopy(aRect);
|
||||
|
||||
_CPDisplayServerAddDisplayObject(self);
|
||||
}
|
||||
|
||||
- (BOOL)needsDisplay
|
||||
{
|
||||
return _dirtyRect && !_CGRectIsEmpty(_dirtyRect);
|
||||
return _dirtyRect && !CGRectIsEmpty(_dirtyRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2210,13 +2225,13 @@ setBoundsOrigin:
|
||||
_DOMContentsElement.style.position = "absolute";
|
||||
_DOMContentsElement.style.visibility = "visible";
|
||||
|
||||
_DOMContentsElement.width = ROUND(_CGRectGetWidth(_frame));
|
||||
_DOMContentsElement.height = ROUND(_CGRectGetHeight(_frame));
|
||||
_DOMContentsElement.width = ROUND(CGRectGetWidth(_frame));
|
||||
_DOMContentsElement.height = ROUND(CGRectGetHeight(_frame));
|
||||
|
||||
_DOMContentsElement.style.top = "0px";
|
||||
_DOMContentsElement.style.left = "0px";
|
||||
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
|
||||
_DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
|
||||
_DOMContentsElement.style.width = ROUND(CGRectGetWidth(_frame)) + "px";
|
||||
_DOMContentsElement.style.height = ROUND(CGRectGetHeight(_frame)) + "px";
|
||||
|
||||
// The performance implications of this aren't clear, but without this subviews might not be redrawn when this
|
||||
// view moves.
|
||||
@@ -2320,13 +2335,11 @@ setBoundsOrigin:
|
||||
*/
|
||||
- (BOOL)scrollRectToVisible:(CGRect)aRect
|
||||
{
|
||||
var visibleRect = [self visibleRect];
|
||||
|
||||
// Make sure we have a rect that exists.
|
||||
aRect = CGRectIntersection(aRect, _bounds);
|
||||
|
||||
// If aRect is empty or is already visible then no scrolling required.
|
||||
if (_CGRectIsEmpty(aRect) || CGRectContainsRect(visibleRect, aRect))
|
||||
// If aRect is empty no scrolling required.
|
||||
if (CGRectIsEmpty(aRect))
|
||||
return NO;
|
||||
|
||||
var enclosingClipView = [self _enclosingClipView];
|
||||
@@ -2335,20 +2348,34 @@ setBoundsOrigin:
|
||||
if (!enclosingClipView)
|
||||
return NO;
|
||||
|
||||
var scrollPoint = _CGPointMakeCopy(visibleRect.origin);
|
||||
var documentView = [enclosingClipView documentView];
|
||||
|
||||
// If the clip view doesn't have a document view, then there isn't much we can do.
|
||||
if (!documentView)
|
||||
return NO;
|
||||
|
||||
// Get the document view visible rect and convert aRect to the document view's coordinate system
|
||||
var documentViewVisibleRect = [documentView visibleRect],
|
||||
rectInDocumentView = [self convertRect:aRect toView:documentView];
|
||||
|
||||
// If already visible then no scrolling required.
|
||||
if (CGRectContainsRect(documentViewVisibleRect, rectInDocumentView))
|
||||
return NO;
|
||||
|
||||
var scrollPoint = CGPointMakeCopy(documentViewVisibleRect.origin);
|
||||
|
||||
// One of the following has to be true since our current visible rect didn't contain aRect.
|
||||
if (_CGRectGetMinX(aRect) <= _CGRectGetMinX(visibleRect))
|
||||
scrollPoint.x = _CGRectGetMinX(aRect);
|
||||
else if (_CGRectGetMaxX(aRect) > _CGRectGetMaxX(visibleRect))
|
||||
scrollPoint.x += _CGRectGetMaxX(aRect) - _CGRectGetMaxX(visibleRect);
|
||||
if (CGRectGetMinX(rectInDocumentView) < CGRectGetMinX(documentViewVisibleRect))
|
||||
scrollPoint.x = CGRectGetMinX(rectInDocumentView);
|
||||
else if (CGRectGetMaxX(rectInDocumentView) > CGRectGetMaxX(documentViewVisibleRect))
|
||||
scrollPoint.x += CGRectGetMaxX(rectInDocumentView) - CGRectGetMaxX(documentViewVisibleRect);
|
||||
|
||||
if (_CGRectGetMinY(aRect) <= _CGRectGetMinY(visibleRect))
|
||||
scrollPoint.y = CGRectGetMinY(aRect);
|
||||
else if (_CGRectGetMaxY(aRect) > _CGRectGetMaxY(visibleRect))
|
||||
scrollPoint.y += _CGRectGetMaxY(aRect) - _CGRectGetMaxY(visibleRect);
|
||||
if (CGRectGetMinY(rectInDocumentView) < CGRectGetMinY(documentViewVisibleRect))
|
||||
scrollPoint.y = CGRectGetMinY(rectInDocumentView);
|
||||
else if (CGRectGetMaxY(rectInDocumentView) > CGRectGetMaxY(documentViewVisibleRect))
|
||||
scrollPoint.y += CGRectGetMaxY(rectInDocumentView) - CGRectGetMaxY(documentViewVisibleRect);
|
||||
|
||||
[enclosingClipView scrollToPoint:CGPointMake(scrollPoint.x, scrollPoint.y)];
|
||||
[enclosingClipView scrollToPoint:scrollPoint];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -2532,21 +2559,35 @@ setBoundsOrigin:
|
||||
|
||||
- (void)_setPreviousKeyView:(CPView)previous
|
||||
{
|
||||
if ([previous isEqual:self])
|
||||
_previousKeyView = nil;
|
||||
else
|
||||
_previousKeyView = previous;
|
||||
if (![previous isEqual:self])
|
||||
{
|
||||
var previousWindow = [previous window];
|
||||
|
||||
if (!previousWindow || previousWindow === _window)
|
||||
{
|
||||
_previousKeyView = previous;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_previousKeyView = nil;
|
||||
}
|
||||
|
||||
- (void)setNextKeyView:(CPView)next
|
||||
{
|
||||
if ([next isEqual:self])
|
||||
_nextKeyView = nil;
|
||||
else
|
||||
if (![next isEqual:self])
|
||||
{
|
||||
_nextKeyView = next;
|
||||
[_nextKeyView _setPreviousKeyView:self];
|
||||
var nextWindow = [next window];
|
||||
|
||||
if (!nextWindow || nextWindow === _window)
|
||||
{
|
||||
_nextKeyView = next;
|
||||
[_nextKeyView _setPreviousKeyView:self];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_nextKeyView = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2768,6 +2809,12 @@ setBoundsOrigin:
|
||||
[self viewDidChangeTheme];
|
||||
}
|
||||
|
||||
- (void)_setThemeIncludingDescendants:(CPTheme)aTheme
|
||||
{
|
||||
[self setTheme:aTheme];
|
||||
[[self subviews] makeObjectsPerformSelector:@selector(_setThemeIncludingDescendants:) withObject:aTheme];
|
||||
}
|
||||
|
||||
- (CPTheme)theme
|
||||
{
|
||||
return _theme;
|
||||
@@ -2791,7 +2838,7 @@ setBoundsOrigin:
|
||||
|
||||
- (CPDictionary)_themeAttributeDictionary
|
||||
{
|
||||
var dictionary = [CPDictionary dictionary];
|
||||
var dictionary = @{};
|
||||
|
||||
if (_themeAttributes)
|
||||
{
|
||||
@@ -2917,7 +2964,7 @@ setBoundsOrigin:
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
}
|
||||
|
||||
- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
|
||||
@@ -2984,7 +3031,8 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
CPViewThemeStateKey = @"CPViewThemeStateKey",
|
||||
CPViewWindowKey = @"CPViewWindowKey",
|
||||
CPViewNextKeyViewKey = @"CPViewNextKeyViewKey",
|
||||
CPViewPreviousKeyViewKey = @"CPViewPreviousKeyViewKey";
|
||||
CPViewPreviousKeyViewKey = @"CPViewPreviousKeyViewKey",
|
||||
CPReuseIdentifierKey = @"CPReuseIdentifierKey";
|
||||
|
||||
@implementation CPView (CPCoding)
|
||||
|
||||
@@ -3013,11 +3061,24 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
{
|
||||
// We have to manually check because it may be 0, so we can't use ||
|
||||
_tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1;
|
||||
_identifier = [aCoder decodeObjectForKey:CPReuseIdentifierKey];
|
||||
|
||||
_window = [aCoder decodeObjectForKey:CPViewWindowKey];
|
||||
_subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || [];
|
||||
_superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
|
||||
|
||||
// We have to manually add the subviews so that they will receive
|
||||
// viewWillMoveToSuperview: and viewDidMoveToSuperview:
|
||||
_subviews = [];
|
||||
|
||||
var subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || [];
|
||||
|
||||
for (var i = 0, count = [subviews count]; i < count; ++i)
|
||||
{
|
||||
// addSubview won't do anything if the superview is already self, so clear it
|
||||
subviews[i]._superview = nil;
|
||||
[self addSubview:subviews[i]];
|
||||
}
|
||||
|
||||
// FIXME: Should we encode/decode this?
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
_registeredDraggedTypesArray = [];
|
||||
@@ -3042,8 +3103,8 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
_DOMImageParts = [];
|
||||
_DOMImageSizes = [];
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMElement, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame));
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, CGRectGetMinX(_frame), CGRectGetMinY(_frame));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMElement, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
|
||||
|
||||
var index = 0,
|
||||
count = _subviews.length;
|
||||
@@ -3163,6 +3224,9 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
for (var attributeName in _themeAttributes)
|
||||
if (_themeAttributes.hasOwnProperty(attributeName))
|
||||
CPThemeAttributeEncode(aCoder, _themeAttributes[attributeName]);
|
||||
|
||||
if (_identifier)
|
||||
[aCoder encodeObject:_identifier forKey:CPReuseIdentifierKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -3192,12 +3256,12 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
{
|
||||
var frame = view._frame;
|
||||
|
||||
transform.tx += _CGRectGetMinX(frame);
|
||||
transform.ty += _CGRectGetMinY(frame);
|
||||
transform.tx += CGRectGetMinX(frame);
|
||||
transform.ty += CGRectGetMinY(frame);
|
||||
|
||||
if (view._boundsTransform)
|
||||
{
|
||||
_CGAffineTransformConcatTo(transform, view._boundsTransform, transform);
|
||||
CGAffineTransformConcatTo(transform, view._boundsTransform, transform);
|
||||
}
|
||||
|
||||
view = view._superview;
|
||||
@@ -3218,8 +3282,8 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
|
||||
var frame = [fromWindow frame];
|
||||
|
||||
transform.tx += _CGRectGetMinX(frame);
|
||||
transform.ty += _CGRectGetMinY(frame);
|
||||
transform.tx += CGRectGetMinX(frame);
|
||||
transform.ty += CGRectGetMinY(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3231,12 +3295,12 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
{
|
||||
var frame = view._frame;
|
||||
|
||||
transform.tx -= _CGRectGetMinX(frame);
|
||||
transform.ty -= _CGRectGetMinY(frame);
|
||||
transform.tx -= CGRectGetMinX(frame);
|
||||
transform.ty -= CGRectGetMinY(frame);
|
||||
|
||||
if (view._boundsTransform)
|
||||
{
|
||||
_CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform);
|
||||
CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform);
|
||||
}
|
||||
|
||||
view = view._superview;
|
||||
@@ -3246,8 +3310,8 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
{
|
||||
var frame = [toWindow frame];
|
||||
|
||||
transform.tx -= _CGRectGetMinX(frame);
|
||||
transform.ty -= _CGRectGetMinY(frame);
|
||||
transform.tx -= CGRectGetMinX(frame);
|
||||
transform.ty -= CGRectGetMinY(frame);
|
||||
}
|
||||
/* var views = [],
|
||||
view = toView;
|
||||
@@ -3264,8 +3328,8 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
{
|
||||
var frame = views[index]._frame;
|
||||
|
||||
transform.tx -= _CGRectGetMinX(frame);
|
||||
transform.ty -= _CGRectGetMinY(frame);
|
||||
transform.tx -= CGRectGetMinX(frame);
|
||||
transform.ty -= CGRectGetMinY(frame);
|
||||
}*/
|
||||
|
||||
return transform;
|
||||
|
||||
@@ -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:.
|
||||
@@ -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;
|
||||
|
||||
|
||||
+3551
-12
File diff suppressed because it is too large
Load Diff
@@ -189,3 +189,8 @@ CPWindowPositionFlexibleRight = 1 << 19;
|
||||
CPWindowPositionFlexibleLeft = 1 << 20;
|
||||
CPWindowPositionFlexibleBottom = 1 << 21;
|
||||
CPWindowPositionFlexibleTop = 1 << 22;
|
||||
|
||||
CPStandardWindowShadowStyle = 0;
|
||||
CPMenuWindowShadowStyle = 1;
|
||||
CPPanelWindowShadowStyle = 2;
|
||||
CPCustomWindowShadowStyle = 3;
|
||||
|
||||
@@ -34,8 +34,9 @@
|
||||
|
||||
+ (id)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
|
||||
@@ -36,8 +35,21 @@
|
||||
|
||||
+ (id)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,18 +22,16 @@
|
||||
|
||||
@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),
|
||||
var _CPPopoverWindowViewDefaultCursorSize = CGSizeMake(16, 10),
|
||||
_CPPopoverWindowViewRadius = 5.0,
|
||||
_CPPopoverWindowViewStrokeWidth = 1.0,
|
||||
_CPPopoverWindowViewShadowSize = _CGSizeMake(0, 6),
|
||||
_CPPopoverWindowViewShadowSize = CGSizeMake(0, 6),
|
||||
_CPPopoverWindowViewShadowBlur = 15.0;
|
||||
|
||||
/*!
|
||||
@@ -51,6 +49,21 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
CGSize _cursorSize;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"popover-window-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"background-gradient": [CPNull null],
|
||||
@"background-gradient-hud": [CPNull null],
|
||||
@"stroke-color": [CPNull null],
|
||||
@"stroke-color-hud": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -157,28 +170,13 @@ var _CPPopoverWindowViewDefaultCursorSize = _CGSizeMake(16, 10),
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
@implementation _CPShadowWindowView : CPView
|
||||
@@ -44,8 +43,7 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[]
|
||||
forKeys:[]];
|
||||
return @{};
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -56,7 +54,7 @@
|
||||
shadowDistance = [_windowView valueForThemeAttribute:@"shadow-distance"],
|
||||
shadowInset = [_windowView valueForThemeAttribute:@"shadow-inset"],
|
||||
size = [_windowView frameSize],
|
||||
shadowSize = _CGSizeMake(size.width, size.height);
|
||||
shadowSize = CGSizeMake(size.width, size.height);
|
||||
|
||||
// if the shadow would be taller/wider than the window height,
|
||||
// make it the same as the window height. this allows views to
|
||||
|
||||
@@ -20,18 +20,20 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPTextField.j"
|
||||
@import "_CPTitleableWindowView.j"
|
||||
@import "CPButton.j"
|
||||
@import "_CPTitleableWindowView.j"
|
||||
|
||||
@class _CPDocModalWindowView
|
||||
|
||||
var _CPStandardWindowViewDividerViewHeight = 1.0;
|
||||
|
||||
@implementation _CPTexturedWindowHeadView : CPView
|
||||
{
|
||||
BOOL _isSheet @accessors(setter=setSheet:);
|
||||
|
||||
_CPWindowView _parentView;
|
||||
CPView _gradientView;
|
||||
CPView _solidView;
|
||||
CPView _dividerView;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -41,8 +43,7 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[]
|
||||
forKeys:[]];
|
||||
return @{};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame windowView:(_CPWindowView)parentView
|
||||
@@ -67,10 +68,11 @@
|
||||
[super layoutSubviews];
|
||||
|
||||
var gradientHeight = [[CPTheme defaultTheme] valueForAttributeWithName:@"gradient-height" forClass:_CPStandardWindowView],
|
||||
bounds = [self bounds];
|
||||
bounds = [self bounds],
|
||||
bezelHeadColor = [[CPTheme defaultTheme] valueForAttributeWithName:_isSheet ? @"bezel-head-sheet-color" : @"bezel-head-color" inState:[_parentView themeState] forClass:_CPStandardWindowView];
|
||||
|
||||
[_gradientView setFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), gradientHeight)];
|
||||
[_gradientView setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"bezel-head-color" inState:[_parentView themeState] forClass:_CPStandardWindowView]];
|
||||
[_gradientView setBackgroundColor:bezelHeadColor];
|
||||
|
||||
[_solidView setFrame:CGRectMake(0.0, gradientHeight, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - gradientHeight)];
|
||||
[_solidView setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"solid-color" forClass:_CPStandardWindowView]];
|
||||
@@ -98,6 +100,7 @@
|
||||
CPButton _minimizeButton;
|
||||
|
||||
BOOL _isDocumentEdited;
|
||||
BOOL _isSheet;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -107,19 +110,40 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], [CPColor blackColor], [CPColor whiteColor], 32, [CPNull null], [CPNull null],[CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
||||
forKeys:[ @"gradient-height",
|
||||
@"solid-color",
|
||||
@"bezel-head-color",
|
||||
@"divider-color",
|
||||
@"body-color",
|
||||
@"title-bar-height",
|
||||
@"minimize-image-highlighted-button",
|
||||
@"minimize-image-button",
|
||||
@"close-image-button",
|
||||
@"close-image-highlighted-button",
|
||||
@"unsaved-image-button",
|
||||
@"unsaved-image-highlighted-button"]];
|
||||
return @{
|
||||
@"gradient-height": [CPNull null],
|
||||
@"solid-color": [CPNull null],
|
||||
@"bezel-head-color": [CPNull null],
|
||||
@"bezel-head-sheet-color": [CPNull null],
|
||||
@"divider-color": [CPColor blackColor],
|
||||
@"body-color": [CPColor whiteColor],
|
||||
@"title-bar-height": 32,
|
||||
@"minimize-image-highlighted-button": [CPNull null],
|
||||
@"minimize-image-button": [CPNull null],
|
||||
@"close-image-button": [CPNull null],
|
||||
@"close-image-highlighted-button": [CPNull null],
|
||||
@"unsaved-image-button": [CPNull null],
|
||||
@"unsaved-image-highlighted-button": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
+ (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;
|
||||
|
||||
// Adjust for the divider
|
||||
contentRect.origin.y += _CPStandardWindowViewDividerViewHeight;
|
||||
contentRect.size.height -= _CPStandardWindowViewDividerViewHeight;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
@@ -138,14 +162,14 @@
|
||||
|
||||
[self addSubview:_headView positioned:CPWindowBelow relativeTo:_titleField];
|
||||
|
||||
_dividerView = [[CPView alloc] initWithFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), 1.0)];
|
||||
_dividerView = [[CPView alloc] initWithFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), _CPStandardWindowViewDividerViewHeight)];
|
||||
|
||||
[_dividerView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_dividerView setHitTests:NO];
|
||||
|
||||
[self addSubview:_dividerView];
|
||||
|
||||
var y = CGRectGetMaxY([_dividerView frame]);
|
||||
var y = CGRectGetMinY([_dividerView frame]);
|
||||
|
||||
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, y, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - y)];
|
||||
|
||||
@@ -202,22 +226,26 @@
|
||||
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
width = CGRectGetWidth(bounds),
|
||||
headHeight = [self toolbarMaxY];
|
||||
|
||||
[_headView setFrameSize:_CGSizeMake(width, headHeight)];
|
||||
[_dividerView setFrame:_CGRectMake(0.0, headHeight, width, 1.0)];
|
||||
|
||||
var dividerMaxY = 0,
|
||||
dividerMinY = 0;
|
||||
|
||||
if (![_dividerView isHidden])
|
||||
if (_isSheet && _toolbarView && [self showsToolbar])
|
||||
{
|
||||
dividerMinY = _CGRectGetMinY([_dividerView frame]);
|
||||
dividerMaxY = _CGRectGetMaxY([_dividerView frame]);
|
||||
headHeight = [_toolbarView frameSize].height;
|
||||
[_toolbarView setFrameOrigin:CGPointMake(0.0, 0.0)];
|
||||
}
|
||||
|
||||
[_bodyView setFrame:_CGRectMake(0.0, dividerMaxY, width, _CGRectGetHeight(bounds) - dividerMaxY)];
|
||||
[_headView setFrameSize:CGSizeMake(width, headHeight)];
|
||||
|
||||
[_dividerView setFrame:CGRectMake(0.0, headHeight, width, _CPStandardWindowViewDividerViewHeight)];
|
||||
|
||||
var dividerMinY = 0,
|
||||
dividerFrame = [_dividerView frame];
|
||||
|
||||
if (![_dividerView isHidden])
|
||||
dividerMinY = CGRectGetMinY(dividerFrame);
|
||||
|
||||
[_bodyView setFrame:CGRectMake(0.0, dividerMinY, width, CGRectGetHeight(bounds) - dividerMinY)];
|
||||
|
||||
var leftOffset = 8;
|
||||
|
||||
@@ -226,11 +254,10 @@
|
||||
if (_minimizeButton)
|
||||
leftOffset += 19.0;
|
||||
|
||||
[_titleField setFrame:_CGRectMake(leftOffset, 0, width - leftOffset * 2.0, [self valueForThemeAttribute:@"title-bar-height"])];
|
||||
[_titleField setFrame:CGRectMake(leftOffset, 0, width - leftOffset * 2.0, [self valueForThemeAttribute:@"title-bar-height"])];
|
||||
|
||||
var contentRect = _CGRectMake(0.0, dividerMaxY, width, _CGRectGetHeight([_bodyView frame]));
|
||||
|
||||
[[theWindow contentView] setFrame:contentRect];
|
||||
var contentFrame = [_bodyView frame];
|
||||
[[theWindow contentView] setFrame:CGRectInset(contentFrame, 1.0, 1.0)];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -293,38 +320,64 @@
|
||||
return [super couldBeMoveEvent:anEvent];
|
||||
}
|
||||
|
||||
- (void)_enableSheet:(BOOL)enable
|
||||
- (void)_enableSheet:(BOOL)enable inWindow:(CPWindow)parentWindow
|
||||
{
|
||||
[super _enableSheet:enable];
|
||||
[super _enableSheet:enable inWindow:parentWindow];
|
||||
|
||||
_isSheet = enable;
|
||||
[_headView setSheet:enable];
|
||||
|
||||
if (_toolbarView && [self showsToolbar])
|
||||
{
|
||||
[_headView setHidden:NO];
|
||||
[_dividerView setHidden:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_headView setHidden:enable];
|
||||
[_dividerView setHidden:enable];
|
||||
}
|
||||
|
||||
[_headView setHidden:enable];
|
||||
[_dividerView setHidden:enable];
|
||||
[_closeButton setHidden:enable];
|
||||
[_minimizeButton setHidden:enable];
|
||||
[_titleField setHidden:enable];
|
||||
|
||||
[[self window] setMovable:!enable];
|
||||
|
||||
if (enable)
|
||||
{
|
||||
[_bodyView setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"body-color" forClass:_CPDocModalWindowView]];
|
||||
|
||||
// Move the shadow view down so it is inside the content border
|
||||
var shadowFrame = [_sheetShadowView frame];
|
||||
[_sheetShadowView setFrameOrigin:CGPointMake(shadowFrame.origin.x, shadowFrame.origin.y + 1)];
|
||||
}
|
||||
else
|
||||
[_bodyView setBackgroundColor:[self valueForThemeAttribute:@"body-color"]];
|
||||
|
||||
// resize the window
|
||||
var theWindow = [self window],
|
||||
frame = [theWindow frame];
|
||||
frame = [theWindow frame],
|
||||
dividerHeight = [_dividerView frame].size.height,
|
||||
dy = [self toolbarMaxY] + dividerHeight;
|
||||
|
||||
if (_toolbarView && [self showsToolbar])
|
||||
dy = [[CPTheme defaultTheme] valueForAttributeWithName:@"gradient-height" forClass:_CPStandardWindowView];
|
||||
|
||||
var dy = _CGRectGetHeight([_headView frame]) + _CGRectGetHeight([_dividerView frame]);
|
||||
if (enable)
|
||||
dy = -dy;
|
||||
|
||||
var newHeight = _CGRectGetMaxY(frame) + dy,
|
||||
newWidth = _CGRectGetMaxX(frame);
|
||||
var newHeight = CGRectGetHeight(frame) + dy,
|
||||
newWidth = CGRectGetWidth(frame);
|
||||
|
||||
frame.size.height += dy;
|
||||
|
||||
[self setFrameSize:_CGSizeMake(newWidth, newHeight)];
|
||||
[self setFrameSize:CGSizeMake(newWidth, newHeight)];
|
||||
|
||||
[self tile];
|
||||
[theWindow setFrame:frame display:NO animate:NO];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -336,25 +389,29 @@
|
||||
|
||||
[_minimizeButton setImage:[self valueForThemeAttribute:@"minimize-image-button"]];
|
||||
[_minimizeButton setAlternateImage:[self valueForThemeAttribute:@"minimize-image-highlighted-button"]];
|
||||
|
||||
if (![_headView isHidden])
|
||||
[_headView setFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), [self toolbarMaxY])];
|
||||
else
|
||||
[_headView setFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0)];
|
||||
|
||||
if (![_dividerView isHidden])
|
||||
[_dividerView setFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), 1.0)];
|
||||
else
|
||||
[_dividerView setFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), 0.0)];
|
||||
|
||||
[_dividerView setBackgroundColor:[self valueForThemeAttribute:@"divider-color"]];
|
||||
|
||||
var y = CGRectGetMaxY([_dividerView frame]);
|
||||
|
||||
[_bodyView setFrame:CGRectMake(0.0, y, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - y)];
|
||||
[_bodyView setBackgroundColor:[self valueForThemeAttribute:@"body-color"]];
|
||||
|
||||
[_headView setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CGSize)_minimumResizeSize
|
||||
{
|
||||
// The minimum width is such that the close button would always be visible.
|
||||
// We give the same margin to the right of the button as there is to the left.
|
||||
var size = [super _minimumResizeSize],
|
||||
closeSize = [self valueForThemeAttribute:@"close-image-size"],
|
||||
closeOrigin = [self valueForThemeAttribute:@"close-image-origin"];
|
||||
|
||||
size.width = closeSize.width + (closeOrigin.x * 2);
|
||||
size.height += _CPStandardWindowViewDividerViewHeight;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
- (int)bodyOffset
|
||||
{
|
||||
return [_bodyView frame].origin.y;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,14 +20,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPTextField.j"
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
@class CPTextField
|
||||
|
||||
|
||||
@implementation _CPTitleableWindowView : _CPWindowView
|
||||
{
|
||||
CPTextField _titleField;
|
||||
CPTextField _titleField;
|
||||
}
|
||||
|
||||
+ (int)titleBarHeight
|
||||
@@ -37,8 +36,8 @@
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect),
|
||||
titleBarHeight = [[self class] titleBarHeight];
|
||||
var contentRect = [super contentRectForFrameRect:aFrameRect],
|
||||
titleBarHeight = [self titleBarHeight];
|
||||
|
||||
contentRect.origin.y += titleBarHeight;
|
||||
contentRect.size.height -= titleBarHeight;
|
||||
@@ -49,7 +48,7 @@
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect),
|
||||
titleBarHeight = [[self class] titleBarHeight];
|
||||
titleBarHeight = [self titleBarHeight];
|
||||
|
||||
frameRect.origin.y -= titleBarHeight;
|
||||
frameRect.size.height += titleBarHeight;
|
||||
@@ -96,7 +95,7 @@
|
||||
|
||||
// The vertical alignment of the title is set by the theme, so just give it all available space. By default
|
||||
// the title will vertically centre within.
|
||||
[_titleField setFrame:_CGRectMake(20.0, 0, width - 40.0, [[self class] titleBarHeight])];
|
||||
[_titleField setFrame:CGRectMake(20.0, 0, width - 40.0, [[self class] titleBarHeight])];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -114,4 +113,17 @@
|
||||
[_titleField setTextShadowOffset:[self currentValueForThemeAttribute:@"title-text-shadow-offset"]];
|
||||
}
|
||||
|
||||
- (CGSize)_minimumResizeSize
|
||||
{
|
||||
var size = [super _minimumResizeSize];
|
||||
|
||||
size.height += [[self class] titleBarHeight];
|
||||
return size;
|
||||
}
|
||||
|
||||
- (int)bodyOffset
|
||||
{
|
||||
return [self contentRectForFrameRect:[self frame]].origin.y;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
@import "_CPToolTip.j"
|
||||
|
||||
|
||||
@implementation _CPToolTipWindowView : _CPWindowView
|
||||
{
|
||||
@@ -40,16 +40,13 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPColor colorWithHexString:@"E3E3E3"],
|
||||
[CPColor colorWithHexString:@"FFFFCA"],
|
||||
2.0,
|
||||
1.0,
|
||||
[CPColor blackColor]]
|
||||
forKeys:[@"stroke-color",
|
||||
@"background-color",
|
||||
@"border-radius",
|
||||
@"stroke-width",
|
||||
@"color"]];
|
||||
return @{
|
||||
@"stroke-color": [CPColor colorWithHexString:@"E3E3E3"],
|
||||
@"background-color": [CPColor colorWithHexString:@"FFFFCA"],
|
||||
@"border-radius": 2.0,
|
||||
@"stroke-width": 1.0,
|
||||
@"color": [CPColor blackColor],
|
||||
};
|
||||
}
|
||||
|
||||
/*! compute the contentView frame from a given window frame
|
||||
@@ -57,7 +54,7 @@
|
||||
*/
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect);
|
||||
var contentRect = [super contentRectForFrameRect:aFrameRect];
|
||||
|
||||
contentRect.origin.x += 3;
|
||||
contentRect.origin.y += 3;
|
||||
@@ -99,18 +96,17 @@
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetFillColor(context, bgColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
|
||||
aRect.origin.x += strokeWidth;
|
||||
aRect.origin.y += strokeWidth;
|
||||
aRect.size.width -= strokeWidth * 2;
|
||||
aRect.size.height -= strokeWidth * 2;
|
||||
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
|
||||
CGContextClosePath(context);
|
||||
|
||||
//Draw it
|
||||
var path = CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES);
|
||||
CGContextAddPath(context, path);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextAddPath(context, path);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+270
-142
@@ -31,6 +31,7 @@
|
||||
@global CPApp
|
||||
|
||||
var _CPWindowViewCornerResizeRectWidth = 10,
|
||||
_CPWindowViewMinContentHeight = 2,
|
||||
|
||||
_CPWindowViewResizeRegionNone = -1,
|
||||
_CPWindowViewResizeRegionTopLeft = 0,
|
||||
@@ -56,7 +57,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
CGSize _toolbarOffset;
|
||||
// BOOL _isAnimatingToolbar;
|
||||
|
||||
CGRect _resizeFrame;
|
||||
CGRect _cachedFrame;
|
||||
int _resizeRegion;
|
||||
CGPoint _mouseDraggedPoint;
|
||||
|
||||
@@ -67,12 +68,12 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
return _CGRectMakeCopy(aFrameRect);
|
||||
return CGRectMakeCopy(aFrameRect);
|
||||
}
|
||||
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
return _CGRectMakeCopy(aContentRect);
|
||||
return CGRectMakeCopy(aContentRect);
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -82,26 +83,28 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[25, CGInsetMakeZero(), 5, [CPColor clearColor], CGSizeMakeZero(), [CPNull null], [CPColor blackColor], [CPNull null],[CPNull null], [CPNull null], [CPNull null], [CPNull null] , [CPColor blackColor], [CPFont systemFontOfSize:CPFontCurrentSystemSize], [CPNull null], _CGSizeMakeZero(), CPCenterTextAlignment, CPLineBreakByTruncatingTail, CPTopVerticalTextAlignment]
|
||||
forKeys:[ @"title-bar-height",
|
||||
@"shadow-inset",
|
||||
@"shadow-distance",
|
||||
@"window-shadow-color",
|
||||
@"size-indicator",
|
||||
@"resize-indicator",
|
||||
@"attached-sheet-shadow-color",
|
||||
@"close-image-origin",
|
||||
@"close-image-size",
|
||||
@"close-image",
|
||||
@"close-active-image",
|
||||
@"bezel-color",
|
||||
@"title-text-color",
|
||||
@"title-font",
|
||||
@"title-text-shadow-color",
|
||||
@"title-text-shadow-offset",
|
||||
@"title-alignment",
|
||||
@"title-line-break-mode",
|
||||
@"title-vertical-alignment"]];
|
||||
return @{
|
||||
@"title-bar-height": 25,
|
||||
@"shadow-inset": CGInsetMakeZero(),
|
||||
@"shadow-distance": 5,
|
||||
@"window-shadow-color": [CPColor clearColor],
|
||||
@"size-indicator": CGSizeMakeZero(),
|
||||
@"resize-indicator": [CPNull null],
|
||||
@"attached-sheet-shadow-color": [CPColor blackColor],
|
||||
@"shadow-height": 8,
|
||||
@"close-image-origin": [CPNull null],
|
||||
@"close-image-size": [CPNull null],
|
||||
@"close-image": [CPNull null],
|
||||
@"close-active-image": [CPNull null],
|
||||
@"bezel-color": [CPNull null],
|
||||
@"title-text-color": [CPColor blackColor],
|
||||
@"title-font": [CPFont systemFontOfSize:CPFontCurrentSystemSize],
|
||||
@"title-text-shadow-color": [CPNull null],
|
||||
@"title-text-shadow-offset": CGSizeMakeZero(),
|
||||
@"title-alignment": CPCenterTextAlignment,
|
||||
@"title-line-break-mode": CPLineBreakByTruncatingTail,
|
||||
@"title-vertical-alignment": CPTopVerticalTextAlignment,
|
||||
};
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
@@ -111,7 +114,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
if ([theToolbar isVisible])
|
||||
{
|
||||
var toolbarHeight = _CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
@@ -127,7 +130,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
if ([theToolbar isVisible])
|
||||
{
|
||||
var toolbarHeight = _CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
|
||||
frameRect.origin.y -= toolbarHeight;
|
||||
frameRect.size.height += toolbarHeight;
|
||||
@@ -143,8 +146,8 @@ _CPWindowViewResizeSlop = 3;
|
||||
if (self)
|
||||
{
|
||||
_styleMask = aStyleMask;
|
||||
_resizeIndicatorOffset = _CGSizeMakeZero();
|
||||
_toolbarOffset = _CGSizeMakeZero();
|
||||
_resizeIndicatorOffset = CGSizeMakeZero();
|
||||
_toolbarOffset = CGSizeMakeZero();
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -176,7 +179,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var theWindow = [self window],
|
||||
couldResize = _styleMask & CPResizableWindowMask;
|
||||
couldResize = _styleMask & CPResizableWindowMask && ![theWindow isFullPlatformWindow];
|
||||
|
||||
couldResize = couldResize && (
|
||||
(CPWindowResizeStyle === CPWindowResizeStyleModern) ||
|
||||
@@ -199,8 +202,8 @@ _CPWindowViewResizeSlop = 3;
|
||||
{
|
||||
// Extend the resize frame to the edge of the window frame
|
||||
var resizeFrame = [_resizeIndicator frame];
|
||||
resizeFrame.size.width = _CGRectGetWidth(windowFrame) - _CGRectGetMinX(resizeFrame);
|
||||
resizeFrame.size.height = _CGRectGetHeight(windowFrame) - _CGRectGetMinY(resizeFrame);
|
||||
resizeFrame.size.width = CGRectGetWidth(windowFrame) - CGRectGetMinX(resizeFrame);
|
||||
resizeFrame.size.height = CGRectGetHeight(windowFrame) - CGRectGetMinY(resizeFrame);
|
||||
|
||||
var localPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
shouldResize = CGRectContainsPoint(resizeFrame, localPoint);
|
||||
@@ -243,6 +246,8 @@ _CPWindowViewResizeSlop = 3;
|
||||
rects are the same size. So to save calculations, we can just create
|
||||
3 rects and move them around to do hit testing. Start with the corners
|
||||
and then do left/right and top/bottom.
|
||||
|
||||
NOTE: If the window is a sheet, the top is never eligible for resizing.
|
||||
*/
|
||||
var wind = [self window],
|
||||
frame = [wind frame],
|
||||
@@ -250,87 +255,88 @@ _CPWindowViewResizeSlop = 3;
|
||||
minSize = [wind minSize],
|
||||
maxSize = [wind maxSize],
|
||||
isFixedWidth = minSize.width === maxSize.width,
|
||||
isFixedHeight = minSize.height === maxSize.height;
|
||||
isFixedHeight = minSize.height === maxSize.height,
|
||||
isSheet = wind._isSheet;
|
||||
|
||||
if (isFixedWidth)
|
||||
{
|
||||
rect = _CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
frame.origin.y - _CPWindowViewResizeSlop,
|
||||
frame.size.width + (_CPWindowViewResizeSlop * 2),
|
||||
_CPWindowViewResizeSlop * 2);
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionTop;
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTop;
|
||||
|
||||
rect.origin.y = _CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
|
||||
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionBottom;
|
||||
}
|
||||
else if (isFixedHeight)
|
||||
{
|
||||
rect = _CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
frame.origin.y - _CPWindowViewResizeSlop,
|
||||
_CPWindowViewResizeSlop * 2,
|
||||
frame.size.height + (_CPWindowViewResizeSlop * 2));
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionLeft;
|
||||
|
||||
rect.origin.x = _CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
|
||||
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect = _CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
|
||||
frame.origin.y - _CPWindowViewResizeSlop,
|
||||
_CPWindowViewCornerResizeRectWidth + _CPWindowViewResizeSlop,
|
||||
_CPWindowViewCornerResizeRectWidth + _CPWindowViewResizeSlop);
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionTopLeft;
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTopLeft;
|
||||
|
||||
rect.origin.x = _CGRectGetMaxX(frame) - _CPWindowViewCornerResizeRectWidth;
|
||||
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewCornerResizeRectWidth;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionTopRight;
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTopRight;
|
||||
|
||||
rect.origin.y = _CGRectGetMaxY(frame) - _CPWindowViewCornerResizeRectWidth;
|
||||
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewCornerResizeRectWidth;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionBottomRight;
|
||||
|
||||
rect.origin.x = frame.origin.x - _CPWindowViewResizeSlop;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionBottomLeft;
|
||||
|
||||
rect = _CGRectMake(rect.origin.x,
|
||||
rect = CGRectMake(rect.origin.x,
|
||||
frame.origin.y + _CPWindowViewCornerResizeRectWidth,
|
||||
_CPWindowViewResizeSlop * 2,
|
||||
_CGRectGetHeight(frame) - (_CPWindowViewCornerResizeRectWidth * 2));
|
||||
CGRectGetHeight(frame) - (_CPWindowViewCornerResizeRectWidth * 2));
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionLeft;
|
||||
|
||||
rect.origin.x = _CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
|
||||
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionRight;
|
||||
|
||||
rect = _CGRectMake(frame.origin.x + _CPWindowViewCornerResizeRectWidth,
|
||||
rect = CGRectMake(frame.origin.x + _CPWindowViewCornerResizeRectWidth,
|
||||
frame.origin.y - _CPWindowViewResizeSlop,
|
||||
_CGRectGetWidth(frame) - (_CPWindowViewCornerResizeRectWidth * 2),
|
||||
CGRectGetWidth(frame) - (_CPWindowViewCornerResizeRectWidth * 2),
|
||||
_CPWindowViewResizeSlop * 2);
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionTop;
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTop;
|
||||
|
||||
rect.origin.y = _CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
|
||||
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
|
||||
|
||||
if (_CGRectContainsPoint(rect, aPoint))
|
||||
if (CGRectContainsPoint(rect, aPoint))
|
||||
return _CPWindowViewResizeRegionBottom;
|
||||
}
|
||||
|
||||
@@ -365,9 +371,9 @@ _CPWindowViewResizeSlop = 3;
|
||||
switch (resizeRegion)
|
||||
{
|
||||
case _CPWindowViewResizeRegionTopLeft:
|
||||
if (minSize && _CGSizeEqualToSize(frameSize, minSize))
|
||||
if (minSize && CGSizeEqualToSize(frameSize, minSize))
|
||||
[[CPCursor resizeNorthwestCursor] set];
|
||||
else if (maxSize && _CGSizeEqualToSize(frameSize, maxSize))
|
||||
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
|
||||
[[CPCursor resizeSoutheastCursor] set];
|
||||
else
|
||||
[[CPCursor resizeNorthwestSoutheastCursor] set];
|
||||
@@ -378,16 +384,16 @@ _CPWindowViewResizeSlop = 3;
|
||||
[[CPCursor resizeUpCursor] set];
|
||||
else if (maxSize && (frameSize.height === maxSize.height))
|
||||
[[CPCursor resizeDownCursor] set];
|
||||
else if ([CPMenu menuBarVisible] && (_CGRectGetMinY([theWindow frame]) <= [CPMenu menuBarHeight]))
|
||||
else if ([CPMenu menuBarVisible] && (CGRectGetMinY([theWindow frame]) <= [CPMenu menuBarHeight]))
|
||||
[[CPCursor resizeDownCursor] set];
|
||||
else
|
||||
[[CPCursor resizeNorthSouthCursor] set];
|
||||
break;
|
||||
|
||||
case _CPWindowViewResizeRegionTopRight:
|
||||
if (minSize && _CGSizeEqualToSize(frameSize, minSize))
|
||||
if (minSize && CGSizeEqualToSize(frameSize, minSize))
|
||||
[[CPCursor resizeNortheastCursor] set];
|
||||
else if (maxSize && _CGSizeEqualToSize(frameSize, maxSize))
|
||||
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
|
||||
[[CPCursor resizeSouthwestCursor] set];
|
||||
else
|
||||
[[CPCursor resizeNortheastSouthwestCursor] set];
|
||||
@@ -403,9 +409,9 @@ _CPWindowViewResizeSlop = 3;
|
||||
break;
|
||||
|
||||
case _CPWindowViewResizeRegionBottomRight:
|
||||
if (minSize && _CGSizeEqualToSize(frameSize, minSize))
|
||||
if (minSize && CGSizeEqualToSize(frameSize, minSize))
|
||||
[[CPCursor resizeSoutheastCursor] set];
|
||||
else if (maxSize && _CGSizeEqualToSize(frameSize, maxSize))
|
||||
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
|
||||
[[CPCursor resizeNorthwestCursor] set];
|
||||
else
|
||||
[[CPCursor resizeNorthwestSoutheastCursor] set];
|
||||
@@ -421,9 +427,9 @@ _CPWindowViewResizeSlop = 3;
|
||||
break;
|
||||
|
||||
case _CPWindowViewResizeRegionBottomLeft:
|
||||
if (minSize && _CGSizeEqualToSize(frameSize, minSize))
|
||||
if (minSize && CGSizeEqualToSize(frameSize, minSize))
|
||||
[[CPCursor resizeSouthwestCursor] set];
|
||||
else if (maxSize && _CGSizeEqualToSize(frameSize, maxSize))
|
||||
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
|
||||
[[CPCursor resizeNortheastCursor] set];
|
||||
else
|
||||
[[CPCursor resizeNortheastSouthwestCursor] set];
|
||||
@@ -448,7 +454,10 @@ _CPWindowViewResizeSlop = 3;
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_cachedScreenFrame = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
var location = [anEvent locationInWindow],
|
||||
theWindow = [self window],
|
||||
@@ -457,42 +466,107 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_mouseDraggedPoint = _CGPointMakeCopy(globalLocation);
|
||||
_resizeFrame = _CGRectMakeCopy(frame);
|
||||
_mouseDraggedPoint = CGPointMake(globalLocation.x, globalLocation.y);
|
||||
_cachedFrame = CGRectMakeCopy(frame);
|
||||
_cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||
}
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var deltaX = globalLocation.x - _mouseDraggedPoint.x,
|
||||
deltaY = globalLocation.y - _mouseDraggedPoint.y,
|
||||
newX = _CGRectGetMinX(_resizeFrame),
|
||||
newY = _CGRectGetMinY(_resizeFrame),
|
||||
newWidth = _CGRectGetWidth(_resizeFrame),
|
||||
newHeight = _CGRectGetHeight(_resizeFrame),
|
||||
platformFrame = [[theWindow platformWindow] usableContentFrame],
|
||||
startX = CGRectGetMinX(_cachedFrame),
|
||||
startY = CGRectGetMinY(_cachedFrame),
|
||||
startWidth = CGRectGetWidth(_cachedFrame),
|
||||
startHeight = CGRectGetHeight(_cachedFrame),
|
||||
newX,
|
||||
newY,
|
||||
newWidth,
|
||||
newHeight,
|
||||
resizeMinSize = [self _minimumResizeSize],
|
||||
minSize = [theWindow minSize],
|
||||
maxSize = [theWindow maxSize];
|
||||
|
||||
minSize = CGSizeMake(MAX(minSize.width, resizeMinSize.width), MAX(minSize.height, resizeMinSize.height));
|
||||
|
||||
// If it's a sheet, horizontal resizing is symmetrical, so the movement is effectively doubled
|
||||
if (theWindow._isSheet)
|
||||
deltaX *= 2;
|
||||
|
||||
// Calculate x and width first
|
||||
switch (_resizeRegion)
|
||||
{
|
||||
case _CPWindowViewResizeRegionTopLeft:
|
||||
case _CPWindowViewResizeRegionLeft:
|
||||
case _CPWindowViewResizeRegionBottomLeft:
|
||||
if (minSize && deltaX > 0)
|
||||
deltaX = MIN(newWidth - minSize.width, deltaX);
|
||||
else if (maxSize && deltaX < 0)
|
||||
deltaX = MAX(newWidth - maxSize.width, deltaX);
|
||||
// If it is shrinking from the left edge, the maximum distance it can move
|
||||
// is the distance between the original width and the min width.
|
||||
if (deltaX > 0)
|
||||
deltaX = MIN(startWidth - minSize.width, deltaX);
|
||||
|
||||
newX += deltaX,
|
||||
newWidth -= deltaX;
|
||||
// If it is growing from the left edge, the maximum distance it can move
|
||||
// is the distance between the original width and the max width.
|
||||
else if (deltaX < 0)
|
||||
deltaX = -MIN(maxSize.width - startWidth, ABS(deltaX));
|
||||
|
||||
if (theWindow._isSheet)
|
||||
deltaX = FLOOR(deltaX / 2);
|
||||
|
||||
newX = startX + deltaX;
|
||||
|
||||
// Pin the left edge to the usable screen left edge
|
||||
var pinnedX = MAX(newX, CGRectGetMinX(_cachedScreenFrame));
|
||||
|
||||
if (pinnedX !== newX)
|
||||
{
|
||||
deltaX += pinnedX - newX;
|
||||
newX = pinnedX;
|
||||
}
|
||||
|
||||
// When resizing from the left, we change the origin and the width
|
||||
if (theWindow._isSheet)
|
||||
deltaX *= 2;
|
||||
|
||||
newWidth = startWidth - deltaX;
|
||||
break;
|
||||
|
||||
case _CPWindowViewResizeRegionTopRight:
|
||||
case _CPWindowViewResizeRegionRight:
|
||||
case _CPWindowViewResizeRegionBottomRight:
|
||||
newWidth += deltaX;
|
||||
// If it is growing from the right edge, the maximum distance it can move
|
||||
// is the distance between the original width and the max width.
|
||||
if (deltaX > 0)
|
||||
deltaX = MIN(maxSize.width - startWidth, deltaX);
|
||||
|
||||
// If it is shrinking from the right edge, the maximum distance it can move
|
||||
// is the distance between the original width and the min width.
|
||||
else if (deltaX < 0)
|
||||
deltaX = -MIN(startWidth - minSize.width, ABS(deltaX));
|
||||
|
||||
if (theWindow._isSheet)
|
||||
deltaX = FLOOR(deltaX / 2);
|
||||
|
||||
// Pin the right edge to the usable screen right edge
|
||||
var newMaxX = startX + startWidth + deltaX,
|
||||
pinnedX = MIN(newMaxX, CGRectGetMaxX(_cachedScreenFrame));
|
||||
|
||||
if (pinnedX !== newMaxX)
|
||||
deltaX += pinnedX - newMaxX;
|
||||
|
||||
if (theWindow._isSheet)
|
||||
{
|
||||
newWidth = startWidth + (deltaX * 2);
|
||||
newX = startX - FLOOR((newWidth - startWidth) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
newWidth = startWidth + deltaX;
|
||||
newX = startX;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
newX = startX;
|
||||
newWidth = startWidth;
|
||||
}
|
||||
|
||||
// Now calculate y and height
|
||||
@@ -501,88 +575,96 @@ _CPWindowViewResizeSlop = 3;
|
||||
case _CPWindowViewResizeRegionTopLeft:
|
||||
case _CPWindowViewResizeRegionTop:
|
||||
case _CPWindowViewResizeRegionTopRight:
|
||||
if (minSize && deltaY > 0)
|
||||
deltaY = MIN(newHeight - minSize.height, deltaY);
|
||||
else if (maxSize && deltaY < 0)
|
||||
deltaY = MAX(newHeight - maxSize.height, deltaY);
|
||||
// If it is shrinking from the top edge, the maximum distance it can move
|
||||
// is the distance between the original height and the min height.
|
||||
if (deltaY > 0)
|
||||
deltaY = MIN(startHeight - minSize.height, deltaY);
|
||||
|
||||
newY += deltaY,
|
||||
newHeight -= deltaY;
|
||||
// If it is growing from the top edge, the maximum distance it can move
|
||||
// is the distance between the original height and the max height.
|
||||
else if (deltaY < 0)
|
||||
deltaY = -MIN(maxSize.height - startHeight, ABS(deltaY));
|
||||
|
||||
newY = startY + deltaY;
|
||||
|
||||
// Pin the top edge to the usable screen top edge
|
||||
var pinnedY = MAX(newY, CGRectGetMinY(_cachedScreenFrame));
|
||||
|
||||
if (pinnedY !== newY)
|
||||
{
|
||||
deltaY += pinnedY - newY;
|
||||
newY = pinnedY;
|
||||
}
|
||||
|
||||
// When resizing from the top, change the origin and the height
|
||||
newHeight = startHeight - deltaY;
|
||||
break;
|
||||
|
||||
case _CPWindowViewResizeRegionBottomLeft:
|
||||
case _CPWindowViewResizeRegionBottom:
|
||||
case _CPWindowViewResizeRegionBottomRight:
|
||||
newHeight += deltaY;
|
||||
// If it is growing from the bottom edge, the maximum distance it can move
|
||||
// is the distance between the original height and the max height.
|
||||
if (deltaY > 0)
|
||||
deltaY = MIN(maxSize.height - startHeight, deltaY);
|
||||
|
||||
// If it is shrinking from the bottom edge, the maximum distance it can move
|
||||
// is the distance between the original height and the min height.
|
||||
else if (deltaY < 0)
|
||||
deltaY = -MIN(startHeight - minSize.height, ABS(deltaY));
|
||||
|
||||
newY = startY;
|
||||
|
||||
// Pin the bottom edge to the usable screen bottom edge
|
||||
var newMaxY = startY + startHeight + deltaY,
|
||||
pinnedY = MIN(newMaxY, CGRectGetMaxY(_cachedScreenFrame));
|
||||
|
||||
if (pinnedY !== newMaxY)
|
||||
deltaY += pinnedY - newMaxY;
|
||||
|
||||
// When resizing from the bottom, change only the height
|
||||
newHeight = startHeight + deltaY;
|
||||
break;
|
||||
|
||||
default:
|
||||
newY = startY;
|
||||
newHeight = startHeight;
|
||||
}
|
||||
|
||||
if (theWindow._isSheet && theWindow._parentView && (frame.size.width !== newWidth))
|
||||
[theWindow._parentView _setAttachedSheetFrameOrigin];
|
||||
|
||||
// Constrain resize to fit within the platform window.
|
||||
var newFrame = CGRectIntersection(_CGRectMake(newX, newY, newWidth, newHeight), platformFrame);
|
||||
|
||||
[theWindow setFrame:newFrame];
|
||||
[theWindow _setFrame:CGRectMake(newX, newY, newWidth, newHeight) display:YES animate:NO constrainWidth:NO constrainHeight:NO];
|
||||
[self setCursorForLocation:location resizing:YES];
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (CGPoint)_pointWithinScreenFrame:(CGPoint)aPoint
|
||||
{
|
||||
// FIXME: this is WRONG, all of this is WRONG
|
||||
if (![CPPlatform isBrowser])
|
||||
return aPoint;
|
||||
|
||||
var visibleFrame = _cachedScreenFrame;
|
||||
|
||||
if (!visibleFrame)
|
||||
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||
|
||||
var minPointY = 0;
|
||||
|
||||
if ([CPMenu menuBarVisible])
|
||||
minPointY = [[CPApp mainMenu] menuBarHeight];
|
||||
|
||||
var restrictedPoint = _CGPointMake(0, 0);
|
||||
|
||||
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), _CGRectGetMaxX(visibleFrame) - 4.0);
|
||||
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), _CGRectGetMaxY(visibleFrame) - 8.0);
|
||||
|
||||
return restrictedPoint;
|
||||
}
|
||||
|
||||
- (void)trackMoveWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
if (![[self window] isMovable])
|
||||
var theWindow = [self window];
|
||||
|
||||
if (![theWindow isMovable])
|
||||
return;
|
||||
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_cachedScreenFrame = nil;
|
||||
return;
|
||||
}
|
||||
else if (type === CPLeftMouseDown)
|
||||
{
|
||||
_mouseDraggedPoint = [[self window] convertBaseToGlobal:[anEvent locationInWindow]];
|
||||
_cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||
_mouseDraggedPoint = [theWindow convertBaseToGlobal:[anEvent locationInWindow]];
|
||||
_cachedFrame = CGRectMakeCopy([theWindow frame]);
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var theWindow = [self window],
|
||||
frame = [theWindow frame],
|
||||
location = [theWindow convertBaseToGlobal:[anEvent locationInWindow]],
|
||||
deltaX = location.x - _mouseDraggedPoint.x,
|
||||
deltaY = location.y - _mouseDraggedPoint.y,
|
||||
origin = [self _pointWithinScreenFrame:_CGPointMake(frame.origin.x + deltaX,
|
||||
frame.origin.y + deltaY)];
|
||||
[theWindow setFrameOrigin:origin];
|
||||
origin = CGPointMake(_cachedFrame.origin.x + deltaX, _cachedFrame.origin.y + deltaY);
|
||||
|
||||
_mouseDraggedPoint = [self _pointWithinScreenFrame:location];
|
||||
[theWindow setFrameOrigin:origin];
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
@@ -593,10 +675,16 @@ _CPWindowViewResizeSlop = 3;
|
||||
[super setFrameSize:newSize];
|
||||
|
||||
// reposition sheet if the parent window resizes or moves
|
||||
var theWindow = [self window];
|
||||
var theWindow = [self window],
|
||||
sheet = [theWindow attachedSheet];
|
||||
|
||||
if ([theWindow attachedSheet])
|
||||
if (sheet)
|
||||
{
|
||||
[theWindow _setAttachedSheetFrameOrigin];
|
||||
[sheet._windowView _adjustShadowViewSize];
|
||||
}
|
||||
else if (theWindow._isSheet)
|
||||
[self _adjustShadowViewSize];
|
||||
}
|
||||
|
||||
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
|
||||
@@ -625,7 +713,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
- (void)setResizeIndicatorOffset:(CGSize)anOffset
|
||||
{
|
||||
if (_CGSizeEqualToSize(_resizeIndicatorOffset, anOffset))
|
||||
if (CGSizeEqualToSize(_resizeIndicatorOffset, anOffset))
|
||||
return;
|
||||
|
||||
_resizeIndicatorOffset = anOffset;
|
||||
@@ -636,7 +724,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
var size = [_resizeIndicator frame].size,
|
||||
boundsSize = [self frame].size;
|
||||
|
||||
[_resizeIndicator setFrameOrigin:_CGPointMake(boundsSize.width - size.width - anOffset.width, boundsSize.height - size.height - anOffset.height)];
|
||||
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - anOffset.width, boundsSize.height - size.height - anOffset.height)];
|
||||
}
|
||||
|
||||
- (CGSize)resizeIndicatorOffset
|
||||
@@ -654,7 +742,9 @@ _CPWindowViewResizeSlop = 3;
|
||||
|
||||
- (BOOL)showsToolbar
|
||||
{
|
||||
return YES;
|
||||
var styleMaskWindow = [[self window] styleMask];
|
||||
|
||||
return styleMaskWindow & CPBorderlessWindowMask || styleMaskWindow & CPTitledWindowMask || styleMaskWindow & CPHUDBackgroundWindowMask || styleMaskWindow & CPBorderlessBridgeWindowMask;
|
||||
}
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
@@ -672,7 +762,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
if (!_toolbarView || [_toolbarView isHidden])
|
||||
return [self toolbarOffset].height;
|
||||
|
||||
return _CGRectGetMaxY([_toolbarView frame]);
|
||||
return CGRectGetMaxY([_toolbarView frame]);
|
||||
}
|
||||
|
||||
- (_CPToolbarView)toolbarView
|
||||
@@ -684,14 +774,14 @@ _CPWindowViewResizeSlop = 3;
|
||||
{
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds);
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
if ([[theWindow toolbar] isVisible])
|
||||
{
|
||||
var toolbarView = [self toolbarView],
|
||||
toolbarOffset = [self toolbarOffset];
|
||||
|
||||
[toolbarView setFrame:_CGRectMake(toolbarOffset.width, toolbarOffset.height, width, _CGRectGetHeight([toolbarView frame]))];
|
||||
[toolbarView setFrame:CGRectMake(toolbarOffset.width, toolbarOffset.height, width, CGRectGetHeight([toolbarView frame]))];
|
||||
}
|
||||
|
||||
if ([self showsResizeIndicator])
|
||||
@@ -699,7 +789,7 @@ _CPWindowViewResizeSlop = 3;
|
||||
var size = [_resizeIndicator frame].size,
|
||||
boundsSize = [self bounds].size;
|
||||
|
||||
[_resizeIndicator setFrameOrigin:_CGPointMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height)];
|
||||
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,22 +866,36 @@ _CPWindowViewResizeSlop = 3;
|
||||
[self addSubview:_resizeIndicator];
|
||||
}
|
||||
|
||||
- (void)_enableSheet:(BOOL)enable
|
||||
- (void)_enableSheet:(BOOL)enable inWindow:(CPWindow)parentWindow
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
_sheetShadowView = [[CPView alloc] initWithFrame:_CGRectMake(0, 0, _CGRectGetWidth([self bounds]), 8)];
|
||||
// Clip the shadow view width to the parent's content view
|
||||
var myWidth = [self bounds].size.width,
|
||||
shadowWidth = [self _shadowViewWidthForParentWindow:parentWindow],
|
||||
shadowHeight = [self currentValueForThemeAttribute:@"shadow-height"];
|
||||
|
||||
_sheetShadowView = [[CPView alloc] initWithFrame:CGRectMake(FLOOR((myWidth - shadowWidth) / 2), 0, shadowWidth, shadowHeight)];
|
||||
[_sheetShadowView setAutoresizingMask:CPViewWidthSizable];
|
||||
[self addSubview:_sheetShadowView];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_sheetShadowView removeFromSuperview];
|
||||
_sheetShadowView = nil;
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CGRect)_shadowViewWidthForParentWindow:(CPWindow)parentWindow
|
||||
{
|
||||
var myWidth = [self bounds].size.width,
|
||||
parentWidth = [[parentWindow contentView] bounds].size.width;
|
||||
|
||||
return MIN(myWidth, parentWidth);
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
@@ -808,4 +912,28 @@ _CPWindowViewResizeSlop = 3;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_adjustShadowViewSize
|
||||
{
|
||||
if (!_sheetShadowView)
|
||||
return;
|
||||
|
||||
var myWidth = [self frame].size.width,
|
||||
shadowFrame = [_sheetShadowView frame],
|
||||
shadowWidth = [self _shadowViewWidthForParentWindow:_window._parentView];
|
||||
|
||||
shadowFrame.origin.x = FLOOR((myWidth - shadowWidth) / 2);
|
||||
shadowFrame.size.width = shadowWidth;
|
||||
[_sheetShadowView setFrame:shadowFrame];
|
||||
}
|
||||
|
||||
- (CGSize)_minimumResizeSize
|
||||
{
|
||||
return CGSizeMake(0, _CPWindowViewMinContentHeight);
|
||||
}
|
||||
|
||||
- (int)bodyOffset
|
||||
{
|
||||
return [self frame].origin.y;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user