mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-09 12:17:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
929cd78bae | ||
|
|
f5961b9e06 | ||
|
|
7fb17e9f41 | ||
|
|
dd70bdc698 | ||
|
|
59d619d190 | ||
|
|
dd160d6bed | ||
|
|
ae5a2c4164 | ||
|
|
a939bed8e0 | ||
|
|
c686a4384b | ||
|
|
6bb2dd2a16 | ||
|
|
2ec574173a | ||
|
|
743feb5360 | ||
|
|
bc4dc041e5 | ||
|
|
8c8d1ae3d3 | ||
|
|
a9781016be | ||
|
|
4be0bb3a30 | ||
|
|
a74267e937 | ||
|
|
6dea853ef3 | ||
|
|
94df530580 | ||
|
|
d038c50531 | ||
|
|
83546d58db | ||
|
|
8de587d4fc | ||
|
|
bd9a6ea150 | ||
|
|
fe69142567 | ||
|
|
fa0a4d3b56 | ||
|
|
5f85f7bef1 | ||
|
|
0a9c9741e8 | ||
|
|
2a3b9e13c3 | ||
|
|
4e07c9f9ee | ||
|
|
397e314cc9 | ||
|
|
c87d96676c | ||
|
|
9f2804c700 | ||
|
|
16183cca09 | ||
|
|
0af3b2f97c | ||
|
|
065227a467 | ||
|
|
753257a650 | ||
|
|
671666e842 | ||
|
|
b9ba1bbe93 | ||
|
|
33e4fea0ec | ||
|
|
13d4e36d39 | ||
|
|
a5c06c8f27 | ||
|
|
76bdbb660e | ||
|
|
a7929e6c1e | ||
|
|
2887d4224c | ||
|
|
7a52805587 | ||
|
|
56d0ebe420 | ||
|
|
b4b54e5744 | ||
|
|
8a9d997b44 | ||
|
|
e1f55fce3a | ||
|
|
6f6ce40c06 | ||
|
|
e32b302c59 | ||
|
|
302e753ebc | ||
|
|
1c007461bd | ||
|
|
3d1638c780 | ||
|
|
c5965c41d5 | ||
|
|
7cc6fa348c | ||
|
|
1e6bca2214 | ||
|
|
d199bd86e6 | ||
|
|
6338b01cb4 | ||
|
|
7714bcc34c | ||
|
|
e6f029c1fa | ||
|
|
fe606e4757 | ||
|
|
a6ee37e030 | ||
|
|
71364c9b1a | ||
|
|
a34155da61 | ||
|
|
2b8fa11b84 | ||
|
|
8fdcbac2bd | ||
|
|
4316192b8d | ||
|
|
19090de380 | ||
|
|
85c5094c8b | ||
|
|
ed8811e66b | ||
|
|
b2e13919e0 | ||
|
|
b4dabb6c35 | ||
|
|
e9d0be1b6a | ||
|
|
3f2607c2d0 | ||
|
|
ceaea9c5b0 | ||
|
|
5419272e48 | ||
|
|
888fc89f86 | ||
|
|
66c644641c | ||
|
|
669c6d4ac0 | ||
|
|
8ed06169d1 | ||
|
|
cf04fcc9d0 | ||
|
|
2e5081b137 | ||
|
|
a1a06c3f75 | ||
|
|
e4950bd831 | ||
|
|
607f681780 | ||
|
|
6eb4bf6656 | ||
|
|
b3cbc7e362 | ||
|
|
d6b3efaae8 | ||
|
|
9b3926cada | ||
|
|
815e64356d | ||
|
|
249a63af95 | ||
|
|
8520247605 | ||
|
|
33345f65ce | ||
|
|
686bce00d9 | ||
|
|
8ae94c2745 | ||
|
|
8feb5b5cee | ||
|
|
2b52f7d8da | ||
|
|
ea660e3dd4 | ||
|
|
ca1a1b43f1 | ||
|
|
3fe5ec5d6d | ||
|
|
142b982577 | ||
|
|
6c6ac4bd2e | ||
|
|
59e5689d1a | ||
|
|
147c65b962 | ||
|
|
7194a6961a | ||
|
|
e404217e8b | ||
|
|
f419629ce4 | ||
|
|
35f958f1a7 | ||
|
|
89dbccd74e | ||
|
|
a4647f2b82 | ||
|
|
94336ebcbb | ||
|
|
64f9309994 | ||
|
|
1c201d7dba | ||
|
|
e1cd4d0f6e | ||
|
|
8fcbf3ce0c | ||
|
|
915867e296 | ||
|
|
ac24b9ee68 | ||
|
|
aa7345935d | ||
|
|
5dfa43ce5f | ||
|
|
3937e66e06 | ||
|
|
ff7774976e | ||
|
|
634fa7b850 | ||
|
|
a435e54a67 | ||
|
|
f132ec5a50 | ||
|
|
852597f11d | ||
|
|
896f91215e | ||
|
|
806fea9222 | ||
|
|
b3d3f742f1 | ||
|
|
bf516b5fc5 | ||
|
|
4ab69ebb68 | ||
|
|
5a7c38d6eb | ||
|
|
972bb4100f | ||
|
|
6d962bc51a | ||
|
|
6a6b83635f | ||
|
|
e8a38e0bc0 | ||
|
|
800e32edad | ||
|
|
d8f202fc1f | ||
|
|
4acb757aec | ||
|
|
9708985901 | ||
|
|
27a1c5e9a4 | ||
|
|
d7ef31c4f5 | ||
|
|
2322743252 | ||
|
|
8b3f9c5557 | ||
|
|
fde18bba2e | ||
|
|
f7a2a2e6fd | ||
|
|
fb07e2ae06 | ||
|
|
f414ed2e8d | ||
|
|
86f3cc1831 | ||
|
|
e77c706c38 | ||
|
|
8bdb0f6215 | ||
|
|
ec5c0e361d | ||
|
|
533dbbfc69 | ||
|
|
0e04f7cae3 | ||
|
|
e4c708efde | ||
|
|
28bd18fab6 | ||
|
|
c9faea8753 | ||
|
|
b573daf59b | ||
|
|
24c5b5f6c9 | ||
|
|
868201b492 | ||
|
|
8db94c0849 | ||
|
|
f8984ced97 | ||
|
|
7539b5b06d | ||
|
|
4ae47ed7c4 | ||
|
|
23cc507b12 | ||
|
|
e9cfc806b6 | ||
|
|
5994c48d5f | ||
|
|
bba0de3306 | ||
|
|
55937daa20 | ||
|
|
fe53f2503b | ||
|
|
9058857403 | ||
|
|
c7517d81c7 | ||
|
|
b8f46565ef | ||
|
|
10940ace13 | ||
|
|
c57842d125 | ||
|
|
bb3ed30b4e | ||
|
|
4f8fa778d5 | ||
|
|
1b1bd039c9 | ||
|
|
3fe907f007 | ||
|
|
c784a2a1ca | ||
|
|
d4d01d9686 | ||
|
|
7ca8d0fb01 | ||
|
|
b985081184 | ||
|
|
30d5a7f7a2 | ||
|
|
02f61fa413 | ||
|
|
b01a4436b6 | ||
|
|
1a8808a4fd | ||
|
|
be5bbdcb32 | ||
|
|
9ad8f75a08 | ||
|
|
1e9798eead | ||
|
|
3242e35250 | ||
|
|
2bf9afa97a | ||
|
|
9e892d4eea | ||
|
|
864c4495c3 | ||
|
|
1c0f679f50 | ||
|
|
71763d041b | ||
|
|
345d48e224 | ||
|
|
bb97c107c9 | ||
|
|
37cad2f59a | ||
|
|
4ccbd592b2 | ||
|
|
8f5fe55dea | ||
|
|
a51a051cee | ||
|
|
abd32f5abc | ||
|
|
d869350a56 | ||
|
|
a3cd47b57c | ||
|
|
d2407d1c2a | ||
|
|
17dc96ad2f | ||
|
|
019acb76a3 | ||
|
|
4509df3c2a | ||
|
|
7059dd63b7 | ||
|
|
402c82801b | ||
|
|
b84d721887 | ||
|
|
48ccbb8883 | ||
|
|
23a5b83ea6 | ||
|
|
b3a427ba18 | ||
|
|
4cdefcc2c7 | ||
|
|
5a2e5a7de3 | ||
|
|
b7c0dcf050 | ||
|
|
3db05c94ab | ||
|
|
1ba69aee91 | ||
|
|
fe9573e5b8 | ||
|
|
9fcf0258e0 | ||
|
|
ea958160dc | ||
|
|
e22faa0d79 | ||
|
|
3d614b38c1 | ||
|
|
d51921d4f3 | ||
|
|
eb8d9775aa | ||
|
|
d5a0469333 | ||
|
|
d5f281320f | ||
|
|
1e49072763 | ||
|
|
d6c7fecf64 | ||
|
|
1392714896 | ||
|
|
2563cb5dc1 | ||
|
|
c42295f0c7 | ||
|
|
cc9bcabf38 | ||
|
|
6d98583fa6 | ||
|
|
6f869cebc1 | ||
|
|
175b204bb6 | ||
|
|
b126b2946d | ||
|
|
fec200c835 | ||
|
|
5c10615c9f | ||
|
|
ea0a47a845 | ||
|
|
835d89774a | ||
|
|
f0a2a91837 | ||
|
|
8614bab724 | ||
|
|
9c181cc9c9 | ||
|
|
1a842b2a6f | ||
|
|
9842640474 | ||
|
|
1b1bd4f972 | ||
|
|
d8a09722c6 | ||
|
|
21a50b990f | ||
|
|
739c844b10 | ||
|
|
a0a7b126ab | ||
|
|
cd05d30f86 | ||
|
|
3012cc7c92 | ||
|
|
78ddc2db70 | ||
|
|
a9fe07f854 | ||
|
|
0f88207d7b | ||
|
|
81ffed3b9b | ||
|
|
ead6e4a592 | ||
|
|
288c3e9c70 | ||
|
|
5a580f4983 | ||
|
|
9cf664fe7b | ||
|
|
10ec8b528c | ||
|
|
3ddf6031fb | ||
|
|
0ee304058d | ||
|
|
03e7d81ffa | ||
|
|
afb2352a7c | ||
|
|
cde179786c | ||
|
|
1b3792a1cc | ||
|
|
3d8b836184 | ||
|
|
08d33f3c1f | ||
|
|
7d1b873beb | ||
|
|
6c12442870 | ||
|
|
6a4d8a24be | ||
|
|
d147e9cbaa | ||
|
|
7480f02c22 | ||
|
|
26afe7c0d8 | ||
|
|
c537541825 | ||
|
|
e248433ec0 | ||
|
|
63e63ce7a1 | ||
|
|
6e6011c5ea | ||
|
|
4ce8dcef12 | ||
|
|
7ee414d0b8 | ||
|
|
2c8972514f | ||
|
|
05b0abacd4 | ||
|
|
5315095182 | ||
|
|
321c11ec9f | ||
|
|
ca53e56c19 | ||
|
|
dcf1d324a5 | ||
|
|
27211db0cc | ||
|
|
2743fe4c0d | ||
|
|
dc5d8f5fd3 | ||
|
|
be96e3037d | ||
|
|
b249a1db13 | ||
|
|
f001b7f2d3 | ||
|
|
561d22168a | ||
|
|
da2c360446 | ||
|
|
8027ebbe02 | ||
|
|
71d8582f94 | ||
|
|
f8674b6d87 | ||
|
|
a086e2fa71 | ||
|
|
592328f604 | ||
|
|
089372be4b | ||
|
|
ba3a2a9f89 | ||
|
|
8e3c26c313 | ||
|
|
dc264231c8 | ||
|
|
86e3717222 | ||
|
|
c4fb9ccc17 | ||
|
|
041f2ecf4d | ||
|
|
1db9b6a9d8 | ||
|
|
3b6bd5a292 | ||
|
|
51d8fd512a | ||
|
|
a578d4881d | ||
|
|
2fb58d3ae1 | ||
|
|
35bbb1a3d5 | ||
|
|
d5355df61c | ||
|
|
222223b847 | ||
|
|
9e03df7416 | ||
|
|
26d124d54b | ||
|
|
635a0d965c | ||
|
|
c891418849 | ||
|
|
39459c9a44 | ||
|
|
8661625dac | ||
|
|
38db22db06 | ||
|
|
722ffeda88 | ||
|
|
ca74f32e3b | ||
|
|
a837b26ac3 | ||
|
|
3b9ed4c1b5 | ||
|
|
77b5f0475d | ||
|
|
1c5d311ec2 | ||
|
|
7d3768e13d | ||
|
|
e6acc7a7d8 | ||
|
|
7099acde2f | ||
|
|
96e3c4db68 | ||
|
|
3b35703c2b | ||
|
|
1a0b69c10b | ||
|
|
5564b75ed0 | ||
|
|
27cf82e1d3 | ||
|
|
025e761929 | ||
|
|
1a99ac7681 | ||
|
|
1ecbe997df | ||
|
|
1d28b120dc | ||
|
|
97289d9070 | ||
|
|
a303b3c04f | ||
|
|
c317274a26 | ||
|
|
547e57c014 | ||
|
|
5a1a7f2c86 | ||
|
|
fb866699e5 | ||
|
|
cf487ba4de | ||
|
|
f79203f5d5 | ||
|
|
d7fe42387c | ||
|
|
ff7f469f9f | ||
|
|
e44ffdc7f4 | ||
|
|
91ef6bf925 | ||
|
|
a33dd51d8e | ||
|
|
2166fc1d51 | ||
|
|
b29e722132 | ||
|
|
06122bba19 | ||
|
|
b40f920ec6 | ||
|
|
e327c39776 | ||
|
|
c7a1717ebe | ||
|
|
b9533386b4 | ||
|
|
69d27364d5 | ||
|
|
e3abd4e407 | ||
|
|
2f501ad736 | ||
|
|
ae5359f953 | ||
|
|
4a57f6a1c4 | ||
|
|
9b1eac1923 | ||
|
|
875dbaa78f | ||
|
|
6b64291690 | ||
|
|
52ce4c1ebf | ||
|
|
a7161e3ca7 | ||
|
|
73746e00b0 | ||
|
|
327d796653 | ||
|
|
af6d38fd16 | ||
|
|
ab105e7273 | ||
|
|
6115acea05 | ||
|
|
0d8bd95c86 | ||
|
|
40bfb55b64 | ||
|
|
f0bba44e45 | ||
|
|
7107adfe16 | ||
|
|
501c15775e | ||
|
|
f29dcc9c6b | ||
|
|
370960418f | ||
|
|
c9fb862ee2 | ||
|
|
6e1acf1f06 | ||
|
|
2952070698 | ||
|
|
dbb10f69f6 | ||
|
|
9fc10260fb | ||
|
|
2fbd54521d | ||
|
|
ae3780c0cf | ||
|
|
ccf9225773 | ||
|
|
8aaa5fe07f | ||
|
|
fa1a10730e | ||
|
|
e91bc3eeef | ||
|
|
76400ecca9 | ||
|
|
9a0cf2b37d | ||
|
|
dae36cda56 | ||
|
|
e07ff706ab | ||
|
|
7ec31a7c53 | ||
|
|
b4221aebcb | ||
|
|
fdcd56e0ae | ||
|
|
2532c760ea | ||
|
|
0f68fa0141 | ||
|
|
26fba1fdd9 | ||
|
|
16bacae7e3 | ||
|
|
d00a8b9d18 | ||
|
|
094b798765 | ||
|
|
89974796b1 | ||
|
|
90c19b1856 | ||
|
|
044a605e47 | ||
|
|
7d62b6e1eb | ||
|
|
93f36a2326 | ||
|
|
0218246678 | ||
|
|
79fde3fbeb | ||
|
|
539ea2e589 | ||
|
|
4f6d939634 | ||
|
|
d68d84cfdf | ||
|
|
1ef7fc45f5 | ||
|
|
430a74735b | ||
|
|
de08addfa1 | ||
|
|
26003365bc | ||
|
|
11ab9a77ad | ||
|
|
e80cbc89b2 | ||
|
|
52f3f81265 | ||
|
|
2599f820c7 | ||
|
|
8fed2c7a9a | ||
|
|
f9f03c8b54 | ||
|
|
110d75b1e5 | ||
|
|
79ec12e2a2 | ||
|
|
5133a7dc91 | ||
|
|
425401c049 | ||
|
|
38f896d018 | ||
|
|
7b3ae56031 | ||
|
|
4418b2403f | ||
|
|
c0f5ed1f87 | ||
|
|
42c60913c6 | ||
|
|
51a8975f0a | ||
|
|
65ce93ce42 | ||
|
|
651882b3c8 | ||
|
|
ac7ff24dd7 | ||
|
|
b54ea6e8ac | ||
|
|
cf6d7f2d85 | ||
|
|
65043c5d78 | ||
|
|
30484e04b9 | ||
|
|
4decc6d9c7 | ||
|
|
1a5b8f5210 | ||
|
|
93119233cd | ||
|
|
2f56f899cf | ||
|
|
b69c25bc2a | ||
|
|
bdcf84ec15 | ||
|
|
f1f78d6c6a | ||
|
|
83e4e7ecce | ||
|
|
e6eb14e819 | ||
|
|
380a860ba9 | ||
|
|
5cbbafdf72 | ||
|
|
863c4639cf | ||
|
|
79e977b2d9 | ||
|
|
93fe320e22 | ||
|
|
0337744c05 | ||
|
|
43f4ecc1b4 | ||
|
|
310d49c74c | ||
|
|
3bd2c2d266 | ||
|
|
b9d2927368 | ||
|
|
8737b1207f | ||
|
|
7b6713aa90 | ||
|
|
ea25d22628 | ||
|
|
d54db1d52b | ||
|
|
9746e3d554 | ||
|
|
6afc5faab0 | ||
|
|
2899389561 | ||
|
|
a1e9322d69 | ||
|
|
da0558f09c | ||
|
|
8879ef99c6 | ||
|
|
09d515e6cc | ||
|
|
014354432a | ||
|
|
d9b327db83 | ||
|
|
da0b0d6c84 | ||
|
|
3f271463e5 | ||
|
|
459240bb88 | ||
|
|
e8210f7dde | ||
|
|
32fc629c33 | ||
|
|
d5b2ccbc30 | ||
|
|
a3e70a56c5 | ||
|
|
abce41d6fd | ||
|
|
e1d45fd385 | ||
|
|
a3e6105a11 | ||
|
|
f022386502 | ||
|
|
e18b21ec1b | ||
|
|
42c71172f2 | ||
|
|
dc801a11c8 | ||
|
|
24fbf27880 | ||
|
|
b0af42e236 | ||
|
|
32fd03b4a0 | ||
|
|
6b72651a05 | ||
|
|
d6117b832f | ||
|
|
3a79e82ce8 | ||
|
|
522d4dcb2b | ||
|
|
11f92353c8 | ||
|
|
3b60714bf0 | ||
|
|
239b6ed79d | ||
|
|
a20b0a7dca | ||
|
|
e9dba10903 | ||
|
|
fd43a08fa3 | ||
|
|
627566465e | ||
|
|
b087757a72 | ||
|
|
d926ad6221 | ||
|
|
90e6c21c95 | ||
|
|
ad4d408f3e | ||
|
|
9a2d079bee | ||
|
|
f254122346 | ||
|
|
10bfeaf8f7 | ||
|
|
f93aa2c5bc | ||
|
|
acf7ef3a96 | ||
|
|
a8d07961c0 | ||
|
|
95cc88733c | ||
|
|
120c06fcb2 | ||
|
|
d303e6e96c | ||
|
|
c4dce38484 | ||
|
|
8eb8b7711d | ||
|
|
f7fc669216 | ||
|
|
7d6b7fd676 | ||
|
|
2387cee799 | ||
|
|
e214d49ea9 | ||
|
|
6f8d2190f5 | ||
|
|
9ca1865179 | ||
|
|
a7c5ca740a | ||
|
|
590b3705eb | ||
|
|
a9f23fe082 | ||
|
|
3c77d43e03 | ||
|
|
7fb78fe157 | ||
|
|
566fdf6400 | ||
|
|
1dc53ed149 | ||
|
|
b57b705b1d | ||
|
|
7d7c037682 | ||
|
|
bf72a7f92d | ||
|
|
df9387fc78 | ||
|
|
9296df89df | ||
|
|
d4d65ed4d7 | ||
|
|
163550c3d5 | ||
|
|
a11f12ab09 | ||
|
|
8e14d6cebc | ||
|
|
90d50bb593 | ||
|
|
b715fb6182 | ||
|
|
31dbd208f4 | ||
|
|
49707af1ba | ||
|
|
b77668dd5a | ||
|
|
50e5fa2c8e | ||
|
|
dedf3cd90f | ||
|
|
651d6a7ed8 | ||
|
|
383dcd5ee6 | ||
|
|
1589d501cc | ||
|
|
060563b748 | ||
|
|
b8b74f1e35 | ||
|
|
6435372fd9 | ||
|
|
3ebb432d3f | ||
|
|
f13362b224 | ||
|
|
2b498feb67 | ||
|
|
5c6fce4e8c | ||
|
|
d000e67fc4 | ||
|
|
c9bc6c3991 | ||
|
|
8c1a3a3bba | ||
|
|
f723318601 | ||
|
|
ebcbfc76b8 | ||
|
|
eaa4efc805 | ||
|
|
e717fd82b9 | ||
|
|
46781cb6fd | ||
|
|
02eaded719 | ||
|
|
0748190ab7 | ||
|
|
cccbb8eee4 | ||
|
|
902878756e | ||
|
|
033663f2cf | ||
|
|
e4093ac3ae | ||
|
|
b7f871e31b | ||
|
|
cc5e8c3f34 | ||
|
|
85e80a62a3 | ||
|
|
60d1073d9a | ||
|
|
b620de45a2 | ||
|
|
536d012105 | ||
|
|
2e24761a54 | ||
|
|
956b640339 | ||
|
|
bee1db8c7d | ||
|
|
51deaf4552 | ||
|
|
57e1431e1a | ||
|
|
975e11abfc | ||
|
|
09ebc0effd | ||
|
|
6a4e0bd43a | ||
|
|
8994f08cbf | ||
|
|
55b97a7eeb | ||
|
|
436f6cb8ea | ||
|
|
9c4fb2c18c | ||
|
|
d27544f2bf | ||
|
|
85f51d7a66 | ||
|
|
3a6f2c4d5b | ||
|
|
f39441e101 | ||
|
|
a801860f90 | ||
|
|
41d757e0c4 | ||
|
|
602a2c47c2 | ||
|
|
3cfbca5a19 | ||
|
|
2cc6c54fbf | ||
|
|
e62fd3cf40 | ||
|
|
8cc61cccfd | ||
|
|
0802b80c35 | ||
|
|
8de508381a | ||
|
|
086fa29d78 |
@@ -5,3 +5,8 @@ Demos
|
||||
./Aristo
|
||||
WebSite
|
||||
.push-package
|
||||
*.xcodeproj/*.pbxuser
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
target
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@@ -59,6 +60,7 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPKeyBinding.j"
|
||||
@import "CPLevelIndicator.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPOpenPanel.j"
|
||||
@@ -66,9 +68,12 @@
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPPredicateEditor.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
@import "CPProgressIndicator.j"
|
||||
@import "CPRadio.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPRuleEditor.j"
|
||||
@import "CPScroller.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPSearchField.j"
|
||||
@@ -87,7 +92,9 @@
|
||||
@import "CPTokenField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "_CPToolTip.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPUserDefaultsController.j"
|
||||
@import "CPView.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@import "CPViewController.j"
|
||||
|
||||
+47
-16
@@ -107,7 +107,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
CPArray _themeBlends @accessors(property=themeBlends);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -141,6 +141,8 @@ CPRunContinuesResponse = -1002;
|
||||
_windows = [];
|
||||
|
||||
[_windows addObject:nil];
|
||||
|
||||
_themeBlends = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -338,7 +340,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>
|
||||
@@ -1003,7 +1005,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
/*!
|
||||
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:
|
||||
@@ -1156,6 +1158,16 @@ CPRunContinuesResponse = -1002;
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (CPThemeBlend)themeBlend
|
||||
{
|
||||
return (_themeBlends.length > 0 ? _themeBlends[0] : nil);
|
||||
}
|
||||
|
||||
- (void)setThemeBlend:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
_themeBlends[0] = aThemeBlend;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
@@ -1218,15 +1230,14 @@ function CPApplicationMain(args, namedArgs)
|
||||
[_CPAppBootstrapper performActions];
|
||||
}
|
||||
|
||||
var _CPAppBootstrapperActions = nil;
|
||||
var _CPAppBootstrapperActions = nil,
|
||||
_CPAppThemeURLsToLoad = [];
|
||||
|
||||
@implementation _CPAppBootstrapper : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPArray)actions
|
||||
{
|
||||
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||
return [@selector(bootstrapPlatform), @selector(loadThemes), @selector(loadMainCibFile)];
|
||||
}
|
||||
|
||||
+ (void)performActions
|
||||
@@ -1250,17 +1261,30 @@ var _CPAppBootstrapperActions = nil;
|
||||
return [CPPlatform bootstrap];
|
||||
}
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
+ (BOOL)loadThemes
|
||||
{
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
_CPAppThemeURLsToLoad.push([CPApplication defaultThemeName]);
|
||||
|
||||
if (defaultThemeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
var auxiliaryThemes = ([[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPAuxiliaryThemes"] || []);
|
||||
|
||||
_CPAppThemeURLsToLoad = _CPAppThemeURLsToLoad.concat(auxiliaryThemes);
|
||||
|
||||
[self loadNextTheme];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)loadNextTheme
|
||||
{
|
||||
var themeName = _CPAppThemeURLsToLoad.shift();
|
||||
|
||||
if (themeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:themeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:themeName + @".blend"];
|
||||
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1268,10 +1292,17 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
var themeBlends = [CPApp themeBlends];
|
||||
|
||||
[self performActions];
|
||||
[themeBlends addObject:aThemeBlend];
|
||||
|
||||
if ([themeBlends count] === 1)
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
if (_CPAppThemeURLsToLoad.length === 0)
|
||||
[self performActions];
|
||||
else
|
||||
[self loadNextTheme];
|
||||
}
|
||||
|
||||
+ (BOOL)loadMainCibFile
|
||||
|
||||
+97
-14
@@ -50,6 +50,8 @@
|
||||
CPArray _sortDescriptors;
|
||||
CPPredicate _filterPredicate;
|
||||
CPArray _arrangedObjects;
|
||||
|
||||
BOOL _disableSetContent;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
@@ -68,7 +70,8 @@
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
||||
{
|
||||
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
|
||||
// Also depends on "filterPredicate" but we'll handle that manually.
|
||||
return [CPSet setWithObjects:"content", "sortDescriptors"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelection
|
||||
@@ -136,7 +139,7 @@
|
||||
_sortDescriptors = [CPArray array];
|
||||
_filterPredicate = nil;
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
_arrangedObjects = nil;
|
||||
[self __setArrangedObjects:[CPArray array]];
|
||||
}
|
||||
|
||||
- (void)prepareContent
|
||||
@@ -273,6 +276,12 @@
|
||||
*/
|
||||
- (void)setContent:(id)value
|
||||
{
|
||||
// This is used to ignore expected setContent: calls caused by a binding to our content
|
||||
// object when we are the ones modifying the content object and can deal with the update
|
||||
// faster directly in the code in charge of the modification.
|
||||
if (_disableSetContent)
|
||||
return;
|
||||
|
||||
if (value === nil)
|
||||
value = [];
|
||||
|
||||
@@ -480,7 +489,14 @@
|
||||
*/
|
||||
- (void)setFilterPredicate:(CPPredicate)value
|
||||
{
|
||||
if (_filterPredicate === value)
|
||||
return;
|
||||
|
||||
// __setFilterPredicate will call _rearrangeObjects without
|
||||
// sending notifications, so we must send them instead.
|
||||
[self willChangeValueForKey:@"arrangedObjects"];
|
||||
[self __setFilterPredicate:value];
|
||||
[self didChangeValueForKey:@"arrangedObjects"];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -493,8 +509,7 @@
|
||||
return;
|
||||
|
||||
_filterPredicate = value;
|
||||
// Use the non-notification version since arrangedObjects already depends
|
||||
// on filterPredicate.
|
||||
// Use the non-notification version.
|
||||
[self _rearrangeObjects];
|
||||
}
|
||||
|
||||
@@ -704,17 +719,35 @@
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
var willClearPredicate = NO;
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
willClearPredicate = YES;
|
||||
}
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
If the content array is bound then our addObject: message below will cause the observed
|
||||
array to change. The binding will call setContent:_contentObject on this array
|
||||
controller to let it know about the change. We want to ignore that message since we
|
||||
A) already have the right _contentObject and B) properly update _arrangedObjects
|
||||
by hand below.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject addObject:object];
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self __setFilterPredicate:nil];
|
||||
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
if (willClearPredicate)
|
||||
{
|
||||
// Full rearrange needed due to changed filter.
|
||||
_filterPredicate = nil;
|
||||
[self _rearrangeObjects];
|
||||
}
|
||||
else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
// Insert directly into the array.
|
||||
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
|
||||
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
@@ -724,11 +757,16 @@
|
||||
else
|
||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
|
||||
}
|
||||
else
|
||||
[self _rearrangeObjects];
|
||||
/*
|
||||
else if (_filterPredicate !== nil)
|
||||
...
|
||||
// Implies _filterPredicate && ![_filterPredicate evaluateWithObject:object], so the new object does
|
||||
// not appear in arrangedObjects and we do not have to update at all.
|
||||
*/
|
||||
|
||||
// This will also send notificaitons for arrangedObjects.
|
||||
[self didChangeValueForKey:@"content"];
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
if (willClearPredicate)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
}
|
||||
|
||||
@@ -747,7 +785,13 @@
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject insertObject:anObject atIndex:anIndex];
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self __setFilterPredicate:nil];
|
||||
@@ -777,12 +821,18 @@
|
||||
- (void)removeObject:(id)object
|
||||
{
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject removeObject:object];
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
var pos = [_arrangedObjects indexOfObject:object];
|
||||
|
||||
[_arrangedObjects removeObjectAtIndex:pos];
|
||||
@@ -871,7 +921,13 @@
|
||||
- (void)_removeObjects:(CPArray)objects
|
||||
{
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject removeObjectsInArray:objects];
|
||||
_disableSetContent = NO;
|
||||
|
||||
var arrangedObjects = [self arrangedObjects],
|
||||
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
|
||||
@@ -910,6 +966,33 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPArrayController (CPBinder)
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
{
|
||||
if (theBinding == @"contentArray")
|
||||
return [_CPArrayControllerContentBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPArrayControllerContentBinder : CPBinder
|
||||
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination mutableArrayValueForKeyPath:keyPath];
|
||||
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
[_source setValue:newValue forKey:aBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoidsEmptySelection",
|
||||
CPArrayControllerClearsFilterPredicateOnInsertion = @"CPArrayControllerClearsFilterPredicateOnInsertion",
|
||||
CPArrayControllerFilterRestrictsInsertion = @"CPArrayControllerFilterRestrictsInsertion",
|
||||
|
||||
@@ -35,6 +35,12 @@ CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBox
|
||||
|
||||
A CPBox is a simple view which can display a border.
|
||||
*/
|
||||
@implementation CPBox : CPView
|
||||
{
|
||||
CPBoxType _boxType;
|
||||
@@ -89,16 +95,46 @@ CPGrooveBorder = 3;
|
||||
|
||||
// Configuring Boxes
|
||||
|
||||
/*!
|
||||
Returns the receiver's border rectangle.
|
||||
|
||||
@return the border rectangle of the box
|
||||
*/
|
||||
- (CPRect)borderRect
|
||||
{
|
||||
return [self bounds];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's border type. Possible values are:
|
||||
|
||||
<pre>
|
||||
CPNoBorder
|
||||
CPLineBorder
|
||||
CPBezelBorder
|
||||
CPGrooveBorder
|
||||
</pre>
|
||||
|
||||
@return the border type of the box
|
||||
*/
|
||||
- (CPBorderType)borderType
|
||||
{
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Sets the receiver's border type. Valid values are:
|
||||
|
||||
<pre>
|
||||
CPNoBorder
|
||||
CPLineBorder
|
||||
CPBezelBorder
|
||||
CPGrooveBorder
|
||||
</pre>
|
||||
|
||||
@param borderType the border type to use
|
||||
*/
|
||||
- (void)setBorderType:(CPBorderType)aBorderType
|
||||
{
|
||||
if (_borderType === aBorderType)
|
||||
@@ -108,11 +144,41 @@ CPGrooveBorder = 3;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's box type. Possible values are:
|
||||
|
||||
<pre>
|
||||
CPBoxPrimary
|
||||
CPBoxSecondary
|
||||
CPBoxSeparator
|
||||
CPBoxOldStyle
|
||||
CPBoxCustom
|
||||
</pre>
|
||||
|
||||
(In the current implementation, all values act the same except CPBoxSeparator.)
|
||||
|
||||
@return the box type of the box.
|
||||
*/
|
||||
- (CPBoxType)boxType
|
||||
{
|
||||
return _boxType;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's box type. Valid values are:
|
||||
|
||||
<pre>
|
||||
CPBoxPrimary
|
||||
CPBoxSecondary
|
||||
CPBoxSeparator
|
||||
CPBoxOldStyle
|
||||
CPBoxCustom
|
||||
</pre>
|
||||
|
||||
(In the current implementation, all values act the same except CPBoxSeparator.)
|
||||
|
||||
@param aBoxType the box type of the box.
|
||||
*/
|
||||
- (void)setBoxType:(CPBoxType)aBoxType
|
||||
{
|
||||
if (_boxType === aBoxType)
|
||||
|
||||
+5
-3
@@ -304,7 +304,7 @@
|
||||
tableHeight = CGRectGetHeight([tableView bounds]);
|
||||
|
||||
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
|
||||
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
|
||||
[[tableView tableColumnWithIdentifier:"Content"] setWidth:[self columnContentWidthForColumnWidth:width]];
|
||||
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
|
||||
|
||||
[tableView setRowHeight:_rowHeight];
|
||||
@@ -436,12 +436,14 @@
|
||||
|
||||
- (float)columnContentWidthForColumnWidth:(float)aWidth
|
||||
{
|
||||
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
|
||||
var columnSpacing = [_tableViews[0] intercellSpacing].width;
|
||||
return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [CPScroller scrollerWidth];
|
||||
}
|
||||
|
||||
- (float)columnWidthForColumnContentWidth:(float)aWidth
|
||||
{
|
||||
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
|
||||
var columnSpacing = [_tableViews[0] intercellSpacing].width;
|
||||
return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [CPScroller scrollerWidth];
|
||||
}
|
||||
|
||||
- (void)setImageWidth:(float)aWidth
|
||||
|
||||
+91
-16
@@ -106,6 +106,11 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
CPString _keyEquivalent;
|
||||
unsigned _keyEquivalentModifierMask;
|
||||
|
||||
CPTimer _continuousDelayTimer;
|
||||
CPTimer _continuousTimer;
|
||||
float _periodicDelay;
|
||||
float _periodicInterval;
|
||||
}
|
||||
|
||||
+ (id)buttonWithTitle:(CPString)aTitle
|
||||
@@ -152,18 +157,27 @@ CPButtonImageOffset = 3.0;
|
||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
||||
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
|
||||
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
_keyEquivalent = @"";
|
||||
_keyEquivalentModifierMask = 0;
|
||||
|
||||
[self setBezelStyle:CPRoundRectBezelStyle];
|
||||
[self setBordered:YES];
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
_keyEquivalent = @"";
|
||||
_keyEquivalentModifierMask = 0;
|
||||
|
||||
// Continuous button defaults.
|
||||
_periodicInterval = 0.05;
|
||||
_periodicDelay = 0.5;
|
||||
}
|
||||
|
||||
// Setting the state
|
||||
/*!
|
||||
Returns a Boolean value indicating whether the button allows a mixed state.
|
||||
@@ -450,6 +464,34 @@ CPButtonImageOffset = 3.0;
|
||||
return _imageDimsWhenDisabled;
|
||||
}
|
||||
|
||||
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
|
||||
{
|
||||
_periodicDelay = aDelay;
|
||||
_periodicInterval = anInterval;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([self isContinuous])
|
||||
{
|
||||
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
|
||||
{
|
||||
if (!_continuousTimer)
|
||||
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
|
||||
}
|
||||
|
||||
repeats:NO];
|
||||
}
|
||||
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)onContinousEvent:(CPTimer)aTimer
|
||||
{
|
||||
if (_target && _action && [_target respondsToSelector:_action])
|
||||
[_target performSelector:_action withObject:self];
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[self highlight:YES];
|
||||
@@ -460,6 +502,7 @@ CPButtonImageOffset = 3.0;
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self highlight:NO];
|
||||
[self invalidateTimers];
|
||||
|
||||
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
|
||||
|
||||
@@ -467,6 +510,21 @@ CPButtonImageOffset = 3.0;
|
||||
[self setNextState];
|
||||
}
|
||||
|
||||
- (void)invalidateTimers
|
||||
{
|
||||
if (_continuousTimer)
|
||||
{
|
||||
[_continuousTimer invalidate];
|
||||
_continuousTimer = nil;
|
||||
}
|
||||
|
||||
if (_continuousDelayTimer)
|
||||
{
|
||||
[_continuousDelayTimer invalidate];
|
||||
_continuousDelayTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
@@ -502,14 +560,9 @@ CPButtonImageOffset = 3.0;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/*!
|
||||
Adjust the size of the button to fit the title and surrounding button image.
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
- (CGSize)_minimumFrameSize
|
||||
{
|
||||
[self layoutSubviews];
|
||||
|
||||
var size,
|
||||
var size = CGSizeMakeZero(),
|
||||
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (contentView)
|
||||
@@ -533,9 +586,19 @@ CPButtonImageOffset = 3.0;
|
||||
if (maxSize.height >= 0.0)
|
||||
size.height = MIN(size.height, maxSize.height);
|
||||
|
||||
[self setFrameSize:size];
|
||||
return size;
|
||||
}
|
||||
|
||||
if (contentView)
|
||||
/*!
|
||||
Adjust the size of the button to fit the title and surrounding button image.
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
{
|
||||
[self layoutSubviews];
|
||||
|
||||
[self setFrameSize:[self _minimumFrameSize]];
|
||||
|
||||
if ([self ephemeralSubviewNamed:@"content-view"])
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
@@ -719,7 +782,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
|
||||
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
|
||||
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
|
||||
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
|
||||
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
|
||||
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
|
||||
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
|
||||
|
||||
@implementation CPButton (CPCoding)
|
||||
|
||||
@@ -733,7 +798,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
[self _init];
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
|
||||
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
|
||||
@@ -749,6 +814,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
|
||||
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
|
||||
_periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
|
||||
_periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
|
||||
|
||||
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
||||
|
||||
[self setNeedsLayout];
|
||||
@@ -765,6 +836,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[self invalidateTimers];
|
||||
|
||||
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
|
||||
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
|
||||
@@ -778,6 +850,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
|
||||
|
||||
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
|
||||
|
||||
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
|
||||
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -131,6 +131,49 @@
|
||||
|
||||
/*!
|
||||
Sets the item prototype to \c anItem
|
||||
|
||||
The item prototype should implement the CPCoding protocol
|
||||
because the item is copied by archiving and unarchiving the
|
||||
prototypal view.
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
@implement MyCustomView : CPCollectionViewItem
|
||||
{
|
||||
CPArray items @accessors;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
if (self)
|
||||
{
|
||||
items = [];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
items = [aCoder decodeObjectForKey:@"KEY"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:items forKey:@"KEY"];
|
||||
[super encodeWithCoder:aCoder];
|
||||
}
|
||||
|
||||
@end
|
||||
</pre>
|
||||
|
||||
This will allow the collection view to create multiple 'clean' copies
|
||||
of the item prototype which will maintain the original values for item
|
||||
and all of the properties archived by the super class.
|
||||
|
||||
@param anItem the new item prototype
|
||||
*/
|
||||
- (void)setItemPrototype:(CPCollectionViewItem)anItem
|
||||
@@ -343,7 +386,7 @@
|
||||
|
||||
_items = [];
|
||||
|
||||
if (!_itemPrototype || !_content)
|
||||
if (!_itemPrototype)
|
||||
return;
|
||||
|
||||
var index = 0;
|
||||
@@ -369,7 +412,7 @@
|
||||
{
|
||||
var width = CGRectGetWidth([self bounds]);
|
||||
|
||||
if (![_content count] || width == _tileWidth)
|
||||
if (width == _tileWidth)
|
||||
return;
|
||||
|
||||
// We try to fit as many views per row as possible. Any remaining space is then
|
||||
@@ -589,9 +632,7 @@
|
||||
_mouseDownEvent = anEvent;
|
||||
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
|
||||
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
|
||||
index = row * _numberOfColumns + column;
|
||||
index = [self _indexAtPoint:location];
|
||||
|
||||
if (index >= 0 && index < _items.length)
|
||||
{
|
||||
@@ -727,6 +768,28 @@
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPMenu)menuForEvent:(CPEvent)theEvent
|
||||
{
|
||||
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
|
||||
return [super menuForEvent:theEvent];
|
||||
|
||||
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
index = [self _indexAtPoint:location];
|
||||
|
||||
return [_delegate collectionView:self menuForItemAtIndex:index];
|
||||
}
|
||||
|
||||
- (int)_indexAtPoint:(CGPoint)thePoint
|
||||
{
|
||||
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
|
||||
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
|
||||
|
||||
return row * _numberOfColumns + column;
|
||||
}
|
||||
|
||||
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
return [_items objectAtIndex:anIndex];
|
||||
@@ -898,6 +961,21 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
||||
|
||||
@implementation CPCollectionView (CPCoding)
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
{
|
||||
var item = _itemPrototype;
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
_minItemSize = [[item view] frameSize];
|
||||
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
_maxItemSize = [[item view] frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
+114
-9
@@ -27,6 +27,7 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPImage.j"
|
||||
|
||||
/// @cond IGNORE
|
||||
|
||||
var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
@@ -54,6 +55,66 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for vertical patterns.
|
||||
*/
|
||||
CPColorPatternIsVertical = YES,
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for horizontal patterns.
|
||||
*/
|
||||
CPColorPatternIsHorizontal = NO;
|
||||
|
||||
/*!
|
||||
To create a simple color with a pattern image:
|
||||
|
||||
<code>CPColorWithImages(name, width, height{, bundle})</code>
|
||||
|
||||
To create a color with a three part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices{, orientation})</code>
|
||||
|
||||
where slices is an array of three [name, width, height{, bundle}] arrays,
|
||||
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
|
||||
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
|
||||
|
||||
To create a color with a nine part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices);</code>
|
||||
|
||||
where slices is an array of nine [name, width, height{, bundle}] arrays.
|
||||
*/
|
||||
function CPColorWithImages()
|
||||
{
|
||||
if (arguments.length < 3)
|
||||
{
|
||||
var slices = arguments[0],
|
||||
imageSlices = [];
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
|
||||
}
|
||||
|
||||
if (imageSlices.length === 3)
|
||||
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
|
||||
else
|
||||
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
|
||||
}
|
||||
else if (arguments.length === 3 || arguments.length === 4)
|
||||
{
|
||||
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -416,7 +477,7 @@ var cachedBlackColor,
|
||||
parseInt(parts[0], 10) / 255.0,
|
||||
parseInt(parts[1], 10) / 255.0,
|
||||
parseInt(parts[2], 10) / 255.0,
|
||||
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
||||
parts[3] ? parseFloat(parts[3], 10) : 1.0
|
||||
];
|
||||
|
||||
_cssString = aString;
|
||||
@@ -605,7 +666,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
*/
|
||||
- (CPString)hexString
|
||||
{
|
||||
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent])
|
||||
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent]);
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(CPColor)aColor
|
||||
@@ -616,12 +677,53 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
if (aColor === self)
|
||||
return YES;
|
||||
|
||||
return [aColor isKindOfClass:CPColor] && [aColor cssString] === [self cssString];
|
||||
if (![aColor isKindOfClass:CPColor])
|
||||
return NO;
|
||||
|
||||
if (_patternImage || [aColor patternImage])
|
||||
return [_patternImage isEqual:[aColor patternImage]];
|
||||
|
||||
// We don't require the components to be equal beyond 8 bits since otherwise
|
||||
// simple rounding errors will make two colours which are exactly the same on
|
||||
// screen compare unequal.
|
||||
return ROUND([self redComponent] * 255.0) == ROUND([aColor redComponent] * 255.0) &&
|
||||
ROUND([self greenComponent] * 255.0) == ROUND([aColor greenComponent] * 255.0) &&
|
||||
ROUND([self blueComponent] * 255.0) == ROUND([aColor blueComponent] * 255.0) &&
|
||||
[self alphaComponent] == [aColor alphaComponent];
|
||||
}
|
||||
|
||||
- (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];
|
||||
|
||||
description += imgDescription.replace(/^/mg, " ") + ",\n";
|
||||
}
|
||||
|
||||
description = description.substr(0, description.length - 2) + "\n ]\n}";
|
||||
}
|
||||
else
|
||||
description += [patternImage description].replace(/^/mg, " ") + "\n}";
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -666,8 +768,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)
|
||||
|
||||
@@ -698,13 +802,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)
|
||||
{
|
||||
@@ -742,3 +845,5 @@ var byteToHex = function(n)
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -131,7 +131,7 @@ CPColorPickerViewHeight = 370;
|
||||
[self setFloatingPanel:YES];
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
[self setMinSize:CGSizeMake(219.0, 342.0)];
|
||||
[self setMinSize:CGSizeMake(219.0, 363.0)];
|
||||
[self setMaxSize:CGSizeMake(323.0, 537.0)];
|
||||
}
|
||||
|
||||
@@ -372,6 +372,7 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
[_opacitySlider setMinValue:0.0];
|
||||
[_opacitySlider setMaxValue:1.0];
|
||||
[_opacitySlider setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[_opacitySlider setTarget:self];
|
||||
[_opacitySlider setAction:@selector(setOpacity:)];
|
||||
|
||||
+16
-12
@@ -44,16 +44,16 @@ CPHTMLCanvasFeature = 1 << 6;
|
||||
CPHTMLContentEditableFeature = 1 << 7;
|
||||
CPHTMLDragAndDropFeature = 1 << 8;
|
||||
|
||||
CPJavascriptInnerTextFeature = 1 << 9;
|
||||
CPJavascriptTextContentFeature = 1 << 10;
|
||||
CPJavascriptClipboardEventsFeature = 1 << 11;
|
||||
CPJavascriptClipboardAccessFeature = 1 << 12;
|
||||
CPJavaScriptInnerTextFeature = 1 << 9;
|
||||
CPJavaScriptTextContentFeature = 1 << 10;
|
||||
CPJavaScriptClipboardEventsFeature = 1 << 11;
|
||||
CPJavaScriptClipboardAccessFeature = 1 << 12;
|
||||
CPJavaScriptCanvasDrawFeature = 1 << 13;
|
||||
CPJavaScriptCanvasTransformFeature = 1 << 14;
|
||||
|
||||
CPVMLFeature = 1 << 15;
|
||||
|
||||
CPJavascriptRemedialKeySupport = 1 << 16;
|
||||
CPJavaScriptRemedialKeySupport = 1 << 16;
|
||||
CPJavaScriptShadowFeature = 1 << 20;
|
||||
|
||||
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
||||
@@ -65,6 +65,7 @@ CPOpacityRequiresFilterFeature = 1 << 24;
|
||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
||||
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
||||
|
||||
CPSOPDisabledFromFileURLs = 1 << 27;
|
||||
|
||||
var USER_AGENT = "",
|
||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||
@@ -92,7 +93,7 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
|
||||
|
||||
// Features we can only be sure of with IE (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPVMLFeature;
|
||||
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
|
||||
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
|
||||
@@ -112,8 +113,8 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
if (USER_AGENT.indexOf("Chrome") === -1)
|
||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
|
||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||
@@ -124,15 +125,18 @@ 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;
|
||||
|
||||
// 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;
|
||||
|
||||
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
|
||||
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
|
||||
|
||||
if (USER_AGENT.indexOf("Chrome") === CPNotFound)
|
||||
PLATFORM_FEATURES |= CPSOPDisabledFromFileURLs;
|
||||
}
|
||||
|
||||
// KHTML
|
||||
@@ -178,9 +182,9 @@ if (typeof document != "undefined")
|
||||
|
||||
// Detect whether we have innerText or textContent (or neither)
|
||||
if (DOMElement.innerText != undefined)
|
||||
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptInnerTextFeature;
|
||||
else if (DOMElement.textContent != undefined)
|
||||
PLATFORM_FEATURES |= CPJavascriptTextContentFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptTextContentFeature;
|
||||
}
|
||||
|
||||
function CPFeatureIsCompatible(aFeature)
|
||||
|
||||
+12
-31
@@ -25,7 +25,6 @@
|
||||
@import "CPView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
@@ -95,8 +94,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
BOOL _trackingWasWithinFrame;
|
||||
unsigned _trackingMouseDownFlags;
|
||||
CGPoint _previousTrackingLocation;
|
||||
|
||||
CPString _toolTip;
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
@@ -149,6 +146,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
}
|
||||
|
||||
/*!
|
||||
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
|
||||
*/
|
||||
- (void)_continuouslyReverseSetBinding
|
||||
{
|
||||
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
|
||||
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
|
||||
|
||||
if ([theBinding continuouslyUpdatesValue])
|
||||
[theBinding reverseSetValueFor:@"objectValue"];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
|
||||
@@ -227,34 +236,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return previousMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the tooltip for the receiver.
|
||||
|
||||
@param aToolTip the tooltip
|
||||
*/
|
||||
/*
|
||||
-(void)setToolTip:(CPString)aToolTip
|
||||
{
|
||||
if (_toolTip == aToolTip)
|
||||
return;
|
||||
|
||||
_toolTip = aToolTip;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.title = aToolTip;
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
/*!
|
||||
Returns the receiver's tooltip
|
||||
*/
|
||||
/*
|
||||
-(CPString)toolTip
|
||||
{
|
||||
return _toolTip;
|
||||
}
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns whether the control can continuously send its action messages.
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@ var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
|
||||
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
|
||||
}
|
||||
|
||||
return nil;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEditing
|
||||
|
||||
+174
-203
@@ -1,36 +1,41 @@
|
||||
/*
|
||||
Testing browsers:
|
||||
WebKit r50235 (Safari 4.0.3+)
|
||||
FireFox 3.5
|
||||
Opera 10.0.0
|
||||
|
||||
Implemented class methods:
|
||||
Webkit : All
|
||||
IE : All
|
||||
FireFox Win : All
|
||||
FireFox Mac : All except closedHandCursor disappearingItemCursor // Firefox mac does not support url cursors
|
||||
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
|
||||
Cursor support by browser:
|
||||
OS X 10.6/Chrome 8 : All
|
||||
OS X 10.6/Safari 5 : All
|
||||
OS X 10.6/Firefox 3 : All except disappearingItemCursor (no url() support)
|
||||
OS X 10.6/Firefox 3.5 : All except disappearingItemCursor (no url() support)
|
||||
OS X 10.6/Firefox 3.6 : All except disappearingItemCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
|
||||
OS X 10.6/Firefox 4.0b10 : All
|
||||
OS X/Opera 9 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
|
||||
OS X/Opera 10 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
|
||||
OS X/Opera 11 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
|
||||
Win XP/Chrome 8 : All
|
||||
Win XP/Safari 5 : All
|
||||
Win XP/Firefox 3 : All
|
||||
Win XP/Firefox 3.5 : All
|
||||
Win XP/Firefox 3.6 : All
|
||||
Win XP/Firefox 4.0b10 : All
|
||||
Win XP/Opera 10 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
|
||||
Win XP/Opera 11 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
|
||||
Win XP/IE 7 : All
|
||||
Win XP/IE 8 : All
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
var currentCursor = nil,
|
||||
cursorStack = [],
|
||||
cursors = {},
|
||||
cursorURLFormat = nil;
|
||||
cursors = {};
|
||||
|
||||
@implementation CPCursor : CPObject
|
||||
{
|
||||
CPString _cssString;
|
||||
CPString _cssString @accessors(readonly);
|
||||
CPString _hotSpot @accessors(readonly, getter=hotSpot);
|
||||
CPImage _image @accessors(readonly, getter=image);
|
||||
BOOL _isSetOnMouseEntered @accessors(readwrite, getter=isSetOnMouseEntered, setter=setOnMouseEntered:);
|
||||
BOOL _isSetOnMouseExited @accessors(readwrite, getter=isSetOnMouseExited, setter=setOnMouseExited:);
|
||||
}
|
||||
|
||||
+ (CPCursor)currentCursor
|
||||
{
|
||||
return currentCursor;
|
||||
}
|
||||
|
||||
- (id)initWithCSSString:(CPString)aString
|
||||
{
|
||||
if (self = [super init])
|
||||
@@ -39,155 +44,18 @@ var currentCursor = nil,
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (CPCursor)cursorWithCSSString:(CPString)cssString
|
||||
// hotspot is supported in CSS3 (but not IE).
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||
{
|
||||
var cursor = cursors[cssString];
|
||||
|
||||
if (typeof cursor == 'undefined')
|
||||
{
|
||||
cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||
cursors[cssString] = cursor;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
_hotSpot = hotSpot;
|
||||
_image = image;
|
||||
return [self initWithCSSString:"url(" + [_image filename] + ")" + hotSpot.x + " " + hotSpot.y + ", auto"];
|
||||
}
|
||||
|
||||
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
|
||||
// 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
|
||||
{
|
||||
if (!cursorURLFormat)
|
||||
{
|
||||
cursorURLFormat = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/%@.cur)";
|
||||
|
||||
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
cursorURLFormat += ", default";
|
||||
}
|
||||
|
||||
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
|
||||
|
||||
return [[CPCursor alloc] initWithCSSString:url];
|
||||
}
|
||||
|
||||
- (CPString)_cssString
|
||||
{
|
||||
return _cssString;
|
||||
}
|
||||
|
||||
+ (CPCursor)arrowCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"default"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)crosshairCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"crosshair"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)IBeamCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"text"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)pointingHandCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"pointer"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeDownCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"n-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"w-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeRightCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"e-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftRightCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"col-resize"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpDownCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"row-resize"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)operationNotAllowedCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"not-allowed"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)dragCopyCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"copy"]; // WebKit | FF
|
||||
}
|
||||
|
||||
+ (CPCursor)dragLinkCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"alias"]; // WebKit | FF
|
||||
}
|
||||
|
||||
+ (CPCursor)contextualMenuCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"context-menu"]; // WebKit | FF Mac . Not impl FF Win.
|
||||
}
|
||||
|
||||
+ (CPCursor)openHandCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-moz-grab"];
|
||||
else if (CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"move"];
|
||||
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
|
||||
}
|
||||
|
||||
+ (CPCursor)closedHandCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
|
||||
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF
|
||||
}
|
||||
|
||||
+ (CPCursor)disappearingItemCursor
|
||||
{
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // None
|
||||
return [self initWithImage:image hotSpot:hotSpot];
|
||||
}
|
||||
|
||||
+ (void)hide
|
||||
@@ -208,44 +76,6 @@ var currentCursor = nil,
|
||||
[CPCursor unhide];
|
||||
}
|
||||
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||
{
|
||||
return [self initWithCSSString:"url(" + [image filename] + "), auto"];
|
||||
}
|
||||
|
||||
|
||||
- (void)mouseEntered:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void)set
|
||||
{
|
||||
currentCursor = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[[self class] _setCursorCSS:_cssString];
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+ (void)_setCursorCSS:(CPString)aString
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
- (void)push
|
||||
{
|
||||
currentCursor = cursorStack.push(self);
|
||||
}
|
||||
|
||||
- (void)pop
|
||||
{
|
||||
[CPCursor pop];
|
||||
@@ -260,6 +90,148 @@ var currentCursor = nil,
|
||||
}
|
||||
}
|
||||
|
||||
- (void)push
|
||||
{
|
||||
currentCursor = cursorStack.push(self);
|
||||
}
|
||||
|
||||
- (void)set
|
||||
{
|
||||
currentCursor = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[[self class] _setCursorCSS:_cssString];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPCursor)currentCursor
|
||||
{
|
||||
return currentCursor;
|
||||
}
|
||||
|
||||
+ (void)_setCursorCSS:(CPString)aString
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
// Internal method that is used to return the system cursors. Caches the system cursors for performance.
|
||||
+ (CPCursor)_systemCursorWithName:(CPString)cursorName cssString:(CPString)aString hasImage:(BOOL)doesHaveImage
|
||||
{
|
||||
var cursor = cursors[cursorName];
|
||||
if (typeof cursor === 'undefined')
|
||||
{
|
||||
var cssString;
|
||||
if (doesHaveImage)
|
||||
cssString = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/" + cursorName + ".cur), " + 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];
|
||||
}
|
||||
|
||||
+ (CPCursor)crosshairCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)IBeamCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)pointingHandCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeDownCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeRightCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftRightCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpDownCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)operationNotAllowedCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed" hasImage:NO];
|
||||
}
|
||||
|
||||
+ (CPCursor)dragCopyCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy" hasImage:YES];
|
||||
}
|
||||
|
||||
+ (CPCursor)dragLinkCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias" hasImage:YES];
|
||||
}
|
||||
|
||||
+ (CPCursor)contextualMenuCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"context-menu" hasImage:YES];
|
||||
}
|
||||
|
||||
+ (CPCursor)openHandCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"move" hasImage:YES];
|
||||
}
|
||||
|
||||
+ (CPCursor)closedHandCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"-moz-grabbing" hasImage:YES];
|
||||
}
|
||||
|
||||
+ (CPCursor)disappearingItemCursor
|
||||
{
|
||||
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"auto" hasImage:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCursor(CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
if (self = [super init])
|
||||
@@ -274,4 +246,3 @@ var currentCursor = nil,
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+16
-12
@@ -44,8 +44,8 @@ var CPDragServerPreviousEvent = nil,
|
||||
|
||||
var CPSharedDragServer = nil;
|
||||
|
||||
var CPDragServerSource = nil;
|
||||
var CPDragServerDraggingInfo = nil;
|
||||
var CPDragServerSource = nil,
|
||||
CPDragServerDraggingInfo = nil;
|
||||
|
||||
/*
|
||||
CPDraggingInfo is a container of information about a specific dragging session.
|
||||
@@ -261,7 +261,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
{
|
||||
var contentView = [scrollView contentView],
|
||||
bounds = [contentView bounds],
|
||||
insetBounds = CGRectInset(bounds, 10, 10),
|
||||
insetBounds = CGRectInset(bounds, 30, 30),
|
||||
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
|
||||
deltaX = 0,
|
||||
deltaY = 0;
|
||||
@@ -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,21 @@ 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;
|
||||
}
|
||||
|
||||
[contentView scrollToPoint: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];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-31
@@ -281,16 +281,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
|
||||
}
|
||||
|
||||
- (id)_initWithType:(CPEventType)anEventType
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_type = anEventType;
|
||||
|
||||
// Make sure these are 0 rather than nil.
|
||||
_deltaX = 0;
|
||||
_deltaY = 0;
|
||||
_deltaZ = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_type = anEventType;
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
@@ -309,11 +321,8 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_type = anEventType;
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
@@ -333,11 +342,8 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_type = anEventType;
|
||||
_location = CPPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
@@ -565,29 +571,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
// Cocoa does not consider space, backspace, or escape a key equivalent
|
||||
// if the first responder is a text field (presumably a subclass of NSText).
|
||||
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
|
||||
|
||||
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 ||
|
||||
(!firstResponderIsText &&
|
||||
(c === CPSpaceFunctionKey ||
|
||||
c === CPDeleteCharacter ||
|
||||
c === CPBackspaceCharacter)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -645,4 +650,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,10 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
|
||||
}
|
||||
#endif
|
||||
_params = aDictionary;
|
||||
if (!_params)
|
||||
_params = aDictionary;
|
||||
else
|
||||
[_params addEntriesFromDictionary:aDictionary];
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
@@ -143,7 +146,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
var enumerator = [_params keyEnumerator],
|
||||
key;
|
||||
|
||||
while (key = [enumerator nextObject] && _DOMObjectElement)
|
||||
while (_DOMObjectElement && (key = [enumerator nextObject]))
|
||||
{
|
||||
var param = document.createElement(@"param");
|
||||
param.name = key;
|
||||
|
||||
+186
-29
@@ -25,20 +25,49 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
|
||||
CPFontDefaultSystemFontSize = 12;
|
||||
|
||||
var _CPFonts = {},
|
||||
_CPFontSystemFontFace = @"Arial, sans-serif",
|
||||
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
|
||||
var _CPFonts = {},
|
||||
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
|
||||
_CPFontSystemFontSize = 12,
|
||||
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
|
||||
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
|
||||
|
||||
|
||||
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
|
||||
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
|
||||
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
|
||||
|
||||
/*!
|
||||
@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:
|
||||
|
||||
- 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.
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
@code
|
||||
<key>CPSystemFontFace</key>
|
||||
<string>Lucida Grande</string>
|
||||
@endcode
|
||||
*/
|
||||
@implementation CPFont : CPObject
|
||||
{
|
||||
@@ -47,78 +76,153 @@ var _CPFonts = {},
|
||||
float _ascender;
|
||||
float _descender;
|
||||
float _lineHeight;
|
||||
BOOL _isBold;
|
||||
BOOL _isBold @accessors(readonly, getter=isBold);
|
||||
BOOL _isItalic @accessors(readonly, getter=isItalic);
|
||||
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
|
||||
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
||||
|
||||
if (systemFont)
|
||||
_CPFontSystemFontFace = systemFont;
|
||||
if (!systemFontFace)
|
||||
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
|
||||
|
||||
if (systemFontFace)
|
||||
[self setSystemFontFace:systemFontFace];
|
||||
|
||||
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
||||
|
||||
if (!systemFontSize)
|
||||
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
|
||||
|
||||
if (systemFontSize)
|
||||
_CPFontSystemFontSize = systemFontSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default system font face, which may consist of several comma-separated family names.
|
||||
*/
|
||||
+ (CPString)systemFontFace
|
||||
{
|
||||
return _CPFontSystemFontFace;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the default system font face, which may consist of several comma-separated family names.
|
||||
*/
|
||||
+ (CPString)setSystemFontFace:(CPString)aFace
|
||||
{
|
||||
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default system font size.
|
||||
*/
|
||||
+ (float)systemFontSize
|
||||
{
|
||||
return _CPFontSystemFontSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the default system font size.
|
||||
*/
|
||||
+ (float)setSystemFontSize:(float)size
|
||||
{
|
||||
if (size > 0)
|
||||
_CPFontSystemFontSize = size;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font with the specified name and size.
|
||||
@param aName the name of the font
|
||||
@param aSize the size of the font (in points)
|
||||
@param aSize the size of the font (in px)
|
||||
@return the requested font
|
||||
*/
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO];
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic: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 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];
|
||||
}
|
||||
|
||||
/*!
|
||||
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 points)
|
||||
@param aSize the size of the font (in px)
|
||||
@return the requested bold font
|
||||
*/
|
||||
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, YES) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES];
|
||||
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic: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 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];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the system font scaled to the specified size
|
||||
@param aSize the size of the font (in points)
|
||||
@param aSize the size of the font (in px)
|
||||
@return the requested system font
|
||||
*/
|
||||
+ (CPFont)systemFontOfSize:(CPSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO];
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the bold system font scaled to the specified size
|
||||
@param aSize the size of the font (in points)
|
||||
@param aSize the size of the font (in px)
|
||||
@return the requested bold system font
|
||||
*/
|
||||
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES];
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_name = _CPFontNormalizedNames(aName);
|
||||
_size = aSize;
|
||||
_ascender = 0;
|
||||
_descender = 0;
|
||||
_lineHeight = 0;
|
||||
_isBold = isBold;
|
||||
_isItalic = isItalic;
|
||||
|
||||
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
|
||||
|
||||
_CPFonts[_cssString] = self;
|
||||
}
|
||||
@@ -139,7 +243,7 @@ var _CPFonts = {},
|
||||
|
||||
/*!
|
||||
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
|
||||
Thus, if the longest descender extends 2 points below the baseline, descender will return –2.
|
||||
Thus, if the longest descender extends 2 px below the baseline, descender will return –2.
|
||||
*/
|
||||
- (float)descender
|
||||
{
|
||||
@@ -188,12 +292,17 @@ var _CPFonts = {},
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
|
||||
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
|
||||
return [CPString stringWithFormat:@"%@ %@", [super description], [self cssString]];
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
|
||||
}
|
||||
|
||||
- (void)_getMetrics
|
||||
@@ -207,9 +316,10 @@ var _CPFonts = {},
|
||||
|
||||
@end
|
||||
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
CPFontSizeKey = @"CPFontSizeKey",
|
||||
CPFontIsBoldKey = @"CPFontIsBoldKey";
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
CPFontSizeKey = @"CPFontSizeKey",
|
||||
CPFontIsBoldKey = @"CPFontIsBoldKey",
|
||||
CPFontIsItalicKey = @"CPFontIsItalicKey";
|
||||
|
||||
@implementation CPFont (CPCoding)
|
||||
|
||||
@@ -220,9 +330,12 @@ var CPFontNameKey = @"CPFontNameKey",
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
return [self _initWithName:[aCoder decodeObjectForKey:CPFontNameKey]
|
||||
size:[aCoder decodeFloatForKey:CPFontSizeKey]
|
||||
bold:[aCoder decodeBoolForKey:CPFontIsBoldKey]];
|
||||
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
|
||||
size = [aCoder decodeFloatForKey:CPFontSizeKey],
|
||||
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
|
||||
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
|
||||
|
||||
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -234,6 +347,50 @@ var CPFontNameKey = @"CPFontNameKey",
|
||||
[aCoder encodeObject:_name forKey:CPFontNameKey];
|
||||
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
|
||||
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
|
||||
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// aName must be normalized
|
||||
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
|
||||
{
|
||||
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
|
||||
|
||||
return properties + _CPFontConcatNameWithFallback(aName);
|
||||
};
|
||||
|
||||
var _CPFontConcatNameWithFallback = function(aName)
|
||||
{
|
||||
var names = _CPFontNormalizedNameArray(aName),
|
||||
fallbackFaces = _CPFontFallbackFaces.slice(0);
|
||||
|
||||
// Remove the fallback names used in the names passed in
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
{
|
||||
for (var j = 0; j < fallbackFaces.length; ++j)
|
||||
{
|
||||
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
|
||||
{
|
||||
fallbackFaces.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (names[i].indexOf(" ") > 0)
|
||||
names[i] = '"' + names[i] + '"';
|
||||
}
|
||||
|
||||
return names.concat(fallbackFaces).join(", ");
|
||||
};
|
||||
|
||||
var _CPFontNormalizedNameArray = function(aName)
|
||||
{
|
||||
var names = aName.split(",");
|
||||
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
names[i] = names[i].replace(_CPFontStripRegExp, "");
|
||||
|
||||
return names;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ var CPGraphicsContextCurrent = nil;
|
||||
*/
|
||||
@implementation CPGraphicsContext : CPObject
|
||||
{
|
||||
CPContext _graphicsPort;
|
||||
CGContext _graphicsPort;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+20
-1
@@ -44,7 +44,8 @@ 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);
|
||||
@@ -324,6 +325,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
|
||||
{
|
||||
|
||||
+16
-13
@@ -174,10 +174,6 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
|
||||
{
|
||||
var valueTransformerName,
|
||||
valueTransformer,
|
||||
placeholder;
|
||||
|
||||
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
|
||||
valueTransformer;
|
||||
|
||||
@@ -224,6 +220,12 @@ var CPBindingOperationAnd = 0,
|
||||
return aValue;
|
||||
}
|
||||
|
||||
- (BOOL)continuouslyUpdatesValue
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey];
|
||||
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPObject (KeyValueBindingCreation)
|
||||
@@ -430,16 +432,17 @@ CPOptionsKey = @"CPOptionsKey";
|
||||
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
|
||||
CPNoSelectionMarker = @"CPNoSelectionMarker";
|
||||
CPNotApplicableMarker = @"CPNotApplicableMarker";
|
||||
CPNullMarker = @"CPNullMarker";
|
||||
|
||||
// Binding name constants
|
||||
CPAlignmentBinding = @"CPAlignmentBinding";
|
||||
CPEditableBinding = @"CPEditableBinding";
|
||||
CPEnabledBinding = @"CPEnabledBinding";
|
||||
CPFontBinding = @"CPFontBinding";
|
||||
CPHiddenBinding = @"CPHiddenBinding";
|
||||
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
|
||||
CPTextColorBinding = @"CPTextColorBinding";
|
||||
CPToolTipBinding = @"CPToolTipBinding";
|
||||
CPAlignmentBinding = @"alignment";
|
||||
CPEditableBinding = @"editable";
|
||||
CPEnabledBinding = @"enabled";
|
||||
CPFontBinding = @"font";
|
||||
CPHiddenBinding = @"hidden";
|
||||
CPSelectedIndexBinding = @"selectedIndex";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
|
||||
//Binding options constants
|
||||
@@ -470,5 +473,5 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
|
||||
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* CPLevelIndicator.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2011, WireLoad 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"
|
||||
|
||||
CPTickMarkBelow = 0;
|
||||
CPTickMarkAbove = 1;
|
||||
CPTickMarkLeft = CPTickMarkAbove;
|
||||
CPTickMarkRight = CPTickMarkBelow;
|
||||
|
||||
CPRelevancyLevelIndicatorStyle = 0;
|
||||
CPContinuousCapacityLevelIndicatorStyle = 1;
|
||||
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
||||
CPRatingLevelIndicatorStyle = 3;
|
||||
|
||||
var _CPLevelIndicatorBezelColor = nil,
|
||||
_CPLevelIndicatorSegmentEmptyColor = nil,
|
||||
_CPLevelIndicatorSegmentNormalColor = nil,
|
||||
_CPLevelIndicatorSegmentWarningColor = nil,
|
||||
_CPLevelIndicatorSegmentCriticalColor = nil,
|
||||
|
||||
_CPLevelIndicatorSpacing = 1;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPLevelIndicator
|
||||
|
||||
CPLevelIndicator is a control which indicates a value visually on a scale.
|
||||
*/
|
||||
@implementation CPLevelIndicator : CPControl
|
||||
{
|
||||
CPLevelIndicator _levelIndicatorStyle @accessors(property=levelIndicatorStyle);
|
||||
double _minValue @accessors(property=minValue);
|
||||
double _maxValue @accessors(property=maxValue);
|
||||
double _warningValue @accessors(property=warningValue);
|
||||
double _criticalValue @accessors(property=criticalValue);
|
||||
CPTickMarkPosition _tickMarkPosition @accessors(property=tickMarkPosition);
|
||||
int _numberOfTickMarks @accessors(property=numberOfTickMarks);
|
||||
int _numberOfMajorTickMarks @accessors(property=numberOfMajorTickMarks);
|
||||
|
||||
BOOL _isEditable;
|
||||
|
||||
BOOL _isTracking;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
|
||||
|
||||
_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)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_levelIndicatorStyle = CPDiscreteCapacityLevelIndicatorStyle;
|
||||
_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];
|
||||
|
||||
var segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segmentCount <= 0)
|
||||
return;
|
||||
|
||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value < _criticalValue)
|
||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
||||
else if (value < _warningValue)
|
||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
{
|
||||
var segmentView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:bezelView];
|
||||
|
||||
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
// TODO Put into theme attributes.
|
||||
var bezelHeight = 18,
|
||||
segmentHeight = 17,
|
||||
bounds = _CGRectCreateCopy([self bounds]);
|
||||
|
||||
if (aViewName == "bezel")
|
||||
{
|
||||
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
|
||||
bounds.size.height = bezelHeight;
|
||||
return bounds;
|
||||
}
|
||||
else if (aViewName.indexOf("segment-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aViewName.substring("segment-bezel-".length), 10),
|
||||
segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segment >= segmentCount)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var basicSegmentWidth = bounds.size.width / segmentCount,
|
||||
segmentFrame = CGRectCreateCopy([self bounds]);
|
||||
|
||||
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.height = segmentHeight;
|
||||
|
||||
return segmentFrame;
|
||||
}
|
||||
|
||||
return _CGRectMakeZero();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether or not the receiver level indicator can be edited.
|
||||
*/
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
{
|
||||
if (_isEditable === shouldBeEditable)
|
||||
return;
|
||||
|
||||
_isEditable = shouldBeEditable;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c YES if the textfield is currently editable by the user.
|
||||
*/
|
||||
- (BOOL)isEditable
|
||||
{
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
return;
|
||||
|
||||
[self _trackMouse:anEvent];
|
||||
}
|
||||
|
||||
- (void)_trackMouse:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type == CPLeftMouseDown || type == CPLeftMouseDragged)
|
||||
{
|
||||
var segmentCount = _maxValue - _minValue;
|
||||
|
||||
if (segmentCount <= 0)
|
||||
return;
|
||||
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
bounds = [self bounds],
|
||||
oldValue = [self doubleValue];
|
||||
newValue = oldValue;
|
||||
|
||||
// Moving the mouse outside of the widget to the left sets it
|
||||
// to its minimum, and moving outside on the right sets it to
|
||||
// its maximum.
|
||||
if (type == CPLeftMouseDragged && location.x < 0)
|
||||
{
|
||||
newValue = _minValue;
|
||||
}
|
||||
else if (type == CPLeftMouseDragged && location.x > bounds.size.width)
|
||||
{
|
||||
newValue = _maxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
{
|
||||
var rect = [self rectForEphemeralSubviewNamed:"segment-bezel-" + i];
|
||||
|
||||
// Once we're tracking the mouse, we only care about horizontal mouse movement.
|
||||
if (location.x >= CGRectGetMinX(rect) && location.x < CGRectGetMaxX(rect))
|
||||
{
|
||||
newValue = (_minValue + i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newValue != oldValue)
|
||||
[self setDoubleValue:newValue];
|
||||
|
||||
// Track the mouse to support click and slide value editing.
|
||||
_isTracking = YES;
|
||||
[CPApp setTarget:self selector:@selector(_trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if ([self isContinuous])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
else if (_isTracking)
|
||||
{
|
||||
_isTracking = NO;
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
- (CPLevelIndicatorStyle)style;
|
||||
- (void)setLevelIndicatorStyle:(CPLevelIndicatorStyle)style;
|
||||
*/
|
||||
|
||||
- (void)setMinValue:(double)minValue
|
||||
{
|
||||
if (_minValue === minValue)
|
||||
return;
|
||||
_minValue = minValue;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setMaxValue:(double)maxValue
|
||||
{
|
||||
if (_maxValue === maxValue)
|
||||
return;
|
||||
_maxValue = maxValue;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setWarningValue:(double)warningValue;
|
||||
{
|
||||
if (_warningValue === warningValue)
|
||||
return;
|
||||
_warningValue = warningValue;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setCriticalValue:(double)criticalValue;
|
||||
{
|
||||
if (_criticalValue === criticalValue)
|
||||
return;
|
||||
_criticalValue = criticalValue;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*
|
||||
- (CPTickMarkPosition)tickMarkPosition;
|
||||
- (void)setTickMarkPosition:(CPTickMarkPosition)position;
|
||||
|
||||
- (int)numberOfTickMarks;
|
||||
- (void)setNumberOfTickMarks:(int)count;
|
||||
|
||||
- (int)numberOfMajorTickMarks;
|
||||
- (void)setNumberOfMajorTickMarks:(int)count;
|
||||
|
||||
- (double)tickMarkValueAtIndex:(int)index;
|
||||
- (CGRect)rectOfTickMarkAtIndex:(int)index;
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
|
||||
CPLevelIndicatorMinValueKey = "CPLevelIndicatorMinValueKey",
|
||||
CPLevelIndicatorMaxValueKey = "CPLevelIndicatorMaxValueKey",
|
||||
CPLevelIndicatorWarningValueKey = "CPLevelIndicatorWarningValueKey",
|
||||
CPLevelIndicatorCriticalValueKey = "CPLevelIndicatorCriticalValueKey",
|
||||
CPLevelIndicatorTickMarkPositionKey = "CPLevelIndicatorTickMarkPositionKey",
|
||||
CPLevelIndicatorNumberOfTickMarksKey = "CPLevelIndicatorNumberOfTickMarksKey",
|
||||
CPLevelIndicatorNumberOfMajorTickMarksKey = "CPLevelIndicatorNumberOfMajorTickMarksKey",
|
||||
CPLevelIndicatorIsEditableKey = "CPLevelIndicatorIsEditableKey";
|
||||
|
||||
@implementation CPLevelIndicator (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_levelIndicatorStyle = [aCoder decodeIntForKey:CPLevelIndicatorStyleKey];
|
||||
_minValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMinValueKey];
|
||||
_maxValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMaxValueKey];
|
||||
_warningValue = [aCoder decodeDoubleForKey:CPLevelIndicatorWarningValueKey];
|
||||
_criticalValue = [aCoder decodeDoubleForKey:CPLevelIndicatorCriticalValueKey];
|
||||
_tickMarkPosition = [aCoder decodeIntForKey:CPLevelIndicatorTickMarkPositionKey];
|
||||
_numberOfTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfTickMarksKey];
|
||||
_numberOfMajorTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
|
||||
|
||||
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_levelIndicatorStyle forKey:CPLevelIndicatorStyleKey];
|
||||
[aCoder encodeDouble:_minValue forKey:CPLevelIndicatorMinValueKey];
|
||||
[aCoder encodeDouble:_maxValue forKey:CPLevelIndicatorMaxValueKey];
|
||||
[aCoder encodeDouble:_warningValue forKey:CPLevelIndicatorWarningValueKey];
|
||||
[aCoder encodeDouble:_criticalValue forKey:CPLevelIndicatorCriticalValueKey];
|
||||
[aCoder encodeInt:_tickMarkPosition forKey:CPLevelIndicatorTickMarkPositionKey];
|
||||
[aCoder encodeInt:_numberOfTickMarks forKey:CPLevelIndicatorNumberOfTickMarksKey];
|
||||
[aCoder encodeInt:_numberOfMajorTickMarks forKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
|
||||
[aCoder encodeBool:_isEditable forKey:CPLevelIndicatorIsEditableKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+51
-13
@@ -195,7 +195,7 @@ var _CPMenuBarVisible = NO,
|
||||
}
|
||||
|
||||
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"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0 / 255.0 green:130.0 / 255.0 blue:186.0 / 255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
|
||||
|
||||
if (!highlightTextColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
@@ -337,6 +337,25 @@ var _CPMenuBarVisible = NO,
|
||||
[self removeObjectFromItemsAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes all the menu items in the receiver.
|
||||
This method is more efficient than removing menu items individually.
|
||||
|
||||
Unlike the other remove methods, this method does not post CPMenuDidChangeItemNotification notifications.
|
||||
*/
|
||||
- (void)removeAllItems
|
||||
{
|
||||
var count = [_items count];
|
||||
|
||||
// Remove the connection to this menu in case
|
||||
// someone else has a reference to the menu item.
|
||||
while (count--)
|
||||
[_items[count] setMenu:nil];
|
||||
|
||||
_items = [CPMutableArray array];
|
||||
_highlightedIndex = CPNotFound;
|
||||
}
|
||||
|
||||
/*!
|
||||
Called when a menu item has visually changed.
|
||||
@param aMenuItem the item that changed
|
||||
@@ -536,7 +555,6 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (void)submenuAction:(id)aSender
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -584,11 +602,34 @@ var _CPMenuBarVisible = NO,
|
||||
}
|
||||
|
||||
/*!
|
||||
Not implemented.
|
||||
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.
|
||||
*/
|
||||
- (void)update
|
||||
{
|
||||
if (![self autoenablesItems])
|
||||
return;
|
||||
|
||||
var items = [self itemArray];
|
||||
for (var i = 0; i < [items count]; i++)
|
||||
{
|
||||
var item = [items objectAtIndex:i];
|
||||
|
||||
if ([item hasSubmenu])
|
||||
continue;
|
||||
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
[item _setEnabled:NO];
|
||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||
[item _setEnabled:[validator validateMenuItem:item]];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item _setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
}
|
||||
|
||||
// Managing the Title
|
||||
@@ -851,7 +892,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
// Handling Tracking
|
||||
/*!
|
||||
Cancels tracking.
|
||||
Cancels tracking.
|
||||
*/
|
||||
- (void)cancelTracking
|
||||
{
|
||||
@@ -911,7 +952,7 @@ var _CPMenuBarVisible = NO,
|
||||
characters = [anEvent charactersIgnoringModifiers],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
for(; index < count; ++index)
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = _items[index],
|
||||
modifierMask = [item keyEquivalentModifierMask];
|
||||
@@ -948,14 +989,6 @@ var _CPMenuBarVisible = NO,
|
||||
}
|
||||
|
||||
//
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
|
||||
{
|
||||
return _items[_highlightedIndex] == aMenuItem;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@@ -971,6 +1004,9 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
if (_highlightedIndex !== CPNotFound)
|
||||
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
|
||||
|
||||
if (_highlightedIndex !== CPNotFound && _menuWindow)
|
||||
[_menuWindow._menuView scrollRectToVisible:[[_items[_highlightedIndex] _menuItemView] frame]];
|
||||
}
|
||||
|
||||
- (void)_setMenuName:(CPString)aName
|
||||
@@ -1097,6 +1133,8 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
|
||||
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
|
||||
|
||||
_autoenablesItems = YES;
|
||||
|
||||
[self setMinimumWidth:0];
|
||||
}
|
||||
|
||||
|
||||
@@ -15,18 +15,18 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
CPMenu _menu;
|
||||
CPView _highlightView;
|
||||
CPArray _menuItemViews;
|
||||
|
||||
|
||||
CPMenuItem _trackingMenuItem;
|
||||
|
||||
|
||||
CPImageView _iconImageView;
|
||||
CPTextField _titleField;
|
||||
|
||||
|
||||
CPColor _textColor;
|
||||
CPColor _titleColor;
|
||||
|
||||
|
||||
CPColor _textShadowColor;
|
||||
CPColor _titleShadowColor;
|
||||
|
||||
|
||||
CPColor _highlightColor;
|
||||
CPColor _highlightTextColor;
|
||||
CPColor _highlightTextShadowColor;
|
||||
@@ -36,9 +36,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (self != [_CPMenuBarWindow class])
|
||||
return;
|
||||
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
|
||||
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
|
||||
}
|
||||
|
||||
@@ -60,27 +60,27 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
[self setLevel:CPMainMenuWindowLevel];
|
||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||
|
||||
|
||||
var contentView = [self contentView];
|
||||
|
||||
|
||||
[contentView setAutoresizesSubviews:NO];
|
||||
|
||||
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
|
||||
//
|
||||
_iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
|
||||
|
||||
|
||||
[contentView addSubview:_iconImageView];
|
||||
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
|
||||
|
||||
[contentView addSubview:_titleField];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
[_titleField setStringValue:aTitle];
|
||||
[_titleField sizeToFit];
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
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];
|
||||
}
|
||||
else
|
||||
@@ -133,9 +133,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_titleColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_titleColor = aColor;
|
||||
|
||||
|
||||
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||
}
|
||||
|
||||
@@ -163,9 +163,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_titleShadowColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_titleShadowColor = aColor;
|
||||
|
||||
|
||||
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_highlightColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_highlightColor = aColor;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_highlightTextColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_highlightTextColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||
@@ -191,9 +191,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_highlightTextShadowColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_highlightTextShadowColor = aColor;
|
||||
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||
}
|
||||
|
||||
@@ -201,9 +201,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if (_menu == aMenu)
|
||||
return;
|
||||
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
@@ -220,16 +220,16 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
removeObserver:self
|
||||
name:CPMenuDidRemoveItemNotification
|
||||
object:_menu];
|
||||
|
||||
|
||||
var items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
|
||||
while (count--)
|
||||
[[items[count] _menuItemView] removeFromSuperview];
|
||||
}
|
||||
|
||||
_menu = aMenu;
|
||||
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
@@ -237,41 +237,41 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
selector:@selector(menuDidAddItem:)
|
||||
name:CPMenuDidAddItemNotification
|
||||
object:_menu];
|
||||
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidChangeItem:)
|
||||
name:CPMenuDidChangeItemNotification
|
||||
object:_menu];
|
||||
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidRemoveItem:)
|
||||
name:CPMenuDidRemoveItemNotification
|
||||
object:_menu];
|
||||
}
|
||||
|
||||
|
||||
_menuItemViews = [];
|
||||
|
||||
|
||||
var contentView = [self contentView],
|
||||
items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
menuItemView = [item _menuItemView];
|
||||
|
||||
|
||||
_menuItemViews.push(menuItemView);
|
||||
|
||||
[menuItemView setTextColor:_textColor];
|
||||
[menuItemView setHidden:[item isHidden]];
|
||||
|
||||
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
|
||||
[contentView addSubview:menuItemView];
|
||||
}
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
[menuItemView setHidden:[menuItem isHidden]];
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -298,9 +298,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
[menuItemView setHidden:[menuItem isHidden]];
|
||||
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
|
||||
[[self contentView] addSubview:menuItemView];
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
[_menuItemViews removeObjectAtIndex:index];
|
||||
|
||||
[menuItemView removeFromSuperview];
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -343,29 +343,29 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
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 setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
@@ -375,14 +375,14 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
else
|
||||
{
|
||||
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
|
||||
|
||||
x = CGRectGetMinX([menuItemView frame]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
@@ -390,7 +390,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
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)];
|
||||
}
|
||||
@@ -505,38 +505,38 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
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
|
||||
@@ -544,7 +544,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
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)];
|
||||
}
|
||||
|
||||
+333
-45
@@ -5,9 +5,8 @@ _CPMenuManagerScrollingStateUp = -1,
|
||||
_CPMenuManagerScrollingStateDown = 1,
|
||||
_CPMenuManagerScrollingStateNone = 0;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
var SharedMenuManager = nil;
|
||||
var STICKY_TIME_INTERVAL = 500,
|
||||
SharedMenuManager = nil;
|
||||
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
@@ -21,6 +20,11 @@ var SharedMenuManager = nil;
|
||||
CPMutableArray _menuContainerStack;
|
||||
|
||||
Function _trackingCallback;
|
||||
|
||||
CPString _keyBuffer;
|
||||
|
||||
CPMenuItem _previousActiveItem;
|
||||
int _showTimerID;
|
||||
}
|
||||
|
||||
+ (_CPMenuManager)sharedMenuManager
|
||||
@@ -36,7 +40,7 @@ var SharedMenuManager = nil;
|
||||
if (SharedMenuManager)
|
||||
return SharedMenuManager;
|
||||
|
||||
return [super init];
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (id)trackingMenuContainer
|
||||
@@ -67,13 +71,13 @@ var SharedMenuManager = nil;
|
||||
|
||||
if (menu === [CPApp mainMenu])
|
||||
{
|
||||
var globalLocation = [anEvent globalLocation];
|
||||
var globalLocation = [anEvent globalLocation],
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var menuLocation = [aMenuContainer convertGlobalToBase:globalLocation];
|
||||
// Find which menu window the mouse is currently on top of
|
||||
menuLocation = [aMenuContainer convertGlobalToBase:globalLocation],
|
||||
|
||||
// Find out the item the mouse is currently on top of
|
||||
var activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
|
||||
// Find out the item the mouse is currently on top of
|
||||
activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
|
||||
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
_menuBarButtonItemIndex = activeItemIndex;
|
||||
@@ -95,7 +99,34 @@ var SharedMenuManager = nil;
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||
[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,
|
||||
submenu = [[menu highlightedItem] submenu];
|
||||
|
||||
// get the current active menu
|
||||
while (submenu && [submenu._menuWindow isVisible])
|
||||
{
|
||||
menu = submenu;
|
||||
submenu = [[menu highlightedItem] submenu];
|
||||
}
|
||||
|
||||
if ([menu numberOfItems])
|
||||
[self interpretKeyEvent:anEvent forMenu:menu];
|
||||
|
||||
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];
|
||||
@@ -103,13 +134,16 @@ var SharedMenuManager = nil;
|
||||
// Remember this for the next periodic event.
|
||||
_lastGlobalLocation = globalLocation;
|
||||
|
||||
if (!_lastGlobalLocation)
|
||||
return;
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||
activeMenu = [activeMenuContainer menu],
|
||||
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
|
||||
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
|
||||
|
||||
// Find out the item the mouse is currently on top of
|
||||
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||
// Find out the item the mouse is currently on top of
|
||||
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
// If the item isn't enabled its as if we clicked on nothing.
|
||||
@@ -121,11 +155,13 @@ var SharedMenuManager = nil;
|
||||
|
||||
var mouseOverMenuView = [activeItem view];
|
||||
|
||||
if (type === CPScrollWheel)
|
||||
[activeMenuContainer scrollByDelta:[anEvent deltaY]];
|
||||
|
||||
if (type === CPPeriodic)
|
||||
{
|
||||
if (_scrollingState === _CPMenuManagerScrollingStateUp)
|
||||
[activeMenuContainer scrollUp];
|
||||
|
||||
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
|
||||
[activeMenuContainer scrollDown];
|
||||
}
|
||||
@@ -135,13 +171,13 @@ var SharedMenuManager = nil;
|
||||
{
|
||||
if (!_lastMouseOverMenuView)
|
||||
[activeMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
|
||||
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||
{
|
||||
[mouseOverMenuView mouseExited:anEvent];
|
||||
// FIXME: Possibly multiple of these?
|
||||
[_lastMouseOverMenuView mouseEntered:anEvent];
|
||||
|
||||
|
||||
_lastMouseOverMenuView = mouseOverMenuView;
|
||||
}
|
||||
|
||||
@@ -151,13 +187,15 @@ var SharedMenuManager = nil;
|
||||
menuContainerWindow = [menuContainerWindow window];
|
||||
|
||||
[menuContainerWindow
|
||||
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
windowNumber:menuContainerWindow
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:[anEvent clickCount]
|
||||
pressure:[anEvent pressure]]];
|
||||
sendEvent:[CPEvent mouseEventWithType:type
|
||||
location:menuLocation
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
windowNumber:menuContainerWindow
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:[anEvent clickCount]
|
||||
pressure:[anEvent pressure]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -166,10 +204,10 @@ var SharedMenuManager = nil;
|
||||
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||
_lastMouseOverMenuView = nil;
|
||||
}
|
||||
|
||||
|
||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||
|
||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
|
||||
|
||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
|
||||
{
|
||||
var oldScrollingState = _scrollingState;
|
||||
|
||||
@@ -179,34 +217,59 @@ var SharedMenuManager = nil;
|
||||
{
|
||||
if (_scrollingState === _CPMenuManagerScrollingStateNone)
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
else if (oldScrollingState === _CPMenuManagerScrollingStateNone)
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
|
||||
// Prevent previous selected menu items from opening by stopping the timer if a
|
||||
// new item is selected before the timer runs out
|
||||
if (_previousActiveItem !== activeItem)
|
||||
{
|
||||
clearTimeout(_showTimerID);
|
||||
_showTimerID = undefined;
|
||||
}
|
||||
|
||||
// If the item has a submenu, show it.
|
||||
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
|
||||
{
|
||||
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
|
||||
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
|
||||
newMenuOrigin;
|
||||
|
||||
if ([activeMenuContainer isMenuBar])
|
||||
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||
else
|
||||
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
||||
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
||||
|
||||
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
||||
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||
// Only start a new timer if the previous was cancelled
|
||||
if (_showTimerID === undefined)
|
||||
{
|
||||
// Close the current menu item because we are going to select a new one after a short delay
|
||||
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
||||
|
||||
if (![activeMenuContainer isMenuBar])
|
||||
{
|
||||
_showTimerID = setTimeout(function()
|
||||
{
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||
}, 250);
|
||||
}
|
||||
else
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||
}
|
||||
}
|
||||
|
||||
// This handles both the case where we've moved away from the menu, and where
|
||||
// This handles both the case where we've moved away from the menu, and where
|
||||
// we've moved to an item without a submenu.
|
||||
else
|
||||
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
||||
|
||||
_previousActiveItem = activeItem;
|
||||
}
|
||||
|
||||
- (void)trackMenuBarButtonEvent:(CPEvent)anEvent
|
||||
@@ -216,16 +279,15 @@ var SharedMenuManager = nil;
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
var globalLocation = [anEvent globalLocation];
|
||||
var globalLocation = [anEvent globalLocation],
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var menu = [self trackingMenu],
|
||||
// Find which menu window the mouse is currently on top of
|
||||
menu = [self trackingMenu],
|
||||
trackingMenuContainer = [self trackingMenuContainer],
|
||||
menuLocation = [trackingMenuContainer convertGlobalToBase:globalLocation];
|
||||
|
||||
if ([trackingMenuContainer itemIndexAtPoint:menuLocation] === _menuBarButtonItemIndex)
|
||||
[menu _highlightItemAtIndex:_menuBarButtonItemIndex];
|
||||
|
||||
else
|
||||
[menu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
@@ -242,9 +304,6 @@ var SharedMenuManager = nil;
|
||||
// Stop all periodic events at this point.
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
// Get the highlighted item from the original menu.
|
||||
var highlightedItem = [trackingMenu highlightedItem];
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
|
||||
@@ -256,9 +315,8 @@ var SharedMenuManager = nil;
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidEndTrackingNotification
|
||||
object:trackingMenu];
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidEndTrackingNotification
|
||||
object:trackingMenu];
|
||||
|
||||
CPApp._activeMenu = nil;
|
||||
}
|
||||
@@ -358,10 +416,240 @@ var SharedMenuManager = nil;
|
||||
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
|
||||
else
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
[menuWindow setFrameOrigin:aGlobalLocation];
|
||||
[menuWindow orderFront:self];
|
||||
}
|
||||
|
||||
/// handle keyboard navigation
|
||||
- (void)interpretKeyEvent:(CPEvent)anEvent forMenu:(CPMenu)menu
|
||||
{
|
||||
var modifierFlags = [anEvent modifierFlags],
|
||||
character = [anEvent charactersIgnoringModifiers],
|
||||
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
|
||||
|
||||
if (selectorNames)
|
||||
{
|
||||
var iter = [selectorNames objectEnumerator],
|
||||
obj;
|
||||
|
||||
while (obj = [iter nextObject])
|
||||
{
|
||||
var aSelector = CPSelectorFromString(obj);
|
||||
|
||||
if ([self respondsToSelector:aSelector])
|
||||
[self performSelector:aSelector withObject:menu];
|
||||
}
|
||||
}
|
||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
|
||||
{
|
||||
if (!_keyBuffer)
|
||||
{
|
||||
_startTime = [CPDate date];
|
||||
_keyBuffer = character;
|
||||
|
||||
[CPEvent stopPeriodicEvents];
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.1];
|
||||
}
|
||||
else
|
||||
_keyBuffer += character;
|
||||
|
||||
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:NO];
|
||||
_lastGlobalLocation = Nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu clearBuffer:(BOOL)shouldClear
|
||||
{
|
||||
var iter = [[menu itemArray] objectEnumerator],
|
||||
obj;
|
||||
|
||||
while (obj = [iter nextObject])
|
||||
{
|
||||
if ([obj isHidden] || ![obj isEnabled])
|
||||
continue;
|
||||
|
||||
if ([[[obj title] commonPrefixWithString:characters options:CPCaseInsensitiveSearch] length] == [characters length])
|
||||
{
|
||||
[menu _highlightItemAtIndex:iter._index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldClear)
|
||||
{
|
||||
[CPEvent stopPeriodicEvents];
|
||||
_keyBuffer = Nil;
|
||||
}
|
||||
else
|
||||
_startTime = [CPDate date];
|
||||
}
|
||||
|
||||
- (void)scrollToBeginningOfDocument:(CPMenu)menu
|
||||
{
|
||||
[menu _highlightItemAtIndex:0];
|
||||
}
|
||||
|
||||
- (void)scrollToEndOfDocument:(CPMenu)menu
|
||||
{
|
||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||
}
|
||||
|
||||
- (void)scrollPageDown:(CPMenu)menu
|
||||
{
|
||||
var menuWindow = menu._menuWindow,
|
||||
menuClipView = menuWindow._menuClipView,
|
||||
bottom = [menuClipView bounds].size.height,
|
||||
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
|
||||
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
|
||||
current = [menu indexOfItem:[menu highlightedItem]];
|
||||
|
||||
if (current == CPNotFound)
|
||||
{
|
||||
[menu _highlightItemAtIndex:0];
|
||||
return;
|
||||
}
|
||||
|
||||
next = current + (last - first);
|
||||
|
||||
if (next < [menu numberOfItems])
|
||||
[menu _highlightItemAtIndex:next];
|
||||
else
|
||||
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
|
||||
|
||||
var item = [menu highlightedItem];
|
||||
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveDown:menu];
|
||||
}
|
||||
|
||||
- (void)scrollPageUp:(CPMenu)menu
|
||||
{
|
||||
var menuWindow = menu._menuWindow,
|
||||
menuClipView = menuWindow._menuClipView,
|
||||
bottom = [menuClipView bounds].size.height,
|
||||
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
|
||||
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
|
||||
current = [menu indexOfItem:[menu highlightedItem]];
|
||||
|
||||
if (current == CPNotFound)
|
||||
{
|
||||
[menu _highlightItemAtIndex:0];
|
||||
return;
|
||||
}
|
||||
|
||||
next = current - (last - first);
|
||||
|
||||
if (next < 0)
|
||||
[menu _highlightItemAtIndex:0];
|
||||
else
|
||||
[menu _highlightItemAtIndex:next];
|
||||
|
||||
var item = [menu highlightedItem];
|
||||
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveUp:menu];
|
||||
}
|
||||
|
||||
- (void)moveLeft:(CPMenu)menu
|
||||
{
|
||||
if ([menu supermenu])
|
||||
{
|
||||
if ([menu supermenu] == [CPApp mainMenu])
|
||||
{
|
||||
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
|
||||
[self moveUp:[CPApp mainMenu]];
|
||||
|
||||
var activeItem = [[CPApp mainMenu] highlightedItem],
|
||||
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
|
||||
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
|
||||
}
|
||||
else
|
||||
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveRight:(CPMenu)menu
|
||||
{
|
||||
var activeItem = [menu highlightedItem];
|
||||
|
||||
if ([activeItem hasSubmenu])
|
||||
{
|
||||
if ([[activeItem submenu] numberOfItems])
|
||||
{
|
||||
var activeItemIndex = [menu indexOfItem:activeItem],
|
||||
activeMenuContainer = menu._menuWindow,
|
||||
activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
|
||||
newMenuOrigin;
|
||||
|
||||
if ([activeMenuContainer isMenuBar])
|
||||
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||
else
|
||||
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
||||
|
||||
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
||||
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||
[self moveDown:[activeItem submenu]];
|
||||
}
|
||||
}
|
||||
else if ([self trackingMenu] == [CPApp mainMenu])
|
||||
{
|
||||
[self showMenu:nil fromMenu:menu atPoint:CGPointMakeZero()];
|
||||
[self moveDown:[CPApp mainMenu]];
|
||||
|
||||
var activeItem = [[CPApp mainMenu] highlightedItem],
|
||||
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
|
||||
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveDown:(CPMenu)menu
|
||||
{
|
||||
var index = menu._highlightedIndex + 1;
|
||||
|
||||
if (index < [menu numberOfItems])
|
||||
{
|
||||
[menu _highlightItemAtIndex:index];
|
||||
|
||||
var item = [menu highlightedItem];
|
||||
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveDown:menu];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveUp:(CPMenu)menu
|
||||
{
|
||||
var index = menu._highlightedIndex - 1;
|
||||
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
[menu _highlightItemAtIndex:index];
|
||||
|
||||
var item = [menu highlightedItem];
|
||||
|
||||
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
|
||||
[self moveUp:menu];
|
||||
}
|
||||
|
||||
- (void)insertNewline:(CPMenu)menu
|
||||
{
|
||||
if ([[menu highlightedItem] hasSubmenu])
|
||||
[self moveRight:menu];
|
||||
else
|
||||
[menu cancelTracking]
|
||||
}
|
||||
|
||||
- (void)cancelOperation:(CPMenu)menu
|
||||
{
|
||||
[menu _highlightItemAtIndex:CPNotFound];
|
||||
[CPEvent stopPeriodicEvents];
|
||||
[[self trackingMenu] cancelTracking];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
var _CPMenuWindowPool = [],
|
||||
_CPMenuWindowPoolCapacity = 5,
|
||||
|
||||
|
||||
_CPMenuWindowBackgroundColors = [];
|
||||
|
||||
|
||||
_CPMenuWindowMenuBarBackgroundStyle = 0;
|
||||
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||
@@ -16,7 +16,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
LEFT_MARGIN = 1.0,
|
||||
RIGHT_MARGIN = 1.0,
|
||||
BOTTOM_MARGIN = 5.0,
|
||||
|
||||
|
||||
SCROLL_INDICATOR_HEIGHT = 16.0;
|
||||
|
||||
/*
|
||||
@@ -26,10 +26,10 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
_CPMenuView _menuView;
|
||||
CPClipView _menuClipView;
|
||||
|
||||
|
||||
CPImageView _moreAboveView;
|
||||
CPImageView _moreBelowView;
|
||||
|
||||
|
||||
CGRect _unconstrainedFrame;
|
||||
CGRect _constraintRect;
|
||||
}
|
||||
@@ -67,9 +67,9 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
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)];
|
||||
}
|
||||
@@ -89,31 +89,31 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[self setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
var contentView = [self contentView];
|
||||
|
||||
|
||||
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
|
||||
[_menuClipView setDocumentView:_menuView];
|
||||
|
||||
|
||||
[contentView addSubview:_menuClipView];
|
||||
|
||||
|
||||
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
|
||||
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
|
||||
|
||||
|
||||
[contentView addSubview:_moreAboveView];
|
||||
|
||||
|
||||
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
|
||||
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
|
||||
|
||||
|
||||
[contentView addSubview:_moreBelowView];
|
||||
|
||||
[self setShadowStyle:CPWindowShadowStyleMenu];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
|
||||
{
|
||||
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
|
||||
|
||||
|
||||
if (!color)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
@@ -146,32 +146,32 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||
]]];
|
||||
|
||||
|
||||
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
||||
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)]
|
||||
]]];
|
||||
|
||||
|
||||
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
||||
}
|
||||
|
||||
@@ -187,11 +187,11 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
[aMenu _setMenuWindow:self];
|
||||
[_menuView setMenu:aMenu];
|
||||
|
||||
|
||||
var menuViewSize = [_menuView frame].size;
|
||||
|
||||
|
||||
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
|
||||
|
||||
|
||||
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
||||
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
|
||||
}
|
||||
@@ -208,10 +208,16 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return [_menuView menu];
|
||||
}
|
||||
|
||||
- (_CPMenuView)_menuView
|
||||
{
|
||||
return _menuView;
|
||||
}
|
||||
|
||||
- (void)orderFront:(id)aSender
|
||||
{
|
||||
[[self menu] update];
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
|
||||
|
||||
[super orderFront:aSender];
|
||||
}
|
||||
|
||||
@@ -270,16 +276,16 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
topMargin = TOP_MARGIN,
|
||||
bottomMargin = BOTTOM_MARGIN,
|
||||
|
||||
|
||||
contentView = [self contentView],
|
||||
bounds = [contentView bounds];
|
||||
|
||||
if (moreAbove)
|
||||
{
|
||||
topMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
|
||||
|
||||
var frame = [_moreAboveView frame];
|
||||
|
||||
|
||||
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
|
||||
}
|
||||
|
||||
@@ -288,13 +294,18 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if (moreBelow)
|
||||
{
|
||||
bottomMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
|
||||
|
||||
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
|
||||
}
|
||||
|
||||
|
||||
[_moreBelowView setHidden:!moreBelow];
|
||||
|
||||
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
|
||||
var clipFrame = CGRectMakeZero();
|
||||
|
||||
clipFrame.origin.x = LEFT_MARGIN;
|
||||
clipFrame.origin.y = topMargin;
|
||||
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN;
|
||||
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
|
||||
|
||||
[_menuClipView setFrame:clipFrame];
|
||||
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
|
||||
@@ -347,24 +358,29 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return [self canScrollUp] || [self canScrollDown];
|
||||
}
|
||||
|
||||
- (void)scrollUp
|
||||
- (void)scrollByDelta:(float)theDelta
|
||||
{
|
||||
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
|
||||
if (theDelta === 0.0)
|
||||
return;
|
||||
|
||||
_unconstrainedFrame.origin.y += 10;
|
||||
if (theDelta > 0.0 && ![self canScrollDown])
|
||||
return;
|
||||
|
||||
if (theDelta < 0.0 && ![self canScrollUp])
|
||||
return;
|
||||
|
||||
_unconstrainedFrame.origin.y -= theDelta;
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
}
|
||||
|
||||
- (void)scrollUp
|
||||
{
|
||||
[self scrollByDelta:-10.0];
|
||||
}
|
||||
|
||||
- (void)scrollDown
|
||||
{
|
||||
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
|
||||
return;
|
||||
|
||||
_unconstrainedFrame.origin.y -= 10;
|
||||
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
[self scrollByDelta:10.0];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -384,16 +400,15 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||
{
|
||||
var frame = [self frame];
|
||||
|
||||
if (![self canScroll])
|
||||
if (!CPRectContainsPoint(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)
|
||||
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + 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)
|
||||
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT && ![_moreBelowView isHidden])
|
||||
return _CPMenuManagerScrollingStateDown;
|
||||
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
@@ -428,7 +443,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
CPArray _menuItemViews;
|
||||
CPArray _visibleMenuItemInfos;
|
||||
|
||||
|
||||
CPFont _font @accessors(property=font);
|
||||
}
|
||||
|
||||
@@ -462,7 +477,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
info = _visibleMenuItemInfos[middle]
|
||||
info = _visibleMenuItemInfos[middle],
|
||||
frame = [info.view frame];
|
||||
|
||||
if (y < CGRectGetMinY(frame))
|
||||
@@ -480,7 +495,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_menuItemViews = [];
|
||||
_visibleMenuItemInfos = [];
|
||||
@@ -500,15 +515,15 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
view = [item _menuItemView];
|
||||
|
||||
view = [item _menuItemView];
|
||||
|
||||
_menuItemViews.push(view);
|
||||
|
||||
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
_visibleMenuItemInfos.push({ view:view, index:index });
|
||||
|
||||
|
||||
[view setFont:_font];
|
||||
[view setShowsStateColumn:showsStateColumn];
|
||||
[view synchronizeWithMenuItem];
|
||||
|
||||
@@ -30,6 +30,25 @@
|
||||
@import "_CPMenuItemView.j"
|
||||
|
||||
|
||||
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];
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPMenuItem
|
||||
@@ -133,10 +152,17 @@
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
_isEnabled = isEnabled;
|
||||
[self _setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
|
||||
_isEnabled = !!isEnabled;
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -599,19 +625,22 @@ CPControlKeyMask
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
|
||||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
|
||||
|
||||
if ([CPMenuItemStringRepresentationDictionary objectForKey:string])
|
||||
string = [CPMenuItemStringRepresentationDictionary objectForKey:string];
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||
{
|
||||
if (_keyEquivalentModifierMask & CPCommandKeyMask)
|
||||
string = "⌘" + string;
|
||||
string = "\u2318" + string;
|
||||
|
||||
if (needsShift)
|
||||
string = "⇧" + string;
|
||||
string = "\u21E7" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||
string = "⌥" + string;
|
||||
string = "\u2325" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPControlKeyMask)
|
||||
string = "^" + string;
|
||||
string = "\u2303" + string;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -851,6 +880,11 @@ CPControlKeyMask
|
||||
return ![self submenu] && [self menu] === [CPApp mainMenu];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description] + @" target: " + [self target] + @" action: " + CPStringFromSelector([self action]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
|
||||
@@ -9,7 +9,7 @@ var SelectionColor = nil,
|
||||
SUBMENU_INDICATOR_COLOR = nil,
|
||||
_CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
@@ -40,7 +40,7 @@ var SelectionColor = nil,
|
||||
|
||||
_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;
|
||||
|
||||
@@ -141,7 +141,7 @@ var SelectionColor = nil,
|
||||
|
||||
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;
|
||||
@@ -149,7 +149,7 @@ var SelectionColor = nil,
|
||||
}
|
||||
|
||||
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
|
||||
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
@@ -218,19 +218,19 @@ var SelectionColor = nil,
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
bounds = [self bounds];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ var LEFT_MARGIN = 3.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
|
||||
var _CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
@@ -42,12 +42,12 @@ var _CPMenuItemSelectionColor = nil,
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -72,12 +72,12 @@ var _CPMenuItemSelectionColor = nil,
|
||||
_menuItem = aMenuItem;
|
||||
_showsStateColumn = YES;
|
||||
_isDirty = YES;
|
||||
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[self synchronizeWithMenuItem];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
_view = menuItemView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if ([_menuItem menu] == [CPApp mainMenu])
|
||||
{
|
||||
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
||||
@@ -129,7 +129,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
[_view removeFromSuperview];
|
||||
_view = [_CPMenuItemStandardView view];
|
||||
}
|
||||
|
||||
|
||||
[_view setMenuItem:_menuItem];
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
{
|
||||
if (![_menuItem hasSubmenu])
|
||||
return NO;
|
||||
|
||||
|
||||
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
@@ -207,7 +207,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
@@ -232,23 +232,23 @@ var _CPMenuItemSelectionColor = nil,
|
||||
return;
|
||||
|
||||
_color = aColor;
|
||||
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
|
||||
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);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* CPObjectController.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* 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/CPDictionary.j>
|
||||
@import <Foundation/CPCountedSet.j>
|
||||
@@ -372,6 +393,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
if (![self content] && [self automaticallyPreparesContent])
|
||||
[self prepareContent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPObservationProxy : CPObject
|
||||
@@ -636,7 +663,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)_controllerMarkerForValues:(CPArray)theValues
|
||||
{
|
||||
var count = [theValues count];
|
||||
var count = [theValues count];
|
||||
|
||||
if (!count)
|
||||
value = CPNoSelectionMarker;
|
||||
@@ -658,6 +685,9 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
}
|
||||
}
|
||||
|
||||
if (value === nil || value.isa && [value isEqual:[CPNull null]])
|
||||
value = CPNullMarker;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* CPOpenPanel.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* 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"
|
||||
|
||||
|
||||
+148
-109
@@ -71,7 +71,8 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
|
||||
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
|
||||
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
|
||||
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
|
||||
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
|
||||
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24,
|
||||
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ = 1 << 25;
|
||||
|
||||
CPOutlineViewDropOnItemIndex = -1;
|
||||
|
||||
@@ -160,55 +161,55 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
return self;
|
||||
}
|
||||
/*!
|
||||
<pre>
|
||||
In addition to standard delegation, the outline view also supports data
|
||||
source delegation. This method sets the data source object. Just like the
|
||||
TableView you have CPTableColumns but instead of rows you deal with items.
|
||||
|
||||
You must implement these data source methods:
|
||||
@section required You must implement these data source methods:
|
||||
|
||||
- (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item;
|
||||
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
|
||||
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
|
||||
@code - (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item; @endcode
|
||||
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item;
|
||||
Returns YES if the item is expandable, otherwise NO.
|
||||
Returns YES if the item is expandable, otherwise NO.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item; @endcode
|
||||
|
||||
- (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item;
|
||||
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
|
||||
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
|
||||
@code - (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item; @endcode
|
||||
|
||||
- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
|
||||
Returns the object value of the item in a given column.
|
||||
Returns the object value of the item in a given column.
|
||||
@code - (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
|
||||
|
||||
---------
|
||||
|
||||
@section optional The following methods are optional:
|
||||
|
||||
@section editin Editing:
|
||||
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
|
||||
@code - (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
|
||||
|
||||
|
||||
The following methods are optional:
|
||||
@section sorting Sorting:
|
||||
The outlineview will call this method if you click the table header. You should sort the datasource based off of the new sort descriptors and reload the data
|
||||
@code - (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors; @endcode
|
||||
|
||||
Editing:
|
||||
- (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
|
||||
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
|
||||
@section draganddrop Drag and Drop:
|
||||
@note In order for the outlineview to receive drops don't forget to first
|
||||
register the tableview for drag types like you do with every other view @endnote
|
||||
|
||||
Return YES if the operation was successful otherwise return NO.
|
||||
The data source should incorporate the data from the dragging pasteboard in this method implementation.
|
||||
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index; @endcode
|
||||
|
||||
|
||||
Sorting:
|
||||
- (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors;
|
||||
The outlineview will call this method if you click the table header. You should sort the datasource based off of the new sort descriptors and reload the data
|
||||
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
|
||||
The data source can retarget a drop if you want by calling <pre>-(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;</pre>
|
||||
@code - (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index; @endcode
|
||||
|
||||
Drag and Drop:
|
||||
In order for the outlineview to receive drops don't forget to first
|
||||
register the tableview for drag types like you do with every other view
|
||||
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index;
|
||||
Return YES if the operation was successful otherwise return NO.
|
||||
The data source should incorporate the data from the dragging pasteboard in this method implementation.
|
||||
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
|
||||
|
||||
- (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index;
|
||||
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
|
||||
The data source can retarget a drop if you want by calling -(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;
|
||||
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard;
|
||||
Returns YES if the drop operation is allowed otherwise NO.
|
||||
This method is invoked by the outlineview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
|
||||
If you want the drag to begin you should return YES and place the drag data on the pboard.
|
||||
</pre>
|
||||
Returns YES if the drop operation is allowed otherwise NO.
|
||||
This method is invoked by the outlineview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
|
||||
If you want the drag to begin you should return YES and place the drag data on the pboard.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard; @endcode
|
||||
*/
|
||||
- (void)setDataSource:(id)aDataSource
|
||||
{
|
||||
@@ -713,74 +714,80 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
|
||||
Sets the delegate for the outlineview.
|
||||
|
||||
The following methods can be implemented:
|
||||
|
||||
User Interaction Notifications:
|
||||
- (void)outlineViewColumnDidMove:(CPNotification)notification;
|
||||
Called when the user moves a column in the outlineview.
|
||||
|
||||
- (void)outlineViewColumnDidResize:(CPNotification)notification;
|
||||
Called when the user resizes a column in the outlineview.
|
||||
|
||||
- (void)outlineViewItemDidCollapse:(CPNotification)notification;
|
||||
Called when the user collapses an item in the outlineview.
|
||||
|
||||
- (void)outlineViewItemDidExpand:(CPNotification)notification;
|
||||
Called when the user expands an item in the outlineview.
|
||||
|
||||
- (void)outlineViewItemWillCollapse:(CPNotification)notification;
|
||||
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
|
||||
|
||||
- (void)outlineViewItemWillExpand:(CPNotification)notification;
|
||||
Called when the used expands an item, but before the item is actually expanded.
|
||||
|
||||
- (void)outlineViewSelectionDidChange:(CPNotification)notification;
|
||||
Called when the user changes the selection of the outlineview.
|
||||
|
||||
- (void)outlineViewSelectionIsChanging:(CPNotification)notification
|
||||
Called when the user changes the selection of the outlineview, but before the change is made.
|
||||
|
||||
Expanding and collapsing items:
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item;
|
||||
Return YES if the item should be given permission to expand, otherwise NO.
|
||||
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item;
|
||||
Return YES if the item should be given permission to collapse, otherwise NO.
|
||||
|
||||
Selection:
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn;
|
||||
Return YES to allow the selection of tableColumn, otherwise NO.
|
||||
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item;
|
||||
Return YES to allow the selection of an item, otherwise NO.
|
||||
|
||||
- (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView;
|
||||
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
|
||||
|
||||
Displaying DataViews:
|
||||
- (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item;
|
||||
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
|
||||
|
||||
Editing:
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item;
|
||||
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
|
||||
|
||||
Group Items:
|
||||
- (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item;
|
||||
Implement this to indicate whether a given item should be rendered using the group item style.
|
||||
Return YES if the item is a group item, otherwise NO.
|
||||
|
||||
Variable Item Heights
|
||||
- (int)outlineView:(CPOutlineView)outlineView heightOfRowByItem:(id)anItem;
|
||||
Implement this method to get custom heights of rows based on the item.
|
||||
This delegate method will be passed your 'item' object and expects you to return an integer height.
|
||||
NOTE: this should only be implemented if rows will be different heights, if you want to set a height for ALL of your rows see -setRowHeight:
|
||||
|
||||
@param aDelegate - the delegate object you wish to set for the receiver.
|
||||
<pre>
|
||||
|
||||
@section notifications User Interaction Notifications:
|
||||
|
||||
Called when the user moves a column in the outlineview.
|
||||
@code - (void)outlineViewColumnDidMove:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user resizes a column in the outlineview.
|
||||
@code - (void)outlineViewColumnDidResize:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user collapses an item in the outlineview.
|
||||
@code - (void)outlineViewItemDidCollapse:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user expands an item in the outlineview.
|
||||
@code - (void)outlineViewItemDidExpand:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
|
||||
@code - (void)outlineViewItemWillCollapse:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the used expands an item, but before the item is actually expanded.
|
||||
@code - (void)outlineViewItemWillExpand:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user changes the selection of the outlineview.
|
||||
@code - (void)outlineViewSelectionDidChange:(CPNotification)notification; @endcode
|
||||
|
||||
Called when the user changes the selection of the outlineview, but before the change is made.
|
||||
@code - (void)outlineViewSelectionIsChanging:(CPNotification)notification; @endcode
|
||||
|
||||
@section expandingandcollapsing Expanding and collapsing items:
|
||||
|
||||
Return YES if the item should be given permission to expand, otherwise NO.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item; @endcode
|
||||
|
||||
Return YES if the item should be given permission to collapse, otherwise NO.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item; @endcode
|
||||
|
||||
@section selection Selection:
|
||||
Return YES to allow the selection of tableColumn, otherwise NO.
|
||||
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn; @endcode
|
||||
|
||||
Return YES to allow the selection of an item, otherwise NO.
|
||||
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item; @endcode
|
||||
|
||||
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
|
||||
@code - (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView; @endcode
|
||||
|
||||
@section dataviews Displaying DataViews:
|
||||
|
||||
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
|
||||
@code - (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
|
||||
|
||||
@section editin Editing:
|
||||
|
||||
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
|
||||
|
||||
@section groups Group Items:
|
||||
|
||||
Implement this to indicate whether a given item should be rendered using the group item style.
|
||||
Return YES if the item is a group item, otherwise NO.
|
||||
@code - (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item; @endcode
|
||||
|
||||
|
||||
@section variableitems Variable Item Heights
|
||||
|
||||
Implement this method to get custom heights of rows based on the item.
|
||||
This delegate method will be passed your 'item' object and expects you to return an integer height.
|
||||
@note This should only be implemented if rows will be different heights, if you want to set a height for ALL of your rows see -setRowHeight:@endnote
|
||||
@code - (int)outlineView:(CPOutlineView)outlineView heightOfRowByItem:(id)anItem; @endcode
|
||||
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
@@ -872,7 +879,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
|
||||
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
|
||||
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:),
|
||||
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ , @selector(outlineView:menuForTableColumn:item:)
|
||||
],
|
||||
delegateCount = [delegateMethods count];
|
||||
|
||||
@@ -944,6 +952,17 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)_sendDelegateDeleteKeyPressed
|
||||
{
|
||||
if ([[self delegate] respondsToSelector: @selector(outlineViewDeleteKeyPressed:)])
|
||||
{
|
||||
[[self delegate] outlineViewDeleteKeyPressed:self];
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the delegate object for the outlineview.
|
||||
*/
|
||||
@@ -983,7 +1002,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
Also see -setOutlineTableColumn:.
|
||||
|
||||
NOTE: This behavior deviates from cocoa slightly.
|
||||
@note This behavior deviates from cocoa slightly.
|
||||
|
||||
@param CPTableColumn aTableColumn - The table column to add.
|
||||
*/
|
||||
@@ -1622,14 +1641,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
|
||||
return NO;
|
||||
|
||||
var rowIndexes = [];
|
||||
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
|
||||
var items = [],
|
||||
index = [theIndexes firstIndex];
|
||||
|
||||
var rowIndex = [rowIndexes count],
|
||||
items = [];
|
||||
|
||||
while (rowIndex--)
|
||||
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
|
||||
while (index !== CPNotFound)
|
||||
{
|
||||
[items addObject:[_outlineView itemAtRow:index]]
|
||||
index = [theIndexes indexGreaterThanIndex:index];
|
||||
}
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||
}
|
||||
@@ -1704,6 +1723,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
|
||||
}
|
||||
|
||||
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldSortDescriptors
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDataSourceMethods &
|
||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_))
|
||||
{
|
||||
[[_outlineView dataSource] outlineView:_outlineView sortDescriptorsDidChange:oldSortDescriptors];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPOutlineViewTableViewDelegate : CPObject
|
||||
@@ -1777,6 +1805,17 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aTableColumn row:(int)aRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_menuForTableColumn_item_))
|
||||
{
|
||||
var item = [_outlineView itemAtRow:aRow];
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView menuForTableColumn:aTableColumn item:item]
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDisclosureButton : CPButton
|
||||
|
||||
+9
-15
@@ -86,10 +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];
|
||||
@@ -195,11 +192,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
*/
|
||||
- (void)removeAllItems
|
||||
{
|
||||
var menu = [self menu],
|
||||
count = [menu numberOfItems];
|
||||
|
||||
while (count--)
|
||||
[menu removeItemAtIndex:0];
|
||||
[[self menu] removeAllItems];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -402,9 +395,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
*/
|
||||
- (CPMenuItem)itemWithTitle:(CPString)aTitle
|
||||
{
|
||||
var menu = [self menu];
|
||||
var menu = [self menu],
|
||||
itemIndex = [menu indexOfItemWithTitle:aTitle];
|
||||
|
||||
return [menu itemAtIndex:[menu indexOfItemWithTitle:aTitle]];
|
||||
if (itemIndex === CPNotFound)
|
||||
return nil;
|
||||
|
||||
return [menu itemAtIndex:itemIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -810,10 +807,7 @@ var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
[self setObjectValue:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonSelectedIndexKey]];
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
@@ -464,3 +464,41 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPProgressIndicator (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
|
||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
||||
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
||||
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
|
||||
_style = [aCoder decodeObjectForKey:@"_style"];
|
||||
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
||||
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
||||
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[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:_isAnimating forKey:@"_isAnimating"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+12
-5
@@ -231,11 +231,18 @@ CPDeleteForwardKeyCode = 46;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME This description is bad.
|
||||
Based on \c anEvent, the receiver should simulate the event.
|
||||
@param anEvent the event to simulate
|
||||
@return \c YES if the event receiver simulated the event
|
||||
/*!
|
||||
Overridden by subclasses to handle a key equivalent.
|
||||
|
||||
If the character code or codes in \c anEvent match the receiver’s key equivalent,
|
||||
the receiver should respond to the event and return \c YES. The default implementation
|
||||
does nothing and returns \c NO.
|
||||
|
||||
You should extract the characters for a key equivalent using
|
||||
\ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]".
|
||||
|
||||
@param anEvent An event object that represents the key equivalent pressed
|
||||
@return \c YES if theEvent is a key equivalent that the receiver handled, \c NO if it is not a key equivalent that it should handle.
|
||||
*/
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
|
||||
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
* CPPredicateEditor.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
|
||||
*/
|
||||
|
||||
@import "CPRuleEditor.j"
|
||||
@import "_CPPredicateEditorTree.j"
|
||||
@import "_CPPredicateEditorRowNode.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
|
||||
@implementation CPPredicateEditor : CPRuleEditor
|
||||
{
|
||||
CPArray _allTemplates;
|
||||
CPArray _rootTrees;
|
||||
CPArray _rootHeaderTrees;
|
||||
id _predicateTarget @accessors(property=target);
|
||||
SEL _predicateAction @accessors(property=action);
|
||||
}
|
||||
|
||||
#pragma mark public methods
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPredicateEditor
|
||||
|
||||
@brief CPPredicateEditor is a subclass of CPRuleEditor that is specialized for editing CPPredicate objects.
|
||||
|
||||
CPPredicateEditor provides a CPPredicate property—objectValue (inherited from CPControl)—that you can get and set directly, and that you can bind using bindings (you typically configure a predicate editor in Interface Builder). CPPredicateEditor depends on another class, CPPredicateEditorRowTemplate, that describes the available predicates and how to display them.
|
||||
|
||||
Unlike CPRuleEditor, CPPredicateEditor does not depend on its delegate to populate its rows (and does not call the populating delegate methods). Instead, its rows are populated from its objectValue property (an instance of CPPredicate). CPPredicateEditor relies on instances CPPredicateEditorRowTemplate, which are responsible for mapping back and forth between the displayed view values and various predicates.
|
||||
|
||||
CPPredicateEditor exposes one property, rowTemplates, which is an array of CPPredicateEditorRowTemplate objects.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Returns the row templates for the receiver.
|
||||
@return The row templates for the receiver.
|
||||
@discussion Until otherwise set, this contains a single compound CPPredicateEditorRowTemplate object.
|
||||
@see setRowTemplates:
|
||||
*/
|
||||
- (CPArray)rowTemplates
|
||||
{
|
||||
return _allTemplates;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Sets the row templates for the receiver.
|
||||
@param rowTemplates An array of CPPredicateEditorRowTemplate objects.
|
||||
@see rowTemplates
|
||||
*/
|
||||
- (void)setRowTemplates:(id)rowTemplates
|
||||
{
|
||||
if (_allTemplates == rowTemplates)
|
||||
return;
|
||||
|
||||
_allTemplates = rowTemplates;
|
||||
|
||||
[self _updateItemsByCompoundTemplates];
|
||||
[self _updateItemsBySimpleTemplates];
|
||||
|
||||
if ([self numberOfRows] > 0)
|
||||
{
|
||||
var predicate = [super predicate];
|
||||
[self _reflectPredicate:predicate];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @cond */
|
||||
- (void)_initRuleEditorShared
|
||||
{
|
||||
[super _initRuleEditorShared];
|
||||
|
||||
_rootTrees = [CPArray array];
|
||||
_rootHeaderTrees = [CPArray array];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
if (self != nil)
|
||||
{
|
||||
var initialTemplate = [[CPPredicateEditorRowTemplate alloc] initWithCompoundTypes:[CPAndPredicateType, CPOrPredicateType]];
|
||||
_allTemplates = [CPArray arrayWithObject:initialTemplate];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)objectValue
|
||||
{
|
||||
return [super predicate];
|
||||
}
|
||||
|
||||
- (void)_updateItemsBySimpleTemplates
|
||||
{
|
||||
var templates = [CPMutableArray array],
|
||||
count = [_allTemplates count],
|
||||
t;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var t = _allTemplates[count];
|
||||
if ([t _rowType] == CPRuleEditorRowTypeSimple)
|
||||
[templates insertObject:t atIndex:0];
|
||||
}
|
||||
|
||||
var trees = [self _constructTreesForTemplates:templates];
|
||||
if ([trees count] > 0)
|
||||
_rootTrees = [self _mergeTree:trees];
|
||||
}
|
||||
|
||||
- (void)_updateItemsByCompoundTemplates
|
||||
{
|
||||
var templates = [CPMutableArray array],
|
||||
count = [_allTemplates count],
|
||||
t;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var t = _allTemplates[count];
|
||||
if ([t _rowType] == CPRuleEditorRowTypeCompound)
|
||||
[templates insertObject:t atIndex:0];
|
||||
}
|
||||
|
||||
var trees = [self _constructTreesForTemplates:templates];
|
||||
if ([trees count] > 0)
|
||||
_rootHeaderTrees = [self _mergeTree:trees];
|
||||
}
|
||||
|
||||
- (CPArray)_constructTreesForTemplates:(id)templates
|
||||
{
|
||||
var trees = [CPMutableArray array],
|
||||
count = [templates count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var tree = [self _constructTreeForTemplate:templates[i]];
|
||||
[trees addObjectsFromArray:tree];
|
||||
}
|
||||
|
||||
return trees;
|
||||
}
|
||||
|
||||
- (id)_mergeTree:(id)tree
|
||||
{
|
||||
var merged = [CPMutableArray array],
|
||||
titles = [CPMutableArray array],
|
||||
count = [tree count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var t = tree[i],
|
||||
title = [CPString stringWithString:[t title]];
|
||||
|
||||
if ([titles containsObject:title])
|
||||
{
|
||||
CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
|
||||
continue;
|
||||
}
|
||||
|
||||
[merged addObject:t];
|
||||
[titles addObject:title];
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
- (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
|
||||
{
|
||||
var tree = [CPArray array],
|
||||
templateViews = [aTemplate templateViews],
|
||||
count = [templateViews count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var children = [CPArray array],
|
||||
itemsCount = 0,
|
||||
menuIndex = -1,
|
||||
itemsArray,
|
||||
|
||||
templateView = [templateViews objectAtIndex:count],
|
||||
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
|
||||
|
||||
if (isPopup)
|
||||
{
|
||||
itemArray = [[templateView itemArray] valueForKey:@"title"];
|
||||
itemsCount = [itemArray count],
|
||||
menuIndex = 0;
|
||||
}
|
||||
|
||||
for (; menuIndex < itemsCount; menuIndex++)
|
||||
{
|
||||
var item = [_CPPredicateEditorTree new];
|
||||
[item setIndexIntoTemplate:count];
|
||||
[item setTemplate:aTemplate];
|
||||
[item setMenuItemIndex:menuIndex];
|
||||
if (isPopup)
|
||||
[item setTitle:[itemArray objectAtIndex:menuIndex]];
|
||||
|
||||
[children addObject:item];
|
||||
}
|
||||
|
||||
[children makeObjectsPerformSelector:@selector(setChildren:) withObject:tree];
|
||||
tree = children;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
#pragma mark Set the Predicate
|
||||
|
||||
- (void)setObjectValue:(id)objectValue
|
||||
{
|
||||
if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
|
||||
[self _reflectPredicate:objectValue];
|
||||
}
|
||||
|
||||
- (void)_reflectPredicate:(id)predicate
|
||||
{
|
||||
var animation = _currentAnimation;
|
||||
_currentAnimation = nil;
|
||||
|
||||
if (predicate != nil)
|
||||
{
|
||||
if ((_nestingMode == CPRuleEditorNestingModeSimple || _nestingMode == CPRuleEditorNestingModeCompound)
|
||||
&& [predicate isKindOfClass:[CPComparisonPredicate class]])
|
||||
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:[CPArray arrayWithObject:predicate]];
|
||||
|
||||
var row = [self _rowObjectFromPredicate:predicate];
|
||||
if (row != nil)
|
||||
[_boundArrayOwner setValue:[CPArray arrayWithObject:row] forKey:_boundArrayKeyPath];
|
||||
}
|
||||
|
||||
[self setAnimation:animation];
|
||||
}
|
||||
|
||||
- (id)_rowObjectFromPredicate:(CPPredicate)predicate
|
||||
{
|
||||
var quality, // TODO: We should use this ref somewhere !
|
||||
type,
|
||||
matchedTemplate = [CPPredicateEditorRowTemplate _bestMatchForPredicate:predicate inTemplates:[self rowTemplates] quality:quality];
|
||||
|
||||
if (matchedTemplate == nil)
|
||||
return nil;
|
||||
|
||||
var copyTemplate = [matchedTemplate copy],
|
||||
subpredicates = [matchedTemplate displayableSubpredicatesOfPredicate:predicate];
|
||||
|
||||
if (subpredicates == nil)
|
||||
{
|
||||
[copyTemplate _setComparisonPredicate:predicate];
|
||||
type = CPRuleEditorRowTypeSimple;
|
||||
}
|
||||
else
|
||||
{
|
||||
[copyTemplate _setCompoundPredicate:predicate];
|
||||
type = CPRuleEditorRowTypeCompound;
|
||||
}
|
||||
|
||||
var row = [self _rowFromTemplate:copyTemplate originalTemplate:matchedTemplate withRowType:type];
|
||||
|
||||
if (subpredicates == nil)
|
||||
return row;
|
||||
|
||||
var count = [subpredicates count],
|
||||
subrows = [CPMutableArray array];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var subrow = [self _rowObjectFromPredicate:subpredicates[i]];
|
||||
if (subrow != nil)
|
||||
[subrows addObject:subrow];
|
||||
}
|
||||
|
||||
[row setValue:subrows forKey:[super subrowsKeyPath]];
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
- (id)_rowFromTemplate:(CPPredicateEditorRowTemplate)aTemplate originalTemplate:(CPPredicateEditorRowTemplate)originalTemplate withRowType:(CPRuleEditorRowType)rowType
|
||||
{
|
||||
var criteria = [CPArray array],
|
||||
values = [CPArray array],
|
||||
templateViews = [aTemplate templateViews],
|
||||
rootItems,
|
||||
count;
|
||||
|
||||
rootItems = (rowType == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
|
||||
|
||||
while ((count = [rootItems count]) > 0)
|
||||
{
|
||||
var treeChild;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
treeChild = [rootItems objectAtIndex:i];
|
||||
|
||||
var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
|
||||
menuItemIndex = [treeChild menuItemIndex];
|
||||
|
||||
if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
|
||||
{
|
||||
var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
|
||||
[node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
|
||||
|
||||
[criteria addObject:node];
|
||||
[values addObject:[node displayValue]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rootItems = [treeChild children];
|
||||
}
|
||||
|
||||
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
#pragma mark Get the predicate
|
||||
|
||||
- (void)_updatePredicate
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[self _updatePredicateFromRows];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
- (void)_updatePredicateFromRows
|
||||
{
|
||||
var rootRowsArray = [super _rootRowsArray],
|
||||
subpredicates = [CPMutableArray array],
|
||||
count = count2 = [rootRowsArray count],
|
||||
predicate;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var item = [rootRowsArray objectAtIndex:count],
|
||||
subpredicate = [self _predicateFromRowItem:item];
|
||||
|
||||
if (subpredicate != nil)
|
||||
[subpredicates insertObject:subpredicate atIndex:0];
|
||||
}
|
||||
|
||||
if (_nestingMode != CPRuleEditorNestingModeList && count2 == 1)
|
||||
predicate = [subpredicates lastObject];
|
||||
else
|
||||
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
|
||||
|
||||
[super _setPredicate:predicate];
|
||||
}
|
||||
|
||||
- (id)_predicateFromRowItem:(id)rowItem
|
||||
{
|
||||
var subpredicates = [CPArray array],
|
||||
rowType = [rowItem valueForKey:_typeKeyPath];
|
||||
|
||||
if (rowType == CPRuleEditorRowTypeCompound)
|
||||
{
|
||||
var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
|
||||
count = [subrows count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var subrow = [subrows objectAtIndex:i];
|
||||
var predicate = [self _predicateFromRowItem:subrow];
|
||||
[subpredicates addObject:predicate];
|
||||
}
|
||||
}
|
||||
|
||||
var criteria = [rowItem valueForKey:_itemsKeyPath],
|
||||
displayValues = [rowItem valueForKey:_valuesKeyPath],
|
||||
count = [criteria count],
|
||||
lastItem = [criteria lastObject],
|
||||
template = [lastItem templateForRow],
|
||||
templateViews = [template templateViews];
|
||||
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
var view = [templateViews objectAtIndex:j],
|
||||
value = [displayValues objectAtIndex:j];
|
||||
[[criteria objectAtIndex:j] setTemplateViews:templateViews];
|
||||
|
||||
if ([view isKindOfClass:[CPPopUpButton class]])
|
||||
[view selectItemWithTitle:value];
|
||||
else if ([view respondsToSelector:@selector(setObjectValue:)])
|
||||
[view setObjectValue:[value objectValue]];
|
||||
}
|
||||
|
||||
return [template predicateWithSubpredicates:subpredicates];
|
||||
}
|
||||
|
||||
- (CPCompoundPredicateType)_compoundPredicateTypeForRootRows
|
||||
{
|
||||
return CPAndPredicateType;
|
||||
}
|
||||
|
||||
#pragma mark Control delegate
|
||||
|
||||
- (void)_sendRuleAction
|
||||
{
|
||||
[self _updatePredicate];
|
||||
[super _sendRuleAction];
|
||||
}
|
||||
|
||||
- (BOOL)_sendsActionOnIncompleteTextChange
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
- (void)_setDefaultTargetAndActionOnView:(CPView)view
|
||||
{
|
||||
if ([view isKindOfClass:[CPControl class]])
|
||||
{
|
||||
[view setTarget:self];
|
||||
[view setAction:@selector(_templateControlValueDidChange:)];
|
||||
}
|
||||
}
|
||||
- (void)_templateControlValueDidChange:(id)sender
|
||||
{
|
||||
}
|
||||
- (void)controlTextDidBeginEditing:(CPNotification)notification
|
||||
{
|
||||
}
|
||||
- (void)controlTextDidEndEditing:(CPNotification)notification
|
||||
{
|
||||
}
|
||||
- (void)controlTextDidChange:(CPNotification)notification
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
#pragma mark RuleEditor delegate methods
|
||||
|
||||
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
|
||||
{
|
||||
if (rowItem == nil)
|
||||
{
|
||||
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
|
||||
return [trees count];
|
||||
}
|
||||
return [[rowItem children] count];
|
||||
}
|
||||
|
||||
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
|
||||
{
|
||||
if (rowItem == nil)
|
||||
{
|
||||
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
|
||||
return [_CPPredicateEditorRowNode rowNodeFromTree:trees[childIndex]];
|
||||
}
|
||||
|
||||
return [[rowItem children] objectAtIndex:childIndex];
|
||||
}
|
||||
|
||||
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
|
||||
{
|
||||
return [rowItem displayValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
|
||||
@implementation CPPredicateEditor (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(id)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
if (self != nil)
|
||||
{
|
||||
var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
|
||||
if (nibTemplates != nil)
|
||||
[self setRowTemplates:nibTemplates];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*! @endcond */
|
||||
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* CPPredicateEditorRowTemplate.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
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
int _templateType @accessors(readwrite, getter=_templateType, setter=_setTemplateType:);
|
||||
unsigned _predicateOptions @accessors(readwrite, setter=_setOptions:);
|
||||
unsigned _predicateModifier @accessors(readwrite, setter=_setModifier:);
|
||||
unsigned _leftAttributeType @accessors(readwrite, getter=leftAttributeType, setter=_setLeftAttributeType:);
|
||||
unsigned _rightAttributeType @accessors(readwrite, getter=rightAttributeType, setter=_setRightAttributeType:);
|
||||
BOOL _leftIsWildcard @accessors(property=leftIsWildcard);
|
||||
BOOL _rightIsWildcard @accessors(property=rightIsWildcard);
|
||||
CPArray _views @accessors(setter=setTemplateViews:);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPredicateEditorRowTemplate
|
||||
|
||||
@brief CPPredicateEditorRowTemplate describes available predicates and how to display them.
|
||||
|
||||
You can create instances of CPPredicateEditorRowTemplate programmatically or in Interface Builder. By default, a non-compound row template has three views: a popup (or static text field) on the left, a popup or static text field for operators, and either a popup or other view on the right. You can subclass CPPredicateEditorRowTemplate to create a row template with different numbers or types of views.
|
||||
|
||||
CPPredicateEditorRowTemplate is a concrete class, but it has five primitive methods which are called by CPPredicateEditor: -#templateViews, -#matchForPredicate:, -#setPredicate:, -#displayableSubpredicatesOfPredicate:, and -#predicateWithSubpredicates:. CPPredicateEditorRowTemplate implements all of them, but you can override them for custom templates. The primitive methods are used by an instance of CPPredicateEditor as follows.
|
||||
|
||||
First, an instance of CPPredicateEditor is created, and some row templates are set on it—either through a nib file or programmatically. The first thing predicate editor does is ask each of the templates for their views, using templateViews.
|
||||
|
||||
After setting up the predicate editor, you typically send it a CPPredicateEditor#setObjectValue: message to restore a saved predicate. CPPredicateEditor needs to determine which of its templates should display each predicate in the predicate tree. It does this by sending each of its row templates a matchForPredicate: message and choosing the one that returns the highest value.
|
||||
|
||||
After finding the best match for a predicate, CPPredicateEditor copies that template to get fresh views, inserts them into the proper row, and then sets the predicate on the template using setPredicate:. Within that method, the CPPredicateEditorRowTemplate object must set its views' values to represent that predicate.
|
||||
|
||||
CPPredicateEditorRowTemplate next asks the template for the “displayable sub-predicates” of the predicate by sending a -#displayableSubpredicatesOfPredicate: message. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, it can return nil for this. Otherwise, it should return a list of predicates to be made into sub-rows of that template's row. The whole process repeats for each sub-predicate.
|
||||
|
||||
At this point, the user sees the predicate that was saved. If the user then makes some changes to the views of the templates, this causes CPPredicateEditor to recompute its predicate by asking each of the templates to return the predicate represented by the new view values, passing in the subpredicates represented by the sub-rows (an empty array if there are none, or nil if they aren't supported by that predicate type).
|
||||
*/
|
||||
|
||||
/*!
|
||||
@name Initializing a Template
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Initializes and returns a “pop-up-pop-up-pop-up”-style row template.
|
||||
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
|
||||
@param rightExpressions An array of CPExpression objects that represent the right hand side of a predicate.
|
||||
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
|
||||
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
|
||||
@param options Options for the predicate (see @c CPComparisonPredicateOptions for possible values).
|
||||
@return A row template of the “pop-up-pop-up-pop-up”-form, with the left and right popups representing the left and right expression arrays -#leftExpressions and -#rightExpressions, and the center popup representing the operators.
|
||||
*/
|
||||
- (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_templateType = 1;
|
||||
_leftIsWildcard = NO;
|
||||
_rightIsWildcard = NO;
|
||||
_leftAttributeType = 0;
|
||||
_rightAttributeType = 0;
|
||||
_predicateModifier = modifier;
|
||||
_predicateOptions = options;
|
||||
|
||||
var leftView = [self _viewFromExpressions:leftExpressions],
|
||||
rightView = [self _viewFromExpressions:rightExpressions],
|
||||
middleView = [self _viewFromOperatorTypes:operators];
|
||||
|
||||
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Initializes and returns a “pop-up-pop-up-view”-style row template.
|
||||
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
|
||||
@param attributeType An attribute type for the right hand side of a predicate. This value dictates the type of view created, and how the control’s object value is coerced before putting it into a predicate.
|
||||
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
|
||||
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
|
||||
@param options Options for the predicate (see CPComparisonPredicateOptions for possible values).
|
||||
@return A row template initialized using the given arguments.
|
||||
*/
|
||||
- (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
var leftView = [self _viewFromExpressions:leftExpressions],
|
||||
middleView = [self _viewFromOperatorTypes:operators],
|
||||
rightView = [self _viewFromAttributeType:attributeType];
|
||||
|
||||
_templateType = 1;
|
||||
_leftIsWildcard = NO;
|
||||
_rightIsWildcard = YES;
|
||||
_leftAttributeType = 0;
|
||||
_rightAttributeType = attributeType;
|
||||
_predicateModifier = modifier;
|
||||
_predicateOptions = options;
|
||||
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Initializes and returns a row template suitable for displaying compound predicates.
|
||||
@param compoundTypes An array of CPNumber objects specifying compound predicate types. See @c CPCompoundPredicateTypes for possible values.
|
||||
@return A row template initialized for displaying compound predicates of the types specified by @a compoundTypes.
|
||||
@discussion CPPredicateEditor contains such a template by default.
|
||||
*/
|
||||
- (id)initWithCompoundTypes:(CPArray )compoundTypes
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
var leftView = [self _viewFromCompoundTypes:compoundTypes],
|
||||
rightView = [[CPPopUpButton alloc] init];
|
||||
|
||||
[rightView addItemWithTitle:@"of the following are true"];
|
||||
|
||||
_templateType = 2;
|
||||
_leftIsWildcard = NO;
|
||||
_rightIsWildcard = NO;
|
||||
_rightAttributeType = 0;
|
||||
_views = [[CPArray alloc] initWithObjects:leftView, rightView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
@name Primitive Methods
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Returns a positive number if the receiver can represent a given predicate, and 0 if it cannot.
|
||||
@return A positive number if the template can represent predicate, and @c 0 if it cannot.
|
||||
@discussion By default, returns values in the range @c 0 to @c 1.
|
||||
The highest match among all the templates determines which template is responsible for displaying the predicate. You can override this to determine which predicates your custom template handles.
|
||||
*/
|
||||
- (double)matchForPredicate:(CPPredicate)predicate
|
||||
{
|
||||
// How exactly this value (float 0-1) is computed ?
|
||||
if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
|
||||
{
|
||||
if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
|
||||
return 1;
|
||||
}
|
||||
else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
|
||||
{
|
||||
if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
|
||||
return 0;
|
||||
|
||||
if (![[self operators] containsObject:[predicate predicateOperatorType]])
|
||||
return 0;
|
||||
|
||||
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]]) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the views for the receiver.
|
||||
@return The views for the receiver.
|
||||
@discussion Instances of CPPopUpButton are treated specially by CPPredicateEditor; their menu items are merged into a single popup button, and matching menu item titles are combined. In this way, a single tree is built from the separate templates.
|
||||
*/
|
||||
- (CPArray)templateViews
|
||||
{
|
||||
return _views;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Sets the value of the views according to the given predicate.
|
||||
@param predicate The predicate value for the receiver.
|
||||
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
|
||||
|
||||
You can override this to set the values of custom views.
|
||||
*/
|
||||
- (void)setPredicate:(CPPredicate)predicate
|
||||
{
|
||||
if (_templateType == 2)
|
||||
[self _setCompoundPredicate:predicate];
|
||||
else
|
||||
[self _setComparisonPredicate:predicate];
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the subpredicates that should be made sub-rows of a given predicate.
|
||||
@param predicate A predicate object.
|
||||
@return The subpredicates that should be made sub-rows of @a predicate. For compound predicates (instances of CPCompoundPredicate), the array of subpredicates; for other types of predicate, returns @c nil. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, returns @c nil.
|
||||
@discussion You can override this method to create custom templates that handle complicated compound predicates.
|
||||
*/
|
||||
- (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
|
||||
{
|
||||
if ([predicate isKindOfClass:[CPCompoundPredicate class]])
|
||||
{
|
||||
var subpredicates = [predicate subpredicates];
|
||||
if ([subpredicates count] == 0)
|
||||
return nil;
|
||||
|
||||
return subpredicates;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the predicate represented by the receiver’s views' values and the given sub-predicates.
|
||||
@param subpredicates An array of predicates.
|
||||
@return The predicate represented by the values of the template's views and the given @a subpredicates. You can override this method to return the predicate represented by your custom views.
|
||||
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
|
||||
|
||||
You can override this method to return the predicate represented by a custom view.
|
||||
*/
|
||||
- (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
|
||||
{
|
||||
if (_templateType == 2)
|
||||
{
|
||||
var type = [[_views[0] selectedItem] representedObject];
|
||||
return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
|
||||
}
|
||||
|
||||
if (_templateType == 1)
|
||||
{
|
||||
var lhs = [self _leftExpression],
|
||||
rhs = [self _rightExpression],
|
||||
operator = [[_views[1] selectedItem] representedObject];
|
||||
|
||||
return [CPComparisonPredicate predicateWithLeftExpression:lhs
|
||||
rightExpression:rhs
|
||||
modifier:[self modifier]
|
||||
type:operator
|
||||
options:[self options]];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@name Information About a Row Template
|
||||
*/
|
||||
|
||||
/*!
|
||||
@brief Returns the left hand expressions for the receiver.
|
||||
@return The left hand expressions for the receiver.
|
||||
*/
|
||||
- (CPArray)leftExpressions
|
||||
{
|
||||
if (_templateType ==1 && !_leftIsWildcard)
|
||||
{
|
||||
var view = [_views objectAtIndex:0];
|
||||
return [[view itemArray] valueForKey:@"representedObject"];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the right hand expressions for the receiver.
|
||||
@return The right hand expressions for the receiver.
|
||||
*/
|
||||
- (CPArray)rightExpressions
|
||||
{
|
||||
if (_templateType == 1 && !_rightIsWildcard)
|
||||
{
|
||||
var view = [_views objectAtIndex:2];
|
||||
return [[view itemArray] valueForKey:@"representedObject"];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the compound predicate types for the receiver.
|
||||
@return An array of CPNumber objects specifying compound predicate types. See @c CompoundPredicateTypes for possible values.
|
||||
*/
|
||||
- (CPArray)compoundTypes
|
||||
{
|
||||
if (_templateType == 2)
|
||||
{
|
||||
var view = [_views objectAtIndex:0];
|
||||
return [[view itemArray] valueForKey:@"representedObject"];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the comparison predicate modifier for the receiver.
|
||||
@return The comparison predicate modifier for the receiver.
|
||||
*/
|
||||
- (CPComparisonPredicateModifier)modifier
|
||||
{
|
||||
if (_templateType == 1)
|
||||
return _predicateModifier;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns Returns the array of operators for the receiver.
|
||||
@return The array of operators for the receiver.
|
||||
*/
|
||||
- (CPArray)operators
|
||||
{
|
||||
if (_templateType == 1)
|
||||
{
|
||||
var view = [_views objectAtIndex:1];
|
||||
return [[view itemArray] valueForKey:@"representedObject"];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the comparison predicate options for the receiver.
|
||||
@return The comparison predicate options for the receiver. See @c CPComparisonPredicateOptions for possible values. Returns @c 0 if this does not apply (for example, for a compound template initialized with -#initWithCompoundTypes:).
|
||||
*/
|
||||
- (int)options
|
||||
{
|
||||
if (_templateType == 1)
|
||||
return _predicateOptions;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the attribute type of the receiver’s right expression.
|
||||
@return The attribute type of the receiver’s right expression.
|
||||
*/
|
||||
- (CPAttributeType)rightExpressionAttributeType
|
||||
{
|
||||
return _rightAttributeType;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Returns the attribute type of the receiver’s left expression.
|
||||
@return The attribute type of the receiver’s left expression.
|
||||
*/
|
||||
- (CPAttributeType)leftExpressionAttributeType
|
||||
{
|
||||
return _leftAttributeType;
|
||||
}
|
||||
|
||||
/*! @cond */
|
||||
+ (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
|
||||
{
|
||||
var count = [templates count],
|
||||
match_value = 0,
|
||||
templateIndex = CPNotFound,
|
||||
i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
var template = [templates objectAtIndex:i],
|
||||
amatch = [template matchForPredicate:predicate];
|
||||
|
||||
if (amatch > match_value)
|
||||
{
|
||||
templateIndex = i;
|
||||
match_value = amatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (templateIndex == CPNotFound)
|
||||
{
|
||||
[CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [templates objectAtIndex:templateIndex];
|
||||
}
|
||||
|
||||
- (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
|
||||
{
|
||||
var left = [_views objectAtIndex:0],
|
||||
type = [predicate compoundPredicateType],
|
||||
index = [left indexOfItemWithRepresentedObject:type];
|
||||
|
||||
[left selectItemAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
|
||||
{
|
||||
var left = [_views objectAtIndex:0],
|
||||
middle = [_views objectAtIndex:1],
|
||||
right = [_views objectAtIndex:2],
|
||||
leftExpression = [predicate leftExpression],
|
||||
rightExpression = [predicate rightExpression],
|
||||
operator = [predicate predicateOperatorType];
|
||||
|
||||
if (_leftIsWildcard)
|
||||
[left setObjectValue:[leftExpression constantValue]];
|
||||
else
|
||||
{
|
||||
var index = [left indexOfItemWithRepresentedObject:leftExpression];
|
||||
[left selectItemAtIndex:index];
|
||||
}
|
||||
|
||||
var op_index = [middle indexOfItemWithRepresentedObject:operator];
|
||||
[middle selectItemAtIndex:op_index];
|
||||
|
||||
if (_rightIsWildcard)
|
||||
[right setObjectValue:[rightExpression constantValue]];
|
||||
else
|
||||
{
|
||||
var index = [right indexOfItemWithRepresentedObject:rightExpression];
|
||||
[right selectItemAtIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPExpression)_leftExpression
|
||||
{
|
||||
return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
|
||||
}
|
||||
|
||||
- (CPExpression)_rightExpression
|
||||
{
|
||||
return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
|
||||
{
|
||||
if (attributeType == 0)
|
||||
return [[aView selectedItem] representedObject];
|
||||
|
||||
var value;
|
||||
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
|
||||
value = [aView intValue];
|
||||
else if (attributeType == CPBooleanAttributeType)
|
||||
value = [aView state];
|
||||
else
|
||||
value = [aView stringValue];
|
||||
|
||||
return [CPExpression expressionForConstantValue:value];
|
||||
}
|
||||
|
||||
- (int)_rowType
|
||||
{
|
||||
return (_templateType - 1);
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
|
||||
}
|
||||
|
||||
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
|
||||
{
|
||||
var operators_array = [CPMutableArray array];
|
||||
|
||||
switch (attributeType)
|
||||
{
|
||||
case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
|
||||
break;
|
||||
case CPBooleanAttributeType : [operators_array addObjects:4,5];
|
||||
break;
|
||||
case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
|
||||
break;
|
||||
default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
|
||||
break;
|
||||
}
|
||||
|
||||
return operators_array;
|
||||
}
|
||||
|
||||
- (int)_templateType
|
||||
{
|
||||
return _templateType;
|
||||
}
|
||||
|
||||
- (id)_displayValueForPredicateOperator:(int)operator
|
||||
{
|
||||
var value;
|
||||
|
||||
switch (operator)
|
||||
{
|
||||
case CPLessThanPredicateOperatorType : value = @"is less than";
|
||||
break;
|
||||
case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
|
||||
break;
|
||||
case CPGreaterThanPredicateOperatorType : value = @"is greater than";
|
||||
break;
|
||||
case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
|
||||
break;
|
||||
case CPEqualToPredicateOperatorType : value = @"is";
|
||||
break;
|
||||
case CPNotEqualToPredicateOperatorType : value = @"is not";
|
||||
break;
|
||||
case CPMatchesPredicateOperatorType : value = @"matches";
|
||||
break;
|
||||
case CPLikePredicateOperatorType : value = @"is like";
|
||||
break;
|
||||
case CPBeginsWithPredicateOperatorType : value = @"begins with";
|
||||
break;
|
||||
case CPEndsWithPredicateOperatorType : value = @"ends with";
|
||||
break;
|
||||
case CPInPredicateOperatorType : value = @"in";
|
||||
break;
|
||||
case CPContainsPredicateOperatorType : value = @"contains";
|
||||
break;
|
||||
case CPBetweenPredicateOperatorType : value = @"between";
|
||||
break;
|
||||
default : CPLogConsole(@"unknown predicate operator %d" + operator);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
|
||||
{
|
||||
var value;
|
||||
switch (predicateType)
|
||||
{
|
||||
case CPNotPredicateType: value = @"None";
|
||||
break;
|
||||
case CPAndPredicateType: value = @"All";
|
||||
break;
|
||||
case CPOrPredicateType: value = @"Any";
|
||||
break;
|
||||
default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (id)_displayValueForConstantValue:(id)value
|
||||
{
|
||||
return [value description]; // number, date, string, ... localize
|
||||
}
|
||||
|
||||
- (id)_displayValueForKeyPath:(CPString)keyPath
|
||||
{
|
||||
return keyPath; // localize
|
||||
}
|
||||
|
||||
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
|
||||
{
|
||||
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
|
||||
count = [expressions count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var exp = expressions[i],
|
||||
type = [exp expressionType],
|
||||
title;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
|
||||
break;
|
||||
case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
|
||||
break;
|
||||
default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
|
||||
break;
|
||||
}
|
||||
|
||||
var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
[item setRepresentedObject:exp];
|
||||
[popup addItem:item];
|
||||
}
|
||||
|
||||
[popup sizeToFit];
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
- (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
|
||||
{
|
||||
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
|
||||
count = [operators count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var op = operators[i],
|
||||
title = [self _displayValueForPredicateOperator:op],
|
||||
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
|
||||
[item setRepresentedObject:op];
|
||||
[popup addItem:item];
|
||||
}
|
||||
|
||||
[popup sizeToFit];
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
- (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
|
||||
{
|
||||
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
|
||||
count = [compoundTypes count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var type = compoundTypes[i],
|
||||
title = [self _displayValueForCompoundPredicateType:type],
|
||||
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
|
||||
[item setRepresentedObject:type];
|
||||
[popup addItem:item];
|
||||
}
|
||||
|
||||
[popup sizeToFit];
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
- (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
|
||||
{
|
||||
var view;
|
||||
|
||||
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
|
||||
{
|
||||
view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
|
||||
}
|
||||
else if (attributeType == CPStringAttributeType)
|
||||
{
|
||||
view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
|
||||
}
|
||||
else if (attributeType == CPBooleanAttributeType)
|
||||
{
|
||||
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
|
||||
}
|
||||
else if (attributeType == CPDateAttributeType)
|
||||
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
|
||||
else
|
||||
return nil;
|
||||
|
||||
[view setTag:attributeType];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
- (CPTextField)_textFieldWithFrame:(CGRect)frame
|
||||
{
|
||||
var textField = [[CPTextField alloc] initWithFrame:frame];
|
||||
[textField setBezeled:YES];
|
||||
[textField setBezelStyle:CPTextFieldSquareBezel];
|
||||
[textField setBordered:YES];
|
||||
[textField setEditable:YES];
|
||||
[textField setFont:[CPFont systemFontOfSize:10]];
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
- (void)_setOptions:(unsigned int)options
|
||||
{
|
||||
_predicateOptions = options;
|
||||
}
|
||||
|
||||
- (void)_setModifier:(unsigned int)modifier
|
||||
{
|
||||
_predicateModifier = modifier;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
if (_templateType == 2)
|
||||
return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
|
||||
else if (_templateType == 1 && _rightIsWildcard)
|
||||
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
|
||||
else
|
||||
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
|
||||
}
|
||||
|
||||
/*
|
||||
- (void)_setLeftExpressionObject:(id)object
|
||||
{
|
||||
}
|
||||
- (void)_setRightExpressionObject:(id)object
|
||||
{
|
||||
}
|
||||
- (BOOL)_predicateIsNoneAreTrue:(id)predicate
|
||||
{
|
||||
}
|
||||
- (id)_viewFromExpressionObject:(id)object
|
||||
{
|
||||
}
|
||||
*/
|
||||
@end
|
||||
|
||||
var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
|
||||
CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
|
||||
CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
|
||||
CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
|
||||
CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
|
||||
CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
|
||||
CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
|
||||
CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
|
||||
|
||||
@implementation CPPredicateEditorRowTemplate (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
|
||||
_predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
|
||||
_predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
|
||||
_leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
|
||||
_rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
|
||||
_leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
|
||||
_rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
|
||||
_views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
|
||||
|
||||
// In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
|
||||
// So we need to regenerate expressions from titles.
|
||||
if (_templateType == 1 && _leftIsWildcard == NO)
|
||||
{
|
||||
var itemArray = [_views[0] itemArray],
|
||||
count = [itemArray count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = itemArray[i];
|
||||
if ([item representedObject] == nil)
|
||||
{
|
||||
var exp = [CPExpression expressionForKeyPath:[item title]];
|
||||
[item setRepresentedObject:exp];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
|
||||
[coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
|
||||
[coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
|
||||
[coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
|
||||
[coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
|
||||
[coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
|
||||
[coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
|
||||
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
|
||||
}
|
||||
|
||||
@end
|
||||
/*! @endcond */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@class _CPPredicateEditorTree;
|
||||
@implementation _CPPredicateEditorRowNode : CPObject
|
||||
{
|
||||
_CPPredicateEditorTree tree @accessors;
|
||||
CPMutableArray templateViews @accessors;
|
||||
CPMutableArray copiedTemplateContainer @accessors;
|
||||
CPArray children @accessors(copy);
|
||||
}
|
||||
|
||||
+ (id)rowNodeFromTree:(id)aTree
|
||||
{
|
||||
var mapTable = {};
|
||||
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:mapTable];
|
||||
}
|
||||
|
||||
+ (id)_rowNodeFromTree:(id)aTree withTemplateTable:(id)templateTable
|
||||
{
|
||||
var node,
|
||||
views,
|
||||
copiedContainer;
|
||||
|
||||
node = [[_CPPredicateEditorRowNode alloc] init];
|
||||
node.tree = aTree;
|
||||
|
||||
var template = [aTree template],
|
||||
uuid = [template UID];
|
||||
|
||||
var cachedNode = templateTable[uuid];
|
||||
|
||||
if (cachedNode == nil)
|
||||
{
|
||||
views = [CPMutableArray array];
|
||||
copiedContainer = [CPMutableArray array];
|
||||
templateTable[uuid] = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
views = [cachedNode templateViews];
|
||||
copiedContainer = [cachedNode copiedTemplateContainer];
|
||||
}
|
||||
|
||||
node.templateViews = views;
|
||||
node.copiedTemplateContainer = copiedContainer;
|
||||
|
||||
var nodeChildren = [CPMutableArray array],
|
||||
treeChildren = [aTree children],
|
||||
count = [treeChildren count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var treeChild = treeChildren[i],
|
||||
child = [_CPPredicateEditorRowNode _rowNodeFromTree:treeChild withTemplateTable:templateTable];
|
||||
|
||||
[nodeChildren addObject:child];
|
||||
}
|
||||
|
||||
[node setChildren:nodeChildren];
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
- (BOOL)applyTemplate:(id)template withViews:(id)views forOriginalTemplate:(id)originalTemplate
|
||||
{
|
||||
var t = [tree template];
|
||||
if (t !== template)
|
||||
{
|
||||
[templateViews setArray:views];
|
||||
[copiedTemplateContainer removeAllObjects];
|
||||
[copiedTemplateContainer addObject:template];
|
||||
}
|
||||
|
||||
var count = [children count];
|
||||
for (var i; i < count; i++)
|
||||
[children[i] applyTemplate:template withViews:views forOriginalTemplate:originalTemplate];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)node
|
||||
{
|
||||
if (![node isKindOfClass:[_CPPredicateEditorRowNode class]])
|
||||
return NO;
|
||||
|
||||
return (tree === [node tree]);
|
||||
}
|
||||
|
||||
- (void)copyTemplateIfNecessary
|
||||
{
|
||||
if ([copiedTemplateContainer count] == 0)
|
||||
{
|
||||
CPLogConsole("COPYING TEMPLATE");
|
||||
var copy = [[tree template] copy];
|
||||
[copiedTemplateContainer addObject:copy];
|
||||
[templateViews addObjectsFromArray:[copy templateViews]];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPView)templateView
|
||||
{
|
||||
[self copyTemplateIfNecessary];
|
||||
return [templateViews objectAtIndex:[tree indexIntoTemplate]];
|
||||
}
|
||||
|
||||
- (id)templateForRow
|
||||
{
|
||||
[self copyTemplateIfNecessary];
|
||||
return [copiedTemplateContainer lastObject];
|
||||
}
|
||||
|
||||
- (CPString)title
|
||||
{
|
||||
return [tree title];
|
||||
}
|
||||
|
||||
- (id)displayValue
|
||||
{
|
||||
var title = [self title];
|
||||
if (title != nil)
|
||||
return title;
|
||||
|
||||
return [self templateView];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"<%@ %@ %@ tree:%@ tviews:%@", [self className],[self UID], [self title], [tree UID], [templateViews description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@implementation _CPPredicateEditorTree : CPObject
|
||||
{
|
||||
CPPredicateEditorRowTemplate template @accessors;
|
||||
CPString title @accessors(copy);
|
||||
CPArray children @accessors(copy);
|
||||
CPInteger indexIntoTemplate @accessors;
|
||||
CPInteger menuItemIndex @accessors;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
var tree = [[_CPPredicateEditorTree alloc] init];
|
||||
[tree setTemplate:template];
|
||||
[tree setTitle:title];
|
||||
[tree setMenuItemIndex:menuItemIndex];
|
||||
[tree setIndexIntoTemplate:indexIntoTemplate];
|
||||
[tree setChildren:children];
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"<%@: %p (%@) [%d-%d] T:%p at:%d> [\r%@\r]", [self className], self, title, indexIntoTemplate, menuItemIndex, template, [template rightExpressionAttributeType], children];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
|
||||
|
||||
@implementation _CPRuleEditorLocalizer : CPObject
|
||||
{
|
||||
CPDictionary _dictionary @accessors(property=dictionary);
|
||||
CPURLConnection connection;
|
||||
CPURLRequest resquest;
|
||||
}
|
||||
|
||||
- (void)loadContentOfURL:(CPURL)aURL
|
||||
{
|
||||
request = [CPURLRequest requestWithURL:aURL];
|
||||
connection = [CPURLConnection connectionWithRequest:request delegate:self];
|
||||
}
|
||||
|
||||
- (void)reloadIfNeeded
|
||||
{
|
||||
if (connection != nil) // Connection waiting
|
||||
{
|
||||
connection = nil;
|
||||
var data = [CPURLConnection sendSynchronousRequest:request returningResponse:NULL];
|
||||
[self loadContent:[data rawString]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
|
||||
{
|
||||
if (connection != nil && rawString != nil)
|
||||
[self loadContent:rawString];
|
||||
|
||||
connection = nil;
|
||||
}
|
||||
|
||||
- (void)loadContent:(CPString)aContent
|
||||
{
|
||||
var dict = [CPDictionary dictionary],
|
||||
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)
|
||||
[dict setObject:match[2] forKey:match[1]];
|
||||
}
|
||||
}
|
||||
|
||||
_dictionary = [CPDictionary dictionaryWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (CPString)localizedStringForString:(CPString)aString
|
||||
{
|
||||
[self reloadIfNeeded];
|
||||
|
||||
if (_dictionary != nil && aString != nil)
|
||||
{
|
||||
var localized = [_dictionary objectForKey:aString];
|
||||
if (localized != nil)
|
||||
return localized;
|
||||
}
|
||||
|
||||
return aString;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
var GRADIENT_NORMAL,
|
||||
GRADIENT_HIGHLIGHTED,
|
||||
IE_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#dfdfdf')";
|
||||
|
||||
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
|
||||
{
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
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))";
|
||||
}
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CPPoint)point
|
||||
{
|
||||
var slice = [self superview];
|
||||
if (!CPRectContainsPoint([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];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)theEvent
|
||||
{
|
||||
if (![self sliceIsEditable])
|
||||
return NO;
|
||||
|
||||
return [super trackMouse:theEvent];
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentRect = [super contentRectForBounds:bounds];
|
||||
contentRect.origin.x += radius;
|
||||
contentRect.size.width -= 2 * radius;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
radius = FLOOR(CGRectGetHeight([self bounds])/2);
|
||||
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
//style.webkitBorderRadius = radiusCSS;
|
||||
//style.mozBorderRadius = radiusCSS;
|
||||
style.borderRadius = radiusCSS;
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
var arrow_width = FLOOR(CGRectGetHeight(bounds)/3.5);
|
||||
|
||||
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
|
||||
|
||||
var arrowsPath = [CPBezierPath bezierPath];
|
||||
[arrowsPath moveToPoint:CGPointMake(0, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width/2, arrow_width + 1)];
|
||||
[arrowsPath closePath];
|
||||
|
||||
CGContextSetFillColor(context, [CPColor colorWithWhite:101/255 alpha:1]);
|
||||
[arrowsPath fill];
|
||||
|
||||
CGContextScaleCTM(context, 1 , -1);
|
||||
[arrowsPath fill];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPRuleEditorButton : CPButton
|
||||
{
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
radius = FLOOR(CGRectGetHeight([self bounds])/2);
|
||||
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
style.borderRadius = radiusCSS;
|
||||
style.backgroundImage = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@implementation _CPRuleEditorViewSlice : CPView
|
||||
{
|
||||
CPRuleEditor _ruleEditor;
|
||||
int _indentation @accessors(property=indentation);
|
||||
int _rowIndex @accessors(property=rowIndex);
|
||||
CPRect _animationTargetRect @accessors(property=_animationTargetRect);
|
||||
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
|
||||
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
|
||||
CPColor _backgroundColor @accessors(property=backgroundColor);
|
||||
}
|
||||
|
||||
- (void)removeFromSuperview
|
||||
{
|
||||
[super removeFromSuperview];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_ruleEditor = editor;
|
||||
_selected = NO;
|
||||
_lastSelected = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_setSelected:(BOOL)select
|
||||
{
|
||||
if (select == _selected)
|
||||
return;
|
||||
|
||||
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
|
||||
_selected = select;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds],
|
||||
maxX = CGRectGetWidth(bounds) - 2,
|
||||
maxY = CGRectGetHeight(bounds);
|
||||
|
||||
// Draw background
|
||||
if ([self _isSelected])
|
||||
_backgroundColor = [_ruleEditor _selectedRowColor];
|
||||
else
|
||||
{
|
||||
var colors = [_ruleEditor _backgroundColors],
|
||||
count = [colors count];
|
||||
_backgroundColor = [colors objectAtIndex:(_rowIndex % count)];
|
||||
}
|
||||
|
||||
CGContextSetFillColor(context, _backgroundColor);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
// Draw Top Border
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 1, 0);
|
||||
CGContextAddLineToPoint(context, maxX, 0);
|
||||
CGContextClosePath(context);
|
||||
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
// Draw Bottom Border
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 1, maxY - 0.5);
|
||||
CGContextAddLineToPoint(context, maxX, maxY - 0.5);
|
||||
CGContextClosePath(context);
|
||||
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
|
||||
CGContextSetStrokeColor(context, bottomColor);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)theEvent
|
||||
{
|
||||
if (editable)
|
||||
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)theEvent
|
||||
{
|
||||
if (editable)
|
||||
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
|
||||
}
|
||||
|
||||
/*
|
||||
- (void)rightMouseDown:(CPEvent)theEvent
|
||||
{
|
||||
[_ruleEditor _rightMouseDownOnSlice:self withEvent:theEvent];
|
||||
}
|
||||
*/
|
||||
|
||||
// =========
|
||||
// ! DEBUG
|
||||
// =========
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"<%@ %p index:%d indentation:%d>",[self className],self,[self rowIndex],[self indentation]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@import "_CPRuleEditorViewSlice.j"
|
||||
@import "_CPRuleEditorPopUpButton.j"
|
||||
@import "CPRuleEditor.j"
|
||||
|
||||
var CONTROL_HEIGHT = 16.,
|
||||
BUTTON_HEIGHT = 16.;
|
||||
|
||||
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
|
||||
{
|
||||
CPMutableArray _ruleOptionViews;
|
||||
CPMutableArray _ruleOptionFrames;
|
||||
CPMutableArray _correspondingRuleItems;
|
||||
CPMutableArray _ruleOptionInitialViewFrames;
|
||||
CPButton _addButton;
|
||||
CPButton _subtractButton;
|
||||
BOOL editable;
|
||||
CPRuleEditorRowType _rowType @accessors;
|
||||
CPRuleEditorRowType _plusButtonRowType;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
||||
{
|
||||
if (self = [super initWithFrame:frame ruleEditorView:editor])
|
||||
[self _initShared];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initShared
|
||||
{
|
||||
_correspondingRuleItems = [[CPMutableArray alloc] init];
|
||||
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionViews = [[CPMutableArray alloc] init];
|
||||
editable = [_ruleEditor isEditable];
|
||||
|
||||
_addButton = [self _createAddRowButton];
|
||||
_subtractButton = [self _createDeleteRowButton];
|
||||
//[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||
//[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||
[_addButton setHidden:!editable];
|
||||
[_subtractButton setHidden:!editable];
|
||||
[self addSubview:_addButton];
|
||||
[self addSubview:_subtractButton];
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
var center = [CPNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (CPButton)_createAddRowButton
|
||||
{
|
||||
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[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]];
|
||||
|
||||
[button setAction:@selector(_deleteOption:)];
|
||||
[button setTarget:self];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
|
||||
{
|
||||
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
|
||||
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
return mItem;
|
||||
}
|
||||
|
||||
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
|
||||
{
|
||||
var title = [[itemsArray objectAtIndex:index] title];
|
||||
var font = [_ruleEditor font],
|
||||
width = [title sizeWithFont:font].width + 20,
|
||||
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT);
|
||||
|
||||
var popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
|
||||
[popup setValue:font forThemeAttribute:@"font"];
|
||||
|
||||
var count = [itemsArray count];
|
||||
for (var i = 0; i < count; i++)
|
||||
[popup addItem:[itemsArray objectAtIndex:i]];
|
||||
|
||||
[popup selectItemAtIndex:index];
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
- (CPMenuItem)_createMenuSeparatorItem
|
||||
{
|
||||
return [CPMenuItem separatorItem];
|
||||
}
|
||||
|
||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString )text
|
||||
{
|
||||
text = [[_ruleEditor standardLocalizer] localizedStringForString:text];
|
||||
|
||||
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];
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
- (void)_addOption:(id)sender
|
||||
{
|
||||
if (_rowIndex == [_ruleEditor numberOfRows] - 1)
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
var type = _plusButtonRowType;
|
||||
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
|
||||
type = CPRuleEditorRowTypeCompound;
|
||||
|
||||
[_ruleEditor _addOptionFromSlice:self ofRowType:type];
|
||||
}
|
||||
|
||||
- (void)_deleteOption:(id)sender
|
||||
{
|
||||
[_ruleEditor _deleteSlice:self];
|
||||
}
|
||||
|
||||
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
|
||||
{
|
||||
var layoutdict = [sender representedObject],
|
||||
newItem = [layoutdict objectForKey:@"item"],
|
||||
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
|
||||
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
|
||||
|
||||
if (![newItem isEqual:oldItem])
|
||||
{
|
||||
[_correspondingRuleItems replaceObjectAtIndex:indexInCriteria withObject:newItem];
|
||||
[_ruleEditor _changedItem:oldItem toItem:newItem inRow:_rowIndex atCriteriaIndex:indexInCriteria];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(CPMenuItem )menuItem
|
||||
{
|
||||
return [_ruleEditor _validateItem:menuItem value:[[menuItem representedObject] valueForKey:@"item"] inRow:_rowIndex];
|
||||
}
|
||||
|
||||
- (void)_emptyRulePartSubviews
|
||||
{
|
||||
var count = [_ruleOptionViews count];
|
||||
|
||||
while (count--)
|
||||
[_ruleOptionViews[count] removeFromSuperview];
|
||||
|
||||
[_ruleOptionViews removeAllObjects];
|
||||
[_ruleOptionFrames removeAllObjects];
|
||||
[_ruleOptionInitialViewFrames removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)_reconfigureSubviews
|
||||
{
|
||||
var ruleItems,
|
||||
criteria,
|
||||
repObject,
|
||||
menuItem,
|
||||
ruleView,
|
||||
criterion,
|
||||
parent,
|
||||
numberOfCriteria,
|
||||
numberOfChildren,
|
||||
firstResponderIndex;
|
||||
|
||||
var ruleItems = [CPMutableArray array];
|
||||
|
||||
[self _emptyRulePartSubviews];
|
||||
|
||||
criteria = [_ruleEditor criteriaForRow:_rowIndex];
|
||||
numberOfCriteria = [criteria count];
|
||||
|
||||
firstResponderIndex = numberOfCriteria - 1;
|
||||
var responder = [[self window] firstResponder];
|
||||
if (responder)
|
||||
firstResponderIndex = [_ruleOptionViews indexOfObjectIdenticalTo:responder];
|
||||
|
||||
for (var i = 0; i < numberOfCriteria; i++)
|
||||
{
|
||||
ruleView = nil;
|
||||
parent = nil;
|
||||
criterion = [criteria objectAtIndex:i];
|
||||
|
||||
if (i > 0)
|
||||
parent = [criteria objectAtIndex:i - 1];
|
||||
|
||||
var childItems = [],
|
||||
childValues = [];
|
||||
|
||||
[_ruleEditor _getAllAvailableItems:childItems values:childValues asChildrenOfItem:parent inRow:_rowIndex];
|
||||
|
||||
numberOfChildren = [childItems count];
|
||||
if (numberOfChildren > 1)
|
||||
{
|
||||
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren];
|
||||
|
||||
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];
|
||||
|
||||
if ([childValue isKindOfClass:[CPMenuItem class]])
|
||||
{
|
||||
[[childValue menu] removeItem:childValue];
|
||||
menuItem = childValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([childValue isEqualToString:@""])
|
||||
menuItem = [self _createMenuSeparatorItem];
|
||||
else
|
||||
{
|
||||
menuItem = [self _createMenuItemWithTitle:childValue];
|
||||
[menuItem setTarget:self];
|
||||
[menuItem setAction:@selector(_ruleOptionPopupChangedAction:)];
|
||||
}
|
||||
}
|
||||
|
||||
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
|
||||
[menuItem setRepresentedObject:repObject];
|
||||
[menuItems addObject:menuItem];
|
||||
}
|
||||
|
||||
ruleView = [self _createPopUpButtonWithItems:menuItems selectedItemIndex:selectedIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = [childValues objectAtIndex:0];
|
||||
var type = [value valueType];
|
||||
|
||||
if (type === 0)
|
||||
ruleView = [self _createStaticTextFieldWithStringValue:value];
|
||||
else
|
||||
{
|
||||
if (type !== 1)
|
||||
{
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"Display value must be a string or a menu item"];
|
||||
continue;
|
||||
}
|
||||
|
||||
ruleView = value;
|
||||
[ruleView setTarget:self];
|
||||
[ruleView setAction:@selector(_sendRuleAction:)];
|
||||
if ([ruleView respondsToSelector:@selector(setDelegate:)])
|
||||
[ruleView setDelegate:self];
|
||||
}
|
||||
}
|
||||
|
||||
if (ruleView != nil)
|
||||
{
|
||||
[_ruleOptionViews addObject:ruleView];
|
||||
var frame = [ruleView frame];
|
||||
[_ruleOptionInitialViewFrames addObject:frame];
|
||||
[_ruleOptionFrames addObject:frame];
|
||||
|
||||
if (!criterion)
|
||||
criterion = [CPNull null];
|
||||
|
||||
[ruleItems addObject:criterion];
|
||||
}
|
||||
}
|
||||
|
||||
[_correspondingRuleItems setArray:ruleItems];
|
||||
|
||||
if (!editable)
|
||||
[self _updateEnabledStateForSubviews];
|
||||
|
||||
[self _relayoutSubviewsWidthChanged:YES];
|
||||
|
||||
if (firstResponderIndex != CPNotFound)
|
||||
{
|
||||
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
|
||||
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
|
||||
}
|
||||
|
||||
//[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)_updateEnabledStateForSubviews
|
||||
{
|
||||
[_ruleOptionViews makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
// CPLogConsole(_cmd);
|
||||
[self _relayoutSubviewsWidthChanged:YES];
|
||||
}
|
||||
|
||||
- (void)_relayoutSubviewsWidthChanged:(BOOL)widthChanged
|
||||
{
|
||||
var optionViewOriginX,
|
||||
leftHorizontalPadding,
|
||||
leftButtonMinX,
|
||||
rowHeight = [_ruleEditor rowHeight],
|
||||
count = [_ruleOptionViews count],
|
||||
sliceFrame = [self frame];
|
||||
|
||||
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];
|
||||
|
||||
if (widthChanged)
|
||||
{
|
||||
optionViewOriginX = [self _leftmostViewFixedHorizontalPadding] + [self _indentationHorizontalPadding] * _indentation;
|
||||
leftHorizontalPadding = [self _rowButtonsLeftHorizontalPadding];
|
||||
leftButtonMinX = CGRectGetMinX(buttonFrame);
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var ruleOptionView = _ruleOptionViews[i],
|
||||
optionFrame = _ruleOptionFrames[i];
|
||||
|
||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame))/2 - 2;
|
||||
if (widthChanged)
|
||||
{
|
||||
optionFrame.origin.x = optionViewOriginX;
|
||||
if (i == count - 1 && ![self _isRulePopup:ruleOptionView])
|
||||
{
|
||||
var initialFrame = _ruleOptionInitialViewFrames[i];
|
||||
optionFrame.size.width = MIN(CGRectGetWidth(initialFrame), leftButtonMinX - leftHorizontalPadding - optionViewOriginX);
|
||||
}
|
||||
}
|
||||
|
||||
[ruleOptionView setFrame:optionFrame];
|
||||
[self addSubview:ruleOptionView];
|
||||
|
||||
if (widthChanged)
|
||||
optionViewOriginX += CGRectGetWidth(optionFrame) + [self _interviewHorizontalPadding];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateButtonVisibilities
|
||||
{
|
||||
[_addButton setHidden:[_ruleEditor _shouldHideAddButtonForSlice:self]];
|
||||
[_subtractButton setHidden:[_ruleEditor _shouldHideSubtractButtonForSlice:self]];
|
||||
}
|
||||
|
||||
- (void)_configurePlusButtonByRowType:(CPRuleEditorRowType)type
|
||||
{
|
||||
[self _setRowTypeToAddFromPlusButton:type];
|
||||
}
|
||||
|
||||
- (BOOL)isEditable
|
||||
{
|
||||
return editable;
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)value
|
||||
{
|
||||
editable = value;
|
||||
// [self _updateEnabledStateForSubviews];
|
||||
[self _updateButtonVisibilities];
|
||||
}
|
||||
|
||||
- (float)_alignmentGridWidth
|
||||
{
|
||||
return [_ruleEditor _alignmentGridWidth];
|
||||
}
|
||||
|
||||
- (float)_indentationHorizontalPadding
|
||||
{
|
||||
return 30.;
|
||||
}
|
||||
|
||||
- (float)_interviewHorizontalPadding
|
||||
{
|
||||
return 6.;
|
||||
}
|
||||
|
||||
- (float)_leftmostViewFixedHorizontalPadding
|
||||
{
|
||||
return 7.;
|
||||
}
|
||||
|
||||
- (float)_minimumVerticalPopupPadding
|
||||
{
|
||||
return 2.;
|
||||
}
|
||||
|
||||
- (float)_rowButtonsInterviewHorizontalPadding
|
||||
{
|
||||
return 6.;
|
||||
}
|
||||
|
||||
- (float)_rowButtonsLeftHorizontalPadding
|
||||
{
|
||||
return 10.;
|
||||
}
|
||||
|
||||
- (float)_rowButtonsRightHorizontalPadding
|
||||
{
|
||||
return 10.;
|
||||
}
|
||||
|
||||
- (void)_setRowTypeToAddFromPlusButton:(int)type
|
||||
{
|
||||
_plusButtonRowType = type;
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay:(BOOL)flag
|
||||
{
|
||||
[super setNeedsDisplay:flag];
|
||||
}
|
||||
|
||||
- (BOOL)_nestingModeShouldHideAddButton
|
||||
{
|
||||
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
|
||||
}
|
||||
|
||||
- (BOOL)_nestingModeShouldHideSubtractButton
|
||||
{
|
||||
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
|
||||
}
|
||||
|
||||
- (BOOL)containsDisplayValue:(id)value
|
||||
{
|
||||
return [[_ruleEditor displayValuesForRow:_rowIndex] containsObject:value];
|
||||
// Ou alors avec _correspondingRuleItems
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
}
|
||||
|
||||
- (BOOL)_isRulePopup:(CPView)view
|
||||
{
|
||||
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)_isRuleStaticTextField:(CPView)view
|
||||
{
|
||||
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_sendRuleAction:(id)sender
|
||||
{
|
||||
[_ruleEditor _sendRuleAction];
|
||||
}
|
||||
|
||||
- (void)_textDidChange:(CPNotification)aNotif
|
||||
{
|
||||
if ([[aNotif object] superview] == self && [_ruleEditor _sendsActionOnIncompleteTextChange])
|
||||
[_ruleEditor _sendRuleAction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPRuleEditorTextField : CPTextField
|
||||
{
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
{
|
||||
[self setBordered:NO];
|
||||
[self setEditable:NO];
|
||||
[self setDrawsBackground:NO];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)hitTest:(CPPoint)point
|
||||
{
|
||||
if (!CPRectContainsPoint([self frame], point))
|
||||
return nil;
|
||||
|
||||
return [self superview];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* CPSavePanel.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"
|
||||
|
||||
|
||||
+36
-2
@@ -1,11 +1,45 @@
|
||||
|
||||
/*
|
||||
* CPScreen.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>
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScreen
|
||||
|
||||
A CPScreen object describes the attributes of a display device available
|
||||
to Cappuccino.
|
||||
*/
|
||||
@implementation CPScreen : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the position and size of the visible area of the receiving screen.
|
||||
This will normally be smaller than the full size of the screen to account
|
||||
for system UI elements. For example, on a Mac the top of the visible frame
|
||||
is placed below the bottom of the menu bar.
|
||||
|
||||
@return the visible screen rectangle
|
||||
*/
|
||||
- (CGRect)visibleFrame
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
@@ -15,4 +49,4 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -342,6 +342,7 @@
|
||||
|
||||
[_contentView setFrame:contentFrame];
|
||||
[_headerClipView setFrame:headerClipViewFrame];
|
||||
[[_headerClipView documentView] setNeedsDisplay:YES];
|
||||
[_cornerView setFrame:[self _cornerViewFrame]];
|
||||
|
||||
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
|
||||
@@ -355,10 +356,11 @@
|
||||
/*!
|
||||
Sets the type of border to be drawn around the view.
|
||||
Valid types are:
|
||||
CPNoBorder
|
||||
CPLineBorder
|
||||
CPBezelBorder
|
||||
CPGrooveBorder
|
||||
<pre>
|
||||
CPNoBorder
|
||||
CPLineBorder
|
||||
CPBezelBorder
|
||||
CPGrooveBorder</pre>
|
||||
*/
|
||||
- (void)setBorderType:(CPBorderType)borderType
|
||||
{
|
||||
@@ -713,7 +715,7 @@
|
||||
*/
|
||||
- (void)setLineScroll:(float)aLineScroll
|
||||
{
|
||||
[self setHorizonalLineScroll:aLineScroll];
|
||||
[self setHorizontalLineScroll:aLineScroll];
|
||||
[self setVerticalLineScroll:aLineScroll];
|
||||
}
|
||||
|
||||
@@ -1077,8 +1079,8 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
|
||||
|
||||
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
// Due to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(_updateCornerAndHeaderView) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
+9
-9
@@ -267,16 +267,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||
effectiveDecrementLineHeight = decrementLineSize.height + trackInset.top,
|
||||
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
|
||||
slotHeight = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
|
||||
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobWidth = width - knobInset.left - knobInset.right,
|
||||
knobHeight = MAX(minimumKnobLength, (slotHeight * _knobProportion)),
|
||||
knobLocation = effectiveDecrementLineHeight + (slotHeight - knobHeight) * [self floatValue];
|
||||
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, slotHeight);
|
||||
_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);
|
||||
|
||||
@@ -296,16 +296,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
|
||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
||||
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
|
||||
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
||||
knobHeight = height - knobInset.top - knobInset.bottom,
|
||||
knobLocation = effectiveDecrementLineWidth + (slotWidth - knobWidth) * [self floatValue];
|
||||
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, slotWidth, height - trackInset.top - trackInset.bottom);
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
@@ -316,7 +316,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-5
@@ -109,7 +109,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||
[self setBordered:YES];
|
||||
[self setEditable:YES];
|
||||
[self setDelegate:self];
|
||||
[self setContinuous:YES];
|
||||
|
||||
var bounds = [self bounds],
|
||||
@@ -125,6 +124,18 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
_canResignFirstResponder = YES;
|
||||
}
|
||||
|
||||
- (void)viewWillMoveToSuperview:(CPView)aView
|
||||
{
|
||||
[super viewWillMoveToSuperview:aView];
|
||||
|
||||
// First we remove any observer that may have been in place to avoid memory leakage.
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
|
||||
|
||||
// Register the observe here if we need to.
|
||||
if (aView)
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
// Managing Buttons
|
||||
/*!
|
||||
Sets the button used to display the search-button image
|
||||
@@ -181,7 +192,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[_cancelButton setTarget:self];
|
||||
[_cancelButton setAction:@selector(cancelOperation:)];
|
||||
[_cancelButton setAction:@selector(cancelOperation:)];
|
||||
[self _updateCancelButtonVisibility];
|
||||
[self addSubview:_cancelButton];
|
||||
}
|
||||
@@ -198,7 +209,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
/*!
|
||||
Resets the cancel button to its default attributes.
|
||||
This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
|
||||
This method resets the target, action, regular image, and pressed image. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
|
||||
*/
|
||||
- (void)resetCancelButton
|
||||
{
|
||||
@@ -420,7 +431,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[_cancelButton setHidden:([[self stringValue] length] === 0)];
|
||||
}
|
||||
|
||||
- (void)controlTextDidChange:(CPNotification)aNotification
|
||||
- (void)_searchFieldTextDidChange:(CPNotification)aNotification
|
||||
{
|
||||
if (![self sendsWholeSearchString])
|
||||
{
|
||||
@@ -680,7 +691,8 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
- (void)cancelOperation:(id)sender
|
||||
{
|
||||
[self setObjectValue:@""];
|
||||
[self _sendPartialString];
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* CPSecureTextField.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPTextField.j"
|
||||
|
||||
|
||||
+5
-2
@@ -382,6 +382,11 @@ CPCircularSlider = 1;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (BOOL)isContinuous
|
||||
{
|
||||
return (_sendActionOn & CPLeftMouseDraggedMask) !== 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
should we have _continuous?
|
||||
@@ -425,8 +430,6 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
{
|
||||
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
|
||||
|
||||
[self setContinuous:YES];
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
[_rgbLabel setStringValue: "Red, Green, Blue"];
|
||||
[_rgbLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 35, 15, 20)];
|
||||
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
|
||||
[_redLabel setStringValue: "R"];
|
||||
[_redLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
@@ -86,18 +86,18 @@
|
||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// red value input box
|
||||
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
|
||||
_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, 58, 15, 20)];
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
[_greenLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 58, aFrame.size.width - 70, 20)];
|
||||
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
|
||||
[_greenSlider setMaxValue: 1.0];
|
||||
[_greenSlider setMinValue: 0.0];
|
||||
[_greenSlider setTarget: self];
|
||||
@@ -105,18 +105,18 @@
|
||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// green value input box
|
||||
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
|
||||
_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, 81, 15, 20)];
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
[_blueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 81, aFrame.size.width - 70, 20)];
|
||||
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
|
||||
[_blueSlider setMaxValue: 1.0];
|
||||
[_blueSlider setMinValue: 0.0];
|
||||
[_blueSlider setTarget: self];
|
||||
@@ -124,7 +124,7 @@
|
||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// blue value input box
|
||||
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
|
||||
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
|
||||
[_blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_blueValue setEditable: YES];
|
||||
[_blueValue setBezeled: YES];
|
||||
@@ -139,7 +139,7 @@
|
||||
[_hueLabel setStringValue: "H"];
|
||||
[_hueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 145, aFrame.size.width - 70, 20)];
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
|
||||
[_hueSlider setMaxValue: 359.0];
|
||||
[_hueSlider setMinValue: 0.0];
|
||||
[_hueSlider setTarget: self];
|
||||
@@ -147,14 +147,14 @@
|
||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// hue value input box
|
||||
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
|
||||
_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, 168, 15, 20)];
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
@@ -166,18 +166,18 @@
|
||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// saturation value input box
|
||||
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
|
||||
_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, 191, 15, 20)];
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 191, aFrame.size.width - 70, 20)];
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
|
||||
[_brightnessSlider setMaxValue: 100.0];
|
||||
[_brightnessSlider setMinValue: 0.0];
|
||||
[_brightnessSlider setTarget: self];
|
||||
@@ -185,7 +185,7 @@
|
||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
// brightness value input box
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
|
||||
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_brightnessValue setEditable: YES];
|
||||
[_brightnessValue setBezeled: YES];
|
||||
@@ -197,7 +197,7 @@
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
//hex input box
|
||||
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
|
||||
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
|
||||
[_hexValue setEditable: YES];
|
||||
[_hexValue setBezeled: YES];
|
||||
[_hexValue setDelegate: self];
|
||||
|
||||
+45
-10
@@ -25,6 +25,7 @@
|
||||
CPSoundLoadStateEmpty = 0;
|
||||
CPSoundLoadStateLoading = 1;
|
||||
CPSoundLoadStateCanBePlayed = 2;
|
||||
CPSoundLoadStateError = 3;
|
||||
|
||||
CPSoundPlayBackStatePlay = 0;
|
||||
CPSoundPlayBackStateStop = 1;
|
||||
@@ -60,14 +61,24 @@ CPSoundPlayBackStatePause = 2;
|
||||
_loops = NO;
|
||||
_audioTag = document.createElement("audio");
|
||||
_audioTag.preload = YES;
|
||||
|
||||
_audioTag.addEventListener("canplay", function()
|
||||
{
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[self _soundDidload];
|
||||
});
|
||||
}, true);
|
||||
|
||||
_audioTag.addEventListener("ended", function()
|
||||
{
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[self _soundDidEnd];
|
||||
});
|
||||
}, true);
|
||||
|
||||
_audioTag.addEventListener("error", function()
|
||||
{
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[self _soundError];
|
||||
}, true);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -137,31 +148,45 @@ CPSoundPlayBackStatePause = 2;
|
||||
[self stop];
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
- (void)_soundError
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateError;
|
||||
CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Media controls
|
||||
|
||||
/*!
|
||||
Play the sound.
|
||||
|
||||
@return YES when the receiver is playing its audio data, NO otherwise.
|
||||
*/
|
||||
- (void)play
|
||||
- (BOOL)play
|
||||
{
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePlay))
|
||||
return;
|
||||
return NO;
|
||||
|
||||
_audioTag.play();
|
||||
_playBackStatus = CPSoundPlayBackStatePlay;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Stop the sound.
|
||||
|
||||
@return YES when the receiver is playing its audio data, NO otherwise.
|
||||
*/
|
||||
- (void)stop
|
||||
- (BOOL)stop
|
||||
{
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStateStop))
|
||||
return;
|
||||
return NO;
|
||||
|
||||
_audioTag.pause();
|
||||
_audioTag.currentTime = 0.0;
|
||||
@@ -169,32 +194,42 @@ CPSoundPlayBackStatePause = 2;
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
|
||||
[_delegate sound:self didFinishPlaying:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Pause the sound.
|
||||
|
||||
@return YES when the receiver is playing its audio data, NO otherwise.
|
||||
*/
|
||||
- (void)pause
|
||||
- (BOOL)pause
|
||||
{
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePause))
|
||||
return;
|
||||
return NO;
|
||||
|
||||
_audioTag.pause();
|
||||
_playBackStatus = CPSoundPlayBackStatePause;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Resume playback of a paused sound.
|
||||
|
||||
@return YES when the receiver is playing its audio data, NO otherwise.
|
||||
*/
|
||||
- (void)resume
|
||||
- (BOOL)resume
|
||||
{
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus !== CPSoundPlayBackStatePause))
|
||||
return;
|
||||
return NO;
|
||||
|
||||
_audioTag.play();
|
||||
_playBackStatus = CPSoundPlayBackStatePlay;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+75
-31
@@ -72,7 +72,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[10.0, 1.0, [CPColor grayColor]]
|
||||
return [CPDictionary dictionaryWithObjects:[1.0, 10.0, [CPColor grayColor]]
|
||||
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
|
||||
}
|
||||
|
||||
@@ -259,6 +259,32 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[self drawDividerInRect:[self rectOfDividerAtIndex:count]];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Because we're use drawRect: to draw the dividers, but use DOM elements instead of CoreGraphics
|
||||
We must remove those DOM elements (the splitters) when the subview is removed.
|
||||
*/
|
||||
- (void)willRemoveSubview:(CPView)aView
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var dividerToRemove = _DOMDividerElements.pop();
|
||||
|
||||
// The divider may not exist if we never rendered out the DOM.
|
||||
if (dividerToRemove)
|
||||
CPDOMDisplayServerRemoveChild(_DOMElement, dividerToRemove);
|
||||
#endif
|
||||
|
||||
_needsResizeSubviews = YES;
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize]
|
||||
}
|
||||
|
||||
/*!
|
||||
Draws the divider at a given rect.
|
||||
@param aRect - the rect of the divider to draw.
|
||||
@@ -286,13 +312,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (_isPaneSplitter)
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
||||
}
|
||||
else
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,41 +739,59 @@ var CPSplitViewHorizontalImage = nil,
|
||||
Sets the delegate of the receiver.
|
||||
Possible delegate methods to implement are listed below.
|
||||
|
||||
<pre>
|
||||
- (void)splitViewDidResizeSubviews:(CPSplitView)aSplitView;
|
||||
Notifies the delegate when the subviews have resized.
|
||||
Notifies the delegate when the subviews have resized.
|
||||
@code
|
||||
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
- (void)splitViewWillResizeSubviews:(CPSplitView)aSplitView;
|
||||
Notifies the delegate when the subviews will be resized.
|
||||
Notifies the delegate when the subviews will be resized.
|
||||
@code
|
||||
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
|
||||
Lets the delegate specify a different rect for which the user can drag the splitView divider.
|
||||
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;
|
||||
@endcode
|
||||
|
||||
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
|
||||
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
|
||||
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
|
||||
@code
|
||||
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
|
||||
@endcode
|
||||
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
|
||||
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
|
||||
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
|
||||
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
|
||||
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
|
||||
@code
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
|
||||
@endcode
|
||||
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview;
|
||||
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
|
||||
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
|
||||
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
|
||||
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
|
||||
@code
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
|
||||
@endcode
|
||||
|
||||
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
|
||||
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
|
||||
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
|
||||
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
|
||||
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
|
||||
@code
|
||||
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
|
||||
@endcode
|
||||
|
||||
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
|
||||
Allows the delegate to constrain the minimum position of a subview.
|
||||
Allows the delegate to constrain the minimum position of a subview.
|
||||
@code
|
||||
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
|
||||
@endcode
|
||||
|
||||
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
|
||||
Allows the delegate to constrain the maximum position of a subview.
|
||||
Allows the delegate to constrain the maximum position of a subview.
|
||||
@code
|
||||
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
|
||||
@endcode
|
||||
|
||||
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
|
||||
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
|
||||
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
|
||||
</pre>
|
||||
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
|
||||
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
|
||||
@code
|
||||
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
|
||||
@endcode
|
||||
|
||||
@param delegate - The delegate of the splitview.
|
||||
*/
|
||||
|
||||
+4
-102
@@ -38,8 +38,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
int _maxValue @accessors(property=maxValue);
|
||||
int _minValue @accessors(property=minValue);
|
||||
|
||||
_CPContinuousButton _buttonDown;
|
||||
_CPContinuousButton _buttonUp;
|
||||
CPButton _buttonDown;
|
||||
CPButton _buttonUp;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -87,14 +87,14 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
|
||||
[self setDoubleValue:0.0];
|
||||
|
||||
_buttonUp = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
|
||||
_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 = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
|
||||
_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:)];
|
||||
@@ -244,101 +244,3 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*! This is a subclass of CPButton that allows to send continuous action.
|
||||
This may should be include in CPButton..
|
||||
*/
|
||||
@implementation _CPContinuousButton : CPButton
|
||||
{
|
||||
CPTimer _continuousDelayTimer;
|
||||
CPTimer _continuousTimer;
|
||||
float _periodicDelay;
|
||||
float _periodicInterval;
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_periodicInterval = 0.05;
|
||||
_periodicDelay = 0.5;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
|
||||
{
|
||||
_periodicDelay = aDelay;
|
||||
_periodicInterval = anInterval;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([self isContinuous])
|
||||
{
|
||||
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
|
||||
{
|
||||
if (!_continuousTimer)
|
||||
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
|
||||
}
|
||||
|
||||
repeats:NO];
|
||||
}
|
||||
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)onContinousEvent:(CPTimer)aTimer
|
||||
{
|
||||
if (_target && _action && [_target respondsToSelector:_action])
|
||||
[_target performSelector:_action withObject:self];
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self invalidateTimers];
|
||||
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
|
||||
}
|
||||
|
||||
- (void)invalidateTimers
|
||||
{
|
||||
if (_continuousTimer)
|
||||
{
|
||||
[_continuousTimer invalidate];
|
||||
_continuousTimer = nil;
|
||||
}
|
||||
|
||||
if (_continuousDelayTimer)
|
||||
{
|
||||
[_continuousDelayTimer invalidate];
|
||||
_continuousDelayTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation _CPContinuousButton (CPCodingCompliance)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_periodicDelay = [aCoder decodeObjectForKey:@"_periodicDelay"];
|
||||
_periodicInterval = [aCoder decodeObjectForKey:@"_periodicInterval"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[self invalidateTimers];
|
||||
[aCoder encodeObject:_periodicDelay forKey:@"_periodicDelay"];
|
||||
[aCoder encodeObject:_periodicInterval forKey:@"_periodicInterval"];
|
||||
}
|
||||
@end
|
||||
|
||||
+47
-2
@@ -16,6 +16,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabView
|
||||
|
||||
A CPTabView object presents a tabbed interface where each page is one a
|
||||
complete view hiearchy of its own. The user can navigate between various
|
||||
pages by clicking on the tab headers.
|
||||
*/
|
||||
@implementation CPTabView : CPView
|
||||
{
|
||||
CPArray _items;
|
||||
@@ -26,6 +34,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPNumber _selectedIndex;
|
||||
|
||||
CPTabViewType _type;
|
||||
CPFont _font;
|
||||
|
||||
id _delegate;
|
||||
unsigned _delegateSelectors;
|
||||
@@ -74,8 +83,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
}
|
||||
|
||||
/*!
|
||||
Inserts a CPTabViewItem into the tab view
|
||||
at the specified index.
|
||||
Inserts a CPTabViewItem into the tab view at the specified index.
|
||||
@param aTabViewItem the item to insert
|
||||
@param anIndex the index for the item
|
||||
*/
|
||||
@@ -121,6 +129,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
/*!
|
||||
Returns the index of the specified item
|
||||
@param aTabViewItem the item to find the index for
|
||||
@return the index of aTabViewItem or CPNotFound
|
||||
*/
|
||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
@@ -130,6 +139,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
/*!
|
||||
Returns the index of the CPTabViewItem with the specified identifier.
|
||||
@param anIdentifier the identifier of the item
|
||||
@return the index of the tab view item identified by anIdentifier, or CPNotFound
|
||||
*/
|
||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
@@ -142,6 +152,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the number of items in the tab view.
|
||||
@return the number of tab view items in the receiver
|
||||
*/
|
||||
- (unsigned)numberOfTabViewItems
|
||||
{
|
||||
@@ -150,6 +161,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the CPTabViewItem at the specified index.
|
||||
@return a tab view item, or nil
|
||||
*/
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
@@ -158,6 +170,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the array of items that backs this tab view.
|
||||
@return a copy of the array of items in the receiver
|
||||
*/
|
||||
- (CPArray)tabViewItems
|
||||
{
|
||||
@@ -261,12 +274,36 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the current item being displayed.
|
||||
@return the tab view item currenly being displayed by the receiver
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
}
|
||||
|
||||
// Modifying the font
|
||||
/*!
|
||||
Returns the font for tab label text.
|
||||
@return the font for tab label text
|
||||
*/
|
||||
- (CPFont)font
|
||||
{
|
||||
return _font;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the font for tab label text to font.
|
||||
@param font the font the receiver should use for tab label text
|
||||
*/
|
||||
- (void)setFont:(CPFont)font
|
||||
{
|
||||
if ([_font isEqual:font])
|
||||
return;
|
||||
|
||||
_font = font;
|
||||
[_tabs setFont:_font];
|
||||
}
|
||||
|
||||
//
|
||||
/*!
|
||||
Sets the tab view type.
|
||||
@@ -314,6 +351,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the tab view type.
|
||||
@return the tab view type of the receiver
|
||||
*/
|
||||
- (CPTabViewType)tabViewType
|
||||
{
|
||||
@@ -322,6 +360,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the receiver's delegate.
|
||||
@return the receiver's delegate
|
||||
*/
|
||||
- (id)delegate
|
||||
{
|
||||
@@ -415,6 +454,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
|
||||
CPTabViewTypeKey = "CPTabViewTypeKey",
|
||||
CPTabViewFontKey = "CPTabViewFontKey",
|
||||
CPTabViewDelegateKey = "CPTabViewDelegateKey";
|
||||
|
||||
@implementation CPTabView (CPCoding)
|
||||
@@ -425,12 +465,16 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
|
||||
[_tabs setFont:_font];
|
||||
|
||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
|
||||
@@ -450,6 +494,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
||||
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
||||
|
||||
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
|
||||
}
|
||||
|
||||
+65
-22
@@ -326,39 +326,38 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
This method sets the "prototype" view which will be used to create all table cells in this column.
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
When you set a dataview and it is added to the tableview the theme state will be set to CPThemeStateTableDataView
|
||||
When the dataview becomes selected the theme state will be set to CPThemeStateSelectedDataView.
|
||||
|
||||
If the dataview shows up in a group row of the tableview the theme state will be set to CPThemeStateGroupRow.
|
||||
|
||||
You should overide setThemeState: and unsetThemeState: to handle these theme state changes in your dataview.
|
||||
|
||||
Example:
|
||||
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@code
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@endcode
|
||||
|
||||
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
|
||||
@code
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
@endcode
|
||||
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
|
||||
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
@note You should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
This is done by adding the following methods to your class:
|
||||
@endnote
|
||||
|
||||
@code
|
||||
- (id)initWithCoder(CPCoder)aCoder;
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder;
|
||||
@endcode
|
||||
|
||||
Example:
|
||||
Say you have two instance variables in your object that need to be set up each time an object is create.
|
||||
We will call these instance variables "image" and "text".
|
||||
Your CPCoding methods will look like the following:
|
||||
|
||||
@code
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
@@ -379,7 +378,16 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
[aCoder encodeObject:image forKey:"MyDataViewImage"];
|
||||
[aCoder encodeObject:text forKey:"MyDataViewText"];
|
||||
}
|
||||
</pre>
|
||||
@endcode
|
||||
|
||||
@section Theming
|
||||
|
||||
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
|
||||
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
|
||||
|
||||
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
|
||||
|
||||
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
|
||||
*/
|
||||
- (void)setDataView:(CPView)aView
|
||||
{
|
||||
@@ -420,7 +428,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
var x = [self tableView]._cachedDataViews[dataViewUID];
|
||||
if (x && x.length)
|
||||
return x.pop();
|
||||
return x.pop();
|
||||
|
||||
// if we haven't cached an archive of the data view, do it now
|
||||
if (!_dataViewData[dataViewUID])
|
||||
@@ -466,7 +474,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
/*!
|
||||
Returns YES if the user can edit cells associated with the receiver by double-clicking the
|
||||
column in the NSTableView, NO otherwise.
|
||||
column in the CPTableView, NO otherwise.
|
||||
*/
|
||||
- (BOOL)isEditable
|
||||
{
|
||||
@@ -592,7 +600,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
|
||||
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
|
||||
{
|
||||
var bindingsDictionary = [CPBinder allBindingsForObject:self],
|
||||
keys = [bindingsDictionary allKeys];
|
||||
@@ -638,6 +646,41 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_reverseSetDataView:(CPView)aDataView forRow:(unsigned)aRow
|
||||
{
|
||||
var bindingsDictionary = [CPBinder allBindingsForObject:self],
|
||||
keys = [bindingsDictionary allKeys],
|
||||
newValue = [aDataView valueForKey:@"objectValue"];
|
||||
|
||||
for (var i = 0, count = [keys count]; i < count; i++)
|
||||
{
|
||||
var bindingName = keys[i],
|
||||
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
|
||||
binding = [bindingsDictionary objectForKey:bindingName],
|
||||
bindingInfo = binding._info,
|
||||
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
||||
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
||||
dotIndex = keyPath.lastIndexOf(".");
|
||||
|
||||
if (dotIndex === CPNotFound)
|
||||
[[destination valueForKeyPath:keyPath] replaceObjectAtIndex:aRow withObject:newValue];
|
||||
else
|
||||
{
|
||||
var firstPart = keyPath.substring(0, dotIndex),
|
||||
secondPart = keyPath.substring(dotIndex + 1),
|
||||
firstValue = [destination valueForKeyPath:firstPart];
|
||||
|
||||
if ([firstValue isKindOfClass:CPArray])
|
||||
[[firstValue objectAtIndex:aRow] setValue:newValue forKeyPath:secondPart];
|
||||
else
|
||||
[[firstValue valueForKeyPath:secondPart] replaceObjectAtIndex:aRow withObject:newValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- (void)objectValue
|
||||
//{
|
||||
// return nil;
|
||||
@@ -695,9 +738,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
{
|
||||
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
|
||||
|
||||
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
|
||||
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||
[aCoder encodeFloat:_width forKey:CPTableColumnWidthKey];
|
||||
[aCoder encodeFloat:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||
[aCoder encodeFloat:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
+10
-11
@@ -212,7 +212,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||
{
|
||||
var headerRect = [self bounds],
|
||||
var headerRect = CGRectMakeCopy([self bounds]),
|
||||
columnRect = [_tableView rectOfColumn:aColumnIndex];
|
||||
|
||||
headerRect.origin.x = _CGRectGetMinX(columnRect);
|
||||
@@ -592,15 +592,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var column = [tableColumns objectAtIndex:i],
|
||||
headerView = [column headerView];
|
||||
headerView = [column headerView],
|
||||
frame = [self headerRectOfColumn:i];
|
||||
|
||||
var frame = [self headerRectOfColumn:i];
|
||||
// Make space for the gridline on the right.
|
||||
frame.origin.x -= 0.5;
|
||||
frame.size.width -= 1.0;
|
||||
frame.size.height -= 0.5;
|
||||
if (i > 0)
|
||||
{
|
||||
frame.origin.x += 0.5;
|
||||
frame.size.width -= 1;
|
||||
}
|
||||
// Note: we're not adding in intercell spacing here. This setting only affects the regular
|
||||
// table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
|
||||
|
||||
[headerView setFrame:frame];
|
||||
|
||||
@@ -642,10 +642,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
|
||||
+376
-255
@@ -136,110 +136,112 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
CPTableView object displays record-oriented data in a table and
|
||||
allows the user to edit values and resize and rearrange columns.
|
||||
A CPTableView requires you to either set a data source which implements
|
||||
numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:,
|
||||
@ref numberofrows "numberOfRowsInTableView:" and @ref objectValueForTable "tableView:objectValueForTableColumn:row:",
|
||||
or alternatively to provide data through Key Value Bindings.
|
||||
|
||||
To use a table view with Key Value Bindings, bind each column's
|
||||
CPValueBinding to an array.field path - typically this would be to a path
|
||||
in an array controller like "arrangedObjects.X", where X is the name of a
|
||||
field. Optionally also bind the table's "selectionIndexes" and
|
||||
"sortDescriptors" to the array controller.
|
||||
\c CPValueBinding to an \c array.field path - typically this would be to a path
|
||||
in an array controller like \c arrangedObjects.X, where \c X is the name of a
|
||||
field. Optionally also bind the table's \c selectionIndexes and
|
||||
\c sortDescriptors to the array controller.
|
||||
|
||||
All delegate and data source methods are documented in the setDataSource: and setDelegate: methods.
|
||||
All delegate and data source methods are documented in the @ref setdatasource "setDataSource:" and @ref setdelegate "setDelegate:" methods.
|
||||
|
||||
If you want to display something other than just text in the table you should call setDataView: on a CPTableColumn object. More documentation in that class including theme states.
|
||||
If you want to display something other than just text in the table you should call @link CPTableColumn::setDataView: setDataView:@endlink on a CPTableColumn object. More documentation in that class including theme states.
|
||||
|
||||
@note CPTableView does not contain its own scrollview. You should be sure you place the tableview in a CPScrollView on your own.
|
||||
|
||||
Note: CPTableView does not contain its own scrollview. You should be sure you place the tableview in a CPScrollView on your own.
|
||||
*/
|
||||
@implementation CPTableView : CPControl
|
||||
{
|
||||
id _dataSource;
|
||||
CPInteger _implementedDataSourceMethods;
|
||||
id _dataSource;
|
||||
CPInteger _implementedDataSourceMethods;
|
||||
|
||||
id _delegate;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
id _delegate;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
|
||||
CPArray _tableColumns;
|
||||
CPArray _tableColumnRanges;
|
||||
CPInteger _dirtyTableColumnRangeIndex;
|
||||
CPInteger _numberOfHiddenColumns;
|
||||
CPArray _tableColumns;
|
||||
CPArray _tableColumnRanges;
|
||||
CPInteger _dirtyTableColumnRangeIndex;
|
||||
CPInteger _numberOfHiddenColumns;
|
||||
|
||||
BOOL _reloadAllRows;
|
||||
Object _objectValues;
|
||||
BOOL _reloadAllRows;
|
||||
Object _objectValues;
|
||||
|
||||
CGRect _exposedRect;
|
||||
CPIndexSet _exposedRows;
|
||||
CPIndexSet _exposedColumns;
|
||||
CGRect _exposedRect;
|
||||
CPIndexSet _exposedRows;
|
||||
CPIndexSet _exposedColumns;
|
||||
|
||||
Object _dataViewsForTableColumns;
|
||||
Object _cachedDataViews;
|
||||
Object _dataViewsForTableColumns;
|
||||
Object _cachedDataViews;
|
||||
|
||||
//Configuring Behavior
|
||||
BOOL _allowsColumnReordering;
|
||||
BOOL _allowsColumnResizing;
|
||||
BOOL _allowsColumnSelection;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
BOOL _allowsColumnReordering;
|
||||
BOOL _allowsColumnResizing;
|
||||
BOOL _allowsColumnSelection;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
|
||||
CPArray _sortDescriptors;
|
||||
CPArray _sortDescriptors;
|
||||
|
||||
//Setting Display Attributes
|
||||
CGSize _intercellSpacing;
|
||||
float _rowHeight;
|
||||
CGSize _intercellSpacing;
|
||||
float _rowHeight;
|
||||
|
||||
BOOL _usesAlternatingRowBackgroundColors;
|
||||
CPArray _alternatingRowBackgroundColors;
|
||||
BOOL _usesAlternatingRowBackgroundColors;
|
||||
CPArray _alternatingRowBackgroundColors;
|
||||
|
||||
unsigned _selectionHighlightStyle;
|
||||
CPTableColumn _currentHighlightedTableColumn;
|
||||
unsigned _gridStyleMask;
|
||||
unsigned _selectionHighlightStyle;
|
||||
CPTableColumn _currentHighlightedTableColumn;
|
||||
unsigned _gridStyleMask;
|
||||
|
||||
unsigned _numberOfRows;
|
||||
CPIndexSet _groupRows;
|
||||
unsigned _numberOfRows;
|
||||
CPIndexSet _groupRows;
|
||||
|
||||
CPArray _cachedRowHeights;
|
||||
CPArray _cachedRowHeights;
|
||||
|
||||
// Persistence
|
||||
CPString _autosaveName;
|
||||
BOOL _autosaveTableColumns;
|
||||
CPString _autosaveName;
|
||||
BOOL _autosaveTableColumns;
|
||||
|
||||
CPTableHeaderView _headerView;
|
||||
_CPCornerView _cornerView;
|
||||
CPTableHeaderView _headerView;
|
||||
_CPCornerView _cornerView;
|
||||
|
||||
CPIndexSet _selectedColumnIndexes;
|
||||
CPIndexSet _selectedRowIndexes;
|
||||
CPInteger _selectionAnchorRow;
|
||||
CPInteger _lastSelectedRow;
|
||||
CPIndexSet _previouslySelectedRowIndexes;
|
||||
CGPoint _startTrackingPoint;
|
||||
CPDate _startTrackingTimestamp;
|
||||
BOOL _trackingPointMovedOutOfClickSlop;
|
||||
CGPoint _editingCellIndex;
|
||||
CPIndexSet _selectedColumnIndexes;
|
||||
CPIndexSet _selectedRowIndexes;
|
||||
CPInteger _selectionAnchorRow;
|
||||
CPInteger _lastSelectedRow;
|
||||
CPIndexSet _previouslySelectedRowIndexes;
|
||||
CGPoint _startTrackingPoint;
|
||||
CPDate _startTrackingTimestamp;
|
||||
BOOL _trackingPointMovedOutOfClickSlop;
|
||||
CGPoint _editingCellIndex;
|
||||
|
||||
_CPTableDrawView _tableDrawView;
|
||||
_CPTableDrawView _tableDrawView;
|
||||
|
||||
SEL _doubleAction;
|
||||
CPInteger _clickedRow;
|
||||
unsigned _columnAutoResizingStyle;
|
||||
SEL _doubleAction;
|
||||
CPInteger _clickedRow;
|
||||
unsigned _columnAutoResizingStyle;
|
||||
|
||||
int _lastTrackedRowIndex;
|
||||
CGPoint _originalMouseDownPoint;
|
||||
BOOL _verticalMotionCanDrag;
|
||||
unsigned _destinationDragStyle;
|
||||
BOOL _isSelectingSession;
|
||||
CPIndexSet _draggedRowIndexes;
|
||||
int _lastTrackedRowIndex;
|
||||
CGPoint _originalMouseDownPoint;
|
||||
BOOL _verticalMotionCanDrag;
|
||||
unsigned _destinationDragStyle;
|
||||
BOOL _isSelectingSession;
|
||||
CPIndexSet _draggedRowIndexes;
|
||||
BOOL _wasSelectionBroken;
|
||||
|
||||
_CPDropOperationDrawingView _dropOperationFeedbackView;
|
||||
CPDragOperation _dragOperationDefaultMask;
|
||||
int _retargetedDropRow;
|
||||
CPDragOperation _retargetedDropOperation;
|
||||
CPDragOperation _dragOperationDefaultMask;
|
||||
int _retargetedDropRow;
|
||||
CPDragOperation _retargetedDropOperation;
|
||||
|
||||
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
|
||||
BOOL _lastColumnShouldSnap;
|
||||
BOOL _implementsCustomDrawRow;
|
||||
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
|
||||
BOOL _lastColumnShouldSnap;
|
||||
BOOL _implementsCustomDrawRow;
|
||||
|
||||
CPTableColumn _draggedColumn;
|
||||
CPArray _differedColumnDataToRemove;
|
||||
CPTableColumn _draggedColumn;
|
||||
CPArray _differedColumnDataToRemove;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -291,11 +293,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[self setGridColor:[CPColor colorWithHexString:@"dce0e2"]];
|
||||
[self setGridStyleMask:CPTableViewGridNone];
|
||||
|
||||
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
|
||||
|
||||
[_headerView setTableView:self];
|
||||
|
||||
_cornerView = nil; //[[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
|
||||
[self setHeaderView:[[CPTableHeaderView alloc] initWithFrame:_CGRectMake(0, 0, [self bounds].size.width, _rowHeight)]];
|
||||
[self setCornerView:[[_CPCornerView alloc] initWithFrame:_CGRectMake(0, 0, [CPScroller scrollerWidth], _CGRectGetHeight([_headerView frame]))]];
|
||||
|
||||
_currentHighlightedTableColumn = nil;
|
||||
|
||||
@@ -324,6 +323,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
{
|
||||
_tableViewFlags = 0;
|
||||
_lastSelectedRow = -1;
|
||||
_clickedRow = -1;
|
||||
|
||||
_selectedColumnIndexes = [CPIndexSet indexSet];
|
||||
_selectedRowIndexes = [CPIndexSet indexSet];
|
||||
@@ -342,14 +342,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
_dirtyTableColumnRangeIndex = 0;
|
||||
_numberOfHiddenColumns = 0;
|
||||
|
||||
_objectValues = { };
|
||||
_dataViewsForTableColumns = { };
|
||||
_dataViews = [];
|
||||
_numberOfRows = 0;
|
||||
_exposedRows = [CPIndexSet indexSet];
|
||||
_exposedColumns = [CPIndexSet indexSet];
|
||||
_cachedDataViews = { };
|
||||
_cachedRowHeights = [];
|
||||
_objectValues = { };
|
||||
_dataViewsForTableColumns = { };
|
||||
_dataViews = [];
|
||||
_numberOfRows = 0;
|
||||
_exposedRows = [CPIndexSet indexSet];
|
||||
_exposedColumns = [CPIndexSet indexSet];
|
||||
_cachedDataViews = { };
|
||||
_cachedRowHeights = [];
|
||||
|
||||
_groupRows = [CPIndexSet indexSet];
|
||||
|
||||
@@ -357,14 +357,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[_tableDrawView setBackgroundColor:[CPColor clearColor]];
|
||||
[self addSubview:_tableDrawView];
|
||||
|
||||
if (!_headerView)
|
||||
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
|
||||
|
||||
[_headerView setTableView:self];
|
||||
|
||||
if (!_cornerView)
|
||||
_cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
|
||||
|
||||
_draggedColumn = nil;
|
||||
|
||||
/* //gradients for the source list when CPTableView is NOT first responder or the window is NOT key
|
||||
@@ -380,47 +372,69 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
@anchor setdatasource
|
||||
Sets the receiver's data source to a given object.
|
||||
The data source implements various methods for handling the tableview's data when bindings are not used.
|
||||
|
||||
Methods include:
|
||||
- (int)numberOfRowsInTableView:(CPTableView)aTableView;
|
||||
Returns the number of rows in the tableview
|
||||
|
||||
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRowIndex;
|
||||
Returns the object value for each dataview. Each dataview will be sent a setObjectValue: method which will contain
|
||||
the object you return from this datasource method.
|
||||
|
||||
Editing:
|
||||
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)anObject forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
Sets the data object for an item in a given row and column. This needs to be implemented if you want inline editing support
|
||||
|
||||
Sorting:
|
||||
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors;
|
||||
The tableview will call this method if you click the tableheader. You should sort the datasource based off of the new sort descriptors and reload the data
|
||||
|
||||
Drag and Drop:
|
||||
In order for the tableview to receive drops don't forget to first register the tableview for drag types like you do with every other view
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(CPDraggingInfo)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation;
|
||||
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
|
||||
The data source can retarget a drop if you want by calling -(void)setDropRow:(int)aRow dropOperation:(CPTableViewDropOperation)anOperation;
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard;
|
||||
Returns YES if the drop operation is allowed otherwise NO.
|
||||
This method is invoked by the tableview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
|
||||
If you want the drag to begin you should return YES and place the drag data on the pboard.
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(CPDraggingInfo)info row:(int)row dropOperation:(CPTableViewDropOperation)operation;
|
||||
Return YES if the operation was successful otherwise return NO.
|
||||
The data source should incorporate the data from the dragging pasteboard in this method implementation.
|
||||
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
|
||||
|
||||
- (CPArray)tableView:(CPTableView)aTableView namesOfPromisedFilesDroppedAtDestination:(CPURL)dropDestination forDraggedRowsWithIndexes:(CPIndexSet)indexSet;
|
||||
NOT YET IMPLEMENTED
|
||||
</pre>
|
||||
@param anObject The data source for the receiver. This object must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
|
||||
|
||||
These methods are outlined below.
|
||||
|
||||
|
||||
@section overview Overview
|
||||
CPTableView generally requires a datasource to run. This data source can be thought of just like a delegate, but specifically for the tableview data.
|
||||
Methods include:
|
||||
|
||||
@section required Required Methods
|
||||
@anchor numberofrows
|
||||
Returns the number of rows in the tableview
|
||||
@code
|
||||
- (int)numberOfRowsInTableView:(CPTableView)aTableView;
|
||||
@endcode
|
||||
|
||||
Returns the object value for each dataview. Each dataview will be sent a setObjectValue: method which will contain the object you return from this datasource method.
|
||||
@anchor objectValueForTable
|
||||
@code
|
||||
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRowIndex;
|
||||
@endcode
|
||||
|
||||
|
||||
@section editing Editing:
|
||||
Sets the data object for an item in a given row and column. This needs to be implemented if you want inline editing support
|
||||
@code
|
||||
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)anObject forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
@endcode
|
||||
|
||||
|
||||
@section sorting Sorting:
|
||||
The tableview will call this method if you click the tableheader. You should sort the datasource based off of the new sort descriptors and reload the data
|
||||
@code
|
||||
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors;
|
||||
@endcode
|
||||
|
||||
|
||||
@section draganddrop Drag and Drop:
|
||||
@note In order for the tableview to receive drops don't forget to first register the tableview for drag types like you do with every other view.
|
||||
|
||||
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
|
||||
The data source can retarget a drop if you want by calling <pre>-(void)setDropRow:(int)aRow dropOperation:(CPTableViewDropOperation)anOperation;</pre>
|
||||
@code
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(CPDraggingInfo)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation;
|
||||
@endcode
|
||||
|
||||
Returns YES if the drop operation is allowed otherwise NO. This method is invoked by the tableview after a drag should begin, but before it is started. If you don't want the drag to being return NO. If you want the drag to begin you should return YES and place the drag data on the pboard.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard;
|
||||
@endcode
|
||||
|
||||
Return YES if the operation was successful otherwise return NO. The data source should incorporate the data from the dragging pasteboard in this method implementation. To get this data use the draggingPasteboard method on the CPDraggingInfo object.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(CPDraggingInfo)info row:(int)row dropOperation:(CPTableViewDropOperation)operation;
|
||||
@endcode
|
||||
|
||||
NOT YET IMPLEMENTED
|
||||
@code
|
||||
- (CPArray)tableView:(CPTableView)aTableView namesOfPromisedFilesDroppedAtDestination:(CPURL)dropDestination forDraggedRowsWithIndexes:(CPIndexSet)indexSet;
|
||||
@endcode
|
||||
*/
|
||||
- (void)setDataSource:(id)aDataSource
|
||||
{
|
||||
@@ -555,7 +569,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
Passing YES will allow the user to resize columns. Passing NO will keep the table columns unmovable by the user.
|
||||
Note the this does not affect autoresizing behavior.
|
||||
@note The this does not affect autoresizing behavior.
|
||||
*/
|
||||
- (void)setAllowsColumnResizing:(BOOL)shouldAllowColumnResizing
|
||||
{
|
||||
@@ -649,13 +663,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)setThemeState:(int)aState
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the intercell spacing in a CGSize object.
|
||||
*/
|
||||
@@ -666,7 +673,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
Sets the height of each row.
|
||||
NOTE: This may still used even if variable row height is being used.
|
||||
@note This may still used even if variable row height is being used.
|
||||
|
||||
@param aRowHeight the height of each row
|
||||
*/
|
||||
@@ -730,9 +737,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
Returns an enumerated value for the selection highlight style.
|
||||
<pre>
|
||||
|
||||
|
||||
Valid values are:
|
||||
<pre>
|
||||
CPTableViewSelectionHighlightStyleNone
|
||||
CPTableViewSelectionHighlightStyleRegular
|
||||
CPTableViewSelectionHighlightStyleSourceList
|
||||
@@ -744,11 +752,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Sets the selection highlight style to an enumerated value.
|
||||
This value can also affect the way the tableview draws feedback when the user is dragging.
|
||||
|
||||
Valid values are:
|
||||
<pre>
|
||||
CPTableViewSelectionHighlightStyleNone
|
||||
CPTableViewSelectionHighlightStyleRegular
|
||||
CPTableViewSelectionHighlightStyleSourceList
|
||||
@@ -790,10 +798,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
|
||||
Sets the highlight gradient for a row or column selection
|
||||
This is specific to the
|
||||
@param aDictionary a CPDictionary expects three keys to be set:
|
||||
<pre>
|
||||
CPSourceListGradient which is a CGGradient
|
||||
CPSourceListTopLineColor which is a CPColor
|
||||
CPSourceListBottomLineColor which is a CPColor
|
||||
@@ -807,8 +816,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Returns a dictionary of containing the keys:
|
||||
<pre>
|
||||
CPSourceListGradient
|
||||
CPSourceListTopLineColor
|
||||
CPSourceListBottomLineColor
|
||||
@@ -1351,7 +1360,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[self selectColumnIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
|
||||
}
|
||||
|
||||
/*
|
||||
/*!
|
||||
Returns the number of columns in the table
|
||||
*/
|
||||
- (int)numberOfColumns
|
||||
@@ -1359,7 +1368,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
return NUMBER_OF_COLUMNS();
|
||||
}
|
||||
|
||||
/*
|
||||
/*!
|
||||
Returns the number of rows in the receiver.
|
||||
*/
|
||||
- (int)numberOfRows
|
||||
@@ -1377,7 +1386,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
_numberOfRows = [[destination valueForKeyPath:keyPath] count];
|
||||
}
|
||||
else if (_dataSource && (_implementedDataSourceMethods & CPTableViewDataSource_numberOfRowsInTableView_))
|
||||
_numberOfRows = [_dataSource numberOfRowsInTableView:self];
|
||||
_numberOfRows = [_dataSource numberOfRowsInTableView:self] || 0;
|
||||
else
|
||||
{
|
||||
if (_dataSource)
|
||||
@@ -1455,7 +1464,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
_cornerView = aView;
|
||||
|
||||
var scrollView = [[self superview] superview];
|
||||
var scrollView = [self enclosingScrollView];
|
||||
|
||||
if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
|
||||
[scrollView _updateCornerAndHeaderView];
|
||||
@@ -1491,8 +1500,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[_headerView setTableView:self];
|
||||
[_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is no header view, there should be no corner view
|
||||
[_cornerView removeFromSuperview];
|
||||
_cornerView = nil;
|
||||
}
|
||||
|
||||
var scrollView = [[self superview] superview];
|
||||
var scrollView = [self enclosingScrollView];
|
||||
|
||||
if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
|
||||
[scrollView _updateCornerAndHeaderView];
|
||||
@@ -1523,7 +1538,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
_numberOfHiddenColumns += 1;
|
||||
_tableColumnRanges[index] = CPMakeRange(x, 0.0);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var width = [_tableColumns[index] width] + _intercellSpacing.width;
|
||||
@@ -1583,10 +1597,20 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
if (_implementedDelegateMethods & CPTableViewDelegate_tableView_heightOfRow_)
|
||||
{
|
||||
var rowToLookUp = MIN(aRowIndex, lastIndex),
|
||||
y = _cachedRowHeights[rowToLookUp].heightAboveRow,
|
||||
height = _cachedRowHeights[rowToLookUp].height + _intercellSpacing.height,
|
||||
rowDelta = aRowIndex - rowToLookUp;
|
||||
var rowToLookUp = MIN(aRowIndex, lastIndex);
|
||||
|
||||
// if the row doesn't exist
|
||||
if (rowToLookUp !== CPNotFound)
|
||||
{
|
||||
var y = _cachedRowHeights[rowToLookUp].heightAboveRow,
|
||||
height = _cachedRowHeights[rowToLookUp].height + _intercellSpacing.height,
|
||||
rowDelta = aRowIndex - rowToLookUp;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = aRowIndex * (_rowHeight + _intercellSpacing.height);
|
||||
height = _rowHeight + _intercellSpacing.height;
|
||||
}
|
||||
|
||||
// if we need the rect of a row past the last index
|
||||
if (rowDelta > 0)
|
||||
@@ -1812,7 +1836,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
leftInset = FLOOR(_intercellSpacing.width / 2.0),
|
||||
topInset = FLOOR(_intercellSpacing.height / 2.0);
|
||||
|
||||
return _CGRectMake(tableColumnRange.location + leftInset, _CGRectGetMinY(rectOfRow) + topInset, tableColumnRange.length - _intercellSpacing.width, _CGRectGetHeight(rectOfRow) - _intercellSpacing.height);
|
||||
return _CGRectMake(tableColumnRange.location + leftInset, _CGRectGetMinY(rectOfRow) + topInset, tableColumnRange.length - _intercellSpacing.width, _CGRectGetHeight(rectOfRow) - _intercellSpacing.height);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1899,7 +1923,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
FIX ME: this is broken
|
||||
FIX ME: this can be a lot faster
|
||||
*/
|
||||
- (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize
|
||||
{
|
||||
@@ -1959,17 +1983,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
// now that we've reached the end we know there are likely rounding errors
|
||||
// so we should size the last resized to fit
|
||||
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:[self numberOfColumns] - 1]),
|
||||
|
||||
// find the last visisble column
|
||||
while (count-- && [_tableColumns[count] isHidden]) ;
|
||||
|
||||
// find the max x, but subtract a single pixel since the spacing isn't applicable here.
|
||||
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:count]) - ([self intercellSpacing].width || 1),
|
||||
newSize = [item width] + delta;
|
||||
|
||||
[item _tryToResizeToWidth:newSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Sets the column autoresizing style of the receiver to a given style.
|
||||
|
||||
@param aStyle the column autoresizing style for the receiver. Valid values are:
|
||||
<pre>
|
||||
CPTableViewNoColumnAutoresizing
|
||||
CPTableViewUniformColumnAutoresizingStyle
|
||||
CPTableViewLastColumnOnlyAutoresizingStyle
|
||||
@@ -2164,8 +2193,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
/*!
|
||||
Set the name under which the table information is automatically saved to theAutosaveName.
|
||||
The table information is saved separately for each user and for each application that user uses.
|
||||
Note that even though a table view has an autosave name, it may not be saving table information automatically.
|
||||
To set whether table information is being saved automatically, use setAutosaveTableColumns:
|
||||
@note Even though a table view has an autosave name, it may not be saving table information automatically.
|
||||
To set whether table information is being saved automatically, use \c setAutosaveTableColumns:
|
||||
*/
|
||||
- (void)setAutosaveName:(CPString)theAutosaveName
|
||||
{
|
||||
@@ -2190,7 +2219,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
Sets whether the order and width of this table view's columns are automatically saved.
|
||||
|
||||
The table information is saved separately for each user and for each application that user uses.
|
||||
Note that if autosaveName returns nil, this setting is ignored and table information isn't saved.
|
||||
@note that if autosaveName returns nil, this setting is ignored and table information isn't saved.
|
||||
*/
|
||||
- (void)setAutosaveTableColumns:(BOOL)shouldAutosave
|
||||
{
|
||||
@@ -2278,80 +2307,141 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Sets the delegate of the receiver. The delegate can implement the following methods:
|
||||
Displaying Cells
|
||||
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
Called when the tableview is about to display a dataview
|
||||
|
||||
- (BOOL)tableView:(CPTableView)tableView isGroupRow:(int)row;
|
||||
Group rows are a way to separate a groups of data in a tableview. Return YES if the given row is a group row, otherwise NO.
|
||||
|
||||
Editing Cells
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
Return YES if the dataview at a given index and column should be edited, otherwise NO.
|
||||
|
||||
|
||||
Setting Row and Column Size
|
||||
- (float)tableView:(CPTableView)tableView heightOfRow:(int)row;
|
||||
Return the height of the row at a given index. Only implement this if you want variable row heights. Otherwise use setRowHeight: on the tableview.
|
||||
|
||||
Selecting in the Tableview
|
||||
- (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView;
|
||||
Return YES if the selection of the tableview should change, otherwise NO to keep the current selection.
|
||||
NOTE: this is only called via user interaction
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex;
|
||||
Return YES if the row at a given index should be selected, other NO to deny the selection.
|
||||
NOTE: this is only called via user interaction
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldSelectTableColumn:(CPTableColumn)aTableColumn;
|
||||
Return YES if the table column given should be selected, otherwise NO to deny the selection.
|
||||
NOTE: this is only called via user interaction
|
||||
|
||||
- (void)tableViewSelectionIsChanging:(CPNotification)aNotification
|
||||
Inform the delegate that the tableview is in the process of chaining the selection.
|
||||
This usually happens when the user is dragging their mouse across rows.
|
||||
NOTE: this is only called via user interaction
|
||||
|
||||
- (void)tableViewSelectionDidChange:(CPNotification)aNotification;
|
||||
Informs the delegate that the tableview selection has changed.
|
||||
NOTE: this is only called via user interaction
|
||||
|
||||
|
||||
Moving and Resizing Columns
|
||||
- (BOOL)tableView:(CPTableView)tableView shouldReorderColumn:(int)columnIndex toColumn:(int)newColumnIndex;
|
||||
Return YES if the column at a given index should move to a new column index, otherwise NO.
|
||||
|
||||
- (void)tableView:(CPTableView)tableView didDragTableColumn:(CPTableColumn)tableColumn;
|
||||
Notifies the delegate that the tableview drag occurred. This is send on mouse up.
|
||||
|
||||
- (void)tableViewColumnDidMove:(CPNotification)aNotification;
|
||||
Notifies the delegate that a tablecolumn was moved by the user.
|
||||
|
||||
- (void)tableViewColumnDidResize:(CPNotification)aNotification
|
||||
Notifies the delegate that the user resized the table column
|
||||
|
||||
|
||||
Responding to Mouse Events
|
||||
- (void)tableView:(CPTableView)tableView didClickTableColumn:(CPTableColumn)tableColumn
|
||||
Sent when the user clicks a table column but doesn't drag.
|
||||
|
||||
- (void)tableView:(CPTableView)tableView mouseDownInHeaderOfTableColumn:(CPTableColumn)tableColumn;
|
||||
Notify the delegate that the user click the table header of a column.
|
||||
|
||||
Contextual Menus
|
||||
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
||||
Called when the user right clicks on the tableview. -1 is passed for the row or column if the user doesn't right click on a real row or column
|
||||
Return a CPMenu that should be displayed if the user right clicks. If you do not implement this the tableview will just call super on menuForEvent
|
||||
|
||||
Delete Key
|
||||
- (void)tableViewDeleteKeyPressed:(CPTableView)aTableView;
|
||||
Called when the user presses the delete key. Many times you will want to delete data (or prompt for deletion) when the user hids the delete key.
|
||||
Your delegate can implement this method to avoid subclassing the tableview to add this behaviour.
|
||||
</pre>
|
||||
@anchor setdelegate
|
||||
Sets the delegate of the receiver.
|
||||
@param aDelegate the delegate object for the tableview.
|
||||
|
||||
The delegate can provide easy notification for user interaction, display behaviour, contextual menus, and more.
|
||||
|
||||
|
||||
|
||||
|
||||
@section displayingcells Displaying Cells:
|
||||
|
||||
Called when the tableview is about to display a dataview
|
||||
@code
|
||||
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
@endcode
|
||||
|
||||
Group rows are a way to separate a groups of data in a tableview. Return YES if the given row is a group row, otherwise NO.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)tableView isGroupRow:(int)row;
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
@section editingcells Editing Cells:
|
||||
|
||||
Return YES if the dataview at a given index and column should be edited, otherwise NO.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@section sizes Setting Row and Column Size:
|
||||
|
||||
Return the height of the row at a given index. Only implement this if you want variable row heights. Otherwise use setRowHeight: on the tableview.
|
||||
@code
|
||||
- (float)tableView:(CPTableView)tableView heightOfRow:(int)row;
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
@section selection Selecting in the TableView:
|
||||
@note These methods are only called when the user does something.@endnote
|
||||
|
||||
Return YES if the selection of the tableview should change, otherwise NO to keep the current selection.
|
||||
@code
|
||||
- (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView;
|
||||
@endcode
|
||||
|
||||
Return YES if the row at a given index should be selected, other NO to deny the selection.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex;
|
||||
@endcode
|
||||
|
||||
Return YES if the table column given should be selected, otherwise NO to deny the selection.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldSelectTableColumn:(CPTableColumn)aTableColumn;
|
||||
@endcode
|
||||
|
||||
Inform the delegate that the tableview is in the process of chaining the selection.
|
||||
This usually happens when the user is dragging their mouse across rows.
|
||||
@code
|
||||
- (void)tableViewSelectionIsChanging:(CPNotification)aNotification
|
||||
@endcode
|
||||
|
||||
Informs the delegate that the tableview selection has changed.
|
||||
@code
|
||||
- (void)tableViewSelectionDidChange:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@section movingandresizingcolumsn Moving and Resizing Columns:
|
||||
|
||||
Return YES if the column at a given index should move to a new column index, otherwise NO.
|
||||
@code
|
||||
- (BOOL)tableView:(CPTableView)tableView shouldReorderColumn:(int)columnIndex toColumn:(int)newColumnIndex;
|
||||
@endcode
|
||||
|
||||
|
||||
Notifies the delegate that the tableview drag occurred. This is send on mouse up.
|
||||
@code
|
||||
- (void)tableView:(CPTableView)tableView didDragTableColumn:(CPTableColumn)tableColumn;
|
||||
@endcode
|
||||
|
||||
|
||||
Notifies the delegate that a tablecolumn was moved by the user.
|
||||
@code
|
||||
- (void)tableViewColumnDidMove:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
Notifies the delegate that the user resized the table column
|
||||
@code
|
||||
- (void)tableViewColumnDidResize:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
@section mousevents Responding to Mouse Events:
|
||||
|
||||
Sent when the user clicks a table column but doesn't drag.
|
||||
@code
|
||||
- (void)tableView:(CPTableView)tableView didClickTableColumn:(CPTableColumn)tableColumn;
|
||||
@endcode
|
||||
|
||||
|
||||
Notify the delegate that the user click the table header of a column.
|
||||
@code
|
||||
- (void)tableView:(CPTableView)tableView mouseDownInHeaderOfTableColumn:(CPTableColumn)tableColumn;
|
||||
@endcode
|
||||
|
||||
|
||||
@section contextualmenus Contextual Menus:
|
||||
|
||||
Called when the user right clicks on the tableview. -1 is passed for the row or column if the user doesn't right click on a real row or column
|
||||
Return a CPMenu that should be displayed if the user right clicks. If you do not implement this the tableview will just call super on menuForEvent
|
||||
@code
|
||||
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aColumn row:(int)aRow;
|
||||
@endcode
|
||||
|
||||
|
||||
@section deletekey Delete Key
|
||||
Called when the user presses the delete key. Many times you will want to delete data (or prompt for deletion) when the user hids the delete key.
|
||||
Your delegate can implement this method to avoid subclassing the tableview to add this behaviour.
|
||||
|
||||
@code
|
||||
- (void)tableViewDeleteKeyPressed:(CPTableView)aTableView;
|
||||
@endcode
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
@@ -2735,7 +2825,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
|
||||
|
||||
// If the column uses content bindings, allow them to override the objectValueForTableColumn.
|
||||
[tableColumn prepareDataView:dataView forRow:row];
|
||||
[tableColumn _prepareDataView:dataView forRow:row];
|
||||
|
||||
[view addSubview:dataView];
|
||||
|
||||
@@ -2801,7 +2891,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
Sets the default operation mask for the drag behavior of the table view.
|
||||
NOTE: isLocal is not implemented.
|
||||
@note isLocal is not implemented.
|
||||
*/
|
||||
- (void)setDraggingSourceOperationMask:(CPDragOperation)mask forLocal:(BOOL)isLocal
|
||||
{
|
||||
@@ -2831,11 +2921,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Sets the feedback style for when the table is the destination of a drag operation.
|
||||
This style is used to determine how the tableview looks when it is the receiver of a drag and drop operation.
|
||||
|
||||
Can be:
|
||||
<pre>
|
||||
CPTableViewDraggingDestinationFeedbackStyleNone
|
||||
CPTableViewDraggingDestinationFeedbackStyleRegular
|
||||
CPTableViewDraggingDestinationFeedbackStyleSourceList
|
||||
@@ -2848,10 +2938,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
|
||||
/*!
|
||||
<pre>
|
||||
Returns the tableview dragging destination feedback style.
|
||||
|
||||
Can be:
|
||||
<pre>
|
||||
CPTableViewDraggingDestinationFeedbackStyleNone
|
||||
CPTableViewDraggingDestinationFeedbackStyleRegular
|
||||
CPTableViewDraggingDestinationFeedbackStyleSourceList
|
||||
@@ -3181,7 +3271,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
// This gives the table column an opportunity to apply its bindings.
|
||||
// It will override the value set above if there is a binding.
|
||||
[tableColumn prepareDataView:dataView forRow:row];
|
||||
[tableColumn _prepareDataView:dataView forRow:row];
|
||||
|
||||
if (isColumnSelected || [self isRowSelected:row])
|
||||
[dataView setThemeState:CPThemeStateSelectedDataView];
|
||||
@@ -3281,7 +3371,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
{
|
||||
_editingCellIndex = nil;
|
||||
|
||||
[_dataSource tableView:self setObjectValue:[sender objectValue] forTableColumn:sender.tableViewEditedColumnObj row:sender.tableViewEditedRowIndex];
|
||||
if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
|
||||
[_dataSource tableView:self setObjectValue:[sender objectValue] forTableColumn:sender.tableViewEditedColumnObj row:sender.tableViewEditedRowIndex];
|
||||
|
||||
// Allow the column binding to do a reverse set. Note that we do this even if the data source method above
|
||||
// is implemented.
|
||||
[sender.tableViewEditedColumnObj _reverseSetDataView:sender forRow:sender.tableViewEditedRowIndex];
|
||||
|
||||
if ([sender respondsToSelector:@selector(setEditable:)])
|
||||
[sender setEditable:NO];
|
||||
@@ -3416,8 +3511,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
var exposedRect = [self exposedRect];
|
||||
|
||||
[self drawBackgroundInClipRect:exposedRect];
|
||||
[self drawGridInClipRect:exposedRect];
|
||||
[self highlightSelectionInClipRect:exposedRect];
|
||||
[self drawGridInClipRect:exposedRect];
|
||||
|
||||
if (_implementsCustomDrawRow)
|
||||
[self _drawRows:_exposedRows clipRect:exposedRect];
|
||||
@@ -3426,7 +3521,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
/*!
|
||||
Draws the background in a given clip rect.
|
||||
This method should only be overridden if you want something other than a solid color or alternating row colors.
|
||||
NOTE: this method should not be called directly, instead use setNeedsDisplay:
|
||||
@note this method should not be called directly, instead use \c setNeedsDisplay:
|
||||
*/
|
||||
- (void)drawBackgroundInClipRect:(CGRect)aRect
|
||||
{
|
||||
@@ -3480,7 +3575,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
Draws the grid for the tableview based on the set grid mask in a given clip rect.
|
||||
NOTE: this method should not be called directly, instead use setNeedsDisplay:
|
||||
@note this method should not be called directly, instead use setNeedsDisplay:
|
||||
*/
|
||||
- (void)drawGridInClipRect:(CGRect)aRect
|
||||
{
|
||||
@@ -3538,11 +3633,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
minY = _CGRectGetMinY(aRect),
|
||||
maxY = _CGRectGetMaxY(aRect);
|
||||
|
||||
|
||||
for (; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
|
||||
{
|
||||
var columnRect = [self rectOfColumn:columnsArray[columnArrayIndex]],
|
||||
columnX = _CGRectGetMaxX(columnRect) + 0.5;
|
||||
columnX = _CGRectGetMaxX(columnRect) - 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, columnX, minY);
|
||||
CGContextAddLineToPoint(context, columnX, maxY);
|
||||
@@ -3557,7 +3651,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
/*!
|
||||
Draws the selection with the set selection highlight style in a given clip rect.
|
||||
You can change the highlight style to a source list style gradient in setSelectionHighlightStyle:
|
||||
NOTE: this method should not be called directly, instead use setNeedsDisplay:
|
||||
@note this method should not be called directly, instead use \c setNeedsDisplay:
|
||||
*/
|
||||
- (void)highlightSelectionInClipRect:(CGRect)aRect
|
||||
{
|
||||
@@ -3576,7 +3670,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
[_selectedRowIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
|
||||
}
|
||||
|
||||
else if ([_selectedColumnIndexes count] >= 1)
|
||||
{
|
||||
rectSelector = @selector(rectOfColumn:);
|
||||
@@ -3788,7 +3881,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
While this method doesn't do anything in Cappuccino, subclasses can override it to customize the
|
||||
appearance of a row.
|
||||
|
||||
NOTE: tableView:willDisplayView:forTableColumn:row is sent to the delegate before drawing
|
||||
@note \c tableView:willDisplayView:forTableColumn:row is sent to the delegate before drawing
|
||||
*/
|
||||
- (void)drawRow:(CPInteger)row clipRect:(CGRect)rect
|
||||
{
|
||||
@@ -3922,7 +4015,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
column = [self columnAtPoint:location],
|
||||
tableColumn = [[self tableColumns] objectAtIndex:column];
|
||||
|
||||
return [[self delegate] tableView:self menuForTableColumn:tableColumn row:row];
|
||||
return [_delegate tableView:self menuForTableColumn:tableColumn row:row];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4052,10 +4145,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Accept either tableView:setObjectValue:forTableColumn:row: delegate method, or a binding.
|
||||
if (mouseIsUp
|
||||
&& (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
|
||||
&& !_trackingPointMovedOutOfClickSlop
|
||||
&& ([[CPApp currentEvent] clickCount] > 1))
|
||||
&& ([[CPApp currentEvent] clickCount] > 1)
|
||||
&& ((_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
|
||||
|| [self infoForBinding:@"content"]))
|
||||
{
|
||||
columnIndex = [self columnAtPoint:lastPoint];
|
||||
if (columnIndex !== -1)
|
||||
@@ -4233,6 +4328,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
*/
|
||||
- (CPDragOperation)draggingUpdated:(id)sender
|
||||
{
|
||||
_retargetedDropRow = nil;
|
||||
_retargetedDropOperation = nil;
|
||||
|
||||
var location = [self convertPoint:[sender draggingLocation] fromView:nil],
|
||||
dropOperation = [self _proposedDropOperationAtPoint:location],
|
||||
numberOfRows = [self numberOfRows],
|
||||
@@ -4241,6 +4339,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
if (_retargetedDropRow !== nil)
|
||||
row = _retargetedDropRow;
|
||||
if (_retargetedDropOperation !== nil)
|
||||
dropOperation = _retargetedDropOperation;
|
||||
|
||||
|
||||
if (dropOperation === CPTableViewDropOn && row >= numberOfRows)
|
||||
@@ -4478,7 +4578,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Selection behavior depends on two things:
|
||||
Determines if the selection is broken. A broken selection
|
||||
is a non-continuous selection of rows.
|
||||
*/
|
||||
- (BOOL)_selectionIsBroken
|
||||
{
|
||||
return [self selectedRowIndexes]._ranges.length !== 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Selection behaviour depends on two things:
|
||||
_lastSelectedRow and the anchored selection (the last row selected by itself)
|
||||
*/
|
||||
- (void)_moveSelectionWithEvent:(CPEvent)theEvent upward:(BOOL)shouldGoUpward
|
||||
@@ -4492,7 +4602,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
var extend = (([theEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection),
|
||||
i = [self selectedRow];
|
||||
|
||||
shouldGoUpward ? i-- : i++;
|
||||
if ([self _selectionIsBroken])
|
||||
{
|
||||
while ([selectedIndexes containsIndex:i])
|
||||
{
|
||||
shouldGoUpward ? i-- : i++;
|
||||
}
|
||||
_wasSelectionBroken = true;
|
||||
}
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex])))
|
||||
{
|
||||
shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex];
|
||||
_wasSelectionBroken = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldGoUpward ? i-- : i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4652,11 +4778,6 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
|
||||
_headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey];
|
||||
_cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey];
|
||||
|
||||
// Make sure we unhide the cornerview because a corner view loaded from cib is always hidden
|
||||
// This might be a bug in IB, or the way we load the NSvFlags might be broken for _NSCornerView
|
||||
if (_cornerView)
|
||||
[_cornerView setHidden:NO];
|
||||
|
||||
[self setDataSource:[aCoder decodeObjectForKey:CPTableViewDataSourceKey]];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTableViewDelegateKey]];
|
||||
|
||||
|
||||
+19
-7
@@ -84,7 +84,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
id _placeholderString;
|
||||
BOOL _currentValueIsPlaceholder;
|
||||
|
||||
id _delegate;
|
||||
|
||||
@@ -705,9 +704,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
// CPTextField uses an HTML input element to take the input so we need to
|
||||
// propagate the dom event so the element is updated. This has to be done
|
||||
// before interpretKeyEvents: though so individual commands have a chance
|
||||
@@ -804,11 +800,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
}
|
||||
|
||||
- (void)textDidChange:(CPNotification)note
|
||||
{
|
||||
if ([note object] !== self)
|
||||
return;
|
||||
|
||||
[self _continuouslyReverseSetBinding];
|
||||
|
||||
[super textDidChange:note];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
// Don't reverse set our empty value
|
||||
if (!_currentValueIsPlaceholder)
|
||||
[self _reverseSetBinding];
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
@@ -1002,6 +1006,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self copy:sender];
|
||||
[self deleteBackward:sender];
|
||||
}
|
||||
else
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
- (void)paste:(id)sender
|
||||
@@ -1023,6 +1029,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
}
|
||||
else
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
- (CPRange)selectedRange
|
||||
@@ -1403,6 +1411,10 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
|
||||
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
|
||||
break;
|
||||
|
||||
case CPNullMarker:
|
||||
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
|
||||
break;
|
||||
}
|
||||
|
||||
[_source setPlaceholderString:newValue];
|
||||
|
||||
+57
-9
@@ -25,9 +25,10 @@
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
var CPThemesByName = { },
|
||||
CPThemeNamesByInheritance = [],
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -76,6 +77,52 @@ var CPThemesByName = { },
|
||||
return CPThemesByName[aName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of all loaded themes, in the order they were loaded.
|
||||
*/
|
||||
+ (CPArray)allThemeNames
|
||||
{
|
||||
return [CPThemeNamesByInheritance copy];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the closest matching theme for a given view or view class.
|
||||
The matching proceeds as follows:
|
||||
|
||||
- The default theme class name for the class is retrieved.
|
||||
- Starting with the last loaded theme and proceeding towards the default theme,
|
||||
each theme is checked to see if it defines that theme class.
|
||||
- If the theme defines the class name, that theme is returned.
|
||||
- If no themes match, the default theme is returned.
|
||||
|
||||
@param aViewOrClass The view or view class to match with a theme
|
||||
@return The first matching theme
|
||||
*/
|
||||
+ (CPTheme)themeForView:(id)aViewOrClass
|
||||
{
|
||||
var themeClass = nil;
|
||||
|
||||
if (class_isMetaClass(aViewOrClass.isa))
|
||||
themeClass = [aViewOrClass defaultThemeClass];
|
||||
else
|
||||
themeClass = [aViewOrClass themeClass];
|
||||
|
||||
if (themeClass)
|
||||
{
|
||||
var count = CPThemeNamesByInheritance.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var theme = CPThemesByName[CPThemeNamesByInheritance[count]];
|
||||
|
||||
if ([theme._attributes containsKey:themeClass])
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
@@ -86,6 +133,9 @@ var CPThemesByName = { },
|
||||
_attributes = [CPDictionary dictionary];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -299,6 +349,9 @@ var CPThemeNameKey = @"CPThemeNameKey",
|
||||
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -466,12 +519,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
{
|
||||
_cache = {};
|
||||
|
||||
if (aValue === undefined || aValue === nil)
|
||||
_values = [CPDictionary dictionary];
|
||||
else
|
||||
_values = [CPDictionary dictionaryWithObject:aValue forKey:String(CPThemeStateNormal)];
|
||||
[self setValue:aValue forState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forState:(CPThemeState)aState
|
||||
|
||||
@@ -849,6 +849,10 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
view = [[_CPToolbarItemView alloc] initWithToolbarItem:item toolbar:self];
|
||||
|
||||
_viewsForToolbarItems[[item UID]] = view;
|
||||
|
||||
if ([item toolTip] && [view respondsToSelector:@selector(setToolTip:)])
|
||||
[view setToolTip:[item toolTip]];
|
||||
|
||||
[self addSubview:view];
|
||||
|
||||
_minWidth += [view minSize].width + TOOLBAR_ITEM_MARGIN;
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* CPUserDefaultsController.j
|
||||
* AppKit
|
||||
*
|
||||
* Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
|
||||
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2011, WireLoad 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/CPString.j>
|
||||
@import <AppKit/CPController.j>
|
||||
|
||||
var SharedUserDefaultsController = nil;
|
||||
|
||||
@implementation CPUserDefaultsController : CPController
|
||||
{
|
||||
CPUserDefaults _defaults @accessors(readonly, property=defaults);
|
||||
CPDictionary _initialValues @accessors(property=initialValues);
|
||||
BOOL _appliesImmediately @accessors(property=appliesImmediately);
|
||||
}
|
||||
|
||||
+ (id)sharedUserDefaultsController
|
||||
{
|
||||
if (!SharedUserDefaultsController)
|
||||
SharedUserDefaultsController = [[CPUserDefaultsController alloc] initWithDefaults:nil initialValues:nil];
|
||||
|
||||
return SharedUserDefaultsController;
|
||||
}
|
||||
|
||||
- (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
if (!someDefaults)
|
||||
someDefaults = [CPUserDefaults standardUserDefaults];
|
||||
|
||||
_defaults = someDefaults;
|
||||
_initialValues = [initialValues copy];
|
||||
_appliesImmediately = YES;
|
||||
_valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)values
|
||||
{
|
||||
return _valueProxy;
|
||||
}
|
||||
|
||||
- (BOOL)hasUnappliedChanges
|
||||
{
|
||||
return [_valueProxy hasUnappliedChanges];
|
||||
}
|
||||
|
||||
- (void)save:(id)sender
|
||||
{
|
||||
[_valueProxy save];
|
||||
}
|
||||
|
||||
- (void)revert:(id)sender
|
||||
{
|
||||
[_valueProxy revert];
|
||||
}
|
||||
|
||||
- (void)revertToInitialValues:(id)sender
|
||||
{
|
||||
[_valueProxy revertToInitialValues];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
|
||||
@implementation CPUserDefaultsController (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
|
||||
return [CPUserDefaultsController sharedUserDefaultsController];
|
||||
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
if (self === SharedUserDefaultsController)
|
||||
{
|
||||
[aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
|
||||
return;
|
||||
}
|
||||
|
||||
[CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CPUserDefaultsControllerProxy : CPObject
|
||||
{
|
||||
CPUserDefaultsController _controller;
|
||||
// TODO Could be optimised with a JS dict.
|
||||
CPMutableDictionary _cachedValues;
|
||||
}
|
||||
|
||||
- (id)initWithController:(CPUserDefaultsController)aController
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_controller = aController;
|
||||
_cachedValues = [CPMutableDictionary dictionary];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// FIXME No dealloc in Cappuccino.
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)valueForKey:(CPString)aKey
|
||||
{
|
||||
var value = [_cachedValues objectForKey:aKey];
|
||||
if (value === nil)
|
||||
{
|
||||
value = [[_controller defaults] objectForKey:aKey];
|
||||
if (value === nil)
|
||||
value = [[_controller initialValues] objectForKey:aKey];
|
||||
|
||||
if (value !== nil)
|
||||
[_cachedValues setObject:value forKey:aKey];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forKey:(CPString)aKey
|
||||
{
|
||||
[self willChangeValueForKey:aKey];
|
||||
[_cachedValues setObject:aValue forKey:aKey];
|
||||
if ([_controller appliesImmediately])
|
||||
[[_controller defaults] setObject:aValue forKey:aKey];
|
||||
[self didChangeValueForKey:aKey];
|
||||
}
|
||||
|
||||
|
||||
- (void)revert
|
||||
{
|
||||
var keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[self willChangeValueForKey:key];
|
||||
[_cachedValues removeObjectForKey:key];
|
||||
[self didChangeValueForKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)save
|
||||
{
|
||||
var keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)revertToInitialValues
|
||||
{
|
||||
var initial = [_controller initialValues],
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[self willChangeValueForKey:key];
|
||||
|
||||
var initialValue = [initial objectForKey:key];
|
||||
if (initialValue !== nil)
|
||||
[_cachedValues setObject:initialValue forKey:key];
|
||||
else
|
||||
[_cachedValues removeObjectForKey:key];
|
||||
|
||||
[self didChangeValueForKey:key];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userDefaultsDidChange:(CPNotification)aNotification
|
||||
{
|
||||
var defaults = [_controller defaults],
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
{
|
||||
var key = keys[keysCount],
|
||||
value = [_cachedValues objectForKey:key],
|
||||
newValue = [defaults objectForKey:key];
|
||||
|
||||
if (![value isEqual:newValue])
|
||||
{
|
||||
[self willChangeValueForKey:key];
|
||||
[_cachedValues setObject:newValue forKey:key];
|
||||
[self didChangeValueForKey:key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasUnappliedChanges
|
||||
{
|
||||
var defaults = [_controller defaults],
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
{
|
||||
var key = keys[keysCount],
|
||||
value = [_cachedValues objectForKey:key],
|
||||
newValue = [defaults objectForKey:key];
|
||||
|
||||
if (![value isEqual:newValue])
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+58
-9
@@ -186,6 +186,9 @@ var CPViewFlags = { },
|
||||
CPView _previousKeyView;
|
||||
|
||||
unsigned _viewClassFlags;
|
||||
|
||||
// ToolTips
|
||||
CPString _toolTip @accessors(property=toolTip);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -292,7 +295,7 @@ var CPViewFlags = { },
|
||||
_DOMImageSizes = [];
|
||||
#endif
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_themeState = CPThemeStateNormal;
|
||||
|
||||
[self setupViewFlags];
|
||||
@@ -1284,6 +1287,14 @@ var CPViewFlags = { },
|
||||
return view !== nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns YES if the view is not hidden, has no hidden ancestor and doesn't belong to a hidden window.
|
||||
*/
|
||||
- (BOOL)_isVisible
|
||||
{
|
||||
return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible];
|
||||
}
|
||||
|
||||
/*!
|
||||
Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
|
||||
e.g. when this view becomes hidden due to a setHidden:YES message to
|
||||
@@ -2121,6 +2132,20 @@ setBoundsOrigin:
|
||||
|
||||
@implementation CPView (KeyView)
|
||||
|
||||
/*!
|
||||
Overridden by subclasses to handle a key equivalent.
|
||||
|
||||
If the receiver’s key equivalent is the same as the characters of the key-down event theEvent,
|
||||
as returned by \ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]",
|
||||
the receiver should take the appropriate action and return \c YES. Otherwise, it should return
|
||||
the result of invoking super’s implementation. The default implementation of this method simply
|
||||
passes the message down the view hierarchy (from superviews to subviews)
|
||||
and returns \c NO if none of the receiver’s subviews responds \c YES.
|
||||
|
||||
@param anEvent An event object that represents the key equivalent pressed
|
||||
@return \c YES if theEvent is a key equivalent that the receiver handled,
|
||||
\c NO if it is not a key equivalent that it should handle.
|
||||
*/
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
var count = [_subviews count];
|
||||
@@ -2167,23 +2192,38 @@ setBoundsOrigin:
|
||||
|
||||
- (CPView)previousValidKeyView
|
||||
{
|
||||
var result = [self previousKeyView];
|
||||
var result = [self previousKeyView],
|
||||
firstResult = result;
|
||||
|
||||
while (result && ![result canBecomeKeyView])
|
||||
{
|
||||
result = [result previousKeyView];
|
||||
|
||||
// Cycled.
|
||||
if (result === firstResult)
|
||||
return nil;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)_setPreviousKeyView:(CPView)previous
|
||||
{
|
||||
_previousKeyView = previous;
|
||||
if ([previous isEqual:self])
|
||||
_previousKeyView = nil;
|
||||
else
|
||||
_previousKeyView = previous;
|
||||
}
|
||||
|
||||
- (void)setNextKeyView:(CPView)next
|
||||
{
|
||||
_nextKeyView = next;
|
||||
[_nextKeyView _setPreviousKeyView:self];
|
||||
if ([next isEqual:self])
|
||||
_nextKeyView = nil;
|
||||
else
|
||||
{
|
||||
_nextKeyView = next;
|
||||
[_nextKeyView _setPreviousKeyView:self];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2498,6 +2538,11 @@ setBoundsOrigin:
|
||||
return [_themeAttributes[aName] valueForState:_themeState];
|
||||
}
|
||||
|
||||
- (BOOL)hasThemeAttribute:(CPString)aName
|
||||
{
|
||||
return (_themeAttributes && _themeAttributes[aName] !== undefined);
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return nil;
|
||||
@@ -2609,7 +2654,11 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
_registeredDraggedTypesArray = [];
|
||||
|
||||
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
|
||||
// Other views (CPBox) might set an autoresizes mask on their subviews before it is actually decoded.
|
||||
// We make sure we don't override the value by checking if it was already set.
|
||||
if (_autoresizingMask === nil)
|
||||
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
|
||||
|
||||
_autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
|
||||
|
||||
_hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey];
|
||||
@@ -2646,7 +2695,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
|
||||
[self setupViewFlags];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey];
|
||||
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
|
||||
_themeAttributes = {};
|
||||
@@ -2727,12 +2776,12 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
|
||||
var nextKeyView = [self nextKeyView];
|
||||
|
||||
if (nextKeyView !== nil)
|
||||
if (nextKeyView !== nil && ![nextKeyView isEqual:self])
|
||||
[aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey];
|
||||
|
||||
var previousKeyView = [self previousKeyView];
|
||||
|
||||
if (previousKeyView !== nil)
|
||||
if (previousKeyView !== nil && ![previousKeyView isEqual:self])
|
||||
[aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
|
||||
|
||||
[aCoder encodeObject:[self themeClass] forKey:CPViewThemeClassKey];
|
||||
|
||||
+59
-31
@@ -29,26 +29,38 @@
|
||||
|
||||
var CPViewControllerCachedCibs;
|
||||
|
||||
/*! @class CPViewController
|
||||
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
|
||||
The basic view controller class supports the presentation of an associated view in addition to basic support
|
||||
for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
|
||||
CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPViewController
|
||||
|
||||
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
|
||||
this entails managing the view hierarchy responsible for presenting your application content.
|
||||
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
|
||||
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
|
||||
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
|
||||
or more additional view controllers that handle the presentation of the application content.
|
||||
The CPViewController class provides the fundamental view-management
|
||||
controller for Cappuccino applications. The basic view controller class
|
||||
supports the presentation of an associated view in addition to basic
|
||||
support for managing modal views and, in the future, animations.
|
||||
Subclasses such as CPNavigationController and CPTabBarController provide
|
||||
additional behavior for managing complex hierarchies of view controllers
|
||||
and views.
|
||||
|
||||
Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
|
||||
will add your root view to an existing view or window's content view. You can manage many view controllers
|
||||
on screen at once. CPViewController is also the preferred way of working with Cibs.
|
||||
You use each instance of CPViewController to manage a single view (and
|
||||
hierarchy). For a simple view controller, this entails managing the view
|
||||
hierarchy responsible for presenting your application content. A typical
|
||||
view hierarchy consists of a root view, a reference to which is available
|
||||
in the view property of this class, and one or more subviews presenting
|
||||
the actual content. In the case of navigation and tab bar controllers, the
|
||||
view controller manages not only the high-level view hierarchy (which
|
||||
provides the navigation controls) but also one or more additional view
|
||||
controllers that handle the presentation of the application content.
|
||||
|
||||
Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
|
||||
It has methods that are called when a view appears or disappears.
|
||||
This class is also a good place for delegate & datasource methods, and other controller stuff.
|
||||
Unlike UIViewController in Cocoa Touch, a CPViewController does not
|
||||
represent an entire screen of content. You will add your root view to an
|
||||
existing view or window's content view. You can manage many view
|
||||
controllers on screen at once. CPViewController is also the preferred way
|
||||
of working with Cibs.
|
||||
|
||||
Subclasses can override -loadView to create their custom view hierarchy,
|
||||
or specify a cib name to be loaded automatically. It has methods that are
|
||||
called when a view appears or disappears. This class is also a good place
|
||||
for delegate & datasource methods, and other controller stuff.
|
||||
*/
|
||||
@implementation CPViewController : CPResponder
|
||||
{
|
||||
@@ -88,9 +100,14 @@ var CPViewControllerCachedCibs;
|
||||
}
|
||||
|
||||
/*!
|
||||
The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
|
||||
In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
|
||||
If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
|
||||
The designated initializer. If you subclass CPViewController, you must
|
||||
call the super implementation of this method, even if you aren't using a
|
||||
Cib.
|
||||
|
||||
In the specified Cib, the File's Owner proxy should have its class set to
|
||||
your view controller subclass, with the view outlet connected to the main
|
||||
view. If you pass in a nil Cib name, then you must either call -setView:
|
||||
before -view is invoked, or override -loadView to set up your views.
|
||||
|
||||
@param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
|
||||
@param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
|
||||
@@ -113,14 +130,18 @@ var CPViewControllerCachedCibs;
|
||||
}
|
||||
|
||||
/*!
|
||||
Programmatically creates the view that the controller manages.
|
||||
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
|
||||
Programmatically creates the view that the controller manages. You should
|
||||
never call this method directly. The view controller calls this method
|
||||
when the view property is requested but is nil.
|
||||
|
||||
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||
If you create your views manually, you must override this method and use
|
||||
it to create your view and assign it to the view property. The default
|
||||
implementation for programmatic views is to create a plain view. You can
|
||||
invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views, you initialize the view using the
|
||||
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views, you initialize the view
|
||||
using the initWithCibName:bundle: method then you must not override this
|
||||
method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently synchronous.
|
||||
*/
|
||||
@@ -144,8 +165,10 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
Returns the view that the controller manages.
|
||||
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
||||
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
||||
|
||||
If this property is nil, the controller sends loadView to itself to create
|
||||
the view that it manages. Subclasses should override the loadView method
|
||||
to create any custom views. The default value is nil.
|
||||
*/
|
||||
- (CPView)view
|
||||
{
|
||||
@@ -183,8 +206,11 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
|
||||
|
||||
This method is called regardless of whether the views were stored in a nib
|
||||
file or created programmatically in the loadView method. This method is
|
||||
most commonly used to perform additional initialization steps on views
|
||||
that are loaded from cib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -194,7 +220,9 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
Manually sets the view that the controller manages.
|
||||
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
||||
|
||||
Setting to nil will cause -loadView to be called on all subsequent calls
|
||||
of -view.
|
||||
|
||||
@param aView The view this controller should represent.
|
||||
*/
|
||||
|
||||
+309
-88
@@ -36,55 +36,94 @@ CPWebViewProgressEstimateChangedNotification = "CPWebViewProgressEstimateChan
|
||||
CPWebViewProgressStartedNotification = "CPWebViewProgressStartedNotification";
|
||||
CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNotification";
|
||||
|
||||
/*!
|
||||
Automatically choose between AppKit (Cappuccino style) scrollbars and
|
||||
native scrollbars. In this mode AppKit scrollbars are always used except
|
||||
when the web view is loaded with a URL which does not appear to pass the
|
||||
same origin policy.
|
||||
*/
|
||||
CPWebViewScrollAuto = 0;
|
||||
/*!
|
||||
Always use AppKit scrollbars. If a URL is loaded whcih does not appear to
|
||||
pass the same origin policy, native scrollbars will be used but a warnning
|
||||
will be logged.
|
||||
*/
|
||||
CPWebViewScrollAppKit = 1;
|
||||
/*!
|
||||
Always use native (platform dependent) scrollbars.
|
||||
*/
|
||||
CPWebViewScrollNative = 2;
|
||||
/*!
|
||||
Never display scrollbars.
|
||||
*/
|
||||
CPWebViewScrollNone = 3;
|
||||
|
||||
// FIXME: somehow make CPWebView work with CPScrollView instead of native scrollbars (is this even possible?)
|
||||
/*!
|
||||
How frequently the size of the document will be checked at page load time
|
||||
when AppKit scrollbars are used.
|
||||
*/
|
||||
CPWebViewAppKitScrollPollInterval = 1.0;
|
||||
|
||||
/*!
|
||||
How many times the size of the size of the document will be checked at
|
||||
page load time when AppKit scrollbars are used.
|
||||
|
||||
AppKit scrollbars must check the size of the document to display the
|
||||
correct size of scrollbars. To improve performance the checks are only
|
||||
performed a limited number of times per reload.
|
||||
*/
|
||||
CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@class CPWebView
|
||||
|
||||
CPWebView is a class which allows you to display arbitrary HTML or embed a
|
||||
CPWebView allows you to display arbitrary HTML or embed a
|
||||
webpage inside your application.
|
||||
|
||||
It's important to note that the same origin policy applies to this view.
|
||||
That is, if the web page being displayed is not located in the same origin
|
||||
(protocol, domain, and port) as the application, you will have limited
|
||||
control over the view and no access to its contents.
|
||||
control over the view and no access to its contents. Furthermore,
|
||||
Cappuccino style scrollbars can't be used to scroll it.
|
||||
*/
|
||||
|
||||
@implementation CPWebView : CPView
|
||||
{
|
||||
CPScrollView _scrollView;
|
||||
CPView _frameView;
|
||||
CPScrollView _scrollView;
|
||||
CPView _frameView;
|
||||
|
||||
IFrame _iframe;
|
||||
CPString _mainFrameURL;
|
||||
CPArray _backwardStack;
|
||||
CPArray _forwardStack;
|
||||
IFrame _iframe;
|
||||
CPString _mainFrameURL;
|
||||
CPArray _backwardStack;
|
||||
CPArray _forwardStack;
|
||||
|
||||
BOOL _ignoreLoadStart;
|
||||
BOOL _ignoreLoadEnd;
|
||||
BOOL _ignoreLoadStart;
|
||||
BOOL _ignoreLoadEnd;
|
||||
BOOL _isLoading;
|
||||
|
||||
id _downloadDelegate;
|
||||
id _frameLoadDelegate;
|
||||
id _policyDelegate;
|
||||
id _resourceLoadDelegate;
|
||||
id _UIDelegate;
|
||||
id _downloadDelegate;
|
||||
id _frameLoadDelegate;
|
||||
id _policyDelegate;
|
||||
id _resourceLoadDelegate;
|
||||
id _UIDelegate;
|
||||
|
||||
CPWebScriptObject _wso;
|
||||
CPWebScriptObject _wso;
|
||||
|
||||
CPString _url;
|
||||
CPString _html;
|
||||
CPString _url;
|
||||
CPString _html;
|
||||
|
||||
Function _loadCallback;
|
||||
Function _loadCallback;
|
||||
|
||||
int _scrollMode;
|
||||
CGSize _scrollSize;
|
||||
int _scrollMode;
|
||||
int _effectiveScrollMode;
|
||||
BOOL _contentIsAccessible;
|
||||
CPTimer _contentSizeCheckTimer;
|
||||
int _contentSizePollCount;
|
||||
|
||||
int _loadHTMLStringTimer;
|
||||
int _loadHTMLStringTimer;
|
||||
|
||||
BOOL _drawsBackground;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
|
||||
@@ -93,17 +132,24 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
_iframe.name = frameName;
|
||||
}
|
||||
return self
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollAuto;
|
||||
_contentIsAccessible = YES;
|
||||
_isLoading = NO;
|
||||
|
||||
_drawsBackground = YES;
|
||||
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
|
||||
[self _initDOMWithFrame:aFrame];
|
||||
}
|
||||
@@ -123,9 +169,10 @@ CPWebViewScrollNative = 2;
|
||||
_iframe.style.borderWidth = "0px";
|
||||
_iframe.frameBorder = "0";
|
||||
|
||||
[self setDrawsBackground:YES];
|
||||
[self _applyBackgroundColor];
|
||||
|
||||
_loadCallback = function() {
|
||||
_loadCallback = function()
|
||||
{
|
||||
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
|
||||
if (!_ignoreLoadStart)
|
||||
{
|
||||
@@ -137,7 +184,6 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
|
||||
_mainFrameURL = _iframe.src;
|
||||
_mainFrameURL = _iframe.src;
|
||||
|
||||
// clear the forward
|
||||
[_forwardStack removeAllObjects];
|
||||
@@ -170,21 +216,29 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
_frameView._DOMElement.appendChild(_iframe);
|
||||
|
||||
[self _setScrollMode:_scrollMode];
|
||||
[self _updateEffectiveScrollMode];
|
||||
|
||||
[self addSubview:_scrollView];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
|
||||
- (void)viewDidUnhide
|
||||
{
|
||||
// Sizing cannot properly happen while we're hidden because the iframe is inaccessible.
|
||||
// So now that it is accessible again, make sure to catch up.
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
[self _resizeWebFrame];
|
||||
[self _scheduleContentSizeCheck];
|
||||
}
|
||||
|
||||
- (void)_attachScrollEventIfNecessary
|
||||
{
|
||||
if (_scrollMode !== CPWebViewScrollAppKit)
|
||||
if (_effectiveScrollMode !== CPWebViewScrollAppKit)
|
||||
return;
|
||||
|
||||
var win = null;
|
||||
@@ -209,75 +263,130 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
- (void)_resizeWebFrame
|
||||
{
|
||||
if (_scrollMode === CPWebViewScrollAppKit)
|
||||
// When a webview is not in the DOM we can't inspect its contents for sizing information.
|
||||
// If we try, we might end up setting the fallback frame size which will then become
|
||||
// somewhat sticky.
|
||||
if (![self _isVisible])
|
||||
{
|
||||
if (_scrollSize)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_effectiveScrollMode === CPWebViewScrollAppKit)
|
||||
{
|
||||
var visibleRect = [_frameView visibleRect];
|
||||
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
|
||||
if (win && win.document && win.document.body)
|
||||
{
|
||||
[_frameView setFrameSize:_scrollSize];
|
||||
var width = win.document.body.scrollWidth,
|
||||
height = win.document.body.scrollHeight;
|
||||
|
||||
_iframe.setAttribute("width", width);
|
||||
_iframe.setAttribute("height", height);
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(width, height)];
|
||||
}
|
||||
else
|
||||
{
|
||||
var visibleRect = [_frameView visibleRect];
|
||||
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
|
||||
if (win && win.document && win.document.body)
|
||||
{
|
||||
var width = win.document.body.scrollWidth,
|
||||
height = win.document.body.scrollHeight;
|
||||
|
||||
_iframe.setAttribute("width", width);
|
||||
_iframe.setAttribute("height", height);
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(width, height)];
|
||||
}
|
||||
else
|
||||
// If we do have access to the content, it might be that the 'body' element simply hasn't loaded yet.
|
||||
// The size will be updated by the content size timer in this case.
|
||||
if (!win || !win.document)
|
||||
{
|
||||
CPLog.warn("using default size 800*1600");
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
||||
}
|
||||
|
||||
[_frameView scrollRectToVisible:visibleRect];
|
||||
}
|
||||
|
||||
[_frameView scrollRectToVisible:visibleRect];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the scroll mode of the receiver. Valid options are
|
||||
CPWebViewScrollAppKit and CPWebViewScrollNative.
|
||||
Sets the scroll mode of the receiver.
|
||||
|
||||
Valid values are:
|
||||
CPWebViewScrollAuto
|
||||
CPWebViewScrollAppKit
|
||||
CPWebViewScrollNative
|
||||
CPWebViewScrollNone
|
||||
|
||||
CPWebViewScrollAuto
|
||||
*/
|
||||
- (void)setScrollMode:(int)aScrollMode
|
||||
{
|
||||
if (_scrollMode == aScrollMode)
|
||||
return;
|
||||
|
||||
[self _setScrollMode:aScrollMode];
|
||||
_scrollMode = aScrollMode;
|
||||
|
||||
[self _updateEffectiveScrollMode];
|
||||
}
|
||||
|
||||
- (void)_setScrollMode:(int)aScrollMode
|
||||
/*!
|
||||
Returns the effective scroll mode of the receiver.
|
||||
|
||||
Valied values are:
|
||||
CPWebViewScrollAuto
|
||||
CPWebViewScrollAppKit
|
||||
CPWebViewScrollNative
|
||||
CPWebViewScrollNone
|
||||
*/
|
||||
- (int)effectiveScrollMode
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
else
|
||||
_scrollMode = aScrollMode;
|
||||
return _effectiveScrollMode;
|
||||
}
|
||||
|
||||
- (void)_updateEffectiveScrollMode
|
||||
{
|
||||
var _newScrollMode = CPWebViewScrollAppKit;
|
||||
|
||||
if (_scrollMode == CPWebViewScrollNative
|
||||
|| (_scrollMode == CPWebViewScrollAuto && !_contentIsAccessible)
|
||||
|| CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_newScrollMode = CPWebViewScrollNative;
|
||||
}
|
||||
else if (_scrollMode == CPWebViewScrollAppKit && !_contentIsAccessible)
|
||||
{
|
||||
// Same behaviour as the previous case except that a warning is logged when AppKit
|
||||
// scrollers can't be used.
|
||||
CPLog.warn(self + " unable to use CPWebViewScrollAppKit scroll mode due to same origin policy.");
|
||||
_newScrollMode = CPWebViewScrollNative;
|
||||
}
|
||||
|
||||
if (_newScrollMode !== _effectiveScrollMode)
|
||||
[self _setEffectiveScrollMode:_newScrollMode];
|
||||
}
|
||||
|
||||
- (void)_setEffectiveScrollMode:(int)aScrollMode
|
||||
{
|
||||
_effectiveScrollMode = aScrollMode;
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
var parent = _iframe.parentNode;
|
||||
// FIXME "scrolling" can't be changed without readding the iframe. Unfortunately this causes a reload.
|
||||
parent.removeChild(_iframe);
|
||||
|
||||
if (_scrollMode === CPWebViewScrollAppKit)
|
||||
if (_effectiveScrollMode === CPWebViewScrollAppKit)
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:YES];
|
||||
[_scrollView setHasVerticalScroller:YES];
|
||||
|
||||
_iframe.setAttribute("scrolling", "no");
|
||||
}
|
||||
else if (_effectiveScrollMode === CPWebViewScrollNone)
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:NO];
|
||||
[_scrollView setHasVerticalScroller:NO];
|
||||
|
||||
_iframe.setAttribute("scrolling", "no");
|
||||
}
|
||||
else
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:NO];
|
||||
@@ -289,10 +398,21 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
|
||||
parent.appendChild(_iframe);
|
||||
[self _applyBackgroundColor];
|
||||
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
|
||||
- (void)_maybePollWebFrameSize
|
||||
{
|
||||
if (CPWebViewAppKitScrollMaxPollCount == 0 || _contentSizePollCount++ < CPWebViewAppKitScrollMaxPollCount)
|
||||
[self _resizeWebFrame];
|
||||
else
|
||||
[_contentSizeCheckTimer invalidate];
|
||||
}
|
||||
|
||||
/*!
|
||||
Loads a string of HTML into the webview.
|
||||
Loads a string of HTML into the receiver.
|
||||
|
||||
@param CPString - The string to load.
|
||||
*/
|
||||
@@ -302,7 +422,7 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
|
||||
/*!
|
||||
Loads a string of HTML into the webview.
|
||||
Loads a string of HTML into the receiver.
|
||||
|
||||
@param CPString - The string to load.
|
||||
@param CPURL - The base url of the string. (not implemented)
|
||||
@@ -310,17 +430,13 @@ CPWebViewScrollNative = 2;
|
||||
- (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL
|
||||
{
|
||||
// FIXME: do something with baseURL?
|
||||
|
||||
[self _setScrollMode:CPWebViewScrollAppKit];
|
||||
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
_url = null;
|
||||
_url = nil;
|
||||
_html = aString;
|
||||
|
||||
[self _load];
|
||||
@@ -328,15 +444,12 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
- (void)_loadMainFrameURL
|
||||
{
|
||||
[self _setScrollMode:CPWebViewScrollNative];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
_url = _mainFrameURL;
|
||||
_html = null;
|
||||
_html = nil;
|
||||
|
||||
[self _load];
|
||||
}
|
||||
@@ -345,13 +458,26 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
if (_url)
|
||||
{
|
||||
// Try to figure out if this URL will pass the same origin policy and hence allow us to potentially
|
||||
// use appkit scrollbars.
|
||||
var cpurl = [CPURL URLWithString:_url];
|
||||
_contentIsAccessible = [cpurl _passesSameOriginPolicy];
|
||||
[self _updateEffectiveScrollMode];
|
||||
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
_iframe.src = _url;
|
||||
}
|
||||
else if (_html)
|
||||
else if (_html !== nil)
|
||||
{
|
||||
// clear the iframe
|
||||
_iframe.src = "";
|
||||
|
||||
_contentIsAccessible = YES;
|
||||
[self _updateEffectiveScrollMode];
|
||||
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
if (_loadHTMLStringTimer !== nil)
|
||||
{
|
||||
window.clearTimeout(_loadHTMLStringTimer);
|
||||
@@ -363,8 +489,11 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
var win = [self DOMWindow];
|
||||
|
||||
/*
|
||||
If _html is the empty string, subtitute in an empty HTML structure. Just leaving the contents entirely empty prompts the browser to subtitute in a white page which would interfere with any custom background colours in use by this web view.
|
||||
*/
|
||||
if (win)
|
||||
win.document.write(_html);
|
||||
win.document.write(_html || "<html><body></body></html>");
|
||||
|
||||
window.setTimeout(_loadCallback, 1);
|
||||
}, 0);
|
||||
@@ -373,6 +502,8 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
- (void)_startedLoading
|
||||
{
|
||||
_isLoading = YES;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressStartedNotification object:self];
|
||||
|
||||
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
|
||||
@@ -381,15 +512,54 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
- (void)_finishedLoading
|
||||
{
|
||||
_isLoading = NO;
|
||||
|
||||
[self _resizeWebFrame];
|
||||
[self _attachScrollEventIfNecessary];
|
||||
|
||||
[self _scheduleContentSizeCheck];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
|
||||
|
||||
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
|
||||
[_frameLoadDelegate webView:self didFinishLoadForFrame:nil]; // FIXME: give this a frame somehow?
|
||||
}
|
||||
|
||||
- (void)_scheduleContentSizeCheck
|
||||
{
|
||||
[_contentSizeCheckTimer invalidate];
|
||||
if (_effectiveScrollMode == CPWebViewScrollAppKit)
|
||||
{
|
||||
/*
|
||||
FIXME Need better method.
|
||||
We don't know when the content of the iframe changes size (e.g. a
|
||||
picture finishes loading, dynamic content is loaded). Often when a
|
||||
page has initially 'loaded', it does not yet have its final size. In
|
||||
lieu of any resize events we will simply check back in a few times
|
||||
some time after loading.
|
||||
|
||||
We run these checks only a limited number of times as to not deplete
|
||||
battery life and slow down the software needlessly. This does mean
|
||||
there are situations where the content changes size and the AppKit
|
||||
scrollbars will be out of sync. Users who have dynamic content
|
||||
in their web view will, for now, have to implement domain specific
|
||||
fixes.
|
||||
*/
|
||||
|
||||
_contentSizePollCount = 0;
|
||||
_contentSizeCheckTimer = [CPTimer scheduledTimerWithTimeInterval:CPWebViewAppKitScrollPollInterval target:self selector:@selector(_maybePollWebFrameSize) userInfo:nil repeats:YES];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the web view is loading. Note: due to browser limitations
|
||||
this value is not particularly reliable.
|
||||
*/
|
||||
- (BOOL)isLoading
|
||||
{
|
||||
return _isLoading;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the URL of the main frame.
|
||||
|
||||
@@ -570,19 +740,44 @@ CPWebViewScrollNative = 2;
|
||||
*/
|
||||
- (BOOL)drawsBackground
|
||||
{
|
||||
return _iframe.style.backgroundColor != "";
|
||||
return _drawsBackground;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the webview draws its own background.
|
||||
Sets whether the webview draws its own background when the displayed contents do not.
|
||||
|
||||
If you are trying to create a transparent iframe:
|
||||
|
||||
A) call this method with NO
|
||||
A) call setBackground:[CPColor transparent]
|
||||
B) ensure the content does not draw a background, e.g. it has <body style="background-color: transparent;">
|
||||
|
||||
@param BOOL - YES if the webview should draw its background, otherwise NO.
|
||||
*/
|
||||
- (void)setDrawsBackground:(BOOL)drawsBackround
|
||||
- (void)setDrawsBackground:(BOOL)drawsBackground
|
||||
{
|
||||
_iframe.style.backgroundColor = drawsBackround ? "white" : "";
|
||||
if (drawsBackground == _drawsBackground)
|
||||
return;
|
||||
_drawsBackground = drawsBackground;
|
||||
|
||||
[self _applyBackgroundColor];
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(CPColor)aColor
|
||||
{
|
||||
[super setBackgroundColor:aColor];
|
||||
[self _applyBackgroundColor];
|
||||
}
|
||||
|
||||
- (void)_applyBackgroundColor
|
||||
{
|
||||
if (_iframe)
|
||||
{
|
||||
var bgColor = [self backgroundColor] || [CPColor whiteColor];
|
||||
_iframe.allowtransparency = !_drawsBackground;
|
||||
_iframe.style.backgroundColor = _drawsBackground ? [bgColor cssString] : "transparent";
|
||||
}
|
||||
}
|
||||
|
||||
// IBActions
|
||||
|
||||
@@ -634,7 +829,11 @@ CPWebViewScrollNative = 2;
|
||||
*/
|
||||
- (@action)reload:(id)sender
|
||||
{
|
||||
[self _loadMainFrameURL];
|
||||
// If we're displaying pure HTML, redisplay it.
|
||||
if(!_url && (_html !== nil))
|
||||
[self loadHTMLString:_html];
|
||||
else
|
||||
[self _loadMainFrameURL];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -789,13 +988,16 @@ CPWebViewScrollNative = 2;
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
_scrollMode = CPWebViewScrollAuto;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[self _initDOMWithFrame:[self frame]];
|
||||
#endif
|
||||
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
if (![self backgroundColor])
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
|
||||
[self _updateEffectiveScrollMode];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -815,3 +1017,22 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPURL(SOP)
|
||||
|
||||
/*!
|
||||
Private API.
|
||||
|
||||
Returns YES if the receiver URL would pass the same origin policy if loaded by the current runtime environment.
|
||||
|
||||
Since Cappuccino runs in the browser, it is often restricted from accessing URLs from outside of its own origin (protocol, domain, port). This method tries to determine if the URL represented by the receiver is of the same origin, or if other circumstances will allow the content at the URL to be interacted with.
|
||||
*/
|
||||
- (BOOL)_passesSameOriginPolicy
|
||||
{
|
||||
var documentURL = [CPURL URLWithString:window.location.href];
|
||||
if ([documentURL isFileURL] && CPFeatureIsCompatible(CPSOPDisabledFromFileURLs))
|
||||
return YES;
|
||||
return ([documentURL scheme] == [self scheme] && [documentURL host] == [self host] && [documentURL port] == [self port]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+33
-14
@@ -193,24 +193,24 @@ var SHADOW_MARGIN_LEFT = 20.0,
|
||||
_CPWindowShadowColor = nil;
|
||||
|
||||
var CPWindowSaveImage = nil,
|
||||
CPWindowSavingImage = nil;
|
||||
CPWindowSavingImage = nil,
|
||||
|
||||
var CPWindowResizeTime = 0.2;
|
||||
CPWindowResizeTime = 0.2;
|
||||
|
||||
/*
|
||||
Keys for which action messages will be sent by default when unhandled, e.g. complete:.
|
||||
*/
|
||||
var CPWindowActionMessageKeys = [
|
||||
CPLeftArrowFunctionKey,
|
||||
CPRightArrowFunctionKey,
|
||||
CPUpArrowFunctionKey,
|
||||
CPDownArrowFunctionKey,
|
||||
CPPageUpFunctionKey,
|
||||
CPPageDownFunctionKey,
|
||||
CPHomeFunctionKey,
|
||||
CPEndFunctionKey,
|
||||
CPEscapeFunctionKey
|
||||
];
|
||||
CPLeftArrowFunctionKey,
|
||||
CPRightArrowFunctionKey,
|
||||
CPUpArrowFunctionKey,
|
||||
CPDownArrowFunctionKey,
|
||||
CPPageUpFunctionKey,
|
||||
CPPageDownFunctionKey,
|
||||
CPHomeFunctionKey,
|
||||
CPEndFunctionKey,
|
||||
CPEscapeFunctionKey
|
||||
];
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -466,12 +466,26 @@ CPTexturedBackgroundWindowMask
|
||||
return _platformWindow;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the platform window of the reciver.
|
||||
This method will first close the reciever,
|
||||
change the platform window, then reopen the window (if it was originally open).
|
||||
*/
|
||||
- (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow
|
||||
{
|
||||
// FIXME: already visible.
|
||||
var wasVisible = [self isVisible];
|
||||
|
||||
// we have to close it first, otherwise we get a DOM exception.
|
||||
if (wasVisible)
|
||||
[self close];
|
||||
|
||||
_platformWindow = aPlatformWindow;
|
||||
|
||||
if (wasVisible)
|
||||
[self orderFront:self];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
@@ -2377,7 +2391,9 @@ CPTexturedBackgroundWindowMask
|
||||
// an event going of the responder chain is passed to the input system as a last resort.
|
||||
// However, the only methods I could get Cocoa to call automatically are
|
||||
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
|
||||
[self _processKeyboardUIKey:anEvent];
|
||||
// Unhandled events just travel further up the responder chain _past_ the window.
|
||||
if (![self _processKeyboardUIKey:anEvent])
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2412,6 +2428,8 @@ CPTexturedBackgroundWindowMask
|
||||
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
|
||||
[[self firstResponder] doCommandBySelector:@selector(complete:)];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_dirtyKeyViewLoop
|
||||
@@ -2906,6 +2924,7 @@ CPCustomWindowShadowStyle = 3;
|
||||
@import "_CPWindowView.j"
|
||||
@import "_CPStandardWindowView.j"
|
||||
@import "_CPDocModalWindowView.j"
|
||||
@import "_CPToolTipWindowView.j"
|
||||
@import "_CPHUDWindowView.j"
|
||||
@import "_CPBorderlessWindowView.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
|
||||
@@ -46,31 +46,31 @@ var _CPToolbarViewBackgroundColor = nil;
|
||||
- (void)tile
|
||||
{
|
||||
[super tile];
|
||||
|
||||
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds];
|
||||
|
||||
|
||||
[[theWindow contentView] setFrame:CGRectMake(0.0, [self toolbarMaxY], CGRectGetWidth(bounds), CGRectGetHeight(bounds) - [self toolbarMaxY])];
|
||||
|
||||
|
||||
if (![[theWindow toolbar] isVisible])
|
||||
{
|
||||
[_toolbarBackgroundView removeFromSuperview];
|
||||
|
||||
|
||||
_toolbarBackgroundView = nil;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_toolbarBackgroundView)
|
||||
{
|
||||
_toolbarBackgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
[_toolbarBackgroundView setBackgroundColor:[[self class] toolbarBackgroundColor]];
|
||||
[_toolbarBackgroundView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
|
||||
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
|
||||
}
|
||||
|
||||
|
||||
var frame = CGRectMakeZero(),
|
||||
toolbarOffset = [self toolbarOffset];
|
||||
|
||||
|
||||
@@ -13,25 +13,25 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
|
||||
{
|
||||
if (!_CPStandardWindowViewBodyBackgroundColor)
|
||||
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:0.9];
|
||||
|
||||
return _CPStandardWindowViewBodyBackgroundColor;
|
||||
|
||||
return _CPStandardWindowViewBodyBackgroundColor;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
self = [super initWithFrame:aFrame styleMask:aStyleMask];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
var theClass = [self class],
|
||||
bounds = [self bounds];
|
||||
|
||||
|
||||
_bodyView = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, _CGRectGetWidth(bounds), _CGRectGetHeight(bounds))];
|
||||
|
||||
|
||||
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
|
||||
[_bodyView setHitTests:NO];
|
||||
|
||||
|
||||
[self addSubview:_bodyView];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
@@ -41,7 +41,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
|
||||
[self addSubview:_shadowView];
|
||||
}
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
|
||||
@@ -106,7 +106,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil,
|
||||
_CPStandardWindowViewMinimizeButtonImage = nil,
|
||||
_CPStandardWindowViewMinimizeButtonHighlightedImage = nil;
|
||||
|
||||
var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
var STANDARD_GRADIENT_HEIGHT = 41.0,
|
||||
STANDARD_TITLEBAR_HEIGHT = 25.0;
|
||||
|
||||
@implementation _CPStandardWindowView : _CPWindowView
|
||||
@@ -342,7 +342,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
if (_minimizeButton)
|
||||
leftOffset += 19.0;
|
||||
|
||||
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset*2.0, CGRectGetHeight([_titleField frame]))];
|
||||
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset * 2.0, CGRectGetHeight([_titleField frame]))];
|
||||
|
||||
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* _CPToolTipWindowView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal
|
||||
* Copyright 2011 <primalmotion@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
|
||||
* 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 "_CPWindowView.j"
|
||||
|
||||
|
||||
@implementation _CPToolTipWindowView : _CPWindowView
|
||||
{
|
||||
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
|
||||
unsigned _gravity @accessors(property=gravity);
|
||||
|
||||
CPColor _backgroundColor;
|
||||
CPColor _strokeColor;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
/*! compute the contentView frame from a given window frame
|
||||
@param aFrameRect the window frame
|
||||
*/
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect);
|
||||
|
||||
contentRect.origin.x += 3;
|
||||
contentRect.origin.y += 3;
|
||||
contentRect.size.width -= 6;
|
||||
contentRect.size.height -= 6;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
/*! compute the window frame from a given contentView frame
|
||||
@param aContentRect the contentView frame
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var aFrameRect = CGRectMakeCopy(aContentRect);
|
||||
|
||||
aFrameRect.origin.x -= 3;
|
||||
aFrameRect.origin.y -= 3;
|
||||
aFrameRect.size.width += 6;
|
||||
aFrameRect.size.height += 6;
|
||||
|
||||
return aFrameRect;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
_strokeColor = [CPColor colorWithHexString:@"E3E3E3"];
|
||||
_backgroundColor = [CPColor colorWithHexString:@"FFFFCA"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark drawing
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = 2,
|
||||
strokeWidth = 1;
|
||||
|
||||
CGContextSetStrokeColor(context, _strokeColor);
|
||||
CGContextSetFillColor(context, _backgroundColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
|
||||
aRect.origin.x += strokeWidth;
|
||||
aRect.origin.y += strokeWidth;
|
||||
aRect.size.width -= strokeWidth * 2;
|
||||
aRect.size.height -= strokeWidth * 2;
|
||||
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
|
||||
CGContextClosePath(context);
|
||||
|
||||
//Draw it
|
||||
CGContextStrokePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -161,7 +161,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
var minPointY = 0;
|
||||
|
||||
if([CPMenu menuBarVisible])
|
||||
if ([CPMenu menuBarVisible])
|
||||
minPointY = [[CPApp mainMenu] menuBarHeight];
|
||||
|
||||
var restrictedPoint = CGPointMake(0, 0);
|
||||
|
||||
@@ -32,10 +32,15 @@
|
||||
@ingroup appkit
|
||||
@class CPWindowController
|
||||
|
||||
An instance of a CPWindowController manages a CPWindow. It has methods
|
||||
that get called when the window is loading, and after the window has loaded. In the
|
||||
Model-View-Controller method of program design, the CPWindowController would be
|
||||
considered the 'Controller' and the CPWindow the 'Model.'
|
||||
An instance of a CPWindowController manages a CPWindow. Windows are typically loaded via a cib,
|
||||
but they can also manage windows created in code. A CPWindowController can manage a window by
|
||||
itself or work with AppKits's document-based architecture.
|
||||
|
||||
In a Document based app, a CPWindowController instance is created and managed by a CPDocument subclass.
|
||||
|
||||
If the CPWindowController is managing a CPWindow created in a cib the \c owner of the CPWindow is this controller.
|
||||
|
||||
@note When creating the window programatically (instead of a cib) you should override the \c loadWindow method.\c loadWindow is called the first time the window object is needed. @endnote
|
||||
*/
|
||||
@implementation CPWindowController : CPResponder
|
||||
{
|
||||
@@ -124,7 +129,8 @@
|
||||
}
|
||||
|
||||
/*!
|
||||
Loads the window
|
||||
Loads the window. This method should never be called directly. Instead call \c window which will in turn call windowWillLoad and windowDidLoad.
|
||||
This method should be overwritten if you are creating the view programatically.
|
||||
*/
|
||||
- (void)loadWindow
|
||||
{
|
||||
@@ -158,7 +164,8 @@
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the window this object controls.
|
||||
Returns the CPWindow the reciever controls.
|
||||
This will cause \c loadWindow to be called if no window object exists yet.
|
||||
*/
|
||||
- (CPWindow)window
|
||||
{
|
||||
@@ -377,7 +384,7 @@
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the document in the controlled window.
|
||||
Returns the CPDocument in the controlled window.
|
||||
*/
|
||||
- (CPDocument)document
|
||||
{
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ CPCibOwner = @"CPCibOwner",
|
||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
|
||||
CPCibReplacementClasses = @"CPCibReplacementClasses",
|
||||
CPCibExternalObjects = @"CPCibExternalObjects";
|
||||
|
||||
|
||||
var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
/*!
|
||||
@@ -87,7 +87,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
{
|
||||
if (![aName hasSuffix:@".cib"])
|
||||
aName = [aName stringByAppendingString:@".cib"];
|
||||
|
||||
|
||||
// If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
|
||||
self = [self initWithContentsOfURL:[aBundle || [CPBundle mainBundle] pathForResource:aName]];
|
||||
|
||||
|
||||
@@ -64,14 +64,14 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
|
||||
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
|
||||
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,8 @@
|
||||
|
||||
// If the destination doesn't respond to this selector, warn but don't die.
|
||||
if (_destination && ![_destination respondsToSelector:selector])
|
||||
{
|
||||
CPLog.warn(@"Could not connect the action " + selector + @" to target of class " + [_destination className]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Not being able to set the action is a fatal error.
|
||||
if ([_source respondsToSelector:@selector(setAction:)])
|
||||
objj_msgSend(_source, @selector(setAction:), selector);
|
||||
|
||||
@@ -76,7 +76,7 @@ var CPCibOwner = @"CPCibOwner";
|
||||
// Path is based solely on anOwner:
|
||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||
path = [bundle pathForResource:aName];
|
||||
|
||||
|
||||
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* CPCibRuntimeAttributesConnector.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Aparajita Fishman.
|
||||
* Copyright 2011, 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 "CPCibConnector.j"
|
||||
|
||||
var CPCibRuntimeAttributesConnectorObjectKey = @"CPCibRuntimeAttributesConnectorObjectKey",
|
||||
CPCibRuntimeAttributesConnectorKeyPathsKey = @"CPCibRuntimeAttributesConnectorKeyPathsKey",
|
||||
CPCibRuntimeAttributesConnectorValuesKey = @"CPCibRuntimeAttributesConnectorValuesKey";
|
||||
|
||||
@implementation CPCibRuntimeAttributesConnector : CPCibConnector
|
||||
{
|
||||
id _keyPaths;
|
||||
id _values;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_source = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
_keyPaths = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
_values = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_source forKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
[aCoder encodeObject:_keyPaths forKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
[aCoder encodeObject:_values forKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
- (void)establishConnection
|
||||
{
|
||||
var count = [_keyPaths count];
|
||||
|
||||
while (count--)
|
||||
[_source setValue:_values[count] forKeyPath:_keyPaths[count]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -61,14 +61,14 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
|
||||
|
||||
if (!object)
|
||||
{
|
||||
CPLog.error("Unable to find class " + theClassName + " in cib file.");
|
||||
CPLog.error("Unable to find class " + theClassName + " referenced in cib file.");
|
||||
|
||||
object = [self allocObjectWithCoder:aCoder className:[aCoder decodeObjectForKey:_CPCibClassSwapperOriginalClassNameKey]];
|
||||
}
|
||||
}
|
||||
|
||||
if (!object)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " in cib file."];
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " referenced in cib file."];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObject:aSize forKey:@"size"]];
|
||||
}
|
||||
|
||||
+ (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize bundleClass:(CPString)aBundleClass
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObjects:[aSize, aBundleClass] forKeys:[@"size", @"bundleClass"]]];
|
||||
}
|
||||
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
self = [super init];
|
||||
@@ -83,7 +88,25 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
||||
if (_className === @"CPImage")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
{
|
||||
if (_resourceName == "CPAddTemplate")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||
else if (_resourceName == "CPRemoveTemplate")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
|
||||
var bundleClass = _properties.valueForKey(@"bundleClass"),
|
||||
bundle = nil;
|
||||
|
||||
if (bundleClass)
|
||||
{
|
||||
bundleClass = CPClassFromString(bundleClass);
|
||||
|
||||
if (bundleClass)
|
||||
bundle = [CPBundle bundleForClass:bundleClass];
|
||||
}
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[(bundle || [aCoder bundle]) pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibBindingConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
|
||||
|
||||
@implementation _CPCibObjectData : CPObject
|
||||
@@ -257,11 +258,29 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
_replacementObjects[[_fileOwner UID]] = anOwner;
|
||||
|
||||
var index = 0,
|
||||
count = _connections.length;
|
||||
count = _connections.length,
|
||||
runtimeAttributeConnectors = [],
|
||||
connection = nil;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var connection = _connections[index];
|
||||
connection = _connections[index];
|
||||
|
||||
if ([connection isKindOfClass:[CPCibRuntimeAttributesConnector class]])
|
||||
// Defer runtime attribute connections until after all other connections are made
|
||||
runtimeAttributeConnectors.push(connection);
|
||||
else
|
||||
{
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
}
|
||||
}
|
||||
|
||||
count = runtimeAttributeConnectors.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
connection = runtimeAttributeConnectors[index];
|
||||
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
_isRemovedOnCompletion = YES;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -130,12 +130,12 @@
|
||||
@end
|
||||
|
||||
/*
|
||||
|
||||
|
||||
*/
|
||||
@implementation CAPropertyAnimation : CAAnimation
|
||||
{
|
||||
CPString _keyPath;
|
||||
|
||||
|
||||
BOOL _isCumulative;
|
||||
BOOL _isAdditive;
|
||||
}
|
||||
@@ -143,9 +143,9 @@
|
||||
+ (id)animationWithKeyPath:(CPString)aKeyPath
|
||||
{
|
||||
var animation = [self animation];
|
||||
|
||||
|
||||
[animation setKeyPath:aKeyPath];
|
||||
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@ if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
CABackingStoreCreate = function()
|
||||
{
|
||||
var DOMElement = document.createElement("canvas");
|
||||
|
||||
|
||||
DOMElement.style.position = "absolute";
|
||||
|
||||
|
||||
// FIXME: Consolidate drawImage to support this.
|
||||
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
|
||||
}
|
||||
@@ -47,7 +47,7 @@ CABackingStoreCreate = function()
|
||||
CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
{
|
||||
var buffer = aBackingStore.buffer;
|
||||
|
||||
|
||||
buffer.width = aSize.width;
|
||||
buffer.height = aSize.height;
|
||||
buffer.style.width = PIXEL(aSize.width);
|
||||
@@ -60,9 +60,9 @@ else
|
||||
CABackingStoreCreate = function()
|
||||
{
|
||||
var context = CGBitmapGraphicsContextCreate();
|
||||
|
||||
|
||||
context.buffer = "";
|
||||
|
||||
|
||||
return { context:context };
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
{
|
||||
if (_flashMovie == aFlashMovie)
|
||||
return;
|
||||
|
||||
|
||||
_flashMovie = aFlashMovie;
|
||||
|
||||
|
||||
_DOMElement.innerHTML = "<object width = \"100%\" height = \"100%\"><param name = \"movie\" value = \"" +
|
||||
aFlashMovie._fileName +
|
||||
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
|
||||
aFlashMovie._fileName +
|
||||
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
|
||||
aFlashMovie._fileName + "\" type = \"application/x-shockwave-flash\" wmode = \"transparent\" width = \"100%\" height = \"100%\"></embed></object>";
|
||||
}
|
||||
|
||||
|
||||
@@ -449,23 +449,28 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
||||
CGContextClearRect(_context, _CGRectMake(0.0, 0.0, _CGRectGetWidth(_backingStoreFrame), _CGRectGetHeight(_backingStoreFrame)));
|
||||
|
||||
// Recomposite
|
||||
var transform = _transformFromLayer;
|
||||
var transform;
|
||||
|
||||
if (_superlayer)
|
||||
{
|
||||
var superlayerTransform = _CALayerGetTransform(_superlayer, nil),
|
||||
superlayerOrigin = CGPointApplyAffineTransform(_superlayer._bounds.origin, superlayerTransform);
|
||||
|
||||
transform = CGAffineTransformConcat(transform, superlayerTransform);
|
||||
transform = CGAffineTransformConcat(_transformFromLayer, superlayerTransform);
|
||||
|
||||
transform.tx -= superlayerOrigin.x;
|
||||
transform.ty -= superlayerOrigin.y;
|
||||
}
|
||||
|
||||
else
|
||||
// Copy so we don't affect the original.
|
||||
transform = CGAffineTransformCreateCopy(_transformFromLayer);
|
||||
|
||||
transform.tx -= _CGRectGetMinX(_backingStoreFrame);
|
||||
transform.ty -= _CGRectGetMinY(_backingStoreFrame);
|
||||
|
||||
CGContextSaveGState(_context);
|
||||
|
||||
CGContextConcatCTM(_context, transform);//_transformFromView);
|
||||
if (USE_BUFFER)
|
||||
{
|
||||
@@ -791,7 +796,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
||||
|
||||
layer._runLoopUpdateMask = 0;
|
||||
}
|
||||
window.loop= false;
|
||||
window.loop = false;
|
||||
CALayerRegisteredRunLoopUpdates = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ var CAMediaNamedTimingFunctions = nil;
|
||||
if (!CAMediaNamedTimingFunctions)
|
||||
{
|
||||
CAMediaNamedTimingFunctions = [CPDictionary dictionary];
|
||||
|
||||
|
||||
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionLinear];
|
||||
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionEaseIn];
|
||||
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseOut];
|
||||
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
}
|
||||
|
||||
|
||||
return [CAMediaNamedTimingFunctions objectForKey:aName];
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ var CAMediaNamedTimingFunctions = nil;
|
||||
- (id)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_c1x = c1x;
|
||||
@@ -71,7 +71,7 @@ var CAMediaNamedTimingFunctions = nil;
|
||||
_c2x = c2x;
|
||||
_c2y = c2y;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ function CGAffineTransformMakeRotation(anAngle)
|
||||
{
|
||||
var sin = SIN(anAngle),
|
||||
cos = COS(anAngle);
|
||||
|
||||
|
||||
return _CGAffineTransformMake(cos, sin, -sin, cos, 0.0, 0.0);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ function CGRectApplyAffineTransform(aRect, anAffineTransform)
|
||||
maxX = MAX(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x),
|
||||
minY = MIN(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y),
|
||||
maxY = MAX(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
|
||||
|
||||
|
||||
return _CGRectMake(minX, minY, (maxX - minX), (maxY - minY));
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ function CGColorCreateCopy(aColor)
|
||||
*/
|
||||
function CGColorCreateGenericGray(gray, alpha)
|
||||
{
|
||||
return CGColorCreate(0, [gray, alpha]);
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray,gray,gray, alpha]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -122,7 +122,7 @@ function CGColorCreateGenericGray(gray, alpha)
|
||||
*/
|
||||
function CGColorCreateGenericRGB(red, green, blue, alpha)
|
||||
{
|
||||
return CGColorCreate(0, [red, green, blue, alpha]);
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [red, green, blue, alpha]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -137,7 +137,8 @@ function CGColorCreateGenericRGB(red, green, blue, alpha)
|
||||
*/
|
||||
function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
|
||||
{
|
||||
return CGColorCreate(0, [cyan, magenta, yellow, black, alpha]);
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceCMYK(),
|
||||
[cyan, magenta, yellow, black, alpha]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -149,19 +150,21 @@ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
|
||||
*/
|
||||
function CGColorCreateCopyWithAlpha(aColor, anAlpha)
|
||||
{
|
||||
var components = aColor.components;
|
||||
if ( !aColor ) return aColor; // Avoid error null pointer in next line
|
||||
|
||||
if (!aColor || anAlpha == components[components.length - 1])
|
||||
var components = aColor.components.slice();
|
||||
|
||||
if (anAlpha == components[components.length - 1])
|
||||
return aColor;
|
||||
|
||||
// set new alpha value now so that a potentially a new cache entry is made and
|
||||
// not that an existing cache entry is mutated.
|
||||
components[components.length - 1] = anAlpha;
|
||||
|
||||
if (aColor.pattern)
|
||||
var copy = CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
|
||||
return CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
|
||||
else
|
||||
var copy = CGColorCreate(aColor.colorspace, components);
|
||||
|
||||
copy.components[components.length - 1] = anAlpha;
|
||||
|
||||
return copy;
|
||||
return CGColorCreate(aColor.colorspace, components);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -123,17 +123,17 @@ function CGColorSpaceCreatePattern(aBaseColorSpace)
|
||||
{
|
||||
if (aBaseColorSpace)
|
||||
return _CGColorSpaceCreateWithModel(kCGColorSpaceModelPattern, aBaseColorSpace.count, aBaseColorSpace);
|
||||
|
||||
|
||||
return _CGColorSpaceCreateWithModel(kCGColorSpaceModelPattern, 0, NULL);
|
||||
}
|
||||
|
||||
function CGColorSpaceCreateWithName(aName)
|
||||
{
|
||||
var colorSpace = _CGNamedColorSpaces[aName];
|
||||
|
||||
|
||||
if (colorSpace)
|
||||
return colorSpace;
|
||||
|
||||
|
||||
switch (aName)
|
||||
{
|
||||
case kCGColorSpaceGenericGray: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelMonochrome, 1, NULL);
|
||||
@@ -144,7 +144,7 @@ function CGColorSpaceCreateWithName(aName)
|
||||
case kCGColorSpaceAdobeRGB1998: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelRGB, 3, NULL);
|
||||
case kCGColorSpaceSRGB: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelRGB, 3, NULL);
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -214,9 +214,9 @@ function CGColorSpaceRetain(aColorSpace)
|
||||
function CGColorSpaceStandardizeComponents(aColorSpace, components)
|
||||
{
|
||||
var count = aColorSpace.count;
|
||||
|
||||
// Standardize the alpha value. We allow the alpha value to have a
|
||||
// higher precision than other components since it is not ultimately
|
||||
|
||||
// Standardize the alpha value. We allow the alpha value to have a
|
||||
// higher precision than other components since it is not ultimately
|
||||
// bound to 256 bits like RGB.
|
||||
STANDARDIZE(components, count, 0, 1, 1000);
|
||||
|
||||
@@ -231,7 +231,7 @@ function CGColorSpaceStandardizeComponents(aColorSpace, components)
|
||||
case kCGColorSpaceModelDeviceN: while (count--)
|
||||
STANDARDIZE(components, count, 0, 1, 255);
|
||||
break;
|
||||
|
||||
|
||||
// We don't currently support these color spaces.
|
||||
case kCGColorSpaceModelIndexed:
|
||||
case kCGColorSpaceModelLab:
|
||||
|
||||
@@ -129,7 +129,7 @@ function CGGStateCreateCopy(aGState)
|
||||
return { alpha:aGState.alpha, strokeStyle:aGState.strokeStyle, fillStyle:aGState.fillStyle, lineWidth:aGState.lineWidth,
|
||||
lineJoin:aGState.lineJoin, lineCap:aGState.lineCap, miterLimit:aGState.miterLimit, globalAlpha:aGState.globalAlpha,
|
||||
blendMode:aGState.blendMode,
|
||||
shadowOffset:aGState.shadowOffset, shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) };
|
||||
shadowOffset:_CGSizeMakeCopy(aGState.shadowOffset), shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) };
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -606,7 +606,7 @@ function CGContextStrokeLineSegments(aContext, points, count)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
if (count === NULL)
|
||||
var count = points.length;
|
||||
|
||||
CGContextBeginPath(aContext);
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
|
||||
var CANVAS_LINECAP_TABLE = [ "butt", "round", "square" ],
|
||||
CANVAS_LINEJOIN_TABLE = [ "miter", "round", "bevel" ],
|
||||
CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
|
||||
"lighter", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over",
|
||||
"copy", "source-in", "source-out", "source-atop",
|
||||
"destination-over", "destination-in", "destination-out", "destination-atop",
|
||||
CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
|
||||
"lighter", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over",
|
||||
"copy", "source-in", "source-out", "source-atop",
|
||||
"destination-over", "destination-in", "destination-out", "destination-atop",
|
||||
"xor", "source-over", "source-over" ];
|
||||
|
||||
#define _CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, anticlockwise) aContext.arc(x, y, radius, startAngle, endAngle, anticlockwise)
|
||||
@@ -106,15 +106,15 @@ function CGContextAddPath(aContext, aPath)
|
||||
return;
|
||||
|
||||
var elements = aPath.elements,
|
||||
|
||||
|
||||
i = 0,
|
||||
count = aPath.count;
|
||||
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var element = elements[i],
|
||||
type = element.type;
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case kCGPathElementMoveToPoint: _CGContextMoveToPointCanvas(aContext, element.x, element.y);
|
||||
@@ -143,10 +143,10 @@ function CGContextAddRect(aContext, aRect)
|
||||
function CGContextAddRects(aContext, rects, count)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
|
||||
if (count === NULL)
|
||||
var count = rects.length;
|
||||
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var rect = rects[i];
|
||||
@@ -180,7 +180,7 @@ function CGContextDrawPath(aContext, aMode)
|
||||
aContext.fill();
|
||||
else if (aMode == kCGPathEOFill || aMode == kCGPathEOFillStroke)
|
||||
alert("not implemented!!!");
|
||||
|
||||
|
||||
if (aMode == kCGPathStroke || aMode == kCGPathFillStroke || aMode == kCGPathEOFillStroke)
|
||||
aContext.stroke();
|
||||
}
|
||||
@@ -193,10 +193,10 @@ function CGContextFillRect(aContext, aRect)
|
||||
function CGContextFillRects(aContext, rects, count)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
|
||||
if (count === NULL)
|
||||
var count = rects.length;
|
||||
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var rect = rects[i];
|
||||
@@ -219,13 +219,13 @@ function CGContextClipToRect(aContext, aRect)
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
_CGContextAddRectCanvas(aContext, aRect);
|
||||
_CGContextClosePathCanvas(aContext);
|
||||
|
||||
|
||||
_CGContextClipCanvas(aContext);
|
||||
}
|
||||
|
||||
function CGContextClipToRects(aContext, rects, count)
|
||||
{
|
||||
if (arguments["count"] == NULL)
|
||||
if (count === NULL)
|
||||
var count = rects.length;
|
||||
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
@@ -240,7 +240,25 @@ function CGContextSetAlpha(aContext, anAlpha)
|
||||
|
||||
function CGContextSetFillColor(aContext, aColor)
|
||||
{
|
||||
aContext.fillStyle = [aColor cssString];
|
||||
if ([aColor patternImage])
|
||||
{
|
||||
var patternImg = [aColor patternImage],
|
||||
size = [patternImg size],
|
||||
img;
|
||||
|
||||
if (size)
|
||||
img = new Image(size.width, size.height);
|
||||
else
|
||||
img = new Image();
|
||||
|
||||
img.src = [patternImg filename];
|
||||
|
||||
var pattern = aContext.createPattern(img, "repeat");
|
||||
|
||||
aContext.fillStyle = pattern;
|
||||
}
|
||||
else
|
||||
aContext.fillStyle = [aColor cssString];
|
||||
}
|
||||
|
||||
function CGContextSetStrokeColor(aContext, aColor)
|
||||
@@ -302,7 +320,7 @@ function CGContextTranslateCTM(aContext, tx, ty)
|
||||
sx = (abs_cos * a / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);\
|
||||
sy = (abs_cos * d / cos + abs_sin * b / sin) / (abs_cos + abs_sin);\
|
||||
}\
|
||||
|
||||
|
||||
#define rotate_scale(a, b, c, d) \
|
||||
var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0;\
|
||||
a1 = (Math.atan2(sign * b, sign * a) + Math.atan2(-c, d)) / 2.0,\
|
||||
@@ -350,7 +368,7 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
{
|
||||
var a = anAffineTransform.a,
|
||||
b = anAffineTransform.b,
|
||||
c = anAffineTransform.c,
|
||||
c = anAffineTransform.c,
|
||||
d = anAffineTransform.d,
|
||||
tx = anAffineTransform.tx,
|
||||
ty = anAffineTransform.ty,
|
||||
@@ -365,13 +383,13 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
sx = a;
|
||||
sy = d;
|
||||
}
|
||||
|
||||
|
||||
// a scale followed by a rotate
|
||||
else if (a * b == -c * d)
|
||||
{
|
||||
scale_rotate(a, b, c, d)
|
||||
}
|
||||
|
||||
|
||||
// rotate, then scale.
|
||||
else if (a * c == -b * d)
|
||||
{
|
||||
@@ -384,8 +402,8 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
v = eigen(CGAffineTransformConcat(transpose, anAffineTransform)),
|
||||
U = CGAffineTransformMake(u.vector_1.x, u.vector_2.x, u.vector_1.y, u.vector_2.y, 0.0, 0.0), // inline
|
||||
VT = CGAffineTransformMake(v.vector_1.x, v.vector_1.y, v.vector_2.x, v.vector_2.y, 0.0, 0.0),
|
||||
S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
|
||||
|
||||
S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
|
||||
|
||||
a = VT.a;
|
||||
b = VT.b;
|
||||
c = VT.c;
|
||||
@@ -401,7 +419,7 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
sx = S.a * sx;
|
||||
sy = S.d * sy;
|
||||
}
|
||||
|
||||
|
||||
if (tx != 0 || ty != 0)
|
||||
CGContextTranslateCTM(aContext, tx, ty);
|
||||
if (a1 != 0.0)
|
||||
@@ -428,12 +446,12 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
|
||||
{
|
||||
var colors = aGradient.colors,
|
||||
count = colors.length,
|
||||
|
||||
|
||||
linearGradient = aContext.createLinearGradient(aStartPoint.x, aStartPoint.y, anEndPoint.x, anEndPoint.y);
|
||||
|
||||
while (count--)
|
||||
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
|
||||
|
||||
|
||||
aContext.fillStyle = linearGradient;
|
||||
aContext.fill();
|
||||
}
|
||||
@@ -442,8 +460,8 @@ function CGBitmapGraphicsContextCreate()
|
||||
{
|
||||
var DOMElement = document.createElement("canvas"),
|
||||
context = DOMElement.getContext("2d");
|
||||
|
||||
|
||||
context.DOMElement = DOMElement;
|
||||
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,21 @@ function CGBitmapGraphicsContextCreate()
|
||||
// The first time around, we have to set up our environment to support vml.
|
||||
document.namespaces.add("cg_vml_", "urn:schemas-microsoft-com:vml");
|
||||
document.createStyleSheet().cssText = "cg_vml_\\:*{behavior:url(#default#VML)}";
|
||||
|
||||
|
||||
CGBitmapGraphicsContextCreate = _CGBitmapGraphicsContextCreate;
|
||||
|
||||
|
||||
return _CGBitmapGraphicsContextCreate();
|
||||
}
|
||||
|
||||
function CGContextSetFillColor(aContext, aColor)
|
||||
{
|
||||
if ([aColor patternImage])
|
||||
// Prefix a marker character to the string so we know it's a pattern image filename
|
||||
aContext.gState.fillStyle = "!" + [[aColor patternImage] filename];
|
||||
else
|
||||
aContext.gState.fillStyle = [aColor cssString];
|
||||
}
|
||||
|
||||
// FIXME: aRect is ignored.
|
||||
function CGContextClearRect(aContext, aRect)
|
||||
{
|
||||
@@ -45,7 +54,7 @@ function CGContextClearRect(aContext, aRect)
|
||||
aContext.buffer = "";
|
||||
else
|
||||
aContext.DOMElement.innerHTML = "";
|
||||
|
||||
|
||||
aContext.path = NULL;
|
||||
}
|
||||
|
||||
@@ -54,12 +63,12 @@ var W = 10.0,
|
||||
Z = 10.0,
|
||||
Z_2 = Z / 2.0;
|
||||
|
||||
#define COORD(aCoordinate) (ROUND(Z * (aCoordinate) - Z_2))
|
||||
#define COORD(aCoordinate) (aCoordinate === 0.0 ? 0 : ROUND(Z * (aCoordinate) - Z_2))
|
||||
|
||||
function CGContextDrawImage(aContext, aRect, anImage)
|
||||
{
|
||||
var string = "";
|
||||
|
||||
|
||||
if (anImage.buffer != nil)
|
||||
string = anImage.buffer;
|
||||
else
|
||||
@@ -68,24 +77,24 @@ function CGContextDrawImage(aContext, aRect, anImage)
|
||||
origin = CGPointApplyAffineTransform(aRect.origin, ctm),
|
||||
similarity = ctm.a == ctm.d && ctm.b == -ctm.c,
|
||||
vml = ["<cg_vml_:group coordsize=\"1,1\" coordorigin=\"0,0\" style=\"width:1;height:1;position:absolute"];
|
||||
|
||||
|
||||
/*if (similarity)
|
||||
{
|
||||
var angle = CGPointMake(1.0, 0.0);
|
||||
|
||||
|
||||
angle = _CGPointApplyAffineTransform(angle, ctm);
|
||||
|
||||
|
||||
vml.push(";rotation:", ATAN2(angle.y - ctm.ty, angle.x - ctm.tx) * 180 / PI);
|
||||
}*/
|
||||
|
||||
// Only create a filter if absolutely necessary. This actually
|
||||
// turns out to only be the case if our transform matrix is not
|
||||
// a similarity matrix, that is to say, the transform actually
|
||||
|
||||
// Only create a filter if absolutely necessary. This actually
|
||||
// turns out to only be the case if our transform matrix is not
|
||||
// a similarity matrix, that is to say, the transform actually
|
||||
// morphs the shape beyond scaling and rotation.
|
||||
//if (!similarity && (ctm.a != 1.0 || ctm.b || ctm.c || ctm.d != 1.0))
|
||||
{
|
||||
var transformedRect = CGRectApplyAffineTransform(aRect, ctm);
|
||||
|
||||
|
||||
vml.push( ";padding:0 ", ROUND(_CGRectGetMaxX(transformedRect)), "px ", ROUND(_CGRectGetMaxY(transformedRect)),
|
||||
"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
|
||||
"M11='", ctm.a, "',M12='", ctm.c, "',M21='", ctm.b, "',M22='", ctm.d, "',",
|
||||
@@ -93,14 +102,14 @@ function CGContextDrawImage(aContext, aRect, anImage)
|
||||
}
|
||||
//else
|
||||
// vml.push(";top:", ROUND(origin.y - 0.5), "px;left:", ROUND(origin.x - 0.5), "px;");
|
||||
|
||||
vml.push( "\"><cg_vml_:image src=\"", anImage._image.src,
|
||||
"\" style=\"width:", _CGRectGetWidth(aRect), "px;height:", _CGRectGetHeight(aRect),
|
||||
|
||||
vml.push( "\"><cg_vml_:image src=\"", anImage._image.src,
|
||||
"\" style=\"width:", _CGRectGetWidth(aRect), "px;height:", _CGRectGetHeight(aRect),
|
||||
"px;\"/></g_vml_:group>");
|
||||
|
||||
|
||||
string = vml.join("");
|
||||
}
|
||||
|
||||
|
||||
if (aContext.buffer != nil)
|
||||
aContext.buffer += string;
|
||||
else
|
||||
@@ -111,74 +120,77 @@ function CGContextDrawPath(aContext, aMode)
|
||||
{
|
||||
if (!aContext || CGPathIsEmpty(aContext.path))
|
||||
return;
|
||||
|
||||
|
||||
var elements = aContext.path.elements,
|
||||
|
||||
|
||||
i = 0,
|
||||
count = aContext.path.count,
|
||||
|
||||
|
||||
gState = aContext.gState,
|
||||
fill = (aMode == kCGPathFill || aMode == kCGPathFillStroke) ? 1 : 0,
|
||||
stroke = (aMode == kCGPathStroke || aMode == kCGPathFillStroke) ? 1 : 0,
|
||||
opacity = gState.alpha,
|
||||
vml = [ "<cg_vml_:shape",
|
||||
" fillcolor=\"", gState.fillStyle,
|
||||
"\" filled=\"", VML_TRUTH_TABLE[fill],
|
||||
"\" style=\"position:absolute;width:", W, ";height:", H,
|
||||
";\" coordorigin=\"0 0\" coordsize=\"", Z * W, " ", Z * H,
|
||||
"\" stroked=\"", VML_TRUTH_TABLE[stroke],
|
||||
"\" strokeweight=\"", gState.lineWidth,
|
||||
"\" strokecolor=\"", gState.strokeStyle,
|
||||
"\" path=\""];
|
||||
|
||||
vml = ["<cg_vml_:shape"];
|
||||
|
||||
if (gState.fillStyle.charAt(0) !== "!")
|
||||
vml.push(" fillcolor=\"", gState.fillStyle, "\"");
|
||||
|
||||
vml.push( " filled=\"", VML_TRUTH_TABLE[fill],
|
||||
"\" style=\"position:absolute;width:", W, ";height:", H,
|
||||
";\" coordorigin=\"0 0\" coordsize=\"", Z * W, " ", Z * H,
|
||||
"\" stroked=\"", VML_TRUTH_TABLE[stroke],
|
||||
"\" strokeweight=\"", gState.lineWidth,
|
||||
"\" strokecolor=\"", gState.strokeStyle,
|
||||
"\" path=\"");
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var element = elements[i],
|
||||
type = element.type;
|
||||
|
||||
switch(type)
|
||||
switch (type)
|
||||
{
|
||||
case kCGPathElementMoveToPoint:
|
||||
case kCGPathElementMoveToPoint:
|
||||
case kCGPathElementAddLineToPoint: vml.push(VML_ELEMENT_TABLE[type], COORD(element.x), ',', COORD(element.y));
|
||||
break;
|
||||
|
||||
case kCGPathElementAddQuadCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
|
||||
|
||||
case kCGPathElementAddQuadCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
|
||||
COORD(element.cpx), ',', COORD(element.cpy), ',',
|
||||
COORD(element.x), ',', COORD(element.y));
|
||||
break;
|
||||
|
||||
case kCGPathElementAddCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
|
||||
|
||||
case kCGPathElementAddCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
|
||||
COORD(element.cp1x), ',', COORD(element.cp1y), ',',
|
||||
COORD(element.cp2x), ',', COORD(element.cp2y), ',',
|
||||
COORD(element.x), ',', COORD(element.y));
|
||||
break;
|
||||
|
||||
|
||||
case kCGPathElementCloseSubpath: vml.push(VML_ELEMENT_TABLE[type]);
|
||||
break;
|
||||
|
||||
|
||||
case kCGPathElementAddArc: var x = element.x,
|
||||
y = element.y,
|
||||
radius = element.radius,
|
||||
clockwise = element.clockwise ? 1 : 0,
|
||||
endAngle = element.endAngle,
|
||||
startAngle = element.startAngle,
|
||||
|
||||
|
||||
start = _CGPointMake(x + radius * COS(startAngle), y + radius * SIN(startAngle));
|
||||
|
||||
// If the angle's are equal, then we won't actually draw an arc, but instead
|
||||
|
||||
// If the angle's are equal, then we won't actually draw an arc, but instead
|
||||
// simply move to its start/end to get the proper fill.
|
||||
// We only need this special case for anti-clockwise because start == end is
|
||||
// We only need this special case for anti-clockwise because start == end is
|
||||
// interpreted as a full circle with anti-clockwise, but empty for clockwise.
|
||||
if (startAngle == endAngle && !clockwise)
|
||||
{
|
||||
vml.push(VML_ELEMENT_TABLE[kCGPathElementMoveToPoint], COORD(start.x), ',', COORD(start.y));
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var end = _CGPointMake(x + radius * COS(endAngle), y + radius * SIN(endAngle));
|
||||
|
||||
// Only do the start correction if the angles aren't equal. If they are, then
|
||||
|
||||
// Only do the start correction if the angles aren't equal. If they are, then
|
||||
// let the circle be empty.
|
||||
// FIXME: Should this be |star.x - end.x| < 0.125 ?
|
||||
if (clockwise && startAngle != endAngle && _CGPointEqualToPoint(start, end))
|
||||
@@ -196,10 +208,10 @@ function CGContextDrawPath(aContext, aMode)
|
||||
else
|
||||
end.y += 0.125;
|
||||
}
|
||||
|
||||
vml.push(VML_ELEMENT_TABLE[type][clockwise],
|
||||
COORD(x - radius), ',', COORD(y - radius), " ",
|
||||
COORD(x + radius), ',', COORD(y + radius), " ",
|
||||
|
||||
vml.push(VML_ELEMENT_TABLE[type][clockwise],
|
||||
COORD(x - radius), ',', COORD(y - radius), " ",
|
||||
COORD(x + radius), ',', COORD(y + radius), " ",
|
||||
COORD(start.x), ',', COORD(start.y), " ",
|
||||
COORD(end.x), ',', COORD(end.y));
|
||||
break;
|
||||
@@ -228,31 +240,36 @@ function CGContextDrawPath(aContext, aMode)
|
||||
}
|
||||
|
||||
vml.push("\">");
|
||||
|
||||
|
||||
if (gState.gradient)
|
||||
vml.push(gState.gradient)
|
||||
|
||||
|
||||
else if (fill)
|
||||
vml.push("<cg_vml_:fill color=\"", gState.fillStyle, "\" opacity=\"", opacity, "\" />");
|
||||
|
||||
{
|
||||
if (gState.fillStyle.charAt(0) === "!")
|
||||
vml.push("<cg_vml_:fill type=\"tile\" src=\"", gState.fillStyle.substring(1), "\" opacity=\"", opacity, "\" />");
|
||||
else // should be a CSS color spec
|
||||
vml.push("<cg_vml_:fill color=\"", gState.fillStyle, "\" opacity=\"", opacity, "\" />");
|
||||
}
|
||||
|
||||
if (stroke)
|
||||
vml.push( "<cg_vml_:stroke opacity=\"", opacity,
|
||||
"\" joinstyle=\"", VML_LINEJOIN_TABLE[gState.lineJoin],
|
||||
"\" miterlimit=\"", gState.miterLimit,
|
||||
"\" endcap=\"", VML_LINECAP_TABLE[gState.lineCap],
|
||||
vml.push( "<cg_vml_:stroke opacity=\"", opacity,
|
||||
"\" joinstyle=\"", VML_LINEJOIN_TABLE[gState.lineJoin],
|
||||
"\" miterlimit=\"", gState.miterLimit,
|
||||
"\" endcap=\"", VML_LINECAP_TABLE[gState.lineCap],
|
||||
"\" weight=\"", gState.lineWidth, "",
|
||||
"px\" color=\"", gState.strokeStyle,"\" />");
|
||||
|
||||
|
||||
var shadowColor = gState.shadowColor;
|
||||
//\"", [shadowColor cssString], "\"
|
||||
if (shadowColor)
|
||||
{
|
||||
var shadowOffset = gState.shadowOffset;
|
||||
|
||||
vml.push("<cg_vml_:shadow on=\"t\" offset=\"",
|
||||
|
||||
vml.push("<cg_vml_:shadow on=\"t\" offset=\"",
|
||||
shadowOffset.width, "pt ", shadowOffset.height, "pt\" opacity=\"", [shadowColor alphaComponent], "\" color=black />");
|
||||
}
|
||||
|
||||
|
||||
vml.push("</cg_vml_:shape>");
|
||||
|
||||
if (aContext.buffer != nil)
|
||||
@@ -270,25 +287,25 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
|
||||
{
|
||||
if (!aContext || !aGradient)
|
||||
return;
|
||||
|
||||
|
||||
var vml = nil;
|
||||
|
||||
|
||||
if (aGradient.vml_gradient)
|
||||
{
|
||||
var stops = [[aGradient.vml_gradient stops] sortedArrayUsingSelector:@selector(comparePosition:)],
|
||||
count = [stops count];
|
||||
|
||||
|
||||
vml = ["<cg_vml_:fill type=\"gradient\" method=\"linear sigma\" "];
|
||||
vml.push("angle=\"" + ([aGradient.vml_gradient angle] + 90) +"\" ");
|
||||
|
||||
vml.push("angle=\"" + ([aGradient.vml_gradient angle] + 90) + "\" ");
|
||||
|
||||
vml.push("colors=\"");
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
vml.push(([stops[i] position]*100).toFixed(0)+"% ");
|
||||
vml.push(([stops[i] position] * 100).toFixed(0) + "% ");
|
||||
vml.push([[[stops[i] color] colorForSlideBase:nil] cssString]);
|
||||
|
||||
if (i < count-1)
|
||||
|
||||
if (i < count - 1)
|
||||
vml.push(",");
|
||||
}
|
||||
|
||||
@@ -304,13 +321,13 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
|
||||
vml.push("colors=\"");
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
vml.push((aGradient.locations[i]*100).toFixed(0)+"% "+to_string(colors[i])+(i<count-1 ? "," : ""));
|
||||
vml.push((aGradient.locations[i] * 100).toFixed(0)+"% " + to_string(colors[i])+(i < count - 1 ? "," : ""));
|
||||
|
||||
vml.push("\" />");
|
||||
}
|
||||
|
||||
|
||||
aContext.gState.gradient = vml.join("");
|
||||
|
||||
|
||||
// if (aContext.buffer != nil)
|
||||
// aContext.buffer += vml.join("");
|
||||
// else
|
||||
|
||||
@@ -29,10 +29,15 @@ kCGGradientDrawsAfterEndLocation = 1 << 1;
|
||||
|
||||
function CGGradientCreateWithColorComponents(aColorSpace, components, locations, count)
|
||||
{
|
||||
if (arguments["locations"] == NULL)
|
||||
var locations = [0.0, 1.0];
|
||||
if ( locations === undefined || locations === NULL )
|
||||
{
|
||||
var num_of_colors = components.length / 4,
|
||||
locations = [];
|
||||
for ( var idx = 0; idx < num_of_colors; idx++ )
|
||||
locations.push( idx / (num_of_colors - 1) );
|
||||
}
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
if ( count === undefined || count === NULL)
|
||||
var count = locations.length;
|
||||
|
||||
var colors = [];
|
||||
@@ -58,4 +63,4 @@ function CGGradientRelease()
|
||||
function CGGradientRetain(aGradient)
|
||||
{
|
||||
return aGradient;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ function CGPathCreateMutable()
|
||||
function CGPathCreateMutableCopy(aPath)
|
||||
{
|
||||
var path = CGPathCreateMutable();
|
||||
|
||||
|
||||
CGPathAddPath(path, aPath);
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle,
|
||||
aStartAngle = ATAN2(start.y - aTransform.ty, start.x - aTransform.tx);
|
||||
|
||||
// Angles that equal "modulo" 2 pi return as equal after transforming them,
|
||||
// so we have to make sure to make them different again if they were different
|
||||
// so we have to make sure to make them different again if they were different
|
||||
// to start out with. It's the difference between no circle and a full circle.
|
||||
if (anEndAngle == aStartAngle && oldEndAngle != oldStartAngle)
|
||||
if (oldStartAngle > oldEndAngle)
|
||||
@@ -111,7 +111,7 @@ function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle,
|
||||
aRadius = _CGSizeApplyAffineTransform(aRadius, aTransform);
|
||||
aRadius = SQRT(aRadius.width * aRadius.width + aRadius.height * aRadius.height);
|
||||
}
|
||||
|
||||
|
||||
aPath.current = _CGPointMake(x + aRadius * COS(anEndAngle), y + aRadius * SIN(anEndAngle));
|
||||
aPath.elements[aPath.count++] = { type:kCGPathElementAddArc, x:x, y:y, radius:aRadius, startAngle:aStartAngle, endAngle:anEndAngle };
|
||||
}
|
||||
@@ -125,14 +125,14 @@ function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
|
||||
var cp1 = _CGPointMake(cp1x, cp1y),
|
||||
cp2 = _CGPointMake(cp2x, cp2y),
|
||||
end = _CGPointMake(x, y);
|
||||
|
||||
|
||||
if (aTransform)
|
||||
{
|
||||
cp1 = _CGPointApplyAffineTransform(cp1, aTransform);
|
||||
cp2 = _CGPointApplyAffineTransform(cp2, aTransform);
|
||||
end = _CGPointApplyAffineTransform(end, aTransform);
|
||||
}
|
||||
|
||||
|
||||
aPath.current = end;
|
||||
aPath.elements[aPath.count++] = { type:kCGPathElementAddCurveToPoint, cp1x:cp1.x, cp1y:cp1.y, cp2x:cp2.x, cp2y:cp2.y, x:end.x, y:end.y };
|
||||
}
|
||||
@@ -140,13 +140,13 @@ function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
|
||||
function CGPathAddLines(aPath, aTransform, points, count)
|
||||
{
|
||||
var i = 1;
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
|
||||
if (count === NULL)
|
||||
var count = points.length;
|
||||
|
||||
|
||||
if (!aPath || count < 2)
|
||||
return;
|
||||
|
||||
|
||||
CGPathMoveToPoint(aPath, aTransform, points[0].x, points[0].y);
|
||||
|
||||
for (; i < count; ++i)
|
||||
@@ -156,7 +156,7 @@ function CGPathAddLines(aPath, aTransform, points, count)
|
||||
function CGPathAddLineToPoint(aPath, aTransform, x, y)
|
||||
{
|
||||
var point = _CGPointMake(x, y);
|
||||
|
||||
|
||||
if (aTransform != NULL)
|
||||
point = _CGPointApplyAffineTransform(point, aTransform);
|
||||
|
||||
@@ -204,13 +204,13 @@ function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
|
||||
{
|
||||
var cp = _CGPointMake(cpx, cpy),
|
||||
end = _CGPointMake(x, y);
|
||||
|
||||
|
||||
if (aTransform)
|
||||
{
|
||||
cp = _CGPointApplyAffineTransform(cp, aTransform);
|
||||
end = _CGPointApplyAffineTransform(end, aTransform);
|
||||
}
|
||||
|
||||
|
||||
aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y }
|
||||
aPath.current = end;
|
||||
}
|
||||
@@ -223,19 +223,19 @@ function CGPathAddRect(aPath, aTransform, aRect)
|
||||
function CGPathAddRects(aPath, aTransform, rects, count)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (arguments["count"] == NULL)
|
||||
|
||||
if (count === NULL)
|
||||
var count = rects.length;
|
||||
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var rect = rects[i];
|
||||
|
||||
|
||||
CGPathMoveToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMinY(rect));
|
||||
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMinY(rect));
|
||||
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
|
||||
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMaxY(rect));
|
||||
|
||||
|
||||
CGPathCloseSubpath(aPath);
|
||||
}
|
||||
}
|
||||
@@ -244,15 +244,15 @@ function CGPathMoveToPoint(aPath, aTransform, x, y)
|
||||
{
|
||||
var point = _CGPointMake(x, y),
|
||||
count = aPath.count;
|
||||
|
||||
|
||||
if (aTransform != NULL)
|
||||
point = _CGPointApplyAffineTransform(point, aTransform);
|
||||
|
||||
aPath.start = point;
|
||||
aPath.current = point;
|
||||
|
||||
|
||||
var previous = aPath.elements[count - 1];
|
||||
|
||||
|
||||
if (count != 0 && previous.type == kCGPathElementMoveToPoint)
|
||||
{
|
||||
previous.x = point.x;
|
||||
@@ -338,11 +338,11 @@ function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius/*not currently
|
||||
function CGPathCloseSubpath(aPath)
|
||||
{
|
||||
var count = aPath.count;
|
||||
|
||||
|
||||
// Don't bother closing this subpath if there aren't any current elements, or the last element already closed the subpath.
|
||||
if (count == 0 || aPath.elements[count - 1].type == kCGPathElementCloseSubpath)
|
||||
return;
|
||||
|
||||
|
||||
aPath.elements[aPath.count++] = { type:kCGPathElementCloseSubpath, points:[aPath.start] };
|
||||
}
|
||||
|
||||
@@ -350,32 +350,32 @@ function CGPathEqualToPath(aPath, anotherPath)
|
||||
{
|
||||
if (aPath == anotherPath)
|
||||
return YES;
|
||||
|
||||
|
||||
if (aPath.count != anotherPath.count || !_CGPointEqualToPoint(aPath.start, anotherPath.start) || !_CGPointEqualToPoint(aPath.current, anotherPath.current))
|
||||
return NO;
|
||||
|
||||
|
||||
var i = 0,
|
||||
count = aPath.count;
|
||||
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var element = aPath[i],
|
||||
anotherElement = anotherPath[i];
|
||||
|
||||
|
||||
if (element.type != anotherElement.type)
|
||||
return NO;
|
||||
|
||||
if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) &&
|
||||
|
||||
if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) &&
|
||||
element.radius != anotherElement.radius)
|
||||
return NO;
|
||||
|
||||
|
||||
var j = element.points.length;
|
||||
|
||||
|
||||
while (j--)
|
||||
if (!_CGPointEqualToPoint(element.points[j], anotherElement.points[j]))
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
|
||||
BOOL _mouseIsDown;
|
||||
BOOL _mouseDownIsRightClick;
|
||||
CGPoint _lastMouseEventLocation;
|
||||
CPWindow _mouseDownWindow;
|
||||
CPTimeInterval _lastMouseUp;
|
||||
CPTimeInterval _lastMouseDown;
|
||||
@@ -103,7 +104,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
#if PLATFORM(DOM)
|
||||
_windowLevels = [];
|
||||
_windowLayers = [CPDictionary dictionary];
|
||||
|
||||
|
||||
_charCodes = {};
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@
|
||||
- (id)initWithLevel:(int)aLevel
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_level = aLevel;
|
||||
|
||||
|
||||
_windows = [];
|
||||
|
||||
|
||||
_DOMElement = document.createElement("div");
|
||||
_DOMElement.style.position = "absolute";
|
||||
_DOMElement.style.top = "0px";
|
||||
@@ -48,7 +48,7 @@
|
||||
_DOMElement.style.width = "1px";
|
||||
_DOMElement.style.height = "1px";
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
_windows[index]._index = index;
|
||||
_windows[index]._DOMElement.style.zIndex = index;
|
||||
}
|
||||
|
||||
|
||||
aWindow._isVisible = NO;
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@
|
||||
var count = [_windows count],
|
||||
zIndex = (anIndex == CPNotFound ? count : anIndex),
|
||||
isVisible = aWindow._isVisible;
|
||||
|
||||
// If the window is already a resident of this layer, remove it.
|
||||
|
||||
// If the window is already a resident of this layer, remove it.
|
||||
if (isVisible)
|
||||
{
|
||||
zIndex = MIN(zIndex, aWindow._index);
|
||||
@@ -93,12 +93,12 @@
|
||||
}
|
||||
else
|
||||
++count;
|
||||
|
||||
|
||||
if (anIndex == CPNotFound || anIndex >= count)
|
||||
[_windows addObject:aWindow];
|
||||
else
|
||||
[_windows insertObject:aWindow atIndex:anIndex];
|
||||
|
||||
|
||||
// Adjust all the affected z-indexes.
|
||||
for (; zIndex < count; ++zIndex)
|
||||
{
|
||||
@@ -112,7 +112,7 @@
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, aWindow._DOMElement);
|
||||
|
||||
aWindow._isVisible = YES;
|
||||
|
||||
|
||||
if ([aWindow isFullBridge])
|
||||
[aWindow setFrame:[aWindow._platformWindow usableContentFrame]];
|
||||
}
|
||||
|
||||
@@ -174,9 +174,9 @@ var DOMFixedWidthSpanElement = nil,
|
||||
|
||||
span.style.font = [aFont cssString];
|
||||
|
||||
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
|
||||
if (CPFeatureIsCompatible(CPJavaScriptInnerTextFeature))
|
||||
span.innerText = aString;
|
||||
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
|
||||
else if (CPFeatureIsCompatible(CPJavaScriptTextContentFeature))
|
||||
span.textContent = aString;
|
||||
|
||||
return _CGSizeMake(span.clientWidth, span.clientHeight);
|
||||
|
||||
@@ -183,14 +183,14 @@ KeyCodesToUnicodeMap[CPKeyCodes.BACKSLASH] = "\\";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.CLOSE_SQUARE_BRACKET] = "]";
|
||||
|
||||
var ModifierKeyCodes = [
|
||||
CPKeyCodes.META,
|
||||
CPKeyCodes.MAC_FF_META,
|
||||
CPKeyCodes.CTRL,
|
||||
CPKeyCodes.ALT,
|
||||
CPKeyCodes.SHIFT
|
||||
];
|
||||
|
||||
var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
CPKeyCodes.META,
|
||||
CPKeyCodes.WEBKIT_RIGHT_META,
|
||||
CPKeyCodes.MAC_FF_META,
|
||||
CPKeyCodes.CTRL,
|
||||
CPKeyCodes.ALT,
|
||||
CPKeyCodes.SHIFT
|
||||
],
|
||||
supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
@implementation CPPlatformWindow (DOM)
|
||||
|
||||
@@ -206,6 +206,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_windowLevels = [];
|
||||
_windowLayers = [CPDictionary dictionary];
|
||||
|
||||
|
||||
[self registerDOMWindow];
|
||||
[self updateFromNativeContentRect];
|
||||
|
||||
@@ -322,7 +323,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_DOMScrollingElement = theDocument.createElement("div");
|
||||
_DOMScrollingElement.style.position = "absolute";
|
||||
_DOMScrollingElement.style.visibility = "hidden";
|
||||
_DOMScrollingElement.style.zIndex = "998";
|
||||
_DOMScrollingElement.style.zIndex = @"999";
|
||||
_DOMScrollingElement.style.height = "60px";
|
||||
_DOMScrollingElement.style.width = "60px";
|
||||
_DOMScrollingElement.style.overflow = "scroll";
|
||||
@@ -484,7 +485,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_DOMBodyElement.ondrag = function () { return NO; };
|
||||
_DOMBodyElement.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; };
|
||||
|
||||
_DOMWindow.attachEvent("onbeforeunload", function()
|
||||
_DOMWindow.attachEvent("onunload", function()
|
||||
{
|
||||
[self updateFromNativeContentRect];
|
||||
[self _removeLayers];
|
||||
@@ -1114,7 +1115,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
{
|
||||
var newEvent = {};
|
||||
|
||||
switch(aDOMEvent.type)
|
||||
switch (aDOMEvent.type)
|
||||
{
|
||||
case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
|
||||
break;
|
||||
@@ -1158,6 +1159,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
{
|
||||
var type = _overriddenEventType || aDOMEvent.type;
|
||||
|
||||
|
||||
// IE's event order is down, up, up, dblclick, so we have create these events artificially.
|
||||
if (type === @"dblclick")
|
||||
{
|
||||
@@ -1203,7 +1205,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
{
|
||||
if (_mouseIsDown)
|
||||
{
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0, nil);
|
||||
|
||||
_mouseIsDown = NO;
|
||||
_lastMouseUp = event;
|
||||
@@ -1253,7 +1255,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
StopContextMenuDOMEventPropagation = YES;
|
||||
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0, nil);
|
||||
|
||||
_mouseIsDown = YES;
|
||||
_lastMouseDown = event;
|
||||
@@ -1264,7 +1266,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
if (_DOMEventMode)
|
||||
return;
|
||||
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? (_mouseDownIsRightClick ? CPRightMouseDragged : CPLeftMouseDragged) : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
|
||||
// _lastMouseEventLocation might be nil on the very first mousemove event. Just send in the current location
|
||||
// in this case - this will result in a delta x and delta y of 0 which seems natural for the first event.
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? (_mouseDownIsRightClick ? CPRightMouseDragged : CPLeftMouseDragged) : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0, _lastMouseEventLocation || location);
|
||||
}
|
||||
|
||||
var isDragging = [[CPDragServer sharedDragServer] isDragging];
|
||||
@@ -1282,7 +1286,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
// if there are any tracking event listeners then show the event guard so we don't lose events to iframes
|
||||
// TODO Actually check for tracking event listeners, not just any listener but _CPRunModalLoop.
|
||||
var hasTrackingEventListener = NO;
|
||||
for (var i=0; i < CPApp._eventListeners.length; i++)
|
||||
for (var i = 0; i < CPApp._eventListeners.length; i++)
|
||||
{
|
||||
if (CPApp._eventListeners[i]._callback !== _CPRunModalLoop)
|
||||
{
|
||||
@@ -1290,6 +1294,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
break;
|
||||
}
|
||||
}
|
||||
_lastMouseEventLocation = location;
|
||||
|
||||
_DOMEventGuard.style.display = hasTrackingEventListener ? "" : "none";
|
||||
|
||||
@@ -1522,7 +1527,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
+ (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
|
||||
{
|
||||
for (var i = keyCodes.length; i > 0; i--)
|
||||
KeyCodesToPrevent[keyCodes[i-1]] = YES;
|
||||
KeyCodesToPrevent[keyCodes[i - 1]] = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1546,7 +1551,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
var CPEventClass = [CPEvent class];
|
||||
|
||||
var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
|
||||
var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure, aMouseDragStart)
|
||||
{
|
||||
aNativeEvent.isa = CPEventClass;
|
||||
|
||||
@@ -1560,6 +1565,17 @@ var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, m
|
||||
aNativeEvent._eventNumber = anEventNumber;
|
||||
aNativeEvent._clickCount = aClickCount;
|
||||
aNativeEvent._pressure = aPressure;
|
||||
if((anEventType == CPLeftMouseDragged) || (anEventType == CPRightMouseDragged) || (anEventType == CPMouseMoved))
|
||||
{
|
||||
aNativeEvent._deltaX = aPoint.x - aMouseDragStart.x;
|
||||
aNativeEvent._deltaY = aPoint.y - aMouseDragStart.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
aNativeEvent._deltaX = 0;
|
||||
aNativeEvent._deltaY = 0;
|
||||
}
|
||||
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user