mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-09 12:17:13 +00:00
Compare commits
2745
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 | ||
|
|
0821794bcc | ||
|
|
347e9cc811 | ||
|
|
1a26fbf6f4 | ||
|
|
fc0689fc3c | ||
|
|
5b28d5f457 | ||
|
|
da47161e1a | ||
|
|
450081ee3e | ||
|
|
e30d54723d | ||
|
|
c874efaa24 | ||
|
|
28473a86dc | ||
|
|
57b2d73632 | ||
|
|
e17253d592 | ||
|
|
eefec02de4 | ||
|
|
c73a96ef7e | ||
|
|
6e424478f1 | ||
|
|
e4ff2fe476 | ||
|
|
ad11967893 | ||
|
|
120d726b8e | ||
|
|
b7d1ccf9b6 | ||
|
|
fdbef474f0 | ||
|
|
b34e24d593 | ||
|
|
c29a54e21a | ||
|
|
25633f03c5 | ||
|
|
7e635fb4ea | ||
|
|
0b865da3be | ||
|
|
30ae887126 | ||
|
|
75d73d3a5e | ||
|
|
0f57683e22 | ||
|
|
6a7e0ff921 | ||
|
|
237143851d | ||
|
|
76e9725e26 | ||
|
|
1080ace4cd | ||
|
|
95790d55d5 | ||
|
|
2d34d458f4 | ||
|
|
331a0a87b1 | ||
|
|
628a4db746 | ||
|
|
b44a3c191d | ||
|
|
8f4fdeaa8f | ||
|
|
cd0f0e3f01 | ||
|
|
abb4077c95 | ||
|
|
cc45fb58a8 | ||
|
|
b23cadea59 | ||
|
|
f27159f63f | ||
|
|
53c4dce509 | ||
|
|
1aaab57edc | ||
|
|
1e004fefcc | ||
|
|
fb2d2c8e05 | ||
|
|
836d8d030c | ||
|
|
38b772c523 | ||
|
|
d8f1446e76 | ||
|
|
f30b3afabd | ||
|
|
1656c60dee | ||
|
|
0f0b315f3b | ||
|
|
f0bb8ce8a7 | ||
|
|
899f40d5f5 | ||
|
|
448d3958a2 | ||
|
|
f36b23bdb2 | ||
|
|
f613f68570 | ||
|
|
58d069ed7d | ||
|
|
3eca24ed58 | ||
|
|
8aacdc0502 | ||
|
|
1f5920f685 | ||
|
|
93fb849296 | ||
|
|
98cfe2922a | ||
|
|
e09627775a | ||
|
|
90df913def | ||
|
|
c1dc40c79b | ||
|
|
c5fbeffa9c | ||
|
|
1f98dbdf65 | ||
|
|
2fdf51d12c | ||
|
|
fab6466180 | ||
|
|
fa708272bc | ||
|
|
a9b68f7c39 | ||
|
|
6281c6469b | ||
|
|
65fd33b9cf | ||
|
|
401a5f7ff7 | ||
|
|
1f0ab2ab49 | ||
|
|
fcad7a7fe4 | ||
|
|
98daaf858f | ||
|
|
348d689243 | ||
|
|
4acd11d649 | ||
|
|
af47857a47 | ||
|
|
1280b6e13e | ||
|
|
a7587d631c | ||
|
|
866e1f00f7 | ||
|
|
4f377bcebe | ||
|
|
64a0fb278b | ||
|
|
f8c9466d04 | ||
|
|
ef62191e6b | ||
|
|
e25cee0855 | ||
|
|
94439f0d10 | ||
|
|
2385f48fe4 | ||
|
|
ed98acc906 | ||
|
|
201c7637f6 | ||
|
|
765b10611b | ||
|
|
28a135880d | ||
|
|
2952812a4b | ||
|
|
6c57c4b1e1 | ||
|
|
706337d8fa | ||
|
|
d13d9228e8 | ||
|
|
c4492fb1a1 | ||
|
|
6e6d4ebc76 | ||
|
|
3b3aa6b2fe | ||
|
|
11bad2e474 | ||
|
|
556f17969c | ||
|
|
a2f40be00e | ||
|
|
cc0503c8a4 | ||
|
|
5ec9cf7faf | ||
|
|
cc05df412e | ||
|
|
806c7935c5 | ||
|
|
e7f0400580 | ||
|
|
ad109532be | ||
|
|
9dbfa99284 | ||
|
|
3c684404ed | ||
|
|
d818615472 | ||
|
|
06694061d2 | ||
|
|
75c305ae0f | ||
|
|
cb786a0166 | ||
|
|
e292bf01d7 | ||
|
|
17f07ee888 | ||
|
|
51c09a1b02 | ||
|
|
fe7befa845 | ||
|
|
eca5ef6f84 | ||
|
|
c023a38544 | ||
|
|
7c831fa19d | ||
|
|
24c0f2aedc | ||
|
|
6170a274d7 | ||
|
|
155796b0e0 | ||
|
|
3b7262681c | ||
|
|
988ab9722c | ||
|
|
8eae427591 | ||
|
|
b4fe13dfb1 | ||
|
|
c0b5ed6b3f | ||
|
|
dfad18e047 | ||
|
|
7f93173b33 | ||
|
|
f435a15b43 | ||
|
|
08d5be5ce3 | ||
|
|
c3d8f4f80b | ||
|
|
bbb8bdb687 | ||
|
|
4138a6d6dc | ||
|
|
6b172cd3a6 | ||
|
|
86e0282011 | ||
|
|
f1250ae5eb | ||
|
|
586c9d3139 | ||
|
|
00fea3e02f | ||
|
|
6a72855de8 | ||
|
|
6b0edaecc6 | ||
|
|
a4bfd2c9f7 | ||
|
|
7a419c262e | ||
|
|
40ac3210c4 | ||
|
|
3bb9e234d8 | ||
|
|
75a4ef99c9 | ||
|
|
1e4b6b6c49 | ||
|
|
c9eeab09a1 | ||
|
|
1a61fc832e | ||
|
|
1d232fd263 | ||
|
|
197f3665bc | ||
|
|
ce62e32dfa | ||
|
|
2cc3521989 | ||
|
|
6fbab322cf | ||
|
|
458fa9d02e | ||
|
|
9f85d2bdb3 | ||
|
|
ff20822b47 | ||
|
|
eff0621966 | ||
|
|
6aeb6199f7 | ||
|
|
072fac837c | ||
|
|
f1fa185383 | ||
|
|
c471bc0f82 | ||
|
|
37e29949ef | ||
|
|
e840e4a547 | ||
|
|
82bb9a6008 | ||
|
|
15ed959da7 | ||
|
|
a0f4c46cb5 | ||
|
|
71d5655ab2 | ||
|
|
29d56b63f7 | ||
|
|
35f495ef5b | ||
|
|
1006890b6e | ||
|
|
083d7304fd | ||
|
|
2d8f651674 | ||
|
|
e8ee370499 | ||
|
|
5c3d71258d | ||
|
|
519031a10e | ||
|
|
821961fc26 | ||
|
|
4021eae002 | ||
|
|
0799ce190d | ||
|
|
a7c4802446 | ||
|
|
094c6fd273 | ||
|
|
72a601371e | ||
|
|
2a80ad8344 | ||
|
|
7e502fffe6 | ||
|
|
e5de031423 | ||
|
|
d064ecd842 | ||
|
|
c0d33a1a19 | ||
|
|
e78f211e8a | ||
|
|
77d66fa0c9 | ||
|
|
a652fdf8d2 | ||
|
|
85481225a3 | ||
|
|
6210bd2e6d | ||
|
|
7dd7dca99a | ||
|
|
48991e6c3b | ||
|
|
825d045143 | ||
|
|
86593cc0f4 | ||
|
|
d987bcf0d0 | ||
|
|
0e82504daf | ||
|
|
7fdc3abd30 | ||
|
|
c52a72ec90 | ||
|
|
e464900f8b | ||
|
|
b82f7061a0 | ||
|
|
55d651ad27 | ||
|
|
5239749580 | ||
|
|
fe5b6d40ac | ||
|
|
5fa42279bd | ||
|
|
b7a2ab57cc | ||
|
|
78949f3620 | ||
|
|
924bf07950 | ||
|
|
181f7acbb8 | ||
|
|
d331de6683 | ||
|
|
41dbc66d24 | ||
|
|
6230319f63 | ||
|
|
b7e768820f | ||
|
|
5dc2595159 | ||
|
|
919aa2622d | ||
|
|
025c66db7e | ||
|
|
b3361100da | ||
|
|
e0ffde1614 | ||
|
|
4bfe607f64 | ||
|
|
c0cbe8e0ab | ||
|
|
1e6d41e113 | ||
|
|
54f0a49281 | ||
|
|
618f5360ae | ||
|
|
6f8b5afd56 | ||
|
|
6432528d37 | ||
|
|
b62e2c0b78 | ||
|
|
f30e846f09 | ||
|
|
0a9b4bdc11 | ||
|
|
0102e99d3c | ||
|
|
19548c196e | ||
|
|
46ee987742 | ||
|
|
34428d82c7 | ||
|
|
bab27b8be1 | ||
|
|
6d06970c0f | ||
|
|
c16a965eb7 | ||
|
|
5cb7b82415 | ||
|
|
4d9a4267f4 | ||
|
|
fdbc7cc585 | ||
|
|
ed6c35a59f | ||
|
|
eca14a8868 | ||
|
|
fc719cb1c2 | ||
|
|
3dc6a30c4c | ||
|
|
3e93e180f1 | ||
|
|
3446f8f6ae | ||
|
|
541dd9eac7 | ||
|
|
62d866b60f | ||
|
|
f8f0444503 | ||
|
|
7eaf84d066 | ||
|
|
95511b5311 | ||
|
|
23817a04e1 | ||
|
|
2b90d6244f | ||
|
|
7485c4eb7a | ||
|
|
317e9881b8 | ||
|
|
c4e06bd2f7 | ||
|
|
fb1532be1c | ||
|
|
f076b05e7e | ||
|
|
71f502a8e8 | ||
|
|
5e1ac06375 | ||
|
|
341eb26c62 | ||
|
|
18f8294fa9 | ||
|
|
959a8e7594 | ||
|
|
4fde060510 | ||
|
|
6da4c54f9e | ||
|
|
ad0e3441a1 | ||
|
|
56e9e436cf | ||
|
|
6fde1e459d | ||
|
|
fa314611bc | ||
|
|
c34ebfa2e8 | ||
|
|
c6f0589ed5 | ||
|
|
8ffa8b6657 | ||
|
|
0a92b98110 | ||
|
|
b6c31757a7 | ||
|
|
676efe247f | ||
|
|
f6defc091c | ||
|
|
8bb779ea9e | ||
|
|
18d0cf51ef | ||
|
|
8b7b363440 | ||
|
|
6ba77c146b | ||
|
|
54ab7ea9ee | ||
|
|
b9c0e96933 | ||
|
|
41650d58a2 | ||
|
|
3519f4f9c7 | ||
|
|
991e40e089 | ||
|
|
1a54aadff0 | ||
|
|
6e3f82299f | ||
|
|
9e845ec580 | ||
|
|
c95fb32d0a | ||
|
|
bfe64ea153 | ||
|
|
146d641f97 | ||
|
|
6a94ea066d | ||
|
|
477ec44b75 | ||
|
|
284b00fa78 | ||
|
|
0f94ba3d39 | ||
|
|
2e157dd969 | ||
|
|
f945845a77 | ||
|
|
457cf98089 | ||
|
|
ab65b53201 | ||
|
|
3da4daeed5 | ||
|
|
f9c5f89595 | ||
|
|
d71947cb63 | ||
|
|
cdf29b6c56 | ||
|
|
73ddadc0f0 | ||
|
|
bd8431504d | ||
|
|
efcee75f30 | ||
|
|
b283e05f9c | ||
|
|
d15757755a | ||
|
|
b3259e4b49 | ||
|
|
cebf8d3579 | ||
|
|
9451a6a1ec | ||
|
|
5d3321839d | ||
|
|
594458235b | ||
|
|
a3273dedc1 | ||
|
|
42824713e3 | ||
|
|
4ad40ee00d | ||
|
|
ddf33a13cd | ||
|
|
4ce8ea9ce9 | ||
|
|
5b84fd6e40 | ||
|
|
d7af63877e | ||
|
|
844ed59dd8 | ||
|
|
35e29a0615 | ||
|
|
7c71cd1f80 | ||
|
|
74ad0faffa | ||
|
|
e13948957c | ||
|
|
64915f18ff | ||
|
|
1f8306d2b3 | ||
|
|
cdc88dbe18 | ||
|
|
b59f96d238 | ||
|
|
110bd20600 | ||
|
|
0d6a962344 | ||
|
|
c192f3b47b | ||
|
|
53fa384608 | ||
|
|
1448791fcd | ||
|
|
a66a4210c3 | ||
|
|
b1ffd8d556 | ||
|
|
4548696c73 | ||
|
|
0d460dd6b1 | ||
|
|
4333e3da67 | ||
|
|
352ccb21ff | ||
|
|
2ac57642a4 | ||
|
|
af1ddf2fc6 | ||
|
|
e23c519fac | ||
|
|
664a31fc87 | ||
|
|
cbcc988625 | ||
|
|
ce33737a38 | ||
|
|
f4e243255a | ||
|
|
8df8479716 | ||
|
|
f28ac43446 | ||
|
|
263df059a4 | ||
|
|
64d1e9ca46 | ||
|
|
286ec29f91 | ||
|
|
66ca5c0d34 | ||
|
|
919335b4f5 | ||
|
|
c5a4b2605c | ||
|
|
2da0142387 | ||
|
|
7ba759b08a | ||
|
|
fdd5aa0a5a | ||
|
|
6ee80f6182 | ||
|
|
af2e0348c1 | ||
|
|
d4bf45a8b8 | ||
|
|
d30425b2bd | ||
|
|
cff8fbbd79 | ||
|
|
8b52c99604 | ||
|
|
5dee254fca | ||
|
|
2ab0f494b4 | ||
|
|
b4a58b47b3 | ||
|
|
b19450684b | ||
|
|
6451e3b3e3 | ||
|
|
14e2a169e4 | ||
|
|
f809919561 | ||
|
|
68d4b9d2cd | ||
|
|
5e1c6ae30d | ||
|
|
e1ba234a76 | ||
|
|
b9b84fe692 | ||
|
|
a3f5c461c3 | ||
|
|
91479543fa | ||
|
|
4dfa724972 | ||
|
|
f8e72504e5 | ||
|
|
51d6ba98d7 | ||
|
|
2309e18eb7 | ||
|
|
6ddb891c29 | ||
|
|
5100f6cb72 | ||
|
|
73e56d820b | ||
|
|
803cbae1dc | ||
|
|
9b9f877942 | ||
|
|
0e6df9d299 | ||
|
|
1cbe1cfaeb | ||
|
|
295eedc0b9 | ||
|
|
97a766517b | ||
|
|
42868ecbee | ||
|
|
4fd4b145d7 | ||
|
|
d5f7dc851e | ||
|
|
06fae21c76 | ||
|
|
29fe631ce6 | ||
|
|
40ab25d2a6 | ||
|
|
0f9a2dc9d3 | ||
|
|
89da16afec | ||
|
|
1dfc77a4ba | ||
|
|
4fb8fa1311 | ||
|
|
782f47a30b | ||
|
|
7eba982278 | ||
|
|
df78df5908 | ||
|
|
0dd98b56bc | ||
|
|
0a573f9da1 | ||
|
|
6d43387c55 | ||
|
|
ed4094016b | ||
|
|
56100f150d | ||
|
|
6284f29a96 | ||
|
|
4e06ed80d1 | ||
|
|
a0c294f689 | ||
|
|
19f668f4f6 | ||
|
|
02bd640aab | ||
|
|
06b1060a45 | ||
|
|
0f0dcb9eae | ||
|
|
5ec6d571eb | ||
|
|
347de2cb8b | ||
|
|
f6a923ad56 | ||
|
|
43455ee661 | ||
|
|
911df72aeb | ||
|
|
b82225e279 | ||
|
|
bb3cc58ad0 | ||
|
|
804a345fec | ||
|
|
7816510fdf | ||
|
|
50031dbc89 | ||
|
|
7f05164a7f | ||
|
|
52a6806022 | ||
|
|
1a9d47c554 | ||
|
|
2c3b3be3ee | ||
|
|
cdaed50939 | ||
|
|
5a155020e6 | ||
|
|
957b34d169 | ||
|
|
79d2ac0566 | ||
|
|
547f9ff61f | ||
|
|
9f0da2ec41 | ||
|
|
32eafb7708 | ||
|
|
c81b8fb3c3 | ||
|
|
a9be167146 | ||
|
|
c755dc3ed9 | ||
|
|
d20fb2039a | ||
|
|
1c3411f808 | ||
|
|
7357be3c35 | ||
|
|
5dd1bed913 | ||
|
|
18eda8aade | ||
|
|
8e16e6266e | ||
|
|
8100cdb17f | ||
|
|
7fa01fa4f3 | ||
|
|
d49e78c43e | ||
|
|
cf46768ac7 | ||
|
|
cfe718f4ef | ||
|
|
bf32b90702 | ||
|
|
9cb14d6db3 | ||
|
|
140cf0debe | ||
|
|
45ad5375a2 | ||
|
|
259adda77d | ||
|
|
964f3fe06d | ||
|
|
002c49b32f | ||
|
|
d4313be406 | ||
|
|
76a4ded128 | ||
|
|
8d68e805f4 | ||
|
|
f1a171a94c | ||
|
|
7e9b12b475 | ||
|
|
63a3a8a731 | ||
|
|
c95421f307 | ||
|
|
edc62449f6 | ||
|
|
a7f1192402 | ||
|
|
6bbda8a8e7 | ||
|
|
2431dbc16f | ||
|
|
d87f86b2a4 | ||
|
|
55a0652c2b | ||
|
|
3e6517849e | ||
|
|
deacdde521 | ||
|
|
aa1559b159 | ||
|
|
88dd2f1495 | ||
|
|
eb2cd75370 | ||
|
|
d072f17896 | ||
|
|
0d31f79f53 | ||
|
|
b869312e4f | ||
|
|
deb6224cf8 | ||
|
|
4757648349 | ||
|
|
a1f166942c | ||
|
|
7dbe0c2899 | ||
|
|
9bc4873721 | ||
|
|
15005f5754 | ||
|
|
c959ca9821 | ||
|
|
26687226f4 | ||
|
|
408b5b517b | ||
|
|
f403699fb2 | ||
|
|
193b289e8e | ||
|
|
533fd0574a | ||
|
|
48ffdf419f | ||
|
|
93e931e2b6 | ||
|
|
6561e4f84e | ||
|
|
24d6e581a6 | ||
|
|
dcdcd8e41a | ||
|
|
24443221f2 | ||
|
|
787dd10c69 | ||
|
|
9705f1fe28 | ||
|
|
d5748474d0 | ||
|
|
2277fb04b9 | ||
|
|
78b2d30905 | ||
|
|
ed81d75815 | ||
|
|
ac3a399df3 | ||
|
|
619f90c677 | ||
|
|
0f3d5f4b10 | ||
|
|
26be5bf264 | ||
|
|
227c696750 | ||
|
|
b1cec9480e | ||
|
|
982da962e5 | ||
|
|
2a11bdb7ef | ||
|
|
3775c3fb2e | ||
|
|
cea120945c | ||
|
|
803c8ce6b5 | ||
|
|
ca99114b16 | ||
|
|
897adf27f0 | ||
|
|
fd59efe41f | ||
|
|
b52217e8a0 | ||
|
|
0280a10832 | ||
|
|
c297e926f9 | ||
|
|
59fa5c27b6 | ||
|
|
a202cfbbe9 | ||
|
|
848c893b9e | ||
|
|
252b8f5ca5 | ||
|
|
d82da5d571 | ||
|
|
1ebdd8ed8e | ||
|
|
7070fe9b2e | ||
|
|
7b2464a740 | ||
|
|
e2f19c30f1 | ||
|
|
5408df40f5 | ||
|
|
79894781b1 | ||
|
|
e798842dee | ||
|
|
98ff6c1279 | ||
|
|
59fb04321d | ||
|
|
81d537fa24 | ||
|
|
6488ab2375 | ||
|
|
a10f36e3a2 | ||
|
|
eed37a0f81 | ||
|
|
0781a4153e | ||
|
|
8ec1325aff | ||
|
|
947b116c06 | ||
|
|
095858d3d5 | ||
|
|
2b1b1ea33b | ||
|
|
bd1f64bfde | ||
|
|
d27e333941 | ||
|
|
c2bf47eca2 | ||
|
|
9035439f61 | ||
|
|
77955f4e2b | ||
|
|
6b7b63dff4 | ||
|
|
dd5bd17e2b | ||
|
|
2ab1493d27 | ||
|
|
9a1e75712d | ||
|
|
4c1ebfbdd4 | ||
|
|
f5bb8abfe0 | ||
|
|
a24f33ad93 | ||
|
|
ad5f0a7f7d | ||
|
|
2611e867b3 | ||
|
|
c9434ec4dc | ||
|
|
282e96649a | ||
|
|
34d6d0695f | ||
|
|
524bd52a56 | ||
|
|
efc5b8faaa | ||
|
|
112c6bd594 | ||
|
|
8b5c0fb715 | ||
|
|
82337b8baa | ||
|
|
71b93a2b4c | ||
|
|
86b302491a | ||
|
|
744f3d70ed | ||
|
|
e28a78afd3 | ||
|
|
7dd034e56c | ||
|
|
b97a07630d | ||
|
|
990aeca0ba | ||
|
|
3c5284f081 | ||
|
|
da01d3aaaa | ||
|
|
9d4e8164b7 | ||
|
|
ce9534cdea | ||
|
|
2236e7d2da | ||
|
|
632e226b51 | ||
|
|
6c4d1e5ce1 | ||
|
|
4ef5dc83bb | ||
|
|
9ebc78773d | ||
|
|
e2f8d77f67 | ||
|
|
256d36320a | ||
|
|
6bc8ad0e2c | ||
|
|
fd3ad76db3 | ||
|
|
8a39561ddb | ||
|
|
27584544d9 | ||
|
|
788ee6cd90 | ||
|
|
97f3ab23b7 | ||
|
|
074e9f70a0 | ||
|
|
621f1f1d61 | ||
|
|
ba338036f9 | ||
|
|
c896101a30 | ||
|
|
cd22b29ff1 | ||
|
|
1d8c46216f | ||
|
|
b5d70b90d9 | ||
|
|
9b03abaeef | ||
|
|
8a3d832b4c | ||
|
|
7fab75216f | ||
|
|
6c265fee30 | ||
|
|
d2848fc519 | ||
|
|
48092bd7ba | ||
|
|
5c15ceedc4 | ||
|
|
f568a2407b | ||
|
|
f1c6a8bc12 | ||
|
|
0fa499bd61 | ||
|
|
c747a79db9 | ||
|
|
a1751cc981 | ||
|
|
7bf5f6f5a9 | ||
|
|
797bfeec98 | ||
|
|
c3c61e1889 | ||
|
|
0d9973abb9 | ||
|
|
7de4fe7afa | ||
|
|
fb155dec58 | ||
|
|
90d27133b0 | ||
|
|
0f5d459ed8 | ||
|
|
f4dc08f1f8 | ||
|
|
4bedd52e16 | ||
|
|
391701fdc7 | ||
|
|
a973be2566 | ||
|
|
298fd49c55 | ||
|
|
23adbd4407 | ||
|
|
5b1cf49170 | ||
|
|
eba3e95b81 | ||
|
|
8819fd5fd7 | ||
|
|
9c2cb393c2 | ||
|
|
ca4e034a3b | ||
|
|
fd138cfae7 | ||
|
|
e530831b81 | ||
|
|
7c56ea47dd | ||
|
|
adb6404a0f | ||
|
|
084e0a315f | ||
|
|
c2f9b91fe2 | ||
|
|
b629b882b4 | ||
|
|
da91ab9879 | ||
|
|
a70bc7d953 | ||
|
|
7614c18fea | ||
|
|
c37783c895 | ||
|
|
905d23d159 | ||
|
|
7bf46cb40b | ||
|
|
385de88e2f | ||
|
|
c2da96e311 | ||
|
|
e46cd1478b | ||
|
|
8bbb3d30b2 | ||
|
|
1edcc511d6 | ||
|
|
9b22b33616 | ||
|
|
3fd8d3e5be | ||
|
|
ce167cf92d | ||
|
|
d718c292f5 | ||
|
|
3ccaa4de50 | ||
|
|
5cd137b745 | ||
|
|
95246d73c1 | ||
|
|
8ff2a32b47 | ||
|
|
90d52a8bb4 | ||
|
|
182f4c369a | ||
|
|
1d1f2d73ca | ||
|
|
a337bc28f9 | ||
|
|
8a5923527f | ||
|
|
59ad8499df | ||
|
|
566cd6c6e8 | ||
|
|
02a885eb09 | ||
|
|
632fba9dd5 | ||
|
|
eb2bb24c19 | ||
|
|
c8a37b4f99 | ||
|
|
117d946ed3 | ||
|
|
d4b0e2a124 | ||
|
|
4acda0c447 | ||
|
|
23401d37d8 | ||
|
|
a7b40a5cdd | ||
|
|
ad5b9b658e | ||
|
|
df28a4696e | ||
|
|
c30a6fb843 | ||
|
|
2e7afc3ca1 | ||
|
|
2f428fa389 | ||
|
|
0a189906cd | ||
|
|
e4a6d8520c | ||
|
|
fe138be7ae | ||
|
|
ff51263671 | ||
|
|
04f650dde7 | ||
|
|
48e797a80d | ||
|
|
bf3a152946 | ||
|
|
7264692a0a | ||
|
|
b5776445ec | ||
|
|
ee1c5478b1 | ||
|
|
63bad1dae0 | ||
|
|
d0fa16b96b | ||
|
|
3dacb4a5ef | ||
|
|
ce80ee1739 | ||
|
|
4e6b9978ce | ||
|
|
31d5ddb20a | ||
|
|
2355b7a38b | ||
|
|
0e68729d7f | ||
|
|
b33763caeb | ||
|
|
5b19c967f4 | ||
|
|
acd98b5c88 | ||
|
|
ff93262873 | ||
|
|
f535a6a242 | ||
|
|
ada73a16ce | ||
|
|
d1c978669b | ||
|
|
b28673d23d | ||
|
|
46848562d0 | ||
|
|
9cbc52e858 | ||
|
|
3cdf4fbc88 | ||
|
|
b032c9e455 | ||
|
|
6d4ce10150 | ||
|
|
8b227798e1 | ||
|
|
1514e8e981 | ||
|
|
4fbd0fdc42 | ||
|
|
fea31d54f8 | ||
|
|
3dffbd6071 | ||
|
|
876757e748 | ||
|
|
7abaa30526 | ||
|
|
1a467f9208 | ||
|
|
54d5f4b0a4 | ||
|
|
ca3a4f9b9c | ||
|
|
d53b8c5b1f | ||
|
|
1e49704062 | ||
|
|
d95268b548 | ||
|
|
e9bafa8f13 | ||
|
|
ef66334292 | ||
|
|
aa17d8c700 | ||
|
|
9f59ac96dd | ||
|
|
425888ee1f | ||
|
|
f72615dcbe | ||
|
|
e3d0d69918 | ||
|
|
77266e0b3c | ||
|
|
64bbe0c641 | ||
|
|
120cea8734 | ||
|
|
5a8c94183a | ||
|
|
de8e08f4f4 | ||
|
|
1e55b79b49 | ||
|
|
dcdc7cef65 | ||
|
|
6e40020906 | ||
|
|
c4c7da3967 | ||
|
|
580da9caef | ||
|
|
657baf9135 | ||
|
|
15c75f05e5 | ||
|
|
a8553c7c10 | ||
|
|
2b6d8697d5 | ||
|
|
dcd3995230 | ||
|
|
ad88dabfd1 | ||
|
|
4e13f3f2fd | ||
|
|
6a2d7bd2df | ||
|
|
81c1f0c7c9 | ||
|
|
cfd6928baa | ||
|
|
7b9582181c | ||
|
|
455ec8e3ae | ||
|
|
ea31bd2be2 | ||
|
|
bf6c0c95eb | ||
|
|
bb20a8f4ff | ||
|
|
cc18a5d3e2 | ||
|
|
88287c6c2d | ||
|
|
0fd0a05cd1 | ||
|
|
b0b084dbe8 | ||
|
|
41a6621ac2 | ||
|
|
9fb73e26dc | ||
|
|
59e8160f18 | ||
|
|
fdf3e499be | ||
|
|
c1ace9a7c3 | ||
|
|
f9a1d7240e | ||
|
|
def8016f44 | ||
|
|
175c70d99e | ||
|
|
872d65b824 | ||
|
|
339937a316 | ||
|
|
eed93dc30d | ||
|
|
bff22779ae | ||
|
|
24ef4d41d2 | ||
|
|
9f1a8fa7a2 | ||
|
|
729d2493cd | ||
|
|
4d8758f755 | ||
|
|
31ea0da526 | ||
|
|
3a2bf36359 | ||
|
|
dc0c63ccc3 | ||
|
|
534635cbc2 | ||
|
|
a7f22a0c5a | ||
|
|
b279a92e4c | ||
|
|
055dd7229e | ||
|
|
0922f3dab7 | ||
|
|
b4cfa8cefb | ||
|
|
6b660a0c76 | ||
|
|
1ccd89ddd8 | ||
|
|
cbb710cde7 | ||
|
|
d3b38ac5e8 | ||
|
|
1fb09dcfae | ||
|
|
f06be56fa3 | ||
|
|
9768ea4af9 | ||
|
|
26c26914da | ||
|
|
41783e87a3 | ||
|
|
299998b247 | ||
|
|
90ae5766e6 | ||
|
|
31ab70d6fc | ||
|
|
7537f4d032 | ||
|
|
32c5c82cb9 | ||
|
|
1c18862e0f | ||
|
|
97b3679101 | ||
|
|
7ecf6ece7c | ||
|
|
22b882648b | ||
|
|
a8150a84be | ||
|
|
df5a7104b1 | ||
|
|
2400b6aeab | ||
|
|
f42b241469 | ||
|
|
1c3d658ca1 | ||
|
|
9cbb8fd5bc | ||
|
|
4c86c75b5f | ||
|
|
f4904b8915 | ||
|
|
176440eeae | ||
|
|
1a0434fd85 | ||
|
|
9d2bdea8d9 | ||
|
|
c6ccf1d487 | ||
|
|
bd0114aa06 | ||
|
|
43506e708d | ||
|
|
3e218d6aec | ||
|
|
bf3c22f42c | ||
|
|
dcee0e5057 | ||
|
|
673c3c19f0 | ||
|
|
fa1441cf71 | ||
|
|
c57ef67784 | ||
|
|
b1e519fd62 | ||
|
|
b51a2e25c2 | ||
|
|
7b2835028a | ||
|
|
0faf38a1e1 | ||
|
|
9eee7a214e | ||
|
|
d0b152c638 | ||
|
|
6d08f0d60b | ||
|
|
aab8ade15b | ||
|
|
4c4a707624 | ||
|
|
5456bad23d | ||
|
|
8e6634168a | ||
|
|
a3179080d3 | ||
|
|
985759ce91 | ||
|
|
a688a3de79 | ||
|
|
2184c7ca4d | ||
|
|
f6b378513d | ||
|
|
02a89e2343 | ||
|
|
e2d4ae4acc | ||
|
|
95b7f78a5a | ||
|
|
e694f8f173 | ||
|
|
8d1a5ac6b9 | ||
|
|
030bd9388b | ||
|
|
a78c1bf03a | ||
|
|
be35ea2704 | ||
|
|
7e562fa3aa | ||
|
|
91f2252255 | ||
|
|
0582033fb7 | ||
|
|
5caf76fb3a | ||
|
|
30509823bb | ||
|
|
835bd59330 | ||
|
|
e73cb7d363 | ||
|
|
8aee458022 | ||
|
|
20eb62b3d2 | ||
|
|
f4f9e8880c | ||
|
|
b0a56f1690 | ||
|
|
8444f808f6 | ||
|
|
b959f13a0c | ||
|
|
f0163e13c9 | ||
|
|
a89ca14abe | ||
|
|
9b77f1b7ac | ||
|
|
e68077d159 | ||
|
|
5724dfe21d | ||
|
|
364208e029 | ||
|
|
fea0299033 | ||
|
|
c1dd821c6e | ||
|
|
6a67243460 | ||
|
|
7f1b396ce8 | ||
|
|
1e5bccd48e | ||
|
|
d016e8a5e8 | ||
|
|
d01a0e1b2d | ||
|
|
2d8681dbd4 | ||
|
|
2bd5696d99 | ||
|
|
fc49574947 | ||
|
|
2c0cf72a60 | ||
|
|
c4dc9c8bdb | ||
|
|
dec7ca1e19 | ||
|
|
ccb6b3b4a2 | ||
|
|
5658ea2c1e | ||
|
|
3886f27acd | ||
|
|
0b1d67116d | ||
|
|
76738a0208 | ||
|
|
32dc0826cb | ||
|
|
590b7ec704 | ||
|
|
98b735b185 | ||
|
|
dd686a0fca | ||
|
|
de04c72767 | ||
|
|
3fe2e4487e | ||
|
|
2cf9fdf0d0 | ||
|
|
7c01f14bfe | ||
|
|
da99b7b455 | ||
|
|
716c340825 | ||
|
|
625e47a725 | ||
|
|
2ca3f657f9 | ||
|
|
b038b6baf6 | ||
|
|
f29f39d427 | ||
|
|
9abb79d191 | ||
|
|
c3740c548d | ||
|
|
629f12a851 | ||
|
|
e4de525a09 | ||
|
|
1a4e5a345d | ||
|
|
a4ae36929b | ||
|
|
b9b98a39bb | ||
|
|
ae4b7cb58e | ||
|
|
f7d67e4b87 | ||
|
|
20c7ed0034 | ||
|
|
5c00ea627e | ||
|
|
ff074294ee | ||
|
|
028965e708 | ||
|
|
28b48edf02 | ||
|
|
86b83338c0 | ||
|
|
25f51eb5cd | ||
|
|
7586af8f91 | ||
|
|
d6b9daf7ca | ||
|
|
2905cd1586 | ||
|
|
7a6009f2e3 | ||
|
|
a6d6fb1a1e | ||
|
|
4af061516c | ||
|
|
df9611cc2c | ||
|
|
99cd246ed8 | ||
|
|
872df9fe39 | ||
|
|
ec4bfa00ee | ||
|
|
68c001e0c0 | ||
|
|
5e40d6702e | ||
|
|
a3d4dc2f9a | ||
|
|
a8d1224097 | ||
|
|
73fea44aa2 | ||
|
|
309463f15d | ||
|
|
37a89a7b0a | ||
|
|
6b6f5d98e4 | ||
|
|
2712a4d45c | ||
|
|
d93fa98d1e | ||
|
|
63616cc50a | ||
|
|
eb643a2df8 | ||
|
|
81f958eee1 | ||
|
|
613f61a898 | ||
|
|
77a009c9a6 | ||
|
|
2d8a849d12 | ||
|
|
b09908e6af | ||
|
|
ad74e93ea2 | ||
|
|
754311d2e2 | ||
|
|
f6514f3c64 | ||
|
|
f398185aad | ||
|
|
4390bea31f | ||
|
|
660c98d6e5 | ||
|
|
1154a629a7 | ||
|
|
09e235eb60 | ||
|
|
9dab0f083d | ||
|
|
6dd44687c5 | ||
|
|
1a639afd99 | ||
|
|
1ee85181e8 | ||
|
|
c7ef136a7b | ||
|
|
5017189440 | ||
|
|
72cc494df4 | ||
|
|
f516078510 | ||
|
|
6a1e5840b5 | ||
|
|
98fbf3abc1 | ||
|
|
e265d09034 | ||
|
|
dbb88b8a17 | ||
|
|
34e7d4abe5 | ||
|
|
f434717372 | ||
|
|
88f8581dcc | ||
|
|
552ba68187 | ||
|
|
cff29904d7 | ||
|
|
b1774cdccf | ||
|
|
32737e0b72 | ||
|
|
b54ce4d782 | ||
|
|
b6adf26549 | ||
|
|
d0bfde1887 | ||
|
|
4094a1f826 | ||
|
|
8afb67521d | ||
|
|
34be9cea3a | ||
|
|
618194996a | ||
|
|
42f49795af | ||
|
|
e444a5d60a | ||
|
|
593f3c2109 | ||
|
|
e9fb821721 | ||
|
|
a4afe1bde9 | ||
|
|
1d29fda5fd | ||
|
|
16b7093e19 | ||
|
|
0f5a6b4e5e | ||
|
|
c7a8124be8 | ||
|
|
c3c74a13c0 | ||
|
|
cde50cc8b4 | ||
|
|
fcc11b8969 | ||
|
|
c9b7d1e842 | ||
|
|
e5f4a7c39a | ||
|
|
814e72879e | ||
|
|
5f9463a030 | ||
|
|
37d4a06aa4 | ||
|
|
fb590550cd | ||
|
|
2f27291c53 | ||
|
|
fc23863d85 | ||
|
|
8651a59f43 | ||
|
|
2f1e9d76ec | ||
|
|
2e1a72030e | ||
|
|
c9f32ac77b | ||
|
|
6efa30c52a | ||
|
|
ef30e21506 | ||
|
|
70b5f9ee98 | ||
|
|
3137839322 | ||
|
|
345a865cc8 | ||
|
|
2a4ef4394c | ||
|
|
3ba5be1ec6 | ||
|
|
606f3dfe6b | ||
|
|
c865644e6c | ||
|
|
fec1586380 | ||
|
|
8e2afde3e4 | ||
|
|
5410884e03 | ||
|
|
e9ceb1d0c6 | ||
|
|
8d14bdd819 | ||
|
|
23f3a01e3c | ||
|
|
3540dd1c26 | ||
|
|
cae5486ec6 | ||
|
|
a769618e3e | ||
|
|
80d537958e | ||
|
|
d923fb56e2 | ||
|
|
7747bbffcf | ||
|
|
db47d8fb85 | ||
|
|
c52315cd8d | ||
|
|
a2787f8783 | ||
|
|
913308d886 | ||
|
|
21bb383193 | ||
|
|
bd83885eca | ||
|
|
d34d139658 | ||
|
|
f5c201c0be | ||
|
|
10fcc0c452 | ||
|
|
378822b777 | ||
|
|
edebb81ed4 | ||
|
|
7cf3ac3b40 | ||
|
|
c46c365823 | ||
|
|
66f5e1fb64 | ||
|
|
c80417c433 | ||
|
|
32e3df1e80 | ||
|
|
3f65153d4f | ||
|
|
5fbf0f83cb | ||
|
|
84c8427bb4 | ||
|
|
539a8f0ca9 | ||
|
|
6281f188f8 | ||
|
|
a444a7de19 | ||
|
|
4369f4b5bb | ||
|
|
3689a7f17f | ||
|
|
d39849b297 | ||
|
|
7764921c21 | ||
|
|
26ceb25e7b | ||
|
|
13423e43d5 | ||
|
|
45da163230 | ||
|
|
281e3c925c | ||
|
|
6f50900b1b | ||
|
|
6b051d77ab | ||
|
|
10ae5bfbc0 | ||
|
|
2200e40001 | ||
|
|
44b609f604 | ||
|
|
d5918157ff | ||
|
|
19b53746cf | ||
|
|
d0769ec360 | ||
|
|
3c20bf8ad6 | ||
|
|
3eab2a528f | ||
|
|
fb404a0671 | ||
|
|
6d6cf52180 | ||
|
|
e9ba326610 | ||
|
|
55ca956f50 | ||
|
|
f43c643d5a | ||
|
|
69f5fc536c | ||
|
|
132ac7c03f | ||
|
|
5683af9bc8 | ||
|
|
429933f601 | ||
|
|
317364681a | ||
|
|
9575fd7771 | ||
|
|
85cfb18906 | ||
|
|
33fe1573ad | ||
|
|
2574fac44a | ||
|
|
b166995327 | ||
|
|
feaf9c6f20 | ||
|
|
0ef03d31b8 | ||
|
|
80ee88d3a7 | ||
|
|
bbc45dd947 | ||
|
|
d07ee3ea23 | ||
|
|
7ffd65476b | ||
|
|
ca0a07cab8 | ||
|
|
0d29f15b70 | ||
|
|
714d36d8c8 | ||
|
|
cd94819099 | ||
|
|
52199776d5 | ||
|
|
f8df87edcf | ||
|
|
dc68daa859 | ||
|
|
1fd021770e | ||
|
|
6f32e598e9 | ||
|
|
19794b06ab | ||
|
|
ecdb064a5b | ||
|
|
d67a03bfb4 | ||
|
|
c361d7a52a | ||
|
|
0018be6fd8 | ||
|
|
4a4aa5fc10 | ||
|
|
8791195673 | ||
|
|
72374257ef | ||
|
|
1b9def2101 | ||
|
|
7a467e249e | ||
|
|
a66942b1b1 | ||
|
|
acd3425c43 | ||
|
|
70bc45ba12 | ||
|
|
026c210e64 | ||
|
|
3bc1849041 | ||
|
|
17668aca17 | ||
|
|
2a48b0ca54 | ||
|
|
5acc15ea9e | ||
|
|
52fff2056b | ||
|
|
2a955884b8 | ||
|
|
ad5403b538 | ||
|
|
4daef7fc07 | ||
|
|
f538cbc51d | ||
|
|
e232b18b94 | ||
|
|
fcf62080d6 | ||
|
|
58103ce0f3 | ||
|
|
0827f584be | ||
|
|
f042996e7f | ||
|
|
7b307a6fb4 | ||
|
|
bb8a7bacdc | ||
|
|
0696b22971 | ||
|
|
d7ff93f7f2 | ||
|
|
0483f9d714 | ||
|
|
56c0f7f6f1 | ||
|
|
dc30092b60 | ||
|
|
25a4a00b16 | ||
|
|
7ccd6f842b | ||
|
|
299a664b9c | ||
|
|
0ed398310f | ||
|
|
55709cb83a | ||
|
|
d0c7796e7c | ||
|
|
544dff205d | ||
|
|
25763962b2 | ||
|
|
fc858933be | ||
|
|
6877aaaf61 | ||
|
|
e4ab1256da | ||
|
|
f2dd6b5dce | ||
|
|
eeceaa0c9b | ||
|
|
bc79d57712 | ||
|
|
36bbab1d84 | ||
|
|
59b6ddc29e | ||
|
|
f04032aa97 | ||
|
|
96cba7281a | ||
|
|
954ec26e80 | ||
|
|
63e8c732cc | ||
|
|
086c0e6ef0 | ||
|
|
fabe1d8991 | ||
|
|
02b65e6dfb | ||
|
|
aa546374f3 | ||
|
|
288ec78c3e | ||
|
|
2f875615a2 | ||
|
|
49adcd85fc | ||
|
|
8e785c2210 | ||
|
|
310422adb1 | ||
|
|
0dbebf2f04 | ||
|
|
46aabf0ea2 | ||
|
|
1a14ef2418 | ||
|
|
aa4eff9f8d | ||
|
|
9ffaf538e2 | ||
|
|
2a21ce4a0c | ||
|
|
09d5957c82 | ||
|
|
2b8b570dd4 | ||
|
|
a7bee74fb0 | ||
|
|
1f803f52d1 | ||
|
|
0d5b4d4958 | ||
|
|
24cce3ca8a | ||
|
|
2a0ee14130 | ||
|
|
e25394a322 | ||
|
|
ab1dc15393 | ||
|
|
3a750591bb | ||
|
|
7da9877c5f | ||
|
|
66ff5dcb86 | ||
|
|
f50a6ea7a3 | ||
|
|
253d7497ef | ||
|
|
1efc2e3c15 | ||
|
|
909c6ed171 | ||
|
|
b4f916351e | ||
|
|
a47a5b76eb | ||
|
|
919bfb7960 | ||
|
|
bc09c99952 | ||
|
|
28ccb27d4f | ||
|
|
d205c4eac7 | ||
|
|
18662deec6 | ||
|
|
d955eceafa | ||
|
|
995d529fb7 | ||
|
|
d4e460dac5 | ||
|
|
0314005e0e | ||
|
|
7831085a97 | ||
|
|
dfb2340e83 | ||
|
|
db8f2fdf75 | ||
|
|
d18e77329f | ||
|
|
8f4acc98d4 | ||
|
|
95f7ba29cc | ||
|
|
7ab20145d1 | ||
|
|
5f7d1e8dc3 | ||
|
|
6010288124 | ||
|
|
8a10105f48 | ||
|
|
478fb43d2a | ||
|
|
4b7cef637b | ||
|
|
69c72d366e | ||
|
|
5e7125e310 | ||
|
|
bc370a2a5a | ||
|
|
0abd9855c2 | ||
|
|
3525bd0183 | ||
|
|
098f72651c | ||
|
|
8c1d147319 | ||
|
|
327debe3a8 | ||
|
|
4af27541d0 | ||
|
|
70182a0ea2 | ||
|
|
183260d9e3 | ||
|
|
df2cf923e1 | ||
|
|
c35ccde682 | ||
|
|
afbfde0909 | ||
|
|
e72093c91e | ||
|
|
1ffdaf0f8b | ||
|
|
74431972d8 | ||
|
|
19804720af | ||
|
|
1f8555ffd2 | ||
|
|
4218c49a7e | ||
|
|
8aaf298466 | ||
|
|
82e2c7a0e8 | ||
|
|
27fa01648f | ||
|
|
ab25408429 | ||
|
|
d896baf38b | ||
|
|
53798c1545 | ||
|
|
1e6f0090da | ||
|
|
0dcca6d388 | ||
|
|
934691fffb | ||
|
|
6bc26eb0cc | ||
|
|
bdcc1539ac | ||
|
|
6715fbbce2 | ||
|
|
da055f83b3 | ||
|
|
1476efce90 | ||
|
|
2078d0e23b | ||
|
|
ea0107f67f | ||
|
|
c71f5baef2 | ||
|
|
66f55df44a | ||
|
|
8fd5f30b87 | ||
|
|
8bc4a287a6 | ||
|
|
d1dd177bfd | ||
|
|
80b6788638 | ||
|
|
ce6444c30e | ||
|
|
5e3d9df81a | ||
|
|
a0d52d415b | ||
|
|
c437537749 | ||
|
|
c16c0309c8 | ||
|
|
1dcd380bb2 | ||
|
|
6fe3d53a13 | ||
|
|
92cdda1d22 | ||
|
|
3eb4155489 | ||
|
|
e657e7a684 | ||
|
|
5446bedfcc | ||
|
|
be36803570 | ||
|
|
998bdb550b | ||
|
|
a0c7305334 | ||
|
|
edb86ebeeb | ||
|
|
bfe53a1d54 | ||
|
|
3ab2ebf71f | ||
|
|
0f43cdee00 | ||
|
|
9ef9bf9f42 | ||
|
|
b04dbb647b | ||
|
|
72092732f3 | ||
|
|
7f0ff5fd0a | ||
|
|
0318d23ab6 | ||
|
|
8fdf78cf67 | ||
|
|
06348bbe0b | ||
|
|
3ec4d3e374 | ||
|
|
9866bf19a4 | ||
|
|
1e3c668c9b | ||
|
|
36bfc7c675 | ||
|
|
d6429e532b | ||
|
|
864db16e33 | ||
|
|
02ebb6e4f7 | ||
|
|
44521a3c22 | ||
|
|
c5afd3d39f | ||
|
|
5b5034da63 | ||
|
|
2fd67f6ba8 | ||
|
|
5b6779a3a9 | ||
|
|
74820a5040 | ||
|
|
be76424513 | ||
|
|
2d4e544931 | ||
|
|
1077294e9a | ||
|
|
bd691d5307 | ||
|
|
48ef639408 | ||
|
|
9830b2b115 | ||
|
|
ca381029f1 | ||
|
|
40e07bbb45 | ||
|
|
7efc8230a2 | ||
|
|
38dd03652a | ||
|
|
21a34f88b2 | ||
|
|
092cb01bb3 | ||
|
|
d9640aa205 | ||
|
|
469414cb35 | ||
|
|
f42e0d42fd | ||
|
|
99798ffea7 | ||
|
|
f96c113065 | ||
|
|
7fe576163d | ||
|
|
314be1ec11 | ||
|
|
0d810e64b7 | ||
|
|
e4d3334313 | ||
|
|
5384a9e86f | ||
|
|
5763ebdf2b | ||
|
|
3f58c4ea6f | ||
|
|
22f75fa9cd | ||
|
|
a76fbb0073 | ||
|
|
299a035b7f | ||
|
|
340b86e97f | ||
|
|
4fff92f3ee | ||
|
|
a41ff7f2d0 | ||
|
|
b11294d9cf | ||
|
|
fda6694e0f | ||
|
|
399734fad4 | ||
|
|
0b5f0e5e61 | ||
|
|
f87dbec170 | ||
|
|
67f7649f6c | ||
|
|
c2cad3cca3 | ||
|
|
5a99011feb | ||
|
|
392702cc18 | ||
|
|
0c8715dd8d | ||
|
|
487d38fd21 | ||
|
|
c028c0ad26 | ||
|
|
925a922d90 | ||
|
|
aeb2671fc0 | ||
|
|
502edbd152 | ||
|
|
5fed81e1dc | ||
|
|
ed2e637219 | ||
|
|
6293380406 | ||
|
|
3649b0ed9c | ||
|
|
73641cb726 | ||
|
|
71cfeae5f1 | ||
|
|
c40aaa04f6 | ||
|
|
f4f4554cde | ||
|
|
1b0fa21f28 | ||
|
|
5c0e079873 | ||
|
|
6ede1ccb04 | ||
|
|
7173d3c866 | ||
|
|
c989c30e00 | ||
|
|
13fbfb6cac | ||
|
|
d649fc2413 | ||
|
|
8015106976 | ||
|
|
6b6c44c4d5 | ||
|
|
742bfcb0e7 | ||
|
|
f222d7bfe7 | ||
|
|
f6bdf06e45 | ||
|
|
c04f188adc | ||
|
|
1e2964ad8f | ||
|
|
dd63174493 | ||
|
|
91642080d6 | ||
|
|
ccf18bb9cb | ||
|
|
64a74d9ac6 | ||
|
|
bc8dc10ac3 | ||
|
|
324e75650d | ||
|
|
8c205faf2d | ||
|
|
d56a15db83 | ||
|
|
342bde7767 | ||
|
|
ec80a4c9e6 | ||
|
|
2a1af53d79 | ||
|
|
c528563421 | ||
|
|
a3a01c2419 | ||
|
|
40d30459b8 | ||
|
|
b746824933 | ||
|
|
1e9958c4c7 | ||
|
|
3230ea2519 | ||
|
|
22fc8337a3 | ||
|
|
86d5818c0f | ||
|
|
b6a173cc0c | ||
|
|
ec9c682052 | ||
|
|
e9d076adcd | ||
|
|
d59bc012b6 | ||
|
|
eb292e6d87 | ||
|
|
129a8cb411 | ||
|
|
d76706b865 | ||
|
|
159c5c7342 | ||
|
|
4d50eea29b | ||
|
|
0ec10515cd | ||
|
|
c2f20c21e6 | ||
|
|
e2ead56256 | ||
|
|
029e45d027 | ||
|
|
93cc97002a | ||
|
|
8fed89164f | ||
|
|
48b9f3198f | ||
|
|
5893b33962 | ||
|
|
d2f3ceaf67 | ||
|
|
271b935ba2 | ||
|
|
3ddab9e26a | ||
|
|
d68278e41f | ||
|
|
25676b4460 | ||
|
|
56c7e1991e | ||
|
|
ff68ccdeab | ||
|
|
4acbfd5587 | ||
|
|
8df2e608ab | ||
|
|
38f8b1a931 | ||
|
|
099ee1e249 | ||
|
|
9e8f659faf | ||
|
|
cd148c36c9 | ||
|
|
aba7fd5527 | ||
|
|
68c794bf9d | ||
|
|
ca9b3a7dbf | ||
|
|
4eba585286 | ||
|
|
4172ecfdf2 | ||
|
|
da80176935 | ||
|
|
f50802b85b | ||
|
|
5351bf7e12 | ||
|
|
96a038559e | ||
|
|
c321084990 | ||
|
|
e13d070439 | ||
|
|
1a8fc7f07f | ||
|
|
9ef95e1f68 | ||
|
|
28ed2f9bd0 | ||
|
|
93f51eaa42 | ||
|
|
7c807dd887 | ||
|
|
429b42d3e0 | ||
|
|
08f013171e | ||
|
|
d620032d0d | ||
|
|
3bc5605633 | ||
|
|
3a0068186a | ||
|
|
e19a782954 | ||
|
|
88783efa7b | ||
|
|
a249588f52 | ||
|
|
2951a83e73 | ||
|
|
b99ece088d | ||
|
|
ebd797d6d7 | ||
|
|
fa7a68f3f8 | ||
|
|
8167c46cfc | ||
|
|
9456810c7e | ||
|
|
79f2ec5d17 | ||
|
|
38a0a261c0 | ||
|
|
91eb23ba87 | ||
|
|
706129bcbd | ||
|
|
97b77e9b7b | ||
|
|
3b85a67faf | ||
|
|
f2571e6536 | ||
|
|
bec8a4b1c6 | ||
|
|
028fb03ef1 | ||
|
|
65aa08a9d9 | ||
|
|
22058a7a93 | ||
|
|
90514bd3cb | ||
|
|
bd7d258fcd | ||
|
|
c21e40e819 | ||
|
|
e0c8ae6335 | ||
|
|
e9d5d33cb2 | ||
|
|
0d9b49df85 | ||
|
|
db5e5d7da6 | ||
|
|
44236795b5 | ||
|
|
a26bca5dbe | ||
|
|
872b446695 | ||
|
|
2b0ed8234c | ||
|
|
27cda34f8b | ||
|
|
39ec1cfd27 | ||
|
|
b7dcd24e11 | ||
|
|
5097030143 | ||
|
|
516fac037f | ||
|
|
1bf632a575 | ||
|
|
6137aa8637 | ||
|
|
4be4506ffc | ||
|
|
d3c368ba92 | ||
|
|
9b0d03b024 | ||
|
|
c21d2fd017 | ||
|
|
2940b5e787 | ||
|
|
cf18bcaaf9 | ||
|
|
c4eaf083b4 | ||
|
|
df6b592d11 | ||
|
|
109e8b1e33 | ||
|
|
85c88d7c93 | ||
|
|
d8e5fa3087 | ||
|
|
697a7b308a | ||
|
|
dcc031f23a | ||
|
|
061ea47953 | ||
|
|
f0e5161b7b | ||
|
|
eada36af26 | ||
|
|
a02c687df9 | ||
|
|
e636087f4a | ||
|
|
4876f77914 | ||
|
|
ed6bed9bf7 | ||
|
|
87cb2eb19d | ||
|
|
53334251b8 | ||
|
|
a069f2945b | ||
|
|
5a0e1d7bb3 | ||
|
|
ed1d77c86d | ||
|
|
74054442a2 | ||
|
|
59ef8329c0 | ||
|
|
20cffaa7fe | ||
|
|
ebeb1040e8 | ||
|
|
cdb919dea3 | ||
|
|
c509e6131a | ||
|
|
db6a4d7042 | ||
|
|
a32b5ea72b | ||
|
|
58a2fce110 | ||
|
|
3d9ae42dbf | ||
|
|
c4a16d10bc | ||
|
|
eeca40c6f0 | ||
|
|
2a031e82a4 | ||
|
|
0e6ce205ab | ||
|
|
9acbe0f2f8 | ||
|
|
3ee9c1a439 | ||
|
|
0eeff20af6 | ||
|
|
a1cf9f1cd4 | ||
|
|
3897f422fe | ||
|
|
9d785d1a3c | ||
|
|
66f818872c | ||
|
|
342bacb25c | ||
|
|
8e81be0319 | ||
|
|
3acfa142bc | ||
|
|
94a58c810e | ||
|
|
757a2bf400 | ||
|
|
b18fbd685b | ||
|
|
56b5a9ec22 | ||
|
|
70432f0198 | ||
|
|
0736f86f32 | ||
|
|
107d739489 | ||
|
|
32a86a911f | ||
|
|
9a32733f88 | ||
|
|
0f655e3264 | ||
|
|
55a4afa341 | ||
|
|
3b5aa1a2ab | ||
|
|
658e569251 | ||
|
|
4eacfd83d6 | ||
|
|
ad0fd0a34e | ||
|
|
1d8092e431 | ||
|
|
57c8d223ad | ||
|
|
8641738777 | ||
|
|
ee190d07c5 | ||
|
|
87cc62d1d8 | ||
|
|
a16388b57d | ||
|
|
98e54d2e09 | ||
|
|
bd02ec057c | ||
|
|
6ac804d37c | ||
|
|
4b764dc8b4 | ||
|
|
3a8ad56d4b | ||
|
|
f5bee48d98 | ||
|
|
24fbfbee60 | ||
|
|
a1bc5ad4d3 | ||
|
|
4aa3824a2a | ||
|
|
37d92c1182 | ||
|
|
d581dec6cf | ||
|
|
a0eadc6c4a | ||
|
|
fdf672cf0a | ||
|
|
b8dacb1ffa | ||
|
|
81a99dd190 | ||
|
|
6a42d601c5 | ||
|
|
59ce74a3df | ||
|
|
eacee00fc8 | ||
|
|
fe70a5541e | ||
|
|
c9d4089b9a | ||
|
|
8fdb872605 | ||
|
|
8b28041cf0 | ||
|
|
4d3f8c3c8c | ||
|
|
f8cb4a15cb | ||
|
|
dd7d36da43 | ||
|
|
12201d38f3 | ||
|
|
3b4ad1d583 | ||
|
|
d44df8a9da | ||
|
|
ab88f72827 | ||
|
|
75a00e8c4a | ||
|
|
76c5500488 | ||
|
|
8cb7c05c88 | ||
|
|
e081dbf127 | ||
|
|
71e8f0201a | ||
|
|
c9ecb20b50 | ||
|
|
7dc213995c | ||
|
|
bea34a9b35 | ||
|
|
5ae405a89b | ||
|
|
66fcbe7871 | ||
|
|
b27a3cdbe5 | ||
|
|
9d7b822409 | ||
|
|
ab3f260757 | ||
|
|
b26b0a321b | ||
|
|
9536858599 | ||
|
|
c7d3ccb13a | ||
|
|
a081f98fd1 | ||
|
|
7096ea549e | ||
|
|
8e007985a1 | ||
|
|
e03e774113 | ||
|
|
7a41282912 | ||
|
|
c8f8c01d2f | ||
|
|
7f6db7bf98 | ||
|
|
e058efb622 | ||
|
|
bafd62d42d | ||
|
|
c14643849f | ||
|
|
edd09ef06a | ||
|
|
d06fccf157 | ||
|
|
6bc3d49ba2 | ||
|
|
a8d8736899 | ||
|
|
b1e4a43cd3 | ||
|
|
eafbebcebb | ||
|
|
0c72c52ba2 | ||
|
|
e8194d9c2e | ||
|
|
f0e1b67197 | ||
|
|
7ba27cf617 | ||
|
|
c9f765645c | ||
|
|
5daa8cb289 | ||
|
|
789d832808 | ||
|
|
0908139218 | ||
|
|
926bcfb514 | ||
|
|
d7971322cb | ||
|
|
6ddeb167b3 | ||
|
|
c1be09c692 | ||
|
|
1c2a304ee5 | ||
|
|
1a51acf2fc | ||
|
|
47a5296f0b | ||
|
|
1189e8c849 | ||
|
|
8d59fc1334 | ||
|
|
ce2316a8ee | ||
|
|
0aae4f2627 | ||
|
|
ec9ddc0819 | ||
|
|
a5bd55dcac | ||
|
|
b0b1bd88a6 | ||
|
|
75d5619abd | ||
|
|
522a641690 | ||
|
|
fe1bd1a978 | ||
|
|
b39f509263 | ||
|
|
7a8173bf6f | ||
|
|
1ea95bf6e0 | ||
|
|
08d690b65d | ||
|
|
edf07a8fbc | ||
|
|
fab7d41446 | ||
|
|
f33a55f1d0 | ||
|
|
96a3eef4e1 | ||
|
|
93dc4d1bc9 | ||
|
|
d973670026 | ||
|
|
c327956537 | ||
|
|
80f5ab09f3 | ||
|
|
5c8f201a92 | ||
|
|
cf777d7f41 | ||
|
|
bb7876759a | ||
|
|
800d6498d6 | ||
|
|
0648b4279f | ||
|
|
1a73abe7c3 | ||
|
|
cce4f7883c | ||
|
|
3dff67e0b1 | ||
|
|
24326883ca | ||
|
|
a5854f129d | ||
|
|
052c07f3e3 | ||
|
|
9367566e61 | ||
|
|
107103bcbb | ||
|
|
20ae47971c | ||
|
|
d4ecb03d15 | ||
|
|
f4eb47519d | ||
|
|
e37bfeeb09 | ||
|
|
bb0972ba49 | ||
|
|
ddc5994869 | ||
|
|
a2eb9e728c | ||
|
|
2169ba35ad | ||
|
|
50b447b05d | ||
|
|
bc14ad6b9d | ||
|
|
ffa33788c4 | ||
|
|
23c9c6bf44 | ||
|
|
604a49634d | ||
|
|
476c02976b | ||
|
|
6ac28e1a77 | ||
|
|
4ec7cea6c4 | ||
|
|
0036f329f5 | ||
|
|
15af54efda | ||
|
|
07966bb7fe | ||
|
|
e7d9b0503b | ||
|
|
072b43d178 | ||
|
|
281d2295ae | ||
|
|
3c7783f97c | ||
|
|
2a82703e46 | ||
|
|
79cf4370b4 | ||
|
|
6217fc8459 | ||
|
|
f1fd3d170a | ||
|
|
4e410f8a81 | ||
|
|
7a1b273d8d | ||
|
|
820531342d | ||
|
|
353db3277a | ||
|
|
82f37549ae | ||
|
|
09e1bd6bf1 | ||
|
|
44f3abf262 | ||
|
|
8c09af5013 | ||
|
|
0781e932c6 | ||
|
|
3cee00323c | ||
|
|
b1f6f3ddfa | ||
|
|
7147266ddf | ||
|
|
357212bff7 | ||
|
|
ed4fc3b20f | ||
|
|
7e8b71dd52 | ||
|
|
267f00bfe1 | ||
|
|
8f90dbce99 | ||
|
|
00485dba89 | ||
|
|
8fd4f5e4b6 | ||
|
|
e7e69b3fd4 | ||
|
|
2463c1dc05 | ||
|
|
bc590286f2 | ||
|
|
8c83816ec8 | ||
|
|
699069ce8f | ||
|
|
ec0cd22c1d | ||
|
|
8da3a8866d | ||
|
|
21f6fdff48 | ||
|
|
ed82a1fc87 | ||
|
|
1fa143453d | ||
|
|
1240bab7ed | ||
|
|
4af29d83d7 | ||
|
|
6aed29af91 | ||
|
|
37f1f50000 | ||
|
|
a93654c66b | ||
|
|
0d2dd94c81 | ||
|
|
c2f97e9aa3 | ||
|
|
e04bf6de95 | ||
|
|
38499c006a | ||
|
|
80cac38682 | ||
|
|
2b16d36aa2 | ||
|
|
dc9d49a12c | ||
|
|
03c81dfa9c | ||
|
|
b096e5dd0a | ||
|
|
7ae519145f | ||
|
|
592c3c1652 | ||
|
|
e940f294a6 | ||
|
|
759de8f45f | ||
|
|
c92c6c37f7 | ||
|
|
f425601043 | ||
|
|
68ba089a26 | ||
|
|
5ff7169546 | ||
|
|
7365a95b4d | ||
|
|
788427ec09 | ||
|
|
01ed8ad583 | ||
|
|
f516ba7a7d | ||
|
|
ab5603bd5a | ||
|
|
5c560e82b3 | ||
|
|
263a94af18 | ||
|
|
9d1cf360b6 | ||
|
|
60f664a5c2 | ||
|
|
a1c7aa7790 | ||
|
|
a29096ca5c | ||
|
|
0ef64f4091 | ||
|
|
945deeba60 | ||
|
|
aa775675b5 | ||
|
|
db76044880 | ||
|
|
edc58e358b | ||
|
|
1133efb3f1 | ||
|
|
d524accc98 | ||
|
|
543f91dd6e | ||
|
|
9848dabfa8 | ||
|
|
bc59efc3ba | ||
|
|
9af63ca32f | ||
|
|
eb8a566ae8 | ||
|
|
38eb3e489e | ||
|
|
97f7eaf499 | ||
|
|
d3356eea5c | ||
|
|
7a57bd73c3 | ||
|
|
b517c93190 | ||
|
|
7a9fded2e4 | ||
|
|
8ed2096de7 | ||
|
|
791a1eb130 | ||
|
|
9dab10ce19 | ||
|
|
fd95c2ced6 | ||
|
|
c32fef0eb9 | ||
|
|
c77b35c07b | ||
|
|
4303ea3584 | ||
|
|
ddb6f63ea7 | ||
|
|
06985a5b6c | ||
|
|
4841f209b3 | ||
|
|
7e6ed01dd2 | ||
|
|
b7e41894af | ||
|
|
5dfcfc32e7 | ||
|
|
fb74541796 | ||
|
|
2f7b29593e | ||
|
|
7ce6b1cfda | ||
|
|
7ad1d14d15 | ||
|
|
444c30e389 | ||
|
|
06fc31c33b | ||
|
|
4c58077cee | ||
|
|
25253942a6 | ||
|
|
4d75b47713 | ||
|
|
63c500c444 | ||
|
|
208c3fea35 | ||
|
|
3201b5921c | ||
|
|
e92a7825bf | ||
|
|
65b1fb2bae | ||
|
|
98df7e1eb8 | ||
|
|
86079af3b1 | ||
|
|
eeab0cf1b2 | ||
|
|
ac16b7ad0b | ||
|
|
e9b87d7acc | ||
|
|
b37893d9bb | ||
|
|
6f4ecdfbd9 | ||
|
|
697921b486 | ||
|
|
3c01d4aa8b | ||
|
|
a1eafdfbd8 | ||
|
|
2cfb171b38 | ||
|
|
2742e3d77b | ||
|
|
5488d8f633 | ||
|
|
35c7155983 | ||
|
|
b90a8a58fd | ||
|
|
85fa2011b2 | ||
|
|
063b05d964 | ||
|
|
ac90a0c0fb | ||
|
|
3efe33d2fb | ||
|
|
3e5ea97768 | ||
|
|
a970657312 | ||
|
|
240615c71b | ||
|
|
d3f4e205af | ||
|
|
cc63c239f6 | ||
|
|
4b82cae638 | ||
|
|
68c8d15ed4 | ||
|
|
021f5bb030 | ||
|
|
fc5d9a413d | ||
|
|
e09acb9208 | ||
|
|
2f57404c9c | ||
|
|
a29bdf0cf4 | ||
|
|
c29597689c | ||
|
|
797fbca6d4 | ||
|
|
6ed4b289d8 | ||
|
|
7dd07b2f5b | ||
|
|
b371fda0a5 | ||
|
|
3bdb11d804 | ||
|
|
199b777dcc | ||
|
|
70ccec2e82 | ||
|
|
a195624549 | ||
|
|
e417eba6bd | ||
|
|
210bb3e5c9 | ||
|
|
140ae354a1 | ||
|
|
2451b08306 | ||
|
|
04d33e772f | ||
|
|
3592fd8dae | ||
|
|
889e8d3b6e | ||
|
|
908fc67f96 | ||
|
|
c9a645285a | ||
|
|
3655724810 | ||
|
|
866047c116 | ||
|
|
8912d31bec | ||
|
|
1e65342814 | ||
|
|
c7ca352205 | ||
|
|
4b1ce8bc0b | ||
|
|
422e940bc7 | ||
|
|
76e2a2b8ca | ||
|
|
e3565bdc7d | ||
|
|
86f01cfaec | ||
|
|
6e4007adc0 | ||
|
|
8c6913c399 | ||
|
|
efdfd0db10 | ||
|
|
d6412eec58 | ||
|
|
53a6d2de83 | ||
|
|
7fe990e9f6 | ||
|
|
7b7ad0715b | ||
|
|
1a57d032b9 | ||
|
|
77bb169680 | ||
|
|
b424c19eee | ||
|
|
4d597069cf | ||
|
|
5afbdf7f20 | ||
|
|
33f558b221 | ||
|
|
b05d0dd1ec | ||
|
|
b2b305cc4b | ||
|
|
c5a9ee544c | ||
|
|
368d66f76e | ||
|
|
5aaae61b46 | ||
|
|
29fe50c2d7 | ||
|
|
d0c59ee253 | ||
|
|
d2e39238f4 | ||
|
|
6eace4258f | ||
|
|
4aec3f7466 | ||
|
|
c8991e07b9 | ||
|
|
48157db973 | ||
|
|
d070e5fce5 | ||
|
|
a8fae51ea8 | ||
|
|
2815d462be | ||
|
|
85f8ca9241 | ||
|
|
b5fb9e8c23 | ||
|
|
1addc002d3 | ||
|
|
e99e2660e9 | ||
|
|
03d1bb8bce | ||
|
|
5b00f7f2e8 | ||
|
|
97b7f0901e | ||
|
|
67b2671dad | ||
|
|
7886d49e65 | ||
|
|
e5284e9b43 | ||
|
|
c6403baa04 | ||
|
|
662b1ec696 | ||
|
|
9570e541d9 | ||
|
|
043df71185 | ||
|
|
8dab47f4da | ||
|
|
90d069df2b | ||
|
|
dcbe3ee650 | ||
|
|
e32489aba1 | ||
|
|
b619c0b793 | ||
|
|
fab61d14fa | ||
|
|
b4edc084f8 | ||
|
|
c7518d0c49 | ||
|
|
a40345c14d | ||
|
|
909471a5d7 | ||
|
|
38f7ea00c2 | ||
|
|
9f459f053e | ||
|
|
4195f3b8c6 | ||
|
|
4926824482 | ||
|
|
cb2f539cf7 | ||
|
|
7f31be7cb1 | ||
|
|
78b9c5b576 | ||
|
|
01e35efdbb | ||
|
|
bef1687b1f | ||
|
|
afa691376e | ||
|
|
be10bcf27a | ||
|
|
608cb86a4a | ||
|
|
88780ff0a9 | ||
|
|
a5e241afd7 | ||
|
|
28772d3254 | ||
|
|
d1f5c1eebc | ||
|
|
c77a282aaf | ||
|
|
7a1cd5c545 | ||
|
|
29ff54054e | ||
|
|
8e1bbe0132 | ||
|
|
a2b6585c0d | ||
|
|
aa452952a8 | ||
|
|
6ea4aa0a66 | ||
|
|
2462cd7b1d | ||
|
|
331e338c06 | ||
|
|
2b68f40872 | ||
|
|
2f7b3c306d | ||
|
|
eba5dbe654 | ||
|
|
9ae1f548bf | ||
|
|
d191255a84 | ||
|
|
9bf8824109 | ||
|
|
f773bd217c | ||
|
|
a5f0f0e3db | ||
|
|
6f6bfc667b | ||
|
|
0789f49b94 | ||
|
|
92c94eab8f | ||
|
|
9f06ed725e | ||
|
|
c45039fd70 | ||
|
|
8e203ec78e | ||
|
|
e32515e5cc | ||
|
|
2b77da821c | ||
|
|
f8404c7a97 | ||
|
|
156610ee07 | ||
|
|
fcaf672bf8 | ||
|
|
dd5d8fcdce | ||
|
|
e0c4f6455d | ||
|
|
dd5d7e9979 | ||
|
|
408baac91e | ||
|
|
f241142216 | ||
|
|
f0561844d8 | ||
|
|
bd6294b806 | ||
|
|
70f8e3a832 | ||
|
|
59b302acde | ||
|
|
f54f8dfec9 | ||
|
|
93135e7e81 | ||
|
|
b8026e19ba | ||
|
|
147d9282fb | ||
|
|
7c18b8bc5f | ||
|
|
2ccbf5d4e5 | ||
|
|
da6d8c86d1 | ||
|
|
78d997b404 | ||
|
|
89b23ef0d7 | ||
|
|
b958911c63 | ||
|
|
c6e5219f2e | ||
|
|
3bb450adbf | ||
|
|
a0f5257258 | ||
|
|
6520615bb0 | ||
|
|
4593212698 | ||
|
|
5363deb122 | ||
|
|
d5a651fc43 | ||
|
|
4740acbcc6 | ||
|
|
bfb2134329 | ||
|
|
ec83977fe1 | ||
|
|
98d08ff05d | ||
|
|
1eb6319b49 | ||
|
|
8f7e06f9d6 | ||
|
|
81e3abe10c | ||
|
|
edcee8934d | ||
|
|
d115d2ef47 | ||
|
|
d1dd725848 | ||
|
|
ebdba33082 | ||
|
|
918f6fbb8f | ||
|
|
28733ec592 | ||
|
|
916b9a399b | ||
|
|
3d62791477 | ||
|
|
64e6764015 | ||
|
|
cbed5c9cb1 | ||
|
|
0246d501e2 | ||
|
|
3d5b30ab9e | ||
|
|
4719578f10 | ||
|
|
fe370c7066 | ||
|
|
63d208bf20 | ||
|
|
5158540208 | ||
|
|
a69f7dc81a | ||
|
|
e848e161d4 | ||
|
|
3db61216e1 | ||
|
|
63b00186f4 | ||
|
|
110d4c478d | ||
|
|
49c29ded92 | ||
|
|
06670f2214 | ||
|
|
134bfec615 | ||
|
|
279326ffe1 | ||
|
|
ecb04e983e | ||
|
|
73b4c33f05 | ||
|
|
ad30f4dcbb | ||
|
|
0318587f80 | ||
|
|
2b6fddf26c | ||
|
|
da61da392b | ||
|
|
984b46ba07 | ||
|
|
1abce77b3a | ||
|
|
420606d8e8 | ||
|
|
80c8fd9794 | ||
|
|
1f479c3f20 | ||
|
|
0af89853d4 | ||
|
|
b5bb9c8ec3 | ||
|
|
ff13de9f75 | ||
|
|
47f40eb04b | ||
|
|
1ffc7ed6fb | ||
|
|
63710d5fae | ||
|
|
a2ef701d18 | ||
|
|
55e07536d9 | ||
|
|
af0a479f88 | ||
|
|
86a28d8cc1 | ||
|
|
3dd178a69d | ||
|
|
417334419a | ||
|
|
c03b3c2d34 | ||
|
|
e97d4a8e72 | ||
|
|
24d0af3104 | ||
|
|
5790e99359 | ||
|
|
0d6c2c9890 | ||
|
|
42220e057b | ||
|
|
c5df9c973f | ||
|
|
91509e7d36 | ||
|
|
b89aa9af0d | ||
|
|
4421b55613 | ||
|
|
75d9929483 | ||
|
|
7c78c2ef5d | ||
|
|
3758c86d20 | ||
|
|
ada547a79d | ||
|
|
445adcb47f | ||
|
|
4e9b975ca8 | ||
|
|
5d26066e02 | ||
|
|
de73d86684 | ||
|
|
d6244f090e | ||
|
|
1c44dc1052 | ||
|
|
4f7fbdc344 | ||
|
|
6fe49fbf8d | ||
|
|
c5f37e665b | ||
|
|
99180ba001 | ||
|
|
9377cf9128 | ||
|
|
e17d8ca302 | ||
|
|
acbaa1eec4 | ||
|
|
65b6ff6ecc | ||
|
|
df7aa30267 | ||
|
|
0f4aab926e | ||
|
|
7f3512d22c | ||
|
|
a6b5ed22b0 | ||
|
|
e843b31287 | ||
|
|
06a5aa45ba | ||
|
|
45a5eed62f | ||
|
|
188e27e931 | ||
|
|
f7a7f06c67 | ||
|
|
ed560ed489 | ||
|
|
186eb66f52 | ||
|
|
860f0d5846 | ||
|
|
4a7c2a96db | ||
|
|
0b09ada144 | ||
|
|
329baa1719 | ||
|
|
85080f5c58 | ||
|
|
910f02ea50 | ||
|
|
bfd8eefa0e | ||
|
|
2d96fcf87f | ||
|
|
8b566f06f0 | ||
|
|
28d174d9d8 | ||
|
|
dd892f746d | ||
|
|
95b1b8b19d | ||
|
|
298b73ddfc | ||
|
|
1a88651e4e | ||
|
|
229e43f20c | ||
|
|
4b9695ff50 | ||
|
|
a02b721944 | ||
|
|
f60a92d2c4 |
@@ -9,3 +9,8 @@ WebSite
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
*.xCodeSupport/
|
||||
*.XcodeSupport/
|
||||
*XcodeSupport/
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
install: ./bootstrap.sh --quiet --noprompt --directory ./narwhal
|
||||
script: jake test
|
||||
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
||||
+12
-2
@@ -20,7 +20,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPToolTip.j"
|
||||
@import "CALayer.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPAccordionView.j"
|
||||
@import "CPAlert.j"
|
||||
@import "CPAnimation.j"
|
||||
@import "CPApplication.j"
|
||||
@@ -35,18 +38,24 @@
|
||||
@import "CPCibBindingConnector.j"
|
||||
@import "CPCibConnector.j"
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibHelpConnector.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorSpace.j"
|
||||
@import "CPColorWell.j"
|
||||
@import "CPComboBox.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPController.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPDatePicker.j"
|
||||
@import "CPDocument.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPEvent.j"
|
||||
@@ -54,7 +63,7 @@
|
||||
@import "CPFlashView.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPFontManager.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPGradient.j"
|
||||
@import "CPGraphics.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@@ -66,6 +75,7 @@
|
||||
@import "CPOutlineView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopover.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPPredicateEditor.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
@@ -91,7 +101,6 @@
|
||||
@import "CPTokenField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "_CPToolTip.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPUserDefaultsController.j"
|
||||
@import "CPView.j"
|
||||
@@ -100,3 +109,4 @@
|
||||
@import "CPWebView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "CPWorkspace.j"
|
||||
|
||||
+15
-15
@@ -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;
|
||||
@@ -227,7 +227,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
|
||||
{
|
||||
var indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, _items.length)];
|
||||
|
||||
[indexSet removeIndexes:_expandedIndexes];
|
||||
[indexSet removeIndexes:_expandedItemIndexes];
|
||||
|
||||
return indexSet;
|
||||
}
|
||||
@@ -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)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+164
-113
@@ -28,15 +28,19 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
@class CPCheckBox
|
||||
|
||||
@global CPApp
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
@@ -53,6 +57,8 @@ CPInformationalAlertStyle = 1;
|
||||
*/
|
||||
CPCriticalAlertStyle = 2;
|
||||
|
||||
var bottomHeight = 71;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -75,32 +81,33 @@ CPCriticalAlertStyle = 2;
|
||||
representing the first button added to the alert which appears on the
|
||||
right, 1 representing the next button to the left and so on)
|
||||
*/
|
||||
@implementation CPAlert : CPView
|
||||
@implementation CPAlert : CPObject
|
||||
{
|
||||
BOOL _showHelp @accessors(property=showsHelp);
|
||||
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
||||
BOOL _showHelp @accessors(property=showsHelp);
|
||||
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
||||
|
||||
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
||||
CPString _title @accessors(property=title);
|
||||
CPView _accessoryView @accessors(property=accessoryView);
|
||||
CPImage _icon @accessors(property=icon);
|
||||
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
||||
CPString _title @accessors(property=title);
|
||||
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;
|
||||
id _delegate @accessors(property=delegate);
|
||||
id _modalDelegate;
|
||||
SEL _didEndSelector;
|
||||
|
||||
CPWindow _window @accessors(property=window,readonly);
|
||||
int _defaultWindowStyle;
|
||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||
CPWindow _window @accessors(property=window, readonly);
|
||||
int _defaultWindowStyle;
|
||||
|
||||
CPImageView _alertImageView;
|
||||
CPTextField _informativeLabel;
|
||||
CPTextField _messageLabel;
|
||||
CPButton _alertHelpButton;
|
||||
CPImageView _alertImageView;
|
||||
CPTextField _informativeLabel;
|
||||
CPTextField _messageLabel;
|
||||
CPButton _alertHelpButton;
|
||||
|
||||
BOOL _needsLayout;
|
||||
BOOL _needsLayout;
|
||||
}
|
||||
|
||||
#pragma mark Creating Alerts
|
||||
@@ -117,21 +124,21 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var newAlert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:aMessage];
|
||||
[alert addButtonWithTitle:defaultButtonTitle];
|
||||
[newAlert setMessageText:aMessage];
|
||||
[newAlert addButtonWithTitle:defaultButtonTitle];
|
||||
|
||||
if (alternateButtonTitle)
|
||||
[alert addButtonWithTitle:alternateButtonTitle];
|
||||
[newAlert addButtonWithTitle:alternateButtonTitle];
|
||||
|
||||
if (otherButtonTitle)
|
||||
[alert addButtonWithTitle:otherButtonTitle];
|
||||
[newAlert addButtonWithTitle:otherButtonTitle];
|
||||
|
||||
if (informativeText)
|
||||
[alert setInformativeText:informativeText];
|
||||
[newAlert setInformativeText:informativeText];
|
||||
|
||||
return alert;
|
||||
return newAlert;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -142,12 +149,12 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithError:(CPString)anErrorMessage
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var newAlert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:anErrorMessage];
|
||||
[alert setAlertStyle:CPCriticalAlertStyle];
|
||||
[newAlert setMessageText:anErrorMessage];
|
||||
[newAlert setAlertStyle:CPCriticalAlertStyle];
|
||||
|
||||
return alert;
|
||||
return newAlert;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -163,7 +170,8 @@ CPCriticalAlertStyle = 2;
|
||||
_alertStyle = CPWarningAlertStyle;
|
||||
_showHelp = NO;
|
||||
_needsLayout = YES;
|
||||
_defaultWindowStyle = CPTitledWindowMask;
|
||||
_defaultWindowStyle = _CPModalWindowMask;
|
||||
_themeView = [_CPAlertThemeView new];
|
||||
|
||||
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
||||
_alertImageView = [[CPImageView alloc] init];
|
||||
@@ -180,6 +188,11 @@ CPCriticalAlertStyle = 2;
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
- (CPTheme)theme
|
||||
{
|
||||
return [_themeView theme];
|
||||
}
|
||||
|
||||
/*!
|
||||
set the theme to use
|
||||
|
||||
@@ -197,9 +210,20 @@ CPCriticalAlertStyle = 2;
|
||||
|
||||
_window = nil; // will be regenerated at next layout
|
||||
_needsLayout = YES;
|
||||
[super setTheme:aTheme];
|
||||
[_themeView setTheme:aTheme];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName
|
||||
{
|
||||
[_themeView setValue:aValue forThemeAttribute:aName];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState
|
||||
{
|
||||
[_themeView setValue:aValue forThemeAttribute:aName inState:aState];
|
||||
}
|
||||
|
||||
|
||||
/*! @deprecated
|
||||
*/
|
||||
- (void)setWindowStyle:(int)aStyle
|
||||
@@ -334,16 +358,16 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
- (void)_layoutMessageView
|
||||
{
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
|
||||
sizeWithFontCorrection = 6.0,
|
||||
messageLabelWidth,
|
||||
messageLabelTextSize;
|
||||
|
||||
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
|
||||
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
|
||||
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
|
||||
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
|
||||
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
|
||||
[_messageLabel setTextColor:[_themeView currentValueForThemeAttribute:@"message-text-color"]];
|
||||
[_messageLabel setFont:[_themeView currentValueForThemeAttribute:@"message-text-font"]];
|
||||
[_messageLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"message-text-shadow-color"]];
|
||||
[_messageLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"message-text-shadow-offset"]];
|
||||
[_messageLabel setAlignment:[_themeView currentValueForThemeAttribute:@"message-text-alignment"]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
messageLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
|
||||
@@ -357,22 +381,22 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
- (void)_layoutInformativeView
|
||||
{
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
|
||||
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
sizeWithFontCorrection = 6.0,
|
||||
informativeLabelWidth,
|
||||
informativeLabelOriginY,
|
||||
informativeLabelTextSize;
|
||||
|
||||
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
|
||||
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
|
||||
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
|
||||
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
|
||||
[_informativeLabel setAlignment:[self currentValueForThemeAttribute:@"informative-text-alignment"]];
|
||||
[_informativeLabel setTextColor:[_themeView currentValueForThemeAttribute:@"informative-text-color"]];
|
||||
[_informativeLabel setFont:[_themeView currentValueForThemeAttribute:@"informative-text-font"]];
|
||||
[_informativeLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-color"]];
|
||||
[_informativeLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
|
||||
[_informativeLabel setAlignment:[_themeView currentValueForThemeAttribute:@"informative-text-alignment"]];
|
||||
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
|
||||
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin,
|
||||
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
|
||||
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin;
|
||||
informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
|
||||
|
||||
[_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
|
||||
@@ -386,8 +410,8 @@ CPCriticalAlertStyle = 2;
|
||||
if (!_accessoryView)
|
||||
return;
|
||||
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
|
||||
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
accessoryViewWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
|
||||
accessoryViewOriginY = CGRectGetMaxY([_informativeLabel frame]) + defaultElementsMargin;
|
||||
|
||||
@@ -403,16 +427,16 @@ CPCriticalAlertStyle = 2;
|
||||
if (!_showSuppressionButton)
|
||||
return;
|
||||
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
suppressionViewXOffset = [self currentValueForThemeAttribute:@"suppression-button-x-offset"],
|
||||
suppressionViewYOffset = [self currentValueForThemeAttribute:@"suppression-button-y-offset"],
|
||||
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
|
||||
suppressionViewXOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-x-offset"],
|
||||
suppressionViewYOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-y-offset"],
|
||||
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
suppressionButtonViewOriginY = CGRectGetMaxY([(_accessoryView || _informativeLabel) frame]) + defaultElementsMargin + suppressionViewYOffset;
|
||||
|
||||
[_suppressionButton setTextColor:[self currentValueForThemeAttribute:@"suppression-button-text-color"]];
|
||||
[_suppressionButton setFont:[self currentValueForThemeAttribute:@"suppression-button-text-font"]];
|
||||
[_suppressionButton setTextShadowColor:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
|
||||
[_suppressionButton setTextShadowOffset:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
|
||||
[_suppressionButton setTextColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-color"]];
|
||||
[_suppressionButton setFont:[_themeView currentValueForThemeAttribute:@"suppression-button-text-font"]];
|
||||
[_suppressionButton setTextShadowColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
|
||||
[_suppressionButton setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
|
||||
[_suppressionButton sizeToFit];
|
||||
|
||||
[_suppressionButton setFrameOrigin:CGPointMake(inset.left + suppressionViewXOffset, suppressionButtonViewOriginY)];
|
||||
@@ -424,14 +448,17 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
- (CGSize)_layoutButtonsFromView:(CPView)lastView
|
||||
{
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
minimumSize = [self currentValueForThemeAttribute:@"size"],
|
||||
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
|
||||
helpLeftOffset = [self currentValueForThemeAttribute:@"help-image-left-offset"],
|
||||
var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
|
||||
minimumSize = [_themeView currentValueForThemeAttribute:@"size"],
|
||||
buttonOffset = [_themeView currentValueForThemeAttribute:@"button-offset"],
|
||||
helpLeftOffset = [_themeView currentValueForThemeAttribute:@"help-image-left-offset"],
|
||||
aRepresentativeButton = [_buttons objectAtIndex:0],
|
||||
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
|
||||
panelSize = [[_window contentView] frame].size,
|
||||
buttonsOriginY,
|
||||
buttonMarginY,
|
||||
buttonMarginX,
|
||||
theme = [self theme],
|
||||
offsetX;
|
||||
|
||||
[aRepresentativeButton setTheme:[self theme]];
|
||||
@@ -444,6 +471,19 @@ CPCriticalAlertStyle = 2;
|
||||
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
|
||||
offsetX = panelSize.width - inset.right;
|
||||
|
||||
switch ([_window styleMask])
|
||||
{
|
||||
case _CPModalWindowMask:
|
||||
buttonMarginY = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-y"];
|
||||
buttonMarginX = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-x"];
|
||||
break;
|
||||
|
||||
default:
|
||||
buttonMarginY = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-y"];
|
||||
buttonMarginX = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-x"];
|
||||
break;
|
||||
}
|
||||
|
||||
for (var i = [_buttons count] - 1; i >= 0 ; i--)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
@@ -455,14 +495,14 @@ CPCriticalAlertStyle = 2;
|
||||
height = CGRectGetHeight(buttonFrame);
|
||||
|
||||
offsetX -= width;
|
||||
[button setFrame:CGRectMake(offsetX, buttonsOriginY, width, height)];
|
||||
[button setFrame:CGRectMake(offsetX + buttonMarginX, buttonsOriginY + buttonMarginY, width, height)];
|
||||
offsetX -= 10;
|
||||
}
|
||||
|
||||
if (_showHelp)
|
||||
{
|
||||
var helpImage = [self currentValueForThemeAttribute:@"help-image"],
|
||||
helpImagePressed = [self currentValueForThemeAttribute:@"help-image-pressed"],
|
||||
var helpImage = [_themeView currentValueForThemeAttribute:@"help-image"],
|
||||
helpImagePressed = [_themeView currentValueForThemeAttribute:@"help-image-pressed"],
|
||||
helpImageSize = helpImage ? [helpImage size] : CGSizeMakeZero(),
|
||||
helpFrame = CGRectMake(helpLeftOffset, buttonsOriginY, helpImageSize.width, helpImageSize.height);
|
||||
|
||||
@@ -487,7 +527,7 @@ CPCriticalAlertStyle = 2;
|
||||
if (!_window)
|
||||
[self _createWindowWithStyle:nil];
|
||||
|
||||
var iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
|
||||
var iconOffset = [_themeView currentValueForThemeAttribute:@"image-offset"],
|
||||
theImage = _icon,
|
||||
finalSize;
|
||||
|
||||
@@ -495,13 +535,13 @@ CPCriticalAlertStyle = 2;
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle:
|
||||
theImage = [self currentValueForThemeAttribute:@"warning-image"];
|
||||
theImage = [_themeView currentValueForThemeAttribute:@"warning-image"];
|
||||
break;
|
||||
case CPInformationalAlertStyle:
|
||||
theImage = [self currentValueForThemeAttribute:@"information-image"];
|
||||
theImage = [_themeView currentValueForThemeAttribute:@"information-image"];
|
||||
break;
|
||||
case CPCriticalAlertStyle:
|
||||
theImage = [self currentValueForThemeAttribute:@"error-image"];
|
||||
theImage = [_themeView currentValueForThemeAttribute:@"error-image"];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -519,7 +559,7 @@ CPCriticalAlertStyle = 2;
|
||||
if (_showSuppressionButton)
|
||||
lastView = _suppressionButton;
|
||||
else if (_accessoryView)
|
||||
lastView = _accessoryView
|
||||
lastView = _accessoryView;
|
||||
|
||||
finalSize = [self _layoutButtonsFromView:lastView];
|
||||
if ([_window styleMask] & CPDocModalWindowMask)
|
||||
@@ -528,6 +568,12 @@ CPCriticalAlertStyle = 2;
|
||||
[_window setFrameSize:finalSize];
|
||||
[_window center];
|
||||
|
||||
if ([_window styleMask] & _CPModalWindowMask || [_window styleMask] & CPHUDBackgroundWindowMask)
|
||||
{
|
||||
[_window setMovable:YES];
|
||||
[_window setMovableByWindowBackground:YES];
|
||||
}
|
||||
|
||||
_needsLayout = NO;
|
||||
}
|
||||
|
||||
@@ -592,9 +638,11 @@ CPCriticalAlertStyle = 2;
|
||||
- (void)_createWindowWithStyle:(int)forceStyle
|
||||
{
|
||||
var frame = CGRectMakeZero();
|
||||
frame.size = [self currentValueForThemeAttribute:@"size"];
|
||||
frame.size = [_themeView currentValueForThemeAttribute:@"size"];
|
||||
|
||||
_window = [[CPWindow alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
|
||||
_window = [[CPPanel alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
|
||||
[_window setLevel:CPStatusWindowLevel];
|
||||
[_window setPlatformWindow:[[CPApp keyWindow] platformWindow]];
|
||||
|
||||
if (_title)
|
||||
[_window setTitle:_title];
|
||||
@@ -631,7 +679,10 @@ CPCriticalAlertStyle = 2;
|
||||
- (@action)_takeReturnCodeFrom:(id)aSender
|
||||
{
|
||||
if ([_window isSheet])
|
||||
{
|
||||
[_window orderOut:nil];
|
||||
[CPApp endSheet:_window returnCode:[aSender tag]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[CPApp abortModal];
|
||||
@@ -646,17 +697,19 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
|
||||
_modalDelegate = nil;
|
||||
_didEndSelector = nil;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
}
|
||||
|
||||
#pragma mark Theme Attributes
|
||||
@end
|
||||
|
||||
@implementation _CPAlertThemeView : CPView
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
@@ -665,42 +718,40 @@ CPCriticalAlertStyle = 2;
|
||||
|
||||
+ (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
|
||||
]
|
||||
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"
|
||||
]];
|
||||
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
|
||||
|
||||
+22
-12
@@ -122,23 +122,30 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
||||
{
|
||||
var timingFunctionName;
|
||||
|
||||
switch (anAnimationCurve)
|
||||
{
|
||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
break;
|
||||
case CPAnimationEaseInOut:
|
||||
timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
break;
|
||||
|
||||
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
|
||||
break;
|
||||
case CPAnimationEaseIn:
|
||||
timingFunctionName = kCAMediaTimingFunctionEaseIn;
|
||||
break;
|
||||
|
||||
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
||||
break;
|
||||
case CPAnimationEaseOut:
|
||||
timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
||||
break;
|
||||
|
||||
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||
break;
|
||||
case CPAnimationLinear:
|
||||
timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||
break;
|
||||
|
||||
default: [CPException raise:CPInvalidArgumentException
|
||||
reason:"Invalid value provided for animation curve"];
|
||||
break;
|
||||
default:
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"Invalid value provided for animation curve"];
|
||||
break;
|
||||
}
|
||||
|
||||
_animationCurve = anAnimationCurve;
|
||||
@@ -307,6 +314,9 @@ ACTUAL_FRAME_RATE = 0;
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return t;
|
||||
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
@@ -321,7 +331,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
// currently used function to determine time
|
||||
// 1:1 conversion to js from webkit source files
|
||||
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
||||
var CubicBezierAtTime = function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration)
|
||||
var CubicBezierAtTime = function(t, p1x, p1y, p2x, p2y, duration)
|
||||
{
|
||||
var ax = 0,
|
||||
bx = 0,
|
||||
|
||||
+205
-94
@@ -23,17 +23,22 @@
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPEvent.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPThemeBlend.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
@import "CPWindowController.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
||||
CPEventModifierFlags = 0;
|
||||
|
||||
CPApp = nil;
|
||||
|
||||
@@ -81,8 +86,10 @@ CPRunContinuesResponse = -1002;
|
||||
@implementation CPApplication : CPResponder
|
||||
{
|
||||
CPArray _eventListeners;
|
||||
int _eventListenerInsertionIndex;
|
||||
|
||||
CPEvent _currentEvent;
|
||||
CPWindow _lastMouseMoveWindow;
|
||||
|
||||
CPArray _windows;
|
||||
CPWindow _keyWindow;
|
||||
@@ -137,10 +144,9 @@ CPRunContinuesResponse = -1002;
|
||||
if (self)
|
||||
{
|
||||
_eventListeners = [];
|
||||
_eventListenerInsertionIndex = 0;
|
||||
|
||||
_windows = [];
|
||||
|
||||
[_windows addObject:nil];
|
||||
_windows = [[CPNull null]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -219,28 +225,22 @@ CPRunContinuesResponse = -1002;
|
||||
// At this point we clear the window.status to eliminate Safari's "Cancelled" error message
|
||||
// The message shouldn't be displayed, because only an XHR is cancelled, but it is a usability issue.
|
||||
// We do it here so that applications can change it in willFinish or didFinishLaunching
|
||||
#if PLATFORM(DOM)
|
||||
window.status = " ";
|
||||
#endif
|
||||
|
||||
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
|
||||
[[CPCursor arrowCursor] set];
|
||||
|
||||
var bundle = [CPBundle mainBundle],
|
||||
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
||||
|
||||
if ([types count] > 0)
|
||||
_documentController = [CPDocumentController sharedDocumentController];
|
||||
|
||||
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
|
||||
delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
|
||||
|
||||
if (delegateClassName)
|
||||
{
|
||||
var delegateClass = objj_getClass(delegateClassName);
|
||||
|
||||
if (delegateClass)
|
||||
if ([_documentController class] == delegateClass)
|
||||
[self setDelegate:_documentController];
|
||||
else
|
||||
[self setDelegate:[[delegateClass alloc] init]];
|
||||
[self setDelegate:[[delegateClass alloc] init]];
|
||||
}
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
@@ -249,13 +249,23 @@ CPRunContinuesResponse = -1002;
|
||||
postNotificationName:CPApplicationWillFinishLaunchingNotification
|
||||
object:self];
|
||||
|
||||
var types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
||||
|
||||
if ([types count] > 0)
|
||||
_documentController = [CPDocumentController sharedDocumentController];
|
||||
|
||||
var needsUntitled = !!_documentController,
|
||||
URLStrings = window.cpOpeningURLStrings && window.cpOpeningURLStrings(),
|
||||
index = 0,
|
||||
URLStrings = nil;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
URLStrings = window.cpOpeningURLStrings && window.cpOpeningURLStrings();
|
||||
#endif
|
||||
|
||||
var index = 0,
|
||||
count = [URLStrings count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
needsUntitled = ![self _openURL:[CPURL URLWithString:URLStrings[index]]] || needsUntitled;
|
||||
needsUntitled = ![self _openURL:[CPURL URLWithString:URLStrings[index]]] && needsUntitled;
|
||||
|
||||
if (needsUntitled && [_delegate respondsToSelector:@selector(applicationShouldOpenUntitledFile:)])
|
||||
needsUntitled = [_delegate applicationShouldOpenUntitledFile:self];
|
||||
@@ -338,7 +348,7 @@ CPRunContinuesResponse = -1002;
|
||||
Copyright - Human readable copyright information.
|
||||
</pre>
|
||||
|
||||
If you choose not the include any of the above keys, they will default
|
||||
If you choose not the include any of the above keys, they will default
|
||||
to the following respective keys in your info.plist file.
|
||||
|
||||
<pre>
|
||||
@@ -362,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:14.0]];
|
||||
[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)]];
|
||||
@@ -391,7 +411,7 @@ CPRunContinuesResponse = -1002;
|
||||
else
|
||||
[versionLabel setStringValue:@""];
|
||||
|
||||
[copyrightLabel setStringValue:copyright || ""];
|
||||
[copyrightLabel setStringValue:copyright || @""];
|
||||
[aboutPanel center];
|
||||
|
||||
_aboutPanel = aboutPanel;
|
||||
@@ -401,7 +421,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
|
||||
- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
||||
- (void)_documentController:(CPDocumentController)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
||||
{
|
||||
// callback method for terminate:
|
||||
if (didCloseAll)
|
||||
@@ -500,6 +520,8 @@ CPRunContinuesResponse = -1002;
|
||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||
{
|
||||
_eventListeners.splice(count, 1);
|
||||
if (count <= _eventListenerInsertionIndex)
|
||||
_eventListenerInsertionIndex--;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -547,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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -576,38 +598,76 @@ CPRunContinuesResponse = -1002;
|
||||
- (void)sendEvent:(CPEvent)anEvent
|
||||
{
|
||||
_currentEvent = anEvent;
|
||||
CPEventModifierFlags = [anEvent modifierFlags];
|
||||
|
||||
var willPropagate = [[[anEvent window] platformWindow] _willPropagateCurrentDOMEvent];
|
||||
var theWindow = [anEvent window];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var willPropagate = [[theWindow platformWindow] _willPropagateCurrentDOMEvent];
|
||||
|
||||
// temporarily pretend we won't propagate the event. we'll restore the saved value later
|
||||
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
#endif
|
||||
|
||||
// Check if this is a candidate for key equivalent...
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var characters = [anEvent characters],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Unconditionally propagate on these keys to solve browser copy paste bugs
|
||||
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// if we make it this far, then restore the original willPropagate value
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
||||
[[theWindow platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
||||
#endif
|
||||
|
||||
if (_eventListeners.length)
|
||||
if ([anEvent type] == CPMouseMoved)
|
||||
{
|
||||
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
|
||||
_eventListeners.pop()._callback(anEvent);
|
||||
if (theWindow !== _lastMouseMoveWindow)
|
||||
[_lastMouseMoveWindow _mouseExitedResizeRect];
|
||||
|
||||
return;
|
||||
_lastMouseMoveWindow = theWindow;
|
||||
}
|
||||
|
||||
[[anEvent window] sendEvent:anEvent];
|
||||
/*
|
||||
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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -643,6 +703,10 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (CPWindow)windowWithWindowNumber:(int)aWindowNumber
|
||||
{
|
||||
// Never allow _windows[0] to be returned - it's an internal CPNull placeholder.
|
||||
if (!aWindowNumber)
|
||||
return nil;
|
||||
|
||||
return _windows[aWindowNumber];
|
||||
}
|
||||
|
||||
@@ -651,7 +715,8 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (CPArray)windows
|
||||
{
|
||||
return _windows;
|
||||
// Return all windows, but not the CPNull placeholder in _windows[0].
|
||||
return [_windows subarrayWithRange:CPMakeRange(1, [_windows count] - 1)];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -879,31 +944,44 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
/*!
|
||||
Fires a callback function when an event matching a given mask occurs.
|
||||
@param aCallback - A js function to be fired.
|
||||
@prarm aMask - An event mask for the next event.
|
||||
@param anExpiration - The date for which this callback expires (not implemented).
|
||||
|
||||
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).
|
||||
@param inMode (not implemented).
|
||||
@param shouldDequeue (not implemented).
|
||||
@param shouldDequeue YES to remove the event from the queue after calling the callback,
|
||||
NO to deliver it normally.
|
||||
*/
|
||||
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
{
|
||||
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, aCallback, shouldDequeue));
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns a target and action for the next event matching a given event mask.
|
||||
The callback method called will be passed the CPEvent when it fires.
|
||||
|
||||
@param aTarget - The target object for the callback.
|
||||
@param aSelector - The selector which should be called on the target object.
|
||||
@param aMask - The mask for a given event which should trigger the callback.
|
||||
@param anExpiration - The date for which the callback expires (not implemented).
|
||||
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.
|
||||
@param anExpiration The date for which the callback expires (not implemented).
|
||||
@param aMode (not implemented).
|
||||
@param shouldDequeue (not implemented).
|
||||
@param shouldDequeue YES to remove the event from the queue after calling the callback,
|
||||
NO to deliver it normally.
|
||||
*/
|
||||
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
{
|
||||
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -921,21 +999,19 @@ 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
|
||||
{
|
||||
var styleMask = [aSheet styleMask];
|
||||
if (!(styleMask & CPDocModalWindowMask))
|
||||
if ([aWindow isSheet])
|
||||
{
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"The target window of beginSheet: cannot be a sheet"];
|
||||
return;
|
||||
}
|
||||
|
||||
[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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -960,10 +1036,10 @@ 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 _detachSheetWindow];
|
||||
[aWindow _endSheet];
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -996,14 +1072,15 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (CPArray)arguments
|
||||
{
|
||||
if (_fullArgsString !== window.location.hash)
|
||||
// FIXME This should probably not access the window object #if !PLATFORM(DOM), but the unit tests rely on it.
|
||||
if (window && window.location && _fullArgsString !== window.location.hash)
|
||||
[self _reloadArguments];
|
||||
|
||||
return _args;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the arguments of your application.
|
||||
Sets the arguments of your application.
|
||||
That is, set the slash seperated values of an array as the window location hash.
|
||||
|
||||
For example if you pass an array:
|
||||
@@ -1023,8 +1100,9 @@ CPRunContinuesResponse = -1002;
|
||||
if (!args || args.length == 0)
|
||||
{
|
||||
_args = [];
|
||||
window.location.hash = @"#";
|
||||
|
||||
// Don't use if PLATFORM(DOM) here - the unit test fakes window.location so we should play along.
|
||||
if (window && window.location)
|
||||
window.location.hash = @"#";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1039,12 +1117,15 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
var hash = [toEncode componentsJoinedByString:@"/"];
|
||||
|
||||
window.location.hash = @"#" + hash;
|
||||
// Don't use if PLATFORM(DOM) here - the unit test fakes window.location so we should play along.
|
||||
if (window && window.location)
|
||||
window.location.hash = @"#" + hash;
|
||||
}
|
||||
|
||||
- (void)_reloadArguments
|
||||
{
|
||||
_fullArgsString = window.location.hash;
|
||||
// FIXME This should probably not access the window object #if !PLATFORM(DOM), but the unit tests rely on it.
|
||||
_fullArgsString = (window && window.location) ? window.location.hash : "";
|
||||
|
||||
if (_fullArgsString.length)
|
||||
{
|
||||
@@ -1158,7 +1239,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo2");
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1166,24 +1247,32 @@ CPRunContinuesResponse = -1002;
|
||||
var _CPModalSessionMake = function(aWindow, aStopCode)
|
||||
{
|
||||
return { _window:aWindow, _state:CPRunContinuesResponse , _previous:nil };
|
||||
}
|
||||
};
|
||||
|
||||
var _CPEventListenerMake = function(anEventMask, aCallback)
|
||||
var _CPEventListenerMake = function(anEventMask, aCallback, shouldDequeue)
|
||||
{
|
||||
return { _mask:anEventMask, _callback:aCallback };
|
||||
}
|
||||
return { _mask:anEventMask, _callback:aCallback, _dequeue:shouldDequeue };
|
||||
};
|
||||
|
||||
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||
_CPRunModalLoop = function(anEvent)
|
||||
{
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:YES];
|
||||
|
||||
var theWindow = [anEvent window],
|
||||
modalSession = CPApp._currentSession;
|
||||
|
||||
if (theWindow == modalSession._window || [theWindow worksWhenModal])
|
||||
/*
|
||||
The special case for popovers here is not clear. In Cocoa the popover window does not respond YES to worksWhenModal, yet it works when there is a modal window. Maybe it starts its own modal session, but interaction with the original modal window seems to continue working as well. Regardless of correctness, this solution beats popovers not working at all from sheets.
|
||||
*/
|
||||
if (theWindow == modalSession._window ||
|
||||
[theWindow worksWhenModal] ||
|
||||
[theWindow attachedSheet] == modalSession._window || // -dw- allow modal parent of sheet to be repositioned
|
||||
([theWindow isKindOfClass:_CPPopoverWindow] && [[theWindow targetView] window] === modalSession._window))
|
||||
{
|
||||
[theWindow sendEvent:anEvent];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
Starts the GUI and Cappuccino frameworks. This function should be
|
||||
@@ -1198,7 +1287,17 @@ function CPApplicationMain(args, namedArgs)
|
||||
#if PLATFORM(DOM)
|
||||
// hook to allow recorder, etc to manipulate things before starting AppKit
|
||||
if (window.parent !== window && typeof window.parent._childAppIsStarting === "function")
|
||||
window.parent._childAppIsStarting(window);
|
||||
{
|
||||
try
|
||||
{
|
||||
window.parent._childAppIsStarting(window);
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
// This could happen if we're in an iframe without access to the parent frame.
|
||||
CPLog.warn("Failed to call parent frame's _childAppIsStarting().");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
var mainBundle = [CPBundle mainBundle],
|
||||
@@ -1255,7 +1354,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
|
||||
if (defaultThemeName === @"Aristo")
|
||||
if (defaultThemeName === @"Aristo" || defaultThemeName === @"Aristo2")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
@@ -1282,7 +1381,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
if (mainCibFile)
|
||||
{
|
||||
[mainBundle loadCibFile:mainCibFile
|
||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
||||
externalNameTable:@{ CPCibOwner: CPApp }
|
||||
loadDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1300,26 +1399,25 @@ var _CPAppBootstrapperActions = nil;
|
||||
// FIXME: We should implement autoenabling.
|
||||
[mainMenu setAutoenablesItems:NO];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
||||
var newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
||||
|
||||
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[newMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-new" forClass:_CPMenuView]];
|
||||
[newMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-new" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||
|
||||
[mainMenu addItem:newMenuItem];
|
||||
|
||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
|
||||
|
||||
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[openMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-open" forClass:_CPMenuView]];
|
||||
[openMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-open" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||
|
||||
[mainMenu addItem:openMenuItem];
|
||||
|
||||
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
||||
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
||||
|
||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[saveMenuItem setImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-save" forClass:_CPMenuView]];
|
||||
[saveMenuItem setAlternateImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-general-icon-save" inState:CPThemeStateHighlighted forClass:_CPMenuView]];
|
||||
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
||||
@@ -1340,8 +1438,8 @@ var _CPAppBootstrapperActions = nil;
|
||||
[editMenu addItem:undoMenuItem];
|
||||
[editMenu addItem:redoMenuItem];
|
||||
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]];
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]];
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
|
||||
|
||||
[editMenuItem setSubmenu:editMenu];
|
||||
@@ -1370,3 +1468,16 @@ var _CPAppBootstrapperActions = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPEvent (CPApplicationModifierFlags)
|
||||
|
||||
/*!
|
||||
Returns the currently pressed modifier flags.
|
||||
*/
|
||||
+ (unsigned)modifierFlags
|
||||
{
|
||||
return CPEventModifierFlags;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+141
-58
@@ -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"];
|
||||
}
|
||||
|
||||
|
||||
@@ -564,8 +564,9 @@
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
[self __setSelectionIndexes:indexes];
|
||||
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -574,7 +575,7 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||
{
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
return [self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -583,28 +584,43 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if (!indexes)
|
||||
indexes = [CPIndexSet indexSet];
|
||||
return [self __setSelectionIndexes:indexes avoidEmpty:_avoidsEmptySelection];
|
||||
}
|
||||
|
||||
if (![indexes count])
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes avoidEmpty:(BOOL)avoidEmpty
|
||||
{
|
||||
var newIndexes = indexes;
|
||||
|
||||
if (!newIndexes)
|
||||
newIndexes = [CPIndexSet indexSet];
|
||||
|
||||
if (![newIndexes count])
|
||||
{
|
||||
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||
if (avoidEmpty && [[self arrangedObjects] count])
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectsCount = [[self arrangedObjects] count];
|
||||
|
||||
// Don't trash the input - the caller might depend on it or we might have been
|
||||
// given _selectionIndexes as the input in which case the equality test below
|
||||
// would always succeed despite our change below.
|
||||
newIndexes = [newIndexes copy];
|
||||
|
||||
// Remove out of bounds indexes.
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||
[newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
|
||||
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
|
||||
if (![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
if (![newIndexes count] && avoidEmpty && objectsCount)
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
if ([_selectionIndexes isEqualToIndexSet:newIndexes])
|
||||
return NO;
|
||||
|
||||
_selectionIndexes = [indexes copy];
|
||||
// If we haven't already created our own index instance, make sure to copy it here so that
|
||||
// the copy the user sent in is decoupled from our internal copy.
|
||||
_selectionIndexes = indexes === newIndexes ? [indexes copy] : newIndexes;
|
||||
|
||||
// Push back the new selection to the model for selectionIndexes if we have one.
|
||||
// There won't be an infinite loop because of the equality check above.
|
||||
@@ -636,10 +652,11 @@
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
|
||||
[self __setSelectedObjects:objects];
|
||||
var r = [self __setSelectedObjects:objects avoidEmpty:NO];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -647,6 +664,11 @@
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)__setSelectedObjects:(CPArray)objects
|
||||
{
|
||||
[self __setSelectedObjects:objects avoidEmpty:_avoidsEmptySelection];
|
||||
}
|
||||
|
||||
- (BOOL)__setSelectedObjects:(CPArray)objects avoidEmpty:(BOOL)avoidEmpty
|
||||
{
|
||||
var set = [CPIndexSet indexSet],
|
||||
count = [objects count],
|
||||
@@ -660,7 +682,7 @@
|
||||
[set addIndex:index];
|
||||
}
|
||||
|
||||
[self __setSelectionIndexes:set];
|
||||
[self __setSelectionIndexes:set avoidEmpty:avoidEmpty];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -722,6 +744,7 @@
|
||||
return;
|
||||
|
||||
var willClearPredicate = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
@@ -770,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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -789,6 +820,7 @@
|
||||
return;
|
||||
|
||||
var willClearPredicate = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
@@ -826,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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -857,6 +895,9 @@
|
||||
|
||||
[_arrangedObjects removeObjectAtIndex:pos];
|
||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
|
||||
|
||||
// This will automatically handle the avoidsEmptySelection case.
|
||||
[self __setSelectionIndexes:_selectionIndexes];
|
||||
}
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
@@ -872,7 +913,9 @@
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
[self insert:sender];
|
||||
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
||||
|
||||
[self addObject:newObject];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -884,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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -898,6 +945,15 @@
|
||||
[self removeObjectsAtArrangedObjectIndexes:_selectionIndexes];
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes the object at the specified index in the controller's arranged objects from the content array.
|
||||
@param int index - index of the object to remove.
|
||||
*/
|
||||
- (void)removeObjectAtArrangedObjectIndex:(int)index
|
||||
{
|
||||
[self removeObjectsAtArrangedObjectIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes the objects at the specified indexes in the controller's arranged objects from the content array.
|
||||
@param CPIndexSet indexes - indexes of the objects to remove.
|
||||
@@ -912,36 +968,38 @@
|
||||
_disableSetContent = YES;
|
||||
|
||||
var arrangedObjects = [self arrangedObjects],
|
||||
index = [anIndexSet lastIndex],
|
||||
position = CPNotFound,
|
||||
newSelectionIndexes = [_selectionIndexes copy];
|
||||
|
||||
while (index !== CPNotFound)
|
||||
{
|
||||
var object = [arrangedObjects objectAtIndex:index];
|
||||
|
||||
// First try the simple case which should work if there are no sort descriptors.
|
||||
if ([_contentObject objectAtIndex:index] === object)
|
||||
[_contentObject removeObjectAtIndex:index];
|
||||
else
|
||||
[anIndexSet enumerateIndexesWithOptions:CPEnumerationReverse
|
||||
usingBlock:function(anIndex)
|
||||
{
|
||||
// Since we don't have a reverse mapping between the sorted order and the
|
||||
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
|
||||
// be the 'wrong' one - as in not the one the user selected - but the wrong
|
||||
// one is still just another pointer to the same object, so the user will not
|
||||
// be able to see any difference.
|
||||
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
|
||||
[_contentObject removeObjectAtIndex:contentIndex];
|
||||
}
|
||||
[arrangedObjects removeObjectAtIndex:index];
|
||||
var object = [arrangedObjects objectAtIndex:anIndex];
|
||||
|
||||
// Deselect this row if it was selected, and either way shift all selection indexes
|
||||
// following it up by 1.
|
||||
[newSelectionIndexes removeIndex:index];
|
||||
[newSelectionIndexes shiftIndexesStartingAtIndex:index by:-1];
|
||||
// First try the simple case which should work if there are no sort descriptors.
|
||||
if ([_contentObject objectAtIndex:anIndex] === object)
|
||||
[_contentObject removeObjectAtIndex:anIndex];
|
||||
else
|
||||
{
|
||||
// Since we don't have a reverse mapping between the sorted order and the
|
||||
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
|
||||
// be the 'wrong' one - as in not the one the user selected - but the wrong
|
||||
// one is still just another pointer to the same object, so the user will not
|
||||
// be able to see any difference.
|
||||
var contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
|
||||
[_contentObject removeObjectAtIndex:contentIndex];
|
||||
}
|
||||
[arrangedObjects removeObjectAtIndex:anIndex];
|
||||
|
||||
if (!_avoidsEmptySelection || [newSelectionIndexes count] > 1)
|
||||
{
|
||||
[newSelectionIndexes removeIndex:anIndex];
|
||||
[newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
|
||||
}
|
||||
else if ([newSelectionIndexes lastIndex] !== anIndex)
|
||||
[newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
|
||||
}];
|
||||
|
||||
index = [anIndexSet indexLessThanIndex:index];
|
||||
}
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
_disableSetContent = NO;
|
||||
@@ -1037,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
|
||||
@@ -1054,22 +1112,47 @@
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
isCompound = [self handlesContentAsCompoundValue];
|
||||
isCompound = [self handlesContentAsCompoundValue],
|
||||
dotIndex = keyPath.lastIndexOf("."),
|
||||
firstPart = dotIndex !== CPNotFound ? keyPath.substring(0, dotIndex) : nil,
|
||||
isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy],
|
||||
newValue;
|
||||
|
||||
if (!isCompound)
|
||||
if (!isCompound && !isSelectionProxy)
|
||||
{
|
||||
newValue = [destination mutableArrayValueForKeyPath:keyPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
// handlesContentAsCompoundValue == YES so we cannot just set up a proxy.
|
||||
// 1. If handlesContentAsCompoundValue we cannot just set up a proxy.
|
||||
// Every read and every write must go through transformValue and
|
||||
// reverseTransformValue, and the resulting object cannot be described by
|
||||
// a key path.
|
||||
|
||||
// 2. If isSelectionProxy, we don't want to proxy a proxy - that's bad
|
||||
// for performance and won't work with markers.
|
||||
|
||||
newValue = [destination valueForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
var isPlaceholder = CPIsControllerMarker(newValue);
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
|
||||
// This seems to be what Cocoa does.
|
||||
if (!newValue)
|
||||
newValue = [CPMutableArray array];
|
||||
}
|
||||
else
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
|
||||
if (isCompound)
|
||||
{
|
||||
|
||||
+92
-6
@@ -20,7 +20,6 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* Copyright 2009 280 North, Inc.
|
||||
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@@ -49,6 +48,8 @@ var DefaultLineWidth = 1.0;
|
||||
{
|
||||
CGPath _path;
|
||||
float _lineWidth;
|
||||
CPArray _lineDashes;
|
||||
float _lineDashesPhase;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -62,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;
|
||||
}
|
||||
@@ -74,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;
|
||||
}
|
||||
@@ -166,6 +176,19 @@ var DefaultLineWidth = 1.0;
|
||||
CGPathAddCurveToPoint(_path, nil, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
|
||||
}
|
||||
|
||||
- (CGRect)bounds
|
||||
{
|
||||
// TODO: this should return this. The controlPointBounds is not a tight fit.
|
||||
// return CGPathGetBoundingBox(_path);
|
||||
|
||||
return [self controlPointBounds];
|
||||
}
|
||||
|
||||
- (CGRect)controlPointBounds
|
||||
{
|
||||
return CGPathGetBoundingBox(_path);
|
||||
}
|
||||
|
||||
/*!
|
||||
Create a line segment between the first and last points in the subpath, closing it.
|
||||
*/
|
||||
@@ -184,6 +207,7 @@ var DefaultLineWidth = 1.0;
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextSetLineDash(ctx, _lineDashesPhase, _lineDashes);
|
||||
CGContextStrokePath(ctx);
|
||||
}
|
||||
|
||||
@@ -197,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.
|
||||
*/
|
||||
@@ -273,10 +337,15 @@ var DefaultLineWidth = 1.0;
|
||||
CGPathAddPath(_path, nil, CGPathWithRoundedRectangleInRect(rect, xRadius, yRadius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
- (void)appendBezierPathWithArcFromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint radius:(float)radius
|
||||
{
|
||||
CGPathAddArcToPoint(_path, null, fromPoint.x, fromPoint.y, toPoint.x, toPoint.y, radius);
|
||||
}
|
||||
|
||||
/*!
|
||||
Append the contents of a CPBezierPath object.
|
||||
*/
|
||||
- (void)appendBezierPath:(NSBezierPath *)other
|
||||
- (void)appendBezierPath:(CPBezierPath)other
|
||||
{
|
||||
CGPathAddPath(_path, nil, other._path);
|
||||
}
|
||||
@@ -289,4 +358,21 @@ var DefaultLineWidth = 1.0;
|
||||
_path = CGPathCreateMutable();
|
||||
}
|
||||
|
||||
- (void)addClip
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextClip(ctx);
|
||||
}
|
||||
|
||||
- (void)setClip
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextClip(ctx);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+296
-93
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPTextField.j"
|
||||
@import "CPView.j"
|
||||
|
||||
// CPBoxType
|
||||
@@ -35,6 +36,16 @@ CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
// CPTitlePosition
|
||||
CPNoTitle = 0;
|
||||
CPAboveTop = 1;
|
||||
CPAtTop = 2;
|
||||
CPBelowTop = 3;
|
||||
CPAboveBottom = 4;
|
||||
CPAtBottom = 5;
|
||||
CPBelowBottom = 6;
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBox
|
||||
@@ -45,15 +56,38 @@ CPGrooveBorder = 3;
|
||||
{
|
||||
CPBoxType _boxType;
|
||||
CPBorderType _borderType;
|
||||
|
||||
CPColor _borderColor;
|
||||
CPColor _fillColor;
|
||||
|
||||
float _cornerRadius;
|
||||
float _borderWidth;
|
||||
|
||||
CPSize _contentMargin;
|
||||
CPView _contentView;
|
||||
|
||||
CPString _title @accessors(getter=title);
|
||||
int _titlePosition @accessors(getter=titlePosition);
|
||||
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
|
||||
@@ -61,6 +95,7 @@ CPGrooveBorder = 3;
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[box setAutoresizingMask:[aView autoresizingMask]];
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
@@ -70,18 +105,16 @@ CPGrooveBorder = 3;
|
||||
return box;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect
|
||||
- (id)initWithFrame:(CGRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_borderType = CPBezelBorder;
|
||||
_fillColor = [CPColor clearColor];
|
||||
_borderColor = [CPColor blackColor];
|
||||
|
||||
_borderWidth = 1.0;
|
||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||
_titlePosition = CPNoTitle;
|
||||
_titleView = [CPTextField labelWithTitle:@""];
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
@@ -100,7 +133,7 @@ CPGrooveBorder = 3;
|
||||
|
||||
@return the border rectangle of the box
|
||||
*/
|
||||
- (CPRect)borderRect
|
||||
- (CGRect)borderRect
|
||||
{
|
||||
return [self bounds];
|
||||
}
|
||||
@@ -190,58 +223,54 @@ CPGrooveBorder = 3;
|
||||
|
||||
- (CPColor)borderColor
|
||||
{
|
||||
return _borderColor;
|
||||
return [self valueForThemeAttribute:@"border-color"];
|
||||
}
|
||||
|
||||
- (void)setBorderColor:(CPColor)color
|
||||
{
|
||||
if ([color isEqual:_borderColor])
|
||||
if ([color isEqual:[self borderColor]])
|
||||
return;
|
||||
|
||||
_borderColor = color;
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:color forThemeAttribute:@"border-color"];
|
||||
}
|
||||
|
||||
- (float)borderWidth
|
||||
{
|
||||
return _borderWidth;
|
||||
return [self valueForThemeAttribute:@"border-width"];
|
||||
}
|
||||
|
||||
- (void)setBorderWidth:(float)width
|
||||
{
|
||||
if (width === _borderWidth)
|
||||
if (width === [self borderWidth])
|
||||
return;
|
||||
|
||||
_borderWidth = width;
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:width forThemeAttribute:@"border-width"];
|
||||
}
|
||||
|
||||
- (float)cornerRadius
|
||||
{
|
||||
return _cornerRadius;
|
||||
return [self valueForThemeAttribute:@"corner-radius"];
|
||||
}
|
||||
|
||||
- (void)setCornerRadius:(float)radius
|
||||
{
|
||||
if (radius === _cornerRadius)
|
||||
if (radius === [self cornerRadius])
|
||||
return;
|
||||
|
||||
_cornerRadius = radius;
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:radius forThemeAttribute:@"corner-radius"];
|
||||
}
|
||||
|
||||
- (CPColor)fillColor
|
||||
{
|
||||
return _fillColor;
|
||||
return [self valueForThemeAttribute:@"background-color"];
|
||||
}
|
||||
|
||||
- (void)setFillColor:(CPColor)color
|
||||
{
|
||||
if ([color isEqual:_fillColor])
|
||||
if ([color isEqual:[self fillColor]])
|
||||
return;
|
||||
|
||||
_fillColor = color;
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:color forThemeAttribute:@"background-color"];
|
||||
}
|
||||
|
||||
- (CPView)contentView
|
||||
@@ -254,48 +283,160 @@ CPGrooveBorder = 3;
|
||||
if (aView === _contentView)
|
||||
return;
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||
var borderWidth = [self borderWidth],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
- (CPSize)contentViewMargins
|
||||
- (CGSize)contentViewMargins
|
||||
{
|
||||
return _contentMargin;
|
||||
return [self valueForThemeAttribute:@"content-margin"];
|
||||
}
|
||||
|
||||
- (void)setContentViewMargins:(CPSize)size
|
||||
- (void)setContentViewMargins:(CGSize)size
|
||||
{
|
||||
if (size.width < 0 || size.height < 0)
|
||||
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
||||
|
||||
_contentMargin = CGSizeMakeCopy(size);
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:CGSizeMakeCopy(size) forThemeAttribute:@"content-margin"];
|
||||
}
|
||||
|
||||
- (void)setFrameFromContentFrame:(CPRect)aRect
|
||||
- (void)setFrameFromContentFrame:(CGRect)aRect
|
||||
{
|
||||
[self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + _borderWidth))];
|
||||
var offset = [self _titleHeightOffset],
|
||||
borderWidth = [self borderWidth],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
|
||||
[self setFrame:CGRectInset(aRect, -(contentMargin.width + borderWidth), -(contentMargin.height + offset[0] + borderWidth))];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
if (aTitle == _title)
|
||||
return;
|
||||
|
||||
_title = aTitle;
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
- (void)setTitlePosition:(int)aTitlePotisition
|
||||
{
|
||||
if (aTitlePotisition == _titlePosition)
|
||||
return;
|
||||
|
||||
_titlePosition = aTitlePotisition;
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
- (CPFont)titleFont
|
||||
{
|
||||
return [_titleView font];
|
||||
}
|
||||
|
||||
- (void)setTitleFont:(CPFont)aFont
|
||||
{
|
||||
[_titleView setFont:aFont];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the text field used to display the receiver's title.
|
||||
|
||||
This is the Cappuccino equivalent to the `titleCell` method.
|
||||
*/
|
||||
- (CPTextField)titleView
|
||||
{
|
||||
return _titleView;
|
||||
}
|
||||
|
||||
- (void)_manageTitlePositioning
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
{
|
||||
[_titleView removeFromSuperview];
|
||||
[self setNeedsDisplay:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[_titleView setStringValue:_title];
|
||||
[_titleView sizeToFit];
|
||||
[self addSubview:_titleView];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
case CPAboveTop:
|
||||
case CPBelowTop:
|
||||
[_titleView setFrameOrigin:CGPointMake(5.0, 0.0)];
|
||||
[_titleView setAutoresizingMask:CPViewNotSizable];
|
||||
break;
|
||||
|
||||
case CPAboveBottom:
|
||||
case CPAtBottom:
|
||||
case CPBelowBottom:
|
||||
var h = [_titleView frameSize].height;
|
||||
[_titleView setFrameOrigin:CGPointMake(5.0, [self frameSize].height - h)];
|
||||
[_titleView setAutoresizingMask:CPViewMinYMargin];
|
||||
break;
|
||||
}
|
||||
|
||||
[self sizeToFit];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame];
|
||||
var contentFrame = [_contentView frame],
|
||||
offset = [self _titleHeightOffset],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
contentFrame.size.height + _contentMargin.height * 2)];
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
if (_borderType === CPNoBorder)
|
||||
if (!contentFrame)
|
||||
return;
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(contentMargin.width, contentMargin.height + offset[1])];
|
||||
}
|
||||
|
||||
- (float)_titleHeightOffset
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
return [0.0, 0.0];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
return [[_titleView frameSize].height, [_titleView frameSize].height];
|
||||
|
||||
case CPAtBottom:
|
||||
return [[_titleView frameSize].height, 0.0];
|
||||
|
||||
default:
|
||||
return [0.0, 0.0];
|
||||
}
|
||||
}
|
||||
|
||||
- (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 = [self bounds];
|
||||
|
||||
switch (_boxType)
|
||||
@@ -304,88 +445,157 @@ CPGrooveBorder = 3;
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (_titlePosition == CPAtTop)
|
||||
{
|
||||
bounds.origin.y += [_titleView frameSize].height;
|
||||
bounds.size.height -= [_titleView frameSize].height;
|
||||
}
|
||||
if (_titlePosition == CPAtBottom)
|
||||
{
|
||||
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:
|
||||
[self _drawBezelBorderInRect:bounds];
|
||||
break;
|
||||
|
||||
default:
|
||||
case CPGrooveBorder:
|
||||
case CPLineBorder:
|
||||
[self _drawLineBorderInRect:bounds];
|
||||
break;
|
||||
|
||||
case CPNoBorder:
|
||||
[self _drawNoBorderInRect:bounds];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
|
||||
- (void)_drawHorizontalSeparatorInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
CGContextSetLineWidth(context, 1.0);
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect) + 0.5);
|
||||
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect) + 0.5);
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMidY(aRect));
|
||||
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMidY(aRect));
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
|
||||
- (void)_drawVerticalSeparatorInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
CGContextSetLineWidth(context, 1.0);
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetMinY(aRect));
|
||||
CGContextAddLineToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetHeight(aRect));
|
||||
CGContextMoveToPoint(context, CGRectGetMidX(aRect), CGRectGetMinY(aRect));
|
||||
CGContextAddLineToPoint(context, CGRectGetMidX(aRect), CGRectGetHeight(aRect));
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)_drawLineBorderInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
cornerRadius = [self cornerRadius],
|
||||
borderWidth = [self borderWidth];
|
||||
|
||||
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
|
||||
CGContextSetLineWidth(context, borderWidth);
|
||||
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
}
|
||||
|
||||
- (void)_drawBezelBorderInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
|
||||
sideGray = 190.0 / 255.0,
|
||||
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
|
||||
borderWidth = _borderWidth;
|
||||
cornerRadius = [self cornerRadius],
|
||||
borderWidth = [self borderWidth],
|
||||
shadowOffset = [self valueForThemeAttribute:@"inner-shadow-offset"],
|
||||
shadowSize = [self valueForThemeAttribute:@"inner-shadow-size"],
|
||||
shadowColor = [self valueForThemeAttribute:@"inner-shadow-color"];
|
||||
|
||||
while (borderWidth--)
|
||||
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
|
||||
var baseRect = aRect;
|
||||
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||
|
||||
CGContextSaveGState(context);
|
||||
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
CGContextSetLineWidth(context, borderWidth);
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
CGContextFillRect(context, aRect);
|
||||
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (void)_drawLineBorderInRect:(CGRect)aRect
|
||||
- (void)_drawPrimaryBorderInRect:(CGRect)aRect
|
||||
{
|
||||
// Draw the "primary" style CPBox.
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
cornerRadius = [self cornerRadius],
|
||||
borderWidth = [self borderWidth],
|
||||
shadowOffset = [self valueForThemeAttribute:@"inner-shadow-offset"],
|
||||
shadowSize = [self valueForThemeAttribute:@"inner-shadow-size"],
|
||||
shadowColor = [self valueForThemeAttribute:@"inner-shadow-color"],
|
||||
baseRect = aRect;
|
||||
|
||||
aRect = CGRectInset(aRect, borderWidth / 2.0, borderWidth / 2.0);
|
||||
|
||||
CGContextSaveGState(context);
|
||||
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
CGContextSetLineWidth(context, borderWidth);
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
CGContextFillRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
// Note we can't use the 0.5 inset rectangle when setting up clipping. The clipping has to be
|
||||
// on integer coordinates for this to look right in Chrome.
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(baseRect, cornerRadius, cornerRadius, YES, YES, YES, YES));
|
||||
CGContextClip(context);
|
||||
CGContextSetShadowWithColor(context, shadowOffset, shadowSize, shadowColor);
|
||||
CGContextStrokeRoundedRectangleInRect(context, aRect, cornerRadius, YES, YES, YES, YES);
|
||||
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (void)_drawNoBorderInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
|
||||
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
|
||||
CGContextSetLineWidth(context, _borderWidth);
|
||||
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextFillRect(context, aRect);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
|
||||
CPBoxFillColorKey = @"CPBoxFillColorKey",
|
||||
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
|
||||
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
|
||||
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
|
||||
CPBoxTitle = @"CPBoxTitle",
|
||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
||||
CPBoxTitleView = @"CPBoxTitleView";
|
||||
|
||||
@implementation CPBox (CPCoding)
|
||||
|
||||
@@ -398,18 +608,16 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
||||
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||
|
||||
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
|
||||
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
|
||||
|
||||
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
|
||||
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
|
||||
|
||||
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
|
||||
_title = [aCoder decodeObjectForKey:CPBoxTitle];
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
||||
|
||||
_contentView = [self subviews][0];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -421,14 +629,9 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
|
||||
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
|
||||
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
||||
|
||||
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
|
||||
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
|
||||
|
||||
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
|
||||
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
|
||||
|
||||
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
|
||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+59
-58
@@ -24,15 +24,16 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPScrollView.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBrowser
|
||||
*/
|
||||
|
||||
@implementation CPBrowser : CPControl
|
||||
{
|
||||
id _delegate;
|
||||
@@ -65,18 +66,18 @@
|
||||
CPArray _columnWidths;
|
||||
}
|
||||
|
||||
+ (CPImage)branchImage
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||
pathForResource:"browser-leaf.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
return "browser";
|
||||
}
|
||||
|
||||
+ (CPImage)highlightedBranchImage
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||
pathForResource:"browser-leaf-highlighted.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
return @{
|
||||
@"image-control-resize": [CPNull null],
|
||||
@"image-control-leaf": [CPNull null],
|
||||
@"image-control-leaf-pressed": [CPNull null]
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -178,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)];
|
||||
|
||||
@@ -258,7 +264,7 @@
|
||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
|
||||
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setImageScaling:CPScaleProportionally];
|
||||
[view setImageScaling:CPImageScaleProportionallyDown];
|
||||
|
||||
[column setDataView:view];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
@@ -276,8 +282,8 @@
|
||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
||||
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setBranchImage:[[self class] branchImage]];
|
||||
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
|
||||
[view setBranchImage:[self valueForThemeAttribute:@"image-control-leaf"]];
|
||||
[view setHighlightedBranchImage:[self valueForThemeAttribute:@"image-control-leaf-pressed"]];
|
||||
|
||||
[column setDataView:view];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
@@ -425,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
|
||||
@@ -704,8 +725,6 @@
|
||||
@end
|
||||
|
||||
|
||||
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
|
||||
@implementation _CPBrowserResizeControl : CPView
|
||||
{
|
||||
CGPoint _mouseDownX;
|
||||
@@ -714,22 +733,14 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
unsigned _width;
|
||||
}
|
||||
|
||||
+ (CPImage)backgroundImage
|
||||
{
|
||||
if (!_CPBrowserResizeControlBackgroundImage)
|
||||
{
|
||||
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
|
||||
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
|
||||
size:CGSizeMake(15, 14)];
|
||||
}
|
||||
|
||||
return _CPBrowserResizeControlBackgroundImage;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
||||
{
|
||||
var browser = [[CPBrowser alloc] init];
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:[browser valueForThemeAttribute:@"image-control-resize"]]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -814,18 +825,26 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
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]];
|
||||
}
|
||||
|
||||
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
|
||||
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
||||
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
||||
}
|
||||
|
||||
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
|
||||
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragViewOffset
|
||||
{
|
||||
var count = theTableColumns.length;
|
||||
while (count--)
|
||||
@@ -838,30 +857,6 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
[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
|
||||
|
||||
@@ -901,6 +896,12 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
|
||||
}
|
||||
|
||||
- (void)tableViewSelectionDidChange:(CPNotification)aNotification
|
||||
{
|
||||
var selectedIndexes = [[aNotification object] selectedRowIndexes];
|
||||
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
||||
}
|
||||
|
||||
- (id)childAtIndex:(unsigned)index
|
||||
{
|
||||
return [_delegate browser:_browser child:index ofItem:_item];
|
||||
@@ -982,7 +983,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
|
||||
|
||||
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||
[imageView setImageScaling:CPScaleNone];
|
||||
[imageView setImageScaling:CPImageScaleNone];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
|
||||
+247
-99
@@ -25,24 +25,26 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
|
||||
@import "CPText.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
/* @group CPBezelStyle */
|
||||
|
||||
CPRoundedBezelStyle = 1;
|
||||
CPRegularSquareBezelStyle = 2;
|
||||
// IB style
|
||||
CPRoundedBezelStyle = 1; // Push
|
||||
CPRegularSquareBezelStyle = 2; // Bevel
|
||||
CPThickSquareBezelStyle = 3;
|
||||
CPThickerSquareBezelStyle = 4;
|
||||
CPDisclosureBezelStyle = 5;
|
||||
CPShadowlessSquareBezelStyle = 6;
|
||||
CPCircularBezelStyle = 7;
|
||||
CPTexturedSquareBezelStyle = 8;
|
||||
CPHelpButtonBezelStyle = 9;
|
||||
CPSmallSquareBezelStyle = 10;
|
||||
CPTexturedRoundedBezelStyle = 11;
|
||||
CPRoundRectBezelStyle = 12;
|
||||
CPRecessedBezelStyle = 13;
|
||||
CPRoundedDisclosureBezelStyle = 14;
|
||||
CPDisclosureBezelStyle = 5; // Disclosure triangle
|
||||
CPShadowlessSquareBezelStyle = 6; // Square
|
||||
CPCircularBezelStyle = 7; // Round
|
||||
CPTexturedSquareBezelStyle = 8; // Textured
|
||||
CPHelpButtonBezelStyle = 9; // Help
|
||||
CPSmallSquareBezelStyle = 10; // Gradient
|
||||
CPTexturedRoundedBezelStyle = 11; // Round Textured
|
||||
CPRoundRectBezelStyle = 12; // Round Rect
|
||||
CPRecessedBezelStyle = 13; // Recessed
|
||||
CPRoundedDisclosureBezelStyle = 14; // Disclosure
|
||||
CPHUDBezelStyle = -1;
|
||||
|
||||
|
||||
@@ -58,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;
|
||||
@@ -70,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],
|
||||
};
|
||||
|
||||
|
||||
CPButtonDefaultHeight = 24.0;
|
||||
/// @cond IGNORE
|
||||
CPButtonDefaultHeight = 25.0;
|
||||
CPButtonImageOffset = 3.0;
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -111,6 +116,16 @@ CPButtonImageOffset = 3.0;
|
||||
CPTimer _continuousTimer;
|
||||
float _periodicDelay;
|
||||
float _periodicInterval;
|
||||
|
||||
BOOL _isTracking;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
|
||||
return [CPActionBinding class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (id)buttonWithTitle:(CPString)aTitle
|
||||
@@ -136,14 +151,19 @@ 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],
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes and returns a newly allocated CPButton object with a specified frame rectangle.
|
||||
@param aFrame The frame rectangle for the created button object.
|
||||
@return An initialized CPView object or nil if the object couldn't be created.
|
||||
Initializes and returns a newly allocated CPButton object with a specified frame rectangle.
|
||||
@param aFrame The frame rectangle for the created button object.
|
||||
@return An initialized CPView object or nil if the object couldn't be created.
|
||||
*/
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
@@ -155,7 +175,7 @@ CPButtonImageOffset = 3.0;
|
||||
[self setValue:CPCenterTextAlignment forThemeAttribute:@"alignment"];
|
||||
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
||||
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
|
||||
[self setValue:CPImageScaleNone forThemeAttribute:@"image-scaling"];
|
||||
|
||||
[self setBezelStyle:CPRoundRectBezelStyle];
|
||||
[self setBordered:YES];
|
||||
@@ -176,11 +196,13 @@ CPButtonImageOffset = 3.0;
|
||||
// Continuous button defaults.
|
||||
_periodicInterval = 0.05;
|
||||
_periodicDelay = 0.5;
|
||||
|
||||
[self setButtonType:CPMomentaryPushInButton];
|
||||
}
|
||||
|
||||
// Setting the state
|
||||
/*!
|
||||
Returns a Boolean value indicating whether the button allows a mixed state.
|
||||
Returns a Boolean value indicating whether the button allows a mixed state.
|
||||
@return \c YES if the button has a 'mixed' state in addition to on and off.
|
||||
*/
|
||||
- (BOOL)allowsMixedState
|
||||
@@ -206,24 +228,20 @@ CPButtonImageOffset = 3.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the value of the button using an Objective-J object.
|
||||
@param anObjectValue The value of the button interpreted as an Objective-J object.
|
||||
Sets the value of the button using an Objective-J object.
|
||||
@param anObjectValue The value of the button interpreted as an Objective-J object.
|
||||
*/
|
||||
- (void)setObjectValue:(id)anObjectValue
|
||||
{
|
||||
if (!anObjectValue || anObjectValue === @"" || ([anObjectValue intValue] === 0))
|
||||
anObjectValue = CPOffState;
|
||||
|
||||
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;
|
||||
|
||||
else
|
||||
anObjectValue = CPOnState;
|
||||
|
||||
@@ -231,24 +249,35 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
switch ([self objectValue])
|
||||
{
|
||||
case CPMixedState: [self unsetThemeState:CPThemeStateSelected];
|
||||
[self setThemeState:CPButtonStateMixed];
|
||||
break;
|
||||
case CPMixedState:
|
||||
[self unsetThemeState:CPThemeStateSelected];
|
||||
[self setThemeState:CPButtonStateMixed];
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
[self setThemeState:CPThemeStateHighlighted];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateHighlighted];
|
||||
break;
|
||||
|
||||
case CPOnState: [self unsetThemeState:CPButtonStateMixed];
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
break;
|
||||
case CPOnState:
|
||||
[self unsetThemeState:CPButtonStateMixed];
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
[self setThemeState:CPThemeStateHighlighted];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateHighlighted];
|
||||
break;
|
||||
|
||||
case CPOffState: [self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed];
|
||||
case CPOffState:
|
||||
[self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed | CPThemeStateHighlighted];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the button's next state.
|
||||
@return The button's state. A button can have two or three states.
|
||||
If it has two, this value is either \c CPOffState (the normal or unpressed state)
|
||||
or \c CPOnState (the alternate or pressed state).
|
||||
If it has three, this value can be \c CPOnState (the feature is in effect everywhere), \c CPOffState (the feature is in effect nowhere), or \c CPMixedState (the feature is in effect somewhere).
|
||||
Returns the button's next state.
|
||||
@return The button's state. A button can have two or three states.
|
||||
If it has two, this value is either \c CPOffState (the normal or unpressed state)
|
||||
or \c CPOnState (the alternate or pressed state).
|
||||
If it has three, this value can be \c CPOnState (the feature is in effect everywhere), \c CPOffState (the feature is in effect nowhere), or \c CPMixedState (the feature is in effect somewhere).
|
||||
*/
|
||||
- (CPInteger)nextState
|
||||
{
|
||||
@@ -294,9 +323,9 @@ CPButtonImageOffset = 3.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the title displayed by the button when in its normal state.
|
||||
@param aTitle The string to set as the button's title. This title is always shown on buttons
|
||||
that don’t use their alternate contents when highlighting or displaying their alternate state.
|
||||
Sets the title displayed by the button when in its normal state.
|
||||
@param aTitle The string to set as the button's title. This title is always shown on buttons
|
||||
that don’t use their alternate contents when highlighting or displaying their alternate state.
|
||||
*/
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
@@ -310,9 +339,9 @@ CPButtonImageOffset = 3.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the title displayed on the button when it’s in its normal state.
|
||||
@return The title displayed on the receiver when it’s in its normal state
|
||||
or the empty string if the button doesn’t display a title.
|
||||
Returns the title displayed on the button when it’s in its normal state.
|
||||
@return The title displayed on the receiver when it’s in its normal state
|
||||
or the empty string if the button doesn’t display a title.
|
||||
*/
|
||||
- (CPString)title
|
||||
{
|
||||
@@ -374,11 +403,19 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
- (void)setShowsStateBy:(CPInteger)aMask
|
||||
{
|
||||
// CPPushInCellMask cannot be set for showsStateBy.
|
||||
aMask &= ~CPPushInCellMask;
|
||||
|
||||
if (_showsStateBy === aMask)
|
||||
return;
|
||||
|
||||
_showsStateBy = aMask;
|
||||
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask) && [self state] != CPOffState)
|
||||
[self setThemeState:CPThemeStateHighlighted];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateHighlighted];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -402,15 +439,20 @@ CPButtonImageOffset = 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
- (CPInteger)highlightsBy
|
||||
{
|
||||
return _highlightsBy;
|
||||
}
|
||||
|
||||
- (void)setButtonType:(CPButtonType)aButtonType
|
||||
{
|
||||
switch (aButtonType)
|
||||
{
|
||||
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
|
||||
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
case CPMomentaryPushInButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
|
||||
case CPMomentaryPushInButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
@@ -418,12 +460,12 @@ CPButtonImageOffset = 3.0;
|
||||
[self setShowsStateBy:CPNoCellMask];
|
||||
break;
|
||||
|
||||
case CPPushOnPushOffButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
|
||||
[self setShowsStateBy:CPChangeBackgroundCellMask];
|
||||
case CPPushOnPushOffButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
|
||||
break;
|
||||
|
||||
case CPOnOffButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeBackgroundCellMask];
|
||||
case CPOnOffButton: [self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
[self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
|
||||
break;
|
||||
|
||||
case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
||||
@@ -494,20 +536,45 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[self highlight:YES];
|
||||
_isTracking = YES;
|
||||
|
||||
return [super startTrackingAt:aPoint];
|
||||
var startedTracking = [super startTrackingAt:aPoint];
|
||||
|
||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
[self highlight:[self state] == CPOffState];
|
||||
else
|
||||
[self highlight:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
[self highlight:[self state] != CPOffState];
|
||||
else
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self highlight:NO];
|
||||
[self invalidateTimers];
|
||||
|
||||
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
|
||||
_isTracking = NO;
|
||||
|
||||
if (mouseIsUp && CGRectContainsPoint([self bounds], aPoint))
|
||||
[self setNextState];
|
||||
else
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
[self highlight:[self state] != CPOffState];
|
||||
else
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self invalidateTimers];
|
||||
}
|
||||
|
||||
- (void)invalidateTimers
|
||||
@@ -529,35 +596,18 @@ CPButtonImageOffset = 3.0;
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
if (_CGInsetIsEmpty(contentInset))
|
||||
return bounds;
|
||||
|
||||
bounds = _CGRectMakeCopy(bounds);
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
bounds.size.width -= contentInset.left + contentInset.right;
|
||||
bounds.size.height -= contentInset.top + contentInset.bottom;
|
||||
|
||||
return bounds;
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
// Is this necessary? The theme itself can just change its inset to a zero inset when !CPThemeStateBordered.
|
||||
if (![self isBordered])
|
||||
return _CGRectMakeZero();
|
||||
return bounds;
|
||||
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
if (_CGInsetIsEmpty(bezelInset))
|
||||
return bounds;
|
||||
|
||||
bounds = _CGRectMakeCopy(bounds);
|
||||
bounds.origin.x += bezelInset.left;
|
||||
bounds.origin.y += bezelInset.top;
|
||||
bounds.size.width -= bezelInset.left + bezelInset.right;
|
||||
bounds.size.height -= bezelInset.top + bezelInset.bottom;
|
||||
|
||||
return bounds;
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
@@ -617,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
|
||||
@@ -641,8 +691,51 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
if (contentView)
|
||||
{
|
||||
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
|
||||
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
|
||||
var title = nil,
|
||||
image = nil;
|
||||
|
||||
if (_isTracking)
|
||||
{
|
||||
if (_highlightsBy & CPContentsCellMask)
|
||||
{
|
||||
if (_showsStateBy & CPContentsCellMask)
|
||||
{
|
||||
title = ([self state] == CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
||||
image = ([self state] == CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
||||
}
|
||||
else
|
||||
{
|
||||
title = [self alternateTitle];
|
||||
image = [self alternateImage];
|
||||
}
|
||||
}
|
||||
else if (_showsStateBy & CPContentsCellMask)
|
||||
{
|
||||
title = ([self state] != CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
||||
image = ([self state] != CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
||||
}
|
||||
else
|
||||
{
|
||||
title = _title;
|
||||
image = [self image];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_showsStateBy & CPContentsCellMask)
|
||||
{
|
||||
title = ([self state] != CPOffState && _alternateTitle) ? _alternateTitle : _title;
|
||||
image = ([self state] != CPOffState && [self alternateImage]) ? [self alternateImage] : [self image];
|
||||
}
|
||||
else
|
||||
{
|
||||
title = _title;
|
||||
image = [self image];
|
||||
}
|
||||
}
|
||||
|
||||
[contentView setText:title];
|
||||
[contentView setImage:image];
|
||||
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
|
||||
|
||||
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
@@ -741,9 +834,51 @@ CPButtonImageOffset = 3.0;
|
||||
return NO;
|
||||
|
||||
[self performClick:nil];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Perform a click on the receiver.
|
||||
|
||||
@param sender - The sender object
|
||||
*/
|
||||
- (void)performClick:(id)sender
|
||||
{
|
||||
// This is slightly different from [super performClick:] in that the highlight behaviour is dependent on
|
||||
// highlightsBy and showsStateBy.
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self setState:[self nextState]];
|
||||
|
||||
var shouldHighlight = NO;
|
||||
|
||||
if (_highlightsBy & (CPPushInCellMask | CPChangeGrayCellMask))
|
||||
{
|
||||
if (_showsStateBy & (CPChangeGrayCellMask | CPChangeBackgroundCellMask))
|
||||
shouldHighlight = [self state] == CPOffState;
|
||||
else
|
||||
shouldHighlight = YES;
|
||||
}
|
||||
|
||||
[self highlight:shouldHighlight];
|
||||
|
||||
try
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (shouldHighlight)
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPButton (NS)
|
||||
@@ -784,7 +919,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
|
||||
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
|
||||
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
|
||||
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
|
||||
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey",
|
||||
CPButtonHighlightsByKey = @"CPButtonHighlightsByKey",
|
||||
CPButtonShowsStateByKey = @"CPButtonShowsStateByKey";
|
||||
|
||||
@implementation CPButton (CPCoding)
|
||||
|
||||
@@ -802,9 +939,20 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
|
||||
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
|
||||
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
|
||||
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
|
||||
if ([aCoder containsValueForKey:CPButtonHighlightsByKey])
|
||||
{
|
||||
// If one exists, assume both do.
|
||||
_highlightsBy = [aCoder decodeIntForKey:CPButtonHighlightsByKey];
|
||||
_showsStateBy = [aCoder decodeIntForKey:CPButtonShowsStateByKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backwards compatibility: if this CPButton was encoded before coding of
|
||||
// highlightsBy and showsStateBy were added, we should just use the
|
||||
// default values from _init rather than overwriting with 0, 0.
|
||||
}
|
||||
|
||||
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
|
||||
|
||||
@@ -843,6 +991,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
|
||||
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
|
||||
|
||||
[aCoder encodeInt:_highlightsBy forKey:CPButtonHighlightsByKey];
|
||||
[aCoder encodeInt:_showsStateBy forKey:CPButtonShowsStateByKey];
|
||||
|
||||
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
|
||||
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
|
||||
|
||||
@@ -856,6 +1007,3 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@import "CPCheckBox.j"
|
||||
@import "CPRadio.j"
|
||||
|
||||
+40
-5
@@ -1,5 +1,31 @@
|
||||
/*
|
||||
* CPButtonBar.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
@class CPSplitView
|
||||
|
||||
@global CPPopUpButtonStatePullsDown
|
||||
|
||||
|
||||
@implementation CPButtonBar : CPView
|
||||
@@ -12,7 +38,7 @@
|
||||
+ (id)plusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-plus" forClass:[CPButtonBar class]];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImage:image];
|
||||
@@ -24,7 +50,7 @@
|
||||
+ (id)minusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-minus" forClass:[CPButtonBar class]];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImage:image];
|
||||
@@ -36,7 +62,7 @@
|
||||
+ (id)actionPopupButton
|
||||
{
|
||||
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
|
||||
image = [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-action" forClass:[CPButtonBar class]];
|
||||
|
||||
[button addItemWithTitle:nil];
|
||||
[[button lastItem] setImage:image];
|
||||
@@ -55,8 +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]]
|
||||
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
|
||||
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
|
||||
|
||||
+35
-41
@@ -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
|
||||
@@ -94,54 +94,48 @@ CPCheckBoxImageOffset = 4.0;
|
||||
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
|
||||
}
|
||||
|
||||
- (CPImage)image
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (CPImage)alternateImage
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
var startedTracking = [super startTrackingAt:aPoint];
|
||||
[self highlight:YES];
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCheckBoxValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination valueForKeyPath:keyPath],
|
||||
isPlaceholder = CPIsControllerMarker(newValue);
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
switch (newValue)
|
||||
{
|
||||
case CPMultipleValuesMarker:
|
||||
newValue = CPMixedState;
|
||||
break;
|
||||
[self _setPlaceholder:CPMixedState forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
case CPNoSelectionMarker:
|
||||
newValue = CPOffState;
|
||||
break;
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setAllowsMixedState:(aValue === CPMixedState)];
|
||||
[_source setState:aValue];
|
||||
}
|
||||
|
||||
case CPNotApplicableMarker:
|
||||
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
|
||||
|
||||
newValue = CPOffState;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newValue === CPMixedState)
|
||||
{
|
||||
[_source setAllowsMixedState:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cocoa will always set allowsMixedState to NO
|
||||
// This behavior will be fine for Cappuccino as well if we (like Cocoa)
|
||||
// default the CPConditionallySetsEnabledBindingOption to YES
|
||||
[_source setAllowsMixedState:NO];
|
||||
}
|
||||
}
|
||||
|
||||
[_source setState:newValue];
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setState:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+34
-22
@@ -22,6 +22,7 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPScrollView
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -44,10 +45,10 @@
|
||||
if (_documentView == aView)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPViewFrameDidChangeNotification
|
||||
@@ -66,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.
|
||||
*/
|
||||
@@ -101,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];
|
||||
@@ -233,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;
|
||||
}
|
||||
|
||||
+610
-240
File diff suppressed because it is too large
Load Diff
@@ -22,13 +22,38 @@
|
||||
|
||||
@import "CPViewController.j"
|
||||
|
||||
|
||||
/*!
|
||||
Represents an object inside a CPCollectionView.
|
||||
*/
|
||||
@implementation CPCollectionViewItem : CPViewController
|
||||
{
|
||||
BOOL _isSelected;
|
||||
CPData _cachedArchive;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
var cibName = [self cibName],
|
||||
copy;
|
||||
|
||||
if (cibName)
|
||||
{
|
||||
copy = [[[self class] alloc] initWithCibName:cibName bundle:[self cibBundle]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_cachedArchive)
|
||||
_cachedArchive = [CPKeyedArchiver archivedDataWithRootObject:self];
|
||||
|
||||
copy = [CPKeyedUnarchiver unarchiveObjectWithData:_cachedArchive];
|
||||
|
||||
// copy connections
|
||||
}
|
||||
|
||||
[copy setRepresentedObject:[self representedObject]];
|
||||
[copy setSelected:_isSelected];
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Setting the Represented Object
|
||||
|
||||
+724
-37
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
@import "CGColor.j"
|
||||
|
||||
@@ -28,6 +29,18 @@
|
||||
@import "CPImage.j"
|
||||
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for vertical patterns.
|
||||
*/
|
||||
CPColorPatternIsVertical = YES;
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for horizontal patterns.
|
||||
*/
|
||||
CPColorPatternIsHorizontal = NO;
|
||||
|
||||
/// @cond IGNORE
|
||||
|
||||
var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
_blueComponent = 2,
|
||||
@@ -54,6 +67,8 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -72,7 +87,7 @@ var cachedBlackColor,
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Creates a color in the RGB colorspace, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
@@ -86,13 +101,13 @@ var cachedBlackColor,
|
||||
*/
|
||||
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[red, green, blue, alpha]];
|
||||
return [[CPColor alloc] _initWithRGBA:[MAX(0.0, MIN(1.0, red)), MAX(0.0, MIN(1.0, green)), MAX(0.0, MIN(1.0, blue)), MAX(0.0, MIN(1.0, alpha))]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithRed:green:blue:alpha:
|
||||
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Creates a color in the RGB colorspace, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
@@ -141,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
|
||||
*/
|
||||
@@ -154,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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +247,17 @@ var cachedBlackColor,
|
||||
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a color in the sRGB colorspace with the given components and alpha values.
|
||||
Values below 0.0 are treated as 0.0 and values above 1.0 are treated as 1.0.
|
||||
*/
|
||||
+ (CPColor)colorWithSRGBRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
// TODO If Cappuccino is ported to a colorspace aware platform, this color should be in
|
||||
// sRGBColorSpace.
|
||||
return [self colorWithRed:red green:green blue:blue alpha:alpha];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a black color object. (RGBA=[0.0, 0.0, 0.0, 1.0])
|
||||
*/
|
||||
@@ -419,7 +485,9 @@ var cachedBlackColor,
|
||||
parts[3] ? parseFloat(parts[3], 10) : 1.0
|
||||
];
|
||||
|
||||
_cssString = aString;
|
||||
// We can't reuse aString as _cssString because the browser might not support the `rgba` syntax, and aString might
|
||||
// use it (issue #1413.)
|
||||
[self _initCSSStringFromComponents];
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -433,18 +501,23 @@ var cachedBlackColor,
|
||||
{
|
||||
_components = components;
|
||||
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
[self _initCSSStringFromComponents];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initCSSStringFromComponents
|
||||
{
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initWithPatternImage:(CPImage)anImage
|
||||
{
|
||||
@@ -532,8 +605,19 @@ var cachedBlackColor,
|
||||
return [[[self class] alloc] _initWithRGBA:components];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver. This method is a placeholder that does nothing but may be implemented in the future.
|
||||
*/
|
||||
- (CPColor)colorUsingColorSpaceName:(id)aColorSpaceName
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
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>
|
||||
@@ -580,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:
|
||||
@@ -633,7 +741,36 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description]+" "+[self cssString];
|
||||
var description = [super description],
|
||||
patternImage = [self patternImage];
|
||||
|
||||
if (!patternImage)
|
||||
return description + " " + [self cssString];
|
||||
|
||||
description += " {\n";
|
||||
|
||||
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
|
||||
{
|
||||
var slices = [patternImage imageSlices];
|
||||
|
||||
if ([patternImage isThreePartImage])
|
||||
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
|
||||
|
||||
description += " patternImage (" + slices.length + " part): [\n";
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var imgDescription = [slices[i] description] || "nil";
|
||||
|
||||
description += imgDescription.replace(/^/mg, " ") + ",\n";
|
||||
}
|
||||
|
||||
description = description.substr(0, description.length - 2) + "\n ]\n}";
|
||||
}
|
||||
else
|
||||
description += ([patternImage description] || "nil").replace(/^/mg, " ") + "\n}";
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -678,8 +815,10 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
@end
|
||||
|
||||
/// @cond IGNORE
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||
/// @endcond
|
||||
|
||||
@implementation CPColor (CPCoding)
|
||||
|
||||
@@ -710,13 +849,12 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
@end
|
||||
|
||||
|
||||
/// @cond IGNORE
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@ignore
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
/*
|
||||
Used for the CPColor +colorWithHexString: implementation.
|
||||
Returns an array of rgb components.
|
||||
*/
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
@@ -754,3 +892,552 @@ var byteToHex = function(n)
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
/*!
|
||||
To create a simple color with a pattern image:
|
||||
CPColorWithImages(name, width, height{, bundle})
|
||||
|
||||
To create a color with a three-part/nine-part image using a pattern string:
|
||||
CPColorWithImages(pattern, attributes{, bundle})
|
||||
|
||||
<pattern> must have one or more placeholders. There are there possible
|
||||
placeholders available that together can be used to build a filename:
|
||||
|
||||
style A top-level style, for example normal (empty) and "default".
|
||||
state The state of a view, for example "highlighted" and "disabled".
|
||||
position The position of an image within a 3-part or 9-part image.
|
||||
This must be provided.
|
||||
|
||||
Each placeholder is filled with the values you pass in a the attributes object.
|
||||
Neither style nor state are necessary, if you omit them the next level of the
|
||||
hierarchy is the top level.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
styles: [...]
|
||||
An array of style names. For example, if you want to generate the filenames
|
||||
"button-bezel" and "default-button-bezel", you would use ["", "default"]
|
||||
for the styles.
|
||||
|
||||
states: [...]
|
||||
An array of state names.
|
||||
|
||||
positions: <spec>
|
||||
Specifies the naming convention for the slices of the image. For 3-part images,
|
||||
<spec> may be one of:
|
||||
|
||||
"@" Equivalent to ["left", "center", "right"] for horizontal
|
||||
images, ["top", "center", "bottom"] for vertical images
|
||||
"#" Equivalent to ["0", "1", "2"]
|
||||
[...] An array of any three literal strings
|
||||
|
||||
For 9-part images, <spec> may be one of:
|
||||
|
||||
"@" | "abbrev" Equivalent to ["top-left", "top", "top-right",
|
||||
"left", "center", "right",
|
||||
"bottom-left", "bottom", "bottom-right"]
|
||||
"full" Equivalent to ["top-left", "top-center", "top-right",
|
||||
"center-left", "center-center", "center-right",
|
||||
"bottom-left", "bottom-center", "bottom-right"]
|
||||
"#" Equivalent to ["0", "1", "2", "3", "4", "5", "6", "7", "8"]
|
||||
[...] An array of any nine literal strings
|
||||
|
||||
width: <number>
|
||||
The width of the left image for horizontal 3-part images, the top image for
|
||||
vertical 3-part images, or the top left corner for 9-part images.
|
||||
|
||||
height: <number>
|
||||
The height of the left image for horizontal 3-part images, the top image for
|
||||
vertical 3-part images, or the top left corner for 9-part images.
|
||||
|
||||
centerWidth: <number>
|
||||
For a horizontal 3-part image that has a center slice width that is not 1.0,
|
||||
set this for the width of the center slice. If omitted, it defaults
|
||||
to 1.0. Not used for 9-part images.
|
||||
|
||||
rightWidth: <number>
|
||||
For a horizontal 3-part image that has different left/right slice widths,
|
||||
or a 9-part image that has different left/right corner slice widths,
|
||||
set this for the width of the right slice. If omitted, the "width"
|
||||
value is used for left and right widths.
|
||||
|
||||
centerHeight: <number>
|
||||
For a vertical 3-part image that has a center slice height that is not 1.0,
|
||||
set this for the height of the center slice. If omitted, it defaults
|
||||
to 1.0. Not used for 9-part images.
|
||||
|
||||
bottomHeight: <number>
|
||||
For a vertical image that has different top/bottom slice heights,
|
||||
or a 9-part image that has different top/bottom corner slice heights,
|
||||
set this for the height of the bottom slice. If omitted, the "height"
|
||||
value is used for top and bottom heights.
|
||||
|
||||
centerIsNil: <BOOL>
|
||||
For 9-part images, if the center image is nil, set this to YES.
|
||||
If omitted or set to NO, a center image must be provided.
|
||||
|
||||
separator: <string>
|
||||
The separator to use between components of the pattern.
|
||||
If it is omitted, it defaults to "-".
|
||||
|
||||
orientation: PatternIsHorizontal | PatternIsVertical
|
||||
The orientation of the image. This must be specified for 3-part images,
|
||||
it should NOT be specified for 9-part images.
|
||||
|
||||
Using a pattern, all of this:
|
||||
|
||||
bezelColor = PatternColor(
|
||||
[
|
||||
["button-bezel-left.png", 4.0, 24.0],
|
||||
["button-bezel-center.png", 1.0, 24.0],
|
||||
["button-bezel-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
highlightedBezelColor = PatternColor(
|
||||
[
|
||||
["button-bezel-highlighted-left.png", 4.0, 24.0],
|
||||
["button-bezel-highlighted-center.png", 1.0, 24.0],
|
||||
["button-bezel-highlighted-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
disabledBezelColor = PatternColor(
|
||||
[
|
||||
["button-bezel-disabled-left.png", 4.0, 24.0],
|
||||
["button-bezel-disabled-center.png", 1.0, 24.0],
|
||||
["button-bezel-disabled-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
defaultBezelColor = PatternColor(
|
||||
[
|
||||
["default-button-bezel-left.png", 4.0, 24.0],
|
||||
["default-button-bezel-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
defaultHighlightedBezelColor = PatternColor(
|
||||
[
|
||||
["default-button-bezel-highlighted-left.png", 4.0, 24.0],
|
||||
["default-button-bezel-highlighted-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-highlighted-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
defaultDisabledBezelColor = PatternColor(
|
||||
[
|
||||
["default-button-bezel-disabled-left.png", 4.0, 24.0],
|
||||
["default-button-bezel-disabled-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-disabled-right.png", 4.0, 24.0]
|
||||
],
|
||||
PatternIsHorizontal)
|
||||
|
||||
can be replaced with this:
|
||||
|
||||
bezelColors = PatternColor(
|
||||
"{style}button-bezel{state}{position}.png",
|
||||
{
|
||||
styles: ["", "default"],
|
||||
states: ["", "highlighted", "disabled"],
|
||||
positions: "@",
|
||||
width: 4.0,
|
||||
height: 24.0,
|
||||
orientation: PatternIsHorizontal
|
||||
})
|
||||
|
||||
Which would effectively create the following object:
|
||||
|
||||
{
|
||||
"@":
|
||||
{
|
||||
"@": <ThreePartImage>:
|
||||
[
|
||||
["button-bezel-left.png", 4.0, 24.0],
|
||||
["button-bezel-center.png", 1.0, 24.0],
|
||||
["button-bezel-right.png", 4.0, 24.0]
|
||||
],
|
||||
"highlighted": <ThreePartImage>:
|
||||
[
|
||||
["button-bezel-highlighted-left.png", 4.0, 24.0],
|
||||
["button-bezel-highlighted-center.png", 1.0, 24.0],
|
||||
["button-bezel-highlighted-right.png", 4.0, 24.0]
|
||||
],
|
||||
"disabled": <ThreePartImage>:
|
||||
[
|
||||
["button-bezel-disabled-left.png", 4.0, 24.0],
|
||||
["button-bezel-disabled-center.png", 1.0, 24.0],
|
||||
["button-bezel-disabled-right.png", 4.0, 24.0]
|
||||
]
|
||||
},
|
||||
|
||||
"default":
|
||||
{
|
||||
"@": <ThreePartImage>:
|
||||
[
|
||||
["default-button-bezel-left.png", 4.0, 24.0],
|
||||
["default-button-bezel-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-right.png", 4.0, 24.0]
|
||||
],
|
||||
"highlighted": <ThreePartImage>:
|
||||
[
|
||||
["default-button-bezel-highlighted-left.png", 4.0, 24.0],
|
||||
["default-button-bezel-highlighted-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-highlighted-right.png", 4.0, 24.0]
|
||||
],
|
||||
"disabled": <ThreePartImage>:
|
||||
[
|
||||
["default-button-bezel-disabled-left.png", 4.0, 24.0],
|
||||
["button-bezel-disabled-center.png", 1.0, 24.0],
|
||||
["default-button-bezel-disabled-right.png", 4.0, 24.0]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
To reference empty names in the pattern color, use the key "@".
|
||||
So, for example, to reference the "default" style, "disabled" state,
|
||||
you would use the following expression:
|
||||
|
||||
bezelColors["@"]["disabled"]
|
||||
|
||||
To create a color with a three-part pattern image explicitly:
|
||||
CPColorWithImages(slices, orientation)
|
||||
|
||||
where slices is an array of three [name, width, height{, bundle}] arrays,
|
||||
and orientation is CPColorPatternIsVertical or CPColorPatternIsHorizontal.
|
||||
|
||||
To create a color with a nine-part pattern image explicitly:
|
||||
CPColorWithImages(slices);
|
||||
|
||||
where slices is an array of nine [name, width, height{, bundle}] arrays.
|
||||
*/
|
||||
function CPColorWithImages()
|
||||
{
|
||||
var slices = nil,
|
||||
numParts = 0,
|
||||
isVertical = false,
|
||||
imageFactory = CPImageInBundle,
|
||||
args = Array.prototype.slice.apply(arguments);
|
||||
|
||||
if (typeof(args[args.length - 1]) === "function")
|
||||
imageFactory = args.pop();
|
||||
|
||||
switch (args.length)
|
||||
{
|
||||
case 1:
|
||||
return imageFromSlices(args[0], isVertical, imageFactory);
|
||||
|
||||
case 2:
|
||||
// New-style 3-part and 9-part images
|
||||
if (typeof(args[0]) === "string")
|
||||
return patternColorsFromPattern.call(this, args[0], args[1], imageFactory);
|
||||
|
||||
return imageFromSlices(args[0], args[1], imageFactory);
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
return [CPColor colorWithPatternImage:imageFactory(args[0], args[1], args[2], args[3])];
|
||||
|
||||
default:
|
||||
throw("ERROR: Invalid argument count: " + args.length);
|
||||
}
|
||||
}
|
||||
|
||||
var imageFromSlices = function(slices, isVertical, imageFactory)
|
||||
{
|
||||
var imageSlices = [];
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? imageFactory(slice[0], slice[1], slice[2], slice[3]) : nil);
|
||||
}
|
||||
|
||||
switch (slices.length)
|
||||
{
|
||||
case 3:
|
||||
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:isVertical]];
|
||||
|
||||
case 9:
|
||||
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
|
||||
|
||||
default:
|
||||
throw("ERROR: Invalid number of image slices: " + slices.length);
|
||||
}
|
||||
};
|
||||
|
||||
var patternColorsFromPattern = function(pattern, attributes, imageFactory)
|
||||
{
|
||||
if (pattern.match(/^.*\{[^}]+\}/))
|
||||
{
|
||||
var width = attributes["width"],
|
||||
height = attributes["height"],
|
||||
separator = attributes["separator"] || "-",
|
||||
orientation = attributes["orientation"],
|
||||
rightWidth,
|
||||
bottomHeight,
|
||||
centerWidthHeight,
|
||||
centerIsNil,
|
||||
numParts;
|
||||
|
||||
// positions are mandatory
|
||||
if (pattern.indexOf("{position}") < 0)
|
||||
throw("ERROR: Pattern strings must have a {position} placeholder (\"" + pattern + "\")");
|
||||
|
||||
if (orientation === undefined)
|
||||
{
|
||||
numParts = 9;
|
||||
|
||||
if (attributes["centerIsNil"] !== undefined)
|
||||
centerIsNil = attributes["centerIsNil"];
|
||||
}
|
||||
else
|
||||
{
|
||||
numParts = 3;
|
||||
isVertical = orientation === PatternIsVertical;
|
||||
|
||||
if (isVertical)
|
||||
{
|
||||
if (attributes["centerHeight"])
|
||||
centerWidthHeight = attributes["centerHeight"];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attributes["centerWidth"])
|
||||
centerWidthHeight = attributes["centerWidth"];
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes["rightWidth"])
|
||||
rightWidth = attributes["rightWidth"];
|
||||
|
||||
if (attributes["bottomHeight"])
|
||||
bottomHeight = attributes["bottomHeight"];
|
||||
|
||||
var positions = attributes["positions"] || "@",
|
||||
states = nil,
|
||||
styles = nil;
|
||||
|
||||
if (numParts === 3)
|
||||
{
|
||||
if (positions === "@")
|
||||
{
|
||||
if (isVertical)
|
||||
positions = ["top", "center", "bottom"];
|
||||
else
|
||||
positions = ["left", "center", "right"];
|
||||
}
|
||||
else if (positions === "#")
|
||||
positions = ["0", "1", "2"];
|
||||
else
|
||||
throw("ERROR: Invalid positions: " + positions)
|
||||
}
|
||||
else // numParts === 9
|
||||
{
|
||||
if (positions === "@" || positions === "abbrev")
|
||||
positions = ["top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right"];
|
||||
else if (positions === "full")
|
||||
positions = ["top-left", "top-center", "top-right", "center-left", "center-center", "center-right", "bottom-left", "bottom-center", "bottom-right"];
|
||||
else if (positions === "#")
|
||||
positions = ["0", "1", "2", "3", "4", "5", "6", "7", "8"];
|
||||
else
|
||||
throw("ERROR: Invalid positions: " + positions)
|
||||
}
|
||||
|
||||
// states
|
||||
if (pattern.indexOf("{state}") >= 0)
|
||||
{
|
||||
states = attributes["states"];
|
||||
|
||||
if (!states)
|
||||
throw("ERROR: {state} placeholder in the pattern (\"" + pattern + "\") but no states item in the attributes");
|
||||
}
|
||||
|
||||
// styles
|
||||
if (pattern.indexOf("{style}") >= 0)
|
||||
{
|
||||
styles = attributes["styles"];
|
||||
|
||||
if (!styles)
|
||||
throw("ERROR: {style} placeholder in the pattern (\"" + pattern + "\") but no styles item in the attributes");
|
||||
}
|
||||
|
||||
// Now assemble the hierarchy
|
||||
var placeholder = "{position}",
|
||||
pos = pattern.indexOf(placeholder),
|
||||
i;
|
||||
|
||||
for (i = 0; i < positions.length; ++i)
|
||||
positions[i] = pattern.replace(placeholder, pos === 0 ? positions[i] + separator : separator + positions[i]);
|
||||
|
||||
var slices = positions,
|
||||
object = slices,
|
||||
key,
|
||||
sep;
|
||||
|
||||
if (states)
|
||||
{
|
||||
placeholder = "{state}";
|
||||
pos = pattern.indexOf(placeholder);
|
||||
object = {};
|
||||
|
||||
for (i = 0; i < states.length; ++i)
|
||||
{
|
||||
var state = states[i];
|
||||
key = state || "@";
|
||||
sep = state ? separator : "";
|
||||
|
||||
object[key] = slices.slice(0);
|
||||
replacePlaceholderInArray(object[key], placeholder, pos === 0 ? state + sep : sep + state);
|
||||
}
|
||||
}
|
||||
|
||||
if (styles)
|
||||
{
|
||||
placeholder = "{style}";
|
||||
pos = pattern.indexOf(placeholder);
|
||||
|
||||
var styleObject = {};
|
||||
|
||||
for (i = 0; i < styles.length; ++i)
|
||||
{
|
||||
var style = styles[i];
|
||||
key = style || "@";
|
||||
sep = style ? separator : "";
|
||||
|
||||
if (states)
|
||||
{
|
||||
styleObject[key] = cloneObject(object);
|
||||
replacePlaceholderInObject(styleObject[key], placeholder, pos === 0 ? style + sep : sep + style);
|
||||
}
|
||||
else
|
||||
{
|
||||
styleObject[key] = slices.slice(0);
|
||||
replacePlaceholderInArray(styleObject[key], placeholder, pos === 0 ? style + sep : sep + style);
|
||||
}
|
||||
}
|
||||
|
||||
object = styleObject;
|
||||
}
|
||||
|
||||
if (styles || states)
|
||||
{
|
||||
if (numParts === 3)
|
||||
makeThreePartSlicesFromObject(object, width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical);
|
||||
else
|
||||
makeNinePartSlicesFromObject(object, width, height, rightWidth, bottomHeight, centerIsNil);
|
||||
|
||||
makeImagesFromObject(object, isVertical, imageFactory);
|
||||
return object;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numParts === 3)
|
||||
makeThreePartSlicesFromArray(object, width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical);
|
||||
else
|
||||
makeNinePartSlicesFromArray(object, width, height, rightWidth, bottomHeight, centerIsNil);
|
||||
|
||||
return imageFromSlices(object, isVertical, imageFactory);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw("ERROR: No placeholders in slice pattern (\"" + pattern + "\")");
|
||||
};
|
||||
|
||||
var replacePlaceholderInArray = function(array, find, replacement)
|
||||
{
|
||||
for (var i = 0; i < array.length; ++i)
|
||||
array[i] = array[i].replace(find, replacement);
|
||||
};
|
||||
|
||||
var replacePlaceholderInObject = function(object, find, replacement)
|
||||
{
|
||||
for (var key in object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
replacePlaceholderInArray(object[key], find, replacement);
|
||||
else
|
||||
replacePlaceholderInObject(object[key], find, replacement);
|
||||
};
|
||||
|
||||
var cloneObject = function(object)
|
||||
{
|
||||
var clone = {};
|
||||
|
||||
for (var key in object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
clone[key] = object[key].slice(0);
|
||||
else if (typeof(object[key]) === "object")
|
||||
clone[key] = cloneObject(object[key]);
|
||||
else
|
||||
clone[key] = object[key];
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
var makeThreePartSlicesFromObject = function(object, width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical)
|
||||
{
|
||||
for (var key in object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
makeThreePartSlicesFromArray(object[key], width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical);
|
||||
else // object
|
||||
makeThreePartSlicesFromObject(object[key], width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical);
|
||||
};
|
||||
|
||||
var makeThreePartSlicesFromArray = function(array, width, height, centerWidthHeight, rightWidth, bottomHeight, isVertical)
|
||||
{
|
||||
array[0] = [array[0], width, height];
|
||||
|
||||
if (isVertical)
|
||||
{
|
||||
array[1] = [array[1], width, centerWidthHeight ? centerWidthHeight : 1.0];
|
||||
array[2] = [array[2], width, bottomHeight ? bottomHeight : height];
|
||||
}
|
||||
else
|
||||
{
|
||||
array[1] = [array[1], centerWidthHeight ? centerWidthHeight : 1.0, height];
|
||||
array[2] = [array[2], rightWidth ? rightWidth : width, height];
|
||||
}
|
||||
};
|
||||
|
||||
var makeNinePartSlicesFromObject = function(object, width, height, rightWidth, bottomHeight, centerIsNil)
|
||||
{
|
||||
for (var key in object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
makeNinePartSlicesFromArray(object[key], width, height, rightWidth, bottomHeight, centerIsNil);
|
||||
else // object
|
||||
makeNinePartSlicesFromObject(object[key], width, height, rightWidth, bottomHeight, centerIsNil);
|
||||
};
|
||||
|
||||
var makeNinePartSlicesFromArray = function(array, width, height, rightWidth, bottomHeight, centerIsNil)
|
||||
{
|
||||
rightWidth = rightWidth ? rightWidth : width;
|
||||
bottomHeight = bottomHeight ? bottomHeight : height;
|
||||
|
||||
array[0] = [array[0], width, height]; // top-left
|
||||
array[1] = [array[1], 1.0, height]; // top
|
||||
array[2] = [array[2], rightWidth, height]; // top-right
|
||||
array[3] = [array[3], width, 1.0]; // left
|
||||
array[4] = centerIsNil ? nil : [array[4], 1.0, 1.0]; // center
|
||||
array[5] = [array[5], rightWidth, 1.0]; // right
|
||||
array[6] = [array[6], width, bottomHeight]; // bottom-left
|
||||
array[7] = [array[7], 1.0, bottomHeight]; // bottom
|
||||
array[8] = [array[8], rightWidth, bottomHeight]; // bottom-right
|
||||
};
|
||||
|
||||
var makeImagesFromObject = function(object, isVertical, imageFactory)
|
||||
{
|
||||
for (var key in object)
|
||||
if (object.hasOwnProperty(key))
|
||||
if (object[key].constructor === Array)
|
||||
object[key] = imageFromSlices(object[key], isVertical, imageFactory);
|
||||
else // object
|
||||
makeImagesFromObject(object[key], isVertical, imageFactory);
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
+64
-59
@@ -20,12 +20,32 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPSlider
|
||||
|
||||
@global CPApp
|
||||
|
||||
/*
|
||||
A color wheel
|
||||
@global
|
||||
@group CPColorPanelMode
|
||||
*/
|
||||
CPWheelColorPickerMode = 1;
|
||||
|
||||
/*
|
||||
Slider based picker
|
||||
@global
|
||||
@group CPColorPanelMode
|
||||
*/
|
||||
CPSliderColorPickerMode = 2;
|
||||
|
||||
CPColorPickerViewWidth = 265;
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
||||
|
||||
@@ -38,22 +58,6 @@ var PREVIEW_HEIGHT = 20.0,
|
||||
var SharedColorPanel = nil,
|
||||
ColorPickerClasses = [];
|
||||
|
||||
/*
|
||||
A color wheel
|
||||
@global
|
||||
@group CPColorPanelMode
|
||||
*/
|
||||
CPWheelColorPickerMode = 1;
|
||||
/*
|
||||
Slider based picker
|
||||
@global
|
||||
@group CPColorPanelMode
|
||||
*/
|
||||
CPSliderColorPickerMode = 2;
|
||||
|
||||
CPColorPickerViewWidth = 265,
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPanel
|
||||
@@ -123,7 +127,7 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
if (self)
|
||||
{
|
||||
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
||||
//[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
||||
|
||||
[self setTitle:@"Color Panel"];
|
||||
[self setLevel:CPFloatingWindowLevel];
|
||||
@@ -144,7 +148,7 @@ CPColorPickerViewHeight = 370;
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
_color = aColor;
|
||||
[_previewView setBackgroundColor: _color];
|
||||
[_previewView setBackgroundColor:_color];
|
||||
|
||||
[CPApp sendAction:@selector(changeColor:) to:nil from:self];
|
||||
|
||||
@@ -248,8 +252,8 @@ CPColorPickerViewHeight = 370;
|
||||
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
|
||||
bounds = [[self contentView] bounds];
|
||||
|
||||
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin:CPPointMake(5, height)];
|
||||
[view setFrameSize:CGSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin:CGPointMake(5, height)];
|
||||
}
|
||||
|
||||
[_currentView removeFromSuperview];
|
||||
@@ -299,7 +303,7 @@ CPColorPickerViewHeight = 370;
|
||||
bounds = [contentView bounds];
|
||||
|
||||
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
[_toolbar setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
|
||||
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
|
||||
@@ -339,7 +343,7 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
[previewBox addSubview:_previewView];
|
||||
|
||||
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
|
||||
var _previewLabel = [[CPTextField alloc] initWithFrame:CGRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
|
||||
[_previewLabel setStringValue:"Preview:"];
|
||||
[_previewLabel setTextColor:[CPColor blackColor]];
|
||||
[_previewLabel setAlignment:CPRightTextAlignment];
|
||||
@@ -357,14 +361,14 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
[swatchBox addSubview:_swatchView];
|
||||
|
||||
var _swatchLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 8 + PREVIEW_HEIGHT + 6, 60, 15)];
|
||||
[_swatchLabel setStringValue: "Swatches:"];
|
||||
var _swatchLabel = [[CPTextField alloc] initWithFrame:CGRectMake(10, TOOLBAR_HEIGHT + 8 + PREVIEW_HEIGHT + 6, 60, 15)];
|
||||
[_swatchLabel setStringValue:"Swatches:"];
|
||||
[_swatchLabel setTextColor:[CPColor blackColor]];
|
||||
[_swatchLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
|
||||
var opacityLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 35, 60, 20)];
|
||||
[opacityLabel setStringValue: "Opacity:"];
|
||||
var opacityLabel = [[CPTextField alloc] initWithFrame:CGRectMake(10, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 35, 60, 20)];
|
||||
[opacityLabel setStringValue:"Opacity:"];
|
||||
[opacityLabel setTextColor:[CPColor blackColor]];
|
||||
[opacityLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
@@ -389,7 +393,7 @@ CPColorPickerViewHeight = 370;
|
||||
_action = nil;
|
||||
_activePicker = nil;
|
||||
|
||||
[_previewView setBackgroundColor: _color];
|
||||
[_previewView setBackgroundColor:_color];
|
||||
|
||||
if (buttonForLater)
|
||||
[self _setPicker:buttonForLater];
|
||||
@@ -407,28 +411,29 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
|
||||
CPColorDragType = "CPColorDragType";
|
||||
|
||||
var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
/* @ignore */
|
||||
@implementation _CPColorPanelSwatches : CPView
|
||||
{
|
||||
CPView[] _swatches;
|
||||
CPArray _swatches;
|
||||
CPColor _dragColor;
|
||||
CPColorPanel _colorPanel;
|
||||
CPCookie _swatchCookie;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
[self setBackgroundColor: [CPColor grayColor]];
|
||||
[self setBackgroundColor:[CPColor grayColor]];
|
||||
|
||||
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
|
||||
|
||||
var whiteColor = [CPColor whiteColor];
|
||||
|
||||
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
|
||||
_swatchCookie = [[CPCookie alloc] initWithName:CPColorPanelSwatchesCookie];
|
||||
var colorList = [self startingColorList];
|
||||
|
||||
_swatches = [];
|
||||
@@ -436,15 +441,15 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
for (var i = 0; i < 50; i++)
|
||||
{
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var view = [[CPView alloc] initWithFrame: CPRectMake(13 * i + 1, 1, 12, 12)],
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMake(13 * i + 1, 1, 12, 12)],
|
||||
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
|
||||
|
||||
[view setBackgroundColor:whiteColor];
|
||||
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
|
||||
[fillView setBackgroundColor:(i < colorList.length) ? colorList[i] : whiteColor];
|
||||
|
||||
[view addSubview:fillView];
|
||||
|
||||
[self addSubview: view];
|
||||
[self addSubview:view];
|
||||
|
||||
_swatches.push(view);
|
||||
}
|
||||
@@ -461,7 +466,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var cookieValue = [_swatchCookie value];
|
||||
|
||||
if (cookieValue == "")
|
||||
if (!cookieValue)
|
||||
{
|
||||
return [
|
||||
[CPColor blackColor],
|
||||
@@ -480,7 +485,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
result = [];
|
||||
|
||||
for (var i = 0; i < cookieValue.length; i++)
|
||||
result.push([CPColor colorWithHexString: cookieValue[i]]);
|
||||
result.push([CPColor colorWithHexString:cookieValue[i]]);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -495,7 +500,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
var future = new Date();
|
||||
future.setYear(2019);
|
||||
|
||||
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
|
||||
[_swatchCookie setValue:JSON.stringify(result) expires:future domain:nil];
|
||||
}
|
||||
|
||||
- (void)setColorPanel:(CPColorPanel)panel
|
||||
@@ -528,7 +533,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
return NO;
|
||||
|
||||
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
|
||||
[_colorPanel setColor:[self colorAtIndex:FLOOR(point.x / 13)] updatePicker:YES];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
@@ -545,10 +550,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
_dragColor = [[swatch subviews][0] backgroundColor];
|
||||
|
||||
var bounds = CPRectCreateCopy([swatch bounds]);
|
||||
var bounds = CGRectMakeCopy([swatch bounds]);
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
var dragView = [[CPView alloc] initWithFrame:bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
@@ -556,13 +561,13 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
[self dragView: dragView
|
||||
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset: CPPointMake(0.0, 0.0)
|
||||
event: anEvent
|
||||
pasteboard: nil
|
||||
source: self
|
||||
slideBack: YES];
|
||||
[self dragView:dragView
|
||||
at:CGPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset:CGPointMake(0.0, 0.0)
|
||||
event:anEvent
|
||||
pasteboard:nil
|
||||
source:self
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
@@ -580,7 +585,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||
return NO;
|
||||
|
||||
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
|
||||
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex:FLOOR(location.x / 13)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -591,7 +596,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
CPColorPanel _colorPanel;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
@@ -632,10 +637,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
var bounds = CPRectMake(0, 0, 15, 15);
|
||||
var bounds = CGRectMake(0, 0, 15, 15);
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
var dragView = [[CPView alloc] initWithFrame:bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
@@ -643,13 +648,13 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
[self dragView: dragView
|
||||
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset: CPPointMake(0.0, 0.0)
|
||||
event: anEvent
|
||||
pasteboard: nil
|
||||
source: self
|
||||
slideBack: YES];
|
||||
[self dragView:dragView
|
||||
at:CGPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset:CGPointMake(0.0, 0.0)
|
||||
event:anEvent
|
||||
pasteboard:nil
|
||||
source:self
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
|
||||
+56
-46
@@ -24,6 +24,12 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPSlider
|
||||
|
||||
@global CPColorPickerViewWidth
|
||||
@global CPColorPickerViewHeight
|
||||
@global CPWheelColorPickerMode
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -44,10 +50,11 @@
|
||||
*/
|
||||
- (id)initWithPickerMask:(int)aMask colorPanel:(CPColorPanel)aPanel
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
_panel = aPanel;
|
||||
_mask = aMask;
|
||||
if (self = [super init])
|
||||
{
|
||||
_panel = aPanel;
|
||||
_mask = aMask;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -76,7 +83,6 @@
|
||||
*/
|
||||
- (void)setMode:(CPColorPanelMode)mode
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -85,7 +91,6 @@
|
||||
*/
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -110,7 +115,7 @@
|
||||
|
||||
- (id)initView
|
||||
{
|
||||
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
var aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
|
||||
_pickerView = [[CPView alloc] initWithFrame:aFrame];
|
||||
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
@@ -128,9 +133,9 @@
|
||||
[_brightnessSlider setAction:@selector(brightnessSliderDidChange:)];
|
||||
[_brightnessSlider setAutoresizingMask:CPViewWidthSizable | CPViewMinYMargin];
|
||||
|
||||
_hueSaturationView = [[__CPColorWheel alloc] initWithFrame: CPRectMake(0, 0, aFrame.size.width, aFrame.size.height - 38)];
|
||||
[_hueSaturationView setDelegate: self];
|
||||
[_hueSaturationView setAutoresizingMask: (CPViewWidthSizable | CPViewHeightSizable)];
|
||||
_hueSaturationView = [[__CPColorWheel alloc] initWithFrame:CGRectMake(0, 0, aFrame.size.width, aFrame.size.height - 38)];
|
||||
[_hueSaturationView setDelegate:self];
|
||||
[_hueSaturationView setAutoresizingMask:(CPViewWidthSizable | CPViewHeightSizable)];
|
||||
|
||||
[_pickerView addSubview:_hueSaturationView];
|
||||
[_pickerView addSubview:_brightnessSlider];
|
||||
@@ -153,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];
|
||||
}
|
||||
@@ -189,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
|
||||
@@ -223,60 +228,64 @@
|
||||
float _radius;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
var path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel.png"];
|
||||
|
||||
_wheelImage = new Image();
|
||||
_wheelImage.src = path;
|
||||
_wheelImage.style.position = "absolute";
|
||||
|
||||
path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel_black.png"];
|
||||
|
||||
_blackWheelImage = new Image();
|
||||
_blackWheelImage.src = path;
|
||||
_blackWheelImage.style.opacity = "0";
|
||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
||||
_blackWheelImage.style.position = "absolute";
|
||||
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.appendChild(_wheelImage);
|
||||
_DOMElement.appendChild(_blackWheelImage);
|
||||
var path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel.png"];
|
||||
|
||||
_wheelImage = new Image();
|
||||
_wheelImage.src = path;
|
||||
_wheelImage.style.position = "absolute";
|
||||
|
||||
path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel_black.png"];
|
||||
|
||||
_blackWheelImage = new Image();
|
||||
_blackWheelImage.src = path;
|
||||
_blackWheelImage.style.opacity = "0";
|
||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
||||
_blackWheelImage.style.position = "absolute";
|
||||
|
||||
_DOMElement.appendChild(_wheelImage);
|
||||
_DOMElement.appendChild(_blackWheelImage);
|
||||
#endif
|
||||
|
||||
[self setWheelSize:aFrame.size];
|
||||
[self setWheelSize:aFrame.size];
|
||||
|
||||
_crosshair = [[CPView alloc] initWithFrame:CPRectMake(_radius - 2, _radius - 2, 4, 4)];
|
||||
[_crosshair setBackgroundColor:[CPColor blackColor]];
|
||||
_crosshair = [[CPView alloc] initWithFrame:CGRectMake(_radius - 2, _radius - 2, 4, 4)];
|
||||
[_crosshair setBackgroundColor:[CPColor blackColor]];
|
||||
|
||||
var view = [[CPView alloc] initWithFrame:CGRectInset([_crosshair bounds], 1.0, 1.0)];
|
||||
[view setBackgroundColor:[CPColor whiteColor]];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectInset([_crosshair bounds], 1.0, 1.0)];
|
||||
[view setBackgroundColor:[CPColor whiteColor]];
|
||||
|
||||
[_crosshair addSubview:view];
|
||||
[_crosshair addSubview:view];
|
||||
|
||||
[self addSubview:_crosshair];
|
||||
[self addSubview:_crosshair];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setWheelBrightness:(float)brightness
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_blackWheelImage.style.opacity = 1.0 - brightness;
|
||||
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness) * 100 + ")"
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
[self setWheelSize:aSize];
|
||||
}
|
||||
|
||||
- (void)setWheelSize:(CPSize)aSize
|
||||
- (void)setWheelSize:(CGSize)aSize
|
||||
{
|
||||
var min = MIN(aSize.width, aSize.height);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_blackWheelImage.style.width = min;
|
||||
_blackWheelImage.style.height = min;
|
||||
_blackWheelImage.width = min;
|
||||
@@ -290,6 +299,7 @@
|
||||
_wheelImage.height = min;
|
||||
_wheelImage.style.top = (aSize.height - min) / 2.0 + "px";
|
||||
_wheelImage.style.left = (aSize.width - min) / 2.0 + "px";
|
||||
#endif
|
||||
|
||||
_radius = min / 2.0;
|
||||
|
||||
@@ -349,15 +359,15 @@
|
||||
_angle = [self radiansToDegrees:angle];
|
||||
_distance = (distance / _radius) * 100.0;
|
||||
|
||||
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
|
||||
[_crosshair setFrameOrigin:CGPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
|
||||
}
|
||||
|
||||
- (void)setPositionToColor:(CPColor)aColor
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* CPColorSpace.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2012, SlevenBits Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
var sRGBColorSpace = nil;
|
||||
|
||||
/*!
|
||||
Represent color spaces.
|
||||
*/
|
||||
@implementation CPColorSpace : CPObject
|
||||
{
|
||||
CGColorSpace _cgColorSpace;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return an object representing the standard sRGB color space.
|
||||
*/
|
||||
+ (CPColorSpace)sRGBColorSpace
|
||||
{
|
||||
if (!sRGBColorSpace)
|
||||
sRGBColorSpace = [[self alloc] initWithCGColorSpace:CGColorSpaceCreateDeviceRGB()];
|
||||
return sRGBColorSpace;
|
||||
}
|
||||
|
||||
- (id)initWithCGColorSpace:(CGColorSpace)cgColorSpace
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_cgColorSpace = cgColorSpace;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a Core Graphics color space representing the receiver.
|
||||
*/
|
||||
- (CGColorSpace)CGColorSpace
|
||||
{
|
||||
return _cgColorSpace;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+149
-78
@@ -43,7 +43,38 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
BOOL _bordered;
|
||||
|
||||
CPColor _color;
|
||||
CPView _wellView;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return [CPColorWellValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"colorwell";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
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
|
||||
{
|
||||
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
|
||||
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
|
||||
|
||||
[theBinding reverseSetValueFor:@"color"];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -53,11 +84,8 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
if (self)
|
||||
{
|
||||
_active = NO;
|
||||
_bordered = YES;
|
||||
_color = [CPColor whiteColor];
|
||||
|
||||
[self drawBezelWithHighlight:NO];
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
[self setBordered:YES];
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
@@ -82,25 +110,23 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
object:[CPColorPanel sharedColorPanel]];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the color well is bordered.
|
||||
*/
|
||||
- (void)setBordered:(BOOL)shouldBeBordered
|
||||
{
|
||||
if (shouldBeBordered)
|
||||
[self setThemeState:CPThemeStateBordered];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateBordered];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the color well is bordered
|
||||
*/
|
||||
- (BOOL)isBordered
|
||||
{
|
||||
return _bordered;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the color well's current color.
|
||||
*/
|
||||
- (void)setBordered:(BOOL)bordered
|
||||
{
|
||||
if (_bordered == bordered)
|
||||
return;
|
||||
|
||||
_bordered = bordered;
|
||||
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
return [self hasThemeState:CPThemeStateBordered];
|
||||
}
|
||||
|
||||
// Managing Color From Color Wells
|
||||
@@ -123,7 +149,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
_color = aColor;
|
||||
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -186,31 +212,6 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
return _active;
|
||||
}
|
||||
|
||||
// Drawing a Color Well
|
||||
|
||||
- (void)drawBezelWithHighlight:(BOOL)shouldHighlight
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Draws the colored area inside the color well without borders.
|
||||
@param aRect the location at which to draw
|
||||
*/
|
||||
- (void)drawWellInside:(CGRect)aRect
|
||||
{
|
||||
if (!_wellView)
|
||||
{
|
||||
_wellView = [[CPView alloc] initWithFrame:aRect];
|
||||
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[self addSubview:_wellView];
|
||||
}
|
||||
else
|
||||
[_wellView setFrame:aRect];
|
||||
|
||||
[_wellView setBackgroundColor:_color];
|
||||
}
|
||||
|
||||
- (void)colorPanelDidChangeColor:(CPNotification)aNotification
|
||||
{
|
||||
[self takeColorFrom:[aNotification object]];
|
||||
@@ -229,27 +230,11 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
[self deactivate];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
[self highlight:NO];
|
||||
|
||||
[self drawBezelWithHighlight:YES];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
[self drawBezelWithHighlight:NO];
|
||||
|
||||
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
|
||||
if (!mouseIsUp || !CGRectContainsPoint([self bounds], aPoint) || ![self isEnabled])
|
||||
return;
|
||||
|
||||
[self activate:YES];
|
||||
@@ -260,6 +245,104 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
[colorPanel orderFront:self];
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return CGRectInsetByInset(bounds, contentInset);
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
return CGRectInsetByInset(bounds, bezelInset);
|
||||
}
|
||||
|
||||
- (CGRect)contentBorderRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
|
||||
|
||||
return CGRectInsetByInset(bounds, contentBorderInset);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
switch (aName)
|
||||
{
|
||||
case "bezel-view":
|
||||
return [self bezelRectForBounds:[self bounds]];
|
||||
case "content-view":
|
||||
return [self contentRectForBounds:[self bounds]];
|
||||
case "content-border-view":
|
||||
return [self contentBorderRectForBounds:[self bounds]];
|
||||
}
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
||||
|
||||
|
||||
[contentView setBackgroundColor:_color];
|
||||
|
||||
var contentBorderView = [self layoutEphemeralSubviewNamed:@"content-border-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
[contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPColorWellValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var placeholderColor = [CPColor blackColor];
|
||||
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source color];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)theBinding
|
||||
{
|
||||
[_source setColor:aValue];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setColor:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
@@ -278,11 +361,8 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
if (self)
|
||||
{
|
||||
_active = NO;
|
||||
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
|
||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||
|
||||
[self drawBezelWithHighlight:NO];
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
[self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
@@ -296,19 +376,10 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// We do this in order to avoid encoding the _wellView, which
|
||||
// should just automatically be created programmatically as needed.
|
||||
var actualSubviews = _subviews;
|
||||
|
||||
_subviews = [_subviews copy];
|
||||
[_subviews removeObjectIdenticalTo:_wellView];
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
_subviews = actualSubviews;
|
||||
|
||||
[aCoder encodeObject:_color forKey:CPColorWellColorKey];
|
||||
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
|
||||
[aCoder encodeObject:[self isBordered] forKey:CPColorWellBorderedKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+1198
File diff suppressed because it is too large
Load Diff
+214
-51
@@ -20,7 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPEvent.j"
|
||||
@import "CPEvent_Constants.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
|
||||
@@ -38,42 +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 = 28;
|
||||
|
||||
// Input elements have 1 px of extra padding on the left regardless of padding setting.
|
||||
CPInput1PxLeftPadding = 29;
|
||||
CPInputOnInputEventFeature = 30;
|
||||
|
||||
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[CPInputTypeCanBeChangedFeature] = YES;
|
||||
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
||||
|
||||
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
@@ -83,7 +99,7 @@ if (typeof window !== "undefined" && window.opera)
|
||||
{
|
||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
}
|
||||
|
||||
// Internet Explorer
|
||||
@@ -92,13 +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] = NO;
|
||||
}
|
||||
|
||||
// WebKit
|
||||
@@ -107,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),
|
||||
@@ -125,18 +144,26 @@ 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] = 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)
|
||||
PLATFORM_BUGS |= CPCanvasParentDrawErrorsOnMovementBug;
|
||||
}
|
||||
|
||||
// KHTML
|
||||
@@ -150,46 +177,79 @@ 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] = 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] = YES;
|
||||
else if (typeof DOMInputElement.setAttribute === "function")
|
||||
{
|
||||
DOMInputElement.setAttribute("oninput", "return;");
|
||||
|
||||
if (typeof DOMInputElement.oninput === "function")
|
||||
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)
|
||||
{
|
||||
return PLATFORM_BUGS & aBug;
|
||||
}
|
||||
|
||||
function CPBrowserIsEngine(anEngine)
|
||||
@@ -229,3 +289,106 @@ else
|
||||
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the properly prefixed JS property for the given name. E.g. in a webkit browser,
|
||||
CPBrowserStyleProperty('transition') -> WebkitTransition
|
||||
|
||||
While technically not a style property, style related event handler names are also supported.
|
||||
CPBrowserStyleProperty('transitionend') -> 'webkitTransitionEnd'
|
||||
|
||||
CSS is only available in platform(dom), so don't rely too heavily on it.
|
||||
*/
|
||||
function CPBrowserStyleProperty(aProperty)
|
||||
{
|
||||
var lowerProperty = aProperty.toLowerCase();
|
||||
|
||||
if (PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] === undefined)
|
||||
{
|
||||
var r = nil;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var testElement = document.createElement('div');
|
||||
|
||||
switch (lowerProperty)
|
||||
{
|
||||
case 'transitionend':
|
||||
var candidates = {
|
||||
'WebkitTransition' : 'webkitTransitionEnd',
|
||||
'MozTransition' : 'transitionend',
|
||||
'OTransition' : 'oTransitionEnd',
|
||||
'msTransition' : 'MSTransitionEnd',
|
||||
'transition' : 'transitionend'
|
||||
};
|
||||
|
||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil;
|
||||
break;
|
||||
default:
|
||||
var prefixes = ["Webkit", "Moz", "O", "ms"],
|
||||
strippedProperty = aProperty.split('-').join(' '),
|
||||
capProperty = [strippedProperty capitalizedString].split(' ').join('');
|
||||
|
||||
for (var i = 0; i < prefixes.length; i++)
|
||||
{
|
||||
// First check if the property is already valid without being formatted, otherwise try the capitalized property
|
||||
if (prefixes[i] + aProperty in testElement.style)
|
||||
{
|
||||
r = prefixes[i] + aProperty;
|
||||
break;
|
||||
}
|
||||
else if (prefixes[i] + capProperty in testElement.style)
|
||||
{
|
||||
r = prefixes[i] + capProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!r && lowerProperty in testElement.style)
|
||||
r = lowerProperty;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] = r;
|
||||
}
|
||||
|
||||
return PLATFORM_STYLE_JS_PROPERTIES[lowerProperty];
|
||||
}
|
||||
|
||||
function CPBrowserCSSProperty(aProperty)
|
||||
{
|
||||
var browserProperty = CPBrowserStyleProperty(aProperty);
|
||||
|
||||
if (!browserProperty)
|
||||
return nil;
|
||||
|
||||
var prefixes = {
|
||||
'Webkit': '-webkit-',
|
||||
'Moz': '-moz-',
|
||||
'O': '-o-',
|
||||
'ms': '-ms-'
|
||||
};
|
||||
|
||||
for (var prefix in prefixes)
|
||||
{
|
||||
if (browserProperty.substring(0, prefix.length) == prefix)
|
||||
{
|
||||
var browserPropertyWithoutPrefix = browserProperty.substring(prefix.length),
|
||||
parts = browserPropertyWithoutPrefix.match(/[A-Z][a-z]+/g);
|
||||
|
||||
// If there were any capitalized words in the browserProperty, insert a "-" between each one
|
||||
if (parts && parts.length > 0)
|
||||
browserPropertyWithoutPrefix = parts.join("-");
|
||||
|
||||
return prefixes[prefix] + browserPropertyWithoutPrefix.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
var parts = browserProperty.match(/[A-Z][a-z]+/g);
|
||||
|
||||
if (parts && parts.length > 0)
|
||||
browserProperty = parts.join("-");
|
||||
|
||||
return browserProperty.toLowerCase();
|
||||
}
|
||||
|
||||
+144
-91
@@ -20,47 +20,58 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPFormatter.j>
|
||||
@import <Foundation/CPTimer.j>
|
||||
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
CPJustifiedTextAlignment = 3;
|
||||
CPNaturalTextAlignment = 4;
|
||||
@global CPApp
|
||||
|
||||
CPRegularControlSize = 0;
|
||||
CPSmallControlSize = 1;
|
||||
CPMiniControlSize = 2;
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
CPJustifiedTextAlignment = 3;
|
||||
CPNaturalTextAlignment = 4;
|
||||
|
||||
CPLineBreakByWordWrapping = 0;
|
||||
CPLineBreakByCharWrapping = 1;
|
||||
CPLineBreakByClipping = 2;
|
||||
CPLineBreakByTruncatingHead = 3;
|
||||
CPLineBreakByTruncatingTail = 4;
|
||||
CPLineBreakByTruncatingMiddle = 5;
|
||||
CPRegularControlSize = 0;
|
||||
CPSmallControlSize = 1;
|
||||
CPMiniControlSize = 2;
|
||||
|
||||
CPTopVerticalTextAlignment = 1;
|
||||
CPCenterVerticalTextAlignment = 2;
|
||||
CPBottomVerticalTextAlignment = 3;
|
||||
CPLineBreakByWordWrapping = 0;
|
||||
CPLineBreakByCharWrapping = 1;
|
||||
CPLineBreakByClipping = 2;
|
||||
CPLineBreakByTruncatingHead = 3;
|
||||
CPLineBreakByTruncatingTail = 4;
|
||||
CPLineBreakByTruncatingMiddle = 5;
|
||||
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
CPTopVerticalTextAlignment = 1;
|
||||
CPCenterVerticalTextAlignment = 2;
|
||||
CPBottomVerticalTextAlignment = 3;
|
||||
|
||||
CPNoImage = 0;
|
||||
CPImageOnly = 1;
|
||||
CPImageLeft = 2;
|
||||
CPImageRight = 3;
|
||||
CPImageBelow = 4;
|
||||
CPImageAbove = 5;
|
||||
CPImageOverlaps = 6;
|
||||
// Deprecated for use with images, use the CPImageScale constants
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
|
||||
CPOnState = 1;
|
||||
CPOffState = 0;
|
||||
CPMixedState = -1;
|
||||
CPImageScaleProportionallyDown = 0;
|
||||
CPImageScaleAxesIndependently = 1;
|
||||
CPImageScaleNone = 2;
|
||||
CPImageScaleProportionallyUpOrDown = 3;
|
||||
|
||||
CPNoImage = 0;
|
||||
CPImageOnly = 1;
|
||||
CPImageLeft = 2;
|
||||
CPImageRight = 3;
|
||||
CPImageBelow = 4;
|
||||
CPImageAbove = 5;
|
||||
CPImageOverlaps = 6;
|
||||
|
||||
CPOnState = 1;
|
||||
CPOffState = 0;
|
||||
CPMixedState = -1;
|
||||
|
||||
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
|
||||
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
|
||||
@@ -82,6 +93,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
CPFormatter _formatter @accessors(property=formatter);
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
@@ -98,52 +110,45 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPLeftTextAlignment,
|
||||
CPTopVerticalTextAlignment,
|
||||
CPLineBreakByClipping,
|
||||
[CPColor blackColor],
|
||||
[CPFont systemFontOfSize:12.0],
|
||||
[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
|
||||
{
|
||||
if (self === [CPControl class])
|
||||
{
|
||||
[self exposeBinding:@"value"];
|
||||
[self exposeBinding:@"objectValue"];
|
||||
[self exposeBinding:@"stringValue"];
|
||||
[self exposeBinding:@"integerValue"];
|
||||
[self exposeBinding:@"intValue"];
|
||||
[self exposeBinding:@"doubleValue"];
|
||||
[self exposeBinding:@"floatValue"];
|
||||
if (self !== [CPControl class])
|
||||
return;
|
||||
|
||||
[self exposeBinding:@"enabled"];
|
||||
}
|
||||
[self exposeBinding:@"value"];
|
||||
[self exposeBinding:@"objectValue"];
|
||||
[self exposeBinding:@"stringValue"];
|
||||
[self exposeBinding:@"integerValue"];
|
||||
[self exposeBinding:@"intValue"];
|
||||
[self exposeBinding:@"doubleValue"];
|
||||
[self exposeBinding:@"floatValue"];
|
||||
|
||||
[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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -221,10 +226,14 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@param anAction the action to send
|
||||
@param anObject the object to which the action will be sent
|
||||
*/
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
|
||||
var binding = [CPBinder getBinding:CPTargetBinding forObject:self];
|
||||
[binding invokeAction];
|
||||
|
||||
return [CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
- (int)sendActionOn:(int)mask
|
||||
@@ -380,7 +389,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self highlight:NO];
|
||||
if (mouseIsUp)
|
||||
[self highlight:NO];
|
||||
else
|
||||
[self highlight:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Enabled controls accept first mouse by default.
|
||||
*/
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
{
|
||||
return [self isEnabled];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
@@ -502,15 +522,46 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
if (_formatter && _value !== undefined)
|
||||
{
|
||||
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
||||
|
||||
if (formattedValue !== nil && formattedValue !== undefined)
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's string value.
|
||||
*/
|
||||
- (void)setStringValue:(CPString)anObject
|
||||
- (void)setStringValue:(CPString)aString
|
||||
{
|
||||
[self setObjectValue:anObject];
|
||||
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
||||
if (aString === nil || aString === undefined)
|
||||
{
|
||||
CPLog.warn("nil or undefined sent to CPControl -setStringValue");
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
if (_formatter)
|
||||
{
|
||||
value = nil;
|
||||
|
||||
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:@ref(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined; // Means the value is invalid
|
||||
}
|
||||
}
|
||||
else
|
||||
value = aString;
|
||||
|
||||
[self setObjectValue:value];
|
||||
}
|
||||
|
||||
- (void)takeDoubleValueFrom:(id)sender
|
||||
@@ -526,21 +577,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setFloatValue:[sender floatValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntegerValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(integerValue)])
|
||||
[self setIntegerValue:[sender integerValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(intValue)])
|
||||
[self setIntValue:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeObjectValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(objectValue)])
|
||||
@@ -559,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
|
||||
@@ -568,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
|
||||
@@ -579,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] }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -751,9 +799,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
Sets the image scaling of the control.
|
||||
|
||||
<pre>
|
||||
CPScaleProportionally
|
||||
CPScaleToFit
|
||||
CPScaleNone
|
||||
CPImageScaleProportionallyDown
|
||||
CPImageScaleAxesIndependently
|
||||
CPImageScaleNone
|
||||
CPImageScaleProportionallyUpOrDown
|
||||
</pre>
|
||||
*/
|
||||
- (void)setImageScaling:(CPImageScaling)scaling
|
||||
@@ -824,17 +873,16 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
@end
|
||||
|
||||
var CPControlValueKey = "CPControlValueKey",
|
||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||
CPControlIsEnabledKey = "CPControlIsEnabledKey",
|
||||
var CPControlValueKey = @"CPControlValueKey",
|
||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||
CPControlIsEnabledKey = @"CPControlIsEnabledKey",
|
||||
CPControlTargetKey = @"CPControlTargetKey",
|
||||
CPControlActionKey = @"CPControlActionKey",
|
||||
CPControlSendActionOnKey = @"CPControlSendActionOnKey",
|
||||
CPControlFormatterKey = @"CPControlFormatterKey",
|
||||
CPControlSendsActionOnEndEditingKey = @"CPControlSendsActionOnEndEditingKey",
|
||||
|
||||
CPControlTargetKey = "CPControlTargetKey",
|
||||
CPControlActionKey = "CPControlActionKey",
|
||||
CPControlSendActionOnKey = "CPControlSendActionOnKey",
|
||||
|
||||
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
|
||||
|
||||
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
__Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
|
||||
@implementation CPControl (CPCoding)
|
||||
|
||||
@@ -857,6 +905,8 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
|
||||
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
||||
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||
|
||||
[self setFormatter:[aCoder decodeObjectForKey:CPControlFormatterKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -882,10 +932,13 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
if (_target !== nil)
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
|
||||
if (_action !== NULL)
|
||||
if (_action !== nil)
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||
|
||||
if (_formatter !== nil)
|
||||
[aCoder encodeObject:_formatter forKey:CPControlFormatterKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -64,7 +64,7 @@ var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
|
||||
count = _editors.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
if (![[_editors objectAtIndex:i] commitEditing])
|
||||
if (![[_editors objectAtIndex:index] commitEditing])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
|
||||
+7
-3
@@ -94,7 +94,7 @@
|
||||
domain = "";
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||
document.cookie = _cookieName + "=" + value + expires + "; path=/" + domain;
|
||||
#else
|
||||
_cookieValue = value;
|
||||
_expires = expires;
|
||||
@@ -111,8 +111,12 @@
|
||||
for (var i = 0; i < ca.length; i++)
|
||||
{
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
|
||||
while (c.charAt(0) == ' ')
|
||||
c = c.substring(1, c.length);
|
||||
|
||||
if (c.indexOf(nameEQ) == 0)
|
||||
return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
|
||||
+94
-11
@@ -23,9 +23,12 @@ Cursor support by browser:
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@global CPApp
|
||||
|
||||
var currentCursor = nil,
|
||||
cursorStack = [],
|
||||
cursors = {};
|
||||
cursors = {},
|
||||
ieCursorMap = {};
|
||||
|
||||
@implementation CPCursor : CPObject
|
||||
{
|
||||
@@ -36,6 +39,20 @@ var currentCursor = nil,
|
||||
BOOL _isSetOnMouseExited @accessors(readwrite, getter=isSetOnMouseExited, setter=setOnMouseExited:);
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== CPCursor)
|
||||
return;
|
||||
|
||||
// IE < 9 does not support some CSS cursors, we map them to supported ones
|
||||
ieCursorMap = {
|
||||
"ew-resize": "e-resize",
|
||||
"ns-resize": "n-resize",
|
||||
"nesw-resize": "ne-resize",
|
||||
"nwse-resize": "nw-resize"
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithCSSString:(CPString)aString
|
||||
{
|
||||
if (self = [super init])
|
||||
@@ -44,23 +61,30 @@ var currentCursor = nil,
|
||||
return self;
|
||||
}
|
||||
|
||||
// hotspot is supported in CSS3 (but not IE).
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||
/*!
|
||||
Init a cursor with the given image and hotspot.
|
||||
hotspot is supported in CSS3 (but not IE).
|
||||
*/
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CGPoint)hotSpot
|
||||
{
|
||||
_hotSpot = hotSpot;
|
||||
_image = image;
|
||||
return [self initWithCSSString:"url(" + [_image filename] + ")" + hotSpot.x + " " + hotSpot.y + ", auto"];
|
||||
}
|
||||
|
||||
// foregroundColor and backgroundColor are ignored in Cocoa as well. See http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSCursor_Class/Reference/Reference.html
|
||||
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CPPoint)aHotSpot
|
||||
/*!
|
||||
Init a cursor with the given image and hotspot. This is provided
|
||||
for compliance with Cocoa. Note that foregroundColor and backgroundColor are ignored
|
||||
(as they are in Cocoa). See http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSCursor_Class/Reference/Reference.html
|
||||
*/
|
||||
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CGPoint)aHotSpot
|
||||
{
|
||||
return [self initWithImage:image hotSpot:hotSpot];
|
||||
return [self initWithImage:image hotSpot:aHotSpot];
|
||||
}
|
||||
|
||||
+ (void)hide
|
||||
{
|
||||
[self _setCursorCSS:"none"]; // Not supported in IE
|
||||
[self _setCursorCSS:@"none"]; // Not supported in IE < 9
|
||||
}
|
||||
|
||||
+ (void)unhide
|
||||
@@ -121,6 +145,7 @@ var currentCursor = nil,
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
|
||||
|
||||
for (var i = 0, count = [platformWindows count]; i < count; i++)
|
||||
platformWindows[i]._DOMBodyElement.style.cursor = aString;
|
||||
#endif
|
||||
@@ -130,22 +155,40 @@ var currentCursor = nil,
|
||||
+ (CPCursor)_systemCursorWithName:(CPString)cursorName cssString:(CPString)aString hasImage:(BOOL)doesHaveImage
|
||||
{
|
||||
var cursor = cursors[cursorName];
|
||||
if (typeof cursor === 'undefined')
|
||||
|
||||
if (typeof cursor === "undefined")
|
||||
{
|
||||
var cssString;
|
||||
|
||||
if (doesHaveImage)
|
||||
cssString = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/" + cursorName + ".cur), " + aString;
|
||||
{
|
||||
var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath],
|
||||
extension = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) ? @"cur" : @"png";
|
||||
|
||||
cssString = [CPString stringWithFormat:@"url(%@cursors/%@.%@), %@", themeResourcePath, cursorName, extension, aString];
|
||||
}
|
||||
|
||||
else
|
||||
cssString = aString
|
||||
{
|
||||
// IE <= 8 does not support some cursors, map them to supported cursors
|
||||
var ieLessThan9 = CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !CPFeatureIsCompatible(CPHTMLCanvasFeature);
|
||||
|
||||
if (ieLessThan9)
|
||||
cssString = ieCursorMap[aString] || aString;
|
||||
else
|
||||
cssString = aString;
|
||||
}
|
||||
|
||||
cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||
cursors[cursorName] = cursor;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
+ (CPCursor)arrowCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:"default" hasImage:NO];
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"default" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)crosshairCursor
|
||||
@@ -163,6 +206,36 @@ var currentCursor = nil,
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeNorthwestCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nw-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeNorthwestSoutheastCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nwse-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeNortheastCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ne-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeNortheastSouthwestCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nesw-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeSouthwestCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"sw-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeSoutheastCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"se-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeDownCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize" hasImage:NO];
|
||||
@@ -188,11 +261,21 @@ var currentCursor = nil,
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeEastWestCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ew-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpDownCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeNorthSouthCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ns-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)operationNotAllowedCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed" hasImage:NO];
|
||||
|
||||
@@ -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
|
||||
+10
-6
@@ -23,12 +23,16 @@
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPAlert.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPSavePanel.j"
|
||||
@import "CPViewController.j"
|
||||
@import "CPWindowController.j"
|
||||
|
||||
@class CPDocumentController
|
||||
|
||||
@global CPApp
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@@ -125,7 +129,7 @@ var CPDocumentUntitledCount = 0;
|
||||
if (self)
|
||||
{
|
||||
_windowControllers = [];
|
||||
_viewControllersForWindowControllers = [CPDictionary dictionary];
|
||||
_viewControllersForWindowControllers = @{};
|
||||
|
||||
_hasUndoManager = YES;
|
||||
_changeCount = 0;
|
||||
@@ -142,7 +146,7 @@ var CPDocumentUntitledCount = 0;
|
||||
@param anError not used
|
||||
@return the initialized document
|
||||
*/
|
||||
- (id)initWithType:(CPString)aType error:({CPError})anError
|
||||
- (id)initWithType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
@@ -211,7 +215,7 @@ var CPDocumentUntitledCount = 0;
|
||||
@throws CPUnsupportedMethodException if this method hasn't been overridden by the subclass
|
||||
@return the document data
|
||||
*/
|
||||
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
|
||||
- (CPData)dataOfType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||
{
|
||||
[CPException raise:CPUnsupportedMethodException
|
||||
reason:"dataOfType:error: must be overridden by the document subclass."];
|
||||
@@ -922,9 +926,9 @@ var CPDocumentUntitledCount = 0;
|
||||
var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
|
||||
{
|
||||
return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
|
||||
}
|
||||
};
|
||||
|
||||
var _CPSaveSessionMake = function(anAbsoluteURL, aSaveOperation, aChangeCount, aDelegate, aDidSaveSelector, aContextInfo, aConnection)
|
||||
{
|
||||
return { absoluteURL:anAbsoluteURL, saveOperation:aSaveOperation, changeCount:aChangeCount, delegate:aDelegate, didSaveSelector:aDidSaveSelector, contextInfo:aContextInfo, connection:aConnection };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
|
||||
@import "CPDocument.j"
|
||||
@import "CPOpenPanel.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPWindowController.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
|
||||
var CPSharedDocumentController = nil;
|
||||
@@ -124,7 +128,7 @@ var CPSharedDocumentController = nil;
|
||||
@param anError not used
|
||||
@return the created document
|
||||
*/
|
||||
- (CPDocument)makeUntitledDocumentOfType:(CPString)aType error:({CPError})anError
|
||||
- (CPDocument)makeUntitledDocumentOfType:(CPString)aType error:(/*{*/CPError/*}*/)anError
|
||||
{
|
||||
return [[[self documentClassForType:aType] alloc] initWithType:aType error:anError];
|
||||
}
|
||||
@@ -144,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];
|
||||
|
||||
@@ -339,10 +343,10 @@ var CPSharedDocumentController = nil;
|
||||
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
|
||||
{
|
||||
var context = {
|
||||
delegate: aDelegate,
|
||||
selector: didCloseSelector,
|
||||
context: info
|
||||
};
|
||||
delegate: aDelegate,
|
||||
selector: didCloseSelector,
|
||||
context: info
|
||||
};
|
||||
|
||||
[self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
|
||||
}
|
||||
|
||||
+37
-64
@@ -20,22 +20,17 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPDragServer_Constants.j"
|
||||
@import "CPEvent.j"
|
||||
@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
|
||||
|
||||
CPDragOperationNone = 0;
|
||||
CPDragOperationCopy = 1 << 1;
|
||||
CPDragOperationLink = 1 << 1;
|
||||
CPDragOperationGeneric = 1 << 2;
|
||||
CPDragOperationPrivate = 1 << 3;
|
||||
CPDragOperationMove = 1 << 4;
|
||||
CPDragOperationDelete = 1 << 5;
|
||||
CPDragOperationEvery = -1;
|
||||
@global CPApp
|
||||
|
||||
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
||||
|
||||
@@ -72,7 +67,7 @@ var CPDragServerSource = nil,
|
||||
- (unsigned)draggingSourceOperationMask
|
||||
*/
|
||||
|
||||
- (CPPoint)draggingLocation
|
||||
- (CGPoint)draggingLocation
|
||||
{
|
||||
return [[CPDragServer sharedDragServer] draggingLocation];
|
||||
}
|
||||
@@ -168,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];
|
||||
}
|
||||
@@ -206,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];
|
||||
@@ -253,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;
|
||||
@@ -270,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)
|
||||
@@ -282,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];
|
||||
@@ -370,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];
|
||||
|
||||
@@ -434,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];
|
||||
|
||||
@@ -461,6 +465,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
else if (type === CPKeyDown)
|
||||
{
|
||||
var characters = [anEvent characters];
|
||||
|
||||
if (characters === CPEscapeFunctionKey)
|
||||
{
|
||||
_dragOperation = CPDragOperationNone;
|
||||
@@ -477,39 +482,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
||||
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
|
||||
untilDate:nil inMode:0 dequeue:NO];
|
||||
}
|
||||
|
||||
@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;
|
||||
untilDate:nil inMode:0 dequeue:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* CPDragServer_Constants.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPDragOperationNone = 0;
|
||||
CPDragOperationCopy = 1 << 1;
|
||||
CPDragOperationLink = 1 << 1;
|
||||
CPDragOperationGeneric = 1 << 2;
|
||||
CPDragOperationPrivate = 1 << 3;
|
||||
CPDragOperationMove = 1 << 4;
|
||||
CPDragOperationDelete = 1 << 5;
|
||||
CPDragOperationEvery = -1;
|
||||
+80
-183
@@ -20,166 +20,24 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPEvent_Constants.j"
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPObjJRuntime.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPCompatibility.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPText.j"
|
||||
|
||||
@class CPTextField
|
||||
|
||||
CPLeftMouseDown = 1;
|
||||
CPLeftMouseUp = 2;
|
||||
CPRightMouseDown = 3;
|
||||
CPRightMouseUp = 4;
|
||||
CPMouseMoved = 5;
|
||||
CPLeftMouseDragged = 6;
|
||||
CPRightMouseDragged = 7;
|
||||
CPMouseEntered = 8;
|
||||
CPMouseExited = 9;
|
||||
CPKeyDown = 10;
|
||||
CPKeyUp = 11;
|
||||
CPFlagsChanged = 12;
|
||||
CPAppKitDefined = 13;
|
||||
CPSystemDefined = 14;
|
||||
CPApplicationDefined = 15;
|
||||
CPPeriodic = 16;
|
||||
CPCursorUpdate = 17;
|
||||
CPScrollWheel = 22;
|
||||
CPOtherMouseDown = 25;
|
||||
CPOtherMouseUp = 26;
|
||||
CPOtherMouseDragged = 27;
|
||||
|
||||
// iPhone Event Types
|
||||
CPTouchStart = 28;
|
||||
CPTouchMove = 29;
|
||||
CPTouchEnd = 30;
|
||||
CPTouchCancel = 31;
|
||||
|
||||
CPAlphaShiftKeyMask = 1 << 16;
|
||||
CPShiftKeyMask = 1 << 17;
|
||||
CPControlKeyMask = 1 << 18;
|
||||
CPAlternateKeyMask = 1 << 19;
|
||||
CPCommandKeyMask = 1 << 20;
|
||||
CPNumericPadKeyMask = 1 << 21;
|
||||
CPHelpKeyMask = 1 << 22;
|
||||
CPFunctionKeyMask = 1 << 23;
|
||||
CPDeviceIndependentModifierFlagsMask = 0xffff0000;
|
||||
|
||||
CPLeftMouseDownMask = 1 << CPLeftMouseDown;
|
||||
CPLeftMouseUpMask = 1 << CPLeftMouseUp;
|
||||
CPRightMouseDownMask = 1 << CPRightMouseDown;
|
||||
CPRightMouseUpMask = 1 << CPRightMouseUp;
|
||||
CPOtherMouseDownMask = 1 << CPOtherMouseDown;
|
||||
CPOtherMouseUpMask = 1 << CPOtherMouseUp;
|
||||
CPMouseMovedMask = 1 << CPMouseMoved;
|
||||
CPLeftMouseDraggedMask = 1 << CPLeftMouseDragged;
|
||||
CPRightMouseDraggedMask = 1 << CPRightMouseDragged;
|
||||
CPOtherMouseDragged = 1 << CPOtherMouseDragged;
|
||||
CPMouseEnteredMask = 1 << CPMouseEntered;
|
||||
CPMouseExitedMask = 1 << CPMouseExited;
|
||||
CPCursorUpdateMask = 1 << CPCursorUpdate;
|
||||
CPKeyDownMask = 1 << CPKeyDown;
|
||||
CPKeyUpMask = 1 << CPKeyUp;
|
||||
CPFlagsChangedMask = 1 << CPFlagsChanged;
|
||||
CPAppKitDefinedMask = 1 << CPAppKitDefined;
|
||||
CPSystemDefinedMask = 1 << CPSystemDefined;
|
||||
CPApplicationDefinedMask = 1 << CPApplicationDefined;
|
||||
CPPeriodicMask = 1 << CPPeriodic;
|
||||
CPScrollWheelMask = 1 << CPScrollWheel;
|
||||
CPAnyEventMask = 0xffffffff;
|
||||
|
||||
CPUpArrowFunctionKey = "\uF700";
|
||||
CPDownArrowFunctionKey = "\uF701";
|
||||
CPLeftArrowFunctionKey = "\uF702";
|
||||
CPRightArrowFunctionKey = "\uF703";
|
||||
CPF1FunctionKey = "\uF704";
|
||||
CPF2FunctionKey = "\uF705";
|
||||
CPF3FunctionKey = "\uF706";
|
||||
CPF4FunctionKey = "\uF707";
|
||||
CPF5FunctionKey = "\uF708";
|
||||
CPF6FunctionKey = "\uF709";
|
||||
CPF7FunctionKey = "\uF70A";
|
||||
CPF8FunctionKey = "\uF70B";
|
||||
CPF9FunctionKey = "\uF70C";
|
||||
CPF10FunctionKey = "\uF70D";
|
||||
CPF11FunctionKey = "\uF70E";
|
||||
CPF12FunctionKey = "\uF70F";
|
||||
CPF13FunctionKey = "\uF710";
|
||||
CPF14FunctionKey = "\uF711";
|
||||
CPF15FunctionKey = "\uF712";
|
||||
CPF16FunctionKey = "\uF713";
|
||||
CPF17FunctionKey = "\uF714";
|
||||
CPF18FunctionKey = "\uF715";
|
||||
CPF19FunctionKey = "\uF716";
|
||||
CPF20FunctionKey = "\uF717";
|
||||
CPF21FunctionKey = "\uF718";
|
||||
CPF22FunctionKey = "\uF719";
|
||||
CPF23FunctionKey = "\uF71A";
|
||||
CPF24FunctionKey = "\uF71B";
|
||||
CPF25FunctionKey = "\uF71C";
|
||||
CPF26FunctionKey = "\uF71D";
|
||||
CPF27FunctionKey = "\uF71E";
|
||||
CPF28FunctionKey = "\uF71F";
|
||||
CPF29FunctionKey = "\uF720";
|
||||
CPF30FunctionKey = "\uF721";
|
||||
CPF31FunctionKey = "\uF722";
|
||||
CPF32FunctionKey = "\uF723";
|
||||
CPF33FunctionKey = "\uF724";
|
||||
CPF34FunctionKey = "\uF725";
|
||||
CPF35FunctionKey = "\uF726";
|
||||
CPInsertFunctionKey = "\uF727";
|
||||
CPDeleteFunctionKey = "\uF728";
|
||||
CPHomeFunctionKey = "\uF729";
|
||||
CPBeginFunctionKey = "\uF72A";
|
||||
CPEndFunctionKey = "\uF72B";
|
||||
CPPageUpFunctionKey = "\uF72C";
|
||||
CPPageDownFunctionKey = "\uF72D";
|
||||
CPPrintScreenFunctionKey = "\uF72E";
|
||||
CPScrollLockFunctionKey = "\uF72F";
|
||||
CPPauseFunctionKey = "\uF730";
|
||||
CPSysReqFunctionKey = "\uF731";
|
||||
CPBreakFunctionKey = "\uF732";
|
||||
CPResetFunctionKey = "\uF733";
|
||||
CPStopFunctionKey = "\uF734";
|
||||
CPMenuFunctionKey = "\uF735";
|
||||
CPUserFunctionKey = "\uF736";
|
||||
CPSystemFunctionKey = "\uF737";
|
||||
CPPrintFunctionKey = "\uF738";
|
||||
CPClearLineFunctionKey = "\uF739";
|
||||
CPClearDisplayFunctionKey = "\uF73A";
|
||||
CPInsertLineFunctionKey = "\uF73B";
|
||||
CPDeleteLineFunctionKey = "\uF73C";
|
||||
CPInsertCharFunctionKey = "\uF73D";
|
||||
CPDeleteCharFunctionKey = "\uF73E";
|
||||
CPPrevFunctionKey = "\uF73F";
|
||||
CPNextFunctionKey = "\uF740";
|
||||
CPSelectFunctionKey = "\uF741";
|
||||
CPExecuteFunctionKey = "\uF742";
|
||||
CPUndoFunctionKey = "\uF743";
|
||||
CPRedoFunctionKey = "\uF744";
|
||||
CPFindFunctionKey = "\uF745";
|
||||
CPHelpFunctionKey = "\uF746";
|
||||
CPModeSwitchFunctionKey = "\uF747";
|
||||
CPEscapeFunctionKey = "\u001B";
|
||||
CPSpaceFunctionKey = "\u0020";
|
||||
|
||||
|
||||
CPDOMEventDoubleClick = "dblclick";
|
||||
CPDOMEventMouseDown = "mousedown";
|
||||
CPDOMEventMouseUp = "mouseup";
|
||||
CPDOMEventMouseMoved = "mousemove";
|
||||
CPDOMEventMouseDragged = "mousedrag";
|
||||
CPDOMEventKeyUp = "keyup";
|
||||
CPDOMEventKeyDown = "keydown";
|
||||
CPDOMEventKeyPress = "keypress";
|
||||
CPDOMEventCopy = "copy";
|
||||
CPDOMEventPaste = "paste";
|
||||
CPDOMEventScrollWheel = "mousewheel";
|
||||
CPDOMEventTouchStart = "touchstart";
|
||||
CPDOMEventTouchMove = "touchmove";
|
||||
CPDOMEventTouchEnd = "touchend";
|
||||
CPDOMEventTouchCancel = "touchcancel";
|
||||
@global CPApp
|
||||
|
||||
var _CPEventPeriodicEventPeriod = 0,
|
||||
_CPEventPeriodicEventTimer = nil,
|
||||
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
|
||||
_CPEventUpperCaseRegex = new RegExp("[A-Z]"),
|
||||
_CPEventStartupMilliseconds = new Date().getTime();
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -189,7 +47,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
@implementation CPEvent : CPObject
|
||||
{
|
||||
CPEventType _type;
|
||||
CPPoint _location;
|
||||
CGPoint _location;
|
||||
unsigned _modifierFlags;
|
||||
CPTimeInterval _timestamp;
|
||||
CPGraphicsContext _context;
|
||||
@@ -203,12 +61,23 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
BOOL _isARepeat;
|
||||
unsigned _keyCode;
|
||||
DOMEvent _DOMEvent;
|
||||
int _data1;
|
||||
int _data2;
|
||||
short _subtype;
|
||||
|
||||
float _deltaX;
|
||||
float _deltaY;
|
||||
float _deltaZ;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current time in fractional seconds since startup.
|
||||
*/
|
||||
+ (CPTimeInterval)currentTimestamp
|
||||
{
|
||||
return (new Date().getTime() - _CPEventStartupMilliseconds) / 1000;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new keyboard event.
|
||||
|
||||
@@ -297,13 +166,13 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
||||
{
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_location = CGPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
_context = aGraphicsContext;
|
||||
@@ -317,13 +186,13 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
|
||||
{
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_location = CGPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
_context = aGraphicsContext;
|
||||
@@ -344,7 +213,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
{
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_location = CGPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
_context = aGraphicsContext;
|
||||
@@ -366,7 +235,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
*/
|
||||
- (CGPoint)locationInWindow
|
||||
{
|
||||
return _CGPointMakeCopy(_location);
|
||||
return CGPointMakeCopy(_location);
|
||||
}
|
||||
|
||||
- (CGPoint)globalLocation
|
||||
@@ -389,7 +258,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the time the event occurred.
|
||||
Returns the time the event occurred in seconds since startup.
|
||||
*/
|
||||
- (CPTimeInterval)timestamp
|
||||
{
|
||||
@@ -508,6 +377,16 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return _DOMEvent;
|
||||
}
|
||||
|
||||
- (int)data1
|
||||
{
|
||||
return _data1;
|
||||
}
|
||||
|
||||
- (int)data2
|
||||
{
|
||||
return _data2;
|
||||
}
|
||||
|
||||
// Getting Scroll Wheel Event Information
|
||||
/*!
|
||||
Returns the change in the x-axis for a mouse event.
|
||||
@@ -571,31 +450,27 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
// Cocoa allows almost any key as a key equivalent unless the first responder is a
|
||||
// text field (presumably a subclass of NSText.)
|
||||
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
|
||||
|
||||
// Some keys are accepted as key equivalents even if the first responder is a text
|
||||
// field.
|
||||
for (var i = 0; i < characterCount; i++)
|
||||
{
|
||||
switch (_characters.charAt(i))
|
||||
var c = _characters.charAt(i);
|
||||
|
||||
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
|
||||
c === CPEnterCharacter ||
|
||||
c === CPNewlineCharacter ||
|
||||
c === CPCarriageReturnCharacter ||
|
||||
c === CPEscapeFunctionKey)
|
||||
{
|
||||
case CPBackspaceCharacter:
|
||||
case CPDeleteCharacter:
|
||||
case CPDeleteFunctionKey:
|
||||
case CPTabCharacter:
|
||||
case CPCarriageReturnCharacter:
|
||||
case CPNewlineCharacter:
|
||||
case CPSpaceFunctionKey:
|
||||
case CPEscapeFunctionKey:
|
||||
case CPPageUpFunctionKey:
|
||||
case CPPageDownFunctionKey:
|
||||
case CPLeftArrowFunctionKey:
|
||||
case CPUpArrowFunctionKey:
|
||||
case CPRightArrowFunctionKey:
|
||||
case CPDownArrowFunctionKey:
|
||||
case CPEndFunctionKey:
|
||||
case CPHomeFunctionKey:
|
||||
return YES;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
// FIXME: More cases?
|
||||
return NO;
|
||||
|
||||
return !firstResponderIsText;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -625,11 +500,34 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
_CPEventPeriodicEventTimer = nil;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case CPKeyDown:
|
||||
case CPKeyUp:
|
||||
case CPFlagsChanged:
|
||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ chars=\"%@\" unmodchars=\"%@\" repeat=%d keyCode=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _characters, _charactersIgnoringModifiers, _isARepeat, _keyCode];
|
||||
case CPLeftMouseDown:
|
||||
case CPLeftMouseUp:
|
||||
case CPRightMouseDown:
|
||||
case CPRightMouseUp:
|
||||
case CPMouseMoved:
|
||||
case CPLeftMouseDragged:
|
||||
case CPRightMouseDragged:
|
||||
case CPMouseEntered:
|
||||
case CPMouseExited:
|
||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ evNum=%d click=%d buttonNumber=%d pressure=%f", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _eventNumber, _clickCount, [self buttonNumber], _pressure];
|
||||
default:
|
||||
return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ subtype=%d data1=%d data2=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _subtype, _data1, _data2];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
function _CPEventFirePeriodEvent()
|
||||
{
|
||||
[CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:_CGPointMakeZero() modifierFlags:0 timestamp:0 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];
|
||||
@@ -651,4 +549,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* CPEvent_Constants.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPLeftMouseDown = 1;
|
||||
CPLeftMouseUp = 2;
|
||||
CPRightMouseDown = 3;
|
||||
CPRightMouseUp = 4;
|
||||
CPMouseMoved = 5;
|
||||
CPLeftMouseDragged = 6;
|
||||
CPRightMouseDragged = 7;
|
||||
CPMouseEntered = 8;
|
||||
CPMouseExited = 9;
|
||||
CPKeyDown = 10;
|
||||
CPKeyUp = 11;
|
||||
CPFlagsChanged = 12;
|
||||
CPAppKitDefined = 13;
|
||||
CPSystemDefined = 14;
|
||||
CPApplicationDefined = 15;
|
||||
CPPeriodic = 16;
|
||||
CPCursorUpdate = 17;
|
||||
CPScrollWheel = 22;
|
||||
CPOtherMouseDown = 25;
|
||||
CPOtherMouseUp = 26;
|
||||
CPOtherMouseDragged = 27;
|
||||
|
||||
// iPhone Event Types
|
||||
CPTouchStart = 28;
|
||||
CPTouchMove = 29;
|
||||
CPTouchEnd = 30;
|
||||
CPTouchCancel = 31;
|
||||
|
||||
CPAlphaShiftKeyMask = 1 << 16;
|
||||
CPShiftKeyMask = 1 << 17;
|
||||
CPControlKeyMask = 1 << 18;
|
||||
CPAlternateKeyMask = 1 << 19;
|
||||
CPCommandKeyMask = 1 << 20;
|
||||
CPNumericPadKeyMask = 1 << 21;
|
||||
CPHelpKeyMask = 1 << 22;
|
||||
CPFunctionKeyMask = 1 << 23;
|
||||
CPDeviceIndependentModifierFlagsMask = 0xffff0000;
|
||||
|
||||
CPLeftMouseDownMask = 1 << CPLeftMouseDown;
|
||||
CPLeftMouseUpMask = 1 << CPLeftMouseUp;
|
||||
CPRightMouseDownMask = 1 << CPRightMouseDown;
|
||||
CPRightMouseUpMask = 1 << CPRightMouseUp;
|
||||
CPOtherMouseDownMask = 1 << CPOtherMouseDown;
|
||||
CPOtherMouseUpMask = 1 << CPOtherMouseUp;
|
||||
CPMouseMovedMask = 1 << CPMouseMoved;
|
||||
CPLeftMouseDraggedMask = 1 << CPLeftMouseDragged;
|
||||
CPRightMouseDraggedMask = 1 << CPRightMouseDragged;
|
||||
CPOtherMouseDragged = 1 << CPOtherMouseDragged;
|
||||
CPMouseEnteredMask = 1 << CPMouseEntered;
|
||||
CPMouseExitedMask = 1 << CPMouseExited;
|
||||
CPCursorUpdateMask = 1 << CPCursorUpdate;
|
||||
CPKeyDownMask = 1 << CPKeyDown;
|
||||
CPKeyUpMask = 1 << CPKeyUp;
|
||||
CPFlagsChangedMask = 1 << CPFlagsChanged;
|
||||
CPAppKitDefinedMask = 1 << CPAppKitDefined;
|
||||
CPSystemDefinedMask = 1 << CPSystemDefined;
|
||||
CPApplicationDefinedMask = 1 << CPApplicationDefined;
|
||||
CPPeriodicMask = 1 << CPPeriodic;
|
||||
CPScrollWheelMask = 1 << CPScrollWheel;
|
||||
CPAnyEventMask = 0xffffffff;
|
||||
|
||||
CPUpArrowFunctionKey = "\uF700";
|
||||
CPDownArrowFunctionKey = "\uF701";
|
||||
CPLeftArrowFunctionKey = "\uF702";
|
||||
CPRightArrowFunctionKey = "\uF703";
|
||||
CPF1FunctionKey = "\uF704";
|
||||
CPF2FunctionKey = "\uF705";
|
||||
CPF3FunctionKey = "\uF706";
|
||||
CPF4FunctionKey = "\uF707";
|
||||
CPF5FunctionKey = "\uF708";
|
||||
CPF6FunctionKey = "\uF709";
|
||||
CPF7FunctionKey = "\uF70A";
|
||||
CPF8FunctionKey = "\uF70B";
|
||||
CPF9FunctionKey = "\uF70C";
|
||||
CPF10FunctionKey = "\uF70D";
|
||||
CPF11FunctionKey = "\uF70E";
|
||||
CPF12FunctionKey = "\uF70F";
|
||||
CPF13FunctionKey = "\uF710";
|
||||
CPF14FunctionKey = "\uF711";
|
||||
CPF15FunctionKey = "\uF712";
|
||||
CPF16FunctionKey = "\uF713";
|
||||
CPF17FunctionKey = "\uF714";
|
||||
CPF18FunctionKey = "\uF715";
|
||||
CPF19FunctionKey = "\uF716";
|
||||
CPF20FunctionKey = "\uF717";
|
||||
CPF21FunctionKey = "\uF718";
|
||||
CPF22FunctionKey = "\uF719";
|
||||
CPF23FunctionKey = "\uF71A";
|
||||
CPF24FunctionKey = "\uF71B";
|
||||
CPF25FunctionKey = "\uF71C";
|
||||
CPF26FunctionKey = "\uF71D";
|
||||
CPF27FunctionKey = "\uF71E";
|
||||
CPF28FunctionKey = "\uF71F";
|
||||
CPF29FunctionKey = "\uF720";
|
||||
CPF30FunctionKey = "\uF721";
|
||||
CPF31FunctionKey = "\uF722";
|
||||
CPF32FunctionKey = "\uF723";
|
||||
CPF33FunctionKey = "\uF724";
|
||||
CPF34FunctionKey = "\uF725";
|
||||
CPF35FunctionKey = "\uF726";
|
||||
CPInsertFunctionKey = "\uF727";
|
||||
CPDeleteFunctionKey = "\uF728";
|
||||
CPHomeFunctionKey = "\uF729";
|
||||
CPBeginFunctionKey = "\uF72A";
|
||||
CPEndFunctionKey = "\uF72B";
|
||||
CPPageUpFunctionKey = "\uF72C";
|
||||
CPPageDownFunctionKey = "\uF72D";
|
||||
CPPrintScreenFunctionKey = "\uF72E";
|
||||
CPScrollLockFunctionKey = "\uF72F";
|
||||
CPPauseFunctionKey = "\uF730";
|
||||
CPSysReqFunctionKey = "\uF731";
|
||||
CPBreakFunctionKey = "\uF732";
|
||||
CPResetFunctionKey = "\uF733";
|
||||
CPStopFunctionKey = "\uF734";
|
||||
CPMenuFunctionKey = "\uF735";
|
||||
CPUserFunctionKey = "\uF736";
|
||||
CPSystemFunctionKey = "\uF737";
|
||||
CPPrintFunctionKey = "\uF738";
|
||||
CPClearLineFunctionKey = "\uF739";
|
||||
CPClearDisplayFunctionKey = "\uF73A";
|
||||
CPInsertLineFunctionKey = "\uF73B";
|
||||
CPDeleteLineFunctionKey = "\uF73C";
|
||||
CPInsertCharFunctionKey = "\uF73D";
|
||||
CPDeleteCharFunctionKey = "\uF73E";
|
||||
CPPrevFunctionKey = "\uF73F";
|
||||
CPNextFunctionKey = "\uF740";
|
||||
CPSelectFunctionKey = "\uF741";
|
||||
CPExecuteFunctionKey = "\uF742";
|
||||
CPUndoFunctionKey = "\uF743";
|
||||
CPRedoFunctionKey = "\uF744";
|
||||
CPFindFunctionKey = "\uF745";
|
||||
CPHelpFunctionKey = "\uF746";
|
||||
CPModeSwitchFunctionKey = "\uF747";
|
||||
CPEscapeFunctionKey = "\u001B";
|
||||
CPSpaceFunctionKey = "\u0020";
|
||||
|
||||
|
||||
CPDOMEventDoubleClick = "dblclick";
|
||||
CPDOMEventMouseDown = "mousedown";
|
||||
CPDOMEventMouseUp = "mouseup";
|
||||
CPDOMEventMouseMoved = "mousemove";
|
||||
CPDOMEventMouseDragged = "mousedrag";
|
||||
CPDOMEventKeyUp = "keyup";
|
||||
CPDOMEventKeyDown = "keydown";
|
||||
CPDOMEventKeyPress = "keypress";
|
||||
CPDOMEventCopy = "copy";
|
||||
CPDOMEventPaste = "paste";
|
||||
CPDOMEventScrollWheel = "mousewheel";
|
||||
CPDOMEventTouchStart = "touchstart";
|
||||
CPDOMEventTouchMove = "touchmove";
|
||||
CPDOMEventTouchEnd = "touchend";
|
||||
CPDOMEventTouchCancel = "touchcancel";
|
||||
+22
-16
@@ -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];
|
||||
@@ -104,14 +97,17 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
- (void)setFlashVars:(CPDictionary)aDictionary
|
||||
{
|
||||
var varString = @"",
|
||||
enumerator = [aDictionary keyEnumerator];
|
||||
enumerator = [aDictionary keyEnumerator],
|
||||
key;
|
||||
|
||||
if (key = [enumerator nextObject])
|
||||
varString = [varString stringByAppendingFormat:@"%@=%@", key, [aDictionary objectForKey:key]];
|
||||
|
||||
var 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,12 +137,12 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_paramElements = [CPDictionary dictionary];
|
||||
_paramElements = @{};
|
||||
|
||||
var enumerator = [_params keyEnumerator],
|
||||
key;
|
||||
|
||||
while (_DOMObjectElement && (key = [enumerator nextObject]))
|
||||
while (_DOMObjectElement && (key = [enumerator nextObject]) !== nil)
|
||||
{
|
||||
var param = document.createElement(@"param");
|
||||
param.name = key;
|
||||
@@ -178,16 +174,26 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
paramEnumerator = [_params keyEnumerator],
|
||||
key;
|
||||
|
||||
while (key = [paramEnumerator nextObject])
|
||||
while ((key = [paramEnumerator nextObject]) !== nil)
|
||||
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
|
||||
|
||||
_DOMObjectElement = document.createElement(@"object");
|
||||
_DOMElement.appendChild(_DOMObjectElement);
|
||||
|
||||
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
||||
_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];
|
||||
|
||||
+194
-74
@@ -28,46 +28,85 @@
|
||||
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
|
||||
CPFontDefaultSystemFontSize = 12;
|
||||
|
||||
var _CPFonts = {},
|
||||
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
||||
_CPFontSystemFontSize = 12,
|
||||
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
||||
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
|
||||
/*!
|
||||
To create a font of a size that will dynamically reflect the current
|
||||
system font size, use this for the size argument.
|
||||
*/
|
||||
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");
|
||||
|
||||
|
||||
#define _CPRealFontSize(aSize) (aSize <= 0 ? _CPFontSystemFontSize : aSize)
|
||||
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
|
||||
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
|
||||
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFontCache[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
|
||||
#define _CPUserFont(aName, aSize, isBold, isItalic) _CPCachedFont(aName, aSize, isBold, isItalic) || [[CPFont alloc] _initWithName:aName size:aSize bold:isBold italic:isItalic system:NO]
|
||||
|
||||
#define _CPSystemFontCacheKey(aSize, isBold) (String(aSize) + (isBold ? "b" : ""))
|
||||
#define _CPCachedSystemFont(aSize, isBold) _CPSystemFontCache[_CPSystemFontCacheKey(aSize, isBold)]
|
||||
#define _CPSystemFont(aSize, isBold) (_CPCachedSystemFont(aSize, isBold) || [[CPFont alloc] _initWithName:_CPFontSystemFacePlaceholder size:aSize bold:isBold italic:NO system:YES])
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFont
|
||||
@ingroup appkit
|
||||
@class CPFont
|
||||
|
||||
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
|
||||
The primary method for getting a particular font is through one of the class methods that take
|
||||
a name and/or size as arguments, and return the appropriate CPFont.
|
||||
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
|
||||
The primary method for getting a particular font is through one of the class methods that take
|
||||
a name and/or size as arguments, and return the appropriate CPFont.
|
||||
|
||||
By default the system font face/size is Arial 12px, with a fallback to sans-serif. You may
|
||||
configure this at runtime in two ways:
|
||||
### System fonts
|
||||
When you create a font using \c -systemFontOfSize: or \c -boldSystemFontOfSize:, a proxy font is
|
||||
created that always refers to the current system font face and size. By default the system
|
||||
font face/size is Arial 12px, with a fallback to sans-serif 12px. You may configure this at
|
||||
runtime in two ways:
|
||||
|
||||
- By sending [CPFont @link CPFont::setSystemFontFace: setSystemFontFace:@endlink] and/or [CPFont @link CPFont::setSystemFontSize: setSystemFontSize:@endlink].
|
||||
- By configuring Info.plist for your application or for AppKit. You can set the font face
|
||||
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
|
||||
by adding a CPSystemFontSize integer item to the Info.plist.
|
||||
- By sending [CPFont setSystemFontFace:<face>] and/or [CPFont setSystemFontSize:<size>].
|
||||
Note that if you change the system font face or size during runtime, the next time
|
||||
any view using a system font is redrawn, it will show the new font.
|
||||
- By configuring Info.plist for your application or for AppKit. You can set the font face
|
||||
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
|
||||
by adding a CPSystemFontSize integer item to the Info.plist.
|
||||
|
||||
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
|
||||
The browser will use the first available font in the list. CPFont always ensures that Arial
|
||||
and sans-serif are in the generated CSS string, so there is no need to add them to the end
|
||||
of your font list.
|
||||
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
|
||||
Do not quote enclose font faces that contain spaces, that is done automatically when a CSS
|
||||
representation of a font is requested.
|
||||
|
||||
If you are using nib2cib, you should use the second method (using Info.plist),
|
||||
and be sure to run nib2cib again any time you modify the CPSystemFontFace or CPSystemFontSize items.
|
||||
For example, you might add this to your application's Info.plist to set the system font to Lucida Grande,
|
||||
with an automatic fallback to Arial or sans-serif:
|
||||
The browser will use the first available font in the list you supply. CPFont always ensures
|
||||
that Arial and sans-serif are in the CSS representation of a font as a fallback, so there is
|
||||
no need to add them to the end of your font list.
|
||||
|
||||
@code
|
||||
### nib2cib conversion
|
||||
Fonts are converted by nib2cib according to the following algorithm:
|
||||
|
||||
- If the font family is Lucida Grande, then a system font will be created.
|
||||
- If the font is Lucida Grande 13 (plain), the "default" font will be used at runtime.
|
||||
The default font is taken from the "font" theme attribute if one exists,
|
||||
otherwise from the current system font face and size.
|
||||
- Lucida Grande of any size other than 13 will retain its size.
|
||||
- Fonts using any family other than Lucida Grande will be used as is, including the size.
|
||||
|
||||
### Using custom web fonts
|
||||
The configurability of CPFont makes it easy to use a custom web font as the system font.
|
||||
For example, if you want to use the google font Asap as the system font, you would do the
|
||||
following:
|
||||
|
||||
- Add a <link> to the <head> of index-debug.html and index.html:
|
||||
@code
|
||||
<link href='http://fonts.googleapis.com/css?family=Asap:400,700' rel='stylesheet' type='text/css'>
|
||||
@endcode
|
||||
- Specify Asap as the system font in Info.plist by adding the following item:
|
||||
@code
|
||||
<key>CPSystemFontFace</key>
|
||||
<string>Lucida Grande</string>
|
||||
@endcode
|
||||
<string>Asap</string>
|
||||
@endcode
|
||||
*/
|
||||
@implementation CPFont : CPObject
|
||||
{
|
||||
@@ -78,19 +117,23 @@ var _CPFonts = {},
|
||||
float _lineHeight;
|
||||
BOOL _isBold @accessors(readonly, getter=isBold);
|
||||
BOOL _isItalic @accessors(readonly, getter=isItalic);
|
||||
BOOL _isSystem @accessors(readonly, getter=isSystem);
|
||||
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [CPFont class])
|
||||
return;
|
||||
|
||||
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
||||
|
||||
if (!systemFontFace)
|
||||
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
||||
|
||||
if (systemFontFace)
|
||||
[self setSystemFontFace:systemFontFace];
|
||||
_CPFontSystemFontFace = _CPFontNormalizedNames(systemFontFace);
|
||||
|
||||
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
||||
|
||||
@@ -114,7 +157,13 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPString)setSystemFontFace:(CPString)aFace
|
||||
{
|
||||
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
|
||||
var normalizedFaces = _CPFontNormalizedNames(aFace);
|
||||
|
||||
if (normalizedFaces === _CPFontSystemFontFace)
|
||||
return;
|
||||
|
||||
[self _invalidateSystemFontCache]
|
||||
_CPFontSystemFontFace = aFace;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -125,106 +174,158 @@ var _CPFonts = {},
|
||||
return _CPFontSystemFontSize;
|
||||
}
|
||||
|
||||
+ (float)systemFontSizeForControlSize:(CPControlSize)aSize
|
||||
{
|
||||
// TODO These sizes should be themable or made less arbitrary in some other way.
|
||||
switch (aSize)
|
||||
{
|
||||
case CPSmallControlSize:
|
||||
return _CPFontSystemFontSize - 1;
|
||||
|
||||
case CPMiniControlSize:
|
||||
return _CPFontSystemFontSize - 2;
|
||||
|
||||
case CPRegularControlSize:
|
||||
default:
|
||||
return _CPFontSystemFontSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the default system font size.
|
||||
*/
|
||||
+ (float)setSystemFontSize:(float)size
|
||||
{
|
||||
if (size > 0)
|
||||
if (size > 0 && size !== _CPFontSystemFontSize)
|
||||
{
|
||||
[self _invalidateSystemFontCache];
|
||||
_CPFontSystemFontSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)_invalidateSystemFontCache
|
||||
{
|
||||
var systemSize = String(_CPFontSystemFontSize),
|
||||
currentSize = String(CPFontCurrentSystemSize);
|
||||
|
||||
for (key in _CPSystemFontCache)
|
||||
{
|
||||
if (_CPSystemFontCache.hasOwnProperty(key) &&
|
||||
(key.indexOf(systemSize) === 0 || key.indexOf(currentSize) === 0))
|
||||
{
|
||||
delete _CPSystemFontCache[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font with the specified name and size.
|
||||
@param aName the name of the font
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 or negative will create a font
|
||||
in the current system font size.
|
||||
@return the requested font
|
||||
*/
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
|
||||
return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, NO, NO);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font with the specified name, size and style.
|
||||
@param aName the name of the font
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 or negative will create a font
|
||||
in the current system font size.
|
||||
@param italic whether the font should be italicized
|
||||
@return the requested font
|
||||
*/
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
|
||||
return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, NO, italic);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a bold font with the specified name and size.
|
||||
@param aName the name of the font
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 or negative will create a font
|
||||
in the current system font size.
|
||||
@return the requested bold font
|
||||
*/
|
||||
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
|
||||
return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, YES, NO);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a bold font with the specified name, size and style.
|
||||
@param aName the name of the font
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 or negative will create a font
|
||||
in the current system font size.
|
||||
@param italic whether the font should be italicized
|
||||
@return the requested font
|
||||
*/
|
||||
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
|
||||
return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, YES, italic);
|
||||
}
|
||||
|
||||
/*!
|
||||
Internal font getter like fontWithName:size:italic: with a bold selector.
|
||||
*/
|
||||
+ (CPFont)_fontWithName:(CPString)aName size:(float)aSize bold:(BOOL)bold italic:(BOOL)italic
|
||||
{
|
||||
return _CPUserFont(aName, aSize <= 0 ? _CPFontSystemFontSize : aSize, bold, italic);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the system font scaled to the specified size
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 creates a static font
|
||||
in the current system font size. Negative creates a font
|
||||
that dynamically tracks the current system font size.
|
||||
@return the requested system font
|
||||
*/
|
||||
+ (CPFont)systemFontOfSize:(CPSize)aSize
|
||||
+ (CPFont)systemFontOfSize:(CGSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
|
||||
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, NO);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the bold system font scaled to the specified size
|
||||
@param aSize the size of the font (in px)
|
||||
@param aSize the size of the font (in px). 0 creates a static font
|
||||
in the current system font size. Negative creates a font
|
||||
that dynamically tracks the current system font size.
|
||||
@return the requested bold system font
|
||||
*/
|
||||
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
|
||||
+ (CPFont)boldSystemFontOfSize:(CGSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
|
||||
return _CPSystemFont(aSize === 0 ? _CPFontSystemFontSize : aSize, YES);
|
||||
}
|
||||
|
||||
/* FIXME Font Descriptor
|
||||
@ignore
|
||||
*/
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
|
||||
{
|
||||
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
|
||||
}
|
||||
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic system:(BOOL)isSystem
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = _CPFontNormalizedNames(aName);
|
||||
_size = aSize;
|
||||
_ascender = 0;
|
||||
_descender = 0;
|
||||
_lineHeight = 0;
|
||||
_isBold = isBold;
|
||||
_isItalic = isItalic;
|
||||
_isSystem = isSystem;
|
||||
|
||||
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
|
||||
|
||||
_CPFonts[_cssString] = self;
|
||||
if (isSystem)
|
||||
{
|
||||
_name = aName;
|
||||
_cssString = _CPFontCreateCSSString(_CPFontSystemFontFace, _size, _isBold, _isItalic);
|
||||
_CPSystemFontCache[_CPSystemFontCacheKey(_size, _isBold)] = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
_name = _CPFontNormalizedNames(aName);
|
||||
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
|
||||
_CPFontCache[_cssString] = self;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -235,10 +336,12 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (float)ascender
|
||||
{
|
||||
if (!_ascender)
|
||||
[self _getMetrics];
|
||||
var font = _isSystem ? _CPSystemFont(_size, _isBold) : self;
|
||||
|
||||
return _ascender;
|
||||
if (!font._ascender)
|
||||
[font _getMetrics];
|
||||
|
||||
return font._ascender;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -247,10 +350,12 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (float)descender
|
||||
{
|
||||
if (!_descender)
|
||||
[self _getMetrics];
|
||||
var font = _isSystem ? _CPSystemFont(_size, _isBold) : self;
|
||||
|
||||
return _descender;
|
||||
if (!font._descender)
|
||||
[font _getMetrics];
|
||||
|
||||
return font._descender;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -260,10 +365,12 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (float)defaultLineHeightForFont
|
||||
{
|
||||
if (!_lineHeight)
|
||||
[self _getMetrics];
|
||||
var font = _isSystem ? _CPSystemFont(_size, _isBold) : self;
|
||||
|
||||
return _lineHeight;
|
||||
if (!font._lineHeight)
|
||||
[font _getMetrics];
|
||||
|
||||
return font._lineHeight;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -271,7 +378,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (float)size
|
||||
{
|
||||
return _size;
|
||||
return _CPRealFontSize(_size);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -279,7 +386,9 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (CPString)cssString
|
||||
{
|
||||
return _cssString;
|
||||
var font = _isSystem ? _CPSystemFont(_size, _isBold) : self;
|
||||
|
||||
return font._cssString;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -287,9 +396,17 @@ var _CPFonts = {},
|
||||
*/
|
||||
- (CPString)familyName
|
||||
{
|
||||
if (_isSystem)
|
||||
return _CPFontSystemFontFace;
|
||||
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (BOOL)isSystemSize
|
||||
{
|
||||
return _size <= 0;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
|
||||
@@ -302,7 +419,7 @@ var _CPFonts = {},
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
|
||||
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic system:_isSystem];
|
||||
}
|
||||
|
||||
- (void)_getMetrics
|
||||
@@ -319,7 +436,8 @@ var _CPFonts = {},
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
CPFontSizeKey = @"CPFontSizeKey",
|
||||
CPFontIsBoldKey = @"CPFontIsBoldKey",
|
||||
CPFontIsItalicKey = @"CPFontIsItalicKey";
|
||||
CPFontIsItalicKey = @"CPFontIsItalicKey",
|
||||
CPFontIsSystemKey = @"CPFontIsSystemKey";
|
||||
|
||||
@implementation CPFont (CPCoding)
|
||||
|
||||
@@ -333,9 +451,10 @@ var CPFontNameKey = @"CPFontNameKey",
|
||||
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
|
||||
size = [aCoder decodeFloatForKey:CPFontSizeKey],
|
||||
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
|
||||
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
|
||||
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey],
|
||||
isSystem = [aCoder decodeBoolForKey:CPFontIsSystemKey];
|
||||
|
||||
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
|
||||
return [self _initWithName:fontName size:size bold:isBold italic:isItalic system:isSystem];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -348,6 +467,7 @@ var CPFontNameKey = @"CPFontNameKey",
|
||||
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
|
||||
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
|
||||
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
|
||||
[aCoder encodeBool:_isSystem forKey:CPFontIsSystemKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -356,7 +476,7 @@ var CPFontNameKey = @"CPFontNameKey",
|
||||
// aName must be normalized
|
||||
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
|
||||
{
|
||||
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
|
||||
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + _CPRealFontSize(aSize) + "px ";
|
||||
|
||||
return properties + _CPFontConcatNameWithFallback(aName);
|
||||
};
|
||||
|
||||
+153
-31
@@ -24,6 +24,21 @@
|
||||
|
||||
@import "CPFont.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPItalicFontMask = 1 << 0;
|
||||
CPBoldFontMask = 1 << 1;
|
||||
CPUnboldFontMask = 1 << 2;
|
||||
CPNonStandardCharacterSetFontMask = 1 << 3;
|
||||
CPNarrowFontMask = 1 << 4;
|
||||
CPExpandedFontMask = 1 << 5;
|
||||
CPCondensedFontMask = 1 << 6;
|
||||
CPSmallCapsFontMask = 1 << 7;
|
||||
CPPosterFontMask = 1 << 8;
|
||||
CPCompressedFontMask = 1 << 9;
|
||||
CPFixedPitchFontMask = 1 << 10;
|
||||
CPUnitalicFontMask = 1 << 24;
|
||||
|
||||
|
||||
var CPSharedFontManager = nil,
|
||||
CPFontManagerFactory = Nil;
|
||||
@@ -33,7 +48,17 @@ var CPSharedFontManager = nil,
|
||||
*/
|
||||
@implementation CPFontManager : CPObject
|
||||
{
|
||||
CPArray _availableFonts;
|
||||
CPArray _availableFonts;
|
||||
|
||||
id _target @accessors(property=target);
|
||||
SEL _action @accessors(property=action);
|
||||
|
||||
id _delegate @accessors(property=delegate);
|
||||
|
||||
CPFont _selectedFont;
|
||||
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
|
||||
|
||||
CPDictionary _activeChange;
|
||||
}
|
||||
|
||||
// Getting the Shared Font Manager
|
||||
@@ -59,6 +84,16 @@ var CPSharedFontManager = nil,
|
||||
CPFontManagerFactory = aClass;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_action = @selector(changeFont:);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of the available fonts
|
||||
*/
|
||||
@@ -66,6 +101,9 @@ var CPSharedFontManager = nil,
|
||||
{
|
||||
if (!_availableFonts)
|
||||
{
|
||||
_availableFonts = [];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_CPFontDetectSpan = document.createElement("span");
|
||||
_CPFontDetectSpan.fontSize = "24px";
|
||||
_CPFontDetectSpan.appendChild(document.createTextNode("mmmmmmmmmml"));
|
||||
@@ -77,13 +115,16 @@ var CPSharedFontManager = nil,
|
||||
|
||||
_CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
|
||||
|
||||
_availableFonts = [];
|
||||
for (var i = 0; i < _CPFontDetectAllFonts.length; i++)
|
||||
{
|
||||
var available = _CPFontDetectFontAvailable(_CPFontDetectAllFonts[i]);
|
||||
if (available)
|
||||
_availableFonts.push(_CPFontDetectAllFonts[i]);
|
||||
}
|
||||
#else
|
||||
// If there's no font detection, just assume all fonts are available.
|
||||
_availableFonts = _CPFontDetectAllFonts;
|
||||
#endif
|
||||
}
|
||||
return _availableFonts;
|
||||
}
|
||||
@@ -97,43 +138,124 @@ var CPSharedFontManager = nil,
|
||||
return _CPFontDetectFontAvailable(aFontName);
|
||||
}
|
||||
|
||||
- (void)setSelectedFont:(CPFont)aFont isMultiple:(BOOL)aFlag
|
||||
{
|
||||
_selectedFont = aFont;
|
||||
_multiple = aFlag;
|
||||
|
||||
// TODO Notify CPFontPanel when it exists.
|
||||
}
|
||||
|
||||
- (CPFont)selectedFont
|
||||
{
|
||||
return _selectedFont;
|
||||
}
|
||||
|
||||
- (int)weightOfFont:(CPFont)aFont
|
||||
{
|
||||
// TODO Weight 5 is a normal of book weight and 9 and above is bold, but it would be nice to be more
|
||||
// precise than that.
|
||||
return [aFont isBold] ? 9 : 5;
|
||||
}
|
||||
|
||||
- (CPFontTraitMask)traitsOfFont:(CPFont)aFont
|
||||
{
|
||||
return ([aFont isBold] ? CPBoldFontMask : 0) | ([aFont isItalic] ? CPItalicFontMask : 0);
|
||||
}
|
||||
|
||||
- (CPFont)convertFont:(CPFont)aFont
|
||||
{
|
||||
if (!_activeChange)
|
||||
return aFont;
|
||||
|
||||
var addTraits = [_activeChange valueForKey:@"addTraits"];
|
||||
|
||||
if (addTraits)
|
||||
aFont = [self convertFont:aFont toHaveTrait:addTraits];
|
||||
|
||||
return aFont;
|
||||
}
|
||||
|
||||
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)addTraits
|
||||
{
|
||||
if (!aFont)
|
||||
return nil;
|
||||
|
||||
var shouldBeBold = ([aFont isBold] || (addTraits & CPBoldFontMask)) && !(addTraits & CPUnboldFontMask),
|
||||
shouldBeItalic = ([aFont isItalic] || (addTraits & CPItalicFontMask)) && !(addTraits & CPUnitalicFontMask),
|
||||
shouldBeSize = [aFont size];
|
||||
|
||||
// XXX On the current platform there will always be a bold/italic version of each font, but still leave
|
||||
// || aFont in here for future platforms.
|
||||
aFont = [CPFont _fontWithName:[aFont familyName] size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
|
||||
|
||||
return aFont;
|
||||
}
|
||||
|
||||
- (CPFont)convertFont:(CPFont)aFont toFace:(CPString)aTypeface
|
||||
{
|
||||
if (!aFont)
|
||||
return nil;
|
||||
|
||||
var shouldBeBold = [aFont isBold],
|
||||
shouldBeItalic = [aFont isItalic],
|
||||
shouldBeSize = [aFont size];
|
||||
|
||||
aFont = [CPFont _fontWithName:aTypeface size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
|
||||
|
||||
return aFont;
|
||||
}
|
||||
|
||||
- (@action)addFontTrait:(id)sender
|
||||
{
|
||||
var tag = [sender tag];
|
||||
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
|
||||
|
||||
[self sendAction];
|
||||
}
|
||||
|
||||
- (BOOL)sendAction
|
||||
{
|
||||
return [CPApp sendAction:_action to:_target from:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPFontDetectSpan,
|
||||
_CPFontDetectReferenceFonts,
|
||||
_CPFontDetectAllFonts = [
|
||||
/* "04b_21","A Charming Font","Abadi MT Condensed","Abadi MT Condensed Extra Bold","Abadi MT Condensed Light","Academy Engraved LET","Agency FB","Alba","Alba Matter","Alba Super","Algerian",*/
|
||||
/* "04b_21", "A Charming Font", "Abadi MT Condensed", "Abadi MT Condensed Extra Bold", "Abadi MT Condensed Light", "Academy Engraved LET", "Agency FB", "Alba", "Alba Matter", "Alba Super", "Algerian",*/
|
||||
"American Typewriter",
|
||||
/* "Andale Mono","Andale Mono IPA","Andy", */
|
||||
"Apple Chancery","Arial","Arial Black","Arial Narrow","Arial Rounded MT Bold","Arial Unicode MS",
|
||||
/* "Avant Garde","Avantgarde","Baby Kruffy","Base 02","Baskerville","Baskerville Old Face","Bauhaus 93","Beesknees ITC","Bell MT","Berlin Sans FB","Berlin Sans FB Demi","Bernard MT Condensed","Bickley Script",*/
|
||||
"Big Caslon","Bitstream Vera Sans","Bitstream Vera Sans Mono","Bitstream Vera Serif",
|
||||
/* "Blackadder ITC","Blackletter686 BT","Bodoni MT","Bodoni MT Black","Bodoni MT Condensed","Bodoni MT Poster Compressed","Book Antiqua","Bookman","Bookman Old Style","Bradley Hand ITC","Braggadocio","Britannic Bold","Broadway","Broadway BT",*/
|
||||
/* "Andale Mono", "Andale Mono IPA", "Andy", */
|
||||
"Apple Chancery", "Arial", "Arial Black", "Arial Narrow", "Arial Rounded MT Bold", "Arial Unicode MS",
|
||||
/* "Avant Garde", "Avantgarde", "Baby Kruffy", "Base 02", "Baskerville", "Baskerville Old Face", "Bauhaus 93", "Beesknees ITC", "Bell MT", "Berlin Sans FB", "Berlin Sans FB Demi", "Bernard MT Condensed", "Bickley Script",*/
|
||||
"Big Caslon", "Bitstream Vera Sans", "Bitstream Vera Sans Mono", "Bitstream Vera Serif",
|
||||
/* "Blackadder ITC", "Blackletter686 BT", "Bodoni MT", "Bodoni MT Black", "Bodoni MT Condensed", "Bodoni MT Poster Compressed", "Book Antiqua", "Bookman", "Bookman Old Style", "Bradley Hand ITC", "Braggadocio", "Britannic Bold", "Broadway", "Broadway BT",*/
|
||||
"Brush Script MT",
|
||||
/* "BudHand","CAMPBELL","Calibri","Californian FB","Calisto MT","Calligraph421 BT",*/
|
||||
/* "BudHand", "CAMPBELL", "Calibri", "Californian FB", "Calisto MT", "Calligraph421 BT",*/
|
||||
"Cambria",
|
||||
/* "Candara","Capitals",*/
|
||||
"Caslon","Castellar","Cataneo BT","Centaur","Century Gothic","Century Schoolbook","Century Schoolbook L",
|
||||
/* "Champignon","Charcoal","Charter","Charter BT","Chicago","Chick","Chiller","ClearlyU","Colonna MT",*/
|
||||
"Comic Sans", "Comic Sans MS","Consolas","Constantia","Cooper Black","Copperplate","Copperplate Gothic Bold","Copperplate Gothic Light","Corbel","Courier","Courier New",
|
||||
/* "Croobie","Curlz MT","Desdemona","Didot","DomBold BT","Edwardian Script ITC","Engravers MT","Eras Bold ITC","Eras Demi ITC","Eras Light ITC","Eras Medium ITC","Eurostile","FIRSTHOME","Fat","Felix Titling","Fine Hand","Fixed","Footlight MT Light","Forte","Franklin Gothic Book","Franklin Gothic Demi","Franklin Gothic Demi Cond","Franklin Gothic Heavy","Franklin Gothic Medium","Franklin Gothic Medium Cond","Freestyle Script","French Script MT","Freshbot","Frosty",*/
|
||||
/* "Candara", "Capitals",*/
|
||||
"Caslon", "Castellar", "Cataneo BT", "Centaur", "Century Gothic", "Century Schoolbook", "Century Schoolbook L",
|
||||
/* "Champignon", "Charcoal", "Charter", "Charter BT", "Chicago", "Chick", "Chiller", "ClearlyU", "Colonna MT",*/
|
||||
"Comic Sans", "Comic Sans MS", "Consolas", "Constantia", "Cooper Black", "Copperplate", "Copperplate Gothic Bold", "Copperplate Gothic Light", "Corbel", "Courier", "Courier New",
|
||||
/* "Croobie", "Curlz MT", "Desdemona", "Didot", "DomBold BT", "Edwardian Script ITC", "Engravers MT", "Eras Bold ITC", "Eras Demi ITC", "Eras Light ITC", "Eras Medium ITC", "Eurostile", "FIRSTHOME", "Fat", "Felix Titling", "Fine Hand", "Fixed", "Footlight MT Light", "Forte", "Franklin Gothic Book", "Franklin Gothic Demi", "Franklin Gothic Demi Cond", "Franklin Gothic Heavy", "Franklin Gothic Medium", "Franklin Gothic Medium Cond", "Freestyle Script", "French Script MT", "Freshbot", "Frosty",*/
|
||||
"Futura",
|
||||
/* "GENUINE","Gadget","Garamond",*/
|
||||
"Geneva","Georgia","Georgia Ref", "Geeza Pro", "Gigi","Gill Sans","Gill Sans MT","Gill Sans MT Condensed","Gill Sans MT Ext Condensed Bold","Gill Sans Ultra Bold","Gill Sans Ultra Bold Condensed",
|
||||
/* "GlooGun","Gloucester MT Extra Condensed","Goudy Old Style","Goudy Stout","Haettenschweiler","Harlow Solid Italic","Harrington",*/
|
||||
"Helvetica","Helvetica Narrow","Helvetica Neue","Herculanum","High Tower Text","Highlight LET","Hoefler Text","Impact","Imprint MT Shadow",
|
||||
/* "Informal Roman","Jenkins v2.0","John Handy LET","Jokerman","Jokerman LET","Jokewood","Juice ITC","Kabel Ult BT","Kartika","Kino MT","Kristen ITC","Kunstler Script","La Bamba LET", */
|
||||
"Lucida","Lucida Bright","Lucida Calligraphy","Lucida Console","Lucida Fax","Lucida Grande","Lucida Handwriting","Lucida Sans","Lucida Sans Typewriter","Lucida Sans Unicode",
|
||||
/* "Luxi Mono","Luxi Sans","Luxi Serif","MARKETPRO","MS Reference Sans Serif","MS Reference Serif","Magneto","Maiandra GD", */
|
||||
/* "GENUINE", "Gadget", "Garamond",*/
|
||||
"Geneva", "Georgia", "Georgia Ref", "Geeza Pro", "Gigi", "Gill Sans", "Gill Sans MT", "Gill Sans MT Condensed", "Gill Sans MT Ext Condensed Bold", "Gill Sans Ultra Bold", "Gill Sans Ultra Bold Condensed",
|
||||
/* "GlooGun", "Gloucester MT Extra Condensed", "Goudy Old Style", "Goudy Stout", "Haettenschweiler", "Harlow Solid Italic", "Harrington",*/
|
||||
"Helvetica", "Helvetica Narrow", "Helvetica Neue", "Herculanum", "High Tower Text", "Highlight LET", "Hoefler Text", "Impact", "Imprint MT Shadow",
|
||||
/* "Informal Roman", "Jenkins v2.0", "John Handy LET", "Jokerman", "Jokerman LET", "Jokewood", "Juice ITC", "Kabel Ult BT", "Kartika", "Kino MT", "Kristen ITC", "Kunstler Script", "La Bamba LET", */
|
||||
"Lucida", "Lucida Bright", "Lucida Calligraphy", "Lucida Console", "Lucida Fax", "Lucida Grande", "Lucida Handwriting", "Lucida Sans", "Lucida Sans Typewriter", "Lucida Sans Unicode",
|
||||
/* "Luxi Mono", "Luxi Sans", "Luxi Serif", "MARKETPRO", "MS Reference Sans Serif", "MS Reference Serif", "Magneto", "Maiandra GD", */
|
||||
"Marker Felt",
|
||||
/* "Matisse ITC","Matura MT Script Capitals","Mead Bold","Mekanik LET","Mercurius Script MT Bold", */
|
||||
"Microsoft Sans Serif","Milano LET","Minion Web","MisterEarl BT","Mistral","Monaco","Monotype Corsiva","Monotype.com","New Century Schoolbook","New York","News Gothic MT",
|
||||
/* "Niagara Engraved","Niagara Solid","Nimbus Mono L","Nimbus Roman No9 L","OCR A Extended","OCRB","Odessa LET","Old English Text MT","OldDreadfulNo7 BT","One Stroke Script LET","Onyx","Optima","Orange LET","Palace Script MT","Palatino","Palatino Linotype", */
|
||||
/* "Matisse ITC", "Matura MT Script Capitals", "Mead Bold", "Mekanik LET", "Mercurius Script MT Bold", */
|
||||
"Microsoft Sans Serif", "Milano LET", "Minion Web", "MisterEarl BT", "Mistral", "Monaco", "Monotype Corsiva", "Monotype.com", "New Century Schoolbook", "New York", "News Gothic MT",
|
||||
/* "Niagara Engraved", "Niagara Solid", "Nimbus Mono L", "Nimbus Roman No9 L", "OCR A Extended", "OCRB", "Odessa LET", "Old English Text MT", "OldDreadfulNo7 BT", "One Stroke Script LET", "Onyx", "Optima", "Orange LET", "Palace Script MT", "Palatino", "Palatino Linotype", */
|
||||
"Papyrus",
|
||||
/* "ParkAvenue BT","Pepita MT","Perpetua","Perpetua Titling MT","Placard Condensed","Playbill","Poornut","Pristina","Pump Demi Bold LET","Pussycat","Quixley LET","Rage Italic","Rage Italic LET","Ravie","Rockwell","Rockwell Condensed","Rockwell Extra Bold","Ruach LET","Runic MT Condensed","Sand","Script MT Bold","Scruff LET","Segoe UI","Showcard Gothic","Skia","Smudger LET","Snap ITC","Square721 BT","Staccato222 BT","Stencil","Sylfaen", */
|
||||
"Tahoma","Techno","Tempus Sans ITC","Terminal","Textile","Times","Times New Roman","Tiranti Solid LET","Trebuchet MS",
|
||||
/* "Tw Cen MT","Tw Cen MT Condensed","Tw Cen MT Condensed Extra Bold","URW Antiqua T","URW Bookman L","URW Chancery L","URW Gothic L","URW Palladio L","Univers","University Roman LET","Utopia", */
|
||||
"Verdana","Verdana Ref", /* "Victorian LET","Viner Hand ITC","Vivaldi","Vladimir Script","Vrinda","Weltron Urban","Westwood LET","Wide Latin","Zapf Chancery", */
|
||||
/* "ParkAvenue BT", "Pepita MT", "Perpetua", "Perpetua Titling MT", "Placard Condensed", "Playbill", "Poornut", "Pristina", "Pump Demi Bold LET", "Pussycat", "Quixley LET", "Rage Italic", "Rage Italic LET", "Ravie", "Rockwell", "Rockwell Condensed", "Rockwell Extra Bold", "Ruach LET", "Runic MT Condensed", "Sand", "Script MT Bold", "Scruff LET", "Segoe UI", "Showcard Gothic", "Skia", "Smudger LET", "Snap ITC", "Square721 BT", "Staccato222 BT", "Stencil", "Sylfaen", */
|
||||
"Tahoma", "Techno", "Tempus Sans ITC", "Terminal", "Textile", "Times", "Times New Roman", "Tiranti Solid LET", "Trebuchet MS",
|
||||
/* "Tw Cen MT", "Tw Cen MT Condensed", "Tw Cen MT Condensed Extra Bold", "URW Antiqua T", "URW Bookman L", "URW Chancery L", "URW Gothic L", "URW Palladio L", "Univers", "University Roman LET", "Utopia", */
|
||||
"Verdana", "Verdana Ref", /* "Victorian LET", "Viner Hand ITC", "Vivaldi", "Vladimir Script", "Vrinda", "Weltron Urban", "Westwood LET", "Wide Latin", "Zapf Chancery", */
|
||||
"Zapfino"];
|
||||
|
||||
// Compare against the reference fonts. Return true if it produces a different size than at least one of them.
|
||||
@@ -143,7 +265,7 @@ var _CPFontDetectFontAvailable = function(font)
|
||||
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var _CPFontDetectCache = {};
|
||||
|
||||
@@ -165,7 +287,7 @@ var _CPFontDetectCompareFonts = function(fontA, fontB)
|
||||
bHeight = _CPFontDetectSpan.offsetHeight;
|
||||
|
||||
return (a.w != bWidth || a.h != bHeight);
|
||||
}
|
||||
};
|
||||
|
||||
// Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
|
||||
var _CPFontDetectPickTwoDifferentFonts = function(candidates)
|
||||
@@ -175,6 +297,6 @@ var _CPFontDetectPickTwoDifferentFonts = function(candidates)
|
||||
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
|
||||
return [candidates[i], candidates[j]];
|
||||
return [candidates[0]];
|
||||
}
|
||||
};
|
||||
|
||||
[CPFontManager setFontManagerFactory:[CPFontManager class]];
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* CPGradient.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2012, SlevenBits Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPException.j>
|
||||
@import <Foundation/CPMutableArray.j>
|
||||
|
||||
@import "CGColor.j"
|
||||
@import "CGColorSpace.j"
|
||||
@import "CGGradient.j"
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
CPGradientDrawsBeforeStartingLocation = kCGGradientDrawsBeforeStartLocation;
|
||||
CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
|
||||
/*!
|
||||
A class for drawing linear and radial gradients with a convenient API.
|
||||
*/
|
||||
@implementation CPGradient : CPObject
|
||||
{
|
||||
CGGradient _gradient;
|
||||
}
|
||||
|
||||
- (id)initWithStartingColor:(CPColor)startingColor endingColor:(CPColor)endingColor
|
||||
{
|
||||
return [self initWithColors:[startingColor, endingColor]];
|
||||
}
|
||||
|
||||
- (id)initWithColors:(CPArray)someColors
|
||||
{
|
||||
var count = [someColors count];
|
||||
|
||||
if (count < 2)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"at least 2 colors required"];
|
||||
|
||||
var distance = 1.0 / (count - 1),
|
||||
locations = [CPMutableArray array],
|
||||
location = 0.0;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
[locations addObject:location];
|
||||
location += distance;
|
||||
}
|
||||
|
||||
return [self initWithColors:someColors atLocations:locations colorSpace:nil];
|
||||
}
|
||||
|
||||
- (id)initWithColors:(CPArray)someColors atLocations:(CPArray)someLocations colorSpace:(CPColorSpace)aColorSpace
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
var cgColors = [],
|
||||
count = [someColors count],
|
||||
colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB;
|
||||
for (var i = 0; i < count; i++)
|
||||
cgColors.push(CGColorCreate(colorSpace, [someColors[i] components]));
|
||||
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawInRect:(CGRect)rect angle:(float)angle
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextClipToRect(ctx, rect);
|
||||
CGContextAddRect(ctx, rect);
|
||||
|
||||
[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));
|
||||
else if (angle < 180.0)
|
||||
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
|
||||
else if (angle < 270.0)
|
||||
startPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
|
||||
else
|
||||
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
|
||||
// we want the opposite corner of the starting corner to just reach the final colour stop.
|
||||
// So when the angle isn't a right angle, the segment has to extend beyond the edge of the
|
||||
// rectangle just far enough. This is hard to describe without a picture but if we place
|
||||
// another line through the opposite corner at -90 degrees, it'll help form some triangles
|
||||
// from which we can derive this formula:
|
||||
//
|
||||
// length = cos(angle) * (rectWidth + rectHeight * tan(angle))
|
||||
//
|
||||
// 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));
|
||||
|
||||
endPoint = CGPointMake(startPoint.x + length * COS(radians),
|
||||
startPoint.y + length * SIN(radians));
|
||||
|
||||
[self drawFromPoint:startPoint toPoint:endPoint options:CPGradientDrawsBeforeStartingLocation | CPGradientDrawsAfterEndingLocation];
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
// TODO kCGGradientDrawsBeforeStartLocation and kCGGradientDrawsAfterEndLocation are not actually supported
|
||||
// by CGContextDrawLinearGradient yet.
|
||||
CGContextDrawLinearGradient(ctx, _gradient, startingPoint, endingPoint, options);
|
||||
}
|
||||
|
||||
@end
|
||||
+27
-14
@@ -23,6 +23,16 @@
|
||||
@import "CPColor.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
CPCalibratedWhiteColorSpace = @"CalibratedWhiteColorSpace";
|
||||
CPCalibratedBlackColorSpace = @"CalibratedBlackColorSpace";
|
||||
CPCalibratedRGBColorSpace = @"CalibratedRGBColorSpace";
|
||||
CPDeviceWhiteColorSpace = @"DeviceWhiteColorSpace";
|
||||
CPDeviceBlackColorSpace = @"DeviceBlackColorSpace";
|
||||
CPDeviceRGBColorSpace = @"DeviceRGBColorSpace";
|
||||
CPDeviceCMYKColorSpace = @"DeviceCMYKColorSpace";
|
||||
CPNamedColorSpace = @"NamedColorSpace";
|
||||
CPPatternColorSpace = @"PatternColorSpace";
|
||||
CPCustomColorSpace = @"CustomColorSpace";
|
||||
|
||||
function CPDrawTiledRects(
|
||||
/* CGRect */ boundsRect,
|
||||
@@ -50,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);
|
||||
@@ -67,31 +77,34 @@ 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, maxX, minY, maxY;
|
||||
var minX,
|
||||
maxX,
|
||||
minY,
|
||||
maxY;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -105,4 +118,4 @@ function CPDrawColorTiledRects(
|
||||
CGContextRestoreGState(context);
|
||||
|
||||
return resultRect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
@import "CGContext.j"
|
||||
|
||||
|
||||
var CPGraphicsContextCurrent = nil;
|
||||
var CPGraphicsContextCurrent = nil,
|
||||
CPGraphicsContextThreadStack = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -52,6 +53,29 @@ var CPGraphicsContextCurrent = nil;
|
||||
CPGraphicsContextCurrent = aGraphicsContext;
|
||||
}
|
||||
|
||||
+ (void)saveGraphicsState
|
||||
{
|
||||
if (!CPGraphicsContextCurrent)
|
||||
return;
|
||||
|
||||
if (!CPGraphicsContextThreadStack)
|
||||
CPGraphicsContextThreadStack = [CPMutableArray array];
|
||||
|
||||
[CPGraphicsContextThreadStack addObject:CPGraphicsContextCurrent];
|
||||
[CPGraphicsContextCurrent saveGraphicsState];
|
||||
}
|
||||
|
||||
+ (void)restoreGraphicsState
|
||||
{
|
||||
var lastContext = [CPGraphicsContextThreadStack lastObject];
|
||||
|
||||
if (lastContext)
|
||||
{
|
||||
[lastContext restoreGraphicsState];
|
||||
[CPGraphicsContextThreadStack removeLastObject];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a graphics context with a provided port.
|
||||
@param aContext the context to initialize with
|
||||
@@ -86,4 +110,27 @@ var CPGraphicsContextCurrent = nil;
|
||||
return _graphicsPort;
|
||||
}
|
||||
|
||||
/*!
|
||||
(Not implemented. Always returns Cappuccino's default, `YES`.)
|
||||
|
||||
Return `isFlipped` of the receiver's focused view, unless no view is focused in which case the receiver's
|
||||
`flipped` flag, as set by `graphicsContextWithGraphicsPort:flipped:`, is returned.
|
||||
|
||||
Note: Cappuccino is flipped by default.
|
||||
*/
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)saveGraphicsState
|
||||
{
|
||||
CGContextSaveGState(_graphicsPort);
|
||||
}
|
||||
|
||||
- (void)restoreGraphicsState
|
||||
{
|
||||
CGContextRestoreGState(_graphicsPort);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+130
-13
@@ -25,9 +25,10 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPRunLoop.j>
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPData.j>
|
||||
|
||||
@import "CPGeometry.j"
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPCompatibility.j"
|
||||
|
||||
CPImageLoadStatusInitialized = 0;
|
||||
CPImageLoadStatusLoading = 1;
|
||||
@@ -44,20 +45,50 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||
|
||||
var imagesForNames = { },
|
||||
AppKitImageForNames = { };
|
||||
AppKitImageForNames = { },
|
||||
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
|
||||
|
||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||
|
||||
function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
/*!
|
||||
Returns a resource image with a relative path and size
|
||||
in a bundle.
|
||||
|
||||
@param filename A filename or relative path to a resource image.
|
||||
@param width Width of the image. May be omitted.
|
||||
@param height Height of the image. May be omitted if width is omitted.
|
||||
@param size Instead of passing width/height, a CGSize may be passed.
|
||||
@param bundle Bundle in which the image resource can be found.
|
||||
If omitted, defaults to the main bundle.
|
||||
@return CPImage
|
||||
*/
|
||||
function CPImageInBundle()
|
||||
{
|
||||
if (!aBundle)
|
||||
aBundle = [CPBundle mainBundle];
|
||||
var filename = arguments[0],
|
||||
size = nil,
|
||||
bundle = nil;
|
||||
|
||||
if (aSize)
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
|
||||
if (typeof(arguments[1]) === "number")
|
||||
{
|
||||
if (arguments[1] !== nil && arguments[1] !== undefined)
|
||||
size = CGSizeMake(arguments[1], arguments[2]);
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
||||
bundle = arguments[3];
|
||||
}
|
||||
else if (typeof(arguments[1]) === "object")
|
||||
{
|
||||
size = arguments[1];
|
||||
bundle = arguments[2];
|
||||
}
|
||||
|
||||
if (!bundle)
|
||||
bundle = [CPBundle mainBundle];
|
||||
|
||||
if (size)
|
||||
return [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:filename] size:size];
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:filename]];
|
||||
}
|
||||
|
||||
function CPAppKitImage(aFilename, aSize)
|
||||
@@ -117,7 +148,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = CPSizeCreateCopy(aSize);
|
||||
_size = CGSizeMakeCopy(aSize);
|
||||
_filename = aFilename;
|
||||
_loadStatus = CPImageLoadStatusInitialized;
|
||||
}
|
||||
@@ -157,6 +188,20 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the receiver with the specified data. The method loads the data into memory.
|
||||
@param someData the CPData object representing the image
|
||||
@return the initialized image
|
||||
*/
|
||||
- (id)initWithData:(CPData)someData
|
||||
{
|
||||
var base64 = [someData base64],
|
||||
type = [base64 hasPrefix:@"/9j/4AAQSkZJRgABAQEASABIAAD/"] ? @"jpg" : @"png",
|
||||
dataURL = "data:image/" + type + ";base64," + base64;
|
||||
|
||||
return [self initWithContentsOfFile:dataURL];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the path of the file associated with this image.
|
||||
*/
|
||||
@@ -165,6 +210,37 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return _filename;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the data associated with this image.
|
||||
@discussion Returns nil if the reciever was not initialized with -initWithData: and the browser does not support the canvas feature;
|
||||
*/
|
||||
- (CPData)data
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var dataURL;
|
||||
|
||||
if ([_filename hasPrefix:@"data:image"])
|
||||
dataURL = _filename;
|
||||
else if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
{
|
||||
var canvas = document.createElement("canvas"),
|
||||
ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = _image.width,
|
||||
canvas.height = _image.height;
|
||||
|
||||
ctx.drawImage(_image, 0, 0);
|
||||
|
||||
dataURL = canvas.toDataURL("image/png");
|
||||
}
|
||||
else
|
||||
return nil;
|
||||
|
||||
var base64 = dataURL.replace(/^data:image\/png;base64,/, "");
|
||||
return [CPData dataWithBase64:base64];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the size of the image.
|
||||
@param the size of the image
|
||||
@@ -226,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
|
||||
@@ -280,7 +364,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.onerror = function ()
|
||||
{
|
||||
@@ -292,7 +376,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.onabort = function ()
|
||||
{
|
||||
@@ -304,7 +388,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.src = _filename;
|
||||
|
||||
@@ -314,6 +398,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
@@ -324,6 +413,24 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var filename = [self filename],
|
||||
size = [self size];
|
||||
|
||||
if (filename.indexOf("data:") === 0)
|
||||
{
|
||||
var index = filename.indexOf(",");
|
||||
|
||||
if (index > 0)
|
||||
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
|
||||
else
|
||||
filename = "data:<unknown type>";
|
||||
}
|
||||
|
||||
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_derefFromImage
|
||||
{
|
||||
@@ -427,6 +534,11 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return _isVertical;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return YES;
|
||||
@@ -491,6 +603,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
return _imageSlices;
|
||||
}
|
||||
|
||||
- (BOOL)isSingleImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
|
||||
+119
-53
@@ -26,10 +26,8 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPShadowView.j"
|
||||
|
||||
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
@global CPImagesPboardType
|
||||
@global appkit_tag_dom_elements
|
||||
|
||||
CPImageAlignCenter = 0;
|
||||
CPImageAlignTop = 1;
|
||||
@@ -41,15 +39,7 @@ CPImageAlignBottomLeft = 6;
|
||||
CPImageAlignBottomRight = 7;
|
||||
CPImageAlignRight = 8;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil,
|
||||
CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
var LEFT_SHADOW_INSET = 3.0,
|
||||
RIGHT_SHADOW_INSET = 3.0,
|
||||
TOP_SHADOW_INSET = 3.0,
|
||||
BOTTOM_SHADOW_INSET = 5.0,
|
||||
VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
|
||||
HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
|
||||
var CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -72,11 +62,24 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [CPImageView class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPView class]];
|
||||
|
||||
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPValueBinding || aBinding === CPValueURLBinding || aBinding === CPValuePathBinding || aBinding === CPDataBinding)
|
||||
return [CPImageViewValueBinder class];
|
||||
else if ([aBinding hasPrefix:CPEditableBinding])
|
||||
return [CPMultipleValueAndBinding class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
@@ -240,7 +243,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[super setImageScaling:anImageScaling];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if ([self currentValueForThemeAttribute:@"image-scaling"] === CPScaleToFit)
|
||||
if ([self currentValueForThemeAttribute:@"image-scaling"] === CPImageScaleAxesIndependently)
|
||||
{
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, 0.0, 0.0);
|
||||
}
|
||||
@@ -297,19 +300,19 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
imageScaling = [self currentValueForThemeAttribute:@"image-scaling"],
|
||||
x = 0.0,
|
||||
y = 0.0,
|
||||
insetWidth = (_hasShadow ? HORIZONTAL_SHADOW_INSET : 0.0),
|
||||
insetHeight = (_hasShadow ? VERTICAL_SHADOW_INSET : 0.0),
|
||||
boundsWidth = _CGRectGetWidth(bounds),
|
||||
boundsHeight = _CGRectGetHeight(bounds),
|
||||
insetWidth = (_hasShadow ? [_shadowView horizontalInset] : 0.0),
|
||||
insetHeight = (_hasShadow ? [_shadowView verticalInset] : 0.0),
|
||||
boundsWidth = CGRectGetWidth(bounds),
|
||||
boundsHeight = CGRectGetHeight(bounds),
|
||||
width = boundsWidth - insetWidth,
|
||||
height = boundsHeight - insetHeight;
|
||||
|
||||
if (imageScaling === CPScaleToFit)
|
||||
if (imageScaling === CPImageScaleAxesIndependently)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(width);
|
||||
_DOMImageElement.height = ROUND(height);
|
||||
#endif
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(width);
|
||||
_DOMImageElement.height = ROUND(height);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -318,17 +321,19 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
if (size.width == -1 && size.height == -1)
|
||||
return;
|
||||
|
||||
if (imageScaling === CPScaleProportionally)
|
||||
switch (imageScaling)
|
||||
{
|
||||
// The max size it can be is size.width x size.height, so only
|
||||
// only proportion otherwise.
|
||||
if (width >= size.width && height >= size.height)
|
||||
{
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
case CPImageScaleProportionallyDown:
|
||||
if (width >= size.width && height >= size.height)
|
||||
{
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
break;
|
||||
}
|
||||
|
||||
// intentionally fall through to the next case
|
||||
|
||||
case CPImageScaleProportionallyUpOrDown:
|
||||
var imageRatio = size.width / size.height,
|
||||
viewRatio = width / height;
|
||||
|
||||
@@ -336,26 +341,19 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
width = height * imageRatio;
|
||||
else
|
||||
height = width / imageRatio;
|
||||
}
|
||||
break;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
case CPImageScaleAxesIndependently:
|
||||
case CPImageScaleNone:
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
break;
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(width);
|
||||
_DOMImageElement.height = ROUND(height);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
}
|
||||
|
||||
if (imageScaling == CPScaleNone)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(size.width);
|
||||
_DOMImageElement.height = ROUND(size.height);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
var x,
|
||||
y;
|
||||
@@ -403,10 +401,10 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
#endif
|
||||
}
|
||||
|
||||
_imageRect = _CGRectMake(x, y, width, height);
|
||||
_imageRect = CGRectMake(x, y, width, height);
|
||||
|
||||
if (_hasShadow)
|
||||
[_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
|
||||
[_shadowView setFrame:CGRectMake(x - [_shadowView leftInset], y - [_shadowView topInset], width + insetWidth, height + insetHeight)];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
@@ -457,6 +455,53 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPImageViewValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[self _setPlaceholder:nil forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:nil forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:nil forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:nil forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setImage:nil];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
var image;
|
||||
|
||||
if (aValue == nil)
|
||||
image = nil;
|
||||
else if (aBinding === CPDataBinding)
|
||||
image = [[CPImage alloc] initWithData:aValue];
|
||||
else if (aBinding === CPValueURLBinding || aBinding === CPValuePathBinding)
|
||||
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",
|
||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
|
||||
@@ -483,6 +528,9 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
_DOMImageElement.setAttribute("draggable", "true");
|
||||
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
||||
}
|
||||
|
||||
if (typeof(appkit_tag_dom_elements) !== "undefined" && !!appkit_tag_dom_elements)
|
||||
_DOMImageElement.setAttribute("data-cappuccino-view", [self className]);
|
||||
#endif
|
||||
|
||||
self = [super initWithCoder:aCoder];
|
||||
@@ -496,7 +544,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
|
||||
|
||||
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
||||
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey])
|
||||
[self setEditable:YES];
|
||||
|
||||
[self setNeedsLayout];
|
||||
@@ -536,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
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPEvent.j"
|
||||
|
||||
@import "CPEvent_Constants.j"
|
||||
@import "CPText.j"
|
||||
|
||||
CPStandardKeyBindings = {
|
||||
@"@.": @"cancelOperation:",
|
||||
|
||||
@"@a": @"selectAll:",
|
||||
@"^a": @"moveToBeginningOfParagraph:",
|
||||
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
|
||||
@"^b": @"moveBackward:",
|
||||
@@ -152,7 +154,7 @@ var CPKeyBindingCache = {};
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if ([self class] !== CPKeyBinding)
|
||||
if (self !== [CPKeyBinding class])
|
||||
return;
|
||||
|
||||
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
|
||||
|
||||
+490
-96
@@ -26,11 +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;
|
||||
@@ -38,9 +41,10 @@ var CPBindingOperationAnd = 0,
|
||||
@implementation CPBinder : CPObject
|
||||
{
|
||||
CPDictionary _info;
|
||||
id _source;
|
||||
id _source @accessors(getter=source);
|
||||
|
||||
JSObject _suppressedNotifications;
|
||||
JSObject _placeholderForMarker;
|
||||
}
|
||||
|
||||
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
|
||||
@@ -93,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];
|
||||
@@ -104,6 +108,7 @@ var CPBindingOperationAnd = 0,
|
||||
+ (void)unbindAllForObject:(id)anObject
|
||||
{
|
||||
var bindings = [bindingsMap objectForKey:[anObject UID]];
|
||||
|
||||
if (!bindings)
|
||||
return;
|
||||
|
||||
@@ -118,23 +123,32 @@ 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 = {};
|
||||
|
||||
if (options)
|
||||
[_info setObject:options forKey:CPOptionsKey];
|
||||
|
||||
[self _updatePlaceholdersWithOptions:options forBinding:aName];
|
||||
|
||||
[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]];
|
||||
}
|
||||
|
||||
@@ -145,15 +159,44 @@ var CPBindingOperationAnd = 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
- (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];
|
||||
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
[_source setValue:newValue forKey:aBinding];
|
||||
if (CPIsControllerMarker(newValue))
|
||||
{
|
||||
[self raiseIfNotApplicable:newValue forKeyPath:keyPath options:options];
|
||||
|
||||
var value = [self _placeholderForMarker:newValue];
|
||||
[self setPlaceholderValue:value withMarker:newValue forBinding:theBinding];
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = [self transformValue:newValue withOptions:options];
|
||||
[self setValue:value forBinding:theBinding];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setValue:aValue forKey:aBinding];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setValue:aValue forKey:aBinding];
|
||||
}
|
||||
|
||||
- (void)reverseSetValueFor:(CPString)aBinding
|
||||
@@ -161,10 +204,18 @@ var CPBindingOperationAnd = 0,
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [_source valueForKeyPath:aBinding];
|
||||
newValue = [self valueForBinding:aBinding];
|
||||
|
||||
newValue = [self reverseTransformValue:newValue withOptions:options];
|
||||
|
||||
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
[destination setValue:newValue forKeyPath:keyPath];
|
||||
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source valueForKeyPath:aBinding];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||
@@ -173,6 +224,7 @@ var CPBindingOperationAnd = 0,
|
||||
return;
|
||||
|
||||
var objectSuppressions = _suppressedNotifications[[anObject UID]];
|
||||
|
||||
if (objectSuppressions && objectSuppressions[aKeyPath])
|
||||
return;
|
||||
|
||||
@@ -191,6 +243,7 @@ var CPBindingOperationAnd = 0,
|
||||
if (!valueTransformer)
|
||||
{
|
||||
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
||||
|
||||
if (valueTransformerClass)
|
||||
{
|
||||
valueTransformer = [[valueTransformerClass alloc] init];
|
||||
@@ -204,14 +257,17 @@ 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;
|
||||
}
|
||||
|
||||
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
|
||||
- (id)reverseTransformValue:(id)aValue withOptions:(CPDictionary)options
|
||||
{
|
||||
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
|
||||
valueTransformer;
|
||||
@@ -249,6 +305,7 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
|
||||
if (!objectSuppressions)
|
||||
_suppressedNotifications[uid] = objectSuppressions = {};
|
||||
|
||||
@@ -265,12 +322,57 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
|
||||
if (!objectSuppressions)
|
||||
return;
|
||||
|
||||
delete objectSuppressions[aKeyPath];
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var count = [CPBinderPlaceholderMarkers count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var marker = CPBinderPlaceholderMarkers[count],
|
||||
optionName = CPBinderPlaceholderOptions[count],
|
||||
isExplicit = [options containsKey:optionName],
|
||||
placeholder = isExplicit ? [options objectForKey:optionName] : nil;
|
||||
|
||||
[self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||
{
|
||||
[self _updatePlaceholdersWithOptions:options];
|
||||
}
|
||||
|
||||
- (JSObject)_placeholderForMarker:(id)aMarker
|
||||
{
|
||||
var placeholder = _placeholderForMarker[[aMarker UID]];
|
||||
|
||||
if (placeholder)
|
||||
return placeholder.value;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)_setPlaceholder:(id)aPlaceholder forMarker:(id)aMarker isDefault:(BOOL)isDefault
|
||||
{
|
||||
if (isDefault)
|
||||
{
|
||||
var existingPlaceholder = _placeholderForMarker[[aMarker UID]];
|
||||
|
||||
// Don't overwrite an explicitly set placeholder with a default.
|
||||
if (existingPlaceholder && !existingPlaceholder.isDefault)
|
||||
return;
|
||||
}
|
||||
|
||||
_placeholderForMarker[[aMarker UID]] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPObject (KeyValueBindingCreation)
|
||||
@@ -280,7 +382,7 @@ var CPBindingOperationAnd = 0,
|
||||
[CPBinder exposeBinding:aBinding forClass:[self class]];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
return [CPBinder class];
|
||||
}
|
||||
@@ -311,10 +413,10 @@ var CPBindingOperationAnd = 0,
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
{
|
||||
if (!anObject || !aKeyPath)
|
||||
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
|
||||
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
||||
|
||||
//if (![[self exposedBindings] containsObject:aBinding])
|
||||
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
|
||||
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
|
||||
|
||||
var binderClass = [[self class] _binderClassForBinding:aBinding];
|
||||
|
||||
@@ -333,7 +435,7 @@ var CPBindingOperationAnd = 0,
|
||||
[binderClass unbind:aBinding forObject:self];
|
||||
}
|
||||
|
||||
- (id)_replacementKeyPathForBinding:(CPString)binding
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)binding
|
||||
{
|
||||
return binding;
|
||||
}
|
||||
@@ -342,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
|
||||
{
|
||||
@@ -362,8 +464,9 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPKeyValueOrBinding : CPBinder
|
||||
@implementation _CPMultipleValueBooleanBinding : CPBinder
|
||||
{
|
||||
CPBindingOperationKind _operation;
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
@@ -373,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
|
||||
@@ -381,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 resolveMultipleValues(/*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 invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
|
||||
{
|
||||
var theBinding = [bindings objectForKey:targetKey],
|
||||
infoDictionary = theBinding._info,
|
||||
@end
|
||||
|
||||
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
||||
options = [infoDictionary objectForKey:CPOptionsKey],
|
||||
@implementation CPMultipleValueAndBinding : _CPMultipleValueBooleanBinding
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
_operation = CPBindingOperationAnd;
|
||||
|
||||
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];
|
||||
@@ -443,28 +638,195 @@ var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argu
|
||||
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
|
||||
|
||||
// Keys in dictionary returned by infoForBinding
|
||||
@@ -473,23 +835,51 @@ 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";
|
||||
CPEditableBinding = @"editable";
|
||||
CPEnabledBinding = @"enabled";
|
||||
CPFontBinding = @"font";
|
||||
CPHiddenBinding = @"hidden";
|
||||
CPSelectedIndexBinding = @"selectedIndex";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
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";
|
||||
CPFontNameBinding = @"fontName";
|
||||
CPFontBoldBinding = @"fontBold";
|
||||
CPHiddenBinding = @"hidden";
|
||||
CPFilterPredicateBinding = @"filterPredicate";
|
||||
CPMaxValueBinding = @"maxValue";
|
||||
CPMinValueBinding = @"minValue";
|
||||
CPPredicateBinding = @"predicate";
|
||||
CPSelectedIndexBinding = @"selectedIndex";
|
||||
CPSelectedLabelBinding = @"selectedLabel";
|
||||
CPSelectedObjectBinding = @"selectedObject";
|
||||
CPSelectedObjectsBinding = @"selectedObjects";
|
||||
CPSelectedTagBinding = @"selectedTag";
|
||||
CPSelectedValueBinding = @"selectedValue";
|
||||
CPSelectedValuesBinding = @"selectedValues";
|
||||
CPSelectionIndexesBinding = @"selectionIndexes";
|
||||
CPTargetBinding = @"target";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPTitleBinding = @"title";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
CPValueURLBinding = @"valueURL";
|
||||
CPValuePathBinding = @"valuePath";
|
||||
CPDataBinding = @"data";
|
||||
|
||||
//Binding options constants
|
||||
// Binding options constants
|
||||
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
||||
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
|
||||
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
|
||||
@@ -518,4 +908,8 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
|
||||
}
|
||||
};
|
||||
|
||||
var CPBinderPlaceholderMarkers = [CPMultipleValuesMarker, CPNoSelectionMarker, CPNotApplicableMarker, CPNullMarker],
|
||||
CPBinderPlaceholderOptions = [CPMultipleValuesPlaceholderBindingOption, CPNoSelectionPlaceholderBindingOption, CPNotApplicablePlaceholderBindingOption, CPNullPlaceholderBindingOption];
|
||||
|
||||
|
||||
+34
-79
@@ -21,6 +21,9 @@
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPTickMarkBelow = 0;
|
||||
CPTickMarkAbove = 1;
|
||||
@@ -32,14 +35,6 @@ CPContinuousCapacityLevelIndicatorStyle = 1;
|
||||
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
||||
CPRatingLevelIndicatorStyle = 3;
|
||||
|
||||
var _CPLevelIndicatorBezelColor = nil,
|
||||
_CPLevelIndicatorSegmentEmptyColor = nil,
|
||||
_CPLevelIndicatorSegmentNormalColor = nil,
|
||||
_CPLevelIndicatorSegmentWarningColor = nil,
|
||||
_CPLevelIndicatorSegmentCriticalColor = nil,
|
||||
|
||||
_CPLevelIndicatorSpacing = 1;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPLevelIndicator
|
||||
@@ -62,54 +57,21 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
BOOL _isTracking;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
|
||||
return "level-indicator";
|
||||
}
|
||||
|
||||
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
|
||||
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
|
||||
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
|
||||
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
|
||||
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
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
|
||||
@@ -122,37 +84,31 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
_maxValue = 2;
|
||||
_warningValue = 2;
|
||||
_criticalValue = 2;
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
// TODO Make themable.
|
||||
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
|
||||
[bezelView setBackgroundColor:[self valueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
var segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segmentCount <= 0)
|
||||
return;
|
||||
|
||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
||||
var filledColor = [self valueForThemeAttribute:@"color-normal"],
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value < _criticalValue)
|
||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
||||
else if (value < _warningValue)
|
||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
||||
if (value <= _criticalValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||
else if (value <= _warningValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
{
|
||||
@@ -160,13 +116,13 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:bezelView];
|
||||
|
||||
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
|
||||
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : [self valueForThemeAttribute:@"color-empty"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
@@ -174,11 +130,11 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
// 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;
|
||||
}
|
||||
@@ -188,20 +144,21 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segment >= segmentCount)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
var basicSegmentWidth = bounds.size.width / segmentCount,
|
||||
segmentFrame = CGRectCreateCopy([self bounds]);
|
||||
segmentFrame = CGRectCreateCopy([self bounds]),
|
||||
spacing = [self valueForThemeAttribute:@"spacing"];
|
||||
|
||||
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||
segmentFrame.origin.y = (CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
|
||||
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
|
||||
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - spacing;
|
||||
segmentFrame.size.height = segmentHeight;
|
||||
|
||||
return segmentFrame;
|
||||
}
|
||||
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -223,7 +180,7 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
- (CPView)hitTest:(CPPoint)aPoint
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
// Don't swallow clicks when displayed in a table.
|
||||
if (![self isEditable])
|
||||
@@ -253,7 +210,7 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
bounds = [self bounds],
|
||||
oldValue = [self doubleValue];
|
||||
oldValue = [self doubleValue],
|
||||
newValue = oldValue;
|
||||
|
||||
// Moving the mouse outside of the widget to the left sets it
|
||||
@@ -385,8 +342,6 @@ var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
|
||||
|
||||
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
+114
-45
@@ -25,12 +25,10 @@
|
||||
@import <Foundation/CPNotificationCenter.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "_CPMenuManager.j"
|
||||
@import "CPApplication.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPPanel.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
||||
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
||||
@@ -38,12 +36,8 @@ CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
|
||||
|
||||
CPMenuDidEndTrackingNotification = @"CPMenuDidEndTrackingNotification";
|
||||
|
||||
var MENUBAR_HEIGHT = 28.0;
|
||||
|
||||
var _CPMenuBarVisible = NO,
|
||||
_CPMenuBarTitle = @"",
|
||||
_CPMenuBarIconImage = nil,
|
||||
_CPMenuBarIconImageAlphaValue = 1.0,
|
||||
_CPMenuBarAttributes = nil,
|
||||
_CPMenuBarSharedWindow = nil;
|
||||
|
||||
@@ -74,16 +68,18 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
|
||||
CPEvent _lastCloseEvent;
|
||||
}
|
||||
|
||||
// Managing the Menu Bar
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== CPMenu)
|
||||
if (self !== [CPMenu class])
|
||||
return;
|
||||
|
||||
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
|
||||
[[self class] setMenuBarAttributes:@{}];
|
||||
}
|
||||
|
||||
+ (BOOL)menuBarVisible
|
||||
@@ -109,8 +105,8 @@ var _CPMenuBarVisible = NO,
|
||||
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
|
||||
|
||||
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
|
||||
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
|
||||
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
|
||||
[_CPMenuBarSharedWindow setIconImage:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-icon-image" forClass:_CPMenuView]];
|
||||
[_CPMenuBarSharedWindow setIconImageAlphaValue:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-icon-image-alpha-value" forClass:_CPMenuView]];
|
||||
|
||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
||||
@@ -154,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
|
||||
{
|
||||
@@ -178,8 +181,8 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
else if (!textColor && !titleColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarTextColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-title-color" forClass:_CPMenuView] forKey:@"CPMenuBarTitleColor"];
|
||||
}
|
||||
|
||||
if (!textShadowColor && titleShadowColor)
|
||||
@@ -190,18 +193,18 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
else if (!textShadowColor && !titleShadowColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] 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:[CPColor colorWithCalibratedRed:94.0 / 255.0 green:130.0 / 255.0 blue:186.0 / 255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightColor"];
|
||||
|
||||
if (!highlightTextColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
|
||||
if (!highlightTextShadowColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
[self _setOrRemoveMenuBarAttribute:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-highlight-text-shadow-color" forClass:_CPMenuView] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
if (_CPMenuBarSharedWindow)
|
||||
{
|
||||
@@ -230,14 +233,14 @@ var _CPMenuBarVisible = NO,
|
||||
- (float)menuBarHeight
|
||||
{
|
||||
if (self === [CPApp mainMenu])
|
||||
return MENUBAR_HEIGHT;
|
||||
return [CPMenu menuBarHeight];
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
+ (float)menuBarHeight
|
||||
{
|
||||
return MENUBAR_HEIGHT;
|
||||
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-height" forClass:_CPMenuView];
|
||||
}
|
||||
|
||||
// Creating a CPMenu Object
|
||||
@@ -352,8 +355,12 @@ var _CPMenuBarVisible = NO,
|
||||
while (count--)
|
||||
[_items[count] setMenu:nil];
|
||||
|
||||
[self _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
// Because we are changing _items directly, be sure to notify KVO
|
||||
[self willChangeValueForKey:@"items"];
|
||||
_items = [CPMutableArray array];
|
||||
_highlightedIndex = CPNotFound;
|
||||
[self didChangeValueForKey:@"items"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -362,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"];
|
||||
@@ -370,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
|
||||
@@ -603,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
|
||||
{
|
||||
@@ -612,6 +625,7 @@ var _CPMenuBarVisible = NO,
|
||||
return;
|
||||
|
||||
var items = [self itemArray];
|
||||
|
||||
for (var i = 0; i < [items count]; i++)
|
||||
{
|
||||
var item = [items objectAtIndex:i];
|
||||
@@ -621,12 +635,36 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
[item _setEnabled:NO];
|
||||
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]];
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item _setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
@@ -671,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];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -711,10 +755,7 @@ var _CPMenuBarVisible = NO,
|
||||
if (aView && !theWindow)
|
||||
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
|
||||
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
[self _menuWillOpen];
|
||||
|
||||
// Convert location to global coordinates if not already in them.
|
||||
if (aView)
|
||||
@@ -802,17 +843,16 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||
{
|
||||
var delegate = [aMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:aMenu];
|
||||
[aMenu _menuWillOpen];
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
aFont = [CPFont systemFontOfSize:[CPFont systemFontSize]];
|
||||
|
||||
var theWindow = [aView window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:aMenu font:aFont];
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuWindow];
|
||||
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
var constraintRect = [CPMenu _constraintRectForView:aView],
|
||||
@@ -875,7 +915,15 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (CPMenuItem)highlightedItem
|
||||
{
|
||||
return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
|
||||
if (_highlightedIndex < 0)
|
||||
return nil;
|
||||
|
||||
var highlightedItem = _items[_highlightedIndex];
|
||||
|
||||
if ([highlightedItem isSeparatorItem])
|
||||
return nil;
|
||||
|
||||
return highlightedItem;
|
||||
}
|
||||
|
||||
// Managing the Delegate
|
||||
@@ -890,6 +938,26 @@ var _CPMenuBarVisible = NO,
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)_menuWillOpen
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
}
|
||||
|
||||
- (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:)])
|
||||
[delegate menuDidClose:self];
|
||||
}
|
||||
|
||||
// Handling Tracking
|
||||
/*!
|
||||
Cancels tracking.
|
||||
@@ -903,7 +971,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
[CPApp sendEvent:[CPEvent
|
||||
otherEventWithType:CPAppKitDefined
|
||||
location:_CGPointMakeZero()
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
@@ -954,8 +1022,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = _items[index],
|
||||
modifierMask = [item keyEquivalentModifierMask];
|
||||
var item = _items[index];
|
||||
|
||||
if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
|
||||
{
|
||||
@@ -1084,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
|
||||
@@ -1098,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
|
||||
|
||||
@@ -1,14 +1,33 @@
|
||||
/*
|
||||
* _CPMenuBarWindow.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPPanel.j"
|
||||
@import "_CPMenuWindow.j"
|
||||
@import "_CPMenuManager.j"
|
||||
|
||||
@class _CPMenuView
|
||||
|
||||
var MENUBAR_HEIGHT = 28.0,
|
||||
MENUBAR_MARGIN = 10.0,
|
||||
MENUBAR_LEFT_MARGIN = 10.0,
|
||||
MENUBAR_RIGHT_MARGIN = 10.0;
|
||||
|
||||
var _CPMenuBarWindowBackgroundColor = nil,
|
||||
_CPMenuBarWindowFont = nil;
|
||||
@global CPMenuDidAddItemNotification
|
||||
@global CPMenuDidChangeItemNotification
|
||||
@global CPMenuDidRemoveItemNotification
|
||||
|
||||
@implementation _CPMenuBarWindow : CPPanel
|
||||
{
|
||||
@@ -32,19 +51,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
CPColor _highlightTextShadowColor;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuBarWindow class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
|
||||
}
|
||||
|
||||
+ (CPFont)font
|
||||
{
|
||||
return _CPMenuBarWindowFont;
|
||||
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-font" forClass:_CPMenuView];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -52,12 +61,14 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
// This only shows up in browser land, so don't bother calculating metrics in desktop.
|
||||
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
|
||||
|
||||
contentRect.size.height = MENUBAR_HEIGHT;
|
||||
contentRect.size.height = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView];
|
||||
|
||||
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_constrainsToUsableScreen = NO;
|
||||
|
||||
[self setLevel:CPMainMenuWindowLevel];
|
||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||
|
||||
@@ -74,7 +85,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:[CPFont systemFontSize] + 1]];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
|
||||
@@ -119,12 +130,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (!aColor)
|
||||
{
|
||||
if (!_CPMenuBarWindowBackgroundColor)
|
||||
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||
|
||||
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
|
||||
}
|
||||
[[self contentView] setBackgroundColor:[[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-background-color" forClass:_CPMenuView]];
|
||||
else
|
||||
[[self contentView] setBackgroundColor:aColor];
|
||||
}
|
||||
@@ -137,6 +143,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
_textColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextColor:) withObject:_textColor];
|
||||
}
|
||||
|
||||
- (void)setTitleColor:(CPColor)aColor
|
||||
@@ -157,6 +164,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuTextShadowColor:) withObject:_textShadowColor];
|
||||
}
|
||||
|
||||
- (void)setTitleShadowColor:(CPColor)aColor
|
||||
@@ -175,6 +183,8 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
return;
|
||||
|
||||
_highlightColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightColor:) withObject:_highlightColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextColor:(CPColor)aColor
|
||||
@@ -184,7 +194,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
_highlightTextColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextColor:) withObject:_highlightTextColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||
@@ -194,7 +204,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
_highlightTextShadowColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setParentMenuHighlightTextShadowColor:) withObject:_highlightTextShadowColor];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
@@ -257,7 +267,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
for (var index = 0; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
menuItemView = [item _menuItemView];
|
||||
@@ -316,6 +326,11 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
|
||||
@@ -335,7 +350,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
- (CPFont)font
|
||||
{
|
||||
[CPFont systemFontOfSize:12.0];
|
||||
[CPFont systemFontOfSize:[CPFont systemFontSize]];
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
@@ -344,7 +359,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
index = 0,
|
||||
count = items.length,
|
||||
|
||||
x = MENUBAR_LEFT_MARGIN,
|
||||
x = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-left-margin" forClass:_CPMenuView],
|
||||
y = 0.0,
|
||||
isLeftAligned = YES;
|
||||
|
||||
@@ -354,7 +369,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
if ([item isSeparatorItem])
|
||||
{
|
||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||
x = CGRectGetWidth([self frame]) - [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-right-margin" forClass:_CPMenuView];
|
||||
isLeftAligned = NO;
|
||||
|
||||
continue;
|
||||
@@ -368,13 +383,13 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
if (isLeftAligned)
|
||||
{
|
||||
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView])];
|
||||
|
||||
x += CGRectGetWidth([menuItemView frame]);
|
||||
}
|
||||
else
|
||||
{
|
||||
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-bar-window-height" forClass:_CPMenuView])];
|
||||
|
||||
x = CGRectGetMinX([menuItemView frame]);
|
||||
}
|
||||
@@ -402,7 +417,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
||||
|
||||
if (!_CGSizeEqualToSize(size, aRect.size))
|
||||
if (!CGSizeEqualToSize(size, aRect.size))
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -452,102 +467,3 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuBarView : _CPMenuView
|
||||
{
|
||||
}
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
||||
}
|
||||
|
||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
if (!CGRectContainsPoint(bounds, aPoint))
|
||||
return CPNotFound;
|
||||
|
||||
var x = aPoint.x,
|
||||
low = 0,
|
||||
high = _visibleMenuItemInfos.length - 1;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
info = _visibleMenuItemInfos[middle],
|
||||
frame = [info.view frame];
|
||||
|
||||
if (x < CGRectGetMinX(frame))
|
||||
high = middle - 1;
|
||||
|
||||
else if (x > CGRectGetMaxX(frame))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return info.index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
var items = [_menu itemArray],
|
||||
index = 0,
|
||||
count = items.length,
|
||||
|
||||
x = MENUBAR_LEFT_MARGIN,
|
||||
y = 0.0,
|
||||
isLeftAligned = YES;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = items[index];
|
||||
|
||||
if ([item isSeparatorItem])
|
||||
{
|
||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||
isLeftAligned = NO;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
var menuItemView = [item _menuItemView],
|
||||
frame = [menuItemView frame];
|
||||
|
||||
if (isLeftAligned)
|
||||
{
|
||||
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||
|
||||
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||
|
||||
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
|
||||
}
|
||||
}
|
||||
|
||||
var bounds = [[self contentView] bounds],
|
||||
titleFrame = [_titleField frame];
|
||||
|
||||
if ([_iconImageView isHidden])
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
else
|
||||
{
|
||||
var iconFrame = [_iconImageView frame],
|
||||
iconWidth = CGRectGetWidth(iconFrame),
|
||||
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
||||
|
||||
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+165
-51
@@ -1,16 +1,52 @@
|
||||
/*
|
||||
* _CPMenuManager.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPNotificationCenter.j>
|
||||
|
||||
@import "CPEvent.j"
|
||||
@import "CPKeyBinding.j"
|
||||
|
||||
@class CPWindow
|
||||
@class _CPMenuWindow
|
||||
|
||||
|
||||
_CPMenuManagerScrollingStateUp = -1,
|
||||
_CPMenuManagerScrollingStateDown = 1,
|
||||
@global CPApp
|
||||
@global CPMenuDidEndTrackingNotification
|
||||
@global _CPMenuWindowMenuBarBackgroundStyle
|
||||
@global _CPMenuWindowPopUpBackgroundStyle
|
||||
|
||||
_CPMenuManagerScrollingStateUp = -1;
|
||||
_CPMenuManagerScrollingStateDown = 1;
|
||||
_CPMenuManagerScrollingStateNone = 0;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500,
|
||||
var STICKY_TIME_INTERVAL = 0.4,
|
||||
SharedMenuManager = nil;
|
||||
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
CPEvent _openEvent;
|
||||
BOOL _mouseWasDragged;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
|
||||
@@ -25,6 +61,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
CPMenuItem _previousActiveItem;
|
||||
int _showTimerID;
|
||||
|
||||
int _menuBarButtonItemIndex;
|
||||
}
|
||||
|
||||
+ (_CPMenuManager)sharedMenuManager
|
||||
@@ -60,9 +98,13 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
var menu = [aMenuContainer menu];
|
||||
|
||||
if ([menu numberOfItems] <= 0)
|
||||
return;
|
||||
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];//new Date();
|
||||
_startTime = [anEvent timestamp];
|
||||
_openEvent = anEvent;
|
||||
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||
|
||||
_constraintRect = aRect;
|
||||
@@ -81,15 +123,22 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
_menuBarButtonItemIndex = activeItemIndex;
|
||||
_menuBarButtonMenuContainer = aMenuContainer;
|
||||
// _menuBarButtonMenuContainer = aMenuContainer;
|
||||
|
||||
if ([activeItem _isMenuBarButton])
|
||||
return [self trackMenuBarButtonEvent:anEvent];
|
||||
}
|
||||
|
||||
_mouseWasDragged = NO;
|
||||
|
||||
[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],
|
||||
@@ -99,8 +148,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPKeyDown)
|
||||
{
|
||||
var menu = trackingMenu,
|
||||
@@ -116,26 +163,18 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if ([menu numberOfItems])
|
||||
[self interpretKeyEvent:anEvent forMenu:menu];
|
||||
|
||||
[self _trackAgain];
|
||||
return;
|
||||
}
|
||||
|
||||
if (_keyBuffer)
|
||||
{
|
||||
if (([CPDate date] - _startTime) > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] / 2))
|
||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:YES];
|
||||
|
||||
if (type === CPPeriodic)
|
||||
return;
|
||||
}
|
||||
|
||||
// Periodic events don't have a valid location.
|
||||
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
||||
|
||||
// Remember this for the next periodic event.
|
||||
_lastGlobalLocation = globalLocation;
|
||||
|
||||
if (!_lastGlobalLocation)
|
||||
if (!globalLocation)
|
||||
{
|
||||
[self _trackAgain];
|
||||
return;
|
||||
}
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||
@@ -146,6 +185,43 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
/*
|
||||
Click outside the menu structure?
|
||||
|
||||
The event which caused the menu to open is not considered even if it's
|
||||
technically a click outside of an open menu, since this would mean the same
|
||||
click which opened the menu could also close it. This is actually common.
|
||||
E.g. you click on a button and it opens a menu below itself.
|
||||
*/
|
||||
if (type === CPLeftMouseDown && _openEvent !== anEvent && (!activeMenuContainer || !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation)))
|
||||
{
|
||||
[self completeTracking];
|
||||
|
||||
/*
|
||||
You can close and interact with a control in a single click. E.g. you can have a menu open,
|
||||
click on a button outside of it and have the menu immediately close and the button activate,
|
||||
without having to click once to close the menu and once to activate the button.
|
||||
|
||||
Since we normally dequeue the event after tracking it, we'll have to put it back on the stack
|
||||
in this special case. Note that it's important the event is executed /right now/, since certain
|
||||
controls such as HTML upload buttons need a native click event at the top of the stack trace
|
||||
to activate - it's not something we can fake later.
|
||||
*/
|
||||
[CPApp sendEvent:anEvent];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[self _trackAgain];
|
||||
|
||||
// unhighlight when mouse is moved off the menu
|
||||
if (_lastGlobalLocation && CGRectContainsPoint([activeMenuContainer globalFrame], _lastGlobalLocation)
|
||||
&& !CGRectContainsPoint([activeMenuContainer globalFrame], globalLocation))
|
||||
[activeMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
// Remember this for the next periodic event.
|
||||
_lastGlobalLocation = globalLocation;
|
||||
|
||||
// If the item isn't enabled its as if we clicked on nothing.
|
||||
if (![activeItem isEnabled] || [activeItem _isMenuBarButton])
|
||||
{
|
||||
@@ -155,7 +231,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
var mouseOverMenuView = [activeItem view];
|
||||
|
||||
if (type === CPScrollWheel)
|
||||
if (type === CPScrollWheel && ![activeMenuContainer isMenuBar])
|
||||
[activeMenuContainer scrollByDelta:[anEvent deltaY]];
|
||||
|
||||
if (type === CPPeriodic)
|
||||
@@ -174,16 +250,16 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||
{
|
||||
[mouseOverMenuView mouseExited:anEvent];
|
||||
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||
// FIXME: Possibly multiple of these?
|
||||
[_lastMouseOverMenuView mouseEntered:anEvent];
|
||||
[mouseOverMenuView mouseEntered:anEvent];
|
||||
|
||||
_lastMouseOverMenuView = mouseOverMenuView;
|
||||
}
|
||||
|
||||
var menuContainerWindow = activeMenuContainer;
|
||||
|
||||
if (![menuContainerWindow isKindOfClass:[CPWindow class]])
|
||||
if (![menuContainerWindow isKindOfClass:CPWindow])
|
||||
menuContainerWindow = [menuContainerWindow window];
|
||||
|
||||
[menuContainerWindow
|
||||
@@ -205,10 +281,14 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
_lastMouseOverMenuView = nil;
|
||||
}
|
||||
|
||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||
if (activeItemIndex !== CPNotFound)
|
||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||
|
||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
|
||||
{
|
||||
if (type === CPLeftMouseDragged)
|
||||
_mouseWasDragged = YES;
|
||||
|
||||
var oldScrollingState = _scrollingState;
|
||||
|
||||
_scrollingState = [activeMenuContainer scrollingStateForPoint:globalLocation];
|
||||
@@ -221,8 +301,38 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
|
||||
[trackingMenu cancelTracking];
|
||||
else if (type === CPLeftMouseUp || type === CPRightMouseUp)
|
||||
{
|
||||
/*
|
||||
There are a few possibilites:
|
||||
|
||||
1. The user clicks and releases without dragging within the sticky time.
|
||||
This is considered a regular mouse click and not a drag. In this case
|
||||
we allow the user to track the menu by moving the mouse. The next
|
||||
mouse up will end tracking.
|
||||
|
||||
2. The user clicks and releases without dragging after the sticky time.
|
||||
This is considered a drag and release and tracking ends.
|
||||
|
||||
3. The user clicks, drags and then releases. Tracking ends.
|
||||
*/
|
||||
if (_mouseWasDragged || ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
|
||||
{
|
||||
/*
|
||||
Close the menu if:
|
||||
|
||||
1. The mouse was dragged.
|
||||
2. The mouse is released in the menubar.
|
||||
3. The current item has a submenu with a custom action.
|
||||
*/
|
||||
if (_mouseWasDragged ||
|
||||
[activeMenuContainer isMenuBar] ||
|
||||
[activeItem action] !== @selector(submenuAction:))
|
||||
{
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent previous selected menu items from opening by stopping the timer if a
|
||||
@@ -234,7 +344,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
}
|
||||
|
||||
// If the item has a submenu, show it.
|
||||
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
|
||||
if ([activeItem hasSubmenu]) // && [activeItem action] === @selector(submenuAction:))
|
||||
{
|
||||
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
|
||||
newMenuOrigin;
|
||||
@@ -306,11 +416,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
|
||||
var delegate = [trackingMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:trackingMenu];
|
||||
[trackingMenu _menuDidClose];
|
||||
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
@@ -351,8 +457,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
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)
|
||||
@@ -379,6 +485,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var count = _menuContainerStack.length,
|
||||
index = count;
|
||||
|
||||
[newMenu _menuWillOpen];
|
||||
|
||||
// Hide all menus up to the base menu...
|
||||
while (index--)
|
||||
{
|
||||
@@ -390,7 +498,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
break;
|
||||
|
||||
// If this menu is already being shown, unhighlight and return.
|
||||
if (menu === newMenu)//&& [menu supermenu] === baseMenu)
|
||||
if (menu === newMenu) //&& [menu supermenu] === baseMenu)
|
||||
return [newMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
[menuContainer orderOut:self];
|
||||
@@ -398,6 +506,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||
[_menuContainerStack removeObjectAtIndex:index];
|
||||
|
||||
[menu _menuDidClose];
|
||||
}
|
||||
|
||||
if (!newMenu)
|
||||
@@ -434,7 +544,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var iter = [selectorNames objectEnumerator],
|
||||
obj;
|
||||
|
||||
while (obj = [iter nextObject])
|
||||
while ((obj = [iter nextObject]) !== nil)
|
||||
{
|
||||
var aSelector = CPSelectorFromString(obj);
|
||||
|
||||
@@ -444,9 +554,12 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
}
|
||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
|
||||
{
|
||||
if (([anEvent timestamp] - _startTime) > STICKY_TIME_INTERVAL)
|
||||
_keyBuffer = nil;
|
||||
|
||||
if (!_keyBuffer)
|
||||
{
|
||||
_startTime = [CPDate date];
|
||||
_startTime = [anEvent timestamp];
|
||||
_keyBuffer = character;
|
||||
|
||||
[CPEvent stopPeriodicEvents];
|
||||
@@ -455,17 +568,17 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
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;
|
||||
|
||||
while (obj = [iter nextObject])
|
||||
while ((obj = [iter nextObject]) !== nil)
|
||||
{
|
||||
if ([obj isHidden] || ![obj isEnabled])
|
||||
continue;
|
||||
@@ -477,13 +590,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldClear)
|
||||
{
|
||||
[CPEvent stopPeriodicEvents];
|
||||
_keyBuffer = Nil;
|
||||
}
|
||||
else
|
||||
_startTime = [CPDate date];
|
||||
_startTime = [CPEvent currentTimestamp];
|
||||
}
|
||||
|
||||
- (void)scrollToBeginningOfDocument:(CPMenu)menu
|
||||
@@ -511,7 +618,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return;
|
||||
}
|
||||
|
||||
next = current + (last - first);
|
||||
var next = current + (last - first);
|
||||
|
||||
if (next < [menu numberOfItems])
|
||||
[menu _highlightItemAtIndex:next];
|
||||
@@ -539,7 +646,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return;
|
||||
}
|
||||
|
||||
next = current - (last - first);
|
||||
var next = current - (last - first);
|
||||
|
||||
if (next < 0)
|
||||
[menu _highlightItemAtIndex:0];
|
||||
@@ -620,6 +727,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveDown:menu];
|
||||
}
|
||||
else if (menu == [CPApp mainMenu])
|
||||
[menu _highlightItemAtIndex:0];
|
||||
}
|
||||
|
||||
- (void)moveUp:(CPMenu)menu
|
||||
@@ -627,7 +736,12 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var index = menu._highlightedIndex - 1;
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
if (index != CPNotFound || menu == [CPApp mainMenu])
|
||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[menu _highlightItemAtIndex:index];
|
||||
|
||||
|
||||
+101
-82
@@ -1,5 +1,29 @@
|
||||
@import "CPWindow.j"
|
||||
/*
|
||||
* _CPMenuWindow.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPClipView.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "_CPMenuManager.j"
|
||||
|
||||
var _CPMenuWindowPool = [],
|
||||
_CPMenuWindowPoolCapacity = 5,
|
||||
@@ -10,15 +34,6 @@ _CPMenuWindowMenuBarBackgroundStyle = 0;
|
||||
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
TOP_MARGIN = 5.0,
|
||||
LEFT_MARGIN = 1.0,
|
||||
RIGHT_MARGIN = 1.0,
|
||||
BOTTOM_MARGIN = 5.0,
|
||||
|
||||
SCROLL_INDICATOR_HEIGHT = 16.0;
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@@ -63,26 +78,17 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
_CPMenuWindowPool.push(aMenuWindow);
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuWindow class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
|
||||
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
|
||||
}
|
||||
|
||||
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
_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];
|
||||
@@ -92,26 +98,24 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
|
||||
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake([_menuView valueForThemeAttribute:@"menu-window-margin-inset"].left, [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top, 0.0, 0.0)];
|
||||
[_menuClipView setDocumentView:_menuView];
|
||||
|
||||
[contentView addSubview:_menuClipView];
|
||||
|
||||
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
|
||||
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
|
||||
[_moreAboveView setImage:[_menuView valueForThemeAttribute:@"menu-window-more-above-image"]];
|
||||
[_moreAboveView setFrameSize:[[_menuView valueForThemeAttribute:@"menu-window-more-above-image"] size]];
|
||||
|
||||
[contentView addSubview:_moreAboveView];
|
||||
|
||||
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
|
||||
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
|
||||
[_moreBelowView setImage:[_menuView valueForThemeAttribute:@"menu-window-more-below-image"]];
|
||||
[_moreBelowView setFrameSize:[[_menuView valueForThemeAttribute:@"menu-window-more-below-image"] size]];
|
||||
|
||||
[contentView addSubview:_moreBelowView];
|
||||
|
||||
[self setShadowStyle:CPWindowShadowStyleMenu];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -119,7 +123,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
+ (float)_standardLeftMargin
|
||||
{
|
||||
return LEFT_MARGIN;
|
||||
return [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-margin-inset" forClass:_CPMenuView].left;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
@@ -141,36 +145,10 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
|
||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||
]]];
|
||||
color = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-pop-up-background-style-color" forClass:_CPMenuView];
|
||||
|
||||
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||
]]];
|
||||
color = [[CPTheme defaultTheme] valueForAttributeWithName:@"menu-window-menu-bar-background-style-color" forClass:_CPMenuView];
|
||||
|
||||
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
||||
}
|
||||
@@ -188,12 +166,13 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[aMenu _setMenuWindow:self];
|
||||
[_menuView setMenu:aMenu];
|
||||
|
||||
var menuViewSize = [_menuView frame].size;
|
||||
var menuViewSize = [_menuView frame].size,
|
||||
marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"];
|
||||
|
||||
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
|
||||
[self setFrameSize:CGSizeMake(marginInset.left + menuViewSize.width + marginInset.right, marginInset.top + menuViewSize.height + marginInset.bottom)];
|
||||
|
||||
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
||||
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
|
||||
[_menuClipView setFrame:CGRectMake(marginInset.left, marginInset.top, menuViewSize.width, menuViewSize.height)];
|
||||
}
|
||||
|
||||
- (void)setMinWidth:(float)aWidth
|
||||
@@ -230,28 +209,30 @@ 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);
|
||||
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect),
|
||||
marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"],
|
||||
scrollIndicatorHeight = [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"];
|
||||
|
||||
// We don't want to simply intersect the visible frame and the unconstrained frame.
|
||||
// We should be allowing as much of the width to fit as possible (pushing back and forward).
|
||||
@@ -270,41 +251,41 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
|
||||
|
||||
// This needs to happen before changing the frame.
|
||||
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
|
||||
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
|
||||
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
|
||||
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + marginInset.left, CGRectGetMinY(aFrame) + marginInset.top),
|
||||
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + marginInset.top,
|
||||
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - marginInset.bottom,
|
||||
|
||||
topMargin = TOP_MARGIN,
|
||||
bottomMargin = BOTTOM_MARGIN,
|
||||
topMargin = marginInset.top,
|
||||
bottomMargin = marginInset.bottom,
|
||||
|
||||
contentView = [self contentView],
|
||||
bounds = [contentView bounds];
|
||||
|
||||
if (moreAbove)
|
||||
{
|
||||
topMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
topMargin += scrollIndicatorHeight;
|
||||
|
||||
var frame = [_moreAboveView frame];
|
||||
|
||||
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
|
||||
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (marginInset.top + scrollIndicatorHeight - CGRectGetHeight(frame)) / 2.0)];
|
||||
}
|
||||
|
||||
[_moreAboveView setHidden:!moreAbove];
|
||||
|
||||
if (moreBelow)
|
||||
{
|
||||
bottomMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
bottomMargin += scrollIndicatorHeight;
|
||||
|
||||
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
|
||||
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - scrollIndicatorHeight - marginInset.bottom)];
|
||||
}
|
||||
|
||||
[_moreBelowView setHidden:!moreBelow];
|
||||
|
||||
var clipFrame = CGRectMakeZero();
|
||||
|
||||
clipFrame.origin.x = LEFT_MARGIN;
|
||||
clipFrame.origin.x = marginInset.left;
|
||||
clipFrame.origin.y = topMargin;
|
||||
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN;
|
||||
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - marginInset.left - marginInset.right;
|
||||
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
|
||||
|
||||
[_menuClipView setFrame:clipFrame];
|
||||
@@ -400,15 +381,15 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||
{
|
||||
var frame = [self frame];
|
||||
if (!CPRectContainsPoint(frame,aGlobalLocation) || ![self canScroll])
|
||||
if (!CGRectContainsPoint(frame,aGlobalLocation) || ![self canScroll])
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
|
||||
// If we're at or above of the top scroll indicator...
|
||||
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT && ![_moreAboveView isHidden])
|
||||
if (aGlobalLocation.y < CGRectGetMinY(frame) + [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top + [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"] && ![_moreAboveView isHidden])
|
||||
return _CPMenuManagerScrollingStateUp;
|
||||
|
||||
// If we're at or below the bottom scroll indicator...
|
||||
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT && ![_moreBelowView isHidden])
|
||||
if (aGlobalLocation.y > CGRectGetMaxY(frame) - [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].bottom - [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"] && ![_moreBelowView isHidden])
|
||||
return _CPMenuManagerScrollingStateDown;
|
||||
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
@@ -416,7 +397,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
- (float)deltaYForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
||||
return [_menuView valueForThemeAttribute:@"menu-window-margin-inset"].top + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
||||
}
|
||||
|
||||
- (CGPoint)rectForItemAtIndex:(int)anIndex
|
||||
@@ -447,6 +428,44 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
CPFont _font @accessors(property=font);
|
||||
}
|
||||
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "menu-view";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"menu-window-more-above-image": [CPNull null],
|
||||
@"menu-window-more-below-image": [CPNull null],
|
||||
@"menu-window-pop-up-background-style-color": [CPNull null],
|
||||
@"menu-window-menu-bar-background-style-color": [CPNull null],
|
||||
@"menu-window-margin-inset": CGInsetMake(5.0, 1.0, 1.0, 5.0),
|
||||
@"menu-window-scroll-indicator-height": 16.0,
|
||||
@"menu-bar-window-background-color": [CPNull null],
|
||||
@"menu-bar-window-background-selected-color": [CPNull null],
|
||||
@"menu-bar-window-font": [CPNull null],
|
||||
@"menu-bar-window-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
|
||||
{
|
||||
return _visibleMenuItemInfos.length;
|
||||
|
||||
@@ -25,29 +25,33 @@
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPImage.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPText.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPMenuItemView.j"
|
||||
|
||||
@class CPMenu
|
||||
|
||||
var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u238B" forKey:CPEscapeFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21E5" forKey:CPTabCharacter];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21E4" forKey:CPBackTabCharacter];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2423" forKey:CPSpaceFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u23CE" forKey:CPCarriageReturnCharacter];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPBackspaceCharacter];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPDeleteFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2326" forKey:CPDeleteCharacter];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21F1" forKey:CPHomeFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21F2" forKey:CPEndFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21DE" forKey:CPPageUpFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u21DF" forKey:CPPageDownFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2191" forKey:CPUpArrowFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2193" forKey:CPDownArrowFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2190" forKey:CPLeftArrowFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2192" forKey:CPRightArrowFunctionKey];
|
||||
[CPMenuItemStringRepresentationDictionary setObject:"\u2327" forKey:CPClearDisplayFunctionKey];
|
||||
@global CPApp
|
||||
|
||||
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
|
||||
@@ -101,6 +105,16 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
_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];
|
||||
@@ -148,14 +162,6 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
@param isEnabled \c YES enables the item. \c NO disables it.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
[self _setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
@@ -289,7 +295,7 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
*/
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
if (_font == aFont)
|
||||
if ([_font isEqual:aFont])
|
||||
return;
|
||||
|
||||
_font = aFont;
|
||||
@@ -496,6 +502,7 @@ CPOffState
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
[_submenu setTitle:[self title]]
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
@@ -939,34 +946,33 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
|
||||
|
||||
_isEnabled = DEFAULT_VALUE(CPMenuItemIsEnabledKey, YES);
|
||||
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
||||
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
||||
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
||||
_isHidden = [aCoder decodeBoolForKey:CPMenuItemIsHiddenKey];
|
||||
_tag = [aCoder decodeIntForKey:CPMenuItemTagKey];
|
||||
_state = [aCoder decodeIntForKey:CPMenuItemStateKey];
|
||||
|
||||
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
||||
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
||||
_image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
|
||||
_alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
|
||||
// CPImage _onStateImage;
|
||||
// CPImage _offStateImage;
|
||||
// CPImage _mixedStateImage;
|
||||
|
||||
// This order matters because setSubmenu: needs _menu to be around.
|
||||
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
|
||||
[self setSubmenu:DEFAULT_VALUE(CPMenuItemSubmenuKey, nil)];
|
||||
_menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
|
||||
[self setSubmenu:[aCoder decodeObjectForKey:CPMenuItemSubmenuKey]];
|
||||
|
||||
_keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] || @"";
|
||||
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentModifierMaskKey] || 0;
|
||||
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPMenuItemKeyEquivalentModifierMaskKey];
|
||||
|
||||
// int _mnemonicLocation;
|
||||
|
||||
// BOOL _isAlternate;
|
||||
|
||||
// Default is 0.
|
||||
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
|
||||
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey]];
|
||||
|
||||
// CPString _toolTip;
|
||||
|
||||
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
|
||||
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
|
||||
_representedObject = [aCoder decodeObjectForKey:CPMenuItemRepresentedObjectKey];
|
||||
_view = [aCoder decodeObjectForKey:CPMenuItemViewKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -1,54 +1,61 @@
|
||||
@import "CPView.j"
|
||||
/*
|
||||
* _CPMenuItemMenuBarView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
var HORIZONTAL_MARGIN = 8.0,
|
||||
SUBMENU_INDICATOR_MARGIN = 3.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var SelectionColor = nil,
|
||||
SUBMENU_INDICATOR_COLOR = nil,
|
||||
_CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
@class _CPMenuBarWindow
|
||||
@class _CPMenuView
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self !== [_CPMenuItemMenuBarView class])
|
||||
return;
|
||||
return "menu-item-bar-view";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"horizontal-margin": 9.0,
|
||||
@"submenu-indicator-margin": 3.0,
|
||||
@"vertical-margin": 4.0,
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
@@ -62,7 +69,7 @@ var SelectionColor = nil,
|
||||
|
||||
if (self)
|
||||
{
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake([self valueForThemeAttribute:@"horizontal-margin"], 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setImageOffset:3.0];
|
||||
@@ -71,88 +78,98 @@ var SelectionColor = nil,
|
||||
|
||||
[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
|
||||
{
|
||||
var x = HORIZONTAL_MARGIN,
|
||||
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 + SUBMENU_INDICATOR_MARGIN;
|
||||
|
||||
x = CGRectGetMaxX(submenuViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||
}
|
||||
else
|
||||
[_submenuIndicatorView setHidden:YES];
|
||||
|
||||
height += 2.0 * 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];
|
||||
}
|
||||
|
||||
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setFrameSize:CGSizeMake(x + [self valueForThemeAttribute:@"horizontal-margin"], height)];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
@@ -161,17 +178,20 @@ var SelectionColor = nil,
|
||||
if (![_menuItem isEnabled])
|
||||
shouldHighlight = NO;
|
||||
|
||||
if (shouldHighlight)
|
||||
_shouldHighlight = shouldHighlight;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (_shouldHighlight)
|
||||
{
|
||||
if (![_menuItem _isMenuBarButton])
|
||||
[self setBackgroundColor:SelectionColor];
|
||||
[self setBackgroundColor:[self highlightColor]];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
|
||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
|
||||
[_imageAndTextView setTextColor:[self highlightTextColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self highlightTextShadowColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,60 +200,7 @@ var SelectionColor = nil,
|
||||
[_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
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
/*
|
||||
* _CPMenuItemSeparatorView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class _CPMenuItemStandardView
|
||||
|
||||
|
||||
@implementation _CPMenuItemSeparatorView : CPView
|
||||
{
|
||||
@@ -31,8 +54,8 @@
|
||||
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);
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
/*
|
||||
* _CPMenuItemStandardView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 14.0 + 3.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0,
|
||||
|
||||
RIGHT_COLUMNS_MARGIN = 30.0,
|
||||
KEY_EQUIVALENT_MARGIN = 10.0;
|
||||
|
||||
var SUBMENU_INDICATOR_COLOR = nil,
|
||||
_CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
@import "CPImageView.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
@implementation _CPMenuItemStandardView : CPView
|
||||
{
|
||||
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;
|
||||
@@ -34,26 +40,32 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
CPView _submenuIndicatorView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self !== [_CPMenuItemStandardView class])
|
||||
return;
|
||||
return "menu-item-standard-view";
|
||||
}
|
||||
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
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
|
||||
@@ -63,7 +75,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
|
||||
+ (float)_standardLeftMargin
|
||||
{
|
||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
return [[CPTheme defaultTheme] valueForAttributeWithName:@"left-margin" forClass:[self class]] + [[CPTheme defaultTheme] valueForAttributeWithName:@"state-column-width" forClass:[self class]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -74,7 +86,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
{
|
||||
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_stateView setImageScaling:CPScaleNone];
|
||||
[_stateView setImageScaling:CPImageScaleNone];
|
||||
|
||||
[self addSubview:_stateView];
|
||||
|
||||
@@ -95,7 +107,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
|
||||
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
|
||||
|
||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
[self addSubview:_submenuIndicatorView];
|
||||
@@ -111,7 +123,10 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
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
|
||||
@@ -119,7 +134,10 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
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
|
||||
@@ -129,16 +147,34 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
|
||||
- (void)update
|
||||
{
|
||||
var x = LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH,
|
||||
var x = [self valueForThemeAttribute:@"left-margin"] + [_menuItem indentationLevel] * [self valueForThemeAttribute:@"indentation-width"],
|
||||
height = 0.0,
|
||||
hasStateColumn = [[_menuItem menu] showsStateColumn];
|
||||
|
||||
if (hasStateColumn)
|
||||
{
|
||||
[_stateView setHidden:NO];
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
//[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
|
||||
x += STATE_COLUMN_WIDTH;
|
||||
switch ([_menuItem state])
|
||||
{
|
||||
case CPOnState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-image"]];
|
||||
break;
|
||||
|
||||
case CPOffState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-image"]];
|
||||
break;
|
||||
|
||||
case CPMixedState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-image"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
x += [self valueForThemeAttribute:@"state-column-width"];
|
||||
}
|
||||
else
|
||||
[_stateView setHidden:YES];
|
||||
@@ -162,7 +198,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
hasSubmenu = [_menuItem hasSubmenu];
|
||||
|
||||
if (hasKeyEquivalent || hasSubmenu)
|
||||
x += RIGHT_COLUMNS_MARGIN;
|
||||
x += [self valueForThemeAttribute:@"right-columns-margin"];
|
||||
|
||||
if (hasKeyEquivalent)
|
||||
{
|
||||
@@ -173,9 +209,9 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
[_keyEquivalentView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
||||
[_keyEquivalentView setFrameOrigin:CGPointMake(x, [self valueForThemeAttribute:@"vertical-margin"])];
|
||||
[_keyEquivalentView sizeToFit];
|
||||
|
||||
|
||||
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
||||
|
||||
keyEquivalentViewFrame.origin.x = x;
|
||||
@@ -183,7 +219,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
|
||||
|
||||
if (hasSubmenu)
|
||||
x += RIGHT_COLUMNS_MARGIN;
|
||||
x += [self valueForThemeAttribute:@"right-columns-margin"];
|
||||
}
|
||||
else
|
||||
[_keyEquivalentView setHidden:YES];
|
||||
@@ -202,28 +238,28 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
else
|
||||
[_submenuIndicatorView setHidden:YES];
|
||||
|
||||
height += 2.0 * VERTICAL_MARGIN;
|
||||
height += 2.0 * [self valueForThemeAttribute:@"vertical-margin"];
|
||||
|
||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||
|
||||
if (hasStateColumn)
|
||||
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
|
||||
[_stateView setFrameSize:CGSizeMake([self valueForThemeAttribute:@"state-column-width"], height)];
|
||||
|
||||
if (hasKeyEquivalent)
|
||||
{
|
||||
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
|
||||
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
|
||||
}
|
||||
|
||||
|
||||
if (hasSubmenu)
|
||||
{
|
||||
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0);
|
||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||
}
|
||||
|
||||
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
|
||||
|
||||
_minSize = CGSizeMake(x + [self valueForThemeAttribute:@"right-margin"], height);
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
@@ -233,42 +269,78 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
{
|
||||
// FIXME: This should probably be even throw.
|
||||
if (![_menuItem isEnabled])
|
||||
return;
|
||||
return;
|
||||
|
||||
_highlighted = shouldHighlight;
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
|
||||
if (shouldHighlight)
|
||||
{
|
||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||
|
||||
[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:_CPMenuItemTextShadowColor];
|
||||
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
[_submenuIndicatorView setColor:[self textColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
[_submenuIndicatorView setColor:[self valueForThemeAttribute:@"submenu-indicator-color"]];
|
||||
}
|
||||
|
||||
|
||||
if ([[_menuItem menu] showsStateColumn])
|
||||
{
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
{
|
||||
switch ([_menuItem state])
|
||||
{
|
||||
case CPOnState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-highlighted-image"]];
|
||||
break;
|
||||
|
||||
case CPOffState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-highlighted-image"]];
|
||||
break;
|
||||
|
||||
case CPMixedState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-highlighted-image"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
{
|
||||
switch ([_menuItem state])
|
||||
{
|
||||
case CPOnState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-on-state-image"]];
|
||||
break;
|
||||
|
||||
case CPOffState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-off-state-image"]];
|
||||
break;
|
||||
|
||||
case CPMixedState:
|
||||
[_stateView setImage:[self valueForThemeAttribute:@"menu-item-default-mixed-state-image"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isHighlighted
|
||||
{
|
||||
return _highlighted;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
||||
@@ -290,15 +362,15 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds];
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMidY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
|
||||
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
|
||||
CGContextSetFillColor(context, _color);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
/*
|
||||
* _CPMenuItemView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPControl.j>
|
||||
@import "CPControl.j"
|
||||
|
||||
@import "_CPMenuItemSeparatorView.j"
|
||||
@import "_CPMenuItemStandardView.j"
|
||||
@import "_CPMenuItemMenuBarView.j"
|
||||
|
||||
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 16.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var _CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
@global CPApp
|
||||
|
||||
/*
|
||||
@ignore
|
||||
@@ -24,7 +34,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
@implementation _CPMenuItemView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem;
|
||||
CPView _view;
|
||||
CPView _view @accessors(property=view, readonly);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
@@ -38,31 +48,22 @@ var _CPMenuItemSelectionColor = nil,
|
||||
CPView _submenuView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self != [_CPMenuItemView class])
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
return "menu-item-view";
|
||||
}
|
||||
|
||||
+ (float)leftMargin
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
return @{};
|
||||
}
|
||||
|
||||
// Not used in the Appkit
|
||||
// + (float)leftMargin
|
||||
// {
|
||||
// return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
// }
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
@@ -176,7 +177,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
if (_font === aFont)
|
||||
if ([_font isEqual:aFont])
|
||||
return;
|
||||
|
||||
_font = aFont;
|
||||
@@ -219,6 +220,36 @@ var _CPMenuItemSelectionColor = nil,
|
||||
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
|
||||
@@ -245,8 +276,6 @@ var _CPMenuItemSelectionColor = nil,
|
||||
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);
|
||||
|
||||
+41
-18
@@ -22,8 +22,10 @@
|
||||
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPCountedSet.j>
|
||||
@import <Foundation/_CPCollectionKVCOperators.j>
|
||||
|
||||
@import "CPController.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
/*!
|
||||
@class
|
||||
@@ -51,6 +53,9 @@
|
||||
|
||||
+ (id)initialize
|
||||
{
|
||||
if (self !== [CPObjectController class])
|
||||
return;
|
||||
|
||||
[self exposeBinding:@"editable"];
|
||||
[self exposeBinding:@"contentObject"];
|
||||
}
|
||||
@@ -101,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;
|
||||
@@ -131,8 +138,8 @@
|
||||
|
||||
_contentObject = aContent;
|
||||
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
[self _selectionDidChange];
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -371,7 +378,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
[self setObjectClass:objectClass || [CPMutableDictionary class]];
|
||||
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
|
||||
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
|
||||
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
|
||||
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
|
||||
|
||||
_observedKeys = [[CPCountedSet alloc] init];
|
||||
@@ -513,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;
|
||||
@@ -537,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];
|
||||
|
||||
@@ -563,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];
|
||||
@@ -579,16 +594,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (void)removeObjectAtIndex:(unsigned)anIndex
|
||||
{
|
||||
var currentObject = [self objectAtIndex:anIndex];
|
||||
|
||||
for (var i = 0, count = [_observationProxies count]; i < count; i++)
|
||||
{
|
||||
var proxy = [_observationProxies objectAtIndex:i],
|
||||
keyPath = [proxy keyPath],
|
||||
operator = keyPath.indexOf(".") === 0;
|
||||
operator = keyPath.charAt(0) === ".";
|
||||
|
||||
if (operator)
|
||||
[self willChangeValueForKey:keyPath];
|
||||
|
||||
[anObject removeObserver:proxy forKeyPath:keyPath];
|
||||
[currentObject removeObserver:proxy forKeyPath:keyPath];
|
||||
|
||||
if (operator)
|
||||
[self didChangeValueForKey:keyPath];
|
||||
@@ -620,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];
|
||||
@@ -652,7 +669,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_cachedValues = [CPDictionary dictionary];
|
||||
_cachedValues = @{};
|
||||
_observationProxies = [CPArray array];
|
||||
_controller = aController;
|
||||
_observedObjectsByKeyPath = {};
|
||||
@@ -663,7 +680,8 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)_controllerMarkerForValues:(CPArray)theValues
|
||||
{
|
||||
var count = [theValues count];
|
||||
var count = [theValues count],
|
||||
value;
|
||||
|
||||
if (!count)
|
||||
value = CPNoSelectionMarker;
|
||||
@@ -677,7 +695,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
value = [theValues objectAtIndex:0];
|
||||
|
||||
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
for (var i = 0, count = [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
{
|
||||
if (![value isEqual:[theValues objectAtIndex:i]])
|
||||
value = CPMultipleValuesMarker;
|
||||
@@ -694,11 +712,17 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
|
||||
[_cachedValues setObject:value forKey:theKeyPath];
|
||||
// Simple collection operators like @count return a scalar value, not an array or set
|
||||
if ([values isKindOfClass:CPArray] || [values isKindOfClass:CPSet])
|
||||
{
|
||||
var value = [self _controllerMarkerForValues:values];
|
||||
[_cachedValues setObject:value forKey:theKeyPath];
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
else
|
||||
return values;
|
||||
}
|
||||
|
||||
- (id)valueForKey:(CPString)theKeyPath
|
||||
@@ -776,8 +800,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
[proxy setNotifyObject:YES];
|
||||
[_observationProxies addObject:proxy];
|
||||
|
||||
// We keep are reference to the observed objects
|
||||
// because the removeObserver: will be called after the selection changes
|
||||
// We keep a reference to the observed objects because removeObserver: will be called after the selection changes.
|
||||
var observedObjects = [_controller selectedObjects];
|
||||
_observedObjectsByKeyPath[aKeyPath] = observedObjects;
|
||||
[observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
|
||||
@@ -793,7 +816,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
[_observationProxies removeObjectAtIndex:index];
|
||||
|
||||
_observedObjects = nil;
|
||||
_observedObjectsByKeyPath[aKeyPath] = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
var options = { directoryURL: [self directoryURL],
|
||||
canChooseFiles: [self canChooseFiles],
|
||||
canChooseDirectories: [self canChooseDirectories],
|
||||
allowsMultipleSelection: [self allowsMultipleSelection] };
|
||||
allowsMultipleSelection: [self allowsMultipleSelection] },
|
||||
|
||||
var result = window.cpOpenPanel(options);
|
||||
result = window.cpOpenPanel(options);
|
||||
|
||||
_URLs = result.URLs;
|
||||
|
||||
|
||||
+203
-94
@@ -20,9 +20,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
|
||||
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
|
||||
@@ -33,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,
|
||||
@@ -62,7 +66,7 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
|
||||
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ = 1 << 12,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 13,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ = 1 << 14,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ = 1 << 15,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_ = 1 << 15,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ = 1 << 16,
|
||||
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ = 1 << 17,
|
||||
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 18,
|
||||
@@ -80,6 +84,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
CPOutlineViewCoalesceSelectionNotificationStateOn = 1,
|
||||
CPOutlineViewCoalesceSelectionNotificationStateDid = 2;
|
||||
|
||||
#define SELECTION_SHOULD_CHANGE(anOutlineView) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_selectionShouldChangeInOutlineView_) || [(anOutlineView)._outlineViewDelegate selectionShouldChangeInOutlineView:(anOutlineView)])
|
||||
|
||||
#define SHOULD_SELECT_ITEM(anOutlineView, anItem) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_) || [(anOutlineView)._outlineViewDelegate outlineView:(anOutlineView) shouldSelectItem:(anItem)])
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPOutlineView
|
||||
@@ -136,7 +144,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
|
||||
|
||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, shouldShowOutlineDisclosureControl:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
|
||||
_itemsForRows = [];
|
||||
_itemInfosForItems = { };
|
||||
@@ -147,7 +155,6 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
_retargedChildIndex = nil;
|
||||
_shouldRetargetChildIndex = NO;
|
||||
_startHoverTime = nil;
|
||||
|
||||
[self setIndentationPerLevel:16.0];
|
||||
[self setIndentationMarkerFollowsDataView:YES];
|
||||
@@ -225,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_;
|
||||
|
||||
@@ -294,6 +301,19 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
return itemInfo.isExpandable;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldShowOutlineDisclosureControlForItem:(id)anItem
|
||||
{
|
||||
if (!anItem)
|
||||
return YES;
|
||||
|
||||
var itemInfo = _itemInfosForItems[[anItem UID]];
|
||||
|
||||
if (!itemInfo)
|
||||
return YES;
|
||||
|
||||
return itemInfo.shouldShowOutlineDisclosureControl;
|
||||
}
|
||||
|
||||
/*!
|
||||
Used to find if an item is already expanded.
|
||||
|
||||
@@ -360,9 +380,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
var previousRowCount = [self numberOfRows];
|
||||
|
||||
itemInfo.isExpanded = YES;
|
||||
// XXX Shouldn't the items reload before the notification is sent?
|
||||
[self _noteItemDidExpand:anItem];
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
[self _noteItemDidExpand:anItem];
|
||||
|
||||
// Shift selection indexes below so that the same items remain selected.
|
||||
var rowCountDelta = [self numberOfRows] - previousRowCount;
|
||||
@@ -453,9 +472,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
}
|
||||
itemInfo.isExpanded = NO;
|
||||
|
||||
// XXX Shouldn't the items reload before the notification is sent?
|
||||
[self _noteItemDidCollapse:anItem];
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
[self _noteItemDidCollapse:anItem];
|
||||
|
||||
// Send selection notifications only after the items have loaded so that
|
||||
// the new selection is consistent with the actual rows for any observers.
|
||||
@@ -690,27 +708,38 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
*/
|
||||
- (CGRect)frameOfOutlineDisclosureControlAtRow:(CPInteger)aRow
|
||||
{
|
||||
if (![self isExpandable:[self itemAtRow:aRow]])
|
||||
return _CGRectMakeZero();
|
||||
var theItem = [self itemAtRow:aRow];
|
||||
if (![self isExpandable:theItem] || ![self _shouldShowOutlineDisclosureControlForItem:theItem])
|
||||
return CGRectMakeZero();
|
||||
|
||||
var dataViewFrame = [self _frameOfOutlineDataViewAtRow:aRow],
|
||||
frame = _CGRectMake(_CGRectGetMinX(dataViewFrame) - 10, _CGRectGetMinY(dataViewFrame), 10, _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];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -822,29 +851,24 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemWillExpandNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemDidExpandNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemWillCollapseNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
@@ -857,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:),
|
||||
@@ -870,7 +895,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ , @selector(outlineView:shouldShowOutlineViewForItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_ , @selector(outlineView:shouldShowOutlineDisclosureControlForItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
|
||||
@@ -921,7 +946,6 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||
[defaultCenter
|
||||
addObserver:_outlineViewDelegate
|
||||
@@ -950,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
|
||||
@@ -984,7 +1012,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
_disclosureControlData = nil;
|
||||
_disclosureControlQueue = [];
|
||||
|
||||
// fIXME: really?
|
||||
// FIXME: really?
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
@@ -1042,11 +1070,12 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
@ignore
|
||||
We need to offset the dataview and add the disclosure triangle.
|
||||
*/
|
||||
- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset
|
||||
- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CGPoint)theDragViewOffset
|
||||
{
|
||||
var dragView = [[_CPColumnDragView alloc] initWithLineColor:[self gridColor]],
|
||||
tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex],
|
||||
bounds = _CGRectMake(0.0, 0.0, [tableColumn width], _CGRectGetHeight([self exposedRect]) + 23.0),
|
||||
defaultRowHeight = [self valueForThemeAttribute:@"default-row-height"],
|
||||
bounds = CGRectMake(0.0, 0.0, [tableColumn width], CGRectGetHeight([self exposedRect]) + defaultRowHeight),
|
||||
columnRect = [self rectOfColumn:theColumnIndex],
|
||||
headerView = [tableColumn headerView],
|
||||
row = [_exposedRows firstIndex];
|
||||
@@ -1060,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]) ) + 23.0;
|
||||
dataViewFrame.origin.y = (CGRectGetMinY(dataViewFrame) - CGRectGetMinY([self exposedRect])) + defaultRowHeight;
|
||||
[dataView setFrame:dataViewFrame];
|
||||
|
||||
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
|
||||
@@ -1084,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]];
|
||||
@@ -1120,13 +1149,14 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
if (_dragHoverTimer)
|
||||
[_dragHoverTimer invalidate];
|
||||
|
||||
var autoExpandCallBack = function(){
|
||||
var autoExpandCallBack = function()
|
||||
{
|
||||
if (_dropItem)
|
||||
{
|
||||
[_dropOperationFeedbackView blink];
|
||||
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO];
|
||||
}
|
||||
@@ -1173,7 +1203,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
|
||||
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CGPoint)theOffset
|
||||
{
|
||||
if (_shouldRetargetItem)
|
||||
return _retargetedItem;
|
||||
@@ -1203,7 +1233,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset
|
||||
- (CGRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CGPoint)theOffset
|
||||
{
|
||||
// Call super and the update x to reflect the current indentation level
|
||||
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
|
||||
@@ -1284,7 +1314,12 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
item = _itemsForRows[row],
|
||||
isExpandable = [self isExpandable:item];
|
||||
|
||||
if (!isExpandable)
|
||||
if (!isExpandable)
|
||||
continue;
|
||||
|
||||
var disclosureControlFrame = [self frameOfOutlineDisclosureControlAtRow:row];
|
||||
|
||||
if (CGRectIsEmpty(disclosureControlFrame))
|
||||
continue;
|
||||
|
||||
var control = [self _dequeueDisclosureControl];
|
||||
@@ -1294,7 +1329,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
|
||||
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||
[control setFrame:[self frameOfOutlineDisclosureControlAtRow:row]];
|
||||
[control setFrame:disclosureControlFrame];
|
||||
|
||||
[self addSubview:control];
|
||||
}
|
||||
@@ -1341,13 +1376,13 @@ 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];
|
||||
|
||||
else
|
||||
[self expandItem:item];
|
||||
[self expandItem:item expandChildren:([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask)];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1422,7 +1457,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1433,7 +1468,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemDidExpandNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1444,7 +1479,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemWillCollapseNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1455,7 +1490,88 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPOutlineViewItemDidCollapseNotification
|
||||
object:self
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
userInfo:@{ "CPObject": item }];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Check for the key events manually, as opposed to waiting for CPWindow to sent the actual action message
|
||||
// in _processKeyboardUIKey:, because we might not want to handle the arrow events.
|
||||
|
||||
if (character !== CPRightArrowFunctionKey && character !== CPLeftArrowFunctionKey)
|
||||
return [super keyDown:anEvent];
|
||||
|
||||
var rows = [self selectedRowIndexes],
|
||||
indexes = [],
|
||||
items = [];
|
||||
|
||||
[rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var i = 0,
|
||||
c = [indexes count];
|
||||
|
||||
for (; i < c; i++)
|
||||
items.push([self itemAtRow:indexes[i]]);
|
||||
|
||||
if (character === CPRightArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self expandItem:items[i]];
|
||||
}
|
||||
else if (character === CPLeftArrowFunctionKey)
|
||||
{
|
||||
// When a single, collapsed item is selected and the left arrow key is pressed, the parent
|
||||
// should be selected if possible.
|
||||
if (c == 1)
|
||||
{
|
||||
var theItem = items[0];
|
||||
if (![self isItemExpanded:theItem])
|
||||
{
|
||||
var parent = [self parentForItem:theItem],
|
||||
shouldSelect = parent && SELECTION_SHOULD_CHANGE(self) && SHOULD_SELECT_ITEM(self, parent);
|
||||
if (shouldSelect)
|
||||
{
|
||||
var rowIndex = [self rowForItem:parent];
|
||||
[self selectRowIndexes:[CPIndexSet indexSetWithIndex:rowIndex] byExtendingSelection:NO];
|
||||
[self scrollRowToVisible:rowIndex];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
[self collapseItem:items[i]];
|
||||
}
|
||||
|
||||
[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
|
||||
@@ -1496,8 +1612,9 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
||||
itemInfo.shouldShowOutlineDisclosureControl = !(_implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_) || [_outlineViewDelegate outlineView:self shouldShowOutlineDisclosureControlForItem:newItem];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
||||
@@ -1521,6 +1638,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [];
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
|
||||
itemInfo.shouldShowOutlineDisclosureControl = !(_implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_) || [_outlineViewDelegate outlineView:self shouldShowOutlineDisclosureControlForItem:anItem];
|
||||
|
||||
// If we were previously expanded, but now no longer expandable, "de-expand".
|
||||
// NOTE: we are *not* collapsing, thus no notification is posted.
|
||||
@@ -1551,7 +1669,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
|
||||
if (!childItemInfo)
|
||||
{
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, shouldShowOutlineDisclosureControl:YES, children:[], weight:1 };
|
||||
itemInfosForItems[[childItem UID]] = childItemInfo;
|
||||
}
|
||||
|
||||
@@ -1602,7 +1720,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
}
|
||||
}//end of with
|
||||
return descendants;
|
||||
}
|
||||
};
|
||||
|
||||
@implementation _CPOutlineViewTableViewDataSource : CPObject
|
||||
{
|
||||
@@ -1653,7 +1771,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||
}
|
||||
|
||||
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CGPoint)theOffset
|
||||
{
|
||||
if (_outlineView._shouldRetargetChildIndex)
|
||||
return _outlineView._retargedChildIndex;
|
||||
@@ -1677,7 +1795,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return childIndex;
|
||||
}
|
||||
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CGPoint)theOffset
|
||||
{
|
||||
if (theDropOperation === CPTableViewDropAbove)
|
||||
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
|
||||
@@ -1749,27 +1867,14 @@ 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
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
|
||||
return SHOULD_SELECT_ITEM(_outlineView, [_outlineView itemAtRow:theRow]);
|
||||
}
|
||||
|
||||
return YES;
|
||||
- (BOOL)selectionShouldChangeInTableView:(CPTableView)theTableView
|
||||
{
|
||||
return SELECTION_SHOULD_CHANGE(_outlineView);
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
||||
@@ -1813,7 +1918,9 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView menuForTableColumn:aTableColumn item:item]
|
||||
}
|
||||
|
||||
return nil;
|
||||
// We reimplement CPView menuForEvent: because we can't call it directly. CPTableView implements menuForEvent:
|
||||
// to call this delegate method.
|
||||
return [_outlineView menu] || [[_outlineView class] defaultMenu];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1847,42 +1954,41 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
width = CGRectGetWidth(bounds),
|
||||
height = CGRectGetHeight(bounds);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextTranslateCTM(context, _CGRectGetWidth(bounds) / 2.0, _CGRectGetHeight(bounds) / 2.0);
|
||||
CGContextRotateCTM(context, _angle);
|
||||
CGContextTranslateCTM(context, -_CGRectGetWidth(bounds) / 2.0, -_CGRectGetHeight(bounds) / 2.0);
|
||||
if (_angle)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// Center, but crisp.
|
||||
CGContextTranslateCTM(context, FLOOR((_CGRectGetWidth(bounds) - 9.0) / 2.0), FLOOR((_CGRectGetHeight(bounds) - 8.0) / 2.0));
|
||||
CGContextTranslateCTM(context, FLOOR((width - 9.0) / 2.0), FLOOR((height - 8.0) / 2.0));
|
||||
|
||||
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]));
|
||||
CGContextFillPath(context);
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
|
||||
if (_angle === 0.0)
|
||||
{
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
}
|
||||
|
||||
else
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.7]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@@ -1920,6 +2026,8 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
|
||||
|
||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||
[super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
|
||||
|
||||
[self _updateIsViewBased];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1946,7 +2054,8 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
|
||||
@end
|
||||
|
||||
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted)
|
||||
{
|
||||
return isSelected
|
||||
? (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
|
||||
@@ -1954,4 +2063,4 @@ var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
: (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,4 +114,9 @@ CPDocModalWindowMask = 1 << 6;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+10
-9
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
@import <Foundation/CPData.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPPropertyListSerialization.j>
|
||||
|
||||
@@ -73,12 +74,12 @@ var CPPasteboards = nil,
|
||||
*/
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [CPPasteboard class])
|
||||
if (self !== [CPPasteboard class])
|
||||
return;
|
||||
|
||||
[self setVersion:1.0];
|
||||
|
||||
CPPasteboards = [CPDictionary dictionary];
|
||||
CPPasteboards = @{};
|
||||
|
||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
||||
supportsNativePasteboard = YES;
|
||||
@@ -117,11 +118,11 @@ var CPPasteboards = nil,
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
// _name = aName;
|
||||
_types = [];
|
||||
|
||||
_owners = [CPDictionary dictionary];
|
||||
_provided = [CPDictionary dictionary];
|
||||
_owners = @{};
|
||||
_provided = @{};
|
||||
|
||||
_changeCount = 0;
|
||||
|
||||
@@ -187,8 +188,8 @@ var CPPasteboards = nil,
|
||||
{
|
||||
[_types setArray:types];
|
||||
|
||||
_owners = [CPDictionary dictionary];
|
||||
_provided = [CPDictionary dictionary];
|
||||
_owners = @{};
|
||||
_provided = @{};
|
||||
|
||||
var count = _types.length;
|
||||
|
||||
@@ -247,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]];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+304
-26
@@ -20,12 +20,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
|
||||
|
||||
var VISIBLE_MARGIN = 7.0;
|
||||
|
||||
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
@@ -86,7 +86,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
[self setPullsDown:shouldPullDown];
|
||||
|
||||
var options = CPKeyValueObservingOptionNew |CPKeyValueObservingOptionOld;/* |CPKeyValueObservingOptionInitial;*/
|
||||
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld; // | CPKeyValueObservingOptionInitial;
|
||||
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
|
||||
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
|
||||
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
|
||||
@@ -193,6 +193,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (void)removeAllItems
|
||||
{
|
||||
[[self menu] removeAllItems];
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -245,22 +246,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
return _selectedIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (int)selectedTag
|
||||
{
|
||||
return [[self selectedItem] tag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_setSelectedTag:(int)aTag
|
||||
{
|
||||
[self selectItemWithTag:aTag];
|
||||
}
|
||||
|
||||
// Setting the Current Selection
|
||||
/*!
|
||||
Selects the specified menu item.
|
||||
@@ -586,10 +571,18 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
if ([indexes containsIndex:0] && [self pullsDown])
|
||||
[self _firstItemDidChange];
|
||||
|
||||
// See whether the index has changed, despite the actual item not changing.
|
||||
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
|
||||
index <= indexOfSelectedItem)
|
||||
--indexOfSelectedItem;
|
||||
if (![self pullsDown] && [indexes containsIndex:indexOfSelectedItem])
|
||||
{
|
||||
// If the selected item is removed the first item becomes selected.
|
||||
indexOfSelectedItem = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// See whether the index has changed, despite the actual item not changing.
|
||||
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
|
||||
index <= indexOfSelectedItem)
|
||||
--indexOfSelectedItem;
|
||||
}
|
||||
|
||||
[self selectItemAtIndex:indexOfSelectedItem];
|
||||
}
|
||||
@@ -674,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.
|
||||
@@ -686,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
|
||||
{
|
||||
@@ -775,6 +773,286 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
[[self selectedItem] setState:CPOffState];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPPopUpButtonSelectionBinder reverseSetValueForObject:self];
|
||||
|
||||
[super _reverseSetBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPPopUpButton (BindingSupport)
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectedIndexBinding ||
|
||||
aBinding == CPSelectedObjectBinding ||
|
||||
aBinding == CPSelectedTagBinding ||
|
||||
aBinding == CPSelectedValueBinding ||
|
||||
aBinding == CPContentBinding ||
|
||||
aBinding == CPContentObjectsBinding ||
|
||||
aBinding == CPContentValuesBinding)
|
||||
{
|
||||
var capitalizedBinding = aBinding.charAt(0).toUpperCase() + aBinding.substr(1);
|
||||
|
||||
return [CPClassFromString(@"_CPPopUpButton" + capitalizedBinding + "Binder") class];
|
||||
}
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonContentBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (CPInteger)_getInsertNullOffset
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey];
|
||||
|
||||
return [options objectForKey:CPInsertsNullPlaceholderBindingOption] ? 1 : 0;
|
||||
}
|
||||
|
||||
- (CPString)_getNullPlaceholder
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey],
|
||||
placeholder = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
|
||||
|
||||
if (placeholder === [CPNull null])
|
||||
placeholder = @"";
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
- (id)transformValue:(CPArray)contentArray withOptions:(CPDictionary)options
|
||||
{
|
||||
// Desactivate the full array transformation forced by super because we don't want this. We want individual transformations (see below).
|
||||
return contentArray;
|
||||
}
|
||||
|
||||
- (void)setValue:(CPArray)contentArray forBinding:(CPString)aBinding
|
||||
{
|
||||
[self _setContent:contentArray];
|
||||
[self _setContentValuesIfNeeded:contentArray];
|
||||
}
|
||||
|
||||
- (void)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [self _content];
|
||||
}
|
||||
|
||||
- (void)_setContent:(CPArray)aValue
|
||||
{
|
||||
var count = [aValue count],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
offset = [self _getInsertNullOffset];
|
||||
|
||||
if (count + offset != [_source numberOfItems])
|
||||
{
|
||||
[_source removeAllItems];
|
||||
|
||||
if (offset)
|
||||
[_source addItemWithTitle:[self _getNullPlaceholder]];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil];
|
||||
[self _setValue:[aValue objectAtIndex:i] forItem:item withOptions:options];
|
||||
[_source addItem:item];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
[self _setValue:[aValue objectAtIndex:i] forItem:[_source itemAtIndex:i + offset] withOptions:options];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_setContentValuesIfNeeded:(CPArray)values
|
||||
{
|
||||
var offset = [self _getInsertNullOffset];
|
||||
|
||||
if (![_source infoForBinding:CPContentValuesBinding])
|
||||
{
|
||||
if (offset)
|
||||
[[_source itemAtIndex:0] setTitle:[self _getNullPlaceholder]];
|
||||
|
||||
var count = [values count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
[[_source itemAtIndex:i + offset] setTitle:[[values objectAtIndex:i] description]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_setValue:(id)aValue forItem:(CPMenuItem)aMenuItem withOptions:(CPDictionary)options
|
||||
{
|
||||
var value = [self _transformValue:aValue withOptions:options];
|
||||
[aMenuItem setRepresentedObject:value];
|
||||
}
|
||||
|
||||
- (id)_transformValue:(id)aValue withOptions:(CPDictionary)options
|
||||
{
|
||||
return [super transformValue:aValue withOptions:options];
|
||||
}
|
||||
|
||||
- (CPArray)_content
|
||||
{
|
||||
return [_source valueForKeyPath:@"itemArray.representedObject"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonContentValuesBinder : _CPPopUpButtonContentBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[super _setContent:aValue];
|
||||
}
|
||||
|
||||
- (void)_setValue:(id)aValue forItem:(CPMenuItem)aMenuItem withOptions:(CPDictionary)options
|
||||
{
|
||||
if (aValue === [CPNull null])
|
||||
aValue = nil;
|
||||
|
||||
var value = [self _transformValue:aValue withOptions:options];
|
||||
[aMenuItem setTitle:value];
|
||||
}
|
||||
|
||||
- (CPArray)_content
|
||||
{
|
||||
return [_source valueForKeyPath:@"itemArray.title"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var binderForObject = {};
|
||||
|
||||
@implementation _CPPopUpButtonSelectionBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors;
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
binderForObject[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = binderForObject[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[self setValue:aValue forBinding:aBinding];
|
||||
}
|
||||
|
||||
- (CPInteger)_getInsertNullOffset
|
||||
{
|
||||
var options = [[CPBinder infoForBinding:CPContentBinding forObject:_source] objectForKey:CPOptionsKey];
|
||||
|
||||
return [options objectForKey:CPInsertsNullPlaceholderBindingOption] ? 1 : 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedIndexBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemAtIndex:aValue + [self _getInsertNullOffset]];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source indexOfSelectedItem] - [self _getInsertNullOffset];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedObjectBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
var index = [_source indexOfItemWithRepresentedObject:aValue],
|
||||
offset = [self _getInsertNullOffset];
|
||||
|
||||
// If the content binding has the option CPNullPlaceholderBindingOption and the object to select is nil, select the first item (i.e., the placeholder).
|
||||
// Other cases to consider:
|
||||
// 1. no binding:
|
||||
// 1.1 there's no item with a represented object matching the object to select.
|
||||
// 1.2 the object to select is nil/CPNull
|
||||
// 2. there's a binding:
|
||||
// 2.1 there's a CPNullPlaceholderBindingOption:
|
||||
// 2.1.1 there's no item with a represented object matching the object to select?
|
||||
// 2.1.2 the object to select is nil/CPNull
|
||||
// 2.2 there's no CPNullPlaceholderBindingOption:
|
||||
// 2.2.1 there's no item with a represented object matching the object to select?
|
||||
// 2.2.2 the object to select is nil/CPNull
|
||||
// More cases? Behaviour that depends on array controller settings?
|
||||
|
||||
if (offset === 1 && index === CPNotFound)
|
||||
index = 0;
|
||||
|
||||
[_source selectItemAtIndex:index];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [[_source selectedItem] representedObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedTagBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemWithTag:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [[_source selectedItem] tag];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedValueBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemWithTitle:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source titleOfSelectedItem];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* CPPopover.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2011 Antoine Mercadal.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
|
||||
CPPopoverBehaviorApplicationDefined = 0;
|
||||
CPPopoverBehaviorTransient = 1;
|
||||
CPPopoverBehaviorSemitransient = 2;
|
||||
|
||||
var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
CPPopoverDelegate_popover_didShow_ = 1 << 1,
|
||||
CPPopoverDelegate_popover_shouldClose_ = 1 << 2,
|
||||
CPPopoverDelegate_popover_willClose_ = 1 << 3,
|
||||
CPPopoverDelegate_popover_didClose_ = 1 << 4;
|
||||
|
||||
|
||||
/*! @ingroup appkit
|
||||
@class CPPopover
|
||||
|
||||
This class represent a widget that displays a popover
|
||||
view relative to another one.
|
||||
|
||||
Delegate can implement:
|
||||
|
||||
@code
|
||||
– popoverShouldClose:(CPPopover)aPopOver
|
||||
– popoverWillShow:(CPPopover)aPopOver
|
||||
– popoverDidShow:(CPPopover)aPopOver
|
||||
– popoverWillClose:(CPPopover)aPopOver
|
||||
– popoverDidClose:(CPPopover)aPopOver
|
||||
@endcode
|
||||
*/
|
||||
@implementation CPPopover : CPResponder
|
||||
{
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(getter=animates);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
_CPPopoverWindow _popoverWindow;
|
||||
int _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*!
|
||||
Initialize the CPPopover witn default values
|
||||
|
||||
@returns an initialized CPPopover
|
||||
*/
|
||||
- (CPPopover)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_animates = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_behavior = CPPopoverBehaviorApplicationDefined;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the current rect of the popover
|
||||
|
||||
@return CGRect representing the frame of the popover
|
||||
*/
|
||||
- (CGRect)positioningRect
|
||||
{
|
||||
if (![_popoverWindow isVisible])
|
||||
return CGRectMakeZero();
|
||||
|
||||
return [_popoverWindow frame];
|
||||
}
|
||||
|
||||
/*! Sets the frame of the popover
|
||||
@param aRect the desired frame
|
||||
*/
|
||||
- (void)setPositioningRect:(CGRect)aRect
|
||||
{
|
||||
if (![_popoverWindow isVisible])
|
||||
return;
|
||||
|
||||
[_popoverWindow setFrame:aRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the popover's view
|
||||
|
||||
@return CGSize representing the size of the popover's view
|
||||
*/
|
||||
- (CGSize)contentSize
|
||||
{
|
||||
if (![_popoverWindow isVisible])
|
||||
return CGRectMakeZero();
|
||||
|
||||
return [[_contentViewController view] frameSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the size of of the popover's view
|
||||
|
||||
@param aSize the desired size
|
||||
*/
|
||||
- (void)setContentSize:(CGSize)aSize
|
||||
{
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Indicates if CPPopover is visible
|
||||
|
||||
@returns \c YES if visible
|
||||
*/
|
||||
- (BOOL)isShown
|
||||
{
|
||||
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:
|
||||
|
||||
- \c CPPopoverBehaviorTransient: the popover will close if another control outside the popover becomes the responder
|
||||
- \c CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover
|
||||
|
||||
@param aBehavior the desired behavior
|
||||
*/
|
||||
- (void)setBehavior:(int)aBehavior
|
||||
{
|
||||
if (_behavior == aBehavior)
|
||||
return;
|
||||
|
||||
_behavior = aBehavior;
|
||||
[_popoverWindow setStyleMask:[self styleMaskForBehavior]];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverShouldClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_shouldClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didClose_;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Positioning
|
||||
|
||||
/*!
|
||||
Show the popover
|
||||
|
||||
@param positioningRect if set, the popover will be positionned to a random rect relative to the window
|
||||
@param positioningView if set, the popover will be positioned relative to this view
|
||||
@param preferredEdge: \c CPRectEdge representing the preferred positioning.
|
||||
*/
|
||||
- (void)showRelativeToRect:(CGRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge
|
||||
{
|
||||
if (!positioningView)
|
||||
[CPException raise:CPInvalidArgumentException reason:"positionView must not be nil"];
|
||||
|
||||
if (!_contentViewController)
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||
|
||||
// If the popover is currently closing, do nothing. That is what Cocoa does.
|
||||
if ([_popoverWindow isClosing])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
|
||||
if (!_popoverWindow)
|
||||
{
|
||||
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self styleMaskForBehavior]];
|
||||
}
|
||||
|
||||
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
||||
[_popoverWindow setAppearance:_appearance];
|
||||
[_popoverWindow setAnimates:_animates];
|
||||
[_popoverWindow setDelegate:self];
|
||||
[_popoverWindow setMovableByWindowBackground:NO];
|
||||
[_popoverWindow setFrame:[_popoverWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||
[_popoverWindow setContentView:[_contentViewController view]];
|
||||
[_popoverWindow positionRelativeToRect:positioningRect ofView:positioningView preferredEdge:preferredEdge];
|
||||
|
||||
if (!_animates && _implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
- (unsigned)styleMaskForBehavior
|
||||
{
|
||||
return (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the popover
|
||||
*/
|
||||
- (void)close
|
||||
{
|
||||
[self _close];
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the popover
|
||||
*/
|
||||
- (void)_close
|
||||
{
|
||||
if ([_popoverWindow isClosing] || ![self isShown])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
|
||||
[_popoverWindow close];
|
||||
|
||||
// popoverDidClose will be sent from popoverWindowDidClose, since
|
||||
// the popover window will close asynchronously when animating.
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action
|
||||
|
||||
/*!
|
||||
Close the popover
|
||||
|
||||
@param sender the sender of the action
|
||||
*/
|
||||
- (IBAction)performClose:(id)sender
|
||||
{
|
||||
if ([_popoverWindow isClosing])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
if (![_delegate popoverShouldClose:self])
|
||||
return;
|
||||
|
||||
[self _close];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegates
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)popoverWindowShouldClose:(_CPPopoverWindow)aPopoverWindow
|
||||
{
|
||||
[self performClose:self];
|
||||
|
||||
// We return NO, because we want the CPPopover to determine
|
||||
// if the popover window can be closed and to give us a chance
|
||||
// to send delegate messages.
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)popoverWindowDidClose:(_CPPopoverWindow)aPopoverWindow
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||
[_delegate popoverDidClose:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)popoverWindowDidShow:(_CPPopoverWindow)aPopoverWindow
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPPopover (Deprecated)
|
||||
|
||||
- (void)setBehaviour:(int)aBehavior
|
||||
{
|
||||
_CPReportLenientDeprecation(self, _cmd, @selector(setBehavior:));
|
||||
|
||||
[self setBehavior:aBehavior];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPPopoverNeedsNewPopoverWindowKey = @"CPPopoverNeedsNewPopoverWindowKey",
|
||||
CPPopoverAppearanceKey = @"CPPopoverAppearanceKey",
|
||||
CPPopoverAnimatesKey = @"CPPopoverAnimatesKey",
|
||||
CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey",
|
||||
CPPopoverDelegateKey = @"CPPopoverDelegateKey",
|
||||
CPPopoverBehaviorKey = @"CPPopoverBehaviorKey";
|
||||
|
||||
@implementation CPPopover (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_appearance = [aCoder decodeIntForKey:CPPopoverAppearanceKey];
|
||||
_animates = [aCoder decodeBoolForKey:CPPopoverAnimatesKey];
|
||||
_contentViewController = [aCoder decodeObjectForKey:CPPopoverContentViewControllerKey];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPPopoverDelegateKey]];
|
||||
[self setBehavior:[aCoder decodeIntForKey:CPPopoverBehaviorKey]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_appearance forKey:CPPopoverAppearanceKey];
|
||||
[aCoder encodeBool:_animates forKey:CPPopoverAnimatesKey];
|
||||
[aCoder encodeObject:_contentViewController forKey:CPPopoverContentViewControllerKey];
|
||||
[aCoder encodeObject:_delegate forKey:CPPopoverDelegateKey];
|
||||
[aCoder encodeInt:_behavior forKey:CPPopoverBehaviorKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+140
-110
@@ -23,29 +23,26 @@
|
||||
@import "CGGeometry.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPView.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorBarStyle = 0;
|
||||
CPProgressIndicatorBarStyle = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorSpinningStyle = 1;
|
||||
CPProgressIndicatorSpinningStyle = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
*/
|
||||
CPProgressIndicatorHUDBarStyle = 2;
|
||||
CPProgressIndicatorHUDBarStyle = 2;
|
||||
|
||||
var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
|
||||
CPProgressIndicatorClassName = nil,
|
||||
CPProgressIndicatorStyleIdentifiers = nil,
|
||||
CPProgressIndicatorStyleSizes = nil;
|
||||
var CPProgressIndicatorSpinningStyleColors = [];
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -64,77 +61,39 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
|
||||
CPControlSize _controlSize;
|
||||
|
||||
BOOL _isIndeterminate;
|
||||
BOOL _indeterminate;
|
||||
CPProgressIndicatorStyle _style;
|
||||
|
||||
BOOL _isAnimating;
|
||||
|
||||
BOOL _isDisplayedWhenStoppedSet;
|
||||
BOOL _isDisplayedWhenStopped;
|
||||
|
||||
CPView _barView;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self != [CPProgressIndicator class])
|
||||
return;
|
||||
return @"progress-indicator";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"indeterminate-bar-color": [CPNull null],
|
||||
@"bar-color": [CPNull null],
|
||||
@"default-height": 20,
|
||||
@"bezel-color": [CPNull null],
|
||||
@"spinning-mini-gif": [CPNull null],
|
||||
@"spinning-small-gif": [CPNull null],
|
||||
@"spinning-regular-gif": [CPNull null],
|
||||
};
|
||||
}
|
||||
|
||||
CPProgressIndicatorSpinningStyleColors = [];
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPValueBinding || aBinding === @"isIndeterminate")
|
||||
return [_CPProgressIndicatorBinder class];
|
||||
|
||||
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
|
||||
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
|
||||
CPProgressIndicatorSpinningStyleColors[CPRegularControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
|
||||
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
|
||||
|
||||
CPProgressIndicatorBezelBorderViewPool = [];
|
||||
|
||||
var start = CPProgressIndicatorBarStyle,
|
||||
end = CPProgressIndicatorHUDBarStyle;
|
||||
|
||||
for (; start <= end; ++start)
|
||||
{
|
||||
CPProgressIndicatorBezelBorderViewPool[start] = [];
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
|
||||
}
|
||||
|
||||
CPProgressIndicatorClassName = [self className];
|
||||
CPProgressIndicatorStyleIdentifiers = [];
|
||||
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
|
||||
|
||||
var regularIdentifier = _CPControlIdentifierForControlSize(CPRegularControlSize),
|
||||
smallIdentifier = _CPControlIdentifierForControlSize(CPSmallControlSize),
|
||||
miniIdentifier = _CPControlIdentifierForControlSize(CPMiniControlSize);
|
||||
|
||||
CPProgressIndicatorStyleSizes = [];
|
||||
|
||||
// Bar Style
|
||||
var prefixes = [
|
||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
|
||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
|
||||
];
|
||||
|
||||
for (var i = 0, count = prefixes.length; i < count; i++)
|
||||
{
|
||||
var prefix = prefixes[i];
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
}
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -153,8 +112,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
[self updateBackgroundColor];
|
||||
[self drawBar];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -316,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];
|
||||
}
|
||||
@@ -331,7 +289,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
*/
|
||||
- (BOOL)isIndeterminate
|
||||
{
|
||||
return _isIndeterminate;
|
||||
return _indeterminate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -345,6 +303,8 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
|
||||
_style = aStyle;
|
||||
|
||||
[self setTheme:(_style === CPProgressIndicatorHUDBarStyle) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
|
||||
@@ -356,8 +316,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
if (_style == CPProgressIndicatorSpinningStyle)
|
||||
[self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
|
||||
else
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), CPProgressIndicatorStyleSizes[
|
||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] + _CPControlIdentifierForControlSize(_controlSize)][0].height)];
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), [self valueForThemeAttribute:@"default-height"])];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -407,56 +366,71 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
/* @ignore */
|
||||
- (void)drawBar
|
||||
{
|
||||
if (_style == CPProgressIndicatorSpinningStyle)
|
||||
return;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
if (!_barView)
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
if (aViewName === @"bar-view" && _style !== CPProgressIndicatorSpinningStyle)
|
||||
{
|
||||
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
|
||||
[self addSubview:_barView];
|
||||
var width = CGRectGetWidth([self bounds]),
|
||||
barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
|
||||
|
||||
if (barWidth > 0.0 && barWidth < 4.0)
|
||||
barWidth = 4.0;
|
||||
|
||||
if (_indeterminate)
|
||||
barWidth = width;
|
||||
|
||||
return CGRectMake(0, 0, barWidth, [self valueForThemeAttribute:@"default-height"]);
|
||||
}
|
||||
|
||||
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
|
||||
NO,
|
||||
CPProgressIndicatorStyleSizes,
|
||||
CPProgressIndicatorClassName,
|
||||
@"Bar",
|
||||
CPProgressIndicatorStyleIdentifiers[_style],
|
||||
_CPControlIdentifierForControlSize(_controlSize))];
|
||||
|
||||
var width = CGRectGetWidth([self bounds]),
|
||||
barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
|
||||
|
||||
if (barWidth > 0.0 && barWidth < 4.0)
|
||||
barWidth = 4.0;
|
||||
|
||||
[_barView setFrameSize:CGSizeMake(barWidth, 16.0)];
|
||||
return 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
|
||||
{
|
||||
if (YES)//_isBezeled)
|
||||
{
|
||||
if (_style == CPProgressIndicatorSpinningStyle)
|
||||
{
|
||||
[_barView removeFromSuperview];
|
||||
|
||||
_barView = nil;
|
||||
// This will cause the bar view to go away due to having a nil rect when _style == CPProgressIndicatorSpinningStyle.
|
||||
[self layoutEphemeralSubviewNamed:"bar-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[self setBackgroundColor:CPProgressIndicatorSpinningStyleColors[_controlSize]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:_CPControlThreePartImagePattern(
|
||||
NO,
|
||||
CPProgressIndicatorStyleSizes,
|
||||
CPProgressIndicatorClassName,
|
||||
@"BezelBorder",
|
||||
CPProgressIndicatorStyleIdentifiers[_style],
|
||||
_CPControlIdentifierForControlSize(_controlSize))];
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
[self drawBar];
|
||||
var barView = [self layoutEphemeralSubviewNamed:"bar-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
if (_indeterminate)
|
||||
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"indeterminate-bar-color"]];
|
||||
else
|
||||
[barView setBackgroundColor:[self currentValueForThemeAttribute:@"bar-color"]];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -476,11 +450,13 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
||||
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
||||
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
|
||||
_style = [aCoder decodeObjectForKey:@"_style"];
|
||||
_indeterminate = [aCoder decodeObjectForKey:@"_indeterminate"];
|
||||
_style = [aCoder decodeIntForKey:@"_style"];
|
||||
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
||||
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
||||
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
|
||||
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -488,17 +464,71 @@ 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.
|
||||
var backgroundColor = [self backgroundColor];
|
||||
[self setBackgroundColor:nil];
|
||||
[super encodeWithCoder:aCoder];
|
||||
[self setBackgroundColor:backgroundColor];
|
||||
|
||||
[aCoder encodeObject:_minValue forKey:@"_minValue"];
|
||||
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
||||
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
|
||||
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
|
||||
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
|
||||
[aCoder encodeObject:_style forKey:@"_style"];
|
||||
[aCoder encodeObject:_indeterminate forKey:@"_indeterminate"];
|
||||
[aCoder encodeInt:_style forKey:@"_style"];
|
||||
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+237
-15
@@ -25,6 +25,8 @@
|
||||
|
||||
@import "CPButton.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -150,6 +152,14 @@ CPRadioImageOffset = 4.0;
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[super sendAction:anAction to:anObject];
|
||||
|
||||
if (_radioGroup)
|
||||
[CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
@@ -173,33 +183,143 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
[aCoder encodeObject:_radioGroup forKey:CPRadioRadioGroupKey];
|
||||
}
|
||||
|
||||
- (CPImage)image
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (CPImage)alternateImage
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
var startedTracking = [super startTrackingAt:aPoint];
|
||||
[self highlight:YES];
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@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];
|
||||
@@ -213,25 +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;
|
||||
|
||||
[CPApp sendAction:_action to:_target from:self];
|
||||
}
|
||||
|
||||
- (CPRadio)selectedRadio
|
||||
{
|
||||
return _selectedRadio;
|
||||
}
|
||||
|
||||
- (CPArray)radios
|
||||
{
|
||||
return [_radios allObjects];
|
||||
[_CPRadioGroupSelectionBinder reverseSetValueForObject:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -261,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
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPObjJRuntime.j>
|
||||
|
||||
@import "CPEvent.j"
|
||||
|
||||
@class CPKeyBinding
|
||||
|
||||
CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
|
||||
@@ -82,6 +82,22 @@
|
||||
}
|
||||
|
||||
/*! @cond */
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return [CPPredicateEditorValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return @"predicate";
|
||||
|
||||
return [super _replacementKeyPathForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (void)_initRuleEditorShared
|
||||
{
|
||||
[super _initRuleEditorShared];
|
||||
@@ -157,28 +173,40 @@
|
||||
return trees;
|
||||
}
|
||||
|
||||
- (id)_mergeTree:(id)tree
|
||||
- (CPMutableArray)_mergeTree:(CPArray)aTree
|
||||
{
|
||||
var merged = [CPMutableArray array],
|
||||
titles = [CPMutableArray array],
|
||||
count = [tree count];
|
||||
var mergedTree = [CPMutableArray array];
|
||||
if (aTree == nil)
|
||||
return mergedTree;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
var icount = [aTree count];
|
||||
for (var i = 0; i < icount; i++)
|
||||
{
|
||||
var t = tree[i],
|
||||
title = [CPString stringWithString:[t title]];
|
||||
var anode = [aTree objectAtIndex:i],
|
||||
jcount = [mergedTree count],
|
||||
merged = NO;
|
||||
|
||||
if ([titles containsObject:title])
|
||||
for (var j = 0; j < jcount; j++)
|
||||
{
|
||||
CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
|
||||
continue;
|
||||
var mergednode = [mergedTree objectAtIndex:j];
|
||||
|
||||
if ([[mergednode title] isEqualToString:[anode title]])
|
||||
{
|
||||
var children1 = [mergednode children],
|
||||
children2 = [anode children],
|
||||
children12 = [children1 arrayByAddingObjectsFromArray:children2],
|
||||
mergedChildren = [self _mergeTree:children12];
|
||||
|
||||
[mergednode setChildren:mergedChildren];
|
||||
merged = YES;
|
||||
}
|
||||
}
|
||||
|
||||
[merged addObject:t];
|
||||
[titles addObject:title];
|
||||
if (!merged)
|
||||
[mergedTree addObject:anode];
|
||||
}
|
||||
|
||||
return merged;
|
||||
return mergedTree;
|
||||
}
|
||||
|
||||
- (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
|
||||
@@ -192,7 +220,7 @@
|
||||
var children = [CPArray array],
|
||||
itemsCount = 0,
|
||||
menuIndex = -1,
|
||||
itemsArray,
|
||||
itemArray,
|
||||
|
||||
templateView = [templateViews objectAtIndex:count],
|
||||
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
|
||||
@@ -200,7 +228,7 @@
|
||||
if (isPopup)
|
||||
{
|
||||
itemArray = [[templateView itemArray] valueForKey:@"title"];
|
||||
itemsCount = [itemArray count],
|
||||
itemsCount = [itemArray count];
|
||||
menuIndex = 0;
|
||||
}
|
||||
|
||||
@@ -227,14 +255,19 @@
|
||||
|
||||
- (void)setObjectValue:(id)objectValue
|
||||
{
|
||||
if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
|
||||
var ov = [self objectValue];
|
||||
if ((ov == nil) != (objectValue == nil) || ![ov isEqual:objectValue])
|
||||
{
|
||||
[self _setPredicate:objectValue];
|
||||
[self _reflectPredicate:objectValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_reflectPredicate:(id)predicate
|
||||
{
|
||||
var animation = _currentAnimation;
|
||||
_currentAnimation = nil;
|
||||
_sendAction = NO;
|
||||
|
||||
if (predicate != nil)
|
||||
{
|
||||
@@ -311,9 +344,9 @@
|
||||
treeChild = [rootItems objectAtIndex:i];
|
||||
|
||||
var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
|
||||
menuItemIndex = [treeChild menuItemIndex];
|
||||
title = [treeChild title];
|
||||
|
||||
if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
|
||||
if (title == nil || [title isEqual:[currentView titleOfSelectedItem]])
|
||||
{
|
||||
var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
|
||||
[node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
|
||||
@@ -327,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;
|
||||
}
|
||||
@@ -336,16 +373,15 @@
|
||||
|
||||
- (void)_updatePredicate
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[self _updatePredicateFromRows];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
- (void)_updatePredicateFromRows
|
||||
{
|
||||
var rootRowsArray = [super _rootRowsArray],
|
||||
subpredicates = [CPMutableArray array],
|
||||
count = count2 = [rootRowsArray count],
|
||||
count,
|
||||
count2 = count = [rootRowsArray count],
|
||||
predicate;
|
||||
|
||||
while (count--)
|
||||
@@ -362,7 +398,7 @@
|
||||
else
|
||||
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
|
||||
|
||||
[super _setPredicate:predicate];
|
||||
[self _setPredicate:predicate];
|
||||
}
|
||||
|
||||
- (id)_predicateFromRowItem:(id)rowItem
|
||||
@@ -373,12 +409,13 @@
|
||||
if (rowType == CPRuleEditorRowTypeCompound)
|
||||
{
|
||||
var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
|
||||
count = [subrows count];
|
||||
count = [subrows count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var subrow = [subrows objectAtIndex:i];
|
||||
var predicate = [self _predicateFromRowItem:subrow];
|
||||
var subrow = [subrows objectAtIndex:i],
|
||||
predicate = [self _predicateFromRowItem:subrow];
|
||||
|
||||
[subpredicates addObject:predicate];
|
||||
}
|
||||
}
|
||||
@@ -414,7 +451,6 @@
|
||||
|
||||
- (void)_sendRuleAction
|
||||
{
|
||||
[self _updatePredicate];
|
||||
[super _sendRuleAction];
|
||||
}
|
||||
|
||||
@@ -483,9 +519,11 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
- (id)initWithCoder:(id)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self != nil)
|
||||
{
|
||||
var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
|
||||
|
||||
if (nibTemplates != nil)
|
||||
[self setRowTemplates:nibTemplates];
|
||||
}
|
||||
@@ -501,4 +539,19 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
|
||||
@end
|
||||
|
||||
/*! @endcond */
|
||||
@implementation CPPredicateEditorValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source _reflectPredicate:nil];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source _reflectPredicate:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
/*! @endcond */
|
||||
|
||||
@@ -20,17 +20,28 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPUndefinedAttributeType = 0,
|
||||
CPInteger16AttributeType = 100,
|
||||
CPInteger32AttributeType = 200,
|
||||
CPInteger64AttributeType = 300,
|
||||
CPDecimalAttributeType = 400,
|
||||
CPDoubleAttributeType = 500,
|
||||
CPFloatAttributeType = 600,
|
||||
CPStringAttributeType = 700,
|
||||
CPBooleanAttributeType = 800,
|
||||
CPDateAttributeType = 900,
|
||||
CPBinaryDataAttributeType = 1000,
|
||||
@import <Foundation/CPPredicate.j>
|
||||
|
||||
@import "CPCheckBox.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
// NOTE: CPDatePicker is not implemented yet
|
||||
@class CPDatePicker
|
||||
|
||||
|
||||
CPUndefinedAttributeType = 0;
|
||||
CPInteger16AttributeType = 100;
|
||||
CPInteger32AttributeType = 200;
|
||||
CPInteger64AttributeType = 300;
|
||||
CPDecimalAttributeType = 400;
|
||||
CPDoubleAttributeType = 500;
|
||||
CPFloatAttributeType = 600;
|
||||
CPStringAttributeType = 700;
|
||||
CPBooleanAttributeType = 800;
|
||||
CPDateAttributeType = 900;
|
||||
CPBinaryDataAttributeType = 1000;
|
||||
CPTransformableAttributeType = 1800;
|
||||
|
||||
@implementation CPPredicateEditorRowTemplate : CPObject
|
||||
@@ -185,7 +196,8 @@ CPTransformableAttributeType = 1800;
|
||||
if (![[self operators] containsObject:[predicate predicateOperatorType]])
|
||||
return 0;
|
||||
|
||||
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]]) return 0;
|
||||
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -280,7 +292,7 @@ CPTransformableAttributeType = 1800;
|
||||
*/
|
||||
- (CPArray)leftExpressions
|
||||
{
|
||||
if (_templateType ==1 && !_leftIsWildcard)
|
||||
if (_templateType == 1 && !_leftIsWildcard)
|
||||
{
|
||||
var view = [_views objectAtIndex:0];
|
||||
return [[view itemArray] valueForKey:@"representedObject"];
|
||||
@@ -582,7 +594,7 @@ CPTransformableAttributeType = 1800;
|
||||
|
||||
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
|
||||
{
|
||||
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
|
||||
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
|
||||
count = [expressions count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
@@ -685,6 +697,7 @@ CPTransformableAttributeType = 1800;
|
||||
[textField setBordered:YES];
|
||||
[textField setEditable:YES];
|
||||
[textField setFont:[CPFont systemFontOfSize:10]];
|
||||
[textField setSendsActionOnEndEditing:YES];
|
||||
|
||||
return textField;
|
||||
}
|
||||
@@ -785,4 +798,4 @@ var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
|
||||
}
|
||||
|
||||
@end
|
||||
/*! @endcond */
|
||||
/*! @endcond */
|
||||
|
||||
+269
-257
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* CPRuleEditor_Constants.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by cacaodev.
|
||||
* Copyright 2011, cacaodev.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
||||
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
||||
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
||||
CPRuleEditorPredicateOptions = "CPRuleEditorPredicateOptions";
|
||||
CPRuleEditorPredicateOperatorType = "CPRuleEditorPredicateOperatorType";
|
||||
CPRuleEditorPredicateCustomSelector = "CPRuleEditorPredicateCustomSelector";
|
||||
CPRuleEditorPredicateCompoundType = "CPRuleEditorPredicateCompoundType";
|
||||
|
||||
CPRuleEditorRowsDidChangeNotification = "CPRuleEditorRowsDidChangeNotification";
|
||||
CPRuleEditorRulesDidChangeNotification = "CPRuleEditorRulesDidChangeNotification";
|
||||
|
||||
CPRuleEditorNestingModeSingle = 0; // Only a single row is allowed. Plus/minus buttons will not be shown
|
||||
CPRuleEditorNestingModeList = 1; // Allows a single list, with no nesting and no compound rows
|
||||
CPRuleEditorNestingModeCompound = 2; // Unlimited nesting and compound rows; this is the default
|
||||
CPRuleEditorNestingModeSimple = 3; // One compound row at the top with subrows beneath it, and no further nesting allowed
|
||||
|
||||
CPRuleEditorRowTypeSimple = 0;
|
||||
CPRuleEditorRowTypeCompound = 1;
|
||||
@@ -1,9 +1,25 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@class _CPPredicateEditorTree;
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@implementation _CPPredicateEditorRowNode : CPObject
|
||||
{
|
||||
_CPPredicateEditorTree tree @accessors;
|
||||
@@ -14,25 +30,21 @@
|
||||
|
||||
+ (id)rowNodeFromTree:(id)aTree
|
||||
{
|
||||
var mapTable = {};
|
||||
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:mapTable];
|
||||
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:{}];
|
||||
}
|
||||
|
||||
+ (id)_rowNodeFromTree:(id)aTree withTemplateTable:(id)templateTable
|
||||
{
|
||||
var node,
|
||||
views,
|
||||
var views,
|
||||
copiedContainer;
|
||||
|
||||
node = [[_CPPredicateEditorRowNode alloc] init];
|
||||
node.tree = aTree;
|
||||
var uuid = [[aTree template] UID],
|
||||
cachedNode = templateTable[uuid],
|
||||
node = [[_CPPredicateEditorRowNode alloc] init];
|
||||
|
||||
var template = [aTree template],
|
||||
uuid = [template UID];
|
||||
[node setTree:aTree];
|
||||
|
||||
var cachedNode = templateTable[uuid];
|
||||
|
||||
if (cachedNode == nil)
|
||||
if (!cachedNode)
|
||||
{
|
||||
views = [CPMutableArray array];
|
||||
copiedContainer = [CPMutableArray array];
|
||||
@@ -44,8 +56,8 @@
|
||||
copiedContainer = [cachedNode copiedTemplateContainer];
|
||||
}
|
||||
|
||||
node.templateViews = views;
|
||||
node.copiedTemplateContainer = copiedContainer;
|
||||
[node setTemplateViews:views];
|
||||
[node setCopiedTemplateContainer:copiedContainer];
|
||||
|
||||
var nodeChildren = [CPMutableArray array],
|
||||
treeChildren = [aTree children],
|
||||
@@ -66,7 +78,9 @@
|
||||
|
||||
- (BOOL)applyTemplate:(id)template withViews:(id)views forOriginalTemplate:(id)originalTemplate
|
||||
{
|
||||
var t = [tree template];
|
||||
var t = [tree template],
|
||||
count = [children count];
|
||||
|
||||
if (t !== template)
|
||||
{
|
||||
[templateViews setArray:views];
|
||||
@@ -74,8 +88,7 @@
|
||||
[copiedTemplateContainer addObject:template];
|
||||
}
|
||||
|
||||
var count = [children count];
|
||||
for (var i; i < count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
[children[i] applyTemplate:template withViews:views forOriginalTemplate:originalTemplate];
|
||||
}
|
||||
|
||||
@@ -89,9 +102,8 @@
|
||||
|
||||
- (void)copyTemplateIfNecessary
|
||||
{
|
||||
if ([copiedTemplateContainer count] == 0)
|
||||
if ([copiedTemplateContainer count] === 0)
|
||||
{
|
||||
CPLogConsole("COPYING TEMPLATE");
|
||||
var copy = [[tree template] copy];
|
||||
[copiedTemplateContainer addObject:copy];
|
||||
[templateViews addObjectsFromArray:[copy templateViews]];
|
||||
@@ -118,7 +130,8 @@
|
||||
- (id)displayValue
|
||||
{
|
||||
var title = [self title];
|
||||
if (title != nil)
|
||||
|
||||
if (title !== nil)
|
||||
return title;
|
||||
|
||||
return [self templateView];
|
||||
@@ -129,4 +142,4 @@
|
||||
return [CPString stringWithFormat:@"<%@ %@ %@ tree:%@ tviews:%@", [self className],[self UID], [self title], [tree UID], [templateViews description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@implementation _CPPredicateEditorTree : CPObject
|
||||
{
|
||||
CPPredicateEditorRowTemplate template @accessors;
|
||||
|
||||
@@ -1,19 +1,35 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPURLConnection.j>
|
||||
@import <Foundation/CPURLRequest.j>
|
||||
|
||||
var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
var LocalizerStringsRegex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
|
||||
@implementation _CPRuleEditorLocalizer : CPObject
|
||||
{
|
||||
CPDictionary _dictionary @accessors(property=dictionary);
|
||||
CPURLConnection connection;
|
||||
CPURLRequest resquest;
|
||||
CPURLRequest request;
|
||||
}
|
||||
|
||||
- (void)loadContentOfURL:(CPURL)aURL
|
||||
@@ -24,9 +40,10 @@ var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
|
||||
- (void)reloadIfNeeded
|
||||
{
|
||||
if (connection != nil) // Connection waiting
|
||||
if (connection !== nil) // Connection waiting
|
||||
{
|
||||
connection = nil;
|
||||
|
||||
var data = [CPURLConnection sendSynchronousRequest:request returningResponse:NULL];
|
||||
[self loadContent:[data rawString]];
|
||||
}
|
||||
@@ -34,7 +51,7 @@ var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
|
||||
{
|
||||
if (connection != nil && rawString != nil)
|
||||
if (connection !== nil && rawString !== nil)
|
||||
[self loadContent:rawString];
|
||||
|
||||
connection = nil;
|
||||
@@ -42,17 +59,19 @@ var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
|
||||
- (void)loadContent:(CPString)aContent
|
||||
{
|
||||
var dict = [CPDictionary dictionary],
|
||||
var dict = @{},
|
||||
lines = [aContent componentsSeparatedByString:"\n"],
|
||||
count = [lines count];
|
||||
|
||||
for (var i = 0 ; i < count ; i++)
|
||||
{
|
||||
var line = [lines objectAtIndex:i];
|
||||
|
||||
if (line.length > 1)
|
||||
{
|
||||
var match = regex.exec(line);
|
||||
if (match.length >= 3)
|
||||
var match = LocalizerStringsRegex.exec(line);
|
||||
|
||||
if (match && match.length >= 3)
|
||||
[dict setObject:match[2] forKey:match[1]];
|
||||
}
|
||||
}
|
||||
@@ -64,12 +83,15 @@ var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
{
|
||||
[self reloadIfNeeded];
|
||||
|
||||
if (_dictionary != nil && aString != nil)
|
||||
if (_dictionary !== nil && aString !== nil)
|
||||
{
|
||||
var localized = [_dictionary objectForKey:aString];
|
||||
if (localized != nil)
|
||||
return localized;
|
||||
|
||||
if (localized !== nil)
|
||||
return localized;
|
||||
}
|
||||
|
||||
return aString;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,64 +1,103 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPPopUpButton.j"
|
||||
|
||||
@class _CPRuleEditorViewSlice
|
||||
|
||||
var GRADIENT_START_COLOR = "#fcfcfc",
|
||||
GRADIENT_END_COLOR = "#dfdfdf",
|
||||
BORDER_COLOR = "#BDBDBD";
|
||||
|
||||
var GRADIENT_NORMAL,
|
||||
GRADIENT_HIGHLIGHTED,
|
||||
IE_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#dfdfdf')";
|
||||
GRADIENT_PROPERTY;
|
||||
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_START_COLOR + "), to(" + GRADIENT_END_COLOR + "))",
|
||||
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_END_COLOR + "), to(" + GRADIENT_START_COLOR + "))";
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, " + GRADIENT_START_COLOR + ", " + GRADIENT_END_COLOR + ")",
|
||||
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, " + GRADIENT_END_COLOR + ", " + GRADIENT_START_COLOR + ")";
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_START_COLOR + "', endColorstr='" + GRADIENT_END_COLOR + "')";
|
||||
GRADIENT_HIGHLIGHTED = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_END_COLOR + "', endColorstr='" + GRADIENT_START_COLOR + "')";
|
||||
GRADIENT_PROPERTY = "filter";
|
||||
}else
|
||||
{
|
||||
GRADIENT_NORMAL = GRADIENT_START_COLOR;
|
||||
GRADIENT_HIGHLIGHTED = GRADIENT_END_COLOR;
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
|
||||
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
|
||||
{
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
- (void)_sharedInit
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))",
|
||||
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(rgb(223, 223, 223)), to(rgb(252, 252, 252)))";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))",
|
||||
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, rgb(223, 223, 223), rgb(252, 252, 252))";
|
||||
}
|
||||
[self setBordered:NO];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var style = _DOMElement.style;
|
||||
style.border = "1px solid " + BORDER_COLOR;
|
||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
var style = _DOMElement.style;
|
||||
style.backgroundImage = GRADIENT_NORMAL;
|
||||
style.border = "1px solid rgb(189, 189, 189)";
|
||||
style.filter = IE_FILTER;
|
||||
|
||||
[self setTextColor:[CPColor colorWithWhite:101/255 alpha:1]];
|
||||
[self setBordered:NO];
|
||||
}
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CPPoint)point
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var slice = [self superview];
|
||||
if (!CPRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
||||
self = [super initWithCoder:aCoder];
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CGRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
||||
return nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)shouldHighlight
|
||||
{
|
||||
_DOMElement.style.backgroundImage = (shouldHighlight) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
||||
}
|
||||
|
||||
- (BOOL)sliceIsEditable
|
||||
{
|
||||
return [[self superview] isEditable];
|
||||
var superview = [self superview];
|
||||
return ![superview isKindOfClass:[_CPRuleEditorViewSlice]] || [superview isEditable];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)theEvent
|
||||
@@ -80,34 +119,32 @@ var GRADIENT_NORMAL,
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
radius = FLOOR(CGRectGetHeight([self bounds])/2);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
//style.webkitBorderRadius = radiusCSS;
|
||||
//style.mozBorderRadius = radiusCSS;
|
||||
style.borderRadius = radiusCSS;
|
||||
#endif
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
var arrow_width = FLOOR(CGRectGetHeight(bounds)/3.5);
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds],
|
||||
arrow_width = FLOOR(CGRectGetHeight(bounds) / 3.5);
|
||||
|
||||
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
|
||||
|
||||
var arrowsPath = [CPBezierPath bezierPath];
|
||||
[arrowsPath moveToPoint:CGPointMake(0, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width/2, arrow_width + 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width / 2, arrow_width + 1)];
|
||||
[arrowsPath closePath];
|
||||
|
||||
CGContextSetFillColor(context, [CPColor colorWithWhite:101/255 alpha:1]);
|
||||
CGContextSetFillColor(context, [CPColor colorWithWhite:101 / 255 alpha:1]);
|
||||
[arrowsPath fill];
|
||||
|
||||
CGContextScaleCTM(context, 1 , -1);
|
||||
@@ -121,37 +158,46 @@ var GRADIENT_NORMAL,
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
- (void)_sharedInit
|
||||
{
|
||||
[self setBordered:NO];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var style = _DOMElement.style;
|
||||
style.border = "1px solid " + BORDER_COLOR;
|
||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
if (self)
|
||||
{
|
||||
[self setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
|
||||
[self setTextColor:[CPColor colorWithWhite:150/255 alpha:1]];
|
||||
[self setAlignment:CPCenterTextAlignment];
|
||||
[self setAutoresizingMask:CPViewMinXMargin];
|
||||
[self setImagePosition:CPImageOnly];
|
||||
[self setBordered:NO];
|
||||
var style = _DOMElement.style;
|
||||
style.border = "1px solid rgb(189, 189, 189)";
|
||||
style.filter = IE_FILTER;
|
||||
}
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
radius = FLOOR(CGRectGetHeight([self bounds])/2);
|
||||
#if PLATFORM(DOM)
|
||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
||||
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
style.borderRadius = radiusCSS;
|
||||
style.backgroundImage = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
||||
style[GRADIENT_PROPERTY] = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
||||
#endif
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@implementation _CPRuleEditorViewSlice : CPView
|
||||
{
|
||||
CPRuleEditor _ruleEditor;
|
||||
int _indentation @accessors(property=indentation);
|
||||
int _rowIndex @accessors(property=rowIndex);
|
||||
CPRect _animationTargetRect @accessors(property=_animationTargetRect);
|
||||
CGRect _animationTargetRect @accessors(property=_animationTargetRect);
|
||||
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
|
||||
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
|
||||
CPColor _backgroundColor @accessors(property=backgroundColor);
|
||||
BOOL _editable @accessors(getter=isEditable, setter=setEditable:);
|
||||
}
|
||||
|
||||
- (void)removeFromSuperview
|
||||
@@ -36,19 +53,19 @@
|
||||
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;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds],
|
||||
maxX = CGRectGetWidth(bounds) - 2,
|
||||
maxX = CGRectGetWidth(bounds),
|
||||
maxY = CGRectGetHeight(bounds);
|
||||
|
||||
// Draw background
|
||||
// Draw background
|
||||
if ([self _isSelected])
|
||||
_backgroundColor = [_ruleEditor _selectedRowColor];
|
||||
else
|
||||
@@ -61,33 +78,33 @@
|
||||
CGContextSetFillColor(context, _backgroundColor);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
// Draw Top Border
|
||||
// Draw Top Border
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 1, 0);
|
||||
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, 1, maxY - 0.5);
|
||||
CGContextAddLineToPoint(context, maxX, maxY - 0.5);
|
||||
CGContextClosePath(context);
|
||||
CGContextMoveToPoint(context, 0, maxY);
|
||||
CGContextAddLineToPoint(context, maxX, maxY);
|
||||
|
||||
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
|
||||
|
||||
CGContextSetStrokeColor(context, bottomColor);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)theEvent
|
||||
{
|
||||
if (editable)
|
||||
if (_editable)
|
||||
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)theEvent
|
||||
{
|
||||
if (editable)
|
||||
if (_editable)
|
||||
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
|
||||
}
|
||||
|
||||
@@ -106,4 +123,4 @@
|
||||
return [CPString stringWithFormat:@"<%@ %p index:%d indentation:%d>",[self className],self,[self rowIndex],[self indentation]];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPRuleEditor_Constants.j"
|
||||
@import "_CPRuleEditorViewSlice.j"
|
||||
@import "_CPRuleEditorPopUpButton.j"
|
||||
@import "CPRuleEditor.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
var CONTROL_HEIGHT = 16.,
|
||||
BUTTON_HEIGHT = 16.;
|
||||
@@ -18,7 +34,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
CPMutableArray _ruleOptionInitialViewFrames;
|
||||
CPButton _addButton;
|
||||
CPButton _subtractButton;
|
||||
BOOL editable;
|
||||
|
||||
CPRuleEditorRowType _rowType @accessors;
|
||||
CPRuleEditorRowType _plusButtonRowType;
|
||||
}
|
||||
@@ -37,14 +53,14 @@ var CONTROL_HEIGHT = 16.,
|
||||
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionViews = [[CPMutableArray alloc] init];
|
||||
editable = [_ruleEditor isEditable];
|
||||
_editable = [_ruleEditor isEditable];
|
||||
|
||||
_addButton = [self _createAddRowButton];
|
||||
_subtractButton = [self _createDeleteRowButton];
|
||||
//[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||
//[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||
[_addButton setHidden:!editable];
|
||||
[_subtractButton setHidden:!editable];
|
||||
[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||
[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||
[_addButton setHidden:!_editable];
|
||||
[_subtractButton setHidden:!_editable];
|
||||
[self addSubview:_addButton];
|
||||
[self addSubview:_subtractButton];
|
||||
|
||||
@@ -54,26 +70,36 @@ var CONTROL_HEIGHT = 16.,
|
||||
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (CPButton)_createAddRowButton
|
||||
- (CPButton)_createRowButton
|
||||
{
|
||||
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[button setImage:[_ruleEditor _addImage]];
|
||||
[button setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
|
||||
[button setTextColor:[CPColor colorWithWhite:150 / 255 alpha:1]];
|
||||
[button setAlignment:CPCenterTextAlignment];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
- (CPButton)_createAddRowButton
|
||||
{
|
||||
var button = [self _createRowButton];
|
||||
|
||||
[button setImage:[_ruleEditor _addImage]];
|
||||
[button setAction:@selector(_addOption:)];
|
||||
[button setTarget:self];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
- (CPButton)_createDeleteRowButton
|
||||
{
|
||||
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[button setImage:[_ruleEditor _removeImage]];
|
||||
var button = [self _createRowButton];
|
||||
|
||||
[button setImage:[_ruleEditor _removeImage]];
|
||||
[button setAction:@selector(_deleteOption:)];
|
||||
[button setTarget:self];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
return button;
|
||||
}
|
||||
@@ -87,12 +113,14 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
|
||||
{
|
||||
var title = [[itemsArray objectAtIndex:index] title];
|
||||
var font = [_ruleEditor font],
|
||||
var title = [[itemsArray objectAtIndex:index] title],
|
||||
font = [_ruleEditor font],
|
||||
width = [title sizeWithFont:font].width + 20,
|
||||
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT);
|
||||
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT),
|
||||
|
||||
var popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
|
||||
popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
|
||||
|
||||
[popup setTextColor:[CPColor colorWithWhite:101 / 255 alpha:1]];
|
||||
[popup setValue:font forThemeAttribute:@"font"];
|
||||
|
||||
var count = [itemsArray count];
|
||||
@@ -109,16 +137,18 @@ var CONTROL_HEIGHT = 16.,
|
||||
return [CPMenuItem separatorItem];
|
||||
}
|
||||
|
||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString )text
|
||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
||||
{
|
||||
text = [[_ruleEditor standardLocalizer] localizedStringForString:text];
|
||||
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CGRectMakeZero()],
|
||||
ruleEditorFont = [_ruleEditor font],
|
||||
font = [CPFont fontWithName:[ruleEditorFont familyName] size:[ruleEditorFont size] + 2],
|
||||
localizedText = [[_ruleEditor standardLocalizer] localizedStringForString:text],
|
||||
size = [localizedText sizeWithFont:font];
|
||||
|
||||
[textField setFrameSize:CGSizeMake(size.width + 4, CONTROL_HEIGHT + 2)];
|
||||
|
||||
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CPMakeRect(0, 0, 200, CONTROL_HEIGHT)];
|
||||
var font = [_ruleEditor font];
|
||||
font = [CPFont fontWithName:font._name size:font._size + 2];
|
||||
[textField setValue:font forThemeAttribute:@"font"];
|
||||
[textField setStringValue:text];
|
||||
[textField sizeToFit];
|
||||
[textField setStringValue:localizedText];
|
||||
|
||||
return textField;
|
||||
}
|
||||
@@ -182,9 +212,10 @@ var CONTROL_HEIGHT = 16.,
|
||||
parent,
|
||||
numberOfCriteria,
|
||||
numberOfChildren,
|
||||
firstResponderIndex;
|
||||
firstResponderIndex,
|
||||
|
||||
var ruleItems = [CPMutableArray array];
|
||||
ruleItems = [CPMutableArray array],
|
||||
responder = [[self window] firstResponder];
|
||||
|
||||
[self _emptyRulePartSubviews];
|
||||
|
||||
@@ -192,7 +223,6 @@ var CONTROL_HEIGHT = 16.,
|
||||
numberOfCriteria = [criteria count];
|
||||
|
||||
firstResponderIndex = numberOfCriteria - 1;
|
||||
var responder = [[self window] firstResponder];
|
||||
if (responder)
|
||||
firstResponderIndex = [_ruleOptionViews indexOfObjectIdenticalTo:responder];
|
||||
|
||||
@@ -213,16 +243,16 @@ var CONTROL_HEIGHT = 16.,
|
||||
numberOfChildren = [childItems count];
|
||||
if (numberOfChildren > 1)
|
||||
{
|
||||
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren];
|
||||
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren],
|
||||
selectedIndex = [childItems indexOfObject:criterion];
|
||||
|
||||
var selectedIndex = [childItems indexOfObject:criterion];
|
||||
if (selectedIndex == CPNotFound)
|
||||
break;
|
||||
|
||||
for (var j = 0; j < numberOfChildren; ++j)
|
||||
{
|
||||
var childItem = [childItems objectAtIndex:j];
|
||||
var childValue = [childValues objectAtIndex:j];
|
||||
var childItem = [childItems objectAtIndex:j],
|
||||
childValue = [childValues objectAtIndex:j];
|
||||
|
||||
if ([childValue isKindOfClass:[CPMenuItem class]])
|
||||
{
|
||||
@@ -241,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];
|
||||
}
|
||||
@@ -250,8 +284,8 @@ var CONTROL_HEIGHT = 16.,
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = [childValues objectAtIndex:0];
|
||||
var type = [value valueType];
|
||||
var value = [childValues objectAtIndex:0],
|
||||
type = [value valueType];
|
||||
|
||||
if (type === 0)
|
||||
ruleView = [self _createStaticTextFieldWithStringValue:value];
|
||||
@@ -287,7 +321,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
[_correspondingRuleItems setArray:ruleItems];
|
||||
|
||||
if (!editable)
|
||||
if (!_editable)
|
||||
[self _updateEnabledStateForSubviews];
|
||||
|
||||
[self _relayoutSubviewsWidthChanged:YES];
|
||||
@@ -308,7 +342,6 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
// CPLogConsole(_cmd);
|
||||
[self _relayoutSubviewsWidthChanged:YES];
|
||||
}
|
||||
|
||||
@@ -319,11 +352,11 @@ var CONTROL_HEIGHT = 16.,
|
||||
leftButtonMinX,
|
||||
rowHeight = [_ruleEditor rowHeight],
|
||||
count = [_ruleOptionViews count],
|
||||
sliceFrame = [self frame];
|
||||
sliceFrame = [self frame],
|
||||
|
||||
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT) / 2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
|
||||
|
||||
var buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT)/2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
|
||||
[_addButton setFrame:buttonFrame];
|
||||
|
||||
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
|
||||
[_subtractButton setFrame:buttonFrame];
|
||||
|
||||
@@ -339,7 +372,8 @@ var CONTROL_HEIGHT = 16.,
|
||||
var ruleOptionView = _ruleOptionViews[i],
|
||||
optionFrame = _ruleOptionFrames[i];
|
||||
|
||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame))/2 - 2;
|
||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame)) / 2 - 2;
|
||||
|
||||
if (widthChanged)
|
||||
{
|
||||
optionFrame.origin.x = optionViewOriginX;
|
||||
@@ -369,14 +403,9 @@ var CONTROL_HEIGHT = 16.,
|
||||
[self _setRowTypeToAddFromPlusButton:type];
|
||||
}
|
||||
|
||||
- (BOOL)isEditable
|
||||
{
|
||||
return editable;
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)value
|
||||
{
|
||||
editable = value;
|
||||
[super setEditable:value]
|
||||
// [self _updateEnabledStateForSubviews];
|
||||
[self _updateButtonVisibilities];
|
||||
}
|
||||
@@ -418,7 +447,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (float)_rowButtonsRightHorizontalPadding
|
||||
{
|
||||
return 10.;
|
||||
return ([[_ruleEditor superview] isKindOfClass:[CPClipView class]]) ? 18. : 10.;
|
||||
}
|
||||
|
||||
- (void)_setRowTypeToAddFromPlusButton:(int)type
|
||||
@@ -452,7 +481,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
}
|
||||
@@ -464,22 +493,16 @@ var CONTROL_HEIGHT = 16.,
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)_isRuleStaticTextField:(CPView)view
|
||||
{
|
||||
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_sendRuleAction:(id)sender
|
||||
{
|
||||
[_ruleEditor _updatePredicate];
|
||||
[_ruleEditor _sendRuleAction];
|
||||
}
|
||||
|
||||
- (void)_textDidChange:(CPNotification)aNotif
|
||||
{
|
||||
if ([[aNotif object] superview] == self && [_ruleEditor _sendsActionOnIncompleteTextChange])
|
||||
[_ruleEditor _sendRuleAction];
|
||||
[self _sendRuleAction:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -491,19 +514,17 @@ var CONTROL_HEIGHT = 16.,
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
if (self)
|
||||
{
|
||||
[self setBordered:NO];
|
||||
[self setEditable:NO];
|
||||
[self setDrawsBackground:NO];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CPPoint)point
|
||||
- (id)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CPRectContainsPoint([self frame], point))
|
||||
if (!CGRectContainsPoint([self frame], point))
|
||||
return nil;
|
||||
|
||||
return [self superview];
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
|
||||
+912
-465
File diff suppressed because it is too large
Load Diff
+347
-123
@@ -5,6 +5,9 @@
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* Modified to match Lion style by Antoine Mercadal 2011
|
||||
* <antoine.mercadal@archipelproject.org>
|
||||
*
|
||||
* 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
|
||||
@@ -20,8 +23,14 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPAnimation.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "CPViewAnimation.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
// CPScroller Constants
|
||||
CPScrollerNoPart = 0;
|
||||
@@ -48,12 +57,25 @@ 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";
|
||||
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
|
||||
CPScrollerStyleLegacy = 0;
|
||||
CPScrollerStyleOverlay = 1;
|
||||
|
||||
CPScrollerKnobStyleDefault = 0;
|
||||
CPScrollerKnobStyleDark = 1;
|
||||
CPScrollerKnobStyleLight = 2;
|
||||
|
||||
CPThemeStateScrollViewLegacy = CPThemeState("scroller-style-legacy");
|
||||
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
|
||||
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
@implementation CPScroller : CPControl
|
||||
{
|
||||
CPControlSize _controlSize;
|
||||
@@ -68,8 +90,19 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
CPScrollerPart _trackingPart;
|
||||
float _trackingFloatValue;
|
||||
CGPoint _trackingStartPoint;
|
||||
|
||||
CPViewAnimation _animationScroller;
|
||||
|
||||
BOOL _allowFadingOut @accessors(getter=allowFadingOut);
|
||||
int _style;
|
||||
CPTimer _timerFadeOut;
|
||||
BOOL _isMouseOver;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "scroller";
|
||||
@@ -77,50 +110,49 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"scroller-width": 15.0,
|
||||
@"knob-slot-color": [CPColor lightGrayColor],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPColor grayColor],
|
||||
@"decrement-line-size":_CGSizeMakeZero(),
|
||||
@"increment-line-size":_CGSizeMakeZero(),
|
||||
@"track-inset":_CGInsetMakeZero(),
|
||||
@"knob-inset": _CGInsetMakeZero(),
|
||||
@"minimum-knob-length":21.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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
+ (float)scrollerWidth
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
_partRects = [];
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
}
|
||||
|
||||
return self;
|
||||
return [self scrollerWidthInStyle:CPScrollerStyleLegacy];
|
||||
}
|
||||
|
||||
// Determining CPScroller Size
|
||||
/*!
|
||||
Returns the CPScroller's width for a CPRegularControlSize.
|
||||
*/
|
||||
+ (float)scrollerWidth
|
||||
+ (float)scrollerWidthInStyle:(int)aStyle
|
||||
{
|
||||
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
|
||||
if (!_CACHED_THEME_SCROLLER)
|
||||
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||
|
||||
if (aStyle == CPScrollerStyleLegacy)
|
||||
return [_CACHED_THEME_SCROLLER valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||
|
||||
return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"scroller-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the CPScroller's overlay value.
|
||||
*/
|
||||
+ (float)scrollerOverlay
|
||||
{
|
||||
if (!_CACHED_THEME_SCROLLER)
|
||||
_CACHED_THEME_SCROLLER = [[self alloc] init];
|
||||
|
||||
return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"track-border-overlay"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -132,6 +164,92 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return [self scrollerWidth];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
_partRects = [];
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
_style = CPScrollerStyleOverlay;
|
||||
var paramAnimFadeOut = @{
|
||||
CPViewAnimationTargetKey: self,
|
||||
CPViewAnimationEffectKey: CPViewAnimationFadeOutEffect,
|
||||
};
|
||||
|
||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[self setAlphaValue:0.0];
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the scroller's style
|
||||
*/
|
||||
- (void)style
|
||||
{
|
||||
return _style;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the scroller's control size
|
||||
@param aStyle the scroller style: CPScrollerStyleLegacy or CPScrollerStyleOverlay
|
||||
*/
|
||||
- (void)setStyle:(id)aStyle
|
||||
{
|
||||
if (_style != nil && _style === aStyle)
|
||||
return;
|
||||
|
||||
_style = aStyle;
|
||||
|
||||
if (_style === CPScrollerStyleLegacy)
|
||||
{
|
||||
[self fadeIn];
|
||||
[self setThemeState:CPThemeStateScrollViewLegacy];
|
||||
}
|
||||
else
|
||||
{
|
||||
_allowFadingOut = YES;
|
||||
[self unsetThemeState:CPThemeStateScrollViewLegacy];
|
||||
}
|
||||
|
||||
//[self _adjustScrollerSize];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the scroller's control size
|
||||
*/
|
||||
- (CPControlSize)controlSize
|
||||
{
|
||||
return _controlSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the scroller's size.
|
||||
@param aControlSize the scroller's size
|
||||
@@ -147,27 +265,6 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the scroller's control size
|
||||
*/
|
||||
- (CPControlSize)controlSize
|
||||
{
|
||||
return _controlSize;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||
}
|
||||
|
||||
- (void)setKnobProportion:(float)aProportion
|
||||
{
|
||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return's the knob's proportion
|
||||
*/
|
||||
@@ -176,22 +273,55 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return _knobProportion;
|
||||
}
|
||||
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
/*!
|
||||
Set the knob's proportion
|
||||
@param aProportion the desired proportion
|
||||
*/
|
||||
- (void)setKnobProportion:(float)aProportion
|
||||
{
|
||||
var themeState = _themeState;
|
||||
if (!_IS_NUMERIC(aProportion))
|
||||
[CPException raise:CPInvalidArgumentException reason:"aProportion must be numeric"];
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Privates
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_adjustScrollerSize
|
||||
{
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [self currentValueForThemeAttribute:@"scroller-width"];
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
|
||||
[self setFrame:frame];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_performFadeOut:(CPTimer)aTimer
|
||||
{
|
||||
[self fadeOut];
|
||||
_timerFadeOut = nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Utilities
|
||||
|
||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
if (aPart == CPScrollerNoPart)
|
||||
return _CGRectMakeZero();
|
||||
return CGRectMakeZero();
|
||||
|
||||
return _partRects[aPart];
|
||||
}
|
||||
@@ -208,6 +338,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
// page rects first since they may overlap with the arrows.
|
||||
|
||||
if (![self hasThemeState:CPThemeStateSelected])
|
||||
return CPScrollerNoPart;
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||
return CPScrollerKnob;
|
||||
|
||||
@@ -258,8 +391,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
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])
|
||||
{
|
||||
@@ -273,21 +406,21 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
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
|
||||
@@ -302,21 +435,21 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,7 +463,35 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return _usableParts;
|
||||
}
|
||||
|
||||
// Drawing the Parts
|
||||
/*!
|
||||
Display the scroller
|
||||
*/
|
||||
- (void)fadeIn
|
||||
{
|
||||
if (_isMouseOver && _knobProportion != 1.0)
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
[self setAlphaValue:1.0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Start the fade out anination
|
||||
*/
|
||||
- (void)fadeOut
|
||||
{
|
||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||
return;
|
||||
|
||||
[_animationScroller startAnimation];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Drawing
|
||||
|
||||
/*!
|
||||
Draws the specified arrow and sets the highlight.
|
||||
@param anArrow the arrow to draw
|
||||
@@ -356,7 +517,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -370,7 +531,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
@@ -379,10 +540,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[self _adjustScrollerSize];
|
||||
[self checkSpaceForParts];
|
||||
|
||||
var index = 0,
|
||||
count = PARTS_ARRANGEMENT.length;
|
||||
count = PARTS_ARRANGEMENT.length,
|
||||
view;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
@@ -443,7 +606,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
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];
|
||||
@@ -458,7 +621,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
if (type === CPLeftMouseDragged)
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -487,20 +651,20 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
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;
|
||||
|
||||
@@ -521,11 +685,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
_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;
|
||||
@@ -541,18 +705,13 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
@@ -564,6 +723,20 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Overrides
|
||||
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
{
|
||||
var themeState = _themeState;
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
@@ -573,19 +746,65 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
[super mouseEntered:anEvent];
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
_allowFadingOut = NO;
|
||||
_isMouseOver = YES;
|
||||
|
||||
if ([self alphaValue] > 0 && _knobProportion != 1.0)
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
[super mouseExited:anEvent];
|
||||
|
||||
if ([self isHidden] || ![self isEnabled] || !_isMouseOver)
|
||||
return;
|
||||
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegates
|
||||
|
||||
- (void)animationDidEnd:(CPAnimation)animation
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
CPScrollerKnobProportionKey = "CPScrollerKnobProportion";
|
||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||
|
||||
@implementation CPScroller (CPCoding)
|
||||
|
||||
@@ -598,6 +817,7 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
||||
|
||||
_knobProportion = 1.0;
|
||||
|
||||
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
|
||||
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
|
||||
|
||||
@@ -605,20 +825,22 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
|
||||
// Adjust the size of the scroller if the size from cib
|
||||
// isn't equal to the scrollerWidth
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
var paramAnimFadeOut = @{
|
||||
CPViewAnimationTargetKey: self,
|
||||
CPViewAnimationEffectKey: CPViewAnimationFadeOutEffect,
|
||||
};
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[self setAlphaValue:0.0];
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
|
||||
|
||||
[self setFrame:frame];
|
||||
[self _setIsVertical:[aCoder decodeBoolForKey:CPScrollerIsVerticalKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -629,7 +851,9 @@ 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];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+39
-34
@@ -21,22 +21,19 @@
|
||||
*/
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
@class CPUserDefaults
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
|
||||
var CPSearchFieldSearchImage = nil,
|
||||
CPSearchFieldFindImage = nil,
|
||||
CPSearchFieldCancelImage = nil,
|
||||
CPSearchFieldCancelPressedImage = nil;
|
||||
|
||||
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
|
||||
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
|
||||
BUTTON_DEFAULT_HEIGHT = 22.0;
|
||||
|
||||
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
||||
|
||||
var RECENT_SEARCH_PREFIX = @" ";
|
||||
@@ -70,16 +67,14 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
return @"searchfield"
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
if (self != [CPSearchField class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
return @{
|
||||
@"image-search": [CPNull null],
|
||||
@"image-find": [CPNull null],
|
||||
@"image-cancel": [CPNull null],
|
||||
@"image-cancel-pressed": [CPNull null]
|
||||
};
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
@@ -170,10 +165,10 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
- (void)resetSearchButton
|
||||
{
|
||||
var button = [self searchButton],
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? [self valueForThemeAttribute:@"image-search"] : [self valueForThemeAttribute:@"image-find"];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||
[button setImage:searchButtonImage];
|
||||
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||
}
|
||||
@@ -193,6 +188,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[_cancelButton setTarget:self];
|
||||
[_cancelButton setAction:@selector(cancelOperation:)];
|
||||
[_cancelButton setButtonType:CPMomentaryChangeButton];
|
||||
[self _updateCancelButtonVisibility];
|
||||
[self addSubview:_cancelButton];
|
||||
}
|
||||
@@ -215,9 +211,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
{
|
||||
var button = [self cancelButton];
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImage:CPSearchFieldCancelImage];
|
||||
[button setAlternateImage:CPSearchFieldCancelPressedImage];
|
||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||
[button setImage:[self valueForThemeAttribute:@"image-cancel"]];
|
||||
[button setAlternateImage:[self valueForThemeAttribute:@"image-cancel-pressed"]];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(cancelOperation:)];
|
||||
@@ -233,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));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -258,7 +254,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
*/
|
||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
|
||||
var size = [[self valueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero();
|
||||
|
||||
return CGRectMake(5, (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -268,7 +266,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
*/
|
||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
|
||||
var size = [[self valueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero();
|
||||
|
||||
return CGRectMake(CGRectGetWidth(rect) - size.width - 5, (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||
}
|
||||
|
||||
// Managing Menu Templates
|
||||
@@ -482,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;
|
||||
@@ -498,14 +498,19 @@ 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)
|
||||
[self _sendAction:self];
|
||||
{
|
||||
if ([_searchButton target] && [_searchButton action])
|
||||
[_searchButton mouseDown:anEvent];
|
||||
else
|
||||
[self _sendAction:self];
|
||||
}
|
||||
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];
|
||||
@@ -674,7 +679,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
return;
|
||||
|
||||
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
||||
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
|
||||
location = CGPointMake(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
|
||||
|
||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||
|
||||
|
||||
+143
-13
@@ -23,7 +23,10 @@
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPSegmentSwitchTrackingSelectOne = 0;
|
||||
CPSegmentSwitchTrackingSelectAny = 1;
|
||||
@@ -55,8 +58,33 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _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
|
||||
@@ -76,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.
|
||||
*/
|
||||
@@ -115,13 +156,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_selectedSegment >= _segments.length)
|
||||
_selectedSegment = -1;
|
||||
|
||||
// Make space for/remove space used by dividers.
|
||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
|
||||
delta = thickness * (dividersAfter - dividersBefore),
|
||||
frame = [self frame];
|
||||
frame = [self frame],
|
||||
widthOfAllSegments = 0,
|
||||
dividerExtraSpace = ([_segments count] - 1) * thickness;
|
||||
|
||||
if (delta)
|
||||
[self setFrameSize:CGSizeMake(frame.size.width + delta, frame.size.height)];
|
||||
for (var i = 0; i < [_segments count]; i++)
|
||||
widthOfAllSegments += [_segments[i] width];
|
||||
|
||||
[self setFrameSize:CGSizeMake(widthOfAllSegments + dividerExtraSpace, frame.size.height)];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
@@ -172,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
|
||||
@@ -366,11 +424,14 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
@param aSegment the segment to enable/disable
|
||||
@throws CPRangeException if \c aSegment is out of bounds
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||
- (void)setEnabled:(BOOL)shouldBeEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setEnabled:isEnabled];
|
||||
if ([_segments[aSegment] enabled] === shouldBeEnabled)
|
||||
return;
|
||||
|
||||
if (isEnabled)
|
||||
[_segments[aSegment] setEnabled:shouldBeEnabled];
|
||||
|
||||
if (shouldBeEnabled)
|
||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||
else
|
||||
_themeStates[aSegment] |= CPThemeStateDisabled;
|
||||
@@ -460,7 +521,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
}
|
||||
else if (aName === "right-segment-bezel")
|
||||
{
|
||||
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
||||
return CGRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
||||
bezelInset.top,
|
||||
contentInset.right,
|
||||
height);
|
||||
@@ -503,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
|
||||
@@ -796,6 +857,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return;
|
||||
|
||||
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||
|
||||
if (highlighted != _trackingHighlighted)
|
||||
{
|
||||
_trackingHighlighted = highlighted;
|
||||
@@ -882,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
|
||||
{
|
||||
|
||||
+9
-30
@@ -31,11 +31,9 @@
|
||||
*/
|
||||
@implementation CPShadow : CPObject
|
||||
{
|
||||
CPSize _offset;
|
||||
float _blurRadius;
|
||||
CPColor _color;
|
||||
|
||||
CPString _cssString;
|
||||
CGSize _offset @accessors(property=shadowOffset);
|
||||
float _blurRadius @accessors(property=shadowBlurRadius);
|
||||
CPColor _color @accessors(property=shadowColor);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -51,7 +49,7 @@
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initWithOffset:(CPSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
|
||||
- (id)_initWithOffset:(CGSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@@ -60,35 +58,16 @@
|
||||
_offset = anOffset;
|
||||
_blurRadius = aBlurRadius;
|
||||
_color = aColor;
|
||||
|
||||
_cssString = [_color cssString] + " " + Math.round(anOffset.width) + @"px " + Math.round(anOffset.height) + @"px " + Math.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
|
||||
@end
|
||||
|
||||
+54
-81
@@ -24,71 +24,43 @@
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
CPLightShadow = 0;
|
||||
CPHeavyShadow = 1;
|
||||
|
||||
var CPShadowViewLightBackgroundColor = nil,
|
||||
CPShadowViewHeavyBackgroundColor = nil;
|
||||
CPThemeStateShadowViewLight = CPThemeState("shadowview-style-light");
|
||||
CPThemeStateShadowViewHeavy = CPThemeState("shadowview-style-heavy");
|
||||
|
||||
var LIGHT_LEFT_INSET = 3.0,
|
||||
LIGHT_RIGHT_INSET = 3.0,
|
||||
LIGHT_TOP_INSET = 3.0,
|
||||
LIGHT_BOTTOM_INSET = 5.0,
|
||||
|
||||
HEAVY_LEFT_INSET = 7.0,
|
||||
HEAVY_RIGHT_INSET = 7.0,
|
||||
HEAVY_TOP_INSET = 5.0,
|
||||
HEAVY_BOTTOM_INSET = 5.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPShadowView : CPView
|
||||
{
|
||||
CPShadowWeight _weight;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self != [CPShadowView class])
|
||||
return;
|
||||
return "shadow-view";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"bezel-color": [CPNull null],
|
||||
@"content-inset": CGInsetMakeZero()
|
||||
};
|
||||
}
|
||||
|
||||
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
+ (CGRect)frameForContentFrame:(CGRect)aFrame withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
var shadowView = [CPShadowView new],
|
||||
inset = [shadowView valueForThemeAttribute:@"content-inset" inState:(aWeight == CPLightShadow) ? CPThemeStateShadowViewLight : CPThemeStateShadowViewHeavy];
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
|
||||
]]];
|
||||
|
||||
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
|
||||
]]];
|
||||
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
|
||||
@@ -98,20 +70,25 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
|
||||
[shadowView setWeight:aWeight];
|
||||
var shadowView = [[self alloc] initWithFrame:[aView frame]];
|
||||
|
||||
var size = [shadowView frame].size,
|
||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||
enclosingView = [aView superview];
|
||||
if (shadowView)
|
||||
{
|
||||
[shadowView setWeight:aWeight];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||
[enclosingView addSubview:shadowView];
|
||||
var size = [shadowView frame].size,
|
||||
inset = [shadowView currentValueForThemeAttribute:@"content-inset"],
|
||||
width = size.width - inset.left - inset.right,
|
||||
height = size.height - inset.top - inset.bottom,
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake(inset.left, inset.top, width, height)];
|
||||
[enclosingView addSubview:shadowView];
|
||||
}
|
||||
|
||||
return shadowView;
|
||||
}
|
||||
@@ -122,9 +99,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
|
||||
if (self)
|
||||
{
|
||||
_weight = CPLightShadow;
|
||||
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
[self setWeight:CPLightShadow];
|
||||
|
||||
[self setHitTests:NO];
|
||||
}
|
||||
@@ -140,54 +115,45 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
_weight = aWeight;
|
||||
|
||||
if (_weight == CPLightShadow)
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
|
||||
[self setThemeState:CPThemeStateShadowViewLight];
|
||||
else
|
||||
[self setBackgroundColor:CPShadowViewHeavyBackgroundColor];
|
||||
[self setThemeState:CPThemeStateShadowViewHeavy];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (float)leftInset
|
||||
{
|
||||
return _weight == CPLightShadow ? LIGHT_LEFT_INSET : HEAVY_LEFT_INSET;
|
||||
return [self currentValueForThemeAttribute:@"content-inset"].left;
|
||||
}
|
||||
|
||||
- (float)rightInset
|
||||
{
|
||||
return _weight == CPLightShadow ? LIGHT_RIGHT_INSET : HEAVY_RIGHT_INSET;
|
||||
return [self currentValueForThemeAttribute:@"content-inset"].right;
|
||||
}
|
||||
|
||||
- (float)topInset
|
||||
{
|
||||
return _weight == CPLightShadow ? LIGHT_TOP_INSET : HEAVY_TOP_INSET;
|
||||
return [self currentValueForThemeAttribute:@"content-inset"].top;
|
||||
}
|
||||
|
||||
- (float)bottomInset
|
||||
{
|
||||
return _weight == CPLightShadow ? LIGHT_BOTTOM_INSET : HEAVY_BOTTOM_INSET;
|
||||
return [self currentValueForThemeAttribute:@"content-inset"].bottom;
|
||||
}
|
||||
|
||||
- (float)horizontalInset
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
|
||||
var currentContentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
|
||||
return currentContentInset.left + currentContentInset.right;
|
||||
}
|
||||
|
||||
- (float)verticalInset
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
|
||||
var currentContentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
|
||||
}
|
||||
|
||||
+ (CGRect)frameForContentFrame:(CGRect)aFrame withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
if (aWeight == CPLightShadow)
|
||||
return CGRectMake(_CGRectGetMinX(aFrame) - LIGHT_LEFT_INSET, _CGRectGetMinY(aFrame) - LIGHT_TOP_INSET, _CGRectGetWidth(aFrame) + LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET, _CGRectGetHeight(aFrame) + LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET);
|
||||
else
|
||||
return CGRectMake(_CGRectGetMinX(aFrame) - HEAVY_LEFT_INSET, _CGRectGetMinY(aFrame) - HEAVY_TOP_INSET, _CGRectGetWidth(aFrame) + HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET, _CGRectGetHeight(aFrame) + HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET);
|
||||
return currentContentInset.top + currentContentInset.bottom;
|
||||
}
|
||||
|
||||
- (CGRect)frameForContentFrame:(CGRect)aFrame
|
||||
@@ -200,4 +166,11 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
[self setFrame:[self frameForContentFrame:aFrame]];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+34
-27
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
|
||||
/*! SLIDER STATES */
|
||||
@@ -39,6 +40,8 @@ CPCircularSlider = 1;
|
||||
double _altIncrementValue;
|
||||
|
||||
BOOL _isVertical;
|
||||
|
||||
CGSize _dragOffset;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -48,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
|
||||
@@ -155,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;
|
||||
}
|
||||
}
|
||||
@@ -177,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])
|
||||
@@ -196,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;
|
||||
@@ -253,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);
|
||||
|
||||
@@ -299,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]];
|
||||
}
|
||||
@@ -366,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;
|
||||
}
|
||||
|
||||
+155
-146
@@ -20,8 +20,14 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPColorPicker.j"
|
||||
@import "CPSlider.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@global CPColorPickerViewWidth
|
||||
@global CPColorPickerViewHeight
|
||||
@global CPSliderColorPickerMode
|
||||
|
||||
|
||||
/*
|
||||
@@ -60,166 +66,166 @@
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
{
|
||||
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
|
||||
return [super initWithPickerMask:mask colorPanel:owningColorPanel];
|
||||
}
|
||||
|
||||
- (id)initView
|
||||
{
|
||||
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
var aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:aFrame];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
_rgbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 10, 100, 20)];
|
||||
[_rgbLabel setStringValue: "Red, Green, Blue"];
|
||||
_rgbLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 10, 100, 20)];
|
||||
[_rgbLabel setStringValue:"Red, Green, Blue"];
|
||||
[_rgbLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
|
||||
[_redLabel setStringValue: "R"];
|
||||
_redLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 37, 15, 20)];
|
||||
[_redLabel setStringValue:"R"];
|
||||
[_redLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_redSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 35, aFrame.size.width - 70, 20)];
|
||||
[_redSlider setMaxValue: 1.0];
|
||||
[_redSlider setMinValue: 0.0];
|
||||
[_redSlider setTarget: self];
|
||||
[_redSlider setAction: @selector(sliderChanged:)];
|
||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_redSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 35, aFrame.size.width - 70, 20)];
|
||||
[_redSlider setMaxValue:1.0];
|
||||
[_redSlider setMinValue:0.0];
|
||||
[_redSlider setTarget:self];
|
||||
[_redSlider setAction:@selector(sliderChanged:)];
|
||||
[_redSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// red value input box
|
||||
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
|
||||
[_redValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_redValue setEditable: YES];
|
||||
[_redValue setBezeled: YES];
|
||||
[_redValue setDelegate: self];
|
||||
[_contentView addSubview: _redValue];
|
||||
_redValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
|
||||
[_redValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_redValue setEditable:YES];
|
||||
[_redValue setBezeled:YES];
|
||||
[_redValue setDelegate:self];
|
||||
[_contentView addSubview:_redValue];
|
||||
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 63, 15, 20)];
|
||||
[_greenLabel setStringValue:"G"];
|
||||
[_greenLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
|
||||
[_greenSlider setMaxValue: 1.0];
|
||||
[_greenSlider setMinValue: 0.0];
|
||||
[_greenSlider setTarget: self];
|
||||
[_greenSlider setAction: @selector(sliderChanged:)];
|
||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_greenSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 61, aFrame.size.width - 70, 20)];
|
||||
[_greenSlider setMaxValue:1.0];
|
||||
[_greenSlider setMinValue:0.0];
|
||||
[_greenSlider setTarget:self];
|
||||
[_greenSlider setAction:@selector(sliderChanged:)];
|
||||
[_greenSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// green value input box
|
||||
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
|
||||
[_greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_greenValue setEditable: YES];
|
||||
[_greenValue setBezeled: YES];
|
||||
[_greenValue setDelegate: self];
|
||||
[_contentView addSubview: _greenValue];
|
||||
_greenValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
|
||||
[_greenValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_greenValue setEditable:YES];
|
||||
[_greenValue setBezeled:YES];
|
||||
[_greenValue setDelegate:self];
|
||||
[_contentView addSubview:_greenValue];
|
||||
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 90, 15, 20)];
|
||||
[_blueLabel setStringValue:"B"];
|
||||
[_blueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
|
||||
[_blueSlider setMaxValue: 1.0];
|
||||
[_blueSlider setMinValue: 0.0];
|
||||
[_blueSlider setTarget: self];
|
||||
[_blueSlider setAction: @selector(sliderChanged:)];
|
||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_blueSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 87, aFrame.size.width - 70, 20)];
|
||||
[_blueSlider setMaxValue:1.0];
|
||||
[_blueSlider setMinValue:0.0];
|
||||
[_blueSlider setTarget:self];
|
||||
[_blueSlider setAction:@selector(sliderChanged:)];
|
||||
[_blueSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// blue value input box
|
||||
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
|
||||
[_blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_blueValue setEditable: YES];
|
||||
[_blueValue setBezeled: YES];
|
||||
[_blueValue setDelegate: self];
|
||||
[_contentView addSubview: _blueValue];
|
||||
_blueValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
|
||||
[_blueValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_blueValue setEditable:YES];
|
||||
[_blueValue setBezeled:YES];
|
||||
[_blueValue setDelegate:self];
|
||||
[_contentView addSubview:_blueValue];
|
||||
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue:"Hue, Saturation, Brightness"];
|
||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 145, 15, 20)];
|
||||
[_hueLabel setStringValue: "H"];
|
||||
_hueLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 145, 15, 20)];
|
||||
[_hueLabel setStringValue:"H"];
|
||||
[_hueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
|
||||
[_hueSlider setMaxValue: 359.0];
|
||||
[_hueSlider setMinValue: 0.0];
|
||||
[_hueSlider setTarget: self];
|
||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 143, aFrame.size.width - 70, 20)];
|
||||
[_hueSlider setMaxValue:0.999];
|
||||
[_hueSlider setMinValue:0.0];
|
||||
[_hueSlider setTarget:self];
|
||||
[_hueSlider setAction:@selector(sliderChanged:)];
|
||||
[_hueSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// hue value input box
|
||||
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
|
||||
[_hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_hueValue setEditable: YES];
|
||||
[_hueValue setBezeled: YES];
|
||||
[_hueValue setDelegate: self];
|
||||
[_contentView addSubview: _hueValue];
|
||||
_hueValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
|
||||
[_hueValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_hueValue setEditable:YES];
|
||||
[_hueValue setBezeled:YES];
|
||||
[_hueValue setDelegate:self];
|
||||
[_contentView addSubview:_hueValue];
|
||||
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 170, 15, 20)];
|
||||
[_saturationLabel setStringValue:"S"];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_saturationSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 168, aFrame.size.width - 70, 20)];
|
||||
[_saturationSlider setMaxValue: 100.0];
|
||||
[_saturationSlider setMinValue: 0.0];
|
||||
[_saturationSlider setTarget: self];
|
||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_saturationSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 168, aFrame.size.width - 70, 20)];
|
||||
[_saturationSlider setMaxValue:1.0];
|
||||
[_saturationSlider setMinValue:0.0];
|
||||
[_saturationSlider setTarget:self];
|
||||
[_saturationSlider setAction:@selector(sliderChanged:)];
|
||||
[_saturationSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// saturation value input box
|
||||
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
|
||||
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_saturationValue setEditable: YES];
|
||||
[_saturationValue setBezeled: YES];
|
||||
[_saturationValue setDelegate: self];
|
||||
[_contentView addSubview: _saturationValue];
|
||||
_saturationValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
|
||||
[_saturationValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_saturationValue setEditable:YES];
|
||||
[_saturationValue setBezeled:YES];
|
||||
[_saturationValue setDelegate:self];
|
||||
[_contentView addSubview:_saturationValue];
|
||||
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 196, 15, 20)];
|
||||
[_brightnessLabel setStringValue:"B"];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
|
||||
[_brightnessSlider setMaxValue: 100.0];
|
||||
[_brightnessSlider setMinValue: 0.0];
|
||||
[_brightnessSlider setTarget: self];
|
||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(15, 194, aFrame.size.width - 70, 20)];
|
||||
[_brightnessSlider setMaxValue:1.0];
|
||||
[_brightnessSlider setMinValue:0.0];
|
||||
[_brightnessSlider setTarget:self];
|
||||
[_brightnessSlider setAction:@selector(sliderChanged:)];
|
||||
[_brightnessSlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// brightness value input box
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
|
||||
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_brightnessValue setEditable: YES];
|
||||
[_brightnessValue setBezeled: YES];
|
||||
[_brightnessValue setDelegate: self];
|
||||
[_contentView addSubview: _brightnessValue];
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame:CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
|
||||
[_brightnessValue setAutoresizingMask:CPViewMinXMargin];
|
||||
[_brightnessValue setEditable:YES];
|
||||
[_brightnessValue setBezeled:YES];
|
||||
[_brightnessValue setDelegate:self];
|
||||
[_contentView addSubview:_brightnessValue];
|
||||
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue: "Hex"];
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame:CGRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue:"Hex"];
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
//hex input box
|
||||
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
|
||||
[_hexValue setEditable: YES];
|
||||
[_hexValue setBezeled: YES];
|
||||
[_hexValue setDelegate: self];
|
||||
[_contentView addSubview: _hexValue];
|
||||
_hexValue = [[CPTextField alloc] initWithFrame:CGRectMake(32, 225, 80, 28)];
|
||||
[_hexValue setEditable:YES];
|
||||
[_hexValue setBezeled:YES];
|
||||
[_hexValue setDelegate:self];
|
||||
[_contentView addSubview:_hexValue];
|
||||
|
||||
[_contentView addSubview: _rgbLabel];
|
||||
[_contentView addSubview: _redLabel];
|
||||
[_contentView addSubview: _greenLabel];
|
||||
[_contentView addSubview: _blueLabel];
|
||||
[_contentView addSubview: _redSlider];
|
||||
[_contentView addSubview: _greenSlider];
|
||||
[_contentView addSubview: _blueSlider];
|
||||
[_contentView addSubview:_rgbLabel];
|
||||
[_contentView addSubview:_redLabel];
|
||||
[_contentView addSubview:_greenLabel];
|
||||
[_contentView addSubview:_blueLabel];
|
||||
[_contentView addSubview:_redSlider];
|
||||
[_contentView addSubview:_greenSlider];
|
||||
[_contentView addSubview:_blueSlider];
|
||||
|
||||
[_contentView addSubview: _hsbLabel];
|
||||
[_contentView addSubview: _hueLabel];
|
||||
[_contentView addSubview: _saturationLabel];
|
||||
[_contentView addSubview: _brightnessLabel];
|
||||
[_contentView addSubview: _hueSlider];
|
||||
[_contentView addSubview: _saturationSlider];
|
||||
[_contentView addSubview: _brightnessSlider];
|
||||
[_contentView addSubview:_hsbLabel];
|
||||
[_contentView addSubview:_hueLabel];
|
||||
[_contentView addSubview:_saturationLabel];
|
||||
[_contentView addSubview:_brightnessLabel];
|
||||
[_contentView addSubview:_hueSlider];
|
||||
[_contentView addSubview:_saturationSlider];
|
||||
[_contentView addSubview:_brightnessSlider];
|
||||
|
||||
[_contentView addSubview: _hexLabel];
|
||||
[_contentView addSubview:_hexLabel];
|
||||
}
|
||||
|
||||
- (CPView)provideNewView:(BOOL)initialRequest
|
||||
@@ -250,35 +256,38 @@
|
||||
{
|
||||
case _hueSlider:
|
||||
case _saturationSlider:
|
||||
case _brightnessSlider: newColor = [CPColor colorWithHue: [_hueSlider floatValue]
|
||||
saturation: [_saturationSlider floatValue]
|
||||
brightness: [_brightnessSlider floatValue]
|
||||
alpha: alpha];
|
||||
case _brightnessSlider: newColor = [CPColor colorWithHue:[_hueSlider floatValue]
|
||||
saturation:[_saturationSlider floatValue]
|
||||
brightness:[_brightnessSlider floatValue]
|
||||
alpha:alpha];
|
||||
|
||||
[self updateRGBSliders: newColor];
|
||||
[self updateRGBSliders:newColor];
|
||||
break;
|
||||
|
||||
case _redSlider:
|
||||
case _greenSlider:
|
||||
case _blueSlider: newColor = [CPColor colorWithCalibratedRed: [_redSlider floatValue]
|
||||
green: [_greenSlider floatValue]
|
||||
blue: [_blueSlider floatValue]
|
||||
alpha: alpha];
|
||||
case _blueSlider: newColor = [CPColor colorWithCalibratedRed:[_redSlider floatValue]
|
||||
green:[_greenSlider floatValue]
|
||||
blue:[_blueSlider floatValue]
|
||||
alpha:alpha];
|
||||
|
||||
[self updateHSBSliders: newColor];
|
||||
[self updateHSBSliders:newColor];
|
||||
break;
|
||||
}
|
||||
|
||||
[self updateLabels];
|
||||
[self updateHex: newColor];
|
||||
[colorPanel setColor: newColor];
|
||||
[self updateHex:newColor];
|
||||
[colorPanel setColor:newColor];
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
[self updateRGBSliders: aColor];
|
||||
[self updateHSBSliders: aColor];
|
||||
[self updateHex: aColor];
|
||||
if (!aColor)
|
||||
[CPException raise:CPInvalidArgumentException reason:"aColor can't be nil"];
|
||||
|
||||
[self updateRGBSliders:aColor];
|
||||
[self updateHSBSliders:aColor];
|
||||
[self updateHex:aColor];
|
||||
[self updateLabels];
|
||||
}
|
||||
|
||||
@@ -307,13 +316,13 @@
|
||||
|
||||
- (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)];
|
||||
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
|
||||
[_redValue setStringValue:ROUND([_redSlider floatValue] * 255)];
|
||||
[_greenValue setStringValue:ROUND([_greenSlider floatValue] * 255)];
|
||||
[_blueValue setStringValue:ROUND([_blueSlider floatValue] * 255)];
|
||||
}
|
||||
|
||||
- (CPImage)provideNewButtonImage
|
||||
@@ -333,12 +342,12 @@
|
||||
|
||||
if (field === _hexValue)
|
||||
{
|
||||
var newColor = [CPColor colorWithHexString: value];
|
||||
var newColor = [CPColor colorWithHexString:value];
|
||||
|
||||
if (newColor)
|
||||
{
|
||||
[self setColor: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
[self setColor:newColor];
|
||||
[[self colorPanel] setColor:newColor];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -346,27 +355,27 @@
|
||||
switch (field)
|
||||
{
|
||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _redSlider];
|
||||
[self sliderChanged:_redSlider];
|
||||
break;
|
||||
|
||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _greenSlider];
|
||||
[self sliderChanged:_greenSlider];
|
||||
break;
|
||||
|
||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _blueSlider];
|
||||
[self sliderChanged:_blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
|
||||
[self sliderChanged: _hueSlider];
|
||||
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)];
|
||||
[self sliderChanged: _saturationSlider];
|
||||
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)];
|
||||
[self sliderChanged: _brightnessSlider];
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100) / 100.0, 0)];
|
||||
[self sliderChanged:_brightnessSlider];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPRunLoop.j>
|
||||
|
||||
CPSoundLoadStateEmpty = 0;
|
||||
CPSoundLoadStateLoading = 1;
|
||||
@@ -45,6 +46,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
CPString _name @accessors(property=name);
|
||||
id _delegate @accessors(property=delegate);
|
||||
|
||||
BOOL _playRequestBeforeLoad;
|
||||
HTMLAudioElement _audioTag;
|
||||
int _loadStatus;
|
||||
int _playBackStatus;
|
||||
@@ -58,9 +60,10 @@ CPSoundPlayBackStatePause = 2;
|
||||
if (self = [super init])
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateEmpty;
|
||||
_loops = NO;
|
||||
// _loops = NO;
|
||||
_audioTag = document.createElement("audio");
|
||||
_audioTag.preload = YES;
|
||||
_playRequestBeforeLoad = NO;
|
||||
|
||||
_audioTag.addEventListener("canplay", function()
|
||||
{
|
||||
@@ -138,6 +141,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
- (void)_soundDidload
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateCanBePlayed;
|
||||
|
||||
if (_playRequestBeforeLoad)
|
||||
{
|
||||
_playRequestBeforeLoad = NO;
|
||||
[self play];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
@@ -167,6 +176,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
*/
|
||||
- (BOOL)play
|
||||
{
|
||||
if (_loadStatus === CPSoundLoadStateLoading)
|
||||
{
|
||||
_playRequestBeforeLoad = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePlay))
|
||||
return NO;
|
||||
|
||||
+467
-104
@@ -20,16 +20,44 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
@import "CPCursor.j"
|
||||
|
||||
@class CPUserDefaults
|
||||
@global CPApp
|
||||
|
||||
#define SPLIT_VIEW_MAYBE_POST_WILL_RESIZE() \
|
||||
if ((_suppressResizeNotificationsMask & DidPostWillResizeNotification) === 0) \
|
||||
{ \
|
||||
[self _postNotificationWillResize]; \
|
||||
_suppressResizeNotificationsMask |= DidPostWillResizeNotification; \
|
||||
}
|
||||
|
||||
#define SPLIT_VIEW_MAYBE_POST_DID_RESIZE() \
|
||||
if ((_suppressResizeNotificationsMask & ShouldSuppressResizeNotifications) !== 0) \
|
||||
_suppressResizeNotificationsMask |= DidSuppressResizeNotification; \
|
||||
else \
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
#define SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION() \
|
||||
((_suppressResizeNotificationsMask & DidSuppressResizeNotification) !== 0)
|
||||
|
||||
#define SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(shouldSuppress) \
|
||||
if (shouldSuppress) \
|
||||
_suppressResizeNotificationsMask |= ShouldSuppressResizeNotifications; \
|
||||
else \
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
|
||||
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
|
||||
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
|
||||
|
||||
var CPSplitViewHorizontalImage = nil,
|
||||
CPSplitViewVerticalImage = nil;
|
||||
var ShouldSuppressResizeNotifications = 1,
|
||||
DidPostWillResizeNotification = 1 << 1,
|
||||
DidSuppressResizeNotification = 1 << 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -45,24 +73,29 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
@implementation CPSplitView : CPView
|
||||
{
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
float _preCollapsePosition;
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
CPDictionary _preCollapsePositions;
|
||||
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
|
||||
CPArray _DOMDividerElements;
|
||||
CPString _dividerImagePath;
|
||||
int _drawingDivider;
|
||||
CPArray _DOMDividerElements;
|
||||
CPString _dividerImagePath;
|
||||
int _drawingDivider;
|
||||
|
||||
BOOL _needsResizeSubviews;
|
||||
CPString _autosaveName;
|
||||
BOOL _shouldAutosave;
|
||||
CGSize _shouldRestoreFromAutosaveUnlessFrameSize;
|
||||
|
||||
CPArray _buttonBars;
|
||||
BOOL _needsResizeSubviews;
|
||||
int _suppressResizeNotificationsMask;
|
||||
|
||||
CPArray _buttonBars;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -72,32 +105,28 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[1.0, 10.0, [CPColor grayColor]]
|
||||
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [CPSplitView class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPSplitViewHorizontalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewHorizontal.png"] size:CPSizeMake(5.0, 10.0)];
|
||||
CPSplitViewVerticalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewVertical.png"] size:CPSizeMake(10.0, 5.0)];
|
||||
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
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
_currentDivider = CPNotFound;
|
||||
|
||||
_DOMDividerElements = [];
|
||||
_buttonBars = [];
|
||||
|
||||
_shouldAutosave = YES;
|
||||
|
||||
[self _setVertical:YES];
|
||||
}
|
||||
|
||||
@@ -142,14 +171,17 @@ var CPSplitViewHorizontalImage = nil,
|
||||
count = _subviews.length;
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
for (; index < count; ++index)
|
||||
[_subviews[index] setFrame:CGRectMake(ROUND((eachSize + dividerThickness) * index), 0, eachSize, frame.size.height)];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; index < count; ++index)
|
||||
[_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)];
|
||||
}
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
}
|
||||
@@ -162,7 +194,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
_originComponent = [self isVertical] ? "x" : "y";
|
||||
_sizeComponent = [self isVertical] ? "width" : "height";
|
||||
_dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename];
|
||||
_dividerImagePath = [self isVertical] ? [[self valueForThemeAttribute:@"vertical-divider-color"] filename] : [[self valueForThemeAttribute:@"horizontal-divider-color"] filename];
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -225,7 +257,6 @@ var CPSplitViewHorizontalImage = nil,
|
||||
rect = CGRectMakeZero();
|
||||
|
||||
rect.size = [self frame].size;
|
||||
|
||||
rect.size[_sizeComponent] = [self dividerThickness];
|
||||
rect.origin[_originComponent] = frame.origin[_originComponent] + frame.size[_sizeComponent];
|
||||
|
||||
@@ -303,8 +334,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
}
|
||||
|
||||
[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
|
||||
}
|
||||
|
||||
@@ -334,28 +365,33 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
_needsResizeSubviews = NO;
|
||||
|
||||
[self resizeSubviewsWithOldSize:[self _calculateSize]];
|
||||
}
|
||||
|
||||
- (CGSize)_calculateSize
|
||||
{
|
||||
var subviews = [self subviews],
|
||||
count = subviews.length,
|
||||
oldSize = CGSizeMakeZero();
|
||||
size = CGSizeMakeZero();
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
oldSize.width += [self dividerThickness] * (count - 1);
|
||||
oldSize.height = CGRectGetHeight([self frame]);
|
||||
size.width += [self dividerThickness] * (count - 1);
|
||||
size.height = CGRectGetHeight([self frame]);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldSize.width = CGRectGetWidth([self frame]);
|
||||
oldSize.height += [self dividerThickness] * (count - 1);
|
||||
size.width = CGRectGetWidth([self frame]);
|
||||
size.height += [self dividerThickness] * (count - 1);
|
||||
}
|
||||
|
||||
while (count--)
|
||||
oldSize[_sizeComponent] += [subviews[count] frame].size[_sizeComponent];
|
||||
size[_sizeComponent] += [subviews[count] frame].size[_sizeComponent];
|
||||
|
||||
[self resizeSubviewsWithOldSize:oldSize];
|
||||
return size;
|
||||
}
|
||||
|
||||
- (BOOL)cursorAtPoint:(CPPoint)aPoint hitDividerAtIndex:(int)anIndex
|
||||
- (BOOL)cursorAtPoint:(CGPoint)aPoint hitDividerAtIndex:(int)anIndex
|
||||
{
|
||||
var frame = [_subviews[anIndex] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||
@@ -408,11 +444,14 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
// We disabled autosaving during tracking.
|
||||
_shouldAutosave = YES;
|
||||
|
||||
if (_currentDivider != CPNotFound)
|
||||
{
|
||||
_currentDivider = CPNotFound;
|
||||
[self _autosave];
|
||||
[self _updateResizeCursor:anEvent];
|
||||
[self _postNotificationDidResize];
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -420,10 +459,11 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
count = [_subviews count] - 1;
|
||||
|
||||
_currentDivider = CPNotFound;
|
||||
var count = [_subviews count] - 1;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
@@ -436,19 +476,20 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
|
||||
{
|
||||
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i],
|
||||
preCollapsePosition = [_preCollapsePositions objectForKey:"" + i] || 0;
|
||||
|
||||
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i]])
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:minPosition ofDividerAtIndex:i];
|
||||
}
|
||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i + 1]])
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:maxPosition ofDividerAtIndex:i];
|
||||
}
|
||||
@@ -458,6 +499,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
_currentDivider = i;
|
||||
_initialOffset = startPosition - point[_originComponent];
|
||||
|
||||
// Don't autosave during a resize. We'll wait until it's done.
|
||||
_shouldAutosave = NO;
|
||||
[self _postNotificationWillResize];
|
||||
}
|
||||
}
|
||||
@@ -526,19 +569,37 @@ var CPSplitViewHorizontalImage = nil,
|
||||
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
|
||||
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
size = frame.size[_sizeComponent],
|
||||
startPosition = frame.origin[_originComponent] + size,
|
||||
var frameA = [_subviews[i] frame],
|
||||
sizeA = frameA.size[_sizeComponent],
|
||||
startPosition = frameA.origin[_originComponent] + sizeA,
|
||||
frameB = [_subviews[i + 1] frame],
|
||||
sizeB = frameB.size[_sizeComponent],
|
||||
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
|
||||
cursor = [CPCursor arrowCursor];
|
||||
|
||||
if (size === 0)
|
||||
if (sizeA === 0)
|
||||
canGrow = YES; // Subview is collapsed.
|
||||
else if (!canShrink &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
{
|
||||
canShrink = YES; // Subview is collapsible.
|
||||
}
|
||||
|
||||
if (sizeB === 0)
|
||||
{
|
||||
// Right/lower subview is collapsed.
|
||||
canGrow = NO;
|
||||
// It's safe to assume it can always be uncollapsed.
|
||||
canShrink = YES;
|
||||
}
|
||||
else if (!canGrow &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i + 1]])
|
||||
{
|
||||
canGrow = YES; // Right/lower subview is collapsible.
|
||||
}
|
||||
|
||||
if (_isVertical && canShrink && canGrow)
|
||||
cursor = [CPCursor resizeLeftRightCursor];
|
||||
@@ -597,7 +658,15 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
// not sure where this should override other positions?
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedPosition = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
|
||||
// Silently ignore bad positions which could result from odd delegate responses. We don't want these
|
||||
// bad results to go into the system and cause havoc with frame sizes as the split view tries to resize
|
||||
// its subviews.
|
||||
if (_IS_NUMERIC(proposedPosition))
|
||||
position = proposedPosition;
|
||||
}
|
||||
|
||||
var proposedMax = [self maxPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
@@ -605,19 +674,37 @@ var CPSplitViewHorizontalImage = nil,
|
||||
actualMin = proposedMin;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedActualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMin))
|
||||
actualMin = proposedActualMin;
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedActualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMax))
|
||||
actualMax = proposedActualMax;
|
||||
}
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
|
||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||
// Is this position past the halfway point to collapse?
|
||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
if ([_delegate splitView:self canCollapseSubview:viewA])
|
||||
realPosition = proposedMin;
|
||||
|
||||
// We can also collapse to the right.
|
||||
if (position > proposedMax - (proposedMax - actualMax) / 2)
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
if ([_delegate splitView:self canCollapseSubview:viewB])
|
||||
realPosition = proposedMax;
|
||||
|
||||
return realPosition;
|
||||
}
|
||||
|
||||
@@ -628,43 +715,77 @@ var CPSplitViewHorizontalImage = nil,
|
||||
*/
|
||||
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
// Any manual changes to the divider position should override anything we are restoring from
|
||||
// autosave.
|
||||
_shouldRestoreFromAutosaveUnlessFrameSize = nil;
|
||||
|
||||
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(YES);
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex],
|
||||
viewA = _subviews[dividerIndex],
|
||||
frameA = [viewA frame],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
frameB = [viewB frame],
|
||||
preCollapsePosition = 0,
|
||||
preSize = frameA.size[_sizeComponent];
|
||||
|
||||
_preCollapsePosition = 0;
|
||||
|
||||
var preSize = frameA.size[_sizeComponent];
|
||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||
|
||||
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
preCollapsePosition = preSize;
|
||||
|
||||
if (preSize !== frameA.size[_sizeComponent])
|
||||
{
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
preSize = frameB.size[_sizeComponent];
|
||||
|
||||
var preOrigin = frameB.origin[_originComponent];
|
||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||
|
||||
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
preCollapsePosition = frameB.origin[_originComponent];
|
||||
|
||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
|
||||
if (preSize !== frameB.size[_sizeComponent] || preOrigin !== frameB.origin[_originComponent])
|
||||
{
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
if (preCollapsePosition)
|
||||
[_preCollapsePositions setObject:preCollapsePosition forKey:"" + dividerIndex];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
if (SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION())
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(NO);
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize)
|
||||
_shouldAutosave = NO;
|
||||
else
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize)
|
||||
_shouldAutosave = YES;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CPSize)oldSize
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)oldSize
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
|
||||
{
|
||||
@@ -672,67 +793,104 @@ var CPSplitViewHorizontalImage = nil,
|
||||
return;
|
||||
}
|
||||
|
||||
[self adjustSubviews];
|
||||
}
|
||||
|
||||
- (void)adjustSubviews
|
||||
{
|
||||
var count = [_subviews count];
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[self _postNotificationWillResize];
|
||||
|
||||
var index = 0,
|
||||
count = [_subviews count],
|
||||
bounds = [self bounds],
|
||||
boundsSize = bounds.size[_sizeComponent],
|
||||
oldSize = [self _calculateSize],
|
||||
dividerThickness = [self dividerThickness],
|
||||
totalDividers = count - 1,
|
||||
totalSizableSpace = 0,
|
||||
nonSizableSpace = 0,
|
||||
lastSizableIndex = -1,
|
||||
oldFlexibleSpace = 0,
|
||||
totalSizablePanes = 0,
|
||||
isVertical = [self isVertical];
|
||||
isSizableMap = {},
|
||||
viewSizes = [],
|
||||
delegateRespondsToShouldAdjust = [_delegate respondsToSelector:@selector(splitView:shouldAdjustSizeOfSubview:)];
|
||||
|
||||
// What we want to do is to preserve non resizable sizes first, and then to preserve the ratio of size to available
|
||||
// non fixed space for every other subview. E.g. assume fixed space was 20 pixels initially, view 1 was 20 and
|
||||
// view 2 was 30 pixels, for a total of 70 pixels. Then the new total size becomes 140 pixels. Now we want the fixed
|
||||
// space to still be 20 pixels, view 1 to be 48 pixels and view 2 to be 72 pixels. This way the relative size of
|
||||
// view 1 to view 2 remains the same - view 1 was 66% of view 2 initially and after the resize view 1 is still
|
||||
// 66% of view 2's size.
|
||||
//
|
||||
// For this calculation, we can consider the dividers themselves to also be fixed size areas - they should remain
|
||||
// the same size before and after.
|
||||
|
||||
// How much flexible size do we have in pre-resize pixels?
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
isSizable = !delegateRespondsToShouldAdjust || [_delegate splitView:self shouldAdjustSizeOfSubview:view],
|
||||
size = [view frame].size[_sizeComponent];
|
||||
|
||||
isSizableMap[index] = isSizable;
|
||||
viewSizes.push(size);
|
||||
|
||||
if (isSizable)
|
||||
{
|
||||
totalSizableSpace += [view frame].size[_sizeComponent];
|
||||
lastSizableIndex = index;
|
||||
oldFlexibleSpace += size;
|
||||
totalSizablePanes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSizablePanes === count)
|
||||
totalSizableSpace = 0;
|
||||
// nonSizableSpace is the number of fixed pixels in pre-resize terms and the desired number post-resize.
|
||||
var nonSizableSpace = oldSize[_sizeComponent] - oldFlexibleSpace,
|
||||
newFlexibleSpace = boundsSize - nonSizableSpace,
|
||||
remainingFixedPixelsToRemove = 0;
|
||||
|
||||
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
||||
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
|
||||
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
|
||||
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
|
||||
if (newFlexibleSpace < 0)
|
||||
{
|
||||
remainingFixedPixelsToRemove = -newFlexibleSpace;
|
||||
newFlexibleSpace = 0;
|
||||
}
|
||||
|
||||
var remainingFixedPanes = count - totalSizablePanes;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
viewFrame = CGRectMakeCopy(bounds),
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
isSizable = isSizableMap[index],
|
||||
targetSize = 0;
|
||||
|
||||
// The last area must take up exactly the remaining space, fixed or not.
|
||||
if (index + 1 === count)
|
||||
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
|
||||
|
||||
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
|
||||
|
||||
else if (isSizable || !totalSizableSpace)
|
||||
targetSize = boundsSize - viewFrame.origin[_originComponent];
|
||||
// Try to keep fixed size areas the same size.
|
||||
else if (!isSizable)
|
||||
{
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
|
||||
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
|
||||
var removedFixedPixels = MIN(remainingFixedPixelsToRemove / remainingFixedPanes, viewSizes[index]);
|
||||
targetSize = viewSizes[index] - removedFixedPixels;
|
||||
remainingFixedPixelsToRemove -= removedFixedPixels;
|
||||
remainingFixedPanes--;
|
||||
}
|
||||
// (new size / flexible size available) == (old size / old flexible size available)
|
||||
else if (oldFlexibleSpace > 0)
|
||||
targetSize = newFlexibleSpace * viewSizes[index] / oldFlexibleSpace;
|
||||
// oldFlexibleSpace <= 0 so all flexible areas were crushed. When we get space, allocate it evenly.
|
||||
// totalSizablePanes cannot be 0 since isSizable.
|
||||
else
|
||||
targetSize = newFlexibleSpace / totalSizablePanes;
|
||||
|
||||
else if (totalSizableSpace && !isSizable)
|
||||
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
||||
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
|
||||
targetSize = MAX(0, ROUND(targetSize));
|
||||
viewFrame.size[_sizeComponent] = targetSize;
|
||||
[view setFrame:viewFrame];
|
||||
bounds.origin[_originComponent] += targetSize + dividerThickness;
|
||||
}
|
||||
|
||||
[self _postNotificationDidResize];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -749,6 +907,11 @@ Notifies the delegate when the subviews will be resized.
|
||||
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
Allows the delegate to specify which of the CPSplitView's subviews should adjust if the window is resized.
|
||||
@code
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView shouldAdjustSizeOfSubview:(CPView)aSubView
|
||||
@endcode
|
||||
|
||||
Lets the delegate specify a different rect for which the user can drag the splitView divider.
|
||||
@code
|
||||
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
|
||||
@@ -831,6 +994,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
@param CPButtonBar - The supplied button bar.
|
||||
@param unsigned int - The divider index the button bar will be assigned to.
|
||||
*/
|
||||
// FIXME Should be renamed to setButtonBar:ofDividerAtIndex:.
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
{
|
||||
if (!aButtonBar)
|
||||
@@ -862,12 +1026,168 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
|
||||
- (void)_postNotificationWillResize
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)_postNotificationDidResize
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification object:self];
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
|
||||
|
||||
// TODO Cocoa always autosaves on "viewDidEndLiveResize". If Cappuccino adds support for this we
|
||||
// should do the same.
|
||||
[self _autosave];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the name under which the split view divider positions is automatically saved to CPUserDefaults.
|
||||
|
||||
@param autosaveName the name to save under or nil to not save
|
||||
*/
|
||||
- (void)setAutosaveName:(CPString)autosaveName
|
||||
{
|
||||
if (_autosaveName == autosaveName)
|
||||
return;
|
||||
|
||||
_autosaveName = autosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
Get the name under which the split view divider position is automatically saved to CPUserDefaults.
|
||||
|
||||
@return the name to save under or nil if no autosave is active
|
||||
*/
|
||||
- (CPString)autosaveName
|
||||
{
|
||||
return _autosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_autosave
|
||||
{
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize || !_shouldAutosave || !_autosaveName)
|
||||
return;
|
||||
|
||||
var userDefaults = [CPUserDefaults standardUserDefaults],
|
||||
autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
|
||||
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
|
||||
count = [_subviews count],
|
||||
positions = [CPMutableArray new],
|
||||
preCollapseArray = [CPMutableArray new];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var frame = [_subviews[i] frame];
|
||||
[positions addObject:CGStringFromRect(frame)];
|
||||
[preCollapseArray addObject:[_preCollapsePositions objectForKey:"" + i]];
|
||||
}
|
||||
|
||||
[userDefaults setObject:positions forKey:autosaveName];
|
||||
[userDefaults setObject:preCollapseArray forKey:autosavePrecollapseName];
|
||||
}
|
||||
|
||||
/*!
|
||||
This is called sometime later after a split view has been restored from a Cib.
|
||||
See notes in initWithCoder.
|
||||
|
||||
@ignore
|
||||
*/
|
||||
- (void)_restoreFromAutosaveIfNeeded
|
||||
{
|
||||
if (_shouldRestoreFromAutosaveUnlessFrameSize && !CGSizeEqualToSize([self frameSize], _shouldRestoreFromAutosaveUnlessFrameSize))
|
||||
{
|
||||
[self _restoreFromAutosave];
|
||||
}
|
||||
|
||||
_shouldRestoreFromAutosaveUnlessFrameSize = nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_restoreFromAutosave
|
||||
{
|
||||
if (!_autosaveName)
|
||||
return;
|
||||
|
||||
var autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
|
||||
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
|
||||
userDefaults = [CPUserDefaults standardUserDefaults],
|
||||
frames = [userDefaults objectForKey:autosaveName],
|
||||
preCollapseArray = [userDefaults objectForKey:autosavePrecollapseName];
|
||||
|
||||
if (frames)
|
||||
{
|
||||
var dividerThickness = [self dividerThickness],
|
||||
position = 0;
|
||||
|
||||
_shouldAutosave = NO;
|
||||
|
||||
for (var i = 0, count = [frames count] - 1; i < count; i++)
|
||||
{
|
||||
var frame = CGRectFromString(frames[i]);
|
||||
position += frame.size[_sizeComponent];
|
||||
|
||||
[self setPosition:position ofDividerAtIndex:i];
|
||||
|
||||
position += dividerThickness;
|
||||
}
|
||||
|
||||
_shouldAutosave = YES;
|
||||
}
|
||||
|
||||
if (preCollapseArray)
|
||||
{
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
|
||||
for (var i = 0, count = [preCollapseArray count]; i < count; i++)
|
||||
{
|
||||
var item = preCollapseArray[i];
|
||||
|
||||
if (item === nil)
|
||||
[_preCollapsePositions removeObjectForKey:String(i)];
|
||||
else
|
||||
[_preCollapsePositions setObject:item forKey:String(i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPString)_framesKeyForAutosaveName:(CPString)theAutosaveName
|
||||
{
|
||||
if (!theAutosaveName)
|
||||
return nil;
|
||||
|
||||
return @"CPSplitView Subview Frames " + theAutosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPString)_precollapseKeyForAutosaveName:(CPString)theAutosaveName
|
||||
{
|
||||
if (!theAutosaveName)
|
||||
return nil;
|
||||
|
||||
return @"CPSplitView Subview Precollapse Positions " + theAutosaveName;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -875,7 +1195,8 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
|
||||
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
|
||||
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey",
|
||||
CPSplitViewAutosaveNameKey = "CPSplitViewAutosaveNameKey";
|
||||
|
||||
@implementation CPSplitView (CPCoding)
|
||||
|
||||
@@ -885,11 +1206,43 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// We need to restore this property before calling super's initWithCoder:.
|
||||
_autosaveName = [aCoder decodeObjectForKey:CPSplitViewAutosaveNameKey];
|
||||
|
||||
/*
|
||||
|
||||
It is common for the main window of a Cappuccino app window to be resized to match the browser
|
||||
window size at the end of the UI being loaded from a cib. But at decoding time (now) whatever
|
||||
window size was originally saved will be in place, so if we try to restore the autosaved divider
|
||||
positions now they might be constrained to the wrong positions due to the difference in frame size,
|
||||
and in addition they might move later when the window is resized.
|
||||
|
||||
The workaround is to restore the position once now (so it's approximately correct during loading),
|
||||
and then once more in the next runloop cycle when any `setFullPlatformWindow` calls are done.
|
||||
|
||||
(However if the frame size doesn't change before the next cycle, we should not restore the position
|
||||
again because that would overwrite any changes the app developer might have made in user code.)
|
||||
|
||||
The other consideration is that any parent split views need to be restored before any child
|
||||
subviews, otherwise the parent restore will also change the positioning of the child.
|
||||
|
||||
*/
|
||||
if (_autosaveName)
|
||||
{
|
||||
// Schedule /before/ [super initWithCoder:]. This way this instance's _restoreFromAutosaveIfNeeded
|
||||
// will happen before that of any subviews loaded by [super initWithCoder:].
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(_restoreFromAutosaveIfNeeded) target:self argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
|
||||
_currentDivider = CPNotFound;
|
||||
_shouldAutosave = YES;
|
||||
|
||||
_DOMDividerElements = [];
|
||||
|
||||
@@ -899,6 +1252,14 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
|
||||
|
||||
if (_autosaveName)
|
||||
{
|
||||
[self _restoreFromAutosave];
|
||||
// Remember the frame size we had at this point so that we can restore again if it changes
|
||||
// before the next runloop cycle. See above notes.
|
||||
_shouldRestoreFromAutosaveUnlessFrameSize = [self frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -919,6 +1280,8 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
|
||||
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
|
||||
|
||||
[aCoder encodeObject:_autosaveName forKey:CPSplitViewAutosaveNameKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+151
-57
@@ -20,20 +20,21 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPControl.j>
|
||||
@import <AppKit/CPButton.j>
|
||||
@import <AppKit/CPTextField.j>
|
||||
@import "CPControl.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
|
||||
var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
|
||||
/*! CPStepper is an implementation of Cocoa NSStepper.
|
||||
/*!
|
||||
CPStepper is an implementation of Cocoa NSStepper.
|
||||
|
||||
This control display a two part button that can be used to increase or decrease a value with a given interval.
|
||||
This control displays a two part button that can be used to increase or decrease a value with a given interval.
|
||||
*/
|
||||
@implementation CPStepper: CPControl
|
||||
{
|
||||
BOOL _valueWraps @accessors(property=valueWraps);
|
||||
BOOL _autorepeat @accessors(getter=autorepeat);
|
||||
int _increment @accessors(property=increment);
|
||||
int _maxValue @accessors(property=maxValue);
|
||||
int _minValue @accessors(property=minValue);
|
||||
@@ -45,7 +46,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*! Initializes a CPStepper with given values
|
||||
/*!
|
||||
Initializes a CPStepper with given values.
|
||||
@param aValue the initial value of the CPStepper
|
||||
@param minValue the minimal acceptable value of the stepper
|
||||
@param maxValue the maximal acceptable value of the stepper
|
||||
@@ -53,18 +55,24 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
*/
|
||||
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||
{
|
||||
var stepper = [[CPStepper alloc] initWithFrame:CPRectMake(0, 0, 19, 25)];
|
||||
var stepper = [[CPStepper alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[stepper setDoubleValue:aValue];
|
||||
[stepper setMinValue:aMinValue];
|
||||
[stepper setMaxValue:aMaxValue];
|
||||
|
||||
// _sizeToFit will put the good size for the stepper depending of the current theme
|
||||
[stepper _sizeToFit];
|
||||
|
||||
return stepper;
|
||||
}
|
||||
|
||||
/*! Initializes a CPStepper with default values:
|
||||
/*!
|
||||
Initializes a CPStepper with default values:
|
||||
- minValue = 0.0
|
||||
- maxValue = 59.0
|
||||
- value = 0.0
|
||||
|
||||
@return Initialized CPStepper
|
||||
*/
|
||||
+ (CPStepper)stepper
|
||||
@@ -72,7 +80,24 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
||||
}
|
||||
|
||||
/*! Initializes the CPStepper
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding || aBinding == CPMinValueBinding || aBinding == CPMaxValueBinding)
|
||||
return [_CPStepperValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
return @"doubleValue";
|
||||
|
||||
return [super _replacementKeyPathForBinding:aBinding];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes a CPStepper.
|
||||
@param aFrame the frame of the control
|
||||
@return initialized CPStepper
|
||||
*/
|
||||
@@ -84,33 +109,43 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
_minValue = 0.0;
|
||||
_increment = 1.0;
|
||||
_valueWraps = YES;
|
||||
_autorepeat = YES;
|
||||
|
||||
[self setDoubleValue:0.0];
|
||||
|
||||
_buttonUp = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
|
||||
[_buttonUp setContinuous:YES];
|
||||
[_buttonUp setTarget:self];
|
||||
[_buttonUp setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonUp setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonUp];
|
||||
|
||||
_buttonDown = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
|
||||
[_buttonDown setContinuous:YES];
|
||||
[_buttonDown setTarget:self];
|
||||
[_buttonDown setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonDown setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonDown];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_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 setContinuous:_autorepeat];
|
||||
[_buttonDown setTarget:self];
|
||||
[_buttonDown setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonDown setAutoresizingMask:CPViewNotSizable];
|
||||
|
||||
[self setContinuous:_autorepeat];
|
||||
[self addSubview:_buttonDown];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Superclass overrides
|
||||
|
||||
/*! set if the CPStepper is enabled or not
|
||||
/*!
|
||||
Set if the CPStepper is enabled or not.
|
||||
@param shouldEnabled BOOL that define if stepper is enabled or not.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)shouldEnabled
|
||||
@@ -121,19 +156,31 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonDown setEnabled:shouldEnabled];
|
||||
}
|
||||
|
||||
/*! set the frame of the CPStepper and check if width is not smaller than theme min-size
|
||||
@param aFrame the frame
|
||||
*/
|
||||
|
||||
- (void)setFrame:(CGRect)aFrame
|
||||
{
|
||||
if (aFrame.size.width >= CGRectGetWidth(aFrame))
|
||||
[super setFrame:aFrame];
|
||||
var upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
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);
|
||||
[super setFrame:frame];
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
/*! @ignore */
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
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);
|
||||
|
||||
[_buttonUp setFrame:upFrame];
|
||||
[_buttonDown setFrame:downFrame];
|
||||
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
||||
@@ -142,16 +189,28 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
/*! set if CPStepper should autorepeat
|
||||
- (void)_sizeToFit
|
||||
{
|
||||
[self setFrame:CGRectMake([self frameOrigin].x, [self frameOrigin].y, 0, 0)];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set if CPStepper should autorepeat.
|
||||
@param shouldAutoRepeat if YES, the first mouse down does one increment (decrement) and, after each delay of 0.5 seconds
|
||||
*/
|
||||
- (void)setAutorepeat:(BOOL)shouldAutoRepeat
|
||||
{
|
||||
[_buttonUp setContinuous:shouldAutoRepeat];
|
||||
[_buttonDown setContinuous:shouldAutoRepeat];
|
||||
if (shouldAutoRepeat !== _autorepeat)
|
||||
{
|
||||
[_buttonUp setContinuous:shouldAutoRepeat];
|
||||
[_buttonDown setContinuous:shouldAutoRepeat];
|
||||
}
|
||||
|
||||
[self setContinuous:shouldAutoRepeat];
|
||||
}
|
||||
|
||||
/*! set the current value of the stepper
|
||||
/*!
|
||||
Set the current value of the stepper.
|
||||
@param aValue a float containing the value
|
||||
*/
|
||||
- (void)setDoubleValue:(float)aValue
|
||||
@@ -167,8 +226,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
#pragma mark -
|
||||
#pragma mark Actions
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
/*! @ignore */
|
||||
- (IBAction)_buttonDidClick:(id)aSender
|
||||
{
|
||||
if (![self isEnabled])
|
||||
@@ -179,11 +237,11 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
else
|
||||
[self setDoubleValue:([self doubleValue] - _increment)];
|
||||
|
||||
if (_target && _action && [_target respondsToSelector:_action])
|
||||
[self sendAction:_action to:_target];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
/*! @perform a programatic click on up button
|
||||
/*!
|
||||
Perform a programatic click on up button.
|
||||
@param aSender sender of the action
|
||||
*/
|
||||
- (IBAction)performClickUp:(id)aSender
|
||||
@@ -191,7 +249,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonUp performClick:aSender];
|
||||
}
|
||||
|
||||
/*! @perform a programatic click on down button
|
||||
/*!
|
||||
Perform a programatic click on down button.
|
||||
@param aSender sender of the action
|
||||
*/
|
||||
- (IBAction)performClickDown:(id)aSender
|
||||
@@ -210,25 +269,55 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null]]
|
||||
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button"]];
|
||||
return @{
|
||||
@"bezel-color-up-button": [CPNull null],
|
||||
@"bezel-color-down-button": [CPNull null],
|
||||
@"up-button-size": CGSizeMakeZero(),
|
||||
@"down-button-size": CGSizeMakeZero(),
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPStepperValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
@implementation CPStepper (CPCodingCompliance)
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||
{
|
||||
var placeholder = (aBinding == CPMaxValueBinding) ? [_source maxValue] : [_source minValue];
|
||||
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[self _setPlaceholder:placeholder forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholder forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholder forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholder forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPStepperMinValue = @"CPStepperMinValue",
|
||||
CPStepperMaxValue = @"CPStepperMaxValue",
|
||||
CPStepperValueWraps = @"CPStepperValueWraps",
|
||||
CPStepperAutorepeat = @"CPStepperAutorepeat",
|
||||
CPStepperIncrement = @"CPStepperIncrement";
|
||||
|
||||
@implementation CPStepper (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
|
||||
_increment = [aCoder decodeObjectForKey:@"_increment"];
|
||||
_buttonUp = [aCoder decodeObjectForKey:@"_buttonUp"];
|
||||
_buttonDown = [aCoder decodeObjectForKey:@"_buttonDown"];
|
||||
_increment = [aCoder decodeIntForKey:CPStepperIncrement];
|
||||
_minValue = [aCoder decodeIntForKey:CPStepperMinValue];
|
||||
_maxValue = [aCoder decodeIntForKey:CPStepperMaxValue];
|
||||
_valueWraps = [aCoder decodeBoolForKey:CPStepperValueWraps];
|
||||
_autorepeat = [aCoder decodeBoolForKey:CPStepperAutorepeat];
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -236,11 +325,16 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
||||
[aCoder encodeObject:_minValue forKey:@"_minValue"];
|
||||
[aCoder encodeObject:_increment forKey:@"_increment"];
|
||||
[aCoder encodeObject:_buttonUp forKey:@"_buttonUp"];
|
||||
[aCoder encodeObject:_buttonDown forKey:@"_buttonDown"];
|
||||
[aCoder encodeInt:_increment forKey:CPStepperIncrement];
|
||||
|
||||
if (_minValue)
|
||||
[aCoder encodeInt:_minValue forKey:CPStepperMinValue];
|
||||
if (_maxValue)
|
||||
[aCoder encodeInt:_maxValue forKey:CPStepperMaxValue];
|
||||
if (_valueWraps)
|
||||
[aCoder encodeBool:_valueWraps forKey:CPStepperValueWraps];
|
||||
if (_autorepeat)
|
||||
[aCoder encodeBool:_autorepeat forKey:CPStepperAutorepeat];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPPlatformString.j"
|
||||
|
||||
|
||||
|
||||
+93
-38
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* CPTabView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Derek Hammer.
|
||||
* Copyright 2010, Derek Hammer.
|
||||
*
|
||||
* 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 "CPBox.j"
|
||||
@import "CPSegmentedControl.j"
|
||||
@import "CPTabViewItem.j"
|
||||
@@ -45,7 +67,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_items = [CPArray array];
|
||||
_selectedIndex = CPNotFound;
|
||||
|
||||
[self _init];
|
||||
[self setTabViewType:CPTopTabsBezelBorder];
|
||||
@@ -56,6 +77,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedIndex = CPNotFound;
|
||||
|
||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
|
||||
[_tabs setHitTests:NO];
|
||||
|
||||
@@ -65,9 +88,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
_box = [[CPBox alloc] initWithFrame:[self bounds]];
|
||||
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
||||
|
||||
[_box setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
|
||||
|
||||
[self addSubview:_box];
|
||||
[self addSubview:_tabs];
|
||||
}
|
||||
@@ -250,17 +270,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
Selects the item at the specified index.
|
||||
@param anIndex the index of the item to display.
|
||||
*/
|
||||
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||
- (BOOL)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
var aTabViewItem = [_items objectAtIndex:anIndex];
|
||||
|
||||
if (anIndex === _selectedIndex)
|
||||
return;
|
||||
|
||||
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||
|
||||
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
||||
return;
|
||||
return NO;
|
||||
|
||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||
@@ -270,6 +288,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -278,7 +298,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
if (_selectedIndex != CPNotFound)
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Modifying the font
|
||||
@@ -317,21 +340,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
_type = aTabViewType;
|
||||
|
||||
if (_type !== CPTopTabsBezelBorder && _type !== CPBottomTabsBezelBorder)
|
||||
{
|
||||
[_box setFrame:[self bounds]];
|
||||
[_tabs removeFromSuperview];
|
||||
}
|
||||
else
|
||||
{
|
||||
var aFrame = [self frame],
|
||||
segmentedHeight = CGRectGetHeight([_tabs frame]),
|
||||
origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
|
||||
|
||||
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
|
||||
CGRectGetHeight(aFrame) - segmentedHeight / 2)];
|
||||
|
||||
[self addSubview:_tabs];
|
||||
}
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
@@ -347,6 +358,29 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
[_box setBorderType:CPNoBorder];
|
||||
break;
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
// Even if CPTabView's autoresizesSubviews is NO, _tabs and _box has to be laid out.
|
||||
// This means we can't rely on autoresize masks.
|
||||
if (_type !== CPTopTabsBezelBorder && _type !== CPBottomTabsBezelBorder)
|
||||
{
|
||||
[_box setFrame:[self bounds]];
|
||||
}
|
||||
else
|
||||
{
|
||||
var aFrame = [self frame],
|
||||
segmentedHeight = CGRectGetHeight([_tabs frame]),
|
||||
origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
|
||||
|
||||
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
|
||||
CGRectGetHeight(aFrame) - segmentedHeight / 2)];
|
||||
|
||||
[self _repositionTabs];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -407,11 +441,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
||||
|
||||
if (segmentIndex != CPNotFound)
|
||||
{
|
||||
[self selectTabViewItemAtIndex:segmentIndex];
|
||||
if (segmentIndex != CPNotFound && [self selectTabViewItemAtIndex:segmentIndex])
|
||||
[_tabs trackSegment:anEvent];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_repositionTabs
|
||||
@@ -428,8 +459,12 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (void)_setSelectedIndex:(CPNumber)index
|
||||
{
|
||||
_selectedIndex = index;
|
||||
[self _setContentViewFromItem:[_items objectAtIndex:_selectedIndex]];
|
||||
}
|
||||
|
||||
[_box setContentView:[[_items objectAtIndex:_selectedIndex] view]];
|
||||
- (void)_setContentViewFromItem:(CPTabViewItem)anItem
|
||||
{
|
||||
[_box setContentView:[anItem view]];
|
||||
}
|
||||
|
||||
- (void)_updateItems
|
||||
@@ -444,9 +479,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
}
|
||||
|
||||
if (_selectedIndex === CPNotFound)
|
||||
{
|
||||
[self selectFirstTabViewItem:self];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -469,29 +502,51 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
[_tabs setFont:_font];
|
||||
|
||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
[_items makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
|
||||
[self setTabViewType:[aCoder decodeIntForKey:CPTabViewTypeKey]];
|
||||
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];
|
||||
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
var selected = [self selectedTabViewItem];
|
||||
if (selected)
|
||||
[aCoder encodeObject:selected forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
||||
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
||||
|
||||
@@ -60,6 +60,7 @@ CPPressedTab = 2;
|
||||
CPView _auxiliaryView;
|
||||
|
||||
CPTabView _tabView;
|
||||
unsigned _tabState; // Looks like it is not yet implemented
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -132,7 +133,13 @@ CPPressedTab = 2;
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
if (_view == aView)
|
||||
return;
|
||||
|
||||
_view = aView;
|
||||
|
||||
if ([_tabView selectedTabViewItem] == self)
|
||||
[_tabView _setContentViewFromItem:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+69
-35
@@ -26,8 +26,11 @@
|
||||
@import <Foundation/CPSortDescriptor.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPTableHeaderView.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
@global CPTableViewColumnDidResizeNotification
|
||||
|
||||
@class _CPTableColumnHeaderView
|
||||
|
||||
CPTableColumnNoResizing = 0;
|
||||
CPTableColumnAutoresizingMask = 1 << 0;
|
||||
@@ -49,7 +52,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
CPTableView _tableView;
|
||||
CPView _headerView;
|
||||
CPView _dataView;
|
||||
Object _dataViewData;
|
||||
CPData _dataViewData;
|
||||
|
||||
float _width;
|
||||
float _minWidth;
|
||||
@@ -83,7 +86,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_dataViewData = { };
|
||||
_dataViewData = nil;
|
||||
|
||||
_width = 100.0;
|
||||
_minWidth = 10.0;
|
||||
@@ -132,7 +135,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
{
|
||||
var min = [self minWidth],
|
||||
max = [self maxWidth],
|
||||
newWidth = MIN(MAX(width, min), max);
|
||||
newWidth = ROUND(MIN(MAX(width, min), max));
|
||||
|
||||
[self setWidth:newWidth];
|
||||
|
||||
@@ -280,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];
|
||||
@@ -392,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
|
||||
@@ -421,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;
|
||||
@@ -494,16 +485,23 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
*/
|
||||
- (CPSortDescriptor)sortDescriptorPrototype
|
||||
{
|
||||
return _sortDescriptorPrototype;
|
||||
if (_sortDescriptorPrototype)
|
||||
return _sortDescriptorPrototype;
|
||||
|
||||
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
|
||||
binding = [binderClass getBinding:CPValueBinding forObject:self];
|
||||
|
||||
return [binding _defaultSortDescriptorPrototype];
|
||||
}
|
||||
|
||||
/*!
|
||||
If NO the tablecolumn will no longer be visible in the tableview
|
||||
If YES the tablecolumn will be visible in the tableview.
|
||||
If YES the tablecolumn will no longer be visible in the tableview.
|
||||
If NO the tablecolumn will be visible in the tableview.
|
||||
*/
|
||||
- (void)setHidden:(BOOL)shouldBeHidden
|
||||
{
|
||||
shouldBeHidden = !!shouldBeHidden
|
||||
|
||||
if (_isHidden === shouldBeHidden)
|
||||
return;
|
||||
|
||||
@@ -550,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
|
||||
@@ -569,6 +567,30 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
[tableView reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
|
||||
}
|
||||
|
||||
- (CPSortDescriptor)_defaultSortDescriptorPrototype
|
||||
{
|
||||
if (![self createsSortDescriptor])
|
||||
return nil;
|
||||
|
||||
var keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
dotIndex = keyPath.indexOf(".");
|
||||
|
||||
if (dotIndex === CPNotFound)
|
||||
return nil;
|
||||
|
||||
var firstPart = keyPath.substring(0, dotIndex),
|
||||
key = keyPath.substring(dotIndex + 1);
|
||||
|
||||
return [CPSortDescriptor sortDescriptorWithKey:key ascending:YES];
|
||||
}
|
||||
|
||||
- (BOOL)createsSortDescriptor
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey],
|
||||
optionValue = [options objectForKey:CPCreatesSortDescriptorBindingOption];
|
||||
return optionValue === nil ? YES : [optionValue boolValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTableColumn (Bindings)
|
||||
@@ -594,7 +616,22 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||
|
||||
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
|
||||
[[self tableView] _establishBindingsIfUnbound:anObject];
|
||||
{
|
||||
// Bind the table to the array controller this column is bound to.
|
||||
// Note that anObject might not be the array controller. E.g. the keypath could be something like
|
||||
// somePathTo.anArrayController.arrangedObjects.aKey. Cocoa doesn't support this but it is consistent
|
||||
// and it makes sense.
|
||||
var acIndex = aKeyPath.lastIndexOf("arrangedObjects."),
|
||||
arrayController = anObject;
|
||||
|
||||
if (acIndex > 1)
|
||||
{
|
||||
var firstPart = aKeyPath.substring(0, acIndex - 1);
|
||||
arrayController = [anObject valueForKeyPath:firstPart];
|
||||
}
|
||||
|
||||
[[self tableView] _establishBindingsIfUnbound:arrayController];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -663,8 +700,11 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
bindingInfo = binding._info,
|
||||
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
||||
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
||||
options = [bindingInfo objectForKey:CPOptionsKey],
|
||||
dotIndex = keyPath.lastIndexOf(".");
|
||||
|
||||
newValue = [binding reverseTransformValue:newValue withOptions:options];
|
||||
|
||||
if (dotIndex === CPNotFound)
|
||||
[[destination valueForKeyPath:keyPath] replaceObjectAtIndex:aRow withObject:newValue];
|
||||
else
|
||||
@@ -681,11 +721,6 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
//- (void)objectValue
|
||||
//{
|
||||
// return nil;
|
||||
//}
|
||||
|
||||
@end
|
||||
|
||||
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
@@ -710,7 +745,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
_dataViewData = { };
|
||||
_dataViewData = nil;
|
||||
|
||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||
@@ -719,7 +754,6 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
|
||||
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
|
||||
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
|
||||
|
||||
+133
-39
@@ -22,9 +22,15 @@
|
||||
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import "CPCursor.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
@class CPTableView
|
||||
|
||||
@global CPApp
|
||||
|
||||
|
||||
@implementation _CPTableColumnHeaderView : CPView
|
||||
@@ -39,13 +45,22 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
|
||||
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-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
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
if (self)
|
||||
[self _init];
|
||||
|
||||
@@ -54,7 +69,7 @@
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_textField setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
@@ -72,12 +87,13 @@
|
||||
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:@"text-font"]];
|
||||
[_textField setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
|
||||
[_textField setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(CPString)string
|
||||
@@ -102,7 +118,52 @@
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[self setValue:aFont forThemeAttribute:"text-font"];
|
||||
[self setValue:aFont forThemeAttribute:@"font"];
|
||||
}
|
||||
|
||||
- (CPFont)font
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"font"]
|
||||
}
|
||||
|
||||
- (void)setAlignment:(CPTextAlignment)alignment
|
||||
{
|
||||
[self setValue:alignment forThemeAttribute:@"text-alignment"];
|
||||
}
|
||||
|
||||
- (CPTextAlignment)alignment
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"text-alignment"]
|
||||
}
|
||||
|
||||
- (void)setLineBreakMode:(CPLineBreakMode)mode
|
||||
{
|
||||
[self setValue:mode forThemeAttribute:@"line-break-mode"];
|
||||
}
|
||||
|
||||
- (CPLineBreakMode)lineBreakMode
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"line-break-mode"]
|
||||
}
|
||||
|
||||
- (void)setTextColor:(CPColor)aColor
|
||||
{
|
||||
[self setValue:aColor forThemeAttribute:@"text-color"];
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"text-color"]
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"text-shadow-color"]
|
||||
}
|
||||
|
||||
- (void)_setIndicatorImage:(CPImage)anImage
|
||||
@@ -122,6 +183,10 @@
|
||||
|
||||
var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
|
||||
_CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
|
||||
_CPTableColumnHeaderViewTextColorKey = @"_CPTableColumnHeaderViewTextColorKey",
|
||||
_CPTableColumnHeaderViewTextShadowColorKey = @"_CPTableColumnHeaderViewTextShadowColorKey",
|
||||
_CPTableColumnHeaderViewAlignmentKey = @"_CPTableColumnHeaderViewAlignmentKey",
|
||||
_CPTableColumnHeaderViewLineBreakModeKey = @"_CPTableColumnHeaderViewLineBreakModeKey",
|
||||
_CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
|
||||
|
||||
@implementation _CPTableColumnHeaderView (CPCoding)
|
||||
@@ -134,6 +199,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
|
||||
[self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
|
||||
[self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
|
||||
[self setTextColor:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewTextColorKey]];
|
||||
[self setTextShadowColor:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewTextShadowColorKey]];
|
||||
[self setAlignment:[aCoder decodeIntForKey:_CPTableColumnHeaderViewAlignmentKey]];
|
||||
[self setLineBreakMode:[aCoder decodeIntForKey:_CPTableColumnHeaderViewLineBreakModeKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -145,7 +214,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
|
||||
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
|
||||
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
|
||||
[aCoder encodeObject:[self font] forKey:_CPTableColumnHeaderViewFontKey];
|
||||
[aCoder encodeObject:[self textColor] forKey:_CPTableColumnHeaderViewTextColorKey];
|
||||
[aCoder encodeObject:[self textShadowColor] forKey:_CPTableColumnHeaderViewTextShadowColorKey];
|
||||
[aCoder encodeInt:[self alignment] forKey:_CPTableColumnHeaderViewAlignmentKey];
|
||||
[aCoder encodeInt:[self lineBreakMode] forKey:_CPTableColumnHeaderViewLineBreakModeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -156,6 +229,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
CGPoint _previousTrackingLocation;
|
||||
int _activeColumn;
|
||||
int _pressedColumn;
|
||||
int _lastDragDestinationColumnIndex;
|
||||
|
||||
BOOL _isResizing;
|
||||
BOOL _isDragging;
|
||||
@@ -174,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;
|
||||
|
||||
@@ -215,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;
|
||||
}
|
||||
@@ -234,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;
|
||||
@@ -256,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;
|
||||
@@ -275,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)
|
||||
{
|
||||
@@ -319,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)
|
||||
{
|
||||
@@ -339,6 +418,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
_lastDragDestinationColumnIndex = -1;
|
||||
[self _setPressedColumn:aColumnIndex];
|
||||
}
|
||||
|
||||
@@ -347,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;
|
||||
@@ -366,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
|
||||
@@ -377,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
|
||||
@@ -410,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];
|
||||
@@ -425,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
|
||||
@@ -452,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];
|
||||
@@ -463,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;
|
||||
@@ -486,6 +576,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self stopTrackingTableColumn:_activeColumn at:aLocation];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[_tableView _enqueueDraggingViews];
|
||||
}
|
||||
|
||||
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
@@ -496,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
|
||||
@@ -552,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];
|
||||
@@ -634,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)));
|
||||
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(CGRectGetMaxY(columnToStroke)) - 1.0);
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
|
||||
+1033
-308
File diff suppressed because it is too large
Load Diff
+512
-224
File diff suppressed because it is too large
Load Diff
+44
-30
@@ -21,9 +21,11 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPMutableArray.j>
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
@class CPView
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
@@ -83,7 +85,7 @@ var CPThemesByName = { },
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_attributes = [CPDictionary dictionary];
|
||||
_attributes = @{};
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
}
|
||||
@@ -145,7 +147,7 @@ var CPThemesByName = { },
|
||||
className = [aClass defaultThemeClass];
|
||||
else if ([aClass respondsToSelector:@selector(themeClass)])
|
||||
{
|
||||
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass",CPStringFromClass([anObject class]));
|
||||
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass", CPStringFromClass(aClass));
|
||||
className = [aClass themeClass];
|
||||
}
|
||||
else
|
||||
@@ -255,7 +257,7 @@ var CPThemesByName = { },
|
||||
attributeNames = [attributes keyEnumerator],
|
||||
objectThemeClass = [anObject themeClass];
|
||||
|
||||
while (attributeName = [attributeNames nextObject])
|
||||
while ((attributeName = [attributeNames nextObject]) !== nil)
|
||||
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
|
||||
}
|
||||
|
||||
@@ -268,7 +270,7 @@ var CPThemesByName = { },
|
||||
|
||||
if (!attributes)
|
||||
{
|
||||
attributes = [CPDictionary dictionary];
|
||||
attributes = @{};
|
||||
|
||||
[_attributes setObject:attributes forKey:aClass];
|
||||
}
|
||||
@@ -402,22 +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");
|
||||
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
|
||||
{
|
||||
@@ -426,7 +431,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
CPDictionary _values @accessors(readonly, getter=values);
|
||||
|
||||
JSObject _cache;
|
||||
_CPThemeAttribute _parentAttribute;
|
||||
_CPThemeAttribute _themeDefaultAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
@@ -438,7 +443,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_cache = { };
|
||||
_name = aName;
|
||||
_defaultValue = aDefaultValue;
|
||||
_values = [CPDictionary dictionary];
|
||||
_values = @{};
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -469,9 +474,9 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_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
|
||||
@@ -537,11 +542,18 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -549,11 +561,11 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
|
||||
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_parentAttribute === anAttribute)
|
||||
if (_themeDefaultAttribute === anAttribute)
|
||||
return;
|
||||
|
||||
_cache = { };
|
||||
_parentAttribute = anAttribute;
|
||||
_themeDefaultAttribute = anAttribute;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
@@ -579,7 +591,8 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_cache = {};
|
||||
|
||||
_name = [aCoder decodeObjectForKey:@"name"];
|
||||
_values = [CPDictionary dictionary];
|
||||
_defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
|
||||
_values = @{};
|
||||
|
||||
if ([aCoder containsValueForKey:@"value"])
|
||||
{
|
||||
@@ -611,6 +624,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_name forKey:@"name"];
|
||||
[aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
|
||||
|
||||
var keys = [_values allKeys],
|
||||
count = keys.length;
|
||||
@@ -626,7 +640,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
}
|
||||
else
|
||||
{
|
||||
var encodedValues = [CPDictionary dictionary];
|
||||
var encodedValues = @{};
|
||||
|
||||
while (count--)
|
||||
{
|
||||
@@ -666,7 +680,7 @@ var numberOfOnes = function(aNumber)
|
||||
cachedNumberOfOnes[slot] = count;
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
numberOfOnes.displayName = "numberOfOnes";
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
@implementation CPThemeBlend : CPObject
|
||||
{
|
||||
CPBundle _bundle;
|
||||
CPBundle _bundle @accessors(getter=bundle);
|
||||
CPArray _themes;
|
||||
id _loadDelegate;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user